summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/.cvsignore5
-rw-r--r--Source/.gitattributes5
-rw-r--r--Source/CMakeInstallDestinations.cmake48
-rw-r--r--Source/CMakeLists.txt795
-rw-r--r--Source/CMakeSourceDir.txt.in1
-rwxr-xr-xSource/CMakeVersion.bash7
-rw-r--r--Source/CMakeVersion.cmake5
-rw-r--r--Source/CMakeVersionCompute.cmake20
-rw-r--r--Source/CMakeVersionSource.cmake37
-rw-r--r--Source/CPack/IFW/cmCPackIFWGenerator.cxx582
-rw-r--r--Source/CPack/IFW/cmCPackIFWGenerator.h167
-rw-r--r--Source/CPack/IFW/cmCPackIFWInstaller.cxx349
-rw-r--r--Source/CPack/IFW/cmCPackIFWInstaller.h118
-rw-r--r--Source/CPack/IFW/cmCPackIFWPackage.cxx484
-rw-r--r--Source/CPack/IFW/cmCPackIFWPackage.h149
-rw-r--r--Source/CPack/IFW/cmCPackIFWRepository.cxx342
-rw-r--r--Source/CPack/IFW/cmCPackIFWRepository.h105
-rw-r--r--Source/CPack/OSXLauncherScript.scptbin0 -> 3102 bytes
-rw-r--r--Source/CPack/OSXScriptLauncher.cxx130
-rw-r--r--Source/CPack/WiX/cmCPackWIXGenerator.cxx1127
-rw-r--r--Source/CPack/WiX/cmCPackWIXGenerator.h167
-rw-r--r--Source/CPack/WiX/cmWIXAccessControlList.cxx136
-rw-r--r--Source/CPack/WiX/cmWIXAccessControlList.h44
-rw-r--r--Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx88
-rw-r--r--Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h44
-rw-r--r--Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx97
-rw-r--r--Source/CPack/WiX/cmWIXFeaturesSourceWriter.h38
-rw-r--r--Source/CPack/WiX/cmWIXFilesSourceWriter.cxx170
-rw-r--r--Source/CPack/WiX/cmWIXFilesSourceWriter.h52
-rw-r--r--Source/CPack/WiX/cmWIXPatch.cxx105
-rw-r--r--Source/CPack/WiX/cmWIXPatch.h47
-rw-r--r--Source/CPack/WiX/cmWIXPatchParser.cxx156
-rw-r--r--Source/CPack/WiX/cmWIXPatchParser.h100
-rw-r--r--Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx196
-rw-r--r--Source/CPack/WiX/cmWIXRichTextFormatWriter.h54
-rw-r--r--Source/CPack/WiX/cmWIXShortcut.cxx115
-rw-r--r--Source/CPack/WiX/cmWIXShortcut.h70
-rw-r--r--Source/CPack/WiX/cmWIXSourceWriter.cxx216
-rw-r--r--Source/CPack/WiX/cmWIXSourceWriter.h75
-rw-r--r--Source/CPack/bills-comments.txt68
-rw-r--r--Source/CPack/cmCPack7zGenerator.cxx22
-rw-r--r--Source/CPack/cmCPack7zGenerator.h36
-rw-r--r--Source/CPack/cmCPackArchiveGenerator.cxx273
-rw-r--r--Source/CPack/cmCPackArchiveGenerator.h75
-rw-r--r--Source/CPack/cmCPackBundleGenerator.cxx292
-rw-r--r--Source/CPack/cmCPackBundleGenerator.h42
-rw-r--r--Source/CPack/cmCPackComponentGroup.cxx43
-rw-r--r--Source/CPack/cmCPackComponentGroup.h149
-rw-r--r--Source/CPack/cmCPackConfigure.h.in11
-rw-r--r--Source/CPack/cmCPackCygwinBinaryGenerator.cxx84
-rw-r--r--Source/CPack/cmCPackCygwinBinaryGenerator.h39
-rw-r--r--Source/CPack/cmCPackCygwinSourceGenerator.cxx167
-rw-r--r--Source/CPack/cmCPackCygwinSourceGenerator.h41
-rw-r--r--Source/CPack/cmCPackDebGenerator.cxx952
-rw-r--r--Source/CPack/cmCPackDebGenerator.h76
-rw-r--r--Source/CPack/cmCPackDragNDropGenerator.cxx898
-rw-r--r--Source/CPack/cmCPackDragNDropGenerator.h60
-rw-r--r--Source/CPack/cmCPackGenerator.cxx1432
-rw-r--r--Source/CPack/cmCPackGenerator.h331
-rw-r--r--Source/CPack/cmCPackGeneratorFactory.cxx183
-rw-r--r--Source/CPack/cmCPackGeneratorFactory.h61
-rw-r--r--Source/CPack/cmCPackLog.cxx190
-rw-r--r--Source/CPack/cmCPackLog.h158
-rw-r--r--Source/CPack/cmCPackNSISGenerator.cxx918
-rw-r--r--Source/CPack/cmCPackNSISGenerator.h85
-rw-r--r--Source/CPack/cmCPackOSXX11Generator.cxx291
-rw-r--r--Source/CPack/cmCPackOSXX11Generator.h48
-rw-r--r--Source/CPack/cmCPackPKGGenerator.cxx367
-rw-r--r--Source/CPack/cmCPackPKGGenerator.h96
-rw-r--r--Source/CPack/cmCPackPackageMakerGenerator.cxx584
-rw-r--r--Source/CPack/cmCPackPackageMakerGenerator.h60
-rw-r--r--Source/CPack/cmCPackProductBuildGenerator.cxx231
-rw-r--r--Source/CPack/cmCPackProductBuildGenerator.h58
-rw-r--r--Source/CPack/cmCPackRPMGenerator.cxx253
-rw-r--r--Source/CPack/cmCPackRPMGenerator.h78
-rw-r--r--Source/CPack/cmCPackSTGZGenerator.cxx125
-rw-r--r--Source/CPack/cmCPackSTGZGenerator.h40
-rw-r--r--Source/CPack/cmCPackTGZGenerator.cxx22
-rw-r--r--Source/CPack/cmCPackTGZGenerator.h36
-rw-r--r--Source/CPack/cmCPackTXZGenerator.cxx22
-rw-r--r--Source/CPack/cmCPackTXZGenerator.h36
-rw-r--r--Source/CPack/cmCPackTarBZip2Generator.cxx22
-rw-r--r--Source/CPack/cmCPackTarBZip2Generator.h35
-rw-r--r--Source/CPack/cmCPackTarCompressGenerator.cxx22
-rw-r--r--Source/CPack/cmCPackTarCompressGenerator.h35
-rw-r--r--Source/CPack/cmCPackZIPGenerator.cxx22
-rw-r--r--Source/CPack/cmCPackZIPGenerator.h36
-rw-r--r--Source/CPack/cpack.cxx429
-rw-r--r--Source/CPack/cygwin.readme69
-rw-r--r--Source/CTest/cmCTestBZR.cxx474
-rw-r--r--Source/CTest/cmCTestBZR.h55
-rw-r--r--Source/CTest/cmCTestBatchTestHandler.cxx131
-rw-r--r--Source/CTest/cmCTestBatchTestHandler.h44
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.cxx457
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.h77
-rw-r--r--Source/CTest/cmCTestBuildCommand.cxx180
-rw-r--r--Source/CTest/cmCTestBuildCommand.h71
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx1168
-rw-r--r--Source/CTest/cmCTestBuildHandler.h155
-rw-r--r--Source/CTest/cmCTestCVS.cxx288
-rw-r--r--Source/CTest/cmCTestCVS.h53
-rw-r--r--Source/CTest/cmCTestCommand.h42
-rw-r--r--Source/CTest/cmCTestConfigureCommand.cxx151
-rw-r--r--Source/CTest/cmCTestConfigureCommand.h56
-rw-r--r--Source/CTest/cmCTestConfigureHandler.cxx112
-rw-r--r--Source/CTest/cmCTestConfigureHandler.h39
-rw-r--r--Source/CTest/cmCTestCoverageCommand.cxx68
-rw-r--r--Source/CTest/cmCTestCoverageCommand.h61
-rw-r--r--Source/CTest/cmCTestCoverageHandler.cxx2359
-rw-r--r--Source/CTest/cmCTestCoverageHandler.h155
-rw-r--r--Source/CTest/cmCTestCurl.cxx249
-rw-r--r--Source/CTest/cmCTestCurl.h53
-rw-r--r--Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx32
-rw-r--r--Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h58
-rw-r--r--Source/CTest/cmCTestGIT.cxx664
-rw-r--r--Source/CTest/cmCTestGIT.h58
-rw-r--r--Source/CTest/cmCTestGenericHandler.cxx145
-rw-r--r--Source/CTest/cmCTestGenericHandler.h113
-rw-r--r--Source/CTest/cmCTestGlobalVC.cxx131
-rw-r--r--Source/CTest/cmCTestGlobalVC.h75
-rw-r--r--Source/CTest/cmCTestHG.cxx311
-rw-r--r--Source/CTest/cmCTestHG.h47
-rw-r--r--Source/CTest/cmCTestHandlerCommand.cxx189
-rw-r--r--Source/CTest/cmCTestHandlerCommand.h78
-rw-r--r--Source/CTest/cmCTestLaunch.cxx631
-rw-r--r--Source/CTest/cmCTestLaunch.h109
-rw-r--r--Source/CTest/cmCTestMemCheckCommand.cxx39
-rw-r--r--Source/CTest/cmCTestMemCheckCommand.h51
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.cxx1071
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.h160
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.cxx836
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.h142
-rw-r--r--Source/CTest/cmCTestP4.cxx534
-rw-r--r--Source/CTest/cmCTestP4.h78
-rw-r--r--Source/CTest/cmCTestReadCustomFilesCommand.cxx30
-rw-r--r--Source/CTest/cmCTestReadCustomFilesCommand.h53
-rw-r--r--Source/CTest/cmCTestRunScriptCommand.cxx53
-rw-r--r--Source/CTest/cmCTestRunScriptCommand.h54
-rw-r--r--Source/CTest/cmCTestRunTest.cxx744
-rw-r--r--Source/CTest/cmCTestRunTest.h125
-rw-r--r--Source/CTest/cmCTestSVN.cxx561
-rw-r--r--Source/CTest/cmCTestSVN.h105
-rw-r--r--Source/CTest/cmCTestScriptHandler.cxx987
-rw-r--r--Source/CTest/cmCTestScriptHandler.h172
-rw-r--r--Source/CTest/cmCTestSleepCommand.cxx49
-rw-r--r--Source/CTest/cmCTestSleepCommand.h54
-rw-r--r--Source/CTest/cmCTestStartCommand.cxx160
-rw-r--r--Source/CTest/cmCTestStartCommand.h70
-rw-r--r--Source/CTest/cmCTestSubmitCommand.cxx258
-rw-r--r--Source/CTest/cmCTestSubmitCommand.h88
-rw-r--r--Source/CTest/cmCTestSubmitHandler.cxx1529
-rw-r--r--Source/CTest/cmCTestSubmitHandler.h100
-rw-r--r--Source/CTest/cmCTestTestCommand.cxx121
-rw-r--r--Source/CTest/cmCTestTestCommand.h68
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx1991
-rw-r--r--Source/CTest/cmCTestTestHandler.h295
-rw-r--r--Source/CTest/cmCTestUpdateCommand.cxx96
-rw-r--r--Source/CTest/cmCTestUpdateCommand.h49
-rw-r--r--Source/CTest/cmCTestUpdateHandler.cxx376
-rw-r--r--Source/CTest/cmCTestUpdateHandler.h73
-rw-r--r--Source/CTest/cmCTestUploadCommand.cxx64
-rw-r--r--Source/CTest/cmCTestUploadCommand.h63
-rw-r--r--Source/CTest/cmCTestUploadHandler.cxx78
-rw-r--r--Source/CTest/cmCTestUploadHandler.h45
-rw-r--r--Source/CTest/cmCTestVC.cxx217
-rw-r--r--Source/CTest/cmCTestVC.h155
-rw-r--r--Source/CTest/cmParseBlanketJSCoverage.cxx148
-rw-r--r--Source/CTest/cmParseBlanketJSCoverage.h45
-rw-r--r--Source/CTest/cmParseCacheCoverage.cxx196
-rw-r--r--Source/CTest/cmParseCacheCoverage.h40
-rw-r--r--Source/CTest/cmParseCoberturaCoverage.cxx166
-rw-r--r--Source/CTest/cmParseCoberturaCoverage.h48
-rw-r--r--Source/CTest/cmParseDelphiCoverage.cxx225
-rw-r--r--Source/CTest/cmParseDelphiCoverage.h41
-rw-r--r--Source/CTest/cmParseGTMCoverage.cxx240
-rw-r--r--Source/CTest/cmParseGTMCoverage.h44
-rw-r--r--Source/CTest/cmParseJacocoCoverage.cxx179
-rw-r--r--Source/CTest/cmParseJacocoCoverage.h55
-rw-r--r--Source/CTest/cmParseMumpsCoverage.cxx144
-rw-r--r--Source/CTest/cmParseMumpsCoverage.h51
-rw-r--r--Source/CTest/cmParsePHPCoverage.cxx216
-rw-r--r--Source/CTest/cmParsePHPCoverage.h43
-rw-r--r--Source/CTest/cmProcess.cxx241
-rw-r--r--Source/CTest/cmProcess.h86
-rw-r--r--Source/Checks/cm_c11_thread_local.c5
-rw-r--r--Source/Checks/cm_c11_thread_local.cmake33
-rw-r--r--Source/Checks/cm_cxx14_cstdio.cmake33
-rw-r--r--Source/Checks/cm_cxx14_cstdio.cpp5
-rw-r--r--Source/Checks/cm_cxx_features.cmake39
-rw-r--r--Source/Checks/cm_cxx_nullptr.cxx14
-rw-r--r--Source/Checks/cm_cxx_override.cxx24
-rw-r--r--Source/Checks/cm_cxx_unordered_map.cxx7
-rw-r--r--Source/Checks/cm_cxx_unordered_set.cxx7
-rw-r--r--Source/CursesDialog/.NoDartCoverage1
-rw-r--r--Source/CursesDialog/CMakeLists.txt51
-rw-r--r--Source/CursesDialog/ccmake.cxx185
-rw-r--r--Source/CursesDialog/cmCursesBoolWidget.cxx58
-rw-r--r--Source/CursesDialog/cmCursesBoolWidget.h40
-rw-r--r--Source/CursesDialog/cmCursesCacheEntryComposite.cxx116
-rw-r--r--Source/CursesDialog/cmCursesCacheEntryComposite.h41
-rw-r--r--Source/CursesDialog/cmCursesDummyWidget.cxx24
-rw-r--r--Source/CursesDialog/cmCursesDummyWidget.h35
-rw-r--r--Source/CursesDialog/cmCursesFilePathWidget.cxx19
-rw-r--r--Source/CursesDialog/cmCursesFilePathWidget.h27
-rw-r--r--Source/CursesDialog/cmCursesForm.cxx54
-rw-r--r--Source/CursesDialog/cmCursesForm.h71
-rw-r--r--Source/CursesDialog/cmCursesLabelWidget.cxx32
-rw-r--r--Source/CursesDialog/cmCursesLabelWidget.h37
-rw-r--r--Source/CursesDialog/cmCursesLongMessageForm.cxx182
-rw-r--r--Source/CursesDialog/cmCursesLongMessageForm.h57
-rw-r--r--Source/CursesDialog/cmCursesMainForm.cxx1154
-rw-r--r--Source/CursesDialog/cmCursesMainForm.h166
-rw-r--r--Source/CursesDialog/cmCursesOptionsWidget.cxx93
-rw-r--r--Source/CursesDialog/cmCursesOptionsWidget.h41
-rw-r--r--Source/CursesDialog/cmCursesPathWidget.cxx86
-rw-r--r--Source/CursesDialog/cmCursesPathWidget.h40
-rw-r--r--Source/CursesDialog/cmCursesStandardIncludes.h45
-rw-r--r--Source/CursesDialog/cmCursesStringWidget.cxx205
-rw-r--r--Source/CursesDialog/cmCursesStringWidget.h76
-rw-r--r--Source/CursesDialog/cmCursesWidget.cxx53
-rw-r--r--Source/CursesDialog/cmCursesWidget.h78
-rw-r--r--Source/CursesDialog/form/.NoDartCoverage1
-rw-r--r--Source/CursesDialog/form/CMakeLists.txt66
-rw-r--r--Source/CursesDialog/form/READ.ME15
-rw-r--r--Source/CursesDialog/form/cmFormConfigure.h.in21
-rw-r--r--Source/CursesDialog/form/eti.h52
-rw-r--r--Source/CursesDialog/form/fld_arg.c91
-rw-r--r--Source/CursesDialog/form/fld_attr.c110
-rw-r--r--Source/CursesDialog/form/fld_current.c124
-rw-r--r--Source/CursesDialog/form/fld_def.c346
-rw-r--r--Source/CursesDialog/form/fld_dup.c97
-rw-r--r--Source/CursesDialog/form/fld_ftchoice.c62
-rw-r--r--Source/CursesDialog/form/fld_ftlink.c83
-rw-r--r--Source/CursesDialog/form/fld_info.c91
-rw-r--r--Source/CursesDialog/form/fld_just.c81
-rw-r--r--Source/CursesDialog/form/fld_link.c90
-rw-r--r--Source/CursesDialog/form/fld_max.c74
-rw-r--r--Source/CursesDialog/form/fld_move.c62
-rw-r--r--Source/CursesDialog/form/fld_newftyp.c125
-rw-r--r--Source/CursesDialog/form/fld_opts.c124
-rw-r--r--Source/CursesDialog/form/fld_pad.c78
-rw-r--r--Source/CursesDialog/form/fld_page.c76
-rw-r--r--Source/CursesDialog/form/fld_stat.c73
-rw-r--r--Source/CursesDialog/form/fld_type.c51
-rw-r--r--Source/CursesDialog/form/fld_user.c67
-rw-r--r--Source/CursesDialog/form/form.h411
-rw-r--r--Source/CursesDialog/form/form.priv.h128
-rw-r--r--Source/CursesDialog/form/frm_cursor.c66
-rw-r--r--Source/CursesDialog/form/frm_data.c183
-rw-r--r--Source/CursesDialog/form/frm_def.c376
-rw-r--r--Source/CursesDialog/form/frm_driver.c3883
-rw-r--r--Source/CursesDialog/form/frm_hook.c140
-rw-r--r--Source/CursesDialog/form/frm_opts.c116
-rw-r--r--Source/CursesDialog/form/frm_page.c100
-rw-r--r--Source/CursesDialog/form/frm_post.c119
-rw-r--r--Source/CursesDialog/form/frm_req_name.c163
-rw-r--r--Source/CursesDialog/form/frm_scale.c63
-rw-r--r--Source/CursesDialog/form/frm_sub.c69
-rw-r--r--Source/CursesDialog/form/frm_user.c67
-rw-r--r--Source/CursesDialog/form/frm_win.c70
-rw-r--r--Source/CursesDialog/form/fty_alnum.c138
-rw-r--r--Source/CursesDialog/form/fty_alpha.c139
-rw-r--r--Source/CursesDialog/form/fty_enum.c295
-rw-r--r--Source/CursesDialog/form/fty_int.c161
-rw-r--r--Source/CursesDialog/form/fty_ipv4.c84
-rw-r--r--Source/CursesDialog/form/fty_num.c192
-rw-r--r--Source/CursesDialog/form/fty_regex.c264
-rw-r--r--Source/CursesDialog/form/llib-lform694
-rw-r--r--Source/CursesDialog/form/mf_common.h93
-rw-r--r--Source/CursesDialog/form/nc_alloc.h83
-rw-r--r--Source/Modules/FindJsonCpp.cmake117
-rw-r--r--Source/QtDialog/AddCacheEntry.cxx108
-rw-r--r--Source/QtDialog/AddCacheEntry.h45
-rw-r--r--Source/QtDialog/AddCacheEntry.ui97
-rw-r--r--Source/QtDialog/CMake.desktop12
-rw-r--r--Source/QtDialog/CMakeLists.txt241
-rw-r--r--Source/QtDialog/CMakeSetup.cxx257
-rw-r--r--Source/QtDialog/CMakeSetup.icnsbin0 -> 138205 bytes
-rw-r--r--Source/QtDialog/CMakeSetup.icobin0 -> 24542 bytes
-rw-r--r--Source/QtDialog/CMakeSetup.qrc8
-rw-r--r--Source/QtDialog/CMakeSetup.rc1
-rw-r--r--Source/QtDialog/CMakeSetup128.pngbin0 -> 13269 bytes
-rw-r--r--Source/QtDialog/CMakeSetup32.pngbin0 -> 358 bytes
-rw-r--r--Source/QtDialog/CMakeSetupDialog.cxx1303
-rw-r--r--Source/QtDialog/CMakeSetupDialog.h148
-rw-r--r--Source/QtDialog/CMakeSetupDialog.ui313
-rw-r--r--Source/QtDialog/Compilers.h21
-rw-r--r--Source/QtDialog/Compilers.ui87
-rw-r--r--Source/QtDialog/CrossCompiler.ui213
-rw-r--r--Source/QtDialog/Delete16.pngbin0 -> 731 bytes
-rw-r--r--Source/QtDialog/FirstConfigure.cxx574
-rw-r--r--Source/QtDialog/FirstConfigure.h189
-rw-r--r--Source/QtDialog/Info.plist.in34
-rw-r--r--Source/QtDialog/Plus16.pngbin0 -> 358 bytes
-rw-r--r--Source/QtDialog/QCMake.cxx462
-rw-r--r--Source/QtDialog/QCMake.h184
-rw-r--r--Source/QtDialog/QCMakeCacheView.cxx687
-rw-r--r--Source/QtDialog/QCMakeCacheView.h180
-rw-r--r--Source/QtDialog/QCMakeWidgets.cxx128
-rw-r--r--Source/QtDialog/QCMakeWidgets.h89
-rw-r--r--Source/QtDialog/QtDialogCPack.cmake.in15
-rw-r--r--Source/QtDialog/RegexExplorer.cxx146
-rw-r--r--Source/QtDialog/RegexExplorer.h48
-rw-r--r--Source/QtDialog/RegexExplorer.ui155
-rw-r--r--Source/QtDialog/WarningMessagesDialog.cxx96
-rw-r--r--Source/QtDialog/WarningMessagesDialog.h75
-rw-r--r--Source/QtDialog/WarningMessagesDialog.ui173
-rw-r--r--Source/QtDialog/cmakecache.xml8
-rw-r--r--Source/QtIFW/CMake.Dialogs.QtGUI.qs21
-rw-r--r--Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in21
-rw-r--r--Source/QtIFW/CMake.qs.in22
-rw-r--r--Source/QtIFW/cmake.org.html7
-rw-r--r--Source/QtIFW/controlscript.qs6
-rw-r--r--Source/QtIFW/installscript.qs.in24
-rw-r--r--Source/bindexplib.cxx460
-rw-r--r--Source/bindexplib.h29
-rw-r--r--Source/cmAddCompileOptionsCommand.cxx26
-rw-r--r--Source/cmAddCompileOptionsCommand.h40
-rw-r--r--Source/cmAddCustomCommandCommand.cxx364
-rw-r--r--Source/cmAddCustomCommandCommand.h49
-rw-r--r--Source/cmAddCustomTargetCommand.cxx234
-rw-r--r--Source/cmAddCustomTargetCommand.h47
-rw-r--r--Source/cmAddDefinitionsCommand.cxx28
-rw-r--r--Source/cmAddDefinitionsCommand.h46
-rw-r--r--Source/cmAddDependenciesCommand.cxx50
-rw-r--r--Source/cmAddDependenciesCommand.h45
-rw-r--r--Source/cmAddExecutableCommand.cxx208
-rw-r--r--Source/cmAddExecutableCommand.h46
-rw-r--r--Source/cmAddLibraryCommand.cxx370
-rw-r--r--Source/cmAddLibraryCommand.h46
-rw-r--r--Source/cmAddSubDirectoryCommand.cxx111
-rw-r--r--Source/cmAddSubDirectoryCommand.h47
-rw-r--r--Source/cmAddTestCommand.cxx146
-rw-r--r--Source/cmAddTestCommand.h48
-rw-r--r--Source/cmAlgorithms.h397
-rw-r--r--Source/cmArchiveWrite.cxx340
-rw-r--r--Source/cmArchiveWrite.h184
-rw-r--r--Source/cmAuxSourceDirectoryCommand.cxx77
-rw-r--r--Source/cmAuxSourceDirectoryCommand.h49
-rw-r--r--Source/cmBootstrapCommands1.cxx96
-rw-r--r--Source/cmBootstrapCommands2.cxx103
-rw-r--r--Source/cmBreakCommand.cxx76
-rw-r--r--Source/cmBreakCommand.h50
-rw-r--r--Source/cmBuildCommand.cxx129
-rw-r--r--Source/cmBuildCommand.h58
-rw-r--r--Source/cmBuildNameCommand.cxx67
-rw-r--r--Source/cmBuildNameCommand.h28
-rw-r--r--Source/cmCLocaleEnvironmentScope.cxx62
-rw-r--r--Source/cmCLocaleEnvironmentScope.h32
-rw-r--r--Source/cmCMakeHostSystemInformationCommand.cxx103
-rw-r--r--Source/cmCMakeHostSystemInformationCommand.h67
-rw-r--r--Source/cmCMakeMinimumRequired.cxx117
-rw-r--r--Source/cmCMakeMinimumRequired.h54
-rw-r--r--Source/cmCMakePolicyCommand.cxx157
-rw-r--r--Source/cmCMakePolicyCommand.h56
-rw-r--r--Source/cmCPackPropertiesGenerator.cxx43
-rw-r--r--Source/cmCPackPropertiesGenerator.h39
-rw-r--r--Source/cmCPluginAPI.cxx852
-rw-r--r--Source/cmCPluginAPI.h234
-rw-r--r--Source/cmCTest.cxx2807
-rw-r--r--Source/cmCTest.h626
-rw-r--r--Source/cmCacheManager.cxx657
-rw-r--r--Source/cmCacheManager.h235
-rw-r--r--Source/cmCallVisualStudioMacro.cxx460
-rw-r--r--Source/cmCallVisualStudioMacro.h43
-rw-r--r--Source/cmCommand.h185
-rw-r--r--Source/cmCommandArgumentLexer.cxx2077
-rw-r--r--Source/cmCommandArgumentLexer.h333
-rw-r--r--Source/cmCommandArgumentLexer.in.l162
-rw-r--r--Source/cmCommandArgumentParser.cxx1829
-rw-r--r--Source/cmCommandArgumentParser.y240
-rw-r--r--Source/cmCommandArgumentParserHelper.cxx321
-rw-r--r--Source/cmCommandArgumentParserHelper.h109
-rw-r--r--Source/cmCommandArgumentParserTokens.h92
-rw-r--r--Source/cmCommandArgumentsHelper.cxx262
-rw-r--r--Source/cmCommandArgumentsHelper.h201
-rw-r--r--Source/cmCommands.cxx.in19
-rw-r--r--Source/cmCommands.h31
-rw-r--r--Source/cmCommandsForBootstrap.cxx16
-rw-r--r--Source/cmCommonTargetGenerator.cxx235
-rw-r--r--Source/cmCommonTargetGenerator.h81
-rw-r--r--Source/cmComputeComponentGraph.cxx142
-rw-r--r--Source/cmComputeComponentGraph.h87
-rw-r--r--Source/cmComputeLinkDepends.cxx859
-rw-r--r--Source/cmComputeLinkDepends.h177
-rw-r--r--Source/cmComputeLinkInformation.cxx1827
-rw-r--r--Source/cmComputeLinkInformation.h209
-rw-r--r--Source/cmComputeTargetDepends.cxx591
-rw-r--r--Source/cmComputeTargetDepends.h94
-rw-r--r--Source/cmConditionEvaluator.cxx727
-rw-r--r--Source/cmConditionEvaluator.h93
-rw-r--r--Source/cmConfigure.cmake.h.in51
-rw-r--r--Source/cmConfigureFileCommand.cxx117
-rw-r--r--Source/cmConfigureFileCommand.h53
-rw-r--r--Source/cmContinueCommand.cxx37
-rw-r--r--Source/cmContinueCommand.h50
-rw-r--r--Source/cmCoreTryCompile.cxx695
-rw-r--r--Source/cmCoreTryCompile.h57
-rw-r--r--Source/cmCreateTestSourceList.cxx163
-rw-r--r--Source/cmCreateTestSourceList.h45
-rw-r--r--Source/cmCryptoHash.cxx123
-rw-r--r--Source/cmCryptoHash.h70
-rw-r--r--Source/cmCurl.cxx62
-rw-r--r--Source/cmCurl.h21
-rw-r--r--Source/cmCustomCommand.cxx137
-rw-r--r--Source/cmCustomCommand.h106
-rw-r--r--Source/cmCustomCommandGenerator.cxx162
-rw-r--r--Source/cmCustomCommandGenerator.h48
-rw-r--r--Source/cmCustomCommandLines.h38
-rw-r--r--Source/cmDefinePropertyCommand.cxx108
-rw-r--r--Source/cmDefinePropertyCommand.h42
-rw-r--r--Source/cmDefinitions.cxx125
-rw-r--r--Source/cmDefinitions.h109
-rw-r--r--Source/cmDepends.cxx282
-rw-r--r--Source/cmDepends.h127
-rw-r--r--Source/cmDependsC.cxx495
-rw-r--r--Source/cmDependsC.h102
-rw-r--r--Source/cmDependsFortran.cxx701
-rw-r--r--Source/cmDependsFortran.h85
-rw-r--r--Source/cmDependsJava.cxx42
-rw-r--r--Source/cmDependsJava.h44
-rw-r--r--Source/cmDependsJavaLexer.cxx2542
-rw-r--r--Source/cmDependsJavaLexer.h334
-rw-r--r--Source/cmDependsJavaLexer.in.l189
-rw-r--r--Source/cmDependsJavaParser.cxx6015
-rw-r--r--Source/cmDependsJavaParser.y3221
-rw-r--r--Source/cmDependsJavaParserHelper.cxx352
-rw-r--r--Source/cmDependsJavaParserHelper.h103
-rw-r--r--Source/cmDependsJavaParserTokens.h254
-rw-r--r--Source/cmDocumentation.cxx772
-rw-r--r--Source/cmDocumentation.h141
-rw-r--r--Source/cmDocumentationEntry.h45
-rw-r--r--Source/cmDocumentationFormatter.cxx197
-rw-r--r--Source/cmDocumentationFormatter.h73
-rw-r--r--Source/cmDocumentationSection.cxx37
-rw-r--r--Source/cmDocumentationSection.h73
-rw-r--r--Source/cmDynamicLoader.cxx104
-rw-r--r--Source/cmDynamicLoader.h46
-rw-r--r--Source/cmELF.cxx916
-rw-r--r--Source/cmELF.h105
-rw-r--r--Source/cmElseCommand.cxx21
-rw-r--r--Source/cmElseCommand.h50
-rw-r--r--Source/cmElseIfCommand.cxx20
-rw-r--r--Source/cmElseIfCommand.h50
-rw-r--r--Source/cmEnableLanguageCommand.cxx35
-rw-r--r--Source/cmEnableLanguageCommand.h48
-rw-r--r--Source/cmEnableTestingCommand.cxx21
-rw-r--r--Source/cmEnableTestingCommand.h53
-rw-r--r--Source/cmEndForEachCommand.cxx21
-rw-r--r--Source/cmEndForEachCommand.h60
-rw-r--r--Source/cmEndFunctionCommand.cxx21
-rw-r--r--Source/cmEndFunctionCommand.h60
-rw-r--r--Source/cmEndIfCommand.cxx28
-rw-r--r--Source/cmEndIfCommand.h50
-rw-r--r--Source/cmEndMacroCommand.cxx21
-rw-r--r--Source/cmEndMacroCommand.h60
-rw-r--r--Source/cmEndWhileCommand.cxx27
-rw-r--r--Source/cmEndWhileCommand.h60
-rw-r--r--Source/cmExecProgramCommand.cxx279
-rw-r--r--Source/cmExecProgramCommand.h57
-rw-r--r--Source/cmExecuteProcessCommand.cxx337
-rw-r--r--Source/cmExecuteProcessCommand.h51
-rw-r--r--Source/cmExecutionStatus.h53
-rw-r--r--Source/cmExpandedCommandArgument.cxx50
-rw-r--r--Source/cmExpandedCommandArgument.h45
-rw-r--r--Source/cmExportBuildFileGenerator.cxx296
-rw-r--r--Source/cmExportBuildFileGenerator.h84
-rw-r--r--Source/cmExportCommand.cxx357
-rw-r--r--Source/cmExportCommand.h72
-rw-r--r--Source/cmExportFileGenerator.cxx1091
-rw-r--r--Source/cmExportFileGenerator.h205
-rw-r--r--Source/cmExportInstallFileGenerator.cxx481
-rw-r--r--Source/cmExportInstallFileGenerator.h93
-rw-r--r--Source/cmExportLibraryDependenciesCommand.cxx182
-rw-r--r--Source/cmExportLibraryDependenciesCommand.h41
-rw-r--r--Source/cmExportSet.cxx40
-rw-r--r--Source/cmExportSet.h57
-rw-r--r--Source/cmExportSetMap.cxx37
-rw-r--r--Source/cmExportSetMap.h38
-rw-r--r--Source/cmExportTryCompileFileGenerator.cxx132
-rw-r--r--Source/cmExportTryCompileFileGenerator.h59
-rw-r--r--Source/cmExprLexer.cxx1928
-rw-r--r--Source/cmExprLexer.h334
-rw-r--r--Source/cmExprLexer.in.l74
-rw-r--r--Source/cmExprParser.cxx1427
-rw-r--r--Source/cmExprParser.y164
-rw-r--r--Source/cmExprParserHelper.cxx101
-rw-r--r--Source/cmExprParserHelper.h69
-rw-r--r--Source/cmExprParserTokens.h76
-rw-r--r--Source/cmExternalMakefileProjectGenerator.cxx60
-rw-r--r--Source/cmExternalMakefileProjectGenerator.h76
-rw-r--r--Source/cmExtraCodeBlocksGenerator.cxx774
-rw-r--r--Source/cmExtraCodeBlocksGenerator.h70
-rw-r--r--Source/cmExtraCodeLiteGenerator.cxx483
-rw-r--r--Source/cmExtraCodeLiteGenerator.h59
-rw-r--r--Source/cmExtraEclipseCDT4Generator.cxx1184
-rw-r--r--Source/cmExtraEclipseCDT4Generator.h122
-rw-r--r--Source/cmExtraKateGenerator.cxx318
-rw-r--r--Source/cmExtraKateGenerator.h63
-rw-r--r--Source/cmExtraSublimeTextGenerator.cxx371
-rw-r--r--Source/cmExtraSublimeTextGenerator.h85
-rw-r--r--Source/cmFLTKWrapUICommand.cxx124
-rw-r--r--Source/cmFLTKWrapUICommand.h67
-rw-r--r--Source/cmFileCommand.cxx3223
-rw-r--r--Source/cmFileCommand.h83
-rw-r--r--Source/cmFileLock.cxx70
-rw-r--r--Source/cmFileLock.h74
-rw-r--r--Source/cmFileLockPool.cxx169
-rw-r--r--Source/cmFileLockPool.h100
-rw-r--r--Source/cmFileLockResult.cxx101
-rw-r--r--Source/cmFileLockResult.h85
-rw-r--r--Source/cmFileLockUnix.cxx91
-rw-r--r--Source/cmFileLockWin32.cxx98
-rw-r--r--Source/cmFileTimeComparison.cxx263
-rw-r--r--Source/cmFileTimeComparison.h48
-rw-r--r--Source/cmFindBase.cxx333
-rw-r--r--Source/cmFindBase.h66
-rw-r--r--Source/cmFindCommon.cxx353
-rw-r--r--Source/cmFindCommon.h136
-rw-r--r--Source/cmFindFileCommand.cxx19
-rw-r--r--Source/cmFindFileCommand.h38
-rw-r--r--Source/cmFindLibraryCommand.cxx477
-rw-r--r--Source/cmFindLibraryCommand.h68
-rw-r--r--Source/cmFindPackageCommand.cxx2065
-rw-r--r--Source/cmFindPackageCommand.h182
-rw-r--r--Source/cmFindPathCommand.cxx162
-rw-r--r--Source/cmFindPathCommand.h61
-rw-r--r--Source/cmFindProgramCommand.cxx267
-rw-r--r--Source/cmFindProgramCommand.h62
-rw-r--r--Source/cmForEachCommand.cxx221
-rw-r--r--Source/cmForEachCommand.h69
-rw-r--r--Source/cmFortranLexer.cxx2431
-rw-r--r--Source/cmFortranLexer.h352
-rw-r--r--Source/cmFortranLexer.in.l191
-rw-r--r--Source/cmFortranParser.cxx1916
-rw-r--r--Source/cmFortranParser.h160
-rw-r--r--Source/cmFortranParser.y287
-rw-r--r--Source/cmFortranParserImpl.cxx359
-rw-r--r--Source/cmFortranParserTokens.h131
-rw-r--r--Source/cmFunctionBlocker.h55
-rw-r--r--Source/cmFunctionCommand.cxx215
-rw-r--r--Source/cmFunctionCommand.h62
-rw-r--r--Source/cmGeneratedFileStream.cxx223
-rw-r--r--Source/cmGeneratedFileStream.h146
-rw-r--r--Source/cmGeneratorExpression.cxx392
-rw-r--r--Source/cmGeneratorExpression.h167
-rw-r--r--Source/cmGeneratorExpressionContext.cxx34
-rw-r--r--Source/cmGeneratorExpressionContext.h55
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.cxx225
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.h94
-rw-r--r--Source/cmGeneratorExpressionEvaluationFile.cxx163
-rw-r--r--Source/cmGeneratorExpressionEvaluationFile.h50
-rw-r--r--Source/cmGeneratorExpressionEvaluator.cxx211
-rw-r--r--Source/cmGeneratorExpressionEvaluator.h121
-rw-r--r--Source/cmGeneratorExpressionLexer.cxx75
-rw-r--r--Source/cmGeneratorExpressionLexer.h60
-rw-r--r--Source/cmGeneratorExpressionNode.cxx1708
-rw-r--r--Source/cmGeneratorExpressionNode.h67
-rw-r--r--Source/cmGeneratorExpressionParser.cxx261
-rw-r--r--Source/cmGeneratorExpressionParser.h41
-rw-r--r--Source/cmGeneratorTarget.cxx5189
-rw-r--r--Source/cmGeneratorTarget.h727
-rw-r--r--Source/cmGetCMakePropertyCommand.cxx57
-rw-r--r--Source/cmGetCMakePropertyCommand.h42
-rw-r--r--Source/cmGetDirectoryPropertyCommand.cxx107
-rw-r--r--Source/cmGetDirectoryPropertyCommand.h45
-rw-r--r--Source/cmGetFilenameComponentCommand.cxx115
-rw-r--r--Source/cmGetFilenameComponentCommand.h51
-rw-r--r--Source/cmGetPropertyCommand.cxx357
-rw-r--r--Source/cmGetPropertyCommand.h71
-rw-r--r--Source/cmGetSourceFilePropertyCommand.cxx49
-rw-r--r--Source/cmGetSourceFilePropertyCommand.h40
-rw-r--r--Source/cmGetTargetPropertyCommand.cxx71
-rw-r--r--Source/cmGetTargetPropertyCommand.h37
-rw-r--r--Source/cmGetTestPropertyCommand.cxx41
-rw-r--r--Source/cmGetTestPropertyCommand.h37
-rw-r--r--Source/cmGhsMultiGpj.cxx43
-rw-r--r--Source/cmGhsMultiGpj.h36
-rw-r--r--Source/cmGhsMultiTargetGenerator.cxx662
-rw-r--r--Source/cmGhsMultiTargetGenerator.h129
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.cxx60
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.h56
-rw-r--r--Source/cmGlobalCommonGenerator.cxx21
-rw-r--r--Source/cmGlobalCommonGenerator.h27
-rw-r--r--Source/cmGlobalGenerator.cxx2818
-rw-r--r--Source/cmGlobalGenerator.h551
-rw-r--r--Source/cmGlobalGeneratorFactory.h76
-rw-r--r--Source/cmGlobalGhsMultiGenerator.cxx499
-rw-r--r--Source/cmGlobalGhsMultiGenerator.h136
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.cxx61
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.h54
-rw-r--r--Source/cmGlobalKdevelopGenerator.cxx602
-rw-r--r--Source/cmGlobalKdevelopGenerator.h97
-rw-r--r--Source/cmGlobalMSYSMakefileGenerator.cxx94
-rw-r--r--Source/cmGlobalMSYSMakefileGenerator.h52
-rw-r--r--Source/cmGlobalMinGWMakefileGenerator.cxx63
-rw-r--r--Source/cmGlobalMinGWMakefileGenerator.h49
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.cxx61
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.h53
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx1306
-rw-r--r--Source/cmGlobalNinjaGenerator.h418
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.cxx996
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.h246
-rw-r--r--Source/cmGlobalVisualStudio10Generator.cxx543
-rw-r--r--Source/cmGlobalVisualStudio10Generator.h148
-rw-r--r--Source/cmGlobalVisualStudio11Generator.cxx285
-rw-r--r--Source/cmGlobalVisualStudio11Generator.h55
-rw-r--r--Source/cmGlobalVisualStudio12Generator.cxx216
-rw-r--r--Source/cmGlobalVisualStudio12Generator.h51
-rw-r--r--Source/cmGlobalVisualStudio14Generator.cxx263
-rw-r--r--Source/cmGlobalVisualStudio14Generator.h51
-rw-r--r--Source/cmGlobalVisualStudio71Generator.cxx289
-rw-r--r--Source/cmGlobalVisualStudio71Generator.h83
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx725
-rw-r--r--Source/cmGlobalVisualStudio7Generator.h179
-rw-r--r--Source/cmGlobalVisualStudio8Generator.cxx478
-rw-r--r--Source/cmGlobalVisualStudio8Generator.h110
-rw-r--r--Source/cmGlobalVisualStudio9Generator.cxx142
-rw-r--r--Source/cmGlobalVisualStudio9Generator.h54
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx851
-rw-r--r--Source/cmGlobalVisualStudioGenerator.h187
-rw-r--r--Source/cmGlobalWatcomWMakeGenerator.cxx56
-rw-r--r--Source/cmGlobalWatcomWMakeGenerator.h51
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx3490
-rw-r--r--Source/cmGlobalXCodeGenerator.h257
-rw-r--r--Source/cmGraphAdjacencyList.h62
-rw-r--r--Source/cmGraphVizWriter.cxx512
-rw-r--r--Source/cmGraphVizWriter.h91
-rw-r--r--Source/cmHexFileConverter.cxx224
-rw-r--r--Source/cmHexFileConverter.h35
-rw-r--r--Source/cmIDEFlagTable.h42
-rw-r--r--Source/cmIDEOptions.cxx199
-rw-r--r--Source/cmIDEOptions.h90
-rw-r--r--Source/cmIfCommand.cxx209
-rw-r--r--Source/cmIfCommand.h82
-rw-r--r--Source/cmIncludeCommand.cxx138
-rw-r--r--Source/cmIncludeCommand.h51
-rw-r--r--Source/cmIncludeDirectoryCommand.cxx136
-rw-r--r--Source/cmIncludeDirectoryCommand.h51
-rw-r--r--Source/cmIncludeExternalMSProjectCommand.cxx101
-rw-r--r--Source/cmIncludeExternalMSProjectCommand.h53
-rw-r--r--Source/cmIncludeRegularExpressionCommand.cxx29
-rw-r--r--Source/cmIncludeRegularExpressionCommand.h52
-rw-r--r--Source/cmInstallCommand.cxx1261
-rw-r--r--Source/cmInstallCommand.h59
-rw-r--r--Source/cmInstallCommandArguments.cxx216
-rw-r--r--Source/cmInstallCommandArguments.h86
-rw-r--r--Source/cmInstallDirectoryGenerator.cxx97
-rw-r--r--Source/cmInstallDirectoryGenerator.h52
-rw-r--r--Source/cmInstallExportGenerator.cxx206
-rw-r--r--Source/cmInstallExportGenerator.h69
-rw-r--r--Source/cmInstallFilesCommand.cxx154
-rw-r--r--Source/cmInstallFilesCommand.h65
-rw-r--r--Source/cmInstallFilesGenerator.cxx98
-rw-r--r--Source/cmInstallFilesGenerator.h53
-rw-r--r--Source/cmInstallGenerator.cxx200
-rw-r--r--Source/cmInstallGenerator.h74
-rw-r--r--Source/cmInstallProgramsCommand.cxx124
-rw-r--r--Source/cmInstallProgramsCommand.h64
-rw-r--r--Source/cmInstallScriptGenerator.cxx43
-rw-r--r--Source/cmInstallScriptGenerator.h33
-rw-r--r--Source/cmInstallTargetGenerator.cxx780
-rw-r--r--Source/cmInstallTargetGenerator.h111
-rw-r--r--Source/cmInstallTargetsCommand.cxx55
-rw-r--r--Source/cmInstallTargetsCommand.h47
-rw-r--r--Source/cmInstallType.h29
-rw-r--r--Source/cmInstalledFile.cxx126
-rw-r--r--Source/cmInstalledFile.h75
-rw-r--r--Source/cmLinkDirectoriesCommand.cxx65
-rw-r--r--Source/cmLinkDirectoriesCommand.h51
-rw-r--r--Source/cmLinkItem.h175
-rw-r--r--Source/cmLinkLibrariesCommand.cxx47
-rw-r--r--Source/cmLinkLibrariesCommand.h47
-rw-r--r--Source/cmLinkedTree.h200
-rw-r--r--Source/cmListCommand.cxx546
-rw-r--r--Source/cmListCommand.h68
-rw-r--r--Source/cmListFileCache.cxx453
-rw-r--r--Source/cmListFileCache.h166
-rw-r--r--Source/cmListFileLexer.c2698
-rw-r--r--Source/cmListFileLexer.h73
-rw-r--r--Source/cmListFileLexer.in.l572
-rw-r--r--Source/cmLoadCacheCommand.cxx166
-rw-r--r--Source/cmLoadCacheCommand.h52
-rw-r--r--Source/cmLoadCommandCommand.cxx265
-rw-r--r--Source/cmLoadCommandCommand.h27
-rw-r--r--Source/cmLocalCommonGenerator.cxx84
-rw-r--r--Source/cmLocalCommonGenerator.h48
-rw-r--r--Source/cmLocalGenerator.cxx2803
-rw-r--r--Source/cmLocalGenerator.h418
-rw-r--r--Source/cmLocalGhsMultiGenerator.cxx42
-rw-r--r--Source/cmLocalGhsMultiGenerator.h38
-rw-r--r--Source/cmLocalNinjaGenerator.cxx504
-rw-r--r--Source/cmLocalNinjaGenerator.h116
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx2087
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.h321
-rw-r--r--Source/cmLocalVisualStudio10Generator.cxx111
-rw-r--r--Source/cmLocalVisualStudio10Generator.h44
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx2152
-rw-r--r--Source/cmLocalVisualStudio7Generator.h139
-rw-r--r--Source/cmLocalVisualStudioGenerator.cxx234
-rw-r--r--Source/cmLocalVisualStudioGenerator.h67
-rw-r--r--Source/cmLocalXCodeGenerator.cxx92
-rw-r--r--Source/cmLocalXCodeGenerator.h43
-rw-r--r--Source/cmLocale.h32
-rw-r--r--Source/cmMachO.cxx370
-rw-r--r--Source/cmMachO.h51
-rw-r--r--Source/cmMacroCommand.cxx249
-rw-r--r--Source/cmMacroCommand.h62
-rw-r--r--Source/cmMakeDirectoryCommand.cxx31
-rw-r--r--Source/cmMakeDirectoryCommand.h54
-rw-r--r--Source/cmMakefile.cxx4539
-rw-r--r--Source/cmMakefile.h960
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx443
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.h31
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx774
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.h41
-rw-r--r--Source/cmMakefileTargetGenerator.cxx1597
-rw-r--r--Source/cmMakefileTargetGenerator.h244
-rw-r--r--Source/cmMakefileUtilityTargetGenerator.cxx114
-rw-r--r--Source/cmMakefileUtilityTargetGenerator.h30
-rw-r--r--Source/cmMarkAsAdvancedCommand.cxx50
-rw-r--r--Source/cmMarkAsAdvancedCommand.h53
-rw-r--r--Source/cmMathCommand.cxx55
-rw-r--r--Source/cmMathCommand.h49
-rw-r--r--Source/cmMessageCommand.cxx81
-rw-r--r--Source/cmMessageCommand.h49
-rw-r--r--Source/cmNewLineStyle.cxx76
-rw-r--r--Source/cmNewLineStyle.h45
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx729
-rw-r--r--Source/cmNinjaNormalTargetGenerator.h53
-rw-r--r--Source/cmNinjaTargetGenerator.cxx745
-rw-r--r--Source/cmNinjaTargetGenerator.h164
-rw-r--r--Source/cmNinjaTypes.h21
-rw-r--r--Source/cmNinjaUtilityTargetGenerator.cxx149
-rw-r--r--Source/cmNinjaUtilityTargetGenerator.h31
-rw-r--r--Source/cmOSXBundleGenerator.cxx228
-rw-r--r--Source/cmOSXBundleGenerator.h71
-rw-r--r--Source/cmObject.h48
-rw-r--r--Source/cmOptionCommand.cxx57
-rw-r--r--Source/cmOptionCommand.h50
-rw-r--r--Source/cmOrderDirectories.cxx573
-rw-r--r--Source/cmOrderDirectories.h97
-rw-r--r--Source/cmOutputConverter.cxx726
-rw-r--r--Source/cmOutputConverter.h177
-rw-r--r--Source/cmOutputRequiredFilesCommand.cxx557
-rw-r--r--Source/cmOutputRequiredFilesCommand.h36
-rw-r--r--Source/cmParseArgumentsCommand.cxx174
-rw-r--r--Source/cmParseArgumentsCommand.h49
-rw-r--r--Source/cmPathLabel.cxx38
-rw-r--r--Source/cmPathLabel.h44
-rw-r--r--Source/cmPolicies.cxx349
-rw-r--r--Source/cmPolicies.h301
-rw-r--r--Source/cmProcessTools.cxx78
-rw-r--r--Source/cmProcessTools.h90
-rw-r--r--Source/cmProjectCommand.cxx216
-rw-r--r--Source/cmProjectCommand.h48
-rw-r--r--Source/cmProperty.cxx37
-rw-r--r--Source/cmProperty.h50
-rw-r--r--Source/cmPropertyDefinition.cxx31
-rw-r--r--Source/cmPropertyDefinition.h63
-rw-r--r--Source/cmPropertyDefinitionMap.cxx45
-rw-r--r--Source/cmPropertyDefinitionMap.h35
-rw-r--r--Source/cmPropertyMap.cxx76
-rw-r--r--Source/cmPropertyMap.h32
-rw-r--r--Source/cmQTWrapCPPCommand.cxx93
-rw-r--r--Source/cmQTWrapCPPCommand.h48
-rw-r--r--Source/cmQTWrapUICommand.cxx137
-rw-r--r--Source/cmQTWrapUICommand.h46
-rw-r--r--Source/cmQtAutoGeneratorInitializer.cxx1001
-rw-r--r--Source/cmQtAutoGeneratorInitializer.h36
-rw-r--r--Source/cmQtAutoGenerators.cxx1491
-rw-r--r--Source/cmQtAutoGenerators.h149
-rw-r--r--Source/cmRST.cxx424
-rw-r--r--Source/cmRST.h102
-rw-r--r--Source/cmRemoveCommand.cxx64
-rw-r--r--Source/cmRemoveCommand.h50
-rw-r--r--Source/cmRemoveDefinitionsCommand.cxx28
-rw-r--r--Source/cmRemoveDefinitionsCommand.h47
-rw-r--r--Source/cmReturnCommand.cxx20
-rw-r--r--Source/cmReturnCommand.h50
-rw-r--r--Source/cmScriptGenerator.cxx197
-rw-r--r--Source/cmScriptGenerator.h99
-rw-r--r--Source/cmSearchPath.cxx228
-rw-r--r--Source/cmSearchPath.h57
-rw-r--r--Source/cmSeparateArgumentsCommand.cxx100
-rw-r--r--Source/cmSeparateArgumentsCommand.h50
-rw-r--r--Source/cmSetCommand.cxx145
-rw-r--r--Source/cmSetCommand.h50
-rw-r--r--Source/cmSetDirectoryPropertiesCommand.cxx56
-rw-r--r--Source/cmSetDirectoryPropertiesCommand.h56
-rw-r--r--Source/cmSetPropertyCommand.cxx437
-rw-r--r--Source/cmSetPropertyCommand.h66
-rw-r--r--Source/cmSetSourceFilesPropertiesCommand.cxx130
-rw-r--r--Source/cmSetSourceFilesPropertiesCommand.h50
-rw-r--r--Source/cmSetTargetPropertiesCommand.cxx85
-rw-r--r--Source/cmSetTargetPropertiesCommand.h44
-rw-r--r--Source/cmSetTestsPropertiesCommand.cxx84
-rw-r--r--Source/cmSetTestsPropertiesCommand.h41
-rw-r--r--Source/cmSiteNameCommand.cxx83
-rw-r--r--Source/cmSiteNameCommand.h50
-rw-r--r--Source/cmSourceFile.cxx336
-rw-r--r--Source/cmSourceFile.h127
-rw-r--r--Source/cmSourceFileLocation.cxx256
-rw-r--r--Source/cmSourceFileLocation.h102
-rw-r--r--Source/cmSourceGroup.cxx173
-rw-r--r--Source/cmSourceGroup.h134
-rw-r--r--Source/cmSourceGroupCommand.cxx85
-rw-r--r--Source/cmSourceGroupCommand.h46
-rw-r--r--Source/cmStandardIncludes.h63
-rw-r--r--Source/cmStandardLexer.h48
-rw-r--r--Source/cmState.cxx1830
-rw-r--r--Source/cmState.h363
-rw-r--r--Source/cmStringCommand.cxx902
-rw-r--r--Source/cmStringCommand.h101
-rw-r--r--Source/cmSubdirCommand.cxx62
-rw-r--r--Source/cmSubdirCommand.h47
-rw-r--r--Source/cmSubdirDependsCommand.cxx21
-rw-r--r--Source/cmSubdirDependsCommand.h27
-rw-r--r--Source/cmSystemTools.cxx2642
-rw-r--r--Source/cmSystemTools.h491
-rw-r--r--Source/cmTarget.cxx1640
-rw-r--r--Source/cmTarget.h350
-rw-r--r--Source/cmTargetCompileDefinitionsCommand.cxx63
-rw-r--r--Source/cmTargetCompileDefinitionsCommand.h56
-rw-r--r--Source/cmTargetCompileFeaturesCommand.cxx59
-rw-r--r--Source/cmTargetCompileFeaturesCommand.h38
-rw-r--r--Source/cmTargetCompileOptionsCommand.cxx52
-rw-r--r--Source/cmTargetCompileOptionsCommand.h50
-rw-r--r--Source/cmTargetDepend.h61
-rw-r--r--Source/cmTargetExport.h43
-rw-r--r--Source/cmTargetIncludeDirectoriesCommand.cxx98
-rw-r--r--Source/cmTargetIncludeDirectoriesCommand.h60
-rw-r--r--Source/cmTargetLinkLibrariesCommand.cxx423
-rw-r--r--Source/cmTargetLinkLibrariesCommand.h67
-rw-r--r--Source/cmTargetLinkLibraryType.h22
-rw-r--r--Source/cmTargetPropCommandBase.cxx148
-rw-r--r--Source/cmTargetPropCommandBase.h61
-rw-r--r--Source/cmTargetSourcesCommand.cxx49
-rw-r--r--Source/cmTargetSourcesCommand.h51
-rw-r--r--Source/cmTest.cxx72
-rw-r--r--Source/cmTest.h71
-rw-r--r--Source/cmTestGenerator.cxx187
-rw-r--r--Source/cmTestGenerator.h51
-rw-r--r--Source/cmTimestamp.cxx170
-rw-r--r--Source/cmTimestamp.h45
-rw-r--r--Source/cmTryCompileCommand.cxx39
-rw-r--r--Source/cmTryCompileCommand.h45
-rw-r--r--Source/cmTryRunCommand.cxx360
-rw-r--r--Source/cmTryRunCommand.h58
-rw-r--r--Source/cmTypeMacro.h40
-rw-r--r--Source/cmUnsetCommand.cxx58
-rw-r--r--Source/cmUnsetCommand.h50
-rw-r--r--Source/cmUseMangledMesaCommand.cxx118
-rw-r--r--Source/cmUseMangledMesaCommand.h30
-rw-r--r--Source/cmUtilitySourceCommand.cxx119
-rw-r--r--Source/cmUtilitySourceCommand.h27
-rw-r--r--Source/cmUuid.cxx192
-rw-r--r--Source/cmUuid.h55
-rw-r--r--Source/cmVS10CLFlagTable.h204
-rw-r--r--Source/cmVS10LibFlagTable.h76
-rw-r--r--Source/cmVS10LinkFlagTable.h244
-rw-r--r--Source/cmVS10MASMFlagTable.h78
-rw-r--r--Source/cmVS10RCFlagTable.h6
-rw-r--r--Source/cmVS11CLFlagTable.h219
-rw-r--r--Source/cmVS11LibFlagTable.h76
-rw-r--r--Source/cmVS11LinkFlagTable.h269
-rw-r--r--Source/cmVS11MASMFlagTable.h78
-rw-r--r--Source/cmVS11RCFlagTable.h6
-rw-r--r--Source/cmVS12CLFlagTable.h221
-rw-r--r--Source/cmVS12LibFlagTable.h76
-rw-r--r--Source/cmVS12LinkFlagTable.h269
-rw-r--r--Source/cmVS12MASMFlagTable.h78
-rw-r--r--Source/cmVS12RCFlagTable.h6
-rw-r--r--Source/cmVS14CLFlagTable.h237
-rw-r--r--Source/cmVS14LibFlagTable.h76
-rw-r--r--Source/cmVS14LinkFlagTable.h271
-rw-r--r--Source/cmVS14MASMFlagTable.h78
-rw-r--r--Source/cmVS14RCFlagTable.h6
-rw-r--r--Source/cmVariableRequiresCommand.cxx74
-rw-r--r--Source/cmVariableRequiresCommand.h27
-rw-r--r--Source/cmVariableWatch.cxx104
-rw-r--r--Source/cmVariableWatch.h94
-rw-r--r--Source/cmVariableWatchCommand.cxx137
-rw-r--r--Source/cmVariableWatchCommand.h62
-rw-r--r--Source/cmVersion.cxx36
-rw-r--r--Source/cmVersion.h43
-rw-r--r--Source/cmVersionConfig.h.in15
-rw-r--r--Source/cmVersionMacros.h22
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx3383
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h169
-rw-r--r--Source/cmVisualStudioGeneratorOptions.cxx339
-rw-r--r--Source/cmVisualStudioGeneratorOptions.h85
-rw-r--r--Source/cmVisualStudioSlnData.cxx58
-rw-r--r--Source/cmVisualStudioSlnData.h59
-rw-r--r--Source/cmVisualStudioSlnParser.cxx637
-rw-r--r--Source/cmVisualStudioSlnParser.h110
-rw-r--r--Source/cmVisualStudioWCEPlatformParser.cxx148
-rw-r--r--Source/cmVisualStudioWCEPlatformParser.h74
-rw-r--r--Source/cmWhileCommand.cxx147
-rw-r--r--Source/cmWhileCommand.h76
-rw-r--r--Source/cmWriteFileCommand.cxx84
-rw-r--r--Source/cmWriteFileCommand.h49
-rw-r--r--Source/cmXCode21Object.cxx96
-rw-r--r--Source/cmXCode21Object.h26
-rw-r--r--Source/cmXCodeObject.cxx263
-rw-r--r--Source/cmXCodeObject.h175
-rw-r--r--Source/cmXMLParser.cxx209
-rw-r--r--Source/cmXMLParser.h118
-rw-r--r--Source/cmXMLSafe.cxx101
-rw-r--r--Source/cmXMLSafe.h46
-rw-r--r--Source/cmXMLWriter.cxx143
-rw-r--r--Source/cmXMLWriter.h125
-rw-r--r--Source/cm_auto_ptr.hxx221
-rw-r--r--Source/cm_get_date.c16
-rw-r--r--Source/cm_get_date.h28
-rw-r--r--Source/cm_sha2.c1613
-rw-r--r--Source/cm_sha2.h140
-rw-r--r--Source/cm_sha2_mangle.h51
-rw-r--r--Source/cm_utf8.c86
-rw-r--r--Source/cm_utf8.h29
-rw-r--r--Source/cmake.cxx2560
-rw-r--r--Source/cmake.h600
-rw-r--r--Source/cmake.version.manifest18
-rw-r--r--Source/cmakemain.cxx399
-rw-r--r--Source/cmakexbuild.cxx80
-rw-r--r--Source/cmcldeps.cxx310
-rw-r--r--Source/cmcmd.cxx1539
-rw-r--r--Source/cmcmd.h39
-rwxr-xr-xSource/cmparseMSBuildXML.py338
-rw-r--r--Source/ctest.cxx190
-rw-r--r--Source/kwsys/.gitattributes12
-rw-r--r--Source/kwsys/Base64.c279
-rw-r--r--Source/kwsys/Base64.h.in122
-rw-r--r--Source/kwsys/CMakeLists.txt1038
-rw-r--r--Source/kwsys/CONTRIBUTING.rst35
-rw-r--r--Source/kwsys/CTestConfig.cmake17
-rw-r--r--Source/kwsys/CTestCustom.cmake.in14
-rw-r--r--Source/kwsys/CommandLineArguments.cxx857
-rw-r--r--Source/kwsys/CommandLineArguments.hxx.in276
-rw-r--r--Source/kwsys/Configure.h.in136
-rw-r--r--Source/kwsys/Configure.hxx.in31
-rw-r--r--Source/kwsys/Copyright.txt31
-rw-r--r--Source/kwsys/Directory.cxx260
-rw-r--r--Source/kwsys/Directory.hxx.in81
-rw-r--r--Source/kwsys/DynamicLoader.cxx531
-rw-r--r--Source/kwsys/DynamicLoader.hxx.in102
-rw-r--r--Source/kwsys/Encoding.h.in79
-rw-r--r--Source/kwsys/Encoding.hxx.in77
-rw-r--r--Source/kwsys/EncodingC.c85
-rw-r--r--Source/kwsys/EncodingCXX.cxx185
-rw-r--r--Source/kwsys/ExtraTest.cmake.in1
-rw-r--r--Source/kwsys/FStream.cxx78
-rw-r--r--Source/kwsys/FStream.hxx.in194
-rw-r--r--Source/kwsys/Glob.cxx559
-rw-r--r--Source/kwsys/Glob.hxx.in152
-rw-r--r--Source/kwsys/IOStream.cxx250
-rw-r--r--Source/kwsys/IOStream.hxx.in136
-rw-r--r--Source/kwsys/MD5.c523
-rw-r--r--Source/kwsys/MD5.h.in107
-rw-r--r--Source/kwsys/Process.h.in469
-rw-r--r--Source/kwsys/ProcessUNIX.c3071
-rw-r--r--Source/kwsys/ProcessWin32.c3030
-rw-r--r--Source/kwsys/README.txt12
-rw-r--r--Source/kwsys/RegularExpression.cxx1244
-rw-r--r--Source/kwsys/RegularExpression.hxx.in443
-rw-r--r--Source/kwsys/SharedForward.h.in944
-rw-r--r--Source/kwsys/String.c115
-rw-r--r--Source/kwsys/String.h.in67
-rw-r--r--Source/kwsys/String.hxx.in65
-rw-r--r--Source/kwsys/System.c301
-rw-r--r--Source/kwsys/System.h.in69
-rw-r--r--Source/kwsys/SystemInformation.cxx5489
-rw-r--r--Source/kwsys/SystemInformation.hxx.in152
-rw-r--r--Source/kwsys/SystemTools.cxx5521
-rw-r--r--Source/kwsys/SystemTools.hxx.in1001
-rw-r--r--Source/kwsys/Terminal.c445
-rw-r--r--Source/kwsys/Terminal.h.in159
-rw-r--r--Source/kwsys/hash_fun.hxx.in149
-rw-r--r--Source/kwsys/hash_map.hxx.in375
-rw-r--r--Source/kwsys/hash_set.hxx.in359
-rw-r--r--Source/kwsys/hashtable.hxx.in997
-rwxr-xr-xSource/kwsys/kwsysHeaderDump.pl50
-rw-r--r--Source/kwsys/kwsysPlatformTests.cmake219
-rw-r--r--Source/kwsys/kwsysPlatformTestsC.c100
-rw-r--r--Source/kwsys/kwsysPlatformTestsCXX.cxx351
-rw-r--r--Source/kwsys/kwsysPrivate.h41
-rw-r--r--Source/kwsys/testCommandLineArguments.cxx187
-rw-r--r--Source/kwsys/testCommandLineArguments1.cxx108
-rw-r--r--Source/kwsys/testDynamicLoader.cxx128
-rw-r--r--Source/kwsys/testDynload.c22
-rw-r--r--Source/kwsys/testEncode.c76
-rw-r--r--Source/kwsys/testEncoding.cxx198
-rw-r--r--Source/kwsys/testFStream.cxx138
-rw-r--r--Source/kwsys/testFail.c35
-rw-r--r--Source/kwsys/testHashSTL.cxx74
-rw-r--r--Source/kwsys/testIOS.cxx164
-rw-r--r--Source/kwsys/testProcess.c755
-rw-r--r--Source/kwsys/testSharedForward.c.in36
-rw-r--r--Source/kwsys/testSystemInformation.cxx119
-rw-r--r--Source/kwsys/testSystemTools.binbin0 -> 766 bytes
-rw-r--r--Source/kwsys/testSystemTools.cxx1080
-rw-r--r--Source/kwsys/testSystemTools.h.in21
-rw-r--r--Source/kwsys/testTerminal.c31
1003 files changed, 266970 insertions, 0 deletions
diff --git a/Source/.cvsignore b/Source/.cvsignore
new file mode 100644
index 0000000..31e286c
--- /dev/null
+++ b/Source/.cvsignore
@@ -0,0 +1,5 @@
+ccommand___Win32_Debug
+Debug
+cmake___Win32_Debug
+ctest___Win32_Debug
+CMakeSetup.map
diff --git a/Source/.gitattributes b/Source/.gitattributes
new file mode 100644
index 0000000..bd25ea8
--- /dev/null
+++ b/Source/.gitattributes
@@ -0,0 +1,5 @@
+# Preserve upstream indentation style.
+cm_sha2.* whitespace=indent-with-non-tab
+
+# Preserve indentation style in generated code.
+cmListFileLexer.c whitespace=-tab-in-indent,-indent-with-non-tab
diff --git a/Source/CMakeInstallDestinations.cmake b/Source/CMakeInstallDestinations.cmake
new file mode 100644
index 0000000..023f6c0
--- /dev/null
+++ b/Source/CMakeInstallDestinations.cmake
@@ -0,0 +1,48 @@
+# Keep formatting here consistent with bootstrap script expectations.
+if(BEOS)
+ set(CMAKE_BIN_DIR_DEFAULT "bin") # HAIKU
+ set(CMAKE_DATA_DIR_DEFAULT "share/cmake-${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}") # HAIKU
+ set(CMAKE_MAN_DIR_DEFAULT "documentation/man") # HAIKU
+ set(CMAKE_DOC_DIR_DEFAULT "documentation/doc/cmake-${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}") # HAIKU
+ set(CMAKE_XDGDATA_DIR_DEFAULT "share") # HAIKU
+elseif(CYGWIN)
+ set(CMAKE_BIN_DIR_DEFAULT "bin") # CYGWIN
+ set(CMAKE_DATA_DIR_DEFAULT "share/cmake-${CMake_VERSION}") # CYGWIN
+ set(CMAKE_DOC_DIR_DEFAULT "share/doc/cmake-${CMake_VERSION}") # CYGWIN
+ set(CMAKE_MAN_DIR_DEFAULT "share/man") # CYGWIN
+ set(CMAKE_XDGDATA_DIR_DEFAULT "share") # CYGWIN
+else()
+ set(CMAKE_BIN_DIR_DEFAULT "bin") # OTHER
+ set(CMAKE_DATA_DIR_DEFAULT "share/cmake-${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}") # OTHER
+ set(CMAKE_DOC_DIR_DEFAULT "doc/cmake-${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}") # OTHER
+ set(CMAKE_MAN_DIR_DEFAULT "man") # OTHER
+ set(CMAKE_XDGDATA_DIR_DEFAULT "share") # OTHER
+endif()
+
+set(CMAKE_BIN_DIR_DESC "bin")
+set(CMAKE_DATA_DIR_DESC "data")
+set(CMAKE_DOC_DIR_DESC "docs")
+set(CMAKE_MAN_DIR_DESC "man pages")
+set(CMAKE_XDGDATA_DIR_DESC "XDG specific files")
+
+foreach(v
+ CMAKE_BIN_DIR
+ CMAKE_DATA_DIR
+ CMAKE_DOC_DIR
+ CMAKE_MAN_DIR
+ CMAKE_XDGDATA_DIR
+ )
+ # Populate the cache with empty values so we know when the user sets them.
+ set(${v} "" CACHE STRING "")
+ set_property(CACHE ${v} PROPERTY HELPSTRING
+ "Location under install prefix for ${${v}_DESC} (default \"${${v}_DEFAULT}\")"
+ )
+ set_property(CACHE ${v} PROPERTY ADVANCED 1)
+
+ # Use the default when the user did not set this variable.
+ if(NOT ${v})
+ set(${v} "${${v}_DEFAULT}")
+ endif()
+ # Remove leading slash to treat as relative to install prefix.
+ string(REGEX REPLACE "^/" "" ${v} "${${v}}")
+endforeach()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
new file mode 100644
index 0000000..d49ebbb
--- /dev/null
+++ b/Source/CMakeLists.txt
@@ -0,0 +1,795 @@
+#=============================================================================
+# CMake - Cross Platform Makefile Generator
+# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+include(CheckIncludeFile)
+# Check if we can build support for ELF parsing.
+if(CMAKE_CXX_PLATFORM_ID MATCHES "OpenBSD")
+ CHECK_INCLUDE_FILES("stdint.h;elf_abi.h" HAVE_ELF_H)
+else()
+ CHECK_INCLUDE_FILE("elf.h" HAVE_ELF_H)
+endif()
+if(HAVE_ELF_H)
+ set(CMAKE_USE_ELF_PARSER 1)
+elseif(HAIKU)
+ # On Haiku, we need to include elf32.h from the private headers
+ set(CMake_HAIKU_INCLUDE_DIRS
+ /boot/system/develop/headers/private/system
+ /boot/system/develop/headers/private/system/arch/x86
+ )
+
+ set(CMAKE_REQUIRED_INCLUDES ${CMake_HAIKU_INCLUDE_DIRS})
+ CHECK_INCLUDE_FILE("elf32.h" HAVE_ELF32_H)
+ unset(CMAKE_REQUIRED_INCLUDES)
+
+ if(HAVE_ELF32_H)
+ set(CMAKE_USE_ELF_PARSER 1)
+ else()
+ unset(CMake_HAIKU_INCLUDE_DIRS)
+ set(CMAKE_USE_ELF_PARSER)
+ endif()
+else()
+ set(CMAKE_USE_ELF_PARSER)
+endif()
+
+if(APPLE)
+ set(CMAKE_USE_MACH_PARSER 1)
+endif()
+
+set(EXECUTABLE_OUTPUT_PATH ${CMake_BIN_DIR})
+
+# ensure Unicode friendly APIs are used on Windows
+if(WIN32)
+ add_definitions(-DUNICODE -D_UNICODE)
+endif()
+
+# configure the .h file
+configure_file(
+ "${CMake_SOURCE_DIR}/Source/cmConfigure.cmake.h.in"
+ "${CMake_BINARY_DIR}/Source/cmConfigure.h"
+ )
+configure_file(
+ "${CMake_SOURCE_DIR}/Source/cmVersionConfig.h.in"
+ "${CMake_BINARY_DIR}/Source/cmVersionConfig.h"
+ )
+configure_file(
+ "${CMake_SOURCE_DIR}/Source/CPack/cmCPackConfigure.h.in"
+ "${CMake_BINARY_DIR}/Source/CPack/cmCPackConfigure.h"
+ )
+
+# Tell CMake executable in the build tree where to find the source tree.
+configure_file(
+ "${CMake_SOURCE_DIR}/Source/CMakeSourceDir.txt.in"
+ "${CMake_BINARY_DIR}/CMakeFiles/CMakeSourceDir.txt" @ONLY
+ )
+
+# add the include path to find the .h
+include_directories(
+ "${CMake_BINARY_DIR}/Source"
+ "${CMake_SOURCE_DIR}/Source"
+ ${CMAKE_ZLIB_INCLUDES}
+ ${CMAKE_EXPAT_INCLUDES}
+ ${CMAKE_TAR_INCLUDES}
+ ${CMAKE_COMPRESS_INCLUDES}
+ ${CMake_HAIKU_INCLUDE_DIRS}
+ )
+
+# let cmake know it is supposed to use it
+add_definitions(-DCMAKE_BUILD_WITH_CMAKE)
+
+option(CMAKE_REGENERATE_YACCLEX
+ "Regenerate YACC and LEXX files" OFF)
+mark_as_advanced(CMAKE_REGENERATE_YACCLEX)
+if(CMAKE_REGENERATE_YACCLEX)
+ set(parsersLexers cmFortran cmCommandArgument cmExpr)
+ find_program(YACC_EXECUTABLE
+ NAMES yacc bison
+ PATHS /usr/bin
+ DOC "Yacc or Bison executable")
+ find_program(FLEX_EXECUTABLE
+ NAMES flex
+ PATHS /usr/bin
+ DOC "Flex executable")
+ mark_as_advanced(YACC_EXECUTABLE FLEX_EXECUTABLE)
+ if(YACC_EXECUTABLE)
+ set(BISON_FLAGS)
+ if(YACC_EXECUTABLE MATCHES "bison")
+ set(BISON_FLAGS "--yacc")
+ endif()
+ set(yacc_files)
+ foreach(name ${parsersLexers})
+ set(src "${CMAKE_CURRENT_SOURCE_DIR}/${name}Parser.y")
+ set(dst "${CMAKE_CURRENT_BINARY_DIR}/${name}Parser.cxx")
+ set(hdr "${CMAKE_CURRENT_BINARY_DIR}/${name}ParserTokens.h")
+ add_custom_command(
+ OUTPUT "${dst}"
+ DEPENDS "${src}"
+ COMMAND
+ ${YACC_EXECUTABLE}
+ --name-prefix=${name}_yy --defines=${hdr} -o${dst} ${src}
+ )
+ set(yacc_files ${yacc_files} "${dst}")
+ endforeach()
+ add_custom_target(RerunYacc DEPENDS ${yacc_files})
+ endif()
+ if(FLEX_EXECUTABLE)
+ set(lex_files)
+ foreach(name ${parsersLexers})
+ set(src "${CMAKE_CURRENT_SOURCE_DIR}/${name}Lexer.in.l")
+ set(dst "${CMAKE_CURRENT_BINARY_DIR}/${name}Lexer.cxx")
+ set(hdr "${CMAKE_CURRENT_BINARY_DIR}/${name}Lexer.h")
+ add_custom_command(
+ OUTPUT "${dst}"
+ DEPENDS "${src}"
+ COMMAND
+ ${FLEX_EXECUTABLE}
+ --prefix=${name}_yy --header-file=${hdr} -o${dst} ${src}
+ )
+ set(lex_files ${lex_files} "${dst}")
+ endforeach()
+ add_custom_target(RerunLex DEPENDS ${lex_files})
+ endif()
+
+endif()
+
+# Check if we can build the ELF parser.
+if(CMAKE_USE_ELF_PARSER)
+ set(ELF_SRCS cmELF.h cmELF.cxx)
+endif()
+
+# Check if we can build the Mach-O parser.
+if(CMAKE_USE_MACH_PARSER)
+ set(MACH_SRCS cmMachO.h cmMachO.cxx)
+endif()
+
+#
+# Sources for CMakeLib
+#
+set(SRCS
+ cmArchiveWrite.cxx
+ cmBootstrapCommands1.cxx
+ cmBootstrapCommands2.cxx
+ cmCacheManager.cxx
+ cmCacheManager.h
+ "${CMAKE_CURRENT_BINARY_DIR}/cmCommands.cxx"
+ cmCLocaleEnvironmentScope.h
+ cmCLocaleEnvironmentScope.cxx
+ cmCommands.h
+ cmCommandArgumentLexer.cxx
+ cmCommandArgumentParser.cxx
+ cmCommandArgumentParserHelper.cxx
+ cmCommonTargetGenerator.cxx
+ cmCommonTargetGenerator.h
+ cmComputeComponentGraph.cxx
+ cmComputeComponentGraph.h
+ cmComputeLinkDepends.cxx
+ cmComputeLinkDepends.h
+ cmComputeLinkInformation.cxx
+ cmComputeLinkInformation.h
+ cmComputeTargetDepends.h
+ cmComputeTargetDepends.cxx
+ cmCPackPropertiesGenerator.h
+ cmCPackPropertiesGenerator.cxx
+ cmCryptoHash.cxx
+ cmCryptoHash.h
+ cmCurl.cxx
+ cmCurl.h
+ cmCustomCommand.cxx
+ cmCustomCommand.h
+ cmCustomCommandGenerator.cxx
+ cmCustomCommandGenerator.h
+ cmDefinitions.cxx
+ cmDefinitions.h
+ cmDepends.cxx
+ cmDepends.h
+ cmDependsC.cxx
+ cmDependsC.h
+ cmDependsFortran.cxx
+ cmDependsFortran.h
+ cmDependsJava.cxx
+ cmDependsJava.h
+ cmDependsJavaLexer.cxx
+ cmDependsJavaParser.cxx
+ cmDependsJavaParserHelper.cxx
+ cmDependsJavaParserHelper.h
+ cmDocumentation.cxx
+ cmDocumentationFormatter.cxx
+ cmDocumentationSection.cxx
+ cmDynamicLoader.cxx
+ cmDynamicLoader.h
+ ${ELF_SRCS}
+ cmExprLexer.cxx
+ cmExprParser.cxx
+ cmExprParserHelper.cxx
+ cmExportBuildFileGenerator.h
+ cmExportBuildFileGenerator.cxx
+ cmExportFileGenerator.h
+ cmExportFileGenerator.cxx
+ cmExportInstallFileGenerator.h
+ cmExportInstallFileGenerator.cxx
+ cmExportTryCompileFileGenerator.h
+ cmExportTryCompileFileGenerator.cxx
+ cmExportSet.h
+ cmExportSet.cxx
+ cmExportSetMap.h
+ cmExportSetMap.cxx
+ cmExternalMakefileProjectGenerator.cxx
+ cmExternalMakefileProjectGenerator.h
+ cmExtraCodeBlocksGenerator.cxx
+ cmExtraCodeBlocksGenerator.h
+ cmExtraCodeLiteGenerator.cxx
+ cmExtraCodeLiteGenerator.h
+ cmExtraEclipseCDT4Generator.cxx
+ cmExtraEclipseCDT4Generator.h
+ cmExtraKateGenerator.cxx
+ cmExtraKateGenerator.h
+ cmExtraSublimeTextGenerator.cxx
+ cmExtraSublimeTextGenerator.h
+ cmFileLock.cxx
+ cmFileLock.h
+ cmFileLockPool.cxx
+ cmFileLockPool.h
+ cmFileLockResult.cxx
+ cmFileLockResult.h
+ cmFileTimeComparison.cxx
+ cmFileTimeComparison.h
+ cmFortranLexer.cxx
+ cmFortranLexer.h
+ cmFortranParser.cxx
+ cmFortranParser.h
+ cmFortranParserImpl.cxx
+ cmGeneratedFileStream.cxx
+ cmGeneratorExpressionContext.cxx
+ cmGeneratorExpressionContext.h
+ cmGeneratorExpressionDAGChecker.cxx
+ cmGeneratorExpressionDAGChecker.h
+ cmGeneratorExpressionEvaluationFile.cxx
+ cmGeneratorExpressionEvaluationFile.h
+ cmGeneratorExpressionEvaluator.cxx
+ cmGeneratorExpressionEvaluator.h
+ cmGeneratorExpressionLexer.cxx
+ cmGeneratorExpressionLexer.h
+ cmGeneratorExpressionNode.cxx
+ cmGeneratorExpressionNode.h
+ cmGeneratorExpressionParser.cxx
+ cmGeneratorExpressionParser.h
+ cmGeneratorExpression.cxx
+ cmGeneratorExpression.h
+ cmGeneratorTarget.cxx
+ cmGeneratorTarget.h
+ cmGlobalCommonGenerator.cxx
+ cmGlobalCommonGenerator.h
+ cmGlobalGenerator.cxx
+ cmGlobalGenerator.h
+ cmGlobalGeneratorFactory.h
+ cmGlobalUnixMakefileGenerator3.cxx
+ cmGlobalUnixMakefileGenerator3.h
+ cmGraphAdjacencyList.h
+ cmGraphVizWriter.cxx
+ cmGraphVizWriter.h
+ cmInstallGenerator.h
+ cmInstallGenerator.cxx
+ cmInstallExportGenerator.cxx
+ cmInstalledFile.h
+ cmInstalledFile.cxx
+ cmInstallFilesGenerator.h
+ cmInstallFilesGenerator.cxx
+ cmInstallScriptGenerator.h
+ cmInstallScriptGenerator.cxx
+ cmInstallTargetGenerator.h
+ cmInstallTargetGenerator.cxx
+ cmInstallDirectoryGenerator.h
+ cmInstallDirectoryGenerator.cxx
+ cmLinkedTree.h
+ cmLinkItem.h
+ cmListFileCache.cxx
+ cmListFileCache.h
+ cmListFileLexer.c
+ cmLocalCommonGenerator.cxx
+ cmLocalCommonGenerator.h
+ cmLocalGenerator.cxx
+ cmLocalGenerator.h
+ cmLocalUnixMakefileGenerator3.cxx
+ cmLocale.h
+ ${MACH_SRCS}
+ cmMakefile.cxx
+ cmMakefile.h
+ cmMakefileTargetGenerator.cxx
+ cmMakefileExecutableTargetGenerator.cxx
+ cmMakefileLibraryTargetGenerator.cxx
+ cmMakefileUtilityTargetGenerator.cxx
+ cmOSXBundleGenerator.cxx
+ cmOSXBundleGenerator.h
+ cmOutputConverter.cxx
+ cmOutputConverter.h
+ cmNewLineStyle.h
+ cmNewLineStyle.cxx
+ cmOrderDirectories.cxx
+ cmOrderDirectories.h
+ cmPolicies.h
+ cmPolicies.cxx
+ cmProcessTools.cxx
+ cmProcessTools.h
+ cmProperty.cxx
+ cmProperty.h
+ cmPropertyDefinition.cxx
+ cmPropertyDefinition.h
+ cmPropertyDefinitionMap.cxx
+ cmPropertyDefinitionMap.h
+ cmPropertyMap.cxx
+ cmPropertyMap.h
+ cmQtAutoGeneratorInitializer.cxx
+ cmQtAutoGeneratorInitializer.h
+ cmQtAutoGenerators.cxx
+ cmQtAutoGenerators.h
+ cmRST.cxx
+ cmRST.h
+ cmScriptGenerator.h
+ cmScriptGenerator.cxx
+ cmSourceFile.cxx
+ cmSourceFile.h
+ cmSourceFileLocation.cxx
+ cmSourceFileLocation.h
+ cmSourceGroup.cxx
+ cmSourceGroup.h
+ cmState.cxx
+ cmState.h
+ cmSystemTools.cxx
+ cmSystemTools.h
+ cmTarget.cxx
+ cmTarget.h
+ cmTargetExport.h
+ cmTest.cxx
+ cmTest.h
+ cmTestGenerator.cxx
+ cmTestGenerator.h
+ cmUuid.cxx
+ cmVariableWatch.cxx
+ cmVariableWatch.h
+ cmVersion.cxx
+ cmVersion.h
+ cmXMLParser.cxx
+ cmXMLParser.h
+ cmXMLSafe.cxx
+ cmXMLSafe.h
+ cmXMLWriter.cxx
+ cmXMLWriter.h
+ cmake.cxx
+ cmake.h
+
+ cm_auto_ptr.hxx
+ cm_get_date.h
+ cm_get_date.c
+ cm_sha2.h
+ cm_sha2.c
+ cm_utf8.h
+ cm_utf8.c
+ )
+
+set(COMMAND_INCLUDES "#include \"cmTargetPropCommandBase.cxx\"\n")
+list(APPEND SRCS cmTargetPropCommandBase.cxx)
+set_property(SOURCE cmTargetPropCommandBase.cxx PROPERTY HEADER_FILE_ONLY ON)
+set(NEW_COMMANDS "")
+foreach(command_file
+ cmAddCompileOptionsCommand
+ cmAuxSourceDirectoryCommand
+ cmBuildNameCommand
+ cmCMakeHostSystemInformationCommand
+ cmElseIfCommand
+ cmExportCommand
+ cmExportLibraryDependenciesCommand
+ cmFLTKWrapUICommand
+ cmIncludeExternalMSProjectCommand
+ cmInstallProgramsCommand
+ cmLinkLibrariesCommand
+ cmLoadCacheCommand
+ cmOutputRequiredFilesCommand
+ cmQTWrapCPPCommand
+ cmQTWrapUICommand
+ cmRemoveCommand
+ cmRemoveDefinitionsCommand
+ cmSourceGroupCommand
+ cmSubdirDependsCommand
+ cmTargetCompileDefinitionsCommand
+ cmTargetCompileFeaturesCommand
+ cmTargetCompileOptionsCommand
+ cmTargetIncludeDirectoriesCommand
+ cmTargetSourcesCommand
+ cmUseMangledMesaCommand
+ cmUtilitySourceCommand
+ cmVariableRequiresCommand
+ cmVariableWatchCommand
+ cmWriteFileCommand
+ # This one must be last because it includes windows.h and
+ # windows.h #defines GetCurrentDirectory which is a member
+ # of cmMakefile
+ cmLoadCommandCommand
+ )
+ set(COMMAND_INCLUDES "${COMMAND_INCLUDES}#include \"${command_file}.cxx\"\n")
+ set(NEW_COMMANDS "${NEW_COMMANDS}commands.push_back(new ${command_file});\n")
+ list(APPEND SRCS ${command_file}.cxx)
+ set_property(SOURCE ${command_file}.cxx PROPERTY HEADER_FILE_ONLY ON)
+endforeach()
+configure_file(cmCommands.cxx.in ${CMAKE_CURRENT_BINARY_DIR}/cmCommands.cxx @ONLY)
+
+# Kdevelop only works on UNIX and not windows
+if(UNIX)
+ set(SRCS ${SRCS} cmGlobalKdevelopGenerator.cxx)
+endif()
+
+# Xcode only works on Apple
+if(APPLE)
+ set(SRCS ${SRCS}
+ cmXCodeObject.cxx
+ cmXCode21Object.cxx
+ cmGlobalXCodeGenerator.cxx
+ cmGlobalXCodeGenerator.h
+ cmLocalXCodeGenerator.cxx
+ cmLocalXCodeGenerator.h)
+endif()
+
+
+if (WIN32)
+ set(SRCS ${SRCS}
+ cmCallVisualStudioMacro.cxx
+ cmCallVisualStudioMacro.h
+ bindexplib.cxx
+ )
+
+ if(NOT UNIX)
+ set(SRCS ${SRCS}
+ cmGlobalBorlandMakefileGenerator.cxx
+ cmGlobalBorlandMakefileGenerator.h
+ cmGlobalMSYSMakefileGenerator.cxx
+ cmGlobalMinGWMakefileGenerator.cxx
+ cmGlobalNMakeMakefileGenerator.cxx
+ cmGlobalNMakeMakefileGenerator.h
+ cmGlobalJOMMakefileGenerator.cxx
+ cmGlobalJOMMakefileGenerator.h
+ cmGlobalVisualStudio71Generator.cxx
+ cmGlobalVisualStudio71Generator.h
+ cmGlobalVisualStudio7Generator.cxx
+ cmGlobalVisualStudio7Generator.h
+ cmGlobalVisualStudio8Generator.cxx
+ cmGlobalVisualStudio8Generator.h
+ cmGlobalVisualStudio9Generator.cxx
+ cmGlobalVisualStudio9Generator.h
+ cmVisualStudioGeneratorOptions.h
+ cmVisualStudioGeneratorOptions.cxx
+ cmVisualStudio10TargetGenerator.h
+ cmVisualStudio10TargetGenerator.cxx
+ cmLocalVisualStudio10Generator.cxx
+ cmLocalVisualStudio10Generator.h
+ cmGlobalVisualStudio10Generator.h
+ cmGlobalVisualStudio10Generator.cxx
+ cmGlobalVisualStudio11Generator.h
+ cmGlobalVisualStudio11Generator.cxx
+ cmGlobalVisualStudio12Generator.h
+ cmGlobalVisualStudio12Generator.cxx
+ cmGlobalVisualStudio14Generator.h
+ cmGlobalVisualStudio14Generator.cxx
+ cmGlobalVisualStudioGenerator.cxx
+ cmGlobalVisualStudioGenerator.h
+ cmIDEFlagTable.h
+ cmIDEOptions.cxx
+ cmIDEOptions.h
+ cmLocalVisualStudio7Generator.cxx
+ cmLocalVisualStudio7Generator.h
+ cmLocalVisualStudioGenerator.cxx
+ cmLocalVisualStudioGenerator.h
+ cmVisualStudioSlnData.h
+ cmVisualStudioSlnData.cxx
+ cmVisualStudioSlnParser.h
+ cmVisualStudioSlnParser.cxx
+ cmVisualStudioWCEPlatformParser.h
+ cmVisualStudioWCEPlatformParser.cxx
+ cmGlobalGhsMultiGenerator.cxx
+ cmGlobalGhsMultiGenerator.h
+ cmLocalGhsMultiGenerator.cxx
+ cmLocalGhsMultiGenerator.h
+ cmGhsMultiTargetGenerator.cxx
+ cmGhsMultiTargetGenerator.h
+ cmGhsMultiGpj.cxx
+ cmGhsMultiGpj.h
+ )
+
+ # Add a manifest file to executables on Windows to allow for
+ # GetVersion to work properly on Windows 8 and above.
+ set(MANIFEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake.version.manifest)
+ endif()
+endif ()
+
+# Watcom support
+if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ set_property(SOURCE cmake.cxx APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_USE_WMAKE)
+ list(APPEND SRCS
+ cmGlobalWatcomWMakeGenerator.cxx
+ cmGlobalWatcomWMakeGenerator.h
+ )
+endif()
+
+# Ninja support
+set(SRCS ${SRCS}
+ cmGlobalNinjaGenerator.cxx
+ cmGlobalNinjaGenerator.h
+ cmNinjaTypes.h
+ cmLocalNinjaGenerator.cxx
+ cmLocalNinjaGenerator.h
+ cmNinjaTargetGenerator.cxx
+ cmNinjaTargetGenerator.h
+ cmNinjaNormalTargetGenerator.cxx
+ cmNinjaNormalTargetGenerator.h
+ cmNinjaUtilityTargetGenerator.cxx
+ cmNinjaUtilityTargetGenerator.h
+ )
+
+if(WIN32 AND NOT CYGWIN)
+ set_source_files_properties(cmcldeps.cxx PROPERTIES COMPILE_DEFINITIONS _WIN32_WINNT=0x0501)
+ add_executable(cmcldeps cmcldeps.cxx ${MANIFEST_FILE})
+ target_link_libraries(cmcldeps CMakeLib)
+ install(TARGETS cmcldeps DESTINATION bin)
+endif()
+
+foreach(v CURL_CA_BUNDLE CURL_CA_PATH)
+ if(${v})
+ set_property(SOURCE cmCurl.cxx APPEND PROPERTY COMPILE_DEFINITIONS ${v}="${${v}}")
+ endif()
+endforeach()
+
+foreach(check
+ STAT_HAS_ST_MTIM
+ STAT_HAS_ST_MTIMESPEC
+ )
+ if(KWSYS_CXX_${check}_COMPILED) # abuse KWSys check cache entry
+ set(CMake_${check} 1)
+ else()
+ set(CMake_${check} 0)
+ endif()
+ set_property(SOURCE cmFileTimeComparison.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS CMake_${check}=${CMake_${check}})
+endforeach()
+
+# create a library used by the command line and the GUI
+add_library(CMakeLib ${SRCS})
+target_link_libraries(CMakeLib cmsys
+ ${CMAKE_EXPAT_LIBRARIES} ${CMAKE_ZLIB_LIBRARIES}
+ ${CMAKE_TAR_LIBRARIES} ${CMAKE_COMPRESS_LIBRARIES}
+ ${CMAKE_CURL_LIBRARIES}
+ ${CMAKE_JSONCPP_LIBRARIES}
+ ${CMake_KWIML_LIBRARIES}
+ )
+
+# On Apple we need CoreFoundation
+if(APPLE)
+ target_link_libraries(CMakeLib "-framework CoreFoundation")
+endif()
+
+if(WIN32 AND NOT UNIX)
+ # We need the rpcrt4 library on Windows.
+ # We need the crypt32 library on Windows for crypto/cert APIs.
+ target_link_libraries(CMakeLib rpcrt4 crypt32)
+endif()
+
+#
+# CTestLib
+#
+include_directories(
+ "${CMake_SOURCE_DIR}/Source/CTest"
+ ${CMAKE_XMLRPC_INCLUDES}
+ ${CMAKE_CURL_INCLUDES}
+ )
+#
+# Sources for CTestLib
+#
+set(CTEST_SRCS cmCTest.cxx
+ CTest/cmProcess.cxx
+ CTest/cmCTestBatchTestHandler.cxx
+ CTest/cmCTestBuildAndTestHandler.cxx
+ CTest/cmCTestBuildCommand.cxx
+ CTest/cmCTestBuildHandler.cxx
+ CTest/cmCTestConfigureCommand.cxx
+ CTest/cmCTestConfigureHandler.cxx
+ CTest/cmCTestCoverageCommand.cxx
+ CTest/cmCTestCoverageHandler.cxx
+ CTest/cmCTestCurl.cxx
+ CTest/cmParseMumpsCoverage.cxx
+ CTest/cmParseCacheCoverage.cxx
+ CTest/cmParseGTMCoverage.cxx
+ CTest/cmParseJacocoCoverage.cxx
+ CTest/cmParseBlanketJSCoverage.cxx
+ CTest/cmParsePHPCoverage.cxx
+ CTest/cmParseCoberturaCoverage.cxx
+ CTest/cmParseDelphiCoverage.cxx
+ CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
+ CTest/cmCTestGenericHandler.cxx
+ CTest/cmCTestHandlerCommand.cxx
+ CTest/cmCTestLaunch.cxx
+ CTest/cmCTestMemCheckCommand.cxx
+ CTest/cmCTestMemCheckHandler.cxx
+ CTest/cmCTestMultiProcessHandler.cxx
+ CTest/cmCTestReadCustomFilesCommand.cxx
+ CTest/cmCTestRunScriptCommand.cxx
+ CTest/cmCTestRunTest.cxx
+ CTest/cmCTestScriptHandler.cxx
+ CTest/cmCTestSleepCommand.cxx
+ CTest/cmCTestStartCommand.cxx
+ CTest/cmCTestSubmitCommand.cxx
+ CTest/cmCTestSubmitHandler.cxx
+ CTest/cmCTestTestCommand.cxx
+ CTest/cmCTestTestHandler.cxx
+ CTest/cmCTestUpdateCommand.cxx
+ CTest/cmCTestUpdateHandler.cxx
+ CTest/cmCTestUploadCommand.cxx
+ CTest/cmCTestUploadHandler.cxx
+
+ CTest/cmCTestVC.cxx
+ CTest/cmCTestVC.h
+ CTest/cmCTestGlobalVC.cxx
+ CTest/cmCTestGlobalVC.h
+ CTest/cmCTestCVS.cxx
+ CTest/cmCTestCVS.h
+ CTest/cmCTestSVN.cxx
+ CTest/cmCTestSVN.h
+ CTest/cmCTestBZR.cxx
+ CTest/cmCTestBZR.h
+ CTest/cmCTestGIT.cxx
+ CTest/cmCTestGIT.h
+ CTest/cmCTestHG.cxx
+ CTest/cmCTestHG.h
+ CTest/cmCTestP4.cxx
+ CTest/cmCTestP4.h
+ )
+
+# Build CTestLib
+add_library(CTestLib ${CTEST_SRCS})
+target_link_libraries(CTestLib CMakeLib ${CMAKE_CURL_LIBRARIES} ${CMAKE_XMLRPC_LIBRARIES})
+
+#
+# Sources for CPack
+#
+set(CPACK_SRCS
+ CPack/cmCPackArchiveGenerator.cxx
+ CPack/cmCPackComponentGroup.cxx
+ CPack/cmCPackGeneratorFactory.cxx
+ CPack/cmCPackGenerator.cxx
+ CPack/cmCPackLog.cxx
+ CPack/cmCPackNSISGenerator.cxx
+ CPack/IFW/cmCPackIFWPackage.cxx
+ CPack/IFW/cmCPackIFWInstaller.cxx
+ CPack/IFW/cmCPackIFWRepository.cxx
+ CPack/IFW/cmCPackIFWGenerator.cxx
+ CPack/cmCPackSTGZGenerator.cxx
+ CPack/cmCPackTGZGenerator.cxx
+ CPack/cmCPackTXZGenerator.cxx
+ CPack/cmCPackTarBZip2Generator.cxx
+ CPack/cmCPackTarCompressGenerator.cxx
+ CPack/cmCPackZIPGenerator.cxx
+ CPack/cmCPack7zGenerator.cxx
+ )
+
+if(CYGWIN)
+ set(CPACK_SRCS ${CPACK_SRCS}
+ CPack/cmCPackCygwinBinaryGenerator.cxx
+ CPack/cmCPackCygwinSourceGenerator.cxx
+ )
+endif()
+
+if(UNIX)
+ set(CPACK_SRCS ${CPACK_SRCS}
+ CPack/cmCPackDebGenerator.cxx
+ CPack/cmCPackRPMGenerator.cxx
+ )
+endif()
+
+if(WIN32)
+ set(CPACK_SRCS ${CPACK_SRCS}
+ CPack/WiX/cmCPackWIXGenerator.cxx
+ CPack/WiX/cmCPackWIXGenerator.h
+ CPack/WiX/cmWIXAccessControlList.cxx
+ CPack/WiX/cmWIXAccessControlList.h
+ CPack/WiX/cmWIXDirectoriesSourceWriter.cxx
+ CPack/WiX/cmWIXDirectoriesSourceWriter.h
+ CPack/WiX/cmWIXFeaturesSourceWriter.cxx
+ CPack/WiX/cmWIXFeaturesSourceWriter.h
+ CPack/WiX/cmWIXFilesSourceWriter.cxx
+ CPack/WiX/cmWIXFilesSourceWriter.h
+ CPack/WiX/cmWIXPatch.cxx
+ CPack/WiX/cmWIXPatch.h
+ CPack/WiX/cmWIXPatchParser.cxx
+ CPack/WiX/cmWIXPatchParser.h
+ CPack/WiX/cmWIXRichTextFormatWriter.cxx
+ CPack/WiX/cmWIXRichTextFormatWriter.h
+ CPack/WiX/cmWIXShortcut.cxx
+ CPack/WiX/cmWIXShortcut.h
+ CPack/WiX/cmWIXSourceWriter.cxx
+ CPack/WiX/cmWIXSourceWriter.h
+ )
+endif()
+
+if(APPLE)
+ set(CPACK_SRCS ${CPACK_SRCS}
+ CPack/cmCPackBundleGenerator.cxx
+ CPack/cmCPackDragNDropGenerator.cxx
+ CPack/cmCPackOSXX11Generator.cxx
+ CPack/cmCPackPKGGenerator.cxx
+ CPack/cmCPackPackageMakerGenerator.cxx
+ CPack/cmCPackProductBuildGenerator.cxx
+ )
+endif()
+
+# Build CPackLib
+add_library(CPackLib ${CPACK_SRCS})
+target_link_libraries(CPackLib CMakeLib)
+if(APPLE)
+ # Some compilers produce errors in the CoreServices framework headers.
+ # Ideally such errors should be fixed by either the compiler vendor
+ # or the framework source, but we try to workaround it and build anyway.
+ # If it does not work, build with reduced functionality and warn.
+ check_include_file("CoreServices/CoreServices.h" HAVE_CoreServices)
+ if(HAVE_CoreServices)
+ set_property(SOURCE CPack/cmCPackDragNDropGenerator.cxx PROPERTY COMPILE_DEFINITIONS HAVE_CoreServices)
+ target_link_libraries(CPackLib "-framework CoreServices")
+ else()
+ message(WARNING "This compiler does not appear to support\n"
+ " #include <CoreServices/CoreServices.h>\n"
+ "Some CPack functionality may be limited.\n"
+ "See CMakeFiles/CMakeError.log for details of the failure.")
+ endif()
+endif()
+
+if(APPLE)
+ add_executable(cmakexbuild cmakexbuild.cxx)
+ target_link_libraries(cmakexbuild CMakeLib)
+ add_executable(OSXScriptLauncher
+ CPack/OSXScriptLauncher.cxx)
+ target_link_libraries(OSXScriptLauncher cmsys)
+ target_link_libraries(OSXScriptLauncher "-framework CoreFoundation")
+endif()
+
+# Build CMake executable
+add_executable(cmake cmakemain.cxx cmcmd.cxx cmcmd.h ${MANIFEST_FILE})
+target_link_libraries(cmake CMakeLib)
+
+# Build CTest executable
+add_executable(ctest ctest.cxx ${MANIFEST_FILE})
+target_link_libraries(ctest CTestLib)
+
+# Build CPack executable
+add_executable(cpack CPack/cpack.cxx ${MANIFEST_FILE})
+target_link_libraries(cpack CPackLib)
+
+# Curses GUI
+if(BUILD_CursesDialog)
+ include(${CMake_SOURCE_DIR}/Source/CursesDialog/CMakeLists.txt)
+endif()
+
+# Qt GUI
+option(BUILD_QtDialog "Build Qt dialog for CMake" FALSE)
+if(BUILD_QtDialog)
+ add_subdirectory(QtDialog)
+endif()
+
+include (${CMake_BINARY_DIR}/Source/LocalUserOptions.cmake OPTIONAL)
+include (${CMake_SOURCE_DIR}/Source/LocalUserOptions.cmake OPTIONAL)
+
+# Install tools
+
+set(_tools cmake ctest cpack)
+
+if(APPLE)
+ list(APPEND _tools cmakexbuild)
+endif()
+
+foreach(_tool ${_tools})
+ CMake_OPTIONAL_COMPONENT(${_tool})
+ install(TARGETS ${_tool} DESTINATION ${CMAKE_BIN_DIR} ${COMPONENT})
+endforeach()
+
+install(FILES cmCPluginAPI.h DESTINATION ${CMAKE_DATA_DIR}/include)
diff --git a/Source/CMakeSourceDir.txt.in b/Source/CMakeSourceDir.txt.in
new file mode 100644
index 0000000..5e6a988
--- /dev/null
+++ b/Source/CMakeSourceDir.txt.in
@@ -0,0 +1 @@
+@CMake_SOURCE_DIR@
diff --git a/Source/CMakeVersion.bash b/Source/CMakeVersion.bash
new file mode 100755
index 0000000..853b0ca
--- /dev/null
+++ b/Source/CMakeVersion.bash
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+# Update the version component if it looks like a date or -f is given.
+if test "x$1" = "x-f"; then shift ; n='*' ; else n='\{8\}' ; fi
+if test "$#" -gt 0; then echo 1>&2 "usage: CMakeVersion.bash [-f]"; exit 1; fi
+sed -i -e '
+s/\(^set(CMake_VERSION_PATCH\) [0-9]'"$n"'\(.*\)/\1 '"$(date +%Y%m%d)"'\2/
+' "${BASH_SOURCE%/*}/CMakeVersion.cmake"
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
new file mode 100644
index 0000000..2a98911
--- /dev/null
+++ b/Source/CMakeVersion.cmake
@@ -0,0 +1,5 @@
+# CMake version number components.
+set(CMake_VERSION_MAJOR 3)
+set(CMake_VERSION_MINOR 6)
+set(CMake_VERSION_PATCH 20160701)
+#set(CMake_VERSION_RC 1)
diff --git a/Source/CMakeVersionCompute.cmake b/Source/CMakeVersionCompute.cmake
new file mode 100644
index 0000000..496d6cf
--- /dev/null
+++ b/Source/CMakeVersionCompute.cmake
@@ -0,0 +1,20 @@
+# Load version number components.
+include(${CMake_SOURCE_DIR}/Source/CMakeVersion.cmake)
+
+# Releases define a small patch level.
+if("${CMake_VERSION_PATCH}" VERSION_LESS 20000000)
+ set(CMake_VERSION_IS_RELEASE 1)
+ set(CMake_VERSION_SOURCE "")
+else()
+ set(CMake_VERSION_IS_RELEASE 0)
+ include(${CMake_SOURCE_DIR}/Source/CMakeVersionSource.cmake)
+endif()
+
+# Compute the full version string.
+set(CMake_VERSION ${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATCH})
+if(CMake_VERSION_RC)
+ set(CMake_VERSION ${CMake_VERSION}-rc${CMake_VERSION_RC})
+endif()
+if(CMake_VERSION_SOURCE)
+ set(CMake_VERSION ${CMake_VERSION}-${CMake_VERSION_SOURCE})
+endif()
diff --git a/Source/CMakeVersionSource.cmake b/Source/CMakeVersionSource.cmake
new file mode 100644
index 0000000..888f557
--- /dev/null
+++ b/Source/CMakeVersionSource.cmake
@@ -0,0 +1,37 @@
+# Try to identify the current development source version.
+set(CMake_VERSION_SOURCE "")
+if(EXISTS ${CMake_SOURCE_DIR}/.git/HEAD)
+ find_program(GIT_EXECUTABLE NAMES git git.cmd)
+ mark_as_advanced(GIT_EXECUTABLE)
+ if(GIT_EXECUTABLE)
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} rev-parse --verify -q --short=4 HEAD
+ OUTPUT_VARIABLE head
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+ )
+ if(head)
+ set(CMake_VERSION_SOURCE "g${head}")
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} update-index -q --refresh
+ WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+ )
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD --
+ OUTPUT_VARIABLE dirty
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+ )
+ if(dirty)
+ set(CMake_VERSION_SOURCE "${CMake_VERSION_SOURCE}-dirty")
+ endif()
+ endif()
+ endif()
+elseif(EXISTS ${CMake_SOURCE_DIR}/CVS/Repository)
+ file(READ ${CMake_SOURCE_DIR}/CVS/Repository repo)
+ set(branch "")
+ if("${repo}" MATCHES "\\.git/([^\r\n]*)")
+ set(branch "${CMAKE_MATCH_1}")
+ endif()
+ set(CMake_VERSION_SOURCE "cvs${branch}")
+endif()
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
new file mode 100644
index 0000000..4a5eb90
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
@@ -0,0 +1,582 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackIFWGenerator.h"
+
+#include <CPack/cmCPackComponentGroup.h>
+#include <CPack/cmCPackLog.h>
+
+#include <cmsys/Directory.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/RegularExpression.hxx>
+#include <cmsys/SystemTools.hxx>
+
+#include <cmGeneratedFileStream.h>
+#include <cmGlobalGenerator.h>
+#include <cmMakefile.h>
+#include <cmSystemTools.h>
+#include <cmTimestamp.h>
+#include <cmVersionConfig.h>
+#include <cmXMLWriter.h>
+
+cmCPackIFWGenerator::cmCPackIFWGenerator()
+{
+}
+
+cmCPackIFWGenerator::~cmCPackIFWGenerator()
+{
+}
+
+bool cmCPackIFWGenerator::IsVersionLess(const char* version)
+{
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
+ FrameworkVersion.data(), version);
+}
+
+bool cmCPackIFWGenerator::IsVersionGreater(const char* version)
+{
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER,
+ FrameworkVersion.data(), version);
+}
+
+bool cmCPackIFWGenerator::IsVersionEqual(const char* version)
+{
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
+ FrameworkVersion.data(), version);
+}
+
+int cmCPackIFWGenerator::PackageFiles()
+{
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Configuration" << std::endl);
+
+ // Installer configuragion
+ Installer.GenerateInstallerFile();
+
+ // Packages configuration
+ Installer.GeneratePackageFiles();
+
+ std::string ifwTLD = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ std::string ifwTmpFile = ifwTLD;
+ ifwTmpFile += "/IFWOutput.log";
+
+ // Run repogen
+ if (!Installer.RemoteRepositories.empty()) {
+ std::string ifwCmd = RepoGen;
+
+ if (IsVersionLess("2.0.0")) {
+ ifwCmd += " -c " + this->toplevel + "/config/config.xml";
+ }
+
+ ifwCmd += " -p " + this->toplevel + "/packages";
+
+ if (!PkgsDirsVector.empty()) {
+ for (std::vector<std::string>::iterator it = PkgsDirsVector.begin();
+ it != PkgsDirsVector.end(); ++it) {
+ ifwCmd += " -p " + *it;
+ }
+ }
+
+ if (!OnlineOnly && !DownloadedPackages.empty()) {
+ ifwCmd += " -i ";
+ std::set<cmCPackIFWPackage*>::iterator it = DownloadedPackages.begin();
+ ifwCmd += (*it)->Name;
+ ++it;
+ while (it != DownloadedPackages.end()) {
+ ifwCmd += "," + (*it)->Name;
+ ++it;
+ }
+ }
+ ifwCmd += " " + this->toplevel + "/repository";
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << ifwCmd << std::endl);
+ std::string output;
+ int retVal = 1;
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Generate repository"
+ << std::endl);
+ bool res = cmSystemTools::RunSingleCommand(ifwCmd.c_str(), &output,
+ &output, &retVal, CM_NULLPTR,
+ this->GeneratorVerbose, 0);
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(ifwTmpFile.c_str());
+ ofs << "# Run command: " << ifwCmd << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running IFW command: "
+ << ifwCmd << std::endl
+ << "Please check " << ifwTmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+
+ if (!Repository.RepositoryUpdate.empty() &&
+ !Repository.PatchUpdatesXml()) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING, "Problem patch IFW \"Updates\" "
+ << "file: " << this->toplevel + "/repository/Updates.xml"
+ << std::endl);
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- repository: "
+ << this->toplevel << "/repository generated" << std::endl);
+ }
+
+ // Run binary creator
+ {
+ std::string ifwCmd = BinCreator;
+ ifwCmd += " -c " + this->toplevel + "/config/config.xml";
+ ifwCmd += " -p " + this->toplevel + "/packages";
+
+ if (!PkgsDirsVector.empty()) {
+ for (std::vector<std::string>::iterator it = PkgsDirsVector.begin();
+ it != PkgsDirsVector.end(); ++it) {
+ ifwCmd += " -p " + *it;
+ }
+ }
+
+ if (OnlineOnly) {
+ ifwCmd += " --online-only";
+ } else if (!DownloadedPackages.empty() &&
+ !Installer.RemoteRepositories.empty()) {
+ ifwCmd += " -e ";
+ std::set<cmCPackIFWPackage*>::iterator it = DownloadedPackages.begin();
+ ifwCmd += (*it)->Name;
+ ++it;
+ while (it != DownloadedPackages.end()) {
+ ifwCmd += "," + (*it)->Name;
+ ++it;
+ }
+ } else if (!DependentPackages.empty()) {
+ ifwCmd += " -i ";
+ // Binary
+ std::set<cmCPackIFWPackage*>::iterator bit = BinaryPackages.begin();
+ while (bit != BinaryPackages.end()) {
+ ifwCmd += (*bit)->Name + ",";
+ ++bit;
+ }
+ // Depend
+ DependenceMap::iterator it = DependentPackages.begin();
+ ifwCmd += it->second.Name;
+ ++it;
+ while (it != DependentPackages.end()) {
+ ifwCmd += "," + it->second.Name;
+ ++it;
+ }
+ }
+ // TODO: set correct name for multipackages
+ if (!this->packageFileNames.empty()) {
+ ifwCmd += " " + packageFileNames[0];
+ } else {
+ ifwCmd += " installer";
+ }
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << ifwCmd << std::endl);
+ std::string output;
+ int retVal = 1;
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Generate package" << std::endl);
+ bool res = cmSystemTools::RunSingleCommand(ifwCmd.c_str(), &output,
+ &output, &retVal, CM_NULLPTR,
+ this->GeneratorVerbose, 0);
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(ifwTmpFile.c_str());
+ ofs << "# Run command: " << ifwCmd << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running IFW command: "
+ << ifwCmd << std::endl
+ << "Please check " << ifwTmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+const char* cmCPackIFWGenerator::GetPackagingInstallPrefix()
+{
+ const char* defPrefix = cmCPackGenerator::GetPackagingInstallPrefix();
+
+ std::string tmpPref = defPrefix ? defPrefix : "";
+
+ if (this->Components.empty()) {
+ tmpPref += "packages/" + GetRootPackageName() + "/data";
+ }
+
+ this->SetOption("CPACK_IFW_PACKAGING_INSTALL_PREFIX", tmpPref.c_str());
+
+ return this->GetOption("CPACK_IFW_PACKAGING_INSTALL_PREFIX");
+}
+
+const char* cmCPackIFWGenerator::GetOutputExtension()
+{
+ return ExecutableSuffix.c_str();
+}
+
+int cmCPackIFWGenerator::InitializeInternal()
+{
+ // Search Qt Installer Framework tools
+
+ const std::string BinCreatorOpt = "CPACK_IFW_BINARYCREATOR_EXECUTABLE";
+ const std::string RepoGenOpt = "CPACK_IFW_REPOGEN_EXECUTABLE";
+ const std::string FrameworkVersionOpt = "CPACK_IFW_FRAMEWORK_VERSION";
+
+ if (!this->IsSet(BinCreatorOpt) || !this->IsSet(RepoGenOpt) ||
+ !this->IsSet(FrameworkVersionOpt)) {
+ this->ReadListFile("CPackIFW.cmake");
+ }
+
+ // Look 'binarycreator' executable (needs)
+
+ const char* BinCreatorStr = this->GetOption(BinCreatorOpt);
+ if (!BinCreatorStr || cmSystemTools::IsNOTFOUND(BinCreatorStr)) {
+ BinCreator = "";
+ } else {
+ BinCreator = BinCreatorStr;
+ }
+
+ if (BinCreator.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find QtIFW compiler \"binarycreator\": "
+ "likely it is not installed, or not in your PATH"
+ << std::endl);
+ return 0;
+ }
+
+ // Look 'repogen' executable (optional)
+
+ const char* RepoGenStr = this->GetOption(RepoGenOpt);
+ if (!RepoGenStr || cmSystemTools::IsNOTFOUND(RepoGenStr)) {
+ RepoGen = "";
+ } else {
+ RepoGen = RepoGenStr;
+ }
+
+ // Framework version
+ if (const char* FrameworkVersionSrt = this->GetOption(FrameworkVersionOpt)) {
+ FrameworkVersion = FrameworkVersionSrt;
+ } else {
+ FrameworkVersion = "1.9.9";
+ }
+
+ // Variables that Change Behavior
+
+ // Resolve duplicate names
+ ResolveDuplicateNames = this->IsOn("CPACK_IFW_RESOLVE_DUPLICATE_NAMES");
+
+ // Additional packages dirs
+ PkgsDirsVector.clear();
+ if (const char* dirs = this->GetOption("CPACK_IFW_PACKAGES_DIRECTORIES")) {
+ cmSystemTools::ExpandListArgument(dirs, PkgsDirsVector);
+ }
+
+ // Installer
+ Installer.Generator = this;
+ Installer.ConfigureFromOptions();
+
+ // Repository
+ Repository.Generator = this;
+ Repository.Name = "Unspecified";
+ if (const char* site = this->GetOption("CPACK_DOWNLOAD_SITE")) {
+ Repository.Url = site;
+ Installer.RemoteRepositories.push_back(&Repository);
+ }
+
+ // Repositories
+ if (const char* RepoAllStr = this->GetOption("CPACK_IFW_REPOSITORIES_ALL")) {
+ std::vector<std::string> RepoAllVector;
+ cmSystemTools::ExpandListArgument(RepoAllStr, RepoAllVector);
+ for (std::vector<std::string>::iterator rit = RepoAllVector.begin();
+ rit != RepoAllVector.end(); ++rit) {
+ GetRepository(*rit);
+ }
+ }
+
+ if (const char* ifwDownloadAll = this->GetOption("CPACK_IFW_DOWNLOAD_ALL")) {
+ OnlineOnly = cmSystemTools::IsOn(ifwDownloadAll);
+ } else if (const char* cpackDownloadAll =
+ this->GetOption("CPACK_DOWNLOAD_ALL")) {
+ OnlineOnly = cmSystemTools::IsOn(cpackDownloadAll);
+ } else {
+ OnlineOnly = false;
+ }
+
+ if (!Installer.RemoteRepositories.empty() && RepoGen.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find QtIFW repository generator \"repogen\": "
+ "likely it is not installed, or not in your PATH"
+ << std::endl);
+ return 0;
+ }
+
+ // Executable suffix
+ if (const char* optExeSuffix = this->GetOption("CMAKE_EXECUTABLE_SUFFIX")) {
+ ExecutableSuffix = optExeSuffix;
+ if (ExecutableSuffix.empty()) {
+ std::string sysName(this->GetOption("CMAKE_SYSTEM_NAME"));
+ if (sysName == "Linux") {
+ ExecutableSuffix = ".run";
+ }
+ }
+ } else {
+ ExecutableSuffix = cmCPackGenerator::GetOutputExtension();
+ }
+
+ return this->Superclass::InitializeInternal();
+}
+
+std::string cmCPackIFWGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ const std::string prefix = "packages/";
+ const std::string suffix = "/data";
+
+ if (componentPackageMethod == ONE_PACKAGE) {
+ return std::string(prefix + GetRootPackageName() + suffix);
+ }
+
+ return prefix + GetComponentPackageName(&Components[componentName]) + suffix;
+}
+
+cmCPackComponent* cmCPackIFWGenerator::GetComponent(
+ const std::string& projectName, const std::string& componentName)
+{
+ ComponentsMap::iterator cit = Components.find(componentName);
+ if (cit != Components.end()) {
+ return &(cit->second);
+ }
+
+ cmCPackComponent* component =
+ cmCPackGenerator::GetComponent(projectName, componentName);
+ if (!component) {
+ return component;
+ }
+
+ std::string name = GetComponentPackageName(component);
+ PackagesMap::iterator pit = Packages.find(name);
+ if (pit != Packages.end()) {
+ return component;
+ }
+
+ cmCPackIFWPackage* package = &Packages[name];
+ package->Name = name;
+ package->Generator = this;
+ if (package->ConfigureFromComponent(component)) {
+ package->Installer = &Installer;
+ Installer.Packages.insert(
+ std::pair<std::string, cmCPackIFWPackage*>(name, package));
+ ComponentPackages.insert(
+ std::pair<cmCPackComponent*, cmCPackIFWPackage*>(component, package));
+ if (component->IsDownloaded) {
+ DownloadedPackages.insert(package);
+ } else {
+ BinaryPackages.insert(package);
+ }
+ } else {
+ Packages.erase(name);
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot configure package \""
+ << name << "\" for component \"" << component->Name << "\""
+ << std::endl);
+ }
+
+ return component;
+}
+
+cmCPackComponentGroup* cmCPackIFWGenerator::GetComponentGroup(
+ const std::string& projectName, const std::string& groupName)
+{
+ cmCPackComponentGroup* group =
+ cmCPackGenerator::GetComponentGroup(projectName, groupName);
+ if (!group) {
+ return group;
+ }
+
+ std::string name = GetGroupPackageName(group);
+ PackagesMap::iterator pit = Packages.find(name);
+ if (pit != Packages.end()) {
+ return group;
+ }
+
+ cmCPackIFWPackage* package = &Packages[name];
+ package->Name = name;
+ package->Generator = this;
+ if (package->ConfigureFromGroup(group)) {
+ package->Installer = &Installer;
+ Installer.Packages.insert(
+ std::pair<std::string, cmCPackIFWPackage*>(name, package));
+ GroupPackages.insert(
+ std::pair<cmCPackComponentGroup*, cmCPackIFWPackage*>(group, package));
+ BinaryPackages.insert(package);
+ } else {
+ Packages.erase(name);
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot configure package \""
+ << name << "\" for component group \"" << group->Name
+ << "\"" << std::endl);
+ }
+ return group;
+}
+
+enum cmCPackGenerator::CPackSetDestdirSupport
+cmCPackIFWGenerator::SupportsSetDestdir() const
+{
+ return cmCPackGenerator::SETDESTDIR_SHOULD_NOT_BE_USED;
+}
+
+bool cmCPackIFWGenerator::SupportsAbsoluteDestination() const
+{
+ return false;
+}
+
+bool cmCPackIFWGenerator::SupportsComponentInstallation() const
+{
+ return true;
+}
+
+bool cmCPackIFWGenerator::IsOnePackage() const
+{
+ return componentPackageMethod == ONE_PACKAGE;
+}
+
+std::string cmCPackIFWGenerator::GetRootPackageName()
+{
+ // Default value
+ std::string name = "root";
+ if (const char* optIFW_PACKAGE_GROUP =
+ this->GetOption("CPACK_IFW_PACKAGE_GROUP")) {
+ // Configure from root group
+ cmCPackIFWPackage package;
+ package.Generator = this;
+ package.ConfigureFromGroup(optIFW_PACKAGE_GROUP);
+ name = package.Name;
+ } else if (const char* optIFW_PACKAGE_NAME =
+ this->GetOption("CPACK_IFW_PACKAGE_NAME")) {
+ // Configure from root package name
+ name = optIFW_PACKAGE_NAME;
+ } else if (const char* optPACKAGE_NAME =
+ this->GetOption("CPACK_PACKAGE_NAME")) {
+ // Configure from package name
+ name = optPACKAGE_NAME;
+ }
+ return name;
+}
+
+std::string cmCPackIFWGenerator::GetGroupPackageName(
+ cmCPackComponentGroup* group) const
+{
+ std::string name;
+ if (!group) {
+ return name;
+ }
+ if (cmCPackIFWPackage* package = GetGroupPackage(group)) {
+ return package->Name;
+ }
+ const char* option =
+ GetOption("CPACK_IFW_COMPONENT_GROUP_" +
+ cmsys::SystemTools::UpperCase(group->Name) + "_NAME");
+ name = option ? option : group->Name;
+ if (group->ParentGroup) {
+ cmCPackIFWPackage* package = GetGroupPackage(group->ParentGroup);
+ bool dot = !ResolveDuplicateNames;
+ if (dot && name.substr(0, package->Name.size()) == package->Name) {
+ dot = false;
+ }
+ if (dot) {
+ name = package->Name + "." + name;
+ }
+ }
+ return name;
+}
+
+std::string cmCPackIFWGenerator::GetComponentPackageName(
+ cmCPackComponent* component) const
+{
+ std::string name;
+ if (!component) {
+ return name;
+ }
+ if (cmCPackIFWPackage* package = GetComponentPackage(component)) {
+ return package->Name;
+ }
+ std::string prefix = "CPACK_IFW_COMPONENT_" +
+ cmsys::SystemTools::UpperCase(component->Name) + "_";
+ const char* option = GetOption(prefix + "NAME");
+ name = option ? option : component->Name;
+ if (component->Group) {
+ cmCPackIFWPackage* package = GetGroupPackage(component->Group);
+ if ((componentPackageMethod == ONE_PACKAGE_PER_GROUP) ||
+ IsOn(prefix + "COMMON")) {
+ return package->Name;
+ }
+ bool dot = !ResolveDuplicateNames;
+ if (dot && name.substr(0, package->Name.size()) == package->Name) {
+ dot = false;
+ }
+ if (dot) {
+ name = package->Name + "." + name;
+ }
+ }
+ return name;
+}
+
+cmCPackIFWPackage* cmCPackIFWGenerator::GetGroupPackage(
+ cmCPackComponentGroup* group) const
+{
+ std::map<cmCPackComponentGroup*, cmCPackIFWPackage*>::const_iterator pit =
+ GroupPackages.find(group);
+ return pit != GroupPackages.end() ? pit->second : CM_NULLPTR;
+}
+
+cmCPackIFWPackage* cmCPackIFWGenerator::GetComponentPackage(
+ cmCPackComponent* component) const
+{
+ std::map<cmCPackComponent*, cmCPackIFWPackage*>::const_iterator pit =
+ ComponentPackages.find(component);
+ return pit != ComponentPackages.end() ? pit->second : CM_NULLPTR;
+}
+
+cmCPackIFWRepository* cmCPackIFWGenerator::GetRepository(
+ const std::string& repositoryName)
+{
+ RepositoriesMap::iterator rit = Repositories.find(repositoryName);
+ if (rit != Repositories.end()) {
+ return &(rit->second);
+ }
+
+ cmCPackIFWRepository* repository = &Repositories[repositoryName];
+ repository->Name = repositoryName;
+ repository->Generator = this;
+ if (repository->ConfigureFromOptions()) {
+ if (repository->Update == cmCPackIFWRepository::None) {
+ Installer.RemoteRepositories.push_back(repository);
+ } else {
+ Repository.RepositoryUpdate.push_back(repository);
+ }
+ } else {
+ Repositories.erase(repositoryName);
+ repository = CM_NULLPTR;
+ cmCPackLogger(cmCPackLog::LOG_WARNING, "Invalid repository \""
+ << repositoryName << "\""
+ << " configuration. Repository will be skipped."
+ << std::endl);
+ }
+ return repository;
+}
+
+void cmCPackIFWGenerator::WriteGeneratedByToStrim(cmXMLWriter& xout)
+{
+ std::ostringstream comment;
+ comment << "Generated by CPack " << CMake_VERSION << " IFW generator "
+ << "for QtIFW ";
+ if (IsVersionLess("2.0")) {
+ comment << "less 2.0";
+ } else {
+ comment << FrameworkVersion;
+ }
+ comment << " tools at " << cmTimestamp().CurrentTime("", true);
+ xout.Comment(comment.str().c_str());
+}
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.h b/Source/CPack/IFW/cmCPackIFWGenerator.h
new file mode 100644
index 0000000..12f2ca6
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.h
@@ -0,0 +1,167 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackIFWGenerator_h
+#define cmCPackIFWGenerator_h
+
+#include <CPack/cmCPackGenerator.h>
+
+#include "cmCPackIFWInstaller.h"
+#include "cmCPackIFWPackage.h"
+#include "cmCPackIFWRepository.h"
+
+class cmXMLWriter;
+
+/** \class cmCPackIFWGenerator
+ * \brief A generator for Qt Installer Framework tools
+ *
+ * http://qt-project.org/doc/qtinstallerframework/index.html
+ */
+class cmCPackIFWGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackIFWGenerator, cmCPackGenerator);
+
+ typedef std::map<std::string, cmCPackIFWPackage> PackagesMap;
+ typedef std::map<std::string, cmCPackIFWRepository> RepositoriesMap;
+ typedef std::map<std::string, cmCPackComponent> ComponentsMap;
+ typedef std::map<std::string, cmCPackComponentGroup> ComponentGoupsMap;
+ typedef std::map<std::string, cmCPackIFWPackage::DependenceStruct>
+ DependenceMap;
+
+ /**
+ * Construct IFW generator
+ */
+ cmCPackIFWGenerator();
+
+ /**
+ * Destruct IFW generator
+ */
+ ~cmCPackIFWGenerator() CM_OVERRIDE;
+
+ /**
+ * Compare \a version with QtIFW framework version
+ */
+ bool IsVersionLess(const char* version);
+
+ /**
+ * Compare \a version with QtIFW framework version
+ */
+ bool IsVersionGreater(const char* version);
+
+ /**
+ * Compare \a version with QtIFW framework version
+ */
+ bool IsVersionEqual(const char* version);
+
+protected:
+ // cmCPackGenerator reimplementation
+
+ /**
+ * @brief Initialize generator
+ * @return 0 on failure
+ */
+ int InitializeInternal() CM_OVERRIDE;
+ int PackageFiles() CM_OVERRIDE;
+ const char* GetPackagingInstallPrefix() CM_OVERRIDE;
+
+ /**
+ * @brief Extension of binary installer
+ * @return Executable suffix or value from default implementation
+ */
+ const char* GetOutputExtension() CM_OVERRIDE;
+
+ std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName) CM_OVERRIDE;
+
+ /**
+ * @brief Get Component
+ * @param projectName Project name
+ * @param componentName Component name
+ *
+ * This method calls the base implementation.
+ *
+ * @return Pointer to component
+ */
+ cmCPackComponent* GetComponent(const std::string& projectName,
+ const std::string& componentName) CM_OVERRIDE;
+
+ /**
+ * @brief Get group of component
+ * @param projectName Project name
+ * @param groupName Component group name
+ *
+ * This method calls the base implementation.
+ *
+ * @return Pointer to component group
+ */
+ cmCPackComponentGroup* GetComponentGroup(
+ const std::string& projectName, const std::string& groupName) CM_OVERRIDE;
+
+ enum cmCPackGenerator::CPackSetDestdirSupport SupportsSetDestdir() const
+ CM_OVERRIDE;
+ bool SupportsAbsoluteDestination() const CM_OVERRIDE;
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+
+protected:
+ // Methods
+
+ bool IsOnePackage() const;
+
+ std::string GetRootPackageName();
+
+ std::string GetGroupPackageName(cmCPackComponentGroup* group) const;
+ std::string GetComponentPackageName(cmCPackComponent* component) const;
+
+ cmCPackIFWPackage* GetGroupPackage(cmCPackComponentGroup* group) const;
+ cmCPackIFWPackage* GetComponentPackage(cmCPackComponent* component) const;
+
+ cmCPackIFWRepository* GetRepository(const std::string& repositoryName);
+
+ void WriteGeneratedByToStrim(cmXMLWriter& xout);
+
+protected:
+ // Data
+
+ friend class cmCPackIFWPackage;
+ friend class cmCPackIFWInstaller;
+ friend class cmCPackIFWRepository;
+
+ // Installer
+ cmCPackIFWInstaller Installer;
+ // Repository
+ cmCPackIFWRepository Repository;
+ // Collection of packages
+ PackagesMap Packages;
+ // Collection of repositories
+ RepositoriesMap Repositories;
+ // Collection of binary packages
+ std::set<cmCPackIFWPackage*> BinaryPackages;
+ // Collection of downloaded packages
+ std::set<cmCPackIFWPackage*> DownloadedPackages;
+ // Dependent packages
+ DependenceMap DependentPackages;
+ std::map<cmCPackComponent*, cmCPackIFWPackage*> ComponentPackages;
+ std::map<cmCPackComponentGroup*, cmCPackIFWPackage*> GroupPackages;
+
+private:
+ std::string RepoGen;
+ std::string BinCreator;
+ std::string FrameworkVersion;
+ std::string ExecutableSuffix;
+
+ bool OnlineOnly;
+ bool ResolveDuplicateNames;
+ std::vector<std::string> PkgsDirsVector;
+};
+
+#endif
diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.cxx b/Source/CPack/IFW/cmCPackIFWInstaller.cxx
new file mode 100644
index 0000000..13a3613
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWInstaller.cxx
@@ -0,0 +1,349 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackIFWInstaller.h"
+
+#include "cmCPackIFWGenerator.h"
+
+#include <CPack/cmCPackLog.h>
+
+#include <cmGeneratedFileStream.h>
+#include <cmXMLWriter.h>
+
+#ifdef cmCPackLogger
+#undef cmCPackLogger
+#endif
+#define cmCPackLogger(logType, msg) \
+ do { \
+ std::ostringstream cmCPackLog_msg; \
+ cmCPackLog_msg << msg; \
+ if (Generator) { \
+ Generator->Logger->Log(logType, __FILE__, __LINE__, \
+ cmCPackLog_msg.str().c_str()); \
+ } \
+ } while (0)
+
+cmCPackIFWInstaller::cmCPackIFWInstaller()
+ : Generator(CM_NULLPTR)
+{
+}
+
+const char* cmCPackIFWInstaller::GetOption(const std::string& op) const
+{
+ return Generator ? Generator->GetOption(op) : CM_NULLPTR;
+}
+
+bool cmCPackIFWInstaller::IsOn(const std::string& op) const
+{
+ return Generator ? Generator->IsOn(op) : false;
+}
+
+bool cmCPackIFWInstaller::IsVersionLess(const char* version)
+{
+ return Generator ? Generator->IsVersionLess(version) : false;
+}
+
+bool cmCPackIFWInstaller::IsVersionGreater(const char* version)
+{
+ return Generator ? Generator->IsVersionGreater(version) : false;
+}
+
+bool cmCPackIFWInstaller::IsVersionEqual(const char* version)
+{
+ return Generator ? Generator->IsVersionEqual(version) : false;
+}
+
+void cmCPackIFWInstaller::ConfigureFromOptions()
+{
+ // Name;
+ if (const char* optIFW_PACKAGE_NAME =
+ this->GetOption("CPACK_IFW_PACKAGE_NAME")) {
+ Name = optIFW_PACKAGE_NAME;
+ } else if (const char* optPACKAGE_NAME =
+ this->GetOption("CPACK_PACKAGE_NAME")) {
+ Name = optPACKAGE_NAME;
+ } else {
+ Name = "Your package";
+ }
+
+ // Title;
+ if (const char* optIFW_PACKAGE_TITLE =
+ GetOption("CPACK_IFW_PACKAGE_TITLE")) {
+ Title = optIFW_PACKAGE_TITLE;
+ } else if (const char* optPACKAGE_DESCRIPTION_SUMMARY =
+ GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY")) {
+ Title = optPACKAGE_DESCRIPTION_SUMMARY;
+ } else {
+ Title = "Your package description";
+ }
+
+ // Version;
+ if (const char* option = GetOption("CPACK_PACKAGE_VERSION")) {
+ Version = option;
+ } else {
+ Version = "1.0.0";
+ }
+
+ // Publisher
+ if (const char* optIFW_PACKAGE_PUBLISHER =
+ GetOption("CPACK_IFW_PACKAGE_PUBLISHER")) {
+ Publisher = optIFW_PACKAGE_PUBLISHER;
+ } else if (const char* optPACKAGE_VENDOR =
+ GetOption("CPACK_PACKAGE_VENDOR")) {
+ Publisher = optPACKAGE_VENDOR;
+ }
+
+ // ProductUrl
+ if (const char* option = GetOption("CPACK_IFW_PRODUCT_URL")) {
+ ProductUrl = option;
+ }
+
+ // ApplicationIcon
+ if (const char* option = GetOption("CPACK_IFW_PACKAGE_ICON")) {
+ if (cmSystemTools::FileExists(option)) {
+ InstallerApplicationIcon = option;
+ } else {
+ // TODO: implement warning
+ }
+ }
+
+ // WindowIcon
+ if (const char* option = GetOption("CPACK_IFW_PACKAGE_WINDOW_ICON")) {
+ if (cmSystemTools::FileExists(option)) {
+ InstallerWindowIcon = option;
+ } else {
+ // TODO: implement warning
+ }
+ }
+
+ // Logo
+ if (const char* option = GetOption("CPACK_IFW_PACKAGE_LOGO")) {
+ if (cmSystemTools::FileExists(option)) {
+ Logo = option;
+ } else {
+ // TODO: implement warning
+ }
+ }
+
+ // Start menu
+ if (const char* optIFW_START_MENU_DIR =
+ this->GetOption("CPACK_IFW_PACKAGE_START_MENU_DIRECTORY")) {
+ StartMenuDir = optIFW_START_MENU_DIR;
+ } else {
+ StartMenuDir = Name;
+ }
+
+ // Default target directory for installation
+ if (const char* optIFW_TARGET_DIRECTORY =
+ GetOption("CPACK_IFW_TARGET_DIRECTORY")) {
+ TargetDir = optIFW_TARGET_DIRECTORY;
+ } else if (const char* optPACKAGE_INSTALL_DIRECTORY =
+ GetOption("CPACK_PACKAGE_INSTALL_DIRECTORY")) {
+ TargetDir = "@ApplicationsDir@/";
+ TargetDir += optPACKAGE_INSTALL_DIRECTORY;
+ } else {
+ TargetDir = "@RootDir@/usr/local";
+ }
+
+ // Default target directory for installation with administrator rights
+ if (const char* option = GetOption("CPACK_IFW_ADMIN_TARGET_DIRECTORY")) {
+ AdminTargetDir = option;
+ }
+
+ // Maintenance tool
+ if (const char* optIFW_MAINTENANCE_TOOL =
+ this->GetOption("CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_NAME")) {
+ MaintenanceToolName = optIFW_MAINTENANCE_TOOL;
+ }
+
+ // Maintenance tool ini file
+ if (const char* optIFW_MAINTENANCE_TOOL_INI =
+ this->GetOption("CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_INI_FILE")) {
+ MaintenanceToolIniFile = optIFW_MAINTENANCE_TOOL_INI;
+ }
+
+ // Allow non-ASCII characters
+ if (this->GetOption("CPACK_IFW_PACKAGE_ALLOW_NON_ASCII_CHARACTERS")) {
+ if (IsOn("CPACK_IFW_PACKAGE_ALLOW_NON_ASCII_CHARACTERS")) {
+ AllowNonAsciiCharacters = "true";
+ } else {
+ AllowNonAsciiCharacters = "false";
+ }
+ }
+
+ // Space in path
+ if (this->GetOption("CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH")) {
+ if (IsOn("CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH")) {
+ AllowSpaceInPath = "true";
+ } else {
+ AllowSpaceInPath = "false";
+ }
+ }
+
+ // Control script
+ if (const char* optIFW_CONTROL_SCRIPT =
+ this->GetOption("CPACK_IFW_PACKAGE_CONTROL_SCRIPT")) {
+ ControlScript = optIFW_CONTROL_SCRIPT;
+ }
+}
+
+void cmCPackIFWInstaller::GenerateInstallerFile()
+{
+ // Lazy directory initialization
+ if (Directory.empty() && Generator) {
+ Directory = Generator->toplevel;
+ }
+
+ // Output stream
+ cmGeneratedFileStream fout((Directory + "/config/config.xml").data());
+ cmXMLWriter xout(fout);
+
+ xout.StartDocument();
+
+ WriteGeneratedByToStrim(xout);
+
+ xout.StartElement("Installer");
+
+ xout.Element("Name", Name);
+ xout.Element("Version", Version);
+ xout.Element("Title", Title);
+
+ if (!Publisher.empty()) {
+ xout.Element("Publisher", Publisher);
+ }
+
+ if (!ProductUrl.empty()) {
+ xout.Element("ProductUrl", ProductUrl);
+ }
+
+ // ApplicationIcon
+ if (!InstallerApplicationIcon.empty()) {
+ std::string name =
+ cmSystemTools::GetFilenameName(InstallerApplicationIcon);
+ std::string path = Directory + "/config/" + name;
+ name = cmSystemTools::GetFilenameWithoutExtension(name);
+ cmsys::SystemTools::CopyFileIfDifferent(InstallerApplicationIcon.data(),
+ path.data());
+ xout.Element("InstallerApplicationIcon", name);
+ }
+
+ // WindowIcon
+ if (!InstallerWindowIcon.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(InstallerWindowIcon);
+ std::string path = Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(InstallerWindowIcon.data(),
+ path.data());
+ xout.Element("InstallerWindowIcon", name);
+ }
+
+ // Logo
+ if (!Logo.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(Logo);
+ std::string path = Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(Logo.data(), path.data());
+ xout.Element("Logo", name);
+ }
+
+ // Start menu
+ if (!IsVersionLess("2.0")) {
+ xout.Element("StartMenuDir", StartMenuDir);
+ }
+
+ // Target dir
+ if (!TargetDir.empty()) {
+ xout.Element("TargetDir", TargetDir);
+ }
+
+ // Admin target dir
+ if (!AdminTargetDir.empty()) {
+ xout.Element("AdminTargetDir", AdminTargetDir);
+ }
+
+ // Remote repositories
+ if (!RemoteRepositories.empty()) {
+ xout.StartElement("RemoteRepositories");
+ for (RepositoriesVector::iterator rit = RemoteRepositories.begin();
+ rit != RemoteRepositories.end(); ++rit) {
+ (*rit)->WriteRepositoryConfig(xout);
+ }
+ xout.EndElement();
+ }
+
+ // Maintenance tool
+ if (!IsVersionLess("2.0") && !MaintenanceToolName.empty()) {
+ xout.Element("MaintenanceToolName", MaintenanceToolName);
+ }
+
+ // Maintenance tool ini file
+ if (!IsVersionLess("2.0") && !MaintenanceToolIniFile.empty()) {
+ xout.Element("MaintenanceToolIniFile", MaintenanceToolIniFile);
+ }
+
+ // Different allows
+ if (IsVersionLess("2.0")) {
+ // CPack IFW default policy
+ xout.Comment("CPack IFW default policy for QtIFW less 2.0");
+ xout.Element("AllowNonAsciiCharacters", "true");
+ xout.Element("AllowSpaceInPath", "true");
+ } else {
+ if (!AllowNonAsciiCharacters.empty()) {
+ xout.Element("AllowNonAsciiCharacters", AllowNonAsciiCharacters);
+ }
+ if (!AllowSpaceInPath.empty()) {
+ xout.Element("AllowSpaceInPath", AllowSpaceInPath);
+ }
+ }
+
+ // Control script (copy to config dir)
+ if (!IsVersionLess("2.0") && !ControlScript.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(ControlScript);
+ std::string path = Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(ControlScript.data(), path.data());
+ xout.Element("ControlScript", name);
+ }
+
+ xout.EndElement();
+ xout.EndDocument();
+}
+
+void cmCPackIFWInstaller::GeneratePackageFiles()
+{
+ if (Packages.empty() || Generator->IsOnePackage()) {
+ // Generate default package
+ cmCPackIFWPackage package;
+ package.Generator = Generator;
+ package.Installer = this;
+ // Check package group
+ if (const char* option = GetOption("CPACK_IFW_PACKAGE_GROUP")) {
+ package.ConfigureFromGroup(option);
+ package.ForcedInstallation = "true";
+ } else {
+ package.ConfigureFromOptions();
+ }
+ package.GeneratePackageFile();
+ return;
+ }
+
+ // Generate packages meta information
+ for (PackagesMap::iterator pit = Packages.begin(); pit != Packages.end();
+ ++pit) {
+ cmCPackIFWPackage* package = pit->second;
+ package->GeneratePackageFile();
+ }
+}
+
+void cmCPackIFWInstaller::WriteGeneratedByToStrim(cmXMLWriter& xout)
+{
+ if (Generator) {
+ Generator->WriteGeneratedByToStrim(xout);
+ }
+}
diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.h b/Source/CPack/IFW/cmCPackIFWInstaller.h
new file mode 100644
index 0000000..3170116
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWInstaller.h
@@ -0,0 +1,118 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackIFWInstaller_h
+#define cmCPackIFWInstaller_h
+
+#include <cmStandardIncludes.h>
+
+class cmCPackIFWPackage;
+class cmCPackIFWGenerator;
+class cmCPackIFWRepository;
+class cmXMLWriter;
+
+/** \class cmCPackIFWInstaller
+ * \brief A binary installer to be created CPack IFW generator
+ */
+class cmCPackIFWInstaller
+{
+public:
+ // Types
+
+ typedef std::map<std::string, cmCPackIFWPackage*> PackagesMap;
+ typedef std::vector<cmCPackIFWRepository*> RepositoriesVector;
+
+public:
+ // Constructor
+
+ /**
+ * Construct installer
+ */
+ cmCPackIFWInstaller();
+
+public:
+ // Configuration
+
+ /// Name of the product being installed
+ std::string Name;
+
+ /// Version number of the product being installed
+ std::string Version;
+
+ /// Name of the installer as displayed on the title bar
+ std::string Title;
+
+ /// Publisher of the software (as shown in the Windows Control Panel)
+ std::string Publisher;
+
+ /// URL to a page that contains product information on your web site
+ std::string ProductUrl;
+
+ /// Filename for a custom installer icon
+ std::string InstallerApplicationIcon;
+
+ /// Filename for a custom window icon
+ std::string InstallerWindowIcon;
+
+ /// Filename for a logo
+ std::string Logo;
+
+ /// Name of the default program group in the Windows Start menu
+ std::string StartMenuDir;
+
+ /// Default target directory for installation
+ std::string TargetDir;
+
+ /// Default target directory for installation with administrator rights
+ std::string AdminTargetDir;
+
+ /// Filename of the generated maintenance tool
+ std::string MaintenanceToolName;
+
+ /// Filename for the configuration of the generated maintenance tool
+ std::string MaintenanceToolIniFile;
+
+ /// Set to true if the installation path can contain non-ASCII characters
+ std::string AllowNonAsciiCharacters;
+
+ /// Set to false if the installation path cannot contain space characters
+ std::string AllowSpaceInPath;
+
+ /// Filename for a custom installer control script
+ std::string ControlScript;
+
+public:
+ // Internal implementation
+
+ const char* GetOption(const std::string& op) const;
+ bool IsOn(const std::string& op) const;
+
+ bool IsVersionLess(const char* version);
+ bool IsVersionGreater(const char* version);
+ bool IsVersionEqual(const char* version);
+
+ void ConfigureFromOptions();
+
+ void GenerateInstallerFile();
+
+ void GeneratePackageFiles();
+
+ cmCPackIFWGenerator* Generator;
+ PackagesMap Packages;
+ RepositoriesVector RemoteRepositories;
+ std::string Directory;
+
+protected:
+ void WriteGeneratedByToStrim(cmXMLWriter& xout);
+};
+
+#endif // cmCPackIFWInstaller_h
diff --git a/Source/CPack/IFW/cmCPackIFWPackage.cxx b/Source/CPack/IFW/cmCPackIFWPackage.cxx
new file mode 100644
index 0000000..5db06e6
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWPackage.cxx
@@ -0,0 +1,484 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackIFWPackage.h"
+
+#include "cmCPackIFWGenerator.h"
+
+#include <CPack/cmCPackLog.h>
+
+#include <cmGeneratedFileStream.h>
+#include <cmTimestamp.h>
+#include <cmXMLWriter.h>
+
+//----------------------------------------------------------------- Logger ---
+#ifdef cmCPackLogger
+#undef cmCPackLogger
+#endif
+#define cmCPackLogger(logType, msg) \
+ do { \
+ std::ostringstream cmCPackLog_msg; \
+ cmCPackLog_msg << msg; \
+ if (Generator) { \
+ Generator->Logger->Log(logType, __FILE__, __LINE__, \
+ cmCPackLog_msg.str().c_str()); \
+ } \
+ } while (0)
+
+//---------------------------------------------------------- CompareStruct ---
+cmCPackIFWPackage::CompareStruct::CompareStruct()
+ : Type(CompareNone)
+{
+}
+
+//------------------------------------------------------- DependenceStruct ---
+cmCPackIFWPackage::DependenceStruct::DependenceStruct()
+{
+}
+
+cmCPackIFWPackage::DependenceStruct::DependenceStruct(
+ const std::string& dependence)
+{
+ // Search compare section
+ size_t pos = std::string::npos;
+ if ((pos = dependence.find("<=")) != std::string::npos) {
+ Compare.Type = CompareLessOrEqual;
+ Compare.Value = dependence.substr(pos + 2);
+ } else if ((pos = dependence.find(">=")) != std::string::npos) {
+ Compare.Type = CompareGreaterOrEqual;
+ Compare.Value = dependence.substr(pos + 2);
+ } else if ((pos = dependence.find('<')) != std::string::npos) {
+ Compare.Type = CompareLess;
+ Compare.Value = dependence.substr(pos + 1);
+ } else if ((pos = dependence.find('=')) != std::string::npos) {
+ Compare.Type = CompareEqual;
+ Compare.Value = dependence.substr(pos + 1);
+ } else if ((pos = dependence.find('>')) != std::string::npos) {
+ Compare.Type = CompareGreater;
+ Compare.Value = dependence.substr(pos + 1);
+ }
+ Name = pos == std::string::npos ? dependence : dependence.substr(0, pos);
+}
+
+std::string cmCPackIFWPackage::DependenceStruct::NameWithCompare() const
+{
+ if (Compare.Type == CompareNone) {
+ return Name;
+ }
+
+ std::string result = Name;
+
+ if (Compare.Type == CompareLessOrEqual) {
+ result += "<=";
+ } else if (Compare.Type == CompareGreaterOrEqual) {
+ result += ">=";
+ } else if (Compare.Type == CompareLess) {
+ result += "<";
+ } else if (Compare.Type == CompareEqual) {
+ result += "=";
+ } else if (Compare.Type == CompareGreater) {
+ result += ">";
+ }
+
+ result += Compare.Value;
+
+ return result;
+}
+
+//------------------------------------------------------ cmCPackIFWPackage ---
+cmCPackIFWPackage::cmCPackIFWPackage()
+ : Generator(CM_NULLPTR)
+ , Installer(CM_NULLPTR)
+{
+}
+
+const char* cmCPackIFWPackage::GetOption(const std::string& op) const
+{
+ const char* option = Generator ? Generator->GetOption(op) : CM_NULLPTR;
+ return option && *option ? option : CM_NULLPTR;
+}
+
+bool cmCPackIFWPackage::IsOn(const std::string& op) const
+{
+ return Generator ? Generator->IsOn(op) : false;
+}
+
+bool cmCPackIFWPackage::IsVersionLess(const char* version)
+{
+ return Generator ? Generator->IsVersionLess(version) : false;
+}
+
+bool cmCPackIFWPackage::IsVersionGreater(const char* version)
+{
+ return Generator ? Generator->IsVersionGreater(version) : false;
+}
+
+bool cmCPackIFWPackage::IsVersionEqual(const char* version)
+{
+ return Generator ? Generator->IsVersionEqual(version) : false;
+}
+
+std::string cmCPackIFWPackage::GetComponentName(cmCPackComponent* component)
+{
+ if (!component) {
+ return "";
+ }
+ const char* option =
+ GetOption("CPACK_IFW_COMPONENT_" +
+ cmsys::SystemTools::UpperCase(component->Name) + "_NAME");
+ return option ? option : component->Name;
+}
+
+void cmCPackIFWPackage::DefaultConfiguration()
+{
+ DisplayName = "";
+ Description = "";
+ Version = "";
+ ReleaseDate = "";
+ Script = "";
+ Licenses.clear();
+ SortingPriority = "";
+ Default = "";
+ Essential = "";
+ Virtual = "";
+ ForcedInstallation = "";
+}
+
+// Defaul configuration (all in one package)
+int cmCPackIFWPackage::ConfigureFromOptions()
+{
+ // Restore defaul configuration
+ DefaultConfiguration();
+
+ // Name
+ Name = Generator->GetRootPackageName();
+
+ // Display name
+ if (const char* option = this->GetOption("CPACK_PACKAGE_NAME")) {
+ DisplayName = option;
+ } else {
+ DisplayName = "Your package";
+ }
+
+ // Description
+ if (const char* option =
+ this->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY")) {
+ Description = option;
+ } else {
+ Description = "Your package description";
+ }
+
+ // Version
+ if (const char* option = GetOption("CPACK_PACKAGE_VERSION")) {
+ Version = option;
+ } else {
+ Version = "1.0.0";
+ }
+
+ ForcedInstallation = "true";
+
+ return 1;
+}
+
+int cmCPackIFWPackage::ConfigureFromComponent(cmCPackComponent* component)
+{
+ if (!component) {
+ return 0;
+ }
+
+ // Restore defaul configuration
+ DefaultConfiguration();
+
+ std::string prefix = "CPACK_IFW_COMPONENT_" +
+ cmsys::SystemTools::UpperCase(component->Name) + "_";
+
+ // Display name
+ DisplayName = component->DisplayName;
+
+ // Description
+ Description = component->Description;
+
+ // Version
+ if (const char* optVERSION = GetOption(prefix + "VERSION")) {
+ Version = optVERSION;
+ } else if (const char* optPACKAGE_VERSION =
+ GetOption("CPACK_PACKAGE_VERSION")) {
+ Version = optPACKAGE_VERSION;
+ } else {
+ Version = "1.0.0";
+ }
+
+ // Script
+ if (const char* option = GetOption(prefix + "SCRIPT")) {
+ Script = option;
+ }
+
+ // CMake dependencies
+ if (!component->Dependencies.empty()) {
+ std::vector<cmCPackComponent*>::iterator dit;
+ for (dit = component->Dependencies.begin();
+ dit != component->Dependencies.end(); ++dit) {
+ Dependencies.insert(Generator->ComponentPackages[*dit]);
+ }
+ }
+
+ // QtIFW dependencies
+ if (const char* option = this->GetOption(prefix + "DEPENDS")) {
+ std::vector<std::string> deps;
+ cmSystemTools::ExpandListArgument(option, deps);
+ for (std::vector<std::string>::iterator dit = deps.begin();
+ dit != deps.end(); ++dit) {
+ DependenceStruct dep(*dit);
+ if (!Generator->Packages.count(dep.Name)) {
+ bool hasDep = Generator->DependentPackages.count(dep.Name) > 0;
+ DependenceStruct& depRef = Generator->DependentPackages[dep.Name];
+ if (!hasDep) {
+ depRef = dep;
+ }
+ AlienDependencies.insert(&depRef);
+ }
+ }
+ }
+
+ // Licenses
+ if (const char* option = this->GetOption(prefix + "LICENSES")) {
+ Licenses.clear();
+ cmSystemTools::ExpandListArgument(option, Licenses);
+ if (Licenses.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING, prefix
+ << "LICENSES"
+ << " should contain pairs of <display_name> and <file_path>."
+ << std::endl);
+ Licenses.clear();
+ }
+ }
+
+ // Priority
+ if (const char* option = this->GetOption(prefix + "PRIORITY")) {
+ SortingPriority = option;
+ }
+
+ // Default
+ Default = component->IsDisabledByDefault ? "false" : "true";
+
+ // Essential
+ if (this->IsOn(prefix + "ESSENTIAL")) {
+ Essential = "true";
+ }
+
+ // Virtual
+ Virtual = component->IsHidden ? "true" : "";
+
+ // ForcedInstallation
+ ForcedInstallation = component->IsRequired ? "true" : "false";
+
+ return 1;
+}
+
+int cmCPackIFWPackage::ConfigureFromGroup(cmCPackComponentGroup* group)
+{
+ if (!group) {
+ return 0;
+ }
+
+ // Restore defaul configuration
+ DefaultConfiguration();
+
+ std::string prefix = "CPACK_IFW_COMPONENT_GROUP_" +
+ cmsys::SystemTools::UpperCase(group->Name) + "_";
+
+ DisplayName = group->DisplayName;
+ Description = group->Description;
+
+ // Version
+ if (const char* optVERSION = GetOption(prefix + "VERSION")) {
+ Version = optVERSION;
+ } else if (const char* optPACKAGE_VERSION =
+ GetOption("CPACK_PACKAGE_VERSION")) {
+ Version = optPACKAGE_VERSION;
+ } else {
+ Version = "1.0.0";
+ }
+
+ // Script
+ if (const char* option = GetOption(prefix + "SCRIPT")) {
+ Script = option;
+ }
+
+ // Licenses
+ if (const char* option = this->GetOption(prefix + "LICENSES")) {
+ Licenses.clear();
+ cmSystemTools::ExpandListArgument(option, Licenses);
+ if (Licenses.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING, prefix
+ << "LICENSES"
+ << " should contain pairs of <display_name> and <file_path>."
+ << std::endl);
+ Licenses.clear();
+ }
+ }
+
+ // Priority
+ if (const char* option = this->GetOption(prefix + "PRIORITY")) {
+ SortingPriority = option;
+ }
+
+ return 1;
+}
+
+int cmCPackIFWPackage::ConfigureFromGroup(const std::string& groupName)
+{
+ // Group configuration
+
+ cmCPackComponentGroup group;
+ std::string prefix =
+ "CPACK_COMPONENT_GROUP_" + cmsys::SystemTools::UpperCase(groupName) + "_";
+
+ if (const char* option = GetOption(prefix + "DISPLAY_NAME")) {
+ group.DisplayName = option;
+ } else {
+ group.DisplayName = group.Name;
+ }
+
+ if (const char* option = GetOption(prefix + "DESCRIPTION")) {
+ group.Description = option;
+ }
+ group.IsBold = IsOn(prefix + "BOLD_TITLE");
+ group.IsExpandedByDefault = IsOn(prefix + "EXPANDED");
+
+ // Package configuration
+
+ group.Name = groupName;
+
+ if (Generator) {
+ Name = Generator->GetGroupPackageName(&group);
+ } else {
+ Name = group.Name;
+ }
+
+ return ConfigureFromGroup(&group);
+}
+
+void cmCPackIFWPackage::GeneratePackageFile()
+{
+ // Lazy directory initialization
+ if (Directory.empty()) {
+ if (Installer) {
+ Directory = Installer->Directory + "/packages/" + Name;
+ } else if (Generator) {
+ Directory = Generator->toplevel + "/packages/" + Name;
+ }
+ }
+
+ // Output stream
+ cmGeneratedFileStream fout((Directory + "/meta/package.xml").data());
+ cmXMLWriter xout(fout);
+
+ xout.StartDocument();
+
+ WriteGeneratedByToStrim(xout);
+
+ xout.StartElement("Package");
+
+ xout.Element("DisplayName", DisplayName);
+ xout.Element("Description", Description);
+ xout.Element("Name", Name);
+ xout.Element("Version", Version);
+
+ if (!ReleaseDate.empty()) {
+ xout.Element("ReleaseDate", ReleaseDate);
+ } else {
+ xout.Element("ReleaseDate", cmTimestamp().CurrentTime("%Y-%m-%d", true));
+ }
+
+ // Script (copy to meta dir)
+ if (!Script.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(Script);
+ std::string path = Directory + "/meta/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(Script.data(), path.data());
+ xout.Element("Script", name);
+ }
+
+ // Dependencies
+ std::set<DependenceStruct> compDepSet;
+ for (std::set<DependenceStruct*>::iterator ait = AlienDependencies.begin();
+ ait != AlienDependencies.end(); ++ait) {
+ compDepSet.insert(*(*ait));
+ }
+ for (std::set<cmCPackIFWPackage*>::iterator it = Dependencies.begin();
+ it != Dependencies.end(); ++it) {
+ compDepSet.insert(DependenceStruct((*it)->Name));
+ }
+ // Write dependencies
+ if (!compDepSet.empty()) {
+ std::ostringstream dependencies;
+ std::set<DependenceStruct>::iterator it = compDepSet.begin();
+ dependencies << it->NameWithCompare();
+ ++it;
+ while (it != compDepSet.end()) {
+ dependencies << "," << it->NameWithCompare();
+ ++it;
+ }
+ xout.Element("Dependencies", dependencies.str());
+ }
+
+ // Licenses (copy to meta dir)
+ std::vector<std::string> licenses = Licenses;
+ for (size_t i = 1; i < licenses.size(); i += 2) {
+ std::string name = cmSystemTools::GetFilenameName(licenses[i]);
+ std::string path = Directory + "/meta/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(licenses[i].data(), path.data());
+ licenses[i] = name;
+ }
+ if (!licenses.empty()) {
+ xout.StartElement("Licenses");
+ for (size_t i = 0; i < licenses.size(); i += 2) {
+ xout.StartElement("License");
+ xout.Attribute("name", licenses[i]);
+ xout.Attribute("file", licenses[i + 1]);
+ xout.EndElement();
+ }
+ xout.EndElement();
+ }
+
+ if (!ForcedInstallation.empty()) {
+ xout.Element("ForcedInstallation", ForcedInstallation);
+ }
+
+ if (!Virtual.empty()) {
+ xout.Element("Virtual", Virtual);
+ } else if (!Default.empty()) {
+ xout.Element("Default", Default);
+ }
+
+ // Essential
+ if (!Essential.empty()) {
+ xout.Element("Essential", Essential);
+ }
+
+ // Priority
+ if (!SortingPriority.empty()) {
+ xout.Element("SortingPriority", SortingPriority);
+ }
+
+ xout.EndElement();
+ xout.EndDocument();
+}
+
+void cmCPackIFWPackage::WriteGeneratedByToStrim(cmXMLWriter& xout)
+{
+ if (Generator) {
+ Generator->WriteGeneratedByToStrim(xout);
+ }
+}
diff --git a/Source/CPack/IFW/cmCPackIFWPackage.h b/Source/CPack/IFW/cmCPackIFWPackage.h
new file mode 100644
index 0000000..55b07ec
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWPackage.h
@@ -0,0 +1,149 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackIFWPackage_h
+#define cmCPackIFWPackage_h
+
+#include <cmStandardIncludes.h>
+
+class cmCPackComponent;
+class cmCPackComponentGroup;
+class cmCPackIFWInstaller;
+class cmCPackIFWGenerator;
+class cmXMLWriter;
+
+/** \class cmCPackIFWPackage
+ * \brief A single component to be installed by CPack IFW generator
+ */
+class cmCPackIFWPackage
+{
+public:
+ // Types
+
+ enum CompareTypes
+ {
+ CompareNone = 0x0,
+ CompareEqual = 0x1,
+ CompareLess = 0x2,
+ CompareLessOrEqual = 0x3,
+ CompareGreater = 0x4,
+ CompareGreaterOrEqual = 0x5
+ };
+
+ struct CompareStruct
+ {
+ CompareStruct();
+
+ unsigned int Type;
+ std::string Value;
+ };
+
+ struct DependenceStruct
+ {
+ DependenceStruct();
+ DependenceStruct(const std::string& dependence);
+
+ std::string Name;
+ CompareStruct Compare;
+
+ std::string NameWithCompare() const;
+
+ bool operator<(const DependenceStruct& other) const
+ {
+ return Name < other.Name;
+ }
+ };
+
+public:
+ // [Con|De]structor
+
+ /**
+ * Construct package
+ */
+ cmCPackIFWPackage();
+
+public:
+ // Configuration
+
+ /// Human-readable name of the component
+ std::string DisplayName;
+
+ /// Human-readable description of the component
+ std::string Description;
+
+ /// Version number of the component
+ std::string Version;
+
+ /// Date when this component version was released
+ std::string ReleaseDate;
+
+ /// Domain-like identification for this component
+ std::string Name;
+
+ /// File name of a script being loaded
+ std::string Script;
+
+ /// List of license agreements to be accepted by the installing user
+ std::vector<std::string> Licenses;
+
+ /// Priority of the component in the tree
+ std::string SortingPriority;
+
+ /// Set to true to preselect the component in the installer
+ std::string Default;
+
+ /// Marks the package as essential to force a restart of the MaintenanceTool
+ std::string Essential;
+
+ /// Set to true to hide the component from the installer
+ std::string Virtual;
+
+ /// Determines that the package must always be installed
+ std::string ForcedInstallation;
+
+public:
+ // Internal implementation
+
+ const char* GetOption(const std::string& op) const;
+ bool IsOn(const std::string& op) const;
+
+ bool IsVersionLess(const char* version);
+ bool IsVersionGreater(const char* version);
+ bool IsVersionEqual(const char* version);
+
+ std::string GetComponentName(cmCPackComponent* component);
+
+ void DefaultConfiguration();
+
+ int ConfigureFromOptions();
+ int ConfigureFromComponent(cmCPackComponent* component);
+ int ConfigureFromGroup(cmCPackComponentGroup* group);
+ int ConfigureFromGroup(const std::string& groupName);
+
+ void GeneratePackageFile();
+
+ // Pointer to generator
+ cmCPackIFWGenerator* Generator;
+ // Pointer to installer
+ cmCPackIFWInstaller* Installer;
+ // Collection of dependencies
+ std::set<cmCPackIFWPackage*> Dependencies;
+ // Collection of unresolved dependencies
+ std::set<DependenceStruct*> AlienDependencies;
+ // Patch to package directory
+ std::string Directory;
+
+protected:
+ void WriteGeneratedByToStrim(cmXMLWriter& xout);
+};
+
+#endif // cmCPackIFWPackage_h
diff --git a/Source/CPack/IFW/cmCPackIFWRepository.cxx b/Source/CPack/IFW/cmCPackIFWRepository.cxx
new file mode 100644
index 0000000..ee6d5e5
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWRepository.cxx
@@ -0,0 +1,342 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackIFWRepository.h"
+
+#include "cmCPackIFWGenerator.h"
+
+#include <CPack/cmCPackLog.h>
+
+#include <cmGeneratedFileStream.h>
+#include <cmXMLParser.h>
+#include <cmXMLWriter.h>
+
+#ifdef cmCPackLogger
+#undef cmCPackLogger
+#endif
+#define cmCPackLogger(logType, msg) \
+ do { \
+ std::ostringstream cmCPackLog_msg; \
+ cmCPackLog_msg << msg; \
+ if (Generator) { \
+ Generator->Logger->Log(logType, __FILE__, __LINE__, \
+ cmCPackLog_msg.str().c_str()); \
+ } \
+ } while (0)
+
+cmCPackIFWRepository::cmCPackIFWRepository()
+ : Update(None)
+ , Generator(CM_NULLPTR)
+{
+}
+
+bool cmCPackIFWRepository::IsValid() const
+{
+ bool valid = true;
+
+ switch (Update) {
+ case None:
+ valid = !Url.empty();
+ break;
+ case Add:
+ valid = !Url.empty();
+ break;
+ case Remove:
+ valid = !Url.empty();
+ break;
+ case Replace:
+ valid = !OldUrl.empty() && !NewUrl.empty();
+ break;
+ }
+
+ return valid;
+}
+
+const char* cmCPackIFWRepository::GetOption(const std::string& op) const
+{
+ return Generator ? Generator->GetOption(op) : CM_NULLPTR;
+}
+
+bool cmCPackIFWRepository::IsOn(const std::string& op) const
+{
+ return Generator ? Generator->IsOn(op) : false;
+}
+
+bool cmCPackIFWRepository::IsVersionLess(const char* version)
+{
+ return Generator ? Generator->IsVersionLess(version) : false;
+}
+
+bool cmCPackIFWRepository::IsVersionGreater(const char* version)
+{
+ return Generator ? Generator->IsVersionGreater(version) : false;
+}
+
+bool cmCPackIFWRepository::IsVersionEqual(const char* version)
+{
+ return Generator ? Generator->IsVersionEqual(version) : false;
+}
+
+bool cmCPackIFWRepository::ConfigureFromOptions()
+{
+ // Name;
+ if (Name.empty()) {
+ return false;
+ }
+
+ std::string prefix =
+ "CPACK_IFW_REPOSITORY_" + cmsys::SystemTools::UpperCase(Name) + "_";
+
+ // Update
+ if (IsOn(prefix + "ADD")) {
+ Update = Add;
+ } else if (IsOn(prefix + "REMOVE")) {
+ Update = Remove;
+ } else if (IsOn(prefix + "REPLACE")) {
+ Update = Replace;
+ } else {
+ Update = None;
+ }
+
+ // Url
+ if (const char* url = GetOption(prefix + "URL")) {
+ Url = url;
+ } else {
+ Url = "";
+ }
+
+ // Old url
+ if (const char* oldUrl = GetOption(prefix + "OLD_URL")) {
+ OldUrl = oldUrl;
+ } else {
+ OldUrl = "";
+ }
+
+ // New url
+ if (const char* newUrl = GetOption(prefix + "NEW_URL")) {
+ NewUrl = newUrl;
+ } else {
+ NewUrl = "";
+ }
+
+ // Enabled
+ if (IsOn(prefix + "DISABLED")) {
+ Enabled = "0";
+ } else {
+ Enabled = "";
+ }
+
+ // Username
+ if (const char* username = GetOption(prefix + "USERNAME")) {
+ Username = username;
+ } else {
+ Username = "";
+ }
+
+ // Password
+ if (const char* password = GetOption(prefix + "PASSWORD")) {
+ Password = password;
+ } else {
+ Password = "";
+ }
+
+ // DisplayName
+ if (const char* displayName = GetOption(prefix + "DISPLAY_NAME")) {
+ DisplayName = displayName;
+ } else {
+ DisplayName = "";
+ }
+
+ return IsValid();
+}
+
+/** \class cmCPackeIFWUpdatesPatcher
+ * \brief Helper class that parses and patch Updates.xml file (QtIFW)
+ */
+class cmCPackeIFWUpdatesPatcher : public cmXMLParser
+{
+public:
+ cmCPackeIFWUpdatesPatcher(cmCPackIFWRepository* r, cmXMLWriter& x)
+ : repository(r)
+ , xout(x)
+ , patched(false)
+ {
+ }
+
+ cmCPackIFWRepository* repository;
+ cmXMLWriter& xout;
+ bool patched;
+
+protected:
+ void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
+ {
+ xout.StartElement(name);
+ StartFragment(atts);
+ }
+
+ void StartFragment(const char** atts)
+ {
+ for (size_t i = 0; atts[i]; i += 2) {
+ const char* key = atts[i];
+ const char* value = atts[i + 1];
+ xout.Attribute(key, value);
+ }
+ }
+
+ void EndElement(const std::string& name) CM_OVERRIDE
+ {
+ if (name == "Updates" && !patched) {
+ repository->WriteRepositoryUpdates(xout);
+ patched = true;
+ }
+ xout.EndElement();
+ if (patched) {
+ return;
+ }
+ if (name == "Checksum") {
+ repository->WriteRepositoryUpdates(xout);
+ patched = true;
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) CM_OVERRIDE
+ {
+ std::string content(data, data + length);
+ if (content == "" || content == " " || content == " " ||
+ content == "\n") {
+ return;
+ }
+ xout.Content(content);
+ }
+};
+
+bool cmCPackIFWRepository::PatchUpdatesXml()
+{
+ // Lazy directory initialization
+ if (Directory.empty() && Generator) {
+ Directory = Generator->toplevel;
+ }
+
+ // Filenames
+ std::string updatesXml = Directory + "/repository/Updates.xml";
+ std::string updatesPatchXml = Directory + "/repository/UpdatesPatch.xml";
+
+ // Output stream
+ cmGeneratedFileStream fout(updatesPatchXml.data());
+ cmXMLWriter xout(fout);
+
+ xout.StartDocument();
+
+ WriteGeneratedByToStrim(xout);
+
+ // Patch
+ {
+ cmCPackeIFWUpdatesPatcher patcher(this, xout);
+ patcher.ParseFile(updatesXml.data());
+ }
+
+ xout.EndDocument();
+
+ fout.Close();
+
+ return cmSystemTools::RenameFile(updatesPatchXml.data(), updatesXml.data());
+}
+
+void cmCPackIFWRepository::WriteRepositoryConfig(cmXMLWriter& xout)
+{
+ xout.StartElement("Repository");
+
+ // Url
+ xout.Element("Url", Url);
+ // Enabled
+ if (!Enabled.empty()) {
+ xout.Element("Enabled", Enabled);
+ }
+ // Username
+ if (!Username.empty()) {
+ xout.Element("Username", Username);
+ }
+ // Password
+ if (!Password.empty()) {
+ xout.Element("Password", Password);
+ }
+ // DisplayName
+ if (!DisplayName.empty()) {
+ xout.Element("DisplayName", DisplayName);
+ }
+
+ xout.EndElement();
+}
+
+void cmCPackIFWRepository::WriteRepositoryUpdate(cmXMLWriter& xout)
+{
+ xout.StartElement("Repository");
+
+ switch (Update) {
+ case None:
+ break;
+ case Add:
+ xout.Attribute("action", "add");
+ break;
+ case Remove:
+ xout.Attribute("action", "remove");
+ break;
+ case Replace:
+ xout.Attribute("action", "replace");
+ break;
+ }
+
+ // Url
+ if (Update == Add || Update == Remove) {
+ xout.Attribute("url", Url);
+ } else if (Update == Replace) {
+ xout.Attribute("oldurl", OldUrl);
+ xout.Attribute("newurl", NewUrl);
+ }
+ // Enabled
+ if (!Enabled.empty()) {
+ xout.Attribute("enabled", Enabled);
+ }
+ // Username
+ if (!Username.empty()) {
+ xout.Attribute("username", Username);
+ }
+ // Password
+ if (!Password.empty()) {
+ xout.Attribute("password", Password);
+ }
+ // DisplayName
+ if (!DisplayName.empty()) {
+ xout.Attribute("displayname", DisplayName);
+ }
+
+ xout.EndElement();
+}
+
+void cmCPackIFWRepository::WriteRepositoryUpdates(cmXMLWriter& xout)
+{
+ if (!RepositoryUpdate.empty()) {
+ xout.StartElement("RepositoryUpdate");
+ for (RepositoriesVector::iterator rit = RepositoryUpdate.begin();
+ rit != RepositoryUpdate.end(); ++rit) {
+ (*rit)->WriteRepositoryUpdate(xout);
+ }
+ xout.EndElement();
+ }
+}
+
+void cmCPackIFWRepository::WriteGeneratedByToStrim(cmXMLWriter& xout)
+{
+ if (Generator) {
+ Generator->WriteGeneratedByToStrim(xout);
+ }
+}
diff --git a/Source/CPack/IFW/cmCPackIFWRepository.h b/Source/CPack/IFW/cmCPackIFWRepository.h
new file mode 100644
index 0000000..5ffb775
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWRepository.h
@@ -0,0 +1,105 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackIFWRepository_h
+#define cmCPackIFWRepository_h
+
+#include <cmStandardIncludes.h>
+
+class cmCPackIFWGenerator;
+class cmXMLWriter;
+
+/** \class cmCPackIFWRepository
+ * \brief A remote repository to be created CPack IFW generator
+ */
+class cmCPackIFWRepository
+{
+public:
+ // Types
+
+ enum Action
+ {
+ None,
+ Add,
+ Remove,
+ Replace
+ };
+
+ typedef std::vector<cmCPackIFWRepository*> RepositoriesVector;
+
+public:
+ // Constructor
+
+ /**
+ * Construct repository
+ */
+ cmCPackIFWRepository();
+
+public:
+ // Configuration
+
+ /// Internal repository name
+ std::string Name;
+
+ /// Optional update action
+ Action Update;
+
+ /// Is points to a list of available components
+ std::string Url;
+
+ /// Is points to a list that will replaced
+ std::string OldUrl;
+
+ /// Is points to a list that will replace to
+ std::string NewUrl;
+
+ /// With "0" disabling this repository
+ std::string Enabled;
+
+ /// Is used as user on a protected repository
+ std::string Username;
+
+ /// Is password to use on a protected repository
+ std::string Password;
+
+ /// Is optional string to display instead of the URL
+ std::string DisplayName;
+
+public:
+ // Internal implementation
+
+ bool IsValid() const;
+
+ const char* GetOption(const std::string& op) const;
+ bool IsOn(const std::string& op) const;
+
+ bool IsVersionLess(const char* version);
+ bool IsVersionGreater(const char* version);
+ bool IsVersionEqual(const char* version);
+
+ bool ConfigureFromOptions();
+
+ bool PatchUpdatesXml();
+
+ void WriteRepositoryConfig(cmXMLWriter& xout);
+ void WriteRepositoryUpdate(cmXMLWriter& xout);
+ void WriteRepositoryUpdates(cmXMLWriter& xout);
+
+ cmCPackIFWGenerator* Generator;
+ RepositoriesVector RepositoryUpdate;
+ std::string Directory;
+
+protected:
+ void WriteGeneratedByToStrim(cmXMLWriter& xout);
+};
+
+#endif // cmCPackIFWRepository_h
diff --git a/Source/CPack/OSXLauncherScript.scpt b/Source/CPack/OSXLauncherScript.scpt
new file mode 100644
index 0000000..342cf8c
--- /dev/null
+++ b/Source/CPack/OSXLauncherScript.scpt
Binary files differ
diff --git a/Source/CPack/OSXScriptLauncher.cxx b/Source/CPack/OSXScriptLauncher.cxx
new file mode 100644
index 0000000..a233e76
--- /dev/null
+++ b/Source/CPack/OSXScriptLauncher.cxx
@@ -0,0 +1,130 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include <cmsys/FStream.hxx>
+#include <cmsys/Process.h>
+#include <cmsys/SystemTools.hxx>
+
+#include <iostream>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+// For the PATH_MAX constant
+#include <sys/syslimits.h>
+
+#define DebugError(x) \
+ ofs << x << std::endl; \
+ std::cout << x << std::endl
+
+int main(int argc, char* argv[])
+{
+ // if ( cmsys::SystemTools::FileExists(
+ std::string cwd = cmsys::SystemTools::GetCurrentWorkingDirectory();
+ cmsys::ofstream ofs("/tmp/output.txt");
+
+ CFStringRef fileName;
+ CFBundleRef appBundle;
+ CFURLRef scriptFileURL;
+ UInt8* path;
+
+ // get CF URL for script
+ if (!(appBundle = CFBundleGetMainBundle())) {
+ DebugError("Cannot get main bundle");
+ return 1;
+ }
+ fileName = CFSTR("RuntimeScript");
+ if (!(scriptFileURL =
+ CFBundleCopyResourceURL(appBundle, fileName, NULL, NULL))) {
+ DebugError("CFBundleCopyResourceURL failed");
+ return 1;
+ }
+
+ // create path string
+ if (!(path = new UInt8[PATH_MAX])) {
+ return 1;
+ }
+
+ // get the file system path of the url as a cstring
+ // in an encoding suitable for posix apis
+ if (CFURLGetFileSystemRepresentation(scriptFileURL, true, path, PATH_MAX) ==
+ false) {
+ DebugError("CFURLGetFileSystemRepresentation failed");
+ return 1;
+ }
+
+ // dispose of the CF variable
+ CFRelease(scriptFileURL);
+
+ std::string fullScriptPath = reinterpret_cast<char*>(path);
+ delete[] path;
+
+ if (!cmsys::SystemTools::FileExists(fullScriptPath.c_str())) {
+ return 1;
+ }
+
+ std::string scriptDirectory =
+ cmsys::SystemTools::GetFilenamePath(fullScriptPath);
+ ofs << fullScriptPath << std::endl;
+ std::vector<const char*> args;
+ args.push_back(fullScriptPath.c_str());
+ int cc;
+ for (cc = 1; cc < argc; ++cc) {
+ args.push_back(argv[cc]);
+ }
+ args.push_back(0);
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, &*args.begin());
+ cmsysProcess_SetWorkingDirectory(cp, scriptDirectory.c_str());
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ cmsysProcess_SetTimeout(cp, 0);
+ cmsysProcess_Execute(cp);
+
+ std::vector<char> tempOutput;
+ char* data;
+ int length;
+ while (cmsysProcess_WaitForData(cp, &data, &length, 0)) {
+ // Translate NULL characters in the output into valid text.
+ // Visual Studio 7 puts these characters in the output of its
+ // build process.
+ for (int i = 0; i < length; ++i) {
+ if (data[i] == '\0') {
+ data[i] = ' ';
+ }
+ }
+ std::cout.write(data, length);
+ }
+
+ cmsysProcess_WaitForExit(cp, 0);
+
+ bool result = true;
+ if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
+ if (cmsysProcess_GetExitValue(cp) != 0) {
+ result = false;
+ }
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) {
+ const char* exception_str = cmsysProcess_GetExceptionString(cp);
+ std::cerr << exception_str << std::endl;
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
+ const char* error_str = cmsysProcess_GetErrorString(cp);
+ std::cerr << error_str << std::endl;
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) {
+ const char* error_str = "Process terminated due to timeout\n";
+ std::cerr << error_str << std::endl;
+ result = false;
+ }
+
+ cmsysProcess_Delete(cp);
+
+ return 0;
+}
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
new file mode 100644
index 0000000..97216c3
--- /dev/null
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
@@ -0,0 +1,1127 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackWIXGenerator.h"
+
+#include <CPack/cmCPackComponentGroup.h>
+#include <CPack/cmCPackLog.h>
+#include <cmCryptoHash.h>
+#include <cmGeneratedFileStream.h>
+#include <cmInstalledFile.h>
+#include <cmSystemTools.h>
+
+#include "cmWIXDirectoriesSourceWriter.h"
+#include "cmWIXFeaturesSourceWriter.h"
+#include "cmWIXFilesSourceWriter.h"
+#include "cmWIXRichTextFormatWriter.h"
+#include "cmWIXSourceWriter.h"
+
+#include <cmsys/Directory.hxx>
+#include <cmsys/Encoding.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/SystemTools.hxx>
+
+#include <rpc.h> // for GUID generation
+
+cmCPackWIXGenerator::cmCPackWIXGenerator()
+ : Patch(0)
+{
+}
+
+cmCPackWIXGenerator::~cmCPackWIXGenerator()
+{
+ if (this->Patch) {
+ delete this->Patch;
+ }
+}
+
+int cmCPackWIXGenerator::InitializeInternal()
+{
+ componentPackageMethod = ONE_PACKAGE;
+ this->Patch = new cmWIXPatch(this->Logger);
+
+ return this->Superclass::InitializeInternal();
+}
+
+bool cmCPackWIXGenerator::RunWiXCommand(std::string const& command)
+{
+ std::string logFileName = this->CPackTopLevel + "/wix.log";
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Running WiX command: " << command
+ << std::endl);
+
+ std::string output;
+
+ int returnValue = 0;
+ bool status = cmSystemTools::RunSingleCommand(command.c_str(), &output,
+ &output, &returnValue, 0,
+ cmSystemTools::OUTPUT_NONE);
+
+ cmsys::ofstream logFile(logFileName.c_str(), std::ios::app);
+ logFile << command << std::endl;
+ logFile << output;
+ logFile.close();
+
+ if (!status || returnValue) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running WiX candle. "
+ "Please check '"
+ << logFileName << "' for errors." << std::endl);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::RunCandleCommand(std::string const& sourceFile,
+ std::string const& objectFile)
+{
+ std::string executable;
+ if (!RequireOption("CPACK_WIX_CANDLE_EXECUTABLE", executable)) {
+ return false;
+ }
+
+ std::ostringstream command;
+ command << QuotePath(executable);
+ command << " -nologo";
+ command << " -arch " << GetArchitecture();
+ command << " -out " << QuotePath(objectFile);
+
+ for (extension_set_t::const_iterator i = CandleExtensions.begin();
+ i != CandleExtensions.end(); ++i) {
+ command << " -ext " << QuotePath(*i);
+ }
+
+ AddCustomFlags("CPACK_WIX_CANDLE_EXTRA_FLAGS", command);
+
+ command << " " << QuotePath(sourceFile);
+
+ return RunWiXCommand(command.str());
+}
+
+bool cmCPackWIXGenerator::RunLightCommand(std::string const& objectFiles)
+{
+ std::string executable;
+ if (!RequireOption("CPACK_WIX_LIGHT_EXECUTABLE", executable)) {
+ return false;
+ }
+
+ std::ostringstream command;
+ command << QuotePath(executable);
+ command << " -nologo";
+ command << " -out " << QuotePath(packageFileNames.at(0));
+
+ for (extension_set_t::const_iterator i = this->LightExtensions.begin();
+ i != this->LightExtensions.end(); ++i) {
+ command << " -ext " << QuotePath(*i);
+ }
+
+ const char* const cultures = GetOption("CPACK_WIX_CULTURES");
+ if (cultures) {
+ command << " -cultures:" << cultures;
+ }
+
+ AddCustomFlags("CPACK_WIX_LIGHT_EXTRA_FLAGS", command);
+
+ command << " " << objectFiles;
+
+ return RunWiXCommand(command.str());
+}
+
+int cmCPackWIXGenerator::PackageFiles()
+{
+ if (!PackageFilesImpl() || cmSystemTools::GetErrorOccuredFlag()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Fatal WiX Generator Error"
+ << std::endl);
+ return false;
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::InitializeWiXConfiguration()
+{
+ if (!ReadListFile("CPackWIX.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while executing CPackWIX.cmake"
+ << std::endl);
+ return false;
+ }
+
+ if (GetOption("CPACK_WIX_PRODUCT_GUID") == 0) {
+ std::string guid = GenerateGUID();
+ SetOption("CPACK_WIX_PRODUCT_GUID", guid.c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "CPACK_WIX_PRODUCT_GUID implicitly set to " << guid << " . "
+ << std::endl);
+ }
+
+ if (GetOption("CPACK_WIX_UPGRADE_GUID") == 0) {
+ std::string guid = GenerateGUID();
+ SetOption("CPACK_WIX_UPGRADE_GUID", guid.c_str());
+
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING, "CPACK_WIX_UPGRADE_GUID implicitly set to "
+ << guid << " . "
+ "Please refer to the documentation on how and why "
+ "you might want to set this explicitly."
+ << std::endl);
+ }
+
+ if (!RequireOption("CPACK_TOPLEVEL_DIRECTORY", this->CPackTopLevel)) {
+ return false;
+ }
+
+ if (GetOption("CPACK_WIX_LICENSE_RTF") == 0) {
+ std::string licenseFilename = this->CPackTopLevel + "/License.rtf";
+ SetOption("CPACK_WIX_LICENSE_RTF", licenseFilename.c_str());
+
+ if (!CreateLicenseFile()) {
+ return false;
+ }
+ }
+
+ if (GetOption("CPACK_PACKAGE_VENDOR") == 0) {
+ std::string defaultVendor = "Humanity";
+ SetOption("CPACK_PACKAGE_VENDOR", defaultVendor.c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "CPACK_PACKAGE_VENDOR implicitly set to "
+ << defaultVendor << " . " << std::endl);
+ }
+
+ if (GetOption("CPACK_WIX_UI_REF") == 0) {
+ std::string defaultRef = "WixUI_InstallDir";
+
+ if (!this->Components.empty()) {
+ defaultRef = "WixUI_FeatureTree";
+ }
+
+ SetOption("CPACK_WIX_UI_REF", defaultRef.c_str());
+ }
+
+ const char* packageContact = GetOption("CPACK_PACKAGE_CONTACT");
+ if (packageContact != 0 && GetOption("CPACK_WIX_PROPERTY_ARPCONTACT") == 0) {
+ SetOption("CPACK_WIX_PROPERTY_ARPCONTACT", packageContact);
+ }
+
+ CollectExtensions("CPACK_WIX_EXTENSIONS", this->CandleExtensions);
+ CollectExtensions("CPACK_WIX_CANDLE_EXTENSIONS", this->CandleExtensions);
+
+ this->LightExtensions.insert("WixUIExtension");
+ CollectExtensions("CPACK_WIX_EXTENSIONS", this->LightExtensions);
+ CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", this->LightExtensions);
+
+ const char* patchFilePath = GetOption("CPACK_WIX_PATCH_FILE");
+ if (patchFilePath) {
+ std::vector<std::string> patchFilePaths;
+ cmSystemTools::ExpandListArgument(patchFilePath, patchFilePaths);
+
+ for (size_t i = 0; i < patchFilePaths.size(); ++i) {
+ if (!this->Patch->LoadFragments(patchFilePaths[i])) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::PackageFilesImpl()
+{
+ if (!InitializeWiXConfiguration()) {
+ return false;
+ }
+
+ CreateWiXVariablesIncludeFile();
+ CreateWiXPropertiesIncludeFile();
+ CreateWiXProductFragmentIncludeFile();
+
+ if (!CreateWiXSourceFiles()) {
+ return false;
+ }
+
+ AppendUserSuppliedExtraSources();
+
+ std::set<std::string> usedBaseNames;
+
+ std::ostringstream objectFiles;
+ for (size_t i = 0; i < this->WixSources.size(); ++i) {
+ std::string const& sourceFilename = this->WixSources[i];
+
+ std::string baseName =
+ cmSystemTools::GetFilenameWithoutLastExtension(sourceFilename);
+
+ unsigned int counter = 0;
+ std::string uniqueBaseName = baseName;
+
+ while (usedBaseNames.find(uniqueBaseName) != usedBaseNames.end()) {
+ std::ostringstream tmp;
+ tmp << baseName << ++counter;
+ uniqueBaseName = tmp.str();
+ }
+
+ usedBaseNames.insert(uniqueBaseName);
+
+ std::string objectFilename =
+ this->CPackTopLevel + "/" + uniqueBaseName + ".wixobj";
+
+ if (!RunCandleCommand(sourceFilename, objectFilename)) {
+ return false;
+ }
+
+ objectFiles << " " << QuotePath(objectFilename);
+ }
+
+ AppendUserSuppliedExtraObjects(objectFiles);
+
+ return RunLightCommand(objectFiles.str());
+}
+
+void cmCPackWIXGenerator::AppendUserSuppliedExtraSources()
+{
+ const char* cpackWixExtraSources = GetOption("CPACK_WIX_EXTRA_SOURCES");
+ if (!cpackWixExtraSources)
+ return;
+
+ cmSystemTools::ExpandListArgument(cpackWixExtraSources, this->WixSources);
+}
+
+void cmCPackWIXGenerator::AppendUserSuppliedExtraObjects(std::ostream& stream)
+{
+ const char* cpackWixExtraObjects = GetOption("CPACK_WIX_EXTRA_OBJECTS");
+ if (!cpackWixExtraObjects)
+ return;
+
+ std::vector<std::string> expandedExtraObjects;
+
+ cmSystemTools::ExpandListArgument(cpackWixExtraObjects,
+ expandedExtraObjects);
+
+ for (size_t i = 0; i < expandedExtraObjects.size(); ++i) {
+ stream << " " << QuotePath(expandedExtraObjects[i]);
+ }
+}
+
+void cmCPackWIXGenerator::CreateWiXVariablesIncludeFile()
+{
+ std::string includeFilename = this->CPackTopLevel + "/cpack_variables.wxi";
+
+ cmWIXSourceWriter includeFile(this->Logger, includeFilename, true);
+
+ CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_GUID");
+ CopyDefinition(includeFile, "CPACK_WIX_UPGRADE_GUID");
+ CopyDefinition(includeFile, "CPACK_PACKAGE_VENDOR");
+ CopyDefinition(includeFile, "CPACK_PACKAGE_NAME");
+ CopyDefinition(includeFile, "CPACK_PACKAGE_VERSION");
+ CopyDefinition(includeFile, "CPACK_WIX_LICENSE_RTF");
+ CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_ICON");
+ CopyDefinition(includeFile, "CPACK_WIX_UI_BANNER");
+ CopyDefinition(includeFile, "CPACK_WIX_UI_DIALOG");
+ SetOptionIfNotSet("CPACK_WIX_PROGRAM_MENU_FOLDER",
+ GetOption("CPACK_PACKAGE_NAME"));
+ CopyDefinition(includeFile, "CPACK_WIX_PROGRAM_MENU_FOLDER");
+ CopyDefinition(includeFile, "CPACK_WIX_UI_REF");
+}
+
+void cmCPackWIXGenerator::CreateWiXPropertiesIncludeFile()
+{
+ std::string includeFilename = this->CPackTopLevel + "/properties.wxi";
+
+ cmWIXSourceWriter includeFile(this->Logger, includeFilename, true);
+
+ std::string prefix = "CPACK_WIX_PROPERTY_";
+ std::vector<std::string> options = GetOptions();
+
+ for (size_t i = 0; i < options.size(); ++i) {
+ std::string const& name = options[i];
+
+ if (name.length() > prefix.length() &&
+ name.substr(0, prefix.length()) == prefix) {
+ std::string id = name.substr(prefix.length());
+ std::string value = GetOption(name.c_str());
+
+ includeFile.BeginElement("Property");
+ includeFile.AddAttribute("Id", id);
+ includeFile.AddAttribute("Value", value);
+ includeFile.EndElement("Property");
+ }
+ }
+
+ if (GetOption("CPACK_WIX_PROPERTY_ARPINSTALLLOCATION") == 0) {
+ includeFile.BeginElement("Property");
+ includeFile.AddAttribute("Id", "INSTALL_ROOT");
+ includeFile.AddAttribute("Secure", "yes");
+
+ includeFile.BeginElement("RegistrySearch");
+ includeFile.AddAttribute("Id", "FindInstallLocation");
+ includeFile.AddAttribute("Root", "HKLM");
+ includeFile.AddAttribute(
+ "Key", "Software\\Microsoft\\Windows\\"
+ "CurrentVersion\\Uninstall\\[WIX_UPGRADE_DETECTED]");
+ includeFile.AddAttribute("Name", "InstallLocation");
+ includeFile.AddAttribute("Type", "raw");
+ includeFile.EndElement("RegistrySearch");
+ includeFile.EndElement("Property");
+
+ includeFile.BeginElement("SetProperty");
+ includeFile.AddAttribute("Id", "ARPINSTALLLOCATION");
+ includeFile.AddAttribute("Value", "[INSTALL_ROOT]");
+ includeFile.AddAttribute("After", "CostFinalize");
+ includeFile.EndElement("SetProperty");
+ }
+}
+
+void cmCPackWIXGenerator::CreateWiXProductFragmentIncludeFile()
+{
+ std::string includeFilename = this->CPackTopLevel + "/product_fragment.wxi";
+
+ cmWIXSourceWriter includeFile(this->Logger, includeFilename, true);
+
+ this->Patch->ApplyFragment("#PRODUCT", includeFile);
+}
+
+void cmCPackWIXGenerator::CopyDefinition(cmWIXSourceWriter& source,
+ std::string const& name)
+{
+ const char* value = GetOption(name.c_str());
+ if (value) {
+ AddDefinition(source, name, value);
+ }
+}
+
+void cmCPackWIXGenerator::AddDefinition(cmWIXSourceWriter& source,
+ std::string const& name,
+ std::string const& value)
+{
+ std::ostringstream tmp;
+ tmp << name << "=\"" << value << '"';
+
+ source.AddProcessingInstruction(
+ "define", cmWIXSourceWriter::CMakeEncodingToUtf8(tmp.str()));
+}
+
+bool cmCPackWIXGenerator::CreateWiXSourceFiles()
+{
+ std::string directoryDefinitionsFilename =
+ this->CPackTopLevel + "/directories.wxs";
+
+ this->WixSources.push_back(directoryDefinitionsFilename);
+
+ cmWIXDirectoriesSourceWriter directoryDefinitions(
+ this->Logger, directoryDefinitionsFilename);
+ directoryDefinitions.BeginElement("Fragment");
+
+ std::string installRoot;
+ if (!RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY", installRoot)) {
+ return false;
+ }
+
+ directoryDefinitions.BeginElement("Directory");
+ directoryDefinitions.AddAttribute("Id", "TARGETDIR");
+ directoryDefinitions.AddAttribute("Name", "SourceDir");
+
+ size_t installRootSize =
+ directoryDefinitions.BeginInstallationPrefixDirectory(
+ GetProgramFilesFolderId(), installRoot);
+
+ std::string fileDefinitionsFilename = this->CPackTopLevel + "/files.wxs";
+
+ this->WixSources.push_back(fileDefinitionsFilename);
+
+ cmWIXFilesSourceWriter fileDefinitions(this->Logger,
+ fileDefinitionsFilename);
+
+ fileDefinitions.BeginElement("Fragment");
+
+ std::string featureDefinitionsFilename =
+ this->CPackTopLevel + "/features.wxs";
+
+ this->WixSources.push_back(featureDefinitionsFilename);
+
+ cmWIXFeaturesSourceWriter featureDefinitions(this->Logger,
+ featureDefinitionsFilename);
+
+ featureDefinitions.BeginElement("Fragment");
+
+ featureDefinitions.BeginElement("Feature");
+ featureDefinitions.AddAttribute("Id", "ProductFeature");
+ featureDefinitions.AddAttribute("Display", "expand");
+ featureDefinitions.AddAttribute("Absent", "disallow");
+ featureDefinitions.AddAttribute("ConfigurableDirectory", "INSTALL_ROOT");
+
+ std::string cpackPackageName;
+ if (!RequireOption("CPACK_PACKAGE_NAME", cpackPackageName)) {
+ return false;
+ }
+
+ featureDefinitions.AddAttribute("Title", cpackPackageName);
+ featureDefinitions.AddAttribute("Level", "1");
+ this->Patch->ApplyFragment("#PRODUCTFEATURE", featureDefinitions);
+
+ const char* package = GetOption("CPACK_WIX_CMAKE_PACKAGE_REGISTRY");
+ if (package) {
+ featureDefinitions.CreateCMakePackageRegistryEntry(
+ package, GetOption("CPACK_WIX_UPGRADE_GUID"));
+ }
+
+ if (!CreateFeatureHierarchy(featureDefinitions)) {
+ return false;
+ }
+
+ featureDefinitions.EndElement("Feature");
+
+ std::set<cmWIXShortcuts::Type> emittedShortcutTypes;
+
+ cmWIXShortcuts globalShortcuts;
+ if (Components.empty()) {
+ AddComponentsToFeature(toplevel, "ProductFeature", directoryDefinitions,
+ fileDefinitions, featureDefinitions,
+ globalShortcuts);
+
+ globalShortcuts.AddShortcutTypes(emittedShortcutTypes);
+ } else {
+ for (std::map<std::string, cmCPackComponent>::const_iterator i =
+ this->Components.begin();
+ i != this->Components.end(); ++i) {
+ cmCPackComponent const& component = i->second;
+
+ std::string componentPath = toplevel;
+ componentPath += "/";
+ componentPath += component.Name;
+
+ std::string componentFeatureId = "CM_C_" + component.Name;
+
+ cmWIXShortcuts featureShortcuts;
+ AddComponentsToFeature(componentPath, componentFeatureId,
+ directoryDefinitions, fileDefinitions,
+ featureDefinitions, featureShortcuts);
+
+ featureShortcuts.AddShortcutTypes(emittedShortcutTypes);
+
+ if (!CreateShortcuts(component.Name, componentFeatureId,
+ featureShortcuts, false, fileDefinitions,
+ featureDefinitions)) {
+ return false;
+ }
+ }
+ }
+
+ bool emitUninstallShortcut =
+ emittedShortcutTypes.find(cmWIXShortcuts::START_MENU) !=
+ emittedShortcutTypes.end();
+
+ if (!CreateShortcuts(std::string(), "ProductFeature", globalShortcuts,
+ emitUninstallShortcut, fileDefinitions,
+ featureDefinitions)) {
+ return false;
+ }
+
+ featureDefinitions.EndElement("Fragment");
+ fileDefinitions.EndElement("Fragment");
+
+ directoryDefinitions.EndInstallationPrefixDirectory(installRootSize);
+
+ if (emittedShortcutTypes.find(cmWIXShortcuts::START_MENU) !=
+ emittedShortcutTypes.end()) {
+ directoryDefinitions.EmitStartMenuFolder(
+ GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER"));
+ }
+
+ if (emittedShortcutTypes.find(cmWIXShortcuts::DESKTOP) !=
+ emittedShortcutTypes.end()) {
+ directoryDefinitions.EmitDesktopFolder();
+ }
+
+ if (emittedShortcutTypes.find(cmWIXShortcuts::STARTUP) !=
+ emittedShortcutTypes.end()) {
+ directoryDefinitions.EmitStartupFolder();
+ }
+
+ directoryDefinitions.EndElement("Directory");
+ directoryDefinitions.EndElement("Fragment");
+
+ if (!GenerateMainSourceFileFromTemplate()) {
+ return false;
+ }
+
+ return this->Patch->CheckForUnappliedFragments();
+}
+
+std::string cmCPackWIXGenerator::GetProgramFilesFolderId() const
+{
+ if (GetArchitecture() == "x86") {
+ return "ProgramFilesFolder";
+ } else {
+ return "ProgramFiles64Folder";
+ }
+}
+
+bool cmCPackWIXGenerator::GenerateMainSourceFileFromTemplate()
+{
+ std::string wixTemplate = FindTemplate("WIX.template.in");
+ if (GetOption("CPACK_WIX_TEMPLATE") != 0) {
+ wixTemplate = GetOption("CPACK_WIX_TEMPLATE");
+ }
+
+ if (wixTemplate.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Could not find CPack WiX template file WIX.template.in"
+ << std::endl);
+ return false;
+ }
+
+ std::string mainSourceFilePath = this->CPackTopLevel + "/main.wxs";
+
+ if (!ConfigureFile(wixTemplate.c_str(), mainSourceFilePath.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Failed creating '"
+ << mainSourceFilePath << "'' from template." << std::endl);
+
+ return false;
+ }
+
+ this->WixSources.push_back(mainSourceFilePath);
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::CreateFeatureHierarchy(
+ cmWIXFeaturesSourceWriter& featureDefinitions)
+{
+ for (std::map<std::string, cmCPackComponentGroup>::const_iterator i =
+ ComponentGroups.begin();
+ i != ComponentGroups.end(); ++i) {
+ cmCPackComponentGroup const& group = i->second;
+ if (group.ParentGroup == 0) {
+ featureDefinitions.EmitFeatureForComponentGroup(group);
+ }
+ }
+
+ for (std::map<std::string, cmCPackComponent>::const_iterator i =
+ this->Components.begin();
+ i != this->Components.end(); ++i) {
+ cmCPackComponent const& component = i->second;
+
+ if (!component.Group) {
+ featureDefinitions.EmitFeatureForComponent(component);
+ }
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::AddComponentsToFeature(
+ std::string const& rootPath, std::string const& featureId,
+ cmWIXDirectoriesSourceWriter& directoryDefinitions,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions, cmWIXShortcuts& shortcuts)
+{
+ featureDefinitions.BeginElement("FeatureRef");
+ featureDefinitions.AddAttribute("Id", featureId);
+
+ std::vector<std::string> cpackPackageExecutablesList;
+ const char* cpackPackageExecutables = GetOption("CPACK_PACKAGE_EXECUTABLES");
+ if (cpackPackageExecutables) {
+ cmSystemTools::ExpandListArgument(cpackPackageExecutables,
+ cpackPackageExecutablesList);
+ if (cpackPackageExecutablesList.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
+ "<text label>."
+ << std::endl);
+ return false;
+ }
+ }
+
+ std::vector<std::string> cpackPackageDesktopLinksList;
+ const char* cpackPackageDesktopLinks =
+ GetOption("CPACK_CREATE_DESKTOP_LINKS");
+ if (cpackPackageDesktopLinks) {
+ cmSystemTools::ExpandListArgument(cpackPackageDesktopLinks,
+ cpackPackageDesktopLinksList);
+ }
+
+ AddDirectoryAndFileDefinitons(rootPath, "INSTALL_ROOT", directoryDefinitions,
+ fileDefinitions, featureDefinitions,
+ cpackPackageExecutablesList,
+ cpackPackageDesktopLinksList, shortcuts);
+
+ featureDefinitions.EndElement("FeatureRef");
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::CreateShortcuts(
+ std::string const& cpackComponentName, std::string const& featureId,
+ cmWIXShortcuts const& shortcuts, bool emitUninstallShortcut,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions)
+{
+ if (!shortcuts.empty(cmWIXShortcuts::START_MENU)) {
+ if (!this->CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::START_MENU, cpackComponentName, featureId, "",
+ shortcuts, emitUninstallShortcut, fileDefinitions,
+ featureDefinitions)) {
+ return false;
+ }
+ }
+
+ if (!shortcuts.empty(cmWIXShortcuts::DESKTOP)) {
+ if (!this->CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::DESKTOP, cpackComponentName, featureId, "DESKTOP",
+ shortcuts, false, fileDefinitions, featureDefinitions)) {
+ return false;
+ }
+ }
+
+ if (!shortcuts.empty(cmWIXShortcuts::STARTUP)) {
+ if (!this->CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::STARTUP, cpackComponentName, featureId, "STARTUP",
+ shortcuts, false, fileDefinitions, featureDefinitions)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::Type type, std::string const& cpackComponentName,
+ std::string const& featureId, std::string const& idPrefix,
+ cmWIXShortcuts const& shortcuts, bool emitUninstallShortcut,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions)
+{
+ std::string directoryId;
+ switch (type) {
+ case cmWIXShortcuts::START_MENU:
+ directoryId = "PROGRAM_MENU_FOLDER";
+ break;
+ case cmWIXShortcuts::DESKTOP:
+ directoryId = "DesktopFolder";
+ break;
+ case cmWIXShortcuts::STARTUP:
+ directoryId = "StartupFolder";
+ break;
+ default:
+ return false;
+ }
+
+ featureDefinitions.BeginElement("FeatureRef");
+ featureDefinitions.AddAttribute("Id", featureId);
+
+ std::string cpackVendor;
+ if (!RequireOption("CPACK_PACKAGE_VENDOR", cpackVendor)) {
+ return false;
+ }
+
+ std::string cpackPackageName;
+ if (!RequireOption("CPACK_PACKAGE_NAME", cpackPackageName)) {
+ return false;
+ }
+
+ std::string idSuffix;
+ if (!cpackComponentName.empty()) {
+ idSuffix += "_";
+ idSuffix += cpackComponentName;
+ }
+
+ std::string componentId = "CM_SHORTCUT";
+ if (idPrefix.size()) {
+ componentId += "_" + idPrefix;
+ }
+
+ componentId += idSuffix;
+
+ fileDefinitions.BeginElement("DirectoryRef");
+ fileDefinitions.AddAttribute("Id", directoryId);
+
+ fileDefinitions.BeginElement("Component");
+ fileDefinitions.AddAttribute("Id", componentId);
+ fileDefinitions.AddAttribute("Guid", "*");
+
+ this->Patch->ApplyFragment(componentId, fileDefinitions);
+
+ std::string registryKey =
+ std::string("Software\\") + cpackVendor + "\\" + cpackPackageName;
+
+ shortcuts.EmitShortcuts(type, registryKey, cpackComponentName,
+ fileDefinitions);
+
+ if (type == cmWIXShortcuts::START_MENU) {
+ fileDefinitions.EmitRemoveFolder("CM_REMOVE_PROGRAM_MENU_FOLDER" +
+ idSuffix);
+ }
+
+ if (emitUninstallShortcut) {
+ fileDefinitions.EmitUninstallShortcut(cpackPackageName);
+ }
+
+ fileDefinitions.EndElement("Component");
+ fileDefinitions.EndElement("DirectoryRef");
+
+ featureDefinitions.EmitComponentRef(componentId);
+ featureDefinitions.EndElement("FeatureRef");
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::CreateLicenseFile()
+{
+ std::string licenseSourceFilename;
+ if (!RequireOption("CPACK_RESOURCE_FILE_LICENSE", licenseSourceFilename)) {
+ return false;
+ }
+
+ std::string licenseDestinationFilename;
+ if (!RequireOption("CPACK_WIX_LICENSE_RTF", licenseDestinationFilename)) {
+ return false;
+ }
+
+ std::string extension = GetRightmostExtension(licenseSourceFilename);
+
+ if (extension == ".rtf") {
+ cmSystemTools::CopyAFile(licenseSourceFilename.c_str(),
+ licenseDestinationFilename.c_str());
+ } else if (extension == ".txt") {
+ cmWIXRichTextFormatWriter rtfWriter(licenseDestinationFilename);
+
+ cmsys::ifstream licenseSource(licenseSourceFilename.c_str());
+
+ std::string line;
+ while (std::getline(licenseSource, line)) {
+ rtfWriter.AddText(line);
+ rtfWriter.AddText("\n");
+ }
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "unsupported WiX License file extension '"
+ << extension << "'" << std::endl);
+
+ return false;
+ }
+
+ return true;
+}
+
+void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons(
+ std::string const& topdir, std::string const& directoryId,
+ cmWIXDirectoriesSourceWriter& directoryDefinitions,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions,
+ std::vector<std::string> const& packageExecutables,
+ std::vector<std::string> const& desktopExecutables,
+ cmWIXShortcuts& shortcuts)
+{
+ cmsys::Directory dir;
+ dir.Load(topdir.c_str());
+
+ std::string relativeDirectoryPath =
+ cmSystemTools::RelativePath(toplevel.c_str(), topdir.c_str());
+
+ if (relativeDirectoryPath.empty()) {
+ relativeDirectoryPath = ".";
+ }
+
+ cmInstalledFile const* directoryInstalledFile = this->GetInstalledFile(
+ this->RelativePathWithoutComponentPrefix(relativeDirectoryPath));
+
+ bool emptyDirectory = dir.GetNumberOfFiles() == 2;
+ bool createDirectory = false;
+
+ if (emptyDirectory) {
+ createDirectory = true;
+ }
+
+ if (directoryInstalledFile) {
+ if (directoryInstalledFile->HasProperty("CPACK_WIX_ACL")) {
+ createDirectory = true;
+ }
+ }
+
+ if (createDirectory) {
+ std::string componentId = fileDefinitions.EmitComponentCreateFolder(
+ directoryId, GenerateGUID(), directoryInstalledFile);
+ featureDefinitions.EmitComponentRef(componentId);
+ }
+
+ if (emptyDirectory) {
+ return;
+ }
+
+ for (size_t i = 0; i < dir.GetNumberOfFiles(); ++i) {
+ std::string fileName = dir.GetFile(static_cast<unsigned long>(i));
+
+ if (fileName == "." || fileName == "..") {
+ continue;
+ }
+
+ std::string fullPath = topdir + "/" + fileName;
+
+ std::string relativePath =
+ cmSystemTools::RelativePath(toplevel.c_str(), fullPath.c_str());
+
+ std::string id = PathToId(relativePath);
+
+ if (cmSystemTools::FileIsDirectory(fullPath.c_str())) {
+ std::string subDirectoryId = std::string("CM_D") + id;
+
+ directoryDefinitions.BeginElement("Directory");
+ directoryDefinitions.AddAttribute("Id", subDirectoryId);
+ directoryDefinitions.AddAttribute("Name", fileName);
+
+ AddDirectoryAndFileDefinitons(
+ fullPath, subDirectoryId, directoryDefinitions, fileDefinitions,
+ featureDefinitions, packageExecutables, desktopExecutables, shortcuts);
+
+ this->Patch->ApplyFragment(subDirectoryId, directoryDefinitions);
+ directoryDefinitions.EndElement("Directory");
+ } else {
+ cmInstalledFile const* installedFile = this->GetInstalledFile(
+ this->RelativePathWithoutComponentPrefix(relativePath));
+
+ if (installedFile) {
+ shortcuts.CreateFromProperties(id, directoryId, *installedFile);
+ }
+
+ std::string componentId = fileDefinitions.EmitComponentFile(
+ directoryId, id, fullPath, *(this->Patch), installedFile);
+
+ featureDefinitions.EmitComponentRef(componentId);
+
+ for (size_t j = 0; j < packageExecutables.size(); ++j) {
+ std::string const& executableName = packageExecutables[j++];
+ std::string const& textLabel = packageExecutables[j];
+
+ if (cmSystemTools::LowerCase(fileName) ==
+ cmSystemTools::LowerCase(executableName) + ".exe") {
+ cmWIXShortcut shortcut;
+ shortcut.label = textLabel;
+ shortcut.workingDirectoryId = directoryId;
+ shortcuts.insert(cmWIXShortcuts::START_MENU, id, shortcut);
+
+ if (!desktopExecutables.empty() &&
+ std::find(desktopExecutables.begin(), desktopExecutables.end(),
+ executableName) != desktopExecutables.end()) {
+ shortcuts.insert(cmWIXShortcuts::DESKTOP, id, shortcut);
+ }
+ }
+ }
+ }
+ }
+}
+
+bool cmCPackWIXGenerator::RequireOption(std::string const& name,
+ std::string& value) const
+{
+ const char* tmp = GetOption(name.c_str());
+ if (tmp) {
+ value = tmp;
+
+ return true;
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Required variable "
+ << name << " not set" << std::endl);
+
+ return false;
+ }
+}
+
+std::string cmCPackWIXGenerator::GetArchitecture() const
+{
+ std::string void_p_size;
+ RequireOption("CPACK_WIX_SIZEOF_VOID_P", void_p_size);
+
+ if (void_p_size == "8") {
+ return "x64";
+ } else {
+ return "x86";
+ }
+}
+
+std::string cmCPackWIXGenerator::GenerateGUID()
+{
+ UUID guid;
+ UuidCreate(&guid);
+
+ unsigned short* tmp = 0;
+ UuidToStringW(&guid, &tmp);
+
+ std::string result =
+ cmsys::Encoding::ToNarrow(reinterpret_cast<wchar_t*>(tmp));
+ RpcStringFreeW(&tmp);
+
+ return cmSystemTools::UpperCase(result);
+}
+
+std::string cmCPackWIXGenerator::QuotePath(std::string const& path)
+{
+ return std::string("\"") + path + '"';
+}
+
+std::string cmCPackWIXGenerator::GetRightmostExtension(
+ std::string const& filename)
+{
+ std::string extension;
+
+ std::string::size_type i = filename.rfind(".");
+ if (i != std::string::npos) {
+ extension = filename.substr(i);
+ }
+
+ return cmSystemTools::LowerCase(extension);
+}
+
+std::string cmCPackWIXGenerator::PathToId(std::string const& path)
+{
+ id_map_t::const_iterator i = PathToIdMap.find(path);
+ if (i != PathToIdMap.end())
+ return i->second;
+
+ std::string id = CreateNewIdForPath(path);
+ return id;
+}
+
+std::string cmCPackWIXGenerator::CreateNewIdForPath(std::string const& path)
+{
+ std::vector<std::string> components;
+ cmSystemTools::SplitPath(path.c_str(), components, false);
+
+ size_t replacementCount = 0;
+
+ std::string identifier;
+ std::string currentComponent;
+
+ for (size_t i = 1; i < components.size(); ++i) {
+ if (i != 1)
+ identifier += '.';
+
+ currentComponent =
+ NormalizeComponentForId(components[i], replacementCount);
+
+ identifier += currentComponent;
+ }
+
+ std::string idPrefix = "P";
+ size_t replacementPercent = replacementCount * 100 / identifier.size();
+ if (replacementPercent > 33 || identifier.size() > 60) {
+ identifier = CreateHashedId(path, currentComponent);
+ idPrefix = "H";
+ }
+
+ std::ostringstream result;
+ result << idPrefix << "_" << identifier;
+
+ size_t ambiguityCount = ++IdAmbiguityCounter[identifier];
+
+ if (ambiguityCount > 999) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while trying to generate a unique Id for '"
+ << path << "'" << std::endl);
+
+ return std::string();
+ } else if (ambiguityCount > 1) {
+ result << "_" << ambiguityCount;
+ }
+
+ std::string resultString = result.str();
+
+ PathToIdMap[path] = resultString;
+
+ return resultString;
+}
+
+std::string cmCPackWIXGenerator::CreateHashedId(
+ std::string const& path, std::string const& normalizedFilename)
+{
+ CM_AUTO_PTR<cmCryptoHash> sha1 = cmCryptoHash::New("SHA1");
+ std::string hash = sha1->HashString(path.c_str());
+
+ std::string identifier;
+ identifier += hash.substr(0, 7) + "_";
+
+ const size_t maxFileNameLength = 52;
+ if (normalizedFilename.length() > maxFileNameLength) {
+ identifier += normalizedFilename.substr(0, maxFileNameLength - 3);
+ identifier += "...";
+ } else {
+ identifier += normalizedFilename;
+ }
+
+ return identifier;
+}
+
+std::string cmCPackWIXGenerator::NormalizeComponentForId(
+ std::string const& component, size_t& replacementCount)
+{
+ std::string result;
+ result.resize(component.size());
+
+ for (size_t i = 0; i < component.size(); ++i) {
+ char c = component[i];
+ if (IsLegalIdCharacter(c)) {
+ result[i] = c;
+ } else {
+ result[i] = '_';
+ ++replacementCount;
+ }
+ }
+
+ return result;
+}
+
+bool cmCPackWIXGenerator::IsLegalIdCharacter(char c)
+{
+ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') || c == '_' || c == '.';
+}
+
+void cmCPackWIXGenerator::CollectExtensions(std::string const& variableName,
+ extension_set_t& extensions)
+{
+ const char* variableContent = GetOption(variableName.c_str());
+ if (!variableContent)
+ return;
+
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(variableContent, list);
+ extensions.insert(list.begin(), list.end());
+}
+
+void cmCPackWIXGenerator::AddCustomFlags(std::string const& variableName,
+ std::ostream& stream)
+{
+ const char* variableContent = GetOption(variableName.c_str());
+ if (!variableContent)
+ return;
+
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(variableContent, list);
+
+ for (std::vector<std::string>::const_iterator i = list.begin();
+ i != list.end(); ++i) {
+ stream << " " << QuotePath(*i);
+ }
+}
+
+std::string cmCPackWIXGenerator::RelativePathWithoutComponentPrefix(
+ std::string const& path)
+{
+ if (this->Components.empty()) {
+ return path;
+ }
+
+ std::string::size_type pos = path.find('/');
+
+ return path.substr(pos + 1);
+}
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h
new file mode 100644
index 0000000..9d3a522
--- /dev/null
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.h
@@ -0,0 +1,167 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackWIXGenerator_h
+#define cmCPackWIXGenerator_h
+
+#include <CPack/cmCPackGenerator.h>
+
+#include "cmWIXPatch.h"
+#include "cmWIXShortcut.h"
+
+#include <map>
+#include <string>
+
+class cmWIXSourceWriter;
+class cmWIXDirectoriesSourceWriter;
+class cmWIXFilesSourceWriter;
+class cmWIXFeaturesSourceWriter;
+
+/** \class cmCPackWIXGenerator
+ * \brief A generator for WIX files
+ */
+class cmCPackWIXGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackWIXGenerator, cmCPackGenerator);
+
+ cmCPackWIXGenerator();
+ ~cmCPackWIXGenerator();
+
+protected:
+ virtual int InitializeInternal();
+
+ virtual int PackageFiles();
+
+ virtual const char* GetOutputExtension() { return ".msi"; }
+
+ virtual enum CPackSetDestdirSupport SupportsSetDestdir() const
+ {
+ return SETDESTDIR_UNSUPPORTED;
+ }
+
+ virtual bool SupportsAbsoluteDestination() const { return false; }
+
+ virtual bool SupportsComponentInstallation() const { return true; }
+
+private:
+ typedef std::map<std::string, std::string> id_map_t;
+ typedef std::map<std::string, size_t> ambiguity_map_t;
+ typedef std::set<std::string> extension_set_t;
+
+ bool InitializeWiXConfiguration();
+
+ bool PackageFilesImpl();
+
+ void CreateWiXVariablesIncludeFile();
+
+ void CreateWiXPropertiesIncludeFile();
+
+ void CreateWiXProductFragmentIncludeFile();
+
+ void CopyDefinition(cmWIXSourceWriter& source, std::string const& name);
+
+ void AddDefinition(cmWIXSourceWriter& source, std::string const& name,
+ std::string const& value);
+
+ bool CreateWiXSourceFiles();
+
+ std::string GetProgramFilesFolderId() const;
+
+ bool GenerateMainSourceFileFromTemplate();
+
+ bool CreateFeatureHierarchy(cmWIXFeaturesSourceWriter& featureDefinitions);
+
+ bool AddComponentsToFeature(
+ std::string const& rootPath, std::string const& featureId,
+ cmWIXDirectoriesSourceWriter& directoryDefinitions,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions, cmWIXShortcuts& shortcuts);
+
+ bool CreateShortcuts(std::string const& cpackComponentName,
+ std::string const& featureId,
+ cmWIXShortcuts const& shortcuts,
+ bool emitUninstallShortcut,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions);
+
+ bool CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::Type type, std::string const& cpackComponentName,
+ std::string const& featureId, std::string const& idPrefix,
+ cmWIXShortcuts const& shortcuts, bool emitUninstallShortcut,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions);
+
+ void AppendUserSuppliedExtraSources();
+
+ void AppendUserSuppliedExtraObjects(std::ostream& stream);
+
+ bool CreateLicenseFile();
+
+ bool RunWiXCommand(std::string const& command);
+
+ bool RunCandleCommand(std::string const& sourceFile,
+ std::string const& objectFile);
+
+ bool RunLightCommand(std::string const& objectFiles);
+
+ void AddDirectoryAndFileDefinitons(
+ std::string const& topdir, std::string const& directoryId,
+ cmWIXDirectoriesSourceWriter& directoryDefinitions,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions,
+ std::vector<std::string> const& packageExecutables,
+ std::vector<std::string> const& desktopExecutables,
+ cmWIXShortcuts& shortcuts);
+
+ bool RequireOption(std::string const& name, std::string& value) const;
+
+ std::string GetArchitecture() const;
+
+ static std::string GenerateGUID();
+
+ static std::string QuotePath(std::string const& path);
+
+ static std::string GetRightmostExtension(std::string const& filename);
+
+ std::string PathToId(std::string const& path);
+
+ std::string CreateNewIdForPath(std::string const& path);
+
+ static std::string CreateHashedId(std::string const& path,
+ std::string const& normalizedFilename);
+
+ std::string NormalizeComponentForId(std::string const& component,
+ size_t& replacementCount);
+
+ static bool IsLegalIdCharacter(char c);
+
+ void CollectExtensions(std::string const& variableName,
+ extension_set_t& extensions);
+
+ void AddCustomFlags(std::string const& variableName, std::ostream& stream);
+
+ std::string RelativePathWithoutComponentPrefix(std::string const& path);
+
+ std::vector<std::string> WixSources;
+ id_map_t PathToIdMap;
+ ambiguity_map_t IdAmbiguityCounter;
+
+ extension_set_t CandleExtensions;
+ extension_set_t LightExtensions;
+
+ std::string CPackTopLevel;
+
+ cmWIXPatch* Patch;
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXAccessControlList.cxx b/Source/CPack/WiX/cmWIXAccessControlList.cxx
new file mode 100644
index 0000000..bbbd92d
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXAccessControlList.cxx
@@ -0,0 +1,136 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXAccessControlList.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+#include <cmSystemTools.h>
+
+cmWIXAccessControlList::cmWIXAccessControlList(
+ cmCPackLog* logger, cmInstalledFile const& installedFile,
+ cmWIXSourceWriter& sourceWriter)
+ : Logger(logger)
+ , InstalledFile(installedFile)
+ , SourceWriter(sourceWriter)
+{
+}
+
+bool cmWIXAccessControlList::Apply()
+{
+ std::vector<std::string> entries;
+ this->InstalledFile.GetPropertyAsList("CPACK_WIX_ACL", entries);
+
+ for (size_t i = 0; i < entries.size(); ++i) {
+ this->CreatePermissionElement(entries[i]);
+ }
+
+ return true;
+}
+
+void cmWIXAccessControlList::CreatePermissionElement(std::string const& entry)
+{
+ std::string::size_type pos = entry.find('=');
+ if (pos == std::string::npos) {
+ this->ReportError(entry, "Did not find mandatory '='");
+ return;
+ }
+
+ std::string user_and_domain = entry.substr(0, pos);
+ std::string permission_string = entry.substr(pos + 1);
+
+ pos = user_and_domain.find('@');
+ std::string user;
+ std::string domain;
+ if (pos != std::string::npos) {
+ user = user_and_domain.substr(0, pos);
+ domain = user_and_domain.substr(pos + 1);
+ } else {
+ user = user_and_domain;
+ }
+
+ std::vector<std::string> permissions =
+ cmSystemTools::tokenize(permission_string, ",");
+
+ this->SourceWriter.BeginElement("Permission");
+ this->SourceWriter.AddAttribute("User", user);
+ if (!domain.empty()) {
+ this->SourceWriter.AddAttribute("Domain", domain);
+ }
+ for (size_t i = 0; i < permissions.size(); ++i) {
+ this->EmitBooleanAttribute(entry,
+ cmSystemTools::TrimWhitespace(permissions[i]));
+ }
+ this->SourceWriter.EndElement("Permission");
+}
+
+void cmWIXAccessControlList::ReportError(std::string const& entry,
+ std::string const& message)
+{
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Failed processing ACL entry '"
+ << entry << "': " << message << std::endl);
+}
+
+bool cmWIXAccessControlList::IsBooleanAttribute(std::string const& name)
+{
+ static const char* validAttributes[] = {
+ /* clang-format needs this comment to break after the opening brace */
+ "Append",
+ "ChangePermission",
+ "CreateChild",
+ "CreateFile",
+ "CreateLink",
+ "CreateSubkeys",
+ "Delete",
+ "DeleteChild",
+ "EnumerateSubkeys",
+ "Execute",
+ "FileAllRights",
+ "GenericAll",
+ "GenericExecute",
+ "GenericRead",
+ "GenericWrite",
+ "Notify",
+ "Read",
+ "ReadAttributes",
+ "ReadExtendedAttributes",
+ "ReadPermission",
+ "SpecificRightsAll",
+ "Synchronize",
+ "TakeOwnership",
+ "Traverse",
+ "Write",
+ "WriteAttributes",
+ "WriteExtendedAttributes",
+ 0
+ };
+
+ size_t i = 0;
+ while (validAttributes[i]) {
+ if (name == validAttributes[i++])
+ return true;
+ }
+
+ return false;
+}
+
+void cmWIXAccessControlList::EmitBooleanAttribute(std::string const& entry,
+ std::string const& name)
+{
+ if (!this->IsBooleanAttribute(name)) {
+ std::ostringstream message;
+ message << "Unknown boolean attribute '" << name << "'";
+ this->ReportError(entry, message.str());
+ }
+
+ this->SourceWriter.AddAttribute(name, "yes");
+}
diff --git a/Source/CPack/WiX/cmWIXAccessControlList.h b/Source/CPack/WiX/cmWIXAccessControlList.h
new file mode 100644
index 0000000..a1ac593
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXAccessControlList.h
@@ -0,0 +1,44 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXAccessControlList_h
+#define cmWIXAccessControlList_h
+
+#include "cmWIXSourceWriter.h"
+
+#include <CPack/cmCPackLog.h>
+#include <cmInstalledFile.h>
+
+class cmWIXAccessControlList
+{
+public:
+ cmWIXAccessControlList(cmCPackLog* logger,
+ cmInstalledFile const& installedFile,
+ cmWIXSourceWriter& sourceWriter);
+
+ bool Apply();
+
+private:
+ void CreatePermissionElement(std::string const& entry);
+
+ void ReportError(std::string const& entry, std::string const& message);
+
+ bool IsBooleanAttribute(std::string const& name);
+
+ void EmitBooleanAttribute(std::string const& entry, std::string const& name);
+
+ cmCPackLog* Logger;
+ cmInstalledFile const& InstalledFile;
+ cmWIXSourceWriter& SourceWriter;
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx
new file mode 100644
index 0000000..de64059
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx
@@ -0,0 +1,88 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXDirectoriesSourceWriter.h"
+
+cmWIXDirectoriesSourceWriter::cmWIXDirectoriesSourceWriter(
+ cmCPackLog* logger, std::string const& filename)
+ : cmWIXSourceWriter(logger, filename)
+{
+}
+
+void cmWIXDirectoriesSourceWriter::EmitStartMenuFolder(
+ std::string const& startMenuFolder)
+{
+ BeginElement("Directory");
+ AddAttribute("Id", "ProgramMenuFolder");
+
+ BeginElement("Directory");
+ AddAttribute("Id", "PROGRAM_MENU_FOLDER");
+ AddAttribute("Name", startMenuFolder);
+ EndElement("Directory");
+
+ EndElement("Directory");
+}
+
+void cmWIXDirectoriesSourceWriter::EmitDesktopFolder()
+{
+ BeginElement("Directory");
+ AddAttribute("Id", "DesktopFolder");
+ AddAttribute("Name", "Desktop");
+ EndElement("Directory");
+}
+
+void cmWIXDirectoriesSourceWriter::EmitStartupFolder()
+{
+ BeginElement("Directory");
+ AddAttribute("Id", "StartupFolder");
+ AddAttribute("Name", "Startup");
+ EndElement("Directory");
+}
+
+size_t cmWIXDirectoriesSourceWriter::BeginInstallationPrefixDirectory(
+ std::string const& programFilesFolderId,
+ std::string const& installRootString)
+{
+ BeginElement("Directory");
+ AddAttribute("Id", programFilesFolderId);
+
+ std::vector<std::string> installRoot;
+
+ cmSystemTools::SplitPath(installRootString.c_str(), installRoot);
+
+ if (!installRoot.empty() && installRoot.back().empty()) {
+ installRoot.pop_back();
+ }
+
+ for (size_t i = 1; i < installRoot.size(); ++i) {
+ BeginElement("Directory");
+
+ if (i == installRoot.size() - 1) {
+ AddAttribute("Id", "INSTALL_ROOT");
+ } else {
+ std::ostringstream tmp;
+ tmp << "INSTALL_PREFIX_" << i;
+ AddAttribute("Id", tmp.str());
+ }
+
+ AddAttribute("Name", installRoot[i]);
+ }
+
+ return installRoot.size();
+}
+
+void cmWIXDirectoriesSourceWriter::EndInstallationPrefixDirectory(size_t size)
+{
+ for (size_t i = 0; i < size; ++i) {
+ EndElement("Directory");
+ }
+}
diff --git a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h
new file mode 100644
index 0000000..023f4b8
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h
@@ -0,0 +1,44 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXDirectoriesSourceWriter_h
+#define cmWIXDirectoriesSourceWriter_h
+
+#include "cmWIXSourceWriter.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+#include <string>
+
+/** \class cmWIXDirectoriesSourceWriter
+ * \brief Helper class to generate directories.wxs
+ */
+class cmWIXDirectoriesSourceWriter : public cmWIXSourceWriter
+{
+public:
+ cmWIXDirectoriesSourceWriter(cmCPackLog* logger,
+ std::string const& filename);
+
+ void EmitStartMenuFolder(std::string const& startMenuFolder);
+
+ void EmitDesktopFolder();
+
+ void EmitStartupFolder();
+
+ size_t BeginInstallationPrefixDirectory(
+ std::string const& programFilesFolderId,
+ std::string const& installRootString);
+
+ void EndInstallationPrefixDirectory(size_t size);
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx
new file mode 100644
index 0000000..16dd0ab
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx
@@ -0,0 +1,97 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXFeaturesSourceWriter.h"
+
+cmWIXFeaturesSourceWriter::cmWIXFeaturesSourceWriter(
+ cmCPackLog* logger, std::string const& filename)
+ : cmWIXSourceWriter(logger, filename)
+{
+}
+
+void cmWIXFeaturesSourceWriter::CreateCMakePackageRegistryEntry(
+ std::string const& package, std::string const& upgradeGuid)
+{
+ BeginElement("Component");
+ AddAttribute("Id", "CM_PACKAGE_REGISTRY");
+ AddAttribute("Directory", "TARGETDIR");
+ AddAttribute("Guid", "*");
+
+ std::string registryKey =
+ std::string("Software\\Kitware\\CMake\\Packages\\") + package;
+
+ BeginElement("RegistryValue");
+ AddAttribute("Root", "HKLM");
+ AddAttribute("Key", registryKey);
+ AddAttribute("Name", upgradeGuid);
+ AddAttribute("Type", "string");
+ AddAttribute("Value", "[INSTALL_ROOT]");
+ AddAttribute("KeyPath", "yes");
+ EndElement("RegistryValue");
+
+ EndElement("Component");
+}
+
+void cmWIXFeaturesSourceWriter::EmitFeatureForComponentGroup(
+ cmCPackComponentGroup const& group)
+{
+ BeginElement("Feature");
+ AddAttribute("Id", "CM_G_" + group.Name);
+
+ if (group.IsExpandedByDefault) {
+ AddAttribute("Display", "expand");
+ }
+
+ AddAttributeUnlessEmpty("Title", group.DisplayName);
+ AddAttributeUnlessEmpty("Description", group.Description);
+
+ for (std::vector<cmCPackComponentGroup*>::const_iterator i =
+ group.Subgroups.begin();
+ i != group.Subgroups.end(); ++i) {
+ EmitFeatureForComponentGroup(**i);
+ }
+
+ for (std::vector<cmCPackComponent*>::const_iterator i =
+ group.Components.begin();
+ i != group.Components.end(); ++i) {
+ EmitFeatureForComponent(**i);
+ }
+
+ EndElement("Feature");
+}
+
+void cmWIXFeaturesSourceWriter::EmitFeatureForComponent(
+ cmCPackComponent const& component)
+{
+ BeginElement("Feature");
+ AddAttribute("Id", "CM_C_" + component.Name);
+
+ AddAttributeUnlessEmpty("Title", component.DisplayName);
+ AddAttributeUnlessEmpty("Description", component.Description);
+
+ if (component.IsRequired) {
+ AddAttribute("Absent", "disallow");
+ }
+
+ if (component.IsHidden) {
+ AddAttribute("Display", "hidden");
+ }
+
+ EndElement("Feature");
+}
+
+void cmWIXFeaturesSourceWriter::EmitComponentRef(std::string const& id)
+{
+ BeginElement("ComponentRef");
+ AddAttribute("Id", id);
+ EndElement("ComponentRef");
+}
diff --git a/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h
new file mode 100644
index 0000000..ee9c17a
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h
@@ -0,0 +1,38 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXFeaturesSourceWriter_h
+#define cmWIXFeaturesSourceWriter_h
+
+#include "cmWIXSourceWriter.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+/** \class cmWIXFeaturesSourceWriter
+ * \brief Helper class to generate features.wxs
+ */
+class cmWIXFeaturesSourceWriter : public cmWIXSourceWriter
+{
+public:
+ cmWIXFeaturesSourceWriter(cmCPackLog* logger, std::string const& filename);
+
+ void CreateCMakePackageRegistryEntry(std::string const& package,
+ std::string const& upgradeGuid);
+
+ void EmitFeatureForComponentGroup(const cmCPackComponentGroup& group);
+
+ void EmitFeatureForComponent(const cmCPackComponent& component);
+
+ void EmitComponentRef(std::string const& id);
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
new file mode 100644
index 0000000..9a143cc
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
@@ -0,0 +1,170 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXFilesSourceWriter.h"
+
+#include "cmWIXAccessControlList.h"
+
+#include <cmInstalledFile.h>
+
+#include <sys/types.h>
+// include sys/stat.h after sys/types.h
+#include <sys/stat.h>
+
+cmWIXFilesSourceWriter::cmWIXFilesSourceWriter(cmCPackLog* logger,
+ std::string const& filename)
+ : cmWIXSourceWriter(logger, filename)
+{
+}
+
+void cmWIXFilesSourceWriter::EmitShortcut(std::string const& id,
+ cmWIXShortcut const& shortcut,
+ std::string const& shortcutPrefix,
+ size_t shortcutIndex)
+{
+ std::ostringstream shortcutId;
+ shortcutId << shortcutPrefix << id;
+
+ if (shortcutIndex > 0) {
+ shortcutId << "_" << shortcutIndex;
+ }
+
+ std::string fileId = std::string("CM_F") + id;
+
+ BeginElement("Shortcut");
+ AddAttribute("Id", shortcutId.str());
+ AddAttribute("Name", shortcut.label);
+ std::string target = "[#" + fileId + "]";
+ AddAttribute("Target", target);
+ AddAttribute("WorkingDirectory", shortcut.workingDirectoryId);
+ EndElement("Shortcut");
+}
+
+void cmWIXFilesSourceWriter::EmitRemoveFolder(std::string const& id)
+{
+ BeginElement("RemoveFolder");
+ AddAttribute("Id", id);
+ AddAttribute("On", "uninstall");
+ EndElement("RemoveFolder");
+}
+
+void cmWIXFilesSourceWriter::EmitInstallRegistryValue(
+ std::string const& registryKey, std::string const& cpackComponentName,
+ std::string const& suffix)
+{
+ std::string valueName;
+ if (!cpackComponentName.empty()) {
+ valueName = cpackComponentName + "_";
+ }
+
+ valueName += "installed";
+ valueName += suffix;
+
+ BeginElement("RegistryValue");
+ AddAttribute("Root", "HKCU");
+ AddAttribute("Key", registryKey);
+ AddAttribute("Name", valueName);
+ AddAttribute("Type", "integer");
+ AddAttribute("Value", "1");
+ AddAttribute("KeyPath", "yes");
+ EndElement("RegistryValue");
+}
+
+void cmWIXFilesSourceWriter::EmitUninstallShortcut(
+ std::string const& packageName)
+{
+ BeginElement("Shortcut");
+ AddAttribute("Id", "UNINSTALL");
+ AddAttribute("Name", "Uninstall " + packageName);
+ AddAttribute("Description", "Uninstalls " + packageName);
+ AddAttribute("Target", "[SystemFolder]msiexec.exe");
+ AddAttribute("Arguments", "/x [ProductCode]");
+ EndElement("Shortcut");
+}
+
+std::string cmWIXFilesSourceWriter::EmitComponentCreateFolder(
+ std::string const& directoryId, std::string const& guid,
+ cmInstalledFile const* installedFile)
+{
+ std::string componentId = std::string("CM_C_EMPTY_") + directoryId;
+
+ BeginElement("DirectoryRef");
+ AddAttribute("Id", directoryId);
+
+ BeginElement("Component");
+ AddAttribute("Id", componentId);
+ AddAttribute("Guid", guid);
+
+ BeginElement("CreateFolder");
+
+ if (installedFile) {
+ cmWIXAccessControlList acl(Logger, *installedFile, *this);
+ acl.Apply();
+ }
+
+ EndElement("CreateFolder");
+ EndElement("Component");
+ EndElement("DirectoryRef");
+
+ return componentId;
+}
+
+std::string cmWIXFilesSourceWriter::EmitComponentFile(
+ std::string const& directoryId, std::string const& id,
+ std::string const& filePath, cmWIXPatch& patch,
+ cmInstalledFile const* installedFile)
+{
+ std::string componentId = std::string("CM_C") + id;
+ std::string fileId = std::string("CM_F") + id;
+
+ BeginElement("DirectoryRef");
+ AddAttribute("Id", directoryId);
+
+ BeginElement("Component");
+ AddAttribute("Id", componentId);
+ AddAttribute("Guid", "*");
+
+ if (installedFile) {
+ if (installedFile->GetPropertyAsBool("CPACK_NEVER_OVERWRITE")) {
+ AddAttribute("NeverOverwrite", "yes");
+ }
+ if (installedFile->GetPropertyAsBool("CPACK_PERMANENT")) {
+ AddAttribute("Permanent", "yes");
+ }
+ }
+
+ BeginElement("File");
+ AddAttribute("Id", fileId);
+ AddAttribute("Source", filePath);
+ AddAttribute("KeyPath", "yes");
+
+ mode_t fileMode = 0;
+ cmSystemTools::GetPermissions(filePath.c_str(), fileMode);
+
+ if (!(fileMode & S_IWRITE)) {
+ AddAttribute("ReadOnly", "yes");
+ }
+
+ if (installedFile) {
+ cmWIXAccessControlList acl(Logger, *installedFile, *this);
+ acl.Apply();
+ }
+
+ patch.ApplyFragment(fileId, *this);
+ EndElement("File");
+
+ patch.ApplyFragment(componentId, *this);
+ EndElement("Component");
+ EndElement("DirectoryRef");
+
+ return componentId;
+}
diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.h b/Source/CPack/WiX/cmWIXFilesSourceWriter.h
new file mode 100644
index 0000000..c577e5b
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.h
@@ -0,0 +1,52 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXFilesSourceWriter_h
+#define cmWIXFilesSourceWriter_h
+
+#include "cmWIXSourceWriter.h"
+
+#include "cmWIXPatch.h"
+#include "cmWIXShortcut.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+/** \class cmWIXFilesSourceWriter
+ * \brief Helper class to generate files.wxs
+ */
+class cmWIXFilesSourceWriter : public cmWIXSourceWriter
+{
+public:
+ cmWIXFilesSourceWriter(cmCPackLog* logger, std::string const& filename);
+
+ void EmitShortcut(std::string const& id, cmWIXShortcut const& shortcut,
+ std::string const& shortcutPrefix, size_t shortcutIndex);
+
+ void EmitRemoveFolder(std::string const& id);
+
+ void EmitInstallRegistryValue(std::string const& registryKey,
+ std::string const& cpackComponentName,
+ std::string const& suffix);
+
+ void EmitUninstallShortcut(std::string const& packageName);
+
+ std::string EmitComponentCreateFolder(std::string const& directoryId,
+ std::string const& guid,
+ cmInstalledFile const* installedFile);
+
+ std::string EmitComponentFile(std::string const& directoryId,
+ std::string const& id,
+ std::string const& filePath, cmWIXPatch& patch,
+ cmInstalledFile const* installedFile);
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXPatch.cxx b/Source/CPack/WiX/cmWIXPatch.cxx
new file mode 100644
index 0000000..c9d010e
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXPatch.cxx
@@ -0,0 +1,105 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXPatch.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+cmWIXPatch::cmWIXPatch(cmCPackLog* logger)
+ : Logger(logger)
+{
+}
+
+bool cmWIXPatch::LoadFragments(std::string const& patchFilePath)
+{
+ cmWIXPatchParser parser(Fragments, Logger);
+ if (!parser.ParseFile(patchFilePath.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Failed parsing XML patch file: '"
+ << patchFilePath << "'" << std::endl);
+ return false;
+ }
+
+ return true;
+}
+
+void cmWIXPatch::ApplyFragment(std::string const& id,
+ cmWIXSourceWriter& writer)
+{
+ cmWIXPatchParser::fragment_map_t::iterator i = Fragments.find(id);
+ if (i == Fragments.end())
+ return;
+
+ const cmWIXPatchElement& fragment = i->second;
+
+ this->ApplyElementChildren(fragment, writer);
+
+ Fragments.erase(i);
+}
+
+void cmWIXPatch::ApplyElementChildren(const cmWIXPatchElement& element,
+ cmWIXSourceWriter& writer)
+{
+ for (cmWIXPatchElement::child_list_t::const_iterator j =
+ element.children.begin();
+ j != element.children.end(); ++j) {
+ cmWIXPatchNode* node = *j;
+
+ switch (node->type()) {
+ case cmWIXPatchNode::ELEMENT:
+ ApplyElement(dynamic_cast<const cmWIXPatchElement&>(*node), writer);
+ break;
+ case cmWIXPatchNode::TEXT:
+ writer.AddTextNode(dynamic_cast<const cmWIXPatchText&>(*node).text);
+ break;
+ }
+ }
+}
+
+void cmWIXPatch::ApplyElement(const cmWIXPatchElement& element,
+ cmWIXSourceWriter& writer)
+{
+ writer.BeginElement(element.name);
+
+ for (cmWIXPatchElement::attributes_t::const_iterator i =
+ element.attributes.begin();
+ i != element.attributes.end(); ++i) {
+ writer.AddAttribute(i->first, i->second);
+ }
+
+ this->ApplyElementChildren(element, writer);
+
+ writer.EndElement(element.name);
+}
+
+bool cmWIXPatch::CheckForUnappliedFragments()
+{
+ std::string fragmentList;
+ for (cmWIXPatchParser::fragment_map_t::const_iterator i = Fragments.begin();
+ i != Fragments.end(); ++i) {
+ if (!fragmentList.empty()) {
+ fragmentList += ", ";
+ }
+
+ fragmentList += "'";
+ fragmentList += i->first;
+ fragmentList += "'";
+ }
+
+ if (!fragmentList.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Some XML patch fragments did not have matching IDs: "
+ << fragmentList << std::endl);
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/CPack/WiX/cmWIXPatch.h b/Source/CPack/WiX/cmWIXPatch.h
new file mode 100644
index 0000000..57b74cd
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXPatch.h
@@ -0,0 +1,47 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXPatch_h
+#define cmWIXPatch_h
+
+#include "cmWIXPatchParser.h"
+#include "cmWIXSourceWriter.h"
+
+#include <string>
+
+/** \class cmWIXPatch
+ * \brief Class that maintains and applies patch fragments
+ */
+class cmWIXPatch
+{
+public:
+ cmWIXPatch(cmCPackLog* logger);
+
+ bool LoadFragments(std::string const& patchFilePath);
+
+ void ApplyFragment(std::string const& id, cmWIXSourceWriter& writer);
+
+ bool CheckForUnappliedFragments();
+
+private:
+ void ApplyElementChildren(const cmWIXPatchElement& element,
+ cmWIXSourceWriter& writer);
+
+ void ApplyElement(const cmWIXPatchElement& element,
+ cmWIXSourceWriter& writer);
+
+ cmCPackLog* Logger;
+
+ cmWIXPatchParser::fragment_map_t Fragments;
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXPatchParser.cxx b/Source/CPack/WiX/cmWIXPatchParser.cxx
new file mode 100644
index 0000000..449a70b
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXPatchParser.cxx
@@ -0,0 +1,156 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXPatchParser.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+#include <cm_expat.h>
+
+cmWIXPatchNode::Type cmWIXPatchText::type()
+{
+ return cmWIXPatchNode::TEXT;
+}
+
+cmWIXPatchNode::Type cmWIXPatchElement::type()
+{
+ return cmWIXPatchNode::ELEMENT;
+}
+
+cmWIXPatchNode::~cmWIXPatchNode()
+{
+}
+
+cmWIXPatchElement::~cmWIXPatchElement()
+{
+ for (child_list_t::iterator i = children.begin(); i != children.end(); ++i) {
+ delete *i;
+ }
+}
+
+cmWIXPatchParser::cmWIXPatchParser(fragment_map_t& fragments,
+ cmCPackLog* logger)
+ : Logger(logger)
+ , State(BEGIN_DOCUMENT)
+ , Valid(true)
+ , Fragments(fragments)
+{
+}
+
+void cmWIXPatchParser::StartElement(const std::string& name, const char** atts)
+{
+ if (State == BEGIN_DOCUMENT) {
+ if (name == "CPackWiXPatch") {
+ State = BEGIN_FRAGMENTS;
+ } else {
+ ReportValidationError("Expected root element 'CPackWiXPatch'");
+ }
+ } else if (State == BEGIN_FRAGMENTS) {
+ if (name == "CPackWiXFragment") {
+ State = INSIDE_FRAGMENT;
+ StartFragment(atts);
+ } else {
+ ReportValidationError("Expected 'CPackWixFragment' element");
+ }
+ } else if (State == INSIDE_FRAGMENT) {
+ cmWIXPatchElement& parent = *ElementStack.back();
+
+ cmWIXPatchElement* element = new cmWIXPatchElement;
+ parent.children.push_back(element);
+
+ element->name = name;
+
+ for (size_t i = 0; atts[i]; i += 2) {
+ std::string key = atts[i];
+ std::string value = atts[i + 1];
+
+ element->attributes[key] = value;
+ }
+
+ ElementStack.push_back(element);
+ }
+}
+
+void cmWIXPatchParser::StartFragment(const char** attributes)
+{
+ for (size_t i = 0; attributes[i]; i += 2) {
+ std::string key = attributes[i];
+ std::string value = attributes[i + 1];
+
+ if (key == "Id") {
+ if (Fragments.find(value) != Fragments.end()) {
+ std::ostringstream tmp;
+ tmp << "Invalid reuse of 'CPackWixFragment' 'Id': " << value;
+ ReportValidationError(tmp.str());
+ }
+
+ ElementStack.push_back(&Fragments[value]);
+ } else {
+ ReportValidationError(
+ "The only allowed 'CPackWixFragment' attribute is 'Id'");
+ }
+ }
+}
+
+void cmWIXPatchParser::EndElement(const std::string& name)
+{
+ if (State == INSIDE_FRAGMENT) {
+ if (name == "CPackWiXFragment") {
+ State = BEGIN_FRAGMENTS;
+ ElementStack.clear();
+ } else {
+ ElementStack.pop_back();
+ }
+ }
+}
+
+void cmWIXPatchParser::CharacterDataHandler(const char* data, int length)
+{
+ const char* whitespace = "\x20\x09\x0d\x0a";
+
+ if (State == INSIDE_FRAGMENT) {
+ cmWIXPatchElement& parent = *ElementStack.back();
+
+ std::string text(data, length);
+
+ std::string::size_type first = text.find_first_not_of(whitespace);
+ std::string::size_type last = text.find_last_not_of(whitespace);
+
+ if (first != std::string::npos && last != std::string::npos) {
+ cmWIXPatchText* text_node = new cmWIXPatchText;
+ text_node->text = text.substr(first, last - first + 1);
+
+ parent.children.push_back(text_node);
+ }
+ }
+}
+
+void cmWIXPatchParser::ReportError(int line, int column, const char* msg)
+{
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while processing XML patch file at "
+ << line << ":" << column << ": " << msg << std::endl);
+ Valid = false;
+}
+
+void cmWIXPatchParser::ReportValidationError(std::string const& message)
+{
+ ReportError(
+ XML_GetCurrentLineNumber(static_cast<XML_Parser>(this->Parser)),
+ XML_GetCurrentColumnNumber(static_cast<XML_Parser>(this->Parser)),
+ message.c_str());
+}
+
+bool cmWIXPatchParser::IsValid() const
+{
+ return Valid;
+}
diff --git a/Source/CPack/WiX/cmWIXPatchParser.h b/Source/CPack/WiX/cmWIXPatchParser.h
new file mode 100644
index 0000000..f9b85bd
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXPatchParser.h
@@ -0,0 +1,100 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackWIXPatchParser_h
+#define cmCPackWIXPatchParser_h
+
+#include <CPack/cmCPackLog.h>
+
+#include <cmXMLParser.h>
+
+#include <list>
+#include <map>
+
+struct cmWIXPatchNode
+{
+ enum Type
+ {
+ TEXT,
+ ELEMENT
+ };
+
+ virtual ~cmWIXPatchNode();
+
+ virtual Type type() = 0;
+};
+
+struct cmWIXPatchText : public cmWIXPatchNode
+{
+ virtual Type type();
+
+ std::string text;
+};
+
+struct cmWIXPatchElement : cmWIXPatchNode
+{
+ virtual Type type();
+
+ ~cmWIXPatchElement();
+
+ typedef std::list<cmWIXPatchNode*> child_list_t;
+ typedef std::map<std::string, std::string> attributes_t;
+
+ std::string name;
+ child_list_t children;
+ attributes_t attributes;
+};
+
+/** \class cmWIXPatchParser
+ * \brief Helper class that parses XML patch files (CPACK_WIX_PATCH_FILE)
+ */
+class cmWIXPatchParser : public cmXMLParser
+{
+public:
+ typedef std::map<std::string, cmWIXPatchElement> fragment_map_t;
+
+ cmWIXPatchParser(fragment_map_t& Fragments, cmCPackLog* logger);
+
+private:
+ virtual void StartElement(const std::string& name, const char** atts);
+
+ void StartFragment(const char** attributes);
+
+ virtual void EndElement(const std::string& name);
+
+ virtual void CharacterDataHandler(const char* data, int length);
+
+ virtual void ReportError(int line, int column, const char* msg);
+
+ void ReportValidationError(std::string const& message);
+
+ bool IsValid() const;
+
+ cmCPackLog* Logger;
+
+ enum ParserState
+ {
+ BEGIN_DOCUMENT,
+ BEGIN_FRAGMENTS,
+ INSIDE_FRAGMENT
+ };
+
+ ParserState State;
+
+ bool Valid;
+
+ fragment_map_t& Fragments;
+
+ std::list<cmWIXPatchElement*> ElementStack;
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx b/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx
new file mode 100644
index 0000000..f3dbcb9
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx
@@ -0,0 +1,196 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2012 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXRichTextFormatWriter.h"
+
+#include <cmVersion.h>
+
+cmWIXRichTextFormatWriter::cmWIXRichTextFormatWriter(
+ std::string const& filename)
+ : File(filename.c_str(), std::ios::binary)
+{
+ StartGroup();
+ WriteHeader();
+ WriteDocumentPrefix();
+}
+
+cmWIXRichTextFormatWriter::~cmWIXRichTextFormatWriter()
+{
+ EndGroup();
+
+ /* I haven't seen this in the RTF spec but
+ * wordpad terminates its RTF like this */
+ File << "\r\n";
+ File.put(0);
+}
+
+void cmWIXRichTextFormatWriter::AddText(std::string const& text)
+{
+ typedef unsigned char rtf_byte_t;
+
+ for (size_t i = 0; i < text.size(); ++i) {
+ rtf_byte_t c = rtf_byte_t(text[i]);
+
+ switch (c) {
+ case '\\':
+ File << "\\\\";
+ break;
+ case '{':
+ File << "\\{";
+ break;
+ case '}':
+ File << "\\}";
+ break;
+ case '\n':
+ File << "\\par\r\n";
+ break;
+ case '\r':
+ continue;
+ default: {
+ if (c <= 0x7F) {
+ File << c;
+ } else {
+ if (c <= 0xC0) {
+ EmitInvalidCodepoint(c);
+ } else if (c < 0xE0 && i + 1 < text.size()) {
+ EmitUnicodeCodepoint((text[i + 1] & 0x3F) | ((c & 0x1F) << 6));
+ i += 1;
+ } else if (c < 0xF0 && i + 2 < text.size()) {
+ EmitUnicodeCodepoint((text[i + 2] & 0x3F) |
+ ((text[i + 1] & 0x3F) << 6) |
+ ((c & 0xF) << 12));
+ i += 2;
+ } else if (c < 0xF8 && i + 3 < text.size()) {
+ EmitUnicodeCodepoint(
+ (text[i + 3] & 0x3F) | ((text[i + 2] & 0x3F) << 6) |
+ ((text[i + 1] & 0x3F) << 12) | ((c & 0x7) << 18));
+ i += 3;
+ } else {
+ EmitInvalidCodepoint(c);
+ }
+ }
+ } break;
+ }
+ }
+}
+
+void cmWIXRichTextFormatWriter::WriteHeader()
+{
+ ControlWord("rtf1");
+ ControlWord("ansi");
+ ControlWord("ansicpg1252");
+ ControlWord("deff0");
+ ControlWord("deflang1031");
+
+ WriteFontTable();
+ WriteColorTable();
+ WriteGenerator();
+}
+
+void cmWIXRichTextFormatWriter::WriteFontTable()
+{
+ StartGroup();
+ ControlWord("fonttbl");
+
+ StartGroup();
+ ControlWord("f0");
+ ControlWord("fswiss");
+ ControlWord("fcharset0 Arial;");
+ EndGroup();
+
+ EndGroup();
+}
+
+void cmWIXRichTextFormatWriter::WriteColorTable()
+{
+ StartGroup();
+ ControlWord("colortbl ;");
+ ControlWord("red255");
+ ControlWord("green0");
+ ControlWord("blue0;");
+ ControlWord("red0");
+ ControlWord("green255");
+ ControlWord("blue0;");
+ ControlWord("red0");
+ ControlWord("green0");
+ ControlWord("blue255;");
+ EndGroup();
+}
+
+void cmWIXRichTextFormatWriter::WriteGenerator()
+{
+ StartGroup();
+ NewControlWord("generator");
+ File << " CPack WiX Generator (" << cmVersion::GetCMakeVersion() << ");";
+ EndGroup();
+}
+
+void cmWIXRichTextFormatWriter::WriteDocumentPrefix()
+{
+ ControlWord("viewkind4");
+ ControlWord("uc1");
+ ControlWord("pard");
+ ControlWord("f0");
+ ControlWord("fs20");
+}
+
+void cmWIXRichTextFormatWriter::ControlWord(std::string const& keyword)
+{
+ File << "\\" << keyword;
+}
+
+void cmWIXRichTextFormatWriter::NewControlWord(std::string const& keyword)
+{
+ File << "\\*\\" << keyword;
+}
+
+void cmWIXRichTextFormatWriter::StartGroup()
+{
+ File.put('{');
+}
+
+void cmWIXRichTextFormatWriter::EndGroup()
+{
+ File.put('}');
+}
+
+void cmWIXRichTextFormatWriter::EmitUnicodeCodepoint(int c)
+{
+ // Do not emit byte order mark (BOM)
+ if (c == 0xFEFF) {
+ return;
+ } else if (c <= 0xFFFF) {
+ EmitUnicodeSurrogate(c);
+ } else {
+ c -= 0x10000;
+ EmitUnicodeSurrogate(((c >> 10) & 0x3FF) + 0xD800);
+ EmitUnicodeSurrogate((c & 0x3FF) + 0xDC00);
+ }
+}
+
+void cmWIXRichTextFormatWriter::EmitUnicodeSurrogate(int c)
+{
+ ControlWord("u");
+ if (c <= 32767) {
+ File << c;
+ } else {
+ File << (c - 65536);
+ }
+ File << "?";
+}
+
+void cmWIXRichTextFormatWriter::EmitInvalidCodepoint(int c)
+{
+ ControlWord("cf1 ");
+ File << "[INVALID-BYTE-" << int(c) << "]";
+ ControlWord("cf0 ");
+}
diff --git a/Source/CPack/WiX/cmWIXRichTextFormatWriter.h b/Source/CPack/WiX/cmWIXRichTextFormatWriter.h
new file mode 100644
index 0000000..acf1fa6
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXRichTextFormatWriter.h
@@ -0,0 +1,54 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2012 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXRichTextFormatWriter_h
+#define cmWIXRichTextFormatWriter_h
+
+#include "cmStandardIncludes.h"
+
+#include <cmsys/FStream.hxx>
+
+/** \class cmWIXRichtTextFormatWriter
+ * \brief Helper class to generate Rich Text Format (RTF) documents
+ * from plain text (e.g. for license and welcome text)
+ */
+class cmWIXRichTextFormatWriter
+{
+public:
+ cmWIXRichTextFormatWriter(std::string const& filename);
+ ~cmWIXRichTextFormatWriter();
+
+ void AddText(std::string const& text);
+
+private:
+ void WriteHeader();
+ void WriteFontTable();
+ void WriteColorTable();
+ void WriteGenerator();
+
+ void WriteDocumentPrefix();
+
+ void ControlWord(std::string const& keyword);
+ void NewControlWord(std::string const& keyword);
+
+ void StartGroup();
+ void EndGroup();
+
+ void EmitUnicodeCodepoint(int c);
+ void EmitUnicodeSurrogate(int c);
+
+ void EmitInvalidCodepoint(int c);
+
+ cmsys::ofstream File;
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXShortcut.cxx b/Source/CPack/WiX/cmWIXShortcut.cxx
new file mode 100644
index 0000000..2685a23
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXShortcut.cxx
@@ -0,0 +1,115 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXShortcut.h"
+
+#include "cmWIXFilesSourceWriter.h"
+
+void cmWIXShortcuts::insert(Type type, std::string const& id,
+ cmWIXShortcut const& shortcut)
+{
+ this->Shortcuts[type][id].push_back(shortcut);
+}
+
+bool cmWIXShortcuts::empty(Type type) const
+{
+ return this->Shortcuts.find(type) == this->Shortcuts.end();
+}
+
+bool cmWIXShortcuts::EmitShortcuts(
+ Type type, std::string const& registryKey,
+ std::string const& cpackComponentName,
+ cmWIXFilesSourceWriter& fileDefinitions) const
+{
+ shortcut_type_map_t::const_iterator i = this->Shortcuts.find(type);
+
+ if (i == this->Shortcuts.end()) {
+ return false;
+ }
+
+ shortcut_id_map_t const& id_map = i->second;
+
+ std::string shortcutPrefix;
+ std::string registrySuffix;
+
+ switch (type) {
+ case START_MENU:
+ shortcutPrefix = "CM_S";
+ break;
+ case DESKTOP:
+ shortcutPrefix = "CM_DS";
+ registrySuffix = "_desktop";
+ break;
+ case STARTUP:
+ shortcutPrefix = "CM_SS";
+ registrySuffix = "_startup";
+ break;
+ default:
+ return false;
+ }
+
+ for (shortcut_id_map_t::const_iterator j = id_map.begin(); j != id_map.end();
+ ++j) {
+ std::string const& id = j->first;
+ shortcut_list_t const& shortcutList = j->second;
+
+ for (size_t shortcutListIndex = 0; shortcutListIndex < shortcutList.size();
+ ++shortcutListIndex) {
+ cmWIXShortcut const& shortcut = shortcutList[shortcutListIndex];
+ fileDefinitions.EmitShortcut(id, shortcut, shortcutPrefix,
+ shortcutListIndex);
+ }
+ }
+
+ fileDefinitions.EmitInstallRegistryValue(registryKey, cpackComponentName,
+ registrySuffix);
+
+ return true;
+}
+
+void cmWIXShortcuts::AddShortcutTypes(std::set<Type>& types)
+{
+ for (shortcut_type_map_t::const_iterator i = this->Shortcuts.begin();
+ i != this->Shortcuts.end(); ++i) {
+ types.insert(i->first);
+ }
+}
+
+void cmWIXShortcuts::CreateFromProperties(std::string const& id,
+ std::string const& directoryId,
+ cmInstalledFile const& installedFile)
+{
+ CreateFromProperty("CPACK_START_MENU_SHORTCUTS", START_MENU, id, directoryId,
+ installedFile);
+
+ CreateFromProperty("CPACK_DESKTOP_SHORTCUTS", DESKTOP, id, directoryId,
+ installedFile);
+
+ CreateFromProperty("CPACK_STARTUP_SHORTCUTS", STARTUP, id, directoryId,
+ installedFile);
+}
+
+void cmWIXShortcuts::CreateFromProperty(std::string const& propertyName,
+ Type type, std::string const& id,
+ std::string const& directoryId,
+ cmInstalledFile const& installedFile)
+{
+ std::vector<std::string> list;
+ installedFile.GetPropertyAsList(propertyName, list);
+
+ for (size_t i = 0; i < list.size(); ++i) {
+ cmWIXShortcut shortcut;
+ shortcut.label = list[i];
+ shortcut.workingDirectoryId = directoryId;
+ insert(type, id, shortcut);
+ }
+}
diff --git a/Source/CPack/WiX/cmWIXShortcut.h b/Source/CPack/WiX/cmWIXShortcut.h
new file mode 100644
index 0000000..593ba34
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXShortcut.h
@@ -0,0 +1,70 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXShortcut_h
+#define cmWIXShortcut_h
+
+#include <cmInstalledFile.h>
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+class cmWIXFilesSourceWriter;
+
+struct cmWIXShortcut
+{
+ std::string label;
+ std::string workingDirectoryId;
+};
+
+class cmWIXShortcuts
+{
+public:
+ enum Type
+ {
+ START_MENU,
+ DESKTOP,
+ STARTUP
+ };
+
+ typedef std::vector<cmWIXShortcut> shortcut_list_t;
+ typedef std::map<std::string, shortcut_list_t> shortcut_id_map_t;
+
+ void insert(Type type, std::string const& id, cmWIXShortcut const& shortcut);
+
+ bool empty(Type type) const;
+
+ bool EmitShortcuts(Type type, std::string const& registryKey,
+ std::string const& cpackComponentName,
+ cmWIXFilesSourceWriter& fileDefinitions) const;
+
+ void AddShortcutTypes(std::set<Type>& types);
+
+ void CreateFromProperties(std::string const& id,
+ std::string const& directoryId,
+ cmInstalledFile const& installedFile);
+
+private:
+ typedef std::map<Type, shortcut_id_map_t> shortcut_type_map_t;
+
+ void CreateFromProperty(std::string const& propertyName, Type type,
+ std::string const& id,
+ std::string const& directoryId,
+ cmInstalledFile const& installedFile);
+
+ shortcut_type_map_t Shortcuts;
+ shortcut_id_map_t EmptyIdMap;
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXSourceWriter.cxx b/Source/CPack/WiX/cmWIXSourceWriter.cxx
new file mode 100644
index 0000000..2c0384e
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXSourceWriter.cxx
@@ -0,0 +1,216 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXSourceWriter.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+#include <windows.h>
+
+cmWIXSourceWriter::cmWIXSourceWriter(cmCPackLog* logger,
+ std::string const& filename,
+ bool isIncludeFile)
+ : Logger(logger)
+ , File(filename.c_str())
+ , State(DEFAULT)
+ , SourceFilename(filename)
+{
+ WriteXMLDeclaration();
+
+ if (isIncludeFile) {
+ BeginElement("Include");
+ } else {
+ BeginElement("Wix");
+ }
+
+ AddAttribute("xmlns", "http://schemas.microsoft.com/wix/2006/wi");
+}
+
+cmWIXSourceWriter::~cmWIXSourceWriter()
+{
+ if (Elements.size() > 1) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, Elements.size() - 1
+ << " WiX elements were still open when closing '"
+ << SourceFilename << "'" << std::endl);
+ return;
+ }
+
+ EndElement(Elements.back());
+}
+
+void cmWIXSourceWriter::BeginElement(std::string const& name)
+{
+ if (State == BEGIN) {
+ File << ">";
+ }
+
+ File << "\n";
+ Indent(Elements.size());
+ File << "<" << name;
+
+ Elements.push_back(name);
+ State = BEGIN;
+}
+
+void cmWIXSourceWriter::EndElement(std::string const& name)
+{
+ if (Elements.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "can not end WiX element with no open elements in '"
+ << SourceFilename << "'" << std::endl);
+ return;
+ }
+
+ if (Elements.back() != name) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "WiX element <"
+ << Elements.back() << "> can not be closed by </" << name
+ << "> in '" << SourceFilename << "'" << std::endl);
+ return;
+ }
+
+ if (State == DEFAULT) {
+ File << "\n";
+ Indent(Elements.size() - 1);
+ File << "</" << Elements.back() << ">";
+ } else {
+ File << "/>";
+ }
+
+ Elements.pop_back();
+ State = DEFAULT;
+}
+
+void cmWIXSourceWriter::AddTextNode(std::string const& text)
+{
+ if (State == BEGIN) {
+ File << ">";
+ }
+
+ if (Elements.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "can not add text without open WiX element in '"
+ << SourceFilename << "'" << std::endl);
+ return;
+ }
+
+ File << this->EscapeAttributeValue(text);
+ State = DEFAULT;
+}
+
+void cmWIXSourceWriter::AddProcessingInstruction(std::string const& target,
+ std::string const& content)
+{
+ if (State == BEGIN) {
+ File << ">";
+ }
+
+ File << "\n";
+ Indent(Elements.size());
+ File << "<?" << target << " " << content << "?>";
+
+ State = DEFAULT;
+}
+
+void cmWIXSourceWriter::AddAttribute(std::string const& key,
+ std::string const& value)
+{
+ std::string utf8 = CMakeEncodingToUtf8(value);
+
+ File << " " << key << "=\"" << EscapeAttributeValue(utf8) << '"';
+}
+
+void cmWIXSourceWriter::AddAttributeUnlessEmpty(std::string const& key,
+ std::string const& value)
+{
+ if (!value.empty()) {
+ AddAttribute(key, value);
+ }
+}
+
+std::string cmWIXSourceWriter::CMakeEncodingToUtf8(std::string const& value)
+{
+#ifdef CMAKE_ENCODING_UTF8
+ return value;
+#else
+ if (value.empty()) {
+ return std::string();
+ }
+
+ int characterCount = MultiByteToWideChar(
+ CP_ACP, 0, value.c_str(), static_cast<int>(value.size()), 0, 0);
+
+ if (characterCount == 0) {
+ return std::string();
+ }
+
+ std::vector<wchar_t> utf16(characterCount);
+
+ MultiByteToWideChar(CP_ACP, 0, value.c_str(), static_cast<int>(value.size()),
+ &utf16[0], static_cast<int>(utf16.size()));
+
+ int utf8ByteCount = WideCharToMultiByte(
+ CP_UTF8, 0, &utf16[0], static_cast<int>(utf16.size()), 0, 0, 0, 0);
+
+ if (utf8ByteCount == 0) {
+ return std::string();
+ }
+
+ std::vector<char> utf8(utf8ByteCount);
+
+ WideCharToMultiByte(CP_UTF8, 0, &utf16[0], static_cast<int>(utf16.size()),
+ &utf8[0], static_cast<int>(utf8.size()), 0, 0);
+
+ return std::string(&utf8[0], utf8.size());
+#endif
+}
+
+void cmWIXSourceWriter::WriteXMLDeclaration()
+{
+ File << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
+}
+
+void cmWIXSourceWriter::Indent(size_t count)
+{
+ for (size_t i = 0; i < count; ++i) {
+ File << " ";
+ }
+}
+
+std::string cmWIXSourceWriter::EscapeAttributeValue(std::string const& value)
+{
+ std::string result;
+ result.reserve(value.size());
+
+ char c = 0;
+ for (size_t i = 0; i < value.size(); ++i) {
+ c = value[i];
+ switch (c) {
+ case '<':
+ result += "&lt;";
+ break;
+ case '>':
+ result += "&gt;";
+ break;
+ case '&':
+ result += "&amp;";
+ break;
+ case '"':
+ result += "&quot;";
+ break;
+ default:
+ result += c;
+ break;
+ }
+ }
+
+ return result;
+}
diff --git a/Source/CPack/WiX/cmWIXSourceWriter.h b/Source/CPack/WiX/cmWIXSourceWriter.h
new file mode 100644
index 0000000..4efc026
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXSourceWriter.h
@@ -0,0 +1,75 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXSourceWriter_h
+#define cmWIXSourceWriter_h
+
+#include <CPack/cmCPackLog.h>
+
+#include <cmsys/FStream.hxx>
+
+#include <string>
+#include <vector>
+
+/** \class cmWIXSourceWriter
+ * \brief Helper class to generate XML WiX source files
+ */
+class cmWIXSourceWriter
+{
+public:
+ cmWIXSourceWriter(cmCPackLog* logger, std::string const& filename,
+ bool isIncludeFile = false);
+
+ ~cmWIXSourceWriter();
+
+ void BeginElement(std::string const& name);
+
+ void EndElement(std::string const& name);
+
+ void AddTextNode(std::string const& text);
+
+ void AddProcessingInstruction(std::string const& target,
+ std::string const& content);
+
+ void AddAttribute(std::string const& key, std::string const& value);
+
+ void AddAttributeUnlessEmpty(std::string const& key,
+ std::string const& value);
+
+ static std::string CMakeEncodingToUtf8(std::string const& value);
+
+protected:
+ cmCPackLog* Logger;
+
+private:
+ enum State
+ {
+ DEFAULT,
+ BEGIN
+ };
+
+ void WriteXMLDeclaration();
+
+ void Indent(size_t count);
+
+ static std::string EscapeAttributeValue(std::string const& value);
+
+ cmsys::ofstream File;
+
+ State State;
+
+ std::vector<std::string> Elements;
+
+ std::string SourceFilename;
+};
+
+#endif
diff --git a/Source/CPack/bills-comments.txt b/Source/CPack/bills-comments.txt
new file mode 100644
index 0000000..c3b4ee8
--- /dev/null
+++ b/Source/CPack/bills-comments.txt
@@ -0,0 +1,68 @@
+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 controled 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/cmCPack7zGenerator.cxx b/Source/CPack/cmCPack7zGenerator.cxx
new file mode 100644
index 0000000..b01c216
--- /dev/null
+++ b/Source/CPack/cmCPack7zGenerator.cxx
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPack7zGenerator.h"
+
+cmCPack7zGenerator::cmCPack7zGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressNone, "7zip")
+{
+}
+
+cmCPack7zGenerator::~cmCPack7zGenerator()
+{
+}
diff --git a/Source/CPack/cmCPack7zGenerator.h b/Source/CPack/cmCPack7zGenerator.h
new file mode 100644
index 0000000..ddbcc34
--- /dev/null
+++ b/Source/CPack/cmCPack7zGenerator.h
@@ -0,0 +1,36 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPack7zGenerator_h
+#define cmCPack7zGenerator_h
+
+#include "cmCPackArchiveGenerator.h"
+
+/** \class cmCPack7zGenerator
+ * \brief A generator for 7z files
+ */
+class cmCPack7zGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPack7zGenerator, cmCPackArchiveGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPack7zGenerator();
+ ~cmCPack7zGenerator() CM_OVERRIDE;
+
+protected:
+ const char* GetOutputExtension() CM_OVERRIDE { return ".7z"; }
+};
+
+#endif
diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx
new file mode 100644
index 0000000..b1f6864
--- /dev/null
+++ b/Source/CPack/cmCPackArchiveGenerator.cxx
@@ -0,0 +1,273 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackArchiveGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+#include <errno.h>
+
+#include <cm_libarchive.h>
+#include <cmsys/Directory.hxx>
+#include <cmsys/SystemTools.hxx>
+
+cmCPackArchiveGenerator::cmCPackArchiveGenerator(cmArchiveWrite::Compress t,
+ std::string const& format)
+{
+ this->Compress = t;
+ this->ArchiveFormat = format;
+}
+
+cmCPackArchiveGenerator::~cmCPackArchiveGenerator()
+{
+}
+
+int cmCPackArchiveGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1");
+ return this->Superclass::InitializeInternal();
+}
+int cmCPackArchiveGenerator::addOneComponentToArchive(
+ cmArchiveWrite& archive, cmCPackComponent* component)
+{
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ " - packaging component: " << component->Name << std::endl);
+ // Add the files of this component to the archive
+ std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+ localToplevel += "/" + component->Name;
+ std::string dir = cmSystemTools::GetCurrentWorkingDirectory();
+ // Change to local toplevel
+ cmSystemTools::ChangeDirectory(localToplevel);
+ std::string filePrefix;
+ if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
+ filePrefix = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ filePrefix += "/";
+ }
+ const char* installPrefix =
+ this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
+ if (installPrefix && installPrefix[0] == '/' && installPrefix[1] != 0) {
+ // add to file prefix and remove the leading '/'
+ filePrefix += installPrefix + 1;
+ filePrefix += "/";
+ }
+ std::vector<std::string>::const_iterator fileIt;
+ for (fileIt = component->Files.begin(); fileIt != component->Files.end();
+ ++fileIt) {
+ std::string rp = filePrefix + *fileIt;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Adding file: " << rp << std::endl);
+ archive.Add(rp, 0, CM_NULLPTR, false);
+ if (!archive) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "ERROR while packaging files: "
+ << archive.GetError() << std::endl);
+ return 0;
+ }
+ }
+ // Go back to previous dir
+ cmSystemTools::ChangeDirectory(dir);
+ return 1;
+}
+
+/*
+ * The macro will open/create a file 'filename'
+ * an declare and open the associated
+ * cmArchiveWrite 'archive' object.
+ */
+#define DECLARE_AND_OPEN_ARCHIVE(filename, archive) \
+ cmGeneratedFileStream gf; \
+ gf.Open(filename.c_str(), false, true); \
+ if (!GenerateHeader(&gf)) { \
+ cmCPackLogger(cmCPackLog::LOG_ERROR, \
+ "Problem to generate Header for archive < " \
+ << filename << ">." << std::endl); \
+ return 0; \
+ } \
+ cmArchiveWrite archive(gf, this->Compress, this->ArchiveFormat); \
+ if (!archive) { \
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem to create archive < " \
+ << filename << ">. ERROR =" << archive.GetError() \
+ << std::endl); \
+ return 0; \
+ }
+
+int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
+{
+ packageFileNames.clear();
+ // The default behavior is to have one package by component group
+ // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
+ if (!ignoreGroup) {
+ std::map<std::string, cmCPackComponentGroup>::iterator compGIt;
+ for (compGIt = this->ComponentGroups.begin();
+ compGIt != this->ComponentGroups.end(); ++compGIt) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Packaging component group: "
+ << compGIt->first << std::endl);
+ // Begin the archive for this group
+ std::string packageFileName = std::string(toplevel);
+ packageFileName += "/" +
+ GetComponentPackageFileName(this->GetOption("CPACK_PACKAGE_FILE_NAME"),
+ compGIt->first, true) +
+ this->GetOutputExtension();
+ // open a block in order to automatically close archive
+ // at the end of the block
+ {
+ DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
+ // now iterate over the component of this group
+ std::vector<cmCPackComponent*>::iterator compIt;
+ for (compIt = (compGIt->second).Components.begin();
+ compIt != (compGIt->second).Components.end(); ++compIt) {
+ // Add the files of this component to the archive
+ addOneComponentToArchive(archive, *compIt);
+ }
+ }
+ // add the generated package to package file names list
+ packageFileNames.push_back(packageFileName);
+ }
+ // Handle Orphan components (components not belonging to any groups)
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ // Does the component belong to a group?
+ if (compIt->second.Group == CM_NULLPTR) {
+ cmCPackLogger(
+ cmCPackLog::LOG_VERBOSE, "Component <"
+ << compIt->second.Name
+ << "> does not belong to any group, package it separately."
+ << std::endl);
+ std::string localToplevel(
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+ std::string packageFileName = std::string(toplevel);
+
+ localToplevel += "/" + compIt->first;
+ packageFileName += "/" + GetComponentPackageFileName(
+ this->GetOption("CPACK_PACKAGE_FILE_NAME"),
+ compIt->first, false) +
+ this->GetOutputExtension();
+ {
+ DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
+ // Add the files of this component to the archive
+ addOneComponentToArchive(archive, &(compIt->second));
+ }
+ // add the generated package to package file names list
+ packageFileNames.push_back(packageFileName);
+ }
+ }
+ }
+ // CPACK_COMPONENTS_IGNORE_GROUPS is set
+ // We build 1 package per component
+ else {
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+ std::string packageFileName = std::string(toplevel);
+
+ localToplevel += "/" + compIt->first;
+ packageFileName += "/" +
+ GetComponentPackageFileName(this->GetOption("CPACK_PACKAGE_FILE_NAME"),
+ compIt->first, false) +
+ this->GetOutputExtension();
+ {
+ DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
+ // Add the files of this component to the archive
+ addOneComponentToArchive(archive, &(compIt->second));
+ }
+ // add the generated package to package file names list
+ packageFileNames.push_back(packageFileName);
+ }
+ }
+ return 1;
+}
+
+int cmCPackArchiveGenerator::PackageComponentsAllInOne()
+{
+ // reset the package file names
+ packageFileNames.clear();
+ packageFileNames.push_back(std::string(toplevel));
+ packageFileNames[0] += "/" +
+ std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) +
+ this->GetOutputExtension();
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Packaging all groups in one package..."
+ "(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE is set)"
+ << std::endl);
+ DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive);
+
+ // The ALL COMPONENTS in ONE package case
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ // Add the files of this component to the archive
+ addOneComponentToArchive(archive, &(compIt->second));
+ }
+
+ // archive goes out of scope so it will finalized and closed.
+ return 1;
+}
+
+int cmCPackArchiveGenerator::PackageFiles()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl);
+
+ if (WantsComponentInstallation()) {
+ // CASE 1 : COMPONENT ALL-IN-ONE package
+ // If ALL COMPONENTS in ONE package has been requested
+ // then the package file is unique and should be open here.
+ if (componentPackageMethod == ONE_PACKAGE) {
+ return PackageComponentsAllInOne();
+ }
+ // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
+ // There will be 1 package for each component group
+ // however one may require to ignore component group and
+ // in this case you'll get 1 package for each component.
+ else {
+ return PackageComponents(componentPackageMethod ==
+ ONE_PACKAGE_PER_COMPONENT);
+ }
+ }
+
+ // CASE 3 : NON COMPONENT package.
+ DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive);
+ std::vector<std::string>::const_iterator fileIt;
+ std::string dir = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::ChangeDirectory(toplevel);
+ for (fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
+ // Get the relative path to the file
+ std::string rp =
+ cmSystemTools::RelativePath(toplevel.c_str(), fileIt->c_str());
+ archive.Add(rp, 0, CM_NULLPTR, false);
+ if (!archive) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem while adding file< "
+ << *fileIt << "> to archive <" << packageFileNames[0]
+ << "> .ERROR =" << archive.GetError() << std::endl);
+ return 0;
+ }
+ }
+ cmSystemTools::ChangeDirectory(dir);
+ // The destructor of cmArchiveWrite will close and finish the write
+ return 1;
+}
+
+int cmCPackArchiveGenerator::GenerateHeader(std::ostream*)
+{
+ return 1;
+}
+
+bool cmCPackArchiveGenerator::SupportsComponentInstallation() const
+{
+ // The Component installation support should only
+ // be activated if explicitly requested by the user
+ // (for backward compatibility reason)
+ return IsOn("CPACK_ARCHIVE_COMPONENT_INSTALL");
+}
diff --git a/Source/CPack/cmCPackArchiveGenerator.h b/Source/CPack/cmCPackArchiveGenerator.h
new file mode 100644
index 0000000..a018ebd
--- /dev/null
+++ b/Source/CPack/cmCPackArchiveGenerator.h
@@ -0,0 +1,75 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackArchiveGenerator_h
+#define cmCPackArchiveGenerator_h
+
+#include "cmCPackGenerator.h"
+
+#include "cmArchiveWrite.h"
+
+/** \class cmCPackArchiveGenerator
+ * \brief A generator base for libarchive generation.
+ * The generator itself uses the libarchive wrapper
+ * \ref cmArchiveWrite.
+ *
+ */
+class cmCPackArchiveGenerator : public cmCPackGenerator
+{
+public:
+ cmTypeMacro(cmCPackArchiveGenerator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackArchiveGenerator(cmArchiveWrite::Compress, std::string const& format);
+ ~cmCPackArchiveGenerator() CM_OVERRIDE;
+ // Used to add a header to the archive
+ virtual int GenerateHeader(std::ostream* os);
+ // component support
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+
+protected:
+ int InitializeInternal() CM_OVERRIDE;
+ /**
+ * Add the files belonging to the specified component
+ * to the provided (already opened) archive.
+ * @param[in,out] archive the archive object
+ * @param[in] component the component whose file will be added to archive
+ */
+ int addOneComponentToArchive(cmArchiveWrite& archive,
+ cmCPackComponent* component);
+
+ /**
+ * The main package file method.
+ * If component install was required this
+ * method will call either PackageComponents or
+ * PackageComponentsAllInOne.
+ */
+ int PackageFiles() CM_OVERRIDE;
+ /**
+ * The method used to package files when component
+ * install is used. This will create one
+ * archive for each component group.
+ */
+ int PackageComponents(bool ignoreGroup);
+ /**
+ * Special case of component install where all
+ * components will be put in a single installer.
+ */
+ int PackageComponentsAllInOne();
+ const char* GetOutputExtension() CM_OVERRIDE = 0;
+ cmArchiveWrite::Compress Compress;
+ std::string ArchiveFormat;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackBundleGenerator.cxx b/Source/CPack/cmCPackBundleGenerator.cxx
new file mode 100644
index 0000000..9276e3a
--- /dev/null
+++ b/Source/CPack/cmCPackBundleGenerator.cxx
@@ -0,0 +1,292 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackBundleGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmSystemTools.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+cmCPackBundleGenerator::cmCPackBundleGenerator()
+{
+}
+
+cmCPackBundleGenerator::~cmCPackBundleGenerator()
+{
+}
+
+int cmCPackBundleGenerator::InitializeInternal()
+{
+ const char* name = this->GetOption("CPACK_BUNDLE_NAME");
+ if (0 == name) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_BUNDLE_NAME must be set to use the Bundle generator."
+ << std::endl);
+
+ return 0;
+ }
+
+ if (this->GetOption("CPACK_BUNDLE_APPLE_CERT_APP")) {
+ const std::string codesign_path = cmSystemTools::FindProgram(
+ "codesign", std::vector<std::string>(), false);
+
+ if (codesign_path.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot locate codesign command"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_CODESIGN", codesign_path.c_str());
+ }
+
+ return this->Superclass::InitializeInternal();
+}
+
+const char* cmCPackBundleGenerator::GetPackagingInstallPrefix()
+{
+ this->InstallPrefix = "/";
+ this->InstallPrefix += this->GetOption("CPACK_BUNDLE_NAME");
+ this->InstallPrefix += ".app/Contents/Resources";
+
+ return this->InstallPrefix.c_str();
+}
+
+int cmCPackBundleGenerator::ConstructBundle()
+{
+
+ // Get required arguments ...
+ const std::string cpack_bundle_name = this->GetOption("CPACK_BUNDLE_NAME")
+ ? this->GetOption("CPACK_BUNDLE_NAME")
+ : "";
+ if (cpack_bundle_name.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "CPACK_BUNDLE_NAME must be set."
+ << std::endl);
+
+ return 0;
+ }
+
+ const std::string cpack_bundle_plist = this->GetOption("CPACK_BUNDLE_PLIST")
+ ? this->GetOption("CPACK_BUNDLE_PLIST")
+ : "";
+ if (cpack_bundle_plist.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "CPACK_BUNDLE_PLIST must be set."
+ << std::endl);
+
+ return 0;
+ }
+
+ const std::string cpack_bundle_icon = this->GetOption("CPACK_BUNDLE_ICON")
+ ? this->GetOption("CPACK_BUNDLE_ICON")
+ : "";
+ if (cpack_bundle_icon.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "CPACK_BUNDLE_ICON must be set."
+ << std::endl);
+
+ return 0;
+ }
+
+ // Get optional arguments ...
+ const std::string cpack_bundle_startup_command =
+ this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND")
+ ? this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND")
+ : "";
+
+ // The staging directory contains everything that will end-up inside the
+ // final disk image ...
+ std::ostringstream staging;
+ staging << toplevel;
+
+ std::ostringstream contents;
+ contents << staging.str() << "/" << cpack_bundle_name << ".app/"
+ << "Contents";
+
+ std::ostringstream application;
+ application << contents.str() << "/"
+ << "MacOS";
+
+ std::ostringstream resources;
+ resources << contents.str() << "/"
+ << "Resources";
+
+ // Install a required, user-provided bundle metadata file ...
+ std::ostringstream plist_source;
+ plist_source << cpack_bundle_plist;
+
+ std::ostringstream plist_target;
+ plist_target << contents.str() << "/"
+ << "Info.plist";
+
+ if (!this->CopyFile(plist_source, plist_target)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Error copying plist. Check the value of CPACK_BUNDLE_PLIST."
+ << std::endl);
+
+ return 0;
+ }
+
+ // Install a user-provided bundle icon ...
+ std::ostringstream icon_source;
+ icon_source << cpack_bundle_icon;
+
+ std::ostringstream icon_target;
+ icon_target << resources.str() << "/" << cpack_bundle_name << ".icns";
+
+ if (!this->CopyFile(icon_source, icon_target)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Error copying bundle icon. Check the value of CPACK_BUNDLE_ICON."
+ << std::endl);
+
+ return 0;
+ }
+
+ // Optionally a user-provided startup command (could be an
+ // executable or a script) ...
+ if (!cpack_bundle_startup_command.empty()) {
+ std::ostringstream command_source;
+ command_source << cpack_bundle_startup_command;
+
+ std::ostringstream command_target;
+ command_target << application.str() << "/" << cpack_bundle_name;
+
+ if (!this->CopyFile(command_source, command_target)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error copying startup command. "
+ " Check the value of CPACK_BUNDLE_STARTUP_COMMAND."
+ << std::endl);
+
+ return 0;
+ }
+
+ cmSystemTools::SetPermissions(command_target.str().c_str(), 0777);
+ }
+
+ return 1;
+}
+
+int cmCPackBundleGenerator::PackageFiles()
+{
+ if (!this->ConstructBundle()) {
+ return 0;
+ }
+
+ if (!this->SignBundle(toplevel)) {
+ return 0;
+ }
+
+ return this->CreateDMG(toplevel, packageFileNames[0]);
+}
+
+bool cmCPackBundleGenerator::SupportsComponentInstallation() const
+{
+ return false;
+}
+
+int cmCPackBundleGenerator::SignBundle(const std::string& src_dir)
+{
+ const std::string cpack_apple_cert_app =
+ this->GetOption("CPACK_BUNDLE_APPLE_CERT_APP")
+ ? this->GetOption("CPACK_BUNDLE_APPLE_CERT_APP")
+ : "";
+
+ // codesign the application.
+ if (!cpack_apple_cert_app.empty()) {
+ std::string output;
+ std::string bundle_path;
+ bundle_path = src_dir + "/";
+ bundle_path += this->GetOption("CPACK_BUNDLE_NAME");
+ bundle_path += ".app";
+
+ // A list of additional files to sign, ie. frameworks and plugins.
+ const std::string sign_parameter =
+ this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_PARAMETER")
+ ? this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_PARAMETER")
+ : "--deep -f";
+
+ const std::string sign_files =
+ this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_FILES")
+ ? this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_FILES")
+ : "";
+
+ std::vector<std::string> relFiles;
+ cmSystemTools::ExpandListArgument(sign_files, relFiles);
+
+ // sign the files supplied by the user, ie. frameworks.
+ for (std::vector<std::string>::iterator it = relFiles.begin();
+ it != relFiles.end(); ++it) {
+ std::ostringstream temp_sign_file_cmd;
+ temp_sign_file_cmd << this->GetOption("CPACK_COMMAND_CODESIGN");
+ temp_sign_file_cmd << " " << sign_parameter << " -s \""
+ << cpack_apple_cert_app;
+ temp_sign_file_cmd << "\" -i ";
+ temp_sign_file_cmd << this->GetOption("CPACK_APPLE_BUNDLE_ID");
+ temp_sign_file_cmd << " \"";
+ temp_sign_file_cmd << bundle_path;
+ temp_sign_file_cmd << *it << "\"";
+
+ if (!this->RunCommand(temp_sign_file_cmd, &output)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error signing file:" << bundle_path << *it << std::endl
+ << output << std::endl);
+
+ return 0;
+ }
+ }
+
+ // sign main binary
+ std::ostringstream temp_sign_binary_cmd;
+ temp_sign_binary_cmd << this->GetOption("CPACK_COMMAND_CODESIGN");
+ temp_sign_binary_cmd << " " << sign_parameter << " -s \""
+ << cpack_apple_cert_app;
+ temp_sign_binary_cmd << "\" \"" << bundle_path << "\"";
+
+ if (!this->RunCommand(temp_sign_binary_cmd, &output)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error signing the application binary." << std::endl
+ << output
+ << std::endl);
+
+ return 0;
+ }
+
+ // sign app bundle
+ std::ostringstream temp_codesign_cmd;
+ temp_codesign_cmd << this->GetOption("CPACK_COMMAND_CODESIGN");
+ temp_codesign_cmd << " " << sign_parameter << " -s \""
+ << cpack_apple_cert_app << "\"";
+ if (this->GetOption("CPACK_BUNDLE_APPLE_ENTITLEMENTS")) {
+ temp_codesign_cmd << " --entitlements ";
+ temp_codesign_cmd << this->GetOption("CPACK_BUNDLE_APPLE_ENTITLEMENTS");
+ }
+ temp_codesign_cmd << " \"" << bundle_path << "\"";
+
+ if (!this->RunCommand(temp_codesign_cmd, &output)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error signing the application package." << std::endl
+ << output
+ << std::endl);
+
+ return 0;
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Application has been codesigned"
+ << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ (this->GetOption("CPACK_BUNDLE_APPLE_ENTITLEMENTS")
+ ? "with entitlement sandboxing"
+ : "without entitlement sandboxing")
+ << std::endl);
+ }
+
+ return 1;
+}
diff --git a/Source/CPack/cmCPackBundleGenerator.h b/Source/CPack/cmCPackBundleGenerator.h
new file mode 100644
index 0000000..9cb2f0a
--- /dev/null
+++ b/Source/CPack/cmCPackBundleGenerator.h
@@ -0,0 +1,42 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackBundleGenerator_h
+#define cmCPackBundleGenerator_h
+
+#include "cmCPackDragNDropGenerator.h"
+
+/** \class cmCPackBundleGenerator
+ * \brief A generator for OSX bundles
+ *
+ * Based on Gimp.app
+ */
+class cmCPackBundleGenerator : public cmCPackDragNDropGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackBundleGenerator, cmCPackDragNDropGenerator);
+
+ cmCPackBundleGenerator();
+ virtual ~cmCPackBundleGenerator();
+
+protected:
+ virtual int InitializeInternal();
+ virtual const char* GetPackagingInstallPrefix();
+ int ConstructBundle();
+ int SignBundle(const std::string& src_dir);
+ int PackageFiles();
+ bool SupportsComponentInstallation() const;
+
+ std::string InstallPrefix;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackComponentGroup.cxx b/Source/CPack/cmCPackComponentGroup.cxx
new file mode 100644
index 0000000..d262ac9
--- /dev/null
+++ b/Source/CPack/cmCPackComponentGroup.cxx
@@ -0,0 +1,43 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackComponentGroup.h"
+
+#include "cmSystemTools.h"
+
+#include <string>
+#include <vector>
+
+unsigned long cmCPackComponent::GetInstalledSize(
+ const std::string& installDir) const
+{
+ if (this->TotalSize != 0) {
+ return this->TotalSize;
+ }
+
+ std::vector<std::string>::const_iterator fileIt;
+ for (fileIt = this->Files.begin(); fileIt != this->Files.end(); ++fileIt) {
+ std::string path = installDir;
+ path += '/';
+ path += *fileIt;
+ this->TotalSize += cmSystemTools::FileLength(path);
+ }
+
+ return this->TotalSize;
+}
+
+unsigned long cmCPackComponent::GetInstalledSizeInKbytes(
+ const std::string& installDir) const
+{
+ unsigned long result = (GetInstalledSize(installDir) + 512) / 1024;
+ return result ? result : 1;
+}
diff --git a/Source/CPack/cmCPackComponentGroup.h b/Source/CPack/cmCPackComponentGroup.h
new file mode 100644
index 0000000..01a9e76
--- /dev/null
+++ b/Source/CPack/cmCPackComponentGroup.h
@@ -0,0 +1,149 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackComponentGroup_h
+#define cmCPackComponentGroup_h
+
+#include "cmStandardIncludes.h"
+
+class cmCPackComponentGroup;
+
+/** \class cmCPackInstallationType
+ * \brief A certain type of installation, which encompasses a
+ * set of components.
+ */
+class cmCPackInstallationType
+{
+public:
+ /// The name of the installation type (used to reference this
+ /// installation type).
+ std::string Name;
+
+ /// The name of the installation type as displayed to the user.
+ std::string DisplayName;
+
+ /// The index number of the installation type. This is an arbitrary
+ /// numbering from 1 to the number of installation types.
+ unsigned Index;
+};
+
+/** \class cmCPackComponent
+ * \brief A single component to be installed by CPack.
+ */
+class cmCPackComponent
+{
+public:
+ cmCPackComponent()
+ : Group(CM_NULLPTR)
+ , IsRequired(true)
+ , IsHidden(false)
+ , IsDisabledByDefault(false)
+ , IsDownloaded(false)
+ , TotalSize(0)
+ {
+ }
+
+ /// The name of the component (used to reference the component).
+ std::string Name;
+
+ /// The name of the component as displayed to the user.
+ std::string DisplayName;
+
+ /// The component group that contains this component (if any).
+ cmCPackComponentGroup* Group;
+
+ /// Whether this component group must always be installed.
+ bool IsRequired : 1;
+
+ /// Whether this component group is hidden. A hidden component group
+ /// is always installed. However, it may still be shown to the user.
+ bool IsHidden : 1;
+
+ /// Whether this component defaults to "disabled".
+ bool IsDisabledByDefault : 1;
+
+ /// Whether this component should be downloaded on-the-fly. If false,
+ /// the component will be a part of the installation package.
+ bool IsDownloaded : 1;
+
+ /// A description of this component.
+ std::string Description;
+
+ /// The installation types that this component is a part of.
+ std::vector<cmCPackInstallationType*> InstallationTypes;
+
+ /// If IsDownloaded is true, the name of the archive file that
+ /// contains the files that are part of this component.
+ std::string ArchiveFile;
+
+ /// The components that this component depends on.
+ std::vector<cmCPackComponent*> Dependencies;
+
+ /// The components that depend on this component.
+ std::vector<cmCPackComponent*> ReverseDependencies;
+
+ /// The list of installed files that are part of this component.
+ std::vector<std::string> Files;
+
+ /// The list of installed directories that are part of this component.
+ std::vector<std::string> Directories;
+
+ /// Get the total installed size of all of the files in this
+ /// component, in bytes. installDir is the directory into which the
+ /// component was installed.
+ unsigned long GetInstalledSize(const std::string& installDir) const;
+
+ /// Identical to GetInstalledSize, but returns the result in
+ /// kilobytes.
+ unsigned long GetInstalledSizeInKbytes(const std::string& installDir) const;
+
+private:
+ mutable unsigned long TotalSize;
+};
+
+/** \class cmCPackComponentGroup
+ * \brief A component group to be installed by CPack.
+ */
+class cmCPackComponentGroup
+{
+public:
+ cmCPackComponentGroup()
+ : ParentGroup(CM_NULLPTR)
+ {
+ }
+
+ /// The name of the group (used to reference the group).
+ std::string Name;
+
+ /// The name of the component as displayed to the user.
+ std::string DisplayName;
+
+ /// The description of this component group.
+ std::string Description;
+
+ /// Whether the name of the component will be shown in bold.
+ bool IsBold : 1;
+
+ /// Whether the section should be expanded by default
+ bool IsExpandedByDefault : 1;
+
+ /// The components within this group.
+ std::vector<cmCPackComponent*> Components;
+
+ /// The parent group of this component group (if any).
+ cmCPackComponentGroup* ParentGroup;
+
+ /// The subgroups of this group.
+ std::vector<cmCPackComponentGroup*> Subgroups;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackConfigure.h.in b/Source/CPack/cmCPackConfigure.h.in
new file mode 100644
index 0000000..3d7702e
--- /dev/null
+++ b/Source/CPack/cmCPackConfigure.h.in
@@ -0,0 +1,11 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
diff --git a/Source/CPack/cmCPackCygwinBinaryGenerator.cxx b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
new file mode 100644
index 0000000..83af89e
--- /dev/null
+++ b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
@@ -0,0 +1,84 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackCygwinBinaryGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cmsys/SystemTools.hxx>
+
+cmCPackCygwinBinaryGenerator::cmCPackCygwinBinaryGenerator()
+{
+}
+
+cmCPackCygwinBinaryGenerator::~cmCPackCygwinBinaryGenerator()
+{
+}
+
+int cmCPackCygwinBinaryGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
+ this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "0");
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackCygwinBinaryGenerator::PackageFiles()
+{
+ std::string packageName = this->GetOption("CPACK_PACKAGE_NAME");
+ packageName += "-";
+ packageName += this->GetOption("CPACK_PACKAGE_VERSION");
+ packageName = cmsys::SystemTools::LowerCase(packageName);
+ std::string manifest = "/usr/share/doc/";
+ manifest += packageName;
+ manifest += "/MANIFEST";
+ std::string manifestFile = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ // Create a MANIFEST file that contains all of the files in
+ // the tar file
+ std::string tempdir = manifestFile;
+ manifestFile += manifest;
+ // create an extra scope to force the stream
+ // 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) {
+ // remove the temp dir and replace with /usr
+ ofs << (*i).substr(tempdir.size()) << "\n";
+ }
+ ofs << manifest << "\n";
+ }
+ // add the manifest file to the list of all files
+ files.push_back(manifestFile);
+
+ // create the bzip2 tar file
+ return this->Superclass::PackageFiles();
+}
+
+const char* cmCPackCygwinBinaryGenerator::GetOutputExtension()
+{
+ this->OutputExtension = "-";
+ const char* patchNumber = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
+ if (!patchNumber) {
+ patchNumber = "1";
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "CPACK_CYGWIN_PATCH_NUMBER not specified using 1"
+ << std::endl);
+ }
+ this->OutputExtension += patchNumber;
+ this->OutputExtension += ".tar.bz2";
+ return this->OutputExtension.c_str();
+}
diff --git a/Source/CPack/cmCPackCygwinBinaryGenerator.h b/Source/CPack/cmCPackCygwinBinaryGenerator.h
new file mode 100644
index 0000000..8de4bae
--- /dev/null
+++ b/Source/CPack/cmCPackCygwinBinaryGenerator.h
@@ -0,0 +1,39 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackCygwinBinaryGenerator_h
+#define cmCPackCygwinBinaryGenerator_h
+
+#include "cmCPackTarBZip2Generator.h"
+
+/** \class cmCPackCygwinBinaryGenerator
+ * \brief A generator for TarBZip2 files
+ */
+class cmCPackCygwinBinaryGenerator : public cmCPackTarBZip2Generator
+{
+public:
+ cmCPackTypeMacro(cmCPackCygwinBinaryGenerator, cmCPackTarBZip2Generator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackCygwinBinaryGenerator();
+ virtual ~cmCPackCygwinBinaryGenerator();
+
+protected:
+ virtual int InitializeInternal();
+ int PackageFiles();
+ virtual const char* GetOutputExtension();
+ std::string OutputExtension;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackCygwinSourceGenerator.cxx b/Source/CPack/cmCPackCygwinSourceGenerator.cxx
new file mode 100644
index 0000000..5fcfaf4
--- /dev/null
+++ b/Source/CPack/cmCPackCygwinSourceGenerator.cxx
@@ -0,0 +1,167 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackCygwinSourceGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cmsys/SystemTools.hxx>
+
+// Includes needed for implementation of RenameFile. This is not in
+// system tools because it is not implemented robustly enough to move
+// files across directories.
+#ifdef _WIN32
+#include <sys/stat.h>
+#include <windows.h>
+#endif
+
+cmCPackCygwinSourceGenerator::cmCPackCygwinSourceGenerator()
+{
+}
+
+cmCPackCygwinSourceGenerator::~cmCPackCygwinSourceGenerator()
+{
+}
+
+int cmCPackCygwinSourceGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "0");
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackCygwinSourceGenerator::PackageFiles()
+{
+ // Create a tar file of the sources
+ std::string packageDirFileName =
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ packageDirFileName += ".tar.bz2";
+ packageFileNames[0] = packageDirFileName;
+ std::string output;
+ // skip one parent up to the cmCPackTarBZip2Generator
+ // to create tar.bz2 file with the list of source
+ // files
+ this->Compress = cmArchiveWrite::CompressBZip2;
+ if (!this->cmCPackTarBZip2Generator::PackageFiles()) {
+ return 0;
+ }
+ // Now create a tar file that contains the above .tar.bz2 file
+ // and the CPACK_CYGWIN_PATCH_FILE and CPACK_TOPLEVEL_DIRECTORY
+ // files
+ std::string compressOutFile = packageDirFileName;
+ // at this point compressOutFile is the full path to
+ // _CPack_Package/.../package-2.5.0.tar.bz2
+ // we want to create a tar _CPack_Package/.../package-2.5.0-1-src.tar.bz2
+ // with these
+ // _CPack_Package/.../package-2.5.0-1.patch
+ // _CPack_Package/.../package-2.5.0-1.sh
+ // _CPack_Package/.../package-2.5.0.tar.bz2
+ // the -1 is CPACK_CYGWIN_PATCH_NUMBER
+
+ // first copy the patch file and the .sh file
+ // to the toplevel cpack temp dir
+
+ // copy the patch file into place
+ if (!this->GetOption("CPACK_CYGWIN_PATCH_FILE")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "No patch file specified for cygwin sources.");
+ return 0;
+ }
+ if (!cmSystemTools::CopyFileAlways(
+ this->GetOption("CPACK_CYGWIN_PATCH_FILE"),
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY"))) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "problem copying: ["
+ << this->GetOption("CPACK_CYGWIN_PATCH_FILE") << "]\nto\n["
+ << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "]\n");
+ return 0;
+ }
+ if (!this->GetOption("CPACK_CYGWIN_BUILD_SCRIPT")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "No build script specified for cygwin sources.");
+ return 0;
+ }
+ // copy the build script into place
+ if (!cmSystemTools::CopyFileAlways(
+ this->GetOption("CPACK_CYGWIN_BUILD_SCRIPT"),
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY"))) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "problem copying: "
+ << this->GetOption("CPACK_CYGWIN_BUILD_SCRIPT") << "\nto\n"
+ << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "]\n");
+ return 0;
+ }
+ std::string outerTarFile = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ outerTarFile += "-";
+ const char* patch = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
+ if (!patch) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING, "CPACK_CYGWIN_PATCH_NUMBER"
+ << " not specified, defaulting to 1\n");
+ patch = "1";
+ }
+ outerTarFile += patch;
+ outerTarFile += "-src.tar.bz2";
+ std::string tmpDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ std::string buildScript = tmpDir;
+ buildScript += "/";
+ buildScript += cmSystemTools::GetFilenameName(
+ this->GetOption("CPACK_CYGWIN_BUILD_SCRIPT"));
+ std::string patchFile = tmpDir;
+ patchFile += "/";
+ patchFile +=
+ cmSystemTools::GetFilenameName(this->GetOption("CPACK_CYGWIN_PATCH_FILE"));
+
+ std::string file = cmSystemTools::GetFilenameName(compressOutFile);
+ std::string sourceTar = cmSystemTools::GetFilenamePath(compressOutFile);
+ sourceTar += "/";
+ sourceTar += file;
+ /* reset list of file to be packaged */
+ files.clear();
+ // a source release in cygwin should have the build script used
+ // to build the package, the patch file that is different from the
+ // regular upstream version of the sources, and a bziped tar file
+ // of the original sources
+ files.push_back(buildScript);
+ files.push_back(patchFile);
+ files.push_back(sourceTar);
+ /* update the name of the produced package */
+ packageFileNames[0] = outerTarFile;
+ /* update the toplevel dir */
+ toplevel = tmpDir;
+ if (!this->cmCPackTarBZip2Generator::PackageFiles()) {
+ return 0;
+ }
+ return 1;
+}
+
+const char* cmCPackCygwinSourceGenerator::GetPackagingInstallPrefix()
+{
+ this->InstallPrefix = "/";
+ this->InstallPrefix += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ return this->InstallPrefix.c_str();
+}
+
+const char* cmCPackCygwinSourceGenerator::GetOutputExtension()
+{
+ this->OutputExtension = "-";
+ const char* patch = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
+ if (!patch) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING, "CPACK_CYGWIN_PATCH_NUMBER"
+ << " not specified, defaulting to 1\n");
+ patch = "1";
+ }
+ this->OutputExtension += patch;
+ this->OutputExtension += "-src.tar.bz2";
+ return this->OutputExtension.c_str();
+}
diff --git a/Source/CPack/cmCPackCygwinSourceGenerator.h b/Source/CPack/cmCPackCygwinSourceGenerator.h
new file mode 100644
index 0000000..4aba8b9
--- /dev/null
+++ b/Source/CPack/cmCPackCygwinSourceGenerator.h
@@ -0,0 +1,41 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackCygwinSourceGenerator_h
+#define cmCPackCygwinSourceGenerator_h
+
+#include "cmCPackTarBZip2Generator.h"
+
+/** \class cmCPackCygwinSourceGenerator
+ * \brief A generator for cygwin source files
+ */
+class cmCPackCygwinSourceGenerator : public cmCPackTarBZip2Generator
+{
+public:
+ cmCPackTypeMacro(cmCPackCygwinSourceGenerator, cmCPackTarBZip2Generator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackCygwinSourceGenerator();
+ virtual ~cmCPackCygwinSourceGenerator();
+
+protected:
+ const char* GetPackagingInstallPrefix();
+ virtual int InitializeInternal();
+ int PackageFiles();
+ virtual const char* GetOutputExtension();
+ std::string InstallPrefix;
+ std::string OutputExtension;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx
new file mode 100644
index 0000000..3edc430
--- /dev/null
+++ b/Source/CPack/cmCPackDebGenerator.cxx
@@ -0,0 +1,952 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackDebGenerator.h"
+
+#include "cmArchiveWrite.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include <cmsys/Glob.hxx>
+#include <cmsys/SystemTools.hxx>
+
+#include <limits.h> // USHRT_MAX
+#include <sys/stat.h>
+
+// NOTE:
+// A debian package .deb is simply an 'ar' archive. The only subtle difference
+// is that debian uses the BSD ar style archive whereas most Linux distro have
+// a GNU ar.
+// See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=161593 for more info
+// Therefore we provide our own implementation of a BSD-ar:
+static int ar_append(const char* archive,
+ const std::vector<std::string>& files);
+
+cmCPackDebGenerator::cmCPackDebGenerator()
+{
+}
+
+cmCPackDebGenerator::~cmCPackDebGenerator()
+{
+}
+
+int cmCPackDebGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
+ if (cmSystemTools::IsOff(this->GetOption("CPACK_SET_DESTDIR"))) {
+ this->SetOption("CPACK_SET_DESTDIR", "I_ON");
+ }
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
+ std::string const& packageName)
+{
+ int retval = 1;
+ // Begin the archive for this pack
+ std::string localToplevel(initialTopLevel);
+ std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel));
+ std::string outputFileName(
+ std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) + "-" +
+ packageName + this->GetOutputExtension());
+
+ localToplevel += "/" + packageName;
+ /* replace the TEMP DIRECTORY with the component one */
+ this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
+ packageFileName += "/" + outputFileName;
+ /* replace proposed CPACK_OUTPUT_FILE_NAME */
+ this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
+ /* replace the TEMPORARY package file name */
+ this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
+ packageFileName.c_str());
+ // Tell CPackDeb.cmake the name of the component GROUP.
+ this->SetOption("CPACK_DEB_PACKAGE_COMPONENT", packageName.c_str());
+ // Tell CPackDeb.cmake the path where the component is.
+ std::string component_path = "/";
+ component_path += packageName;
+ this->SetOption("CPACK_DEB_PACKAGE_COMPONENT_PART_PATH",
+ component_path.c_str());
+ if (!this->ReadListFile("CPackDeb.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while execution CPackDeb.cmake"
+ << std::endl);
+ retval = 0;
+ return retval;
+ }
+
+ cmsys::Glob gl;
+ std::string findExpr(this->GetOption("GEN_WDIR"));
+ findExpr += "/*";
+ gl.RecurseOn();
+ gl.SetRecurseListDirs(true);
+ if (!gl.FindFiles(findExpr)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find any files in the installed directory"
+ << std::endl);
+ return 0;
+ }
+ packageFiles = gl.GetFiles();
+
+ int res = createDeb();
+ if (res != 1) {
+ retval = 0;
+ }
+ // add the generated package to package file names list
+ packageFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ packageFileName += "/";
+ packageFileName += this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME");
+ packageFileNames.push_back(packageFileName);
+ return retval;
+}
+
+int cmCPackDebGenerator::PackageComponents(bool ignoreGroup)
+{
+ int retval = 1;
+ /* Reset package file name list it will be populated during the
+ * component packaging run*/
+ packageFileNames.clear();
+ std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+
+ // The default behavior is to have one package by component group
+ // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
+ if (!ignoreGroup) {
+ std::map<std::string, cmCPackComponentGroup>::iterator compGIt;
+ for (compGIt = this->ComponentGroups.begin();
+ compGIt != this->ComponentGroups.end(); ++compGIt) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Packaging component group: "
+ << compGIt->first << std::endl);
+ // Begin the archive for this group
+ retval &= PackageOnePack(initialTopLevel, compGIt->first);
+ }
+ // Handle Orphan components (components not belonging to any groups)
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ // Does the component belong to a group?
+ if (compIt->second.Group == CM_NULLPTR) {
+ cmCPackLogger(
+ cmCPackLog::LOG_VERBOSE, "Component <"
+ << compIt->second.Name
+ << "> does not belong to any group, package it separately."
+ << std::endl);
+ // Begin the archive for this orphan component
+ retval &= PackageOnePack(initialTopLevel, compIt->first);
+ }
+ }
+ }
+ // CPACK_COMPONENTS_IGNORE_GROUPS is set
+ // We build 1 package per component
+ else {
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ retval &= PackageOnePack(initialTopLevel, compIt->first);
+ }
+ }
+ return retval;
+}
+
+//----------------------------------------------------------------------
+int cmCPackDebGenerator::PackageComponentsAllInOne(
+ const std::string& compInstDirName)
+{
+ int retval = 1;
+ /* Reset package file name list it will be populated during the
+ * component packaging run*/
+ packageFileNames.clear();
+ std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Packaging all groups in one package..."
+ "(CPACK_COMPONENTS_ALL_[GROUPS_]IN_ONE_PACKAGE is set)"
+ << std::endl);
+
+ // The ALL GROUPS in ONE package case
+ std::string localToplevel(initialTopLevel);
+ std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel));
+ std::string outputFileName(
+ std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) +
+ this->GetOutputExtension());
+ // all GROUP in one vs all COMPONENT in one
+ localToplevel += "/" + compInstDirName;
+
+ /* replace the TEMP DIRECTORY with the component one */
+ this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
+ packageFileName += "/" + outputFileName;
+ /* replace proposed CPACK_OUTPUT_FILE_NAME */
+ this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
+ /* replace the TEMPORARY package file name */
+ this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
+ packageFileName.c_str());
+
+ if (!compInstDirName.empty()) {
+ // Tell CPackDeb.cmake the path where the component is.
+ std::string component_path = "/";
+ component_path += compInstDirName;
+ this->SetOption("CPACK_DEB_PACKAGE_COMPONENT_PART_PATH",
+ component_path.c_str());
+ }
+ if (!this->ReadListFile("CPackDeb.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while execution CPackDeb.cmake"
+ << std::endl);
+ retval = 0;
+ return retval;
+ }
+
+ cmsys::Glob gl;
+ std::string findExpr(this->GetOption("GEN_WDIR"));
+ findExpr += "/*";
+ gl.RecurseOn();
+ gl.SetRecurseListDirs(true);
+ if (!gl.FindFiles(findExpr)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find any files in the installed directory"
+ << std::endl);
+ return 0;
+ }
+ packageFiles = gl.GetFiles();
+
+ int res = createDeb();
+ if (res != 1) {
+ retval = 0;
+ }
+ // add the generated package to package file names list
+ packageFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ packageFileName += "/";
+ packageFileName += this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME");
+ packageFileNames.push_back(packageFileName);
+ return retval;
+}
+
+int cmCPackDebGenerator::PackageFiles()
+{
+ /* Are we in the component packaging case */
+ if (WantsComponentInstallation()) {
+ // CASE 1 : COMPONENT ALL-IN-ONE package
+ // If ALL GROUPS or ALL COMPONENTS in ONE package has been requested
+ // then the package file is unique and should be open here.
+ if (componentPackageMethod == ONE_PACKAGE) {
+ return PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE");
+ }
+ // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
+ // There will be 1 package for each component group
+ // however one may require to ignore component group and
+ // in this case you'll get 1 package for each component.
+ else {
+ return PackageComponents(componentPackageMethod ==
+ ONE_PACKAGE_PER_COMPONENT);
+ }
+ }
+ // CASE 3 : NON COMPONENT package.
+ else {
+ return PackageComponentsAllInOne("");
+ }
+}
+
+int cmCPackDebGenerator::createDeb()
+{
+ // debian-binary file
+ const std::string strGenWDIR(this->GetOption("GEN_WDIR"));
+ const std::string dbfilename = strGenWDIR + "/debian-binary";
+ { // the scope is needed for cmGeneratedFileStream
+ cmGeneratedFileStream out(dbfilename.c_str());
+ out << "2.0";
+ out << std::endl; // required for valid debian package
+ }
+
+ // control file
+ std::string ctlfilename = strGenWDIR + "/control";
+
+ // debian policy enforce lower case for package name
+ // mandatory entries:
+ std::string debian_pkg_name = cmsys::SystemTools::LowerCase(
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME"));
+ const char* debian_pkg_version =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_VERSION");
+ const char* debian_pkg_section =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SECTION");
+ const char* debian_pkg_priority =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PRIORITY");
+ const char* debian_pkg_arch =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
+ const char* maintainer =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
+ const char* desc = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DESCRIPTION");
+
+ // optional entries
+ const char* debian_pkg_dep =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DEPENDS");
+ const char* debian_pkg_rec =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_RECOMMENDS");
+ const char* debian_pkg_sug =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SUGGESTS");
+ const char* debian_pkg_url =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_HOMEPAGE");
+ const char* debian_pkg_predep =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PREDEPENDS");
+ const char* debian_pkg_enhances =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ENHANCES");
+ const char* debian_pkg_breaks =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_BREAKS");
+ const char* debian_pkg_conflicts =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONFLICTS");
+ const char* debian_pkg_provides =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PROVIDES");
+ const char* debian_pkg_replaces =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_REPLACES");
+ const char* debian_pkg_source =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE");
+
+ { // the scope is needed for cmGeneratedFileStream
+ cmGeneratedFileStream out(ctlfilename.c_str());
+ out << "Package: " << debian_pkg_name << "\n";
+ out << "Version: " << debian_pkg_version << "\n";
+ out << "Section: " << debian_pkg_section << "\n";
+ out << "Priority: " << debian_pkg_priority << "\n";
+ out << "Architecture: " << debian_pkg_arch << "\n";
+ if (debian_pkg_source && *debian_pkg_source) {
+ out << "Source: " << debian_pkg_source << "\n";
+ }
+ if (debian_pkg_dep && *debian_pkg_dep) {
+ out << "Depends: " << debian_pkg_dep << "\n";
+ }
+ if (debian_pkg_rec && *debian_pkg_rec) {
+ out << "Recommends: " << debian_pkg_rec << "\n";
+ }
+ if (debian_pkg_sug && *debian_pkg_sug) {
+ out << "Suggests: " << debian_pkg_sug << "\n";
+ }
+ if (debian_pkg_url && *debian_pkg_url) {
+ out << "Homepage: " << debian_pkg_url << "\n";
+ }
+ if (debian_pkg_predep && *debian_pkg_predep) {
+ out << "Pre-Depends: " << debian_pkg_predep << "\n";
+ }
+ if (debian_pkg_enhances && *debian_pkg_enhances) {
+ out << "Enhances: " << debian_pkg_enhances << "\n";
+ }
+ if (debian_pkg_breaks && *debian_pkg_breaks) {
+ out << "Breaks: " << debian_pkg_breaks << "\n";
+ }
+ if (debian_pkg_conflicts && *debian_pkg_conflicts) {
+ out << "Conflicts: " << debian_pkg_conflicts << "\n";
+ }
+ if (debian_pkg_provides && *debian_pkg_provides) {
+ out << "Provides: " << debian_pkg_provides << "\n";
+ }
+ if (debian_pkg_replaces && *debian_pkg_replaces) {
+ out << "Replaces: " << debian_pkg_replaces << "\n";
+ }
+ unsigned long totalSize = 0;
+ {
+ std::string dirName = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ dirName += '/';
+ for (std::vector<std::string>::const_iterator fileIt =
+ packageFiles.begin();
+ fileIt != packageFiles.end(); ++fileIt) {
+ totalSize += cmSystemTools::FileLength(*fileIt);
+ }
+ }
+ out << "Installed-Size: " << (totalSize + 1023) / 1024 << "\n";
+ out << "Maintainer: " << maintainer << "\n";
+ out << "Description: " << desc << "\n";
+ out << std::endl;
+ }
+
+ const std::string shlibsfilename = strGenWDIR + "/shlibs";
+
+ const char* debian_pkg_shlibs =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SHLIBS");
+ const bool gen_shibs = this->IsOn("CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS") &&
+ debian_pkg_shlibs && *debian_pkg_shlibs;
+ if (gen_shibs) {
+ cmGeneratedFileStream out(shlibsfilename.c_str());
+ out << debian_pkg_shlibs;
+ out << std::endl;
+ }
+
+ const std::string postinst = strGenWDIR + "/postinst";
+ const std::string postrm = strGenWDIR + "/postrm";
+ if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST")) {
+ cmGeneratedFileStream out(postinst.c_str());
+ out << "#!/bin/sh\n\n"
+ "set -e\n\n"
+ "if [ \"$1\" = \"configure\" ]; then\n"
+ "\tldconfig\n"
+ "fi\n";
+ }
+ if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM")) {
+ cmGeneratedFileStream out(postrm.c_str());
+ out << "#!/bin/sh\n\n"
+ "set -e\n\n"
+ "if [ \"$1\" = \"remove\" ]; then\n"
+ "\tldconfig\n"
+ "fi\n";
+ }
+
+ cmArchiveWrite::Compress tar_compression_type = cmArchiveWrite::CompressGZip;
+ const char* debian_compression_type =
+ this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE");
+ if (!debian_compression_type) {
+ debian_compression_type = "gzip";
+ }
+
+ std::string compression_suffix;
+ if (!strcmp(debian_compression_type, "lzma")) {
+ compression_suffix = ".lzma";
+ tar_compression_type = cmArchiveWrite::CompressLZMA;
+ } else if (!strcmp(debian_compression_type, "xz")) {
+ compression_suffix = ".xz";
+ tar_compression_type = cmArchiveWrite::CompressXZ;
+ } else if (!strcmp(debian_compression_type, "bzip2")) {
+ compression_suffix = ".bz2";
+ tar_compression_type = cmArchiveWrite::CompressBZip2;
+ } else if (!strcmp(debian_compression_type, "gzip")) {
+ compression_suffix = ".gz";
+ tar_compression_type = cmArchiveWrite::CompressGZip;
+ } else if (!strcmp(debian_compression_type, "none")) {
+ compression_suffix = "";
+ tar_compression_type = cmArchiveWrite::CompressNone;
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error unrecognized compression type: "
+ << debian_compression_type << std::endl);
+ }
+
+ std::string filename_data_tar =
+ strGenWDIR + "/data.tar" + compression_suffix;
+
+ // atomic file generation for data.tar
+ {
+ cmGeneratedFileStream fileStream_data_tar;
+ fileStream_data_tar.Open(filename_data_tar.c_str(), false, true);
+ if (!fileStream_data_tar) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error opening the file \""
+ << filename_data_tar << "\" for writing" << std::endl);
+ return 0;
+ }
+ cmArchiveWrite data_tar(fileStream_data_tar, tar_compression_type, "paxr");
+
+ // uid/gid should be the one of the root user, and this root user has
+ // always uid/gid equal to 0.
+ data_tar.SetUIDAndGID(0u, 0u);
+ data_tar.SetUNAMEAndGNAME("root", "root");
+
+ // now add all directories which have to be compressed
+ // collect all top level install dirs for that
+ // e.g. /opt/bin/foo, /usr/bin/bar and /usr/bin/baz would
+ // give /usr and /opt
+ size_t topLevelLength = strGenWDIR.length();
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "WDIR: \""
+ << strGenWDIR << "\", length = " << topLevelLength
+ << std::endl);
+ std::set<std::string> orderedFiles;
+
+ // we have to reconstruct the parent folders as well
+
+ for (std::vector<std::string>::const_iterator fileIt =
+ packageFiles.begin();
+ fileIt != packageFiles.end(); ++fileIt) {
+ std::string currentPath = *fileIt;
+ while (currentPath != strGenWDIR) {
+ // the last one IS strGenWDIR, but we do not want this one:
+ // XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application
+ // should not add XXX/application
+ orderedFiles.insert(currentPath);
+ currentPath = cmSystemTools::CollapseCombinedPath(currentPath, "..");
+ }
+ }
+
+ for (std::set<std::string>::const_iterator fileIt = orderedFiles.begin();
+ fileIt != orderedFiles.end(); ++fileIt) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "FILEIT: \"" << *fileIt << "\""
+ << std::endl);
+ std::string::size_type slashPos = fileIt->find('/', topLevelLength + 1);
+ std::string relativeDir =
+ fileIt->substr(topLevelLength, slashPos - topLevelLength);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "RELATIVEDIR: \""
+ << relativeDir << "\"" << std::endl);
+
+ // do not recurse because the loop will do it
+ if (!data_tar.Add(*fileIt, topLevelLength, ".", false)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem adding file to tar:"
+ << std::endl
+ << "#top level directory: " << strGenWDIR << std::endl
+ << "#file: " << *fileIt << std::endl
+ << "#error:" << data_tar.GetError() << std::endl);
+ return 0;
+ }
+ }
+ } // scope for file generation
+
+ std::string md5filename = strGenWDIR + "/md5sums";
+ {
+ // the scope is needed for cmGeneratedFileStream
+ cmGeneratedFileStream out(md5filename.c_str());
+
+ std::string topLevelWithTrailingSlash =
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ topLevelWithTrailingSlash += '/';
+ for (std::vector<std::string>::const_iterator fileIt =
+ packageFiles.begin();
+ fileIt != packageFiles.end(); ++fileIt) {
+ // hash only regular files
+ if (cmSystemTools::FileIsDirectory(*fileIt) ||
+ cmSystemTools::FileIsSymlink(*fileIt)) {
+ continue;
+ }
+
+ char md5sum[33];
+ if (!cmSystemTools::ComputeFileMD5(*fileIt, md5sum)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem computing the md5 of "
+ << *fileIt << std::endl);
+ }
+
+ md5sum[32] = 0;
+
+ std::string output(md5sum);
+ output += " " + *fileIt + "\n";
+ // debian md5sums entries are like this:
+ // 014f3604694729f3bf19263bac599765 usr/bin/ccmake
+ // thus strip the full path (with the trailing slash)
+ cmSystemTools::ReplaceString(output, topLevelWithTrailingSlash.c_str(),
+ "");
+ out << output;
+ }
+ // each line contains a eol.
+ // Do not end the md5sum file with yet another (invalid)
+ }
+
+ std::string filename_control_tar = strGenWDIR + "/control.tar.gz";
+ // atomic file generation for control.tar
+ {
+ cmGeneratedFileStream fileStream_control_tar;
+ fileStream_control_tar.Open(filename_control_tar.c_str(), false, true);
+ if (!fileStream_control_tar) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error opening the file \""
+ << filename_control_tar << "\" for writing"
+ << std::endl);
+ return 0;
+ }
+ cmArchiveWrite control_tar(fileStream_control_tar,
+ cmArchiveWrite::CompressGZip, "paxr");
+
+ // sets permissions and uid/gid for the files
+ control_tar.SetUIDAndGID(0u, 0u);
+ control_tar.SetUNAMEAndGNAME("root", "root");
+
+ /* permissions are set according to
+ https://www.debian.org/doc/debian-policy/ch-files.html#s-permissions-owners
+ and
+ https://lintian.debian.org/tags/control-file-has-bad-permissions.html
+ */
+ const mode_t permission644 = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ const mode_t permissionExecute = S_IXUSR | S_IXGRP | S_IXOTH;
+ const mode_t permission755 = permission644 | permissionExecute;
+
+ // for md5sum and control (that we have generated here), we use 644
+ // (RW-R--R--)
+ // so that deb lintian doesn't warn about it
+ control_tar.SetPermissions(permission644);
+
+ // adds control and md5sums
+ if (!control_tar.Add(md5filename, strGenWDIR.length(), ".") ||
+ !control_tar.Add(strGenWDIR + "/control", strGenWDIR.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << strGenWDIR << std::endl
+ << "#file: \"control\" or \"md5sums\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return 0;
+ }
+
+ // adds generated shlibs file
+ if (gen_shibs) {
+ if (!control_tar.Add(shlibsfilename, strGenWDIR.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << strGenWDIR << std::endl
+ << "#file: \"shlibs\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return 0;
+ }
+ }
+
+ // adds LDCONFIG related files
+ if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST")) {
+ control_tar.SetPermissions(permission755);
+ if (!control_tar.Add(postinst, strGenWDIR.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << strGenWDIR << std::endl
+ << "#file: \"postinst\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return 0;
+ }
+ control_tar.SetPermissions(permission644);
+ }
+
+ if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM")) {
+ control_tar.SetPermissions(permission755);
+ if (!control_tar.Add(postrm, strGenWDIR.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << strGenWDIR << std::endl
+ << "#file: \"postinst\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return 0;
+ }
+ control_tar.SetPermissions(permission644);
+ }
+
+ // for the other files, we use
+ // -either the original permission on the files
+ // -either a permission strictly defined by the Debian policies
+ const char* controlExtra =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA");
+ if (controlExtra) {
+ // permissions are now controlled by the original file permissions
+
+ const bool permissionStrictPolicy =
+ this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION");
+
+ static const char* strictFiles[] = { "config", "postinst", "postrm",
+ "preinst", "prerm" };
+ std::set<std::string> setStrictFiles(
+ strictFiles,
+ strictFiles + sizeof(strictFiles) / sizeof(strictFiles[0]));
+
+ // default
+ control_tar.ClearPermissions();
+
+ std::vector<std::string> controlExtraList;
+ cmSystemTools::ExpandListArgument(controlExtra, controlExtraList);
+ for (std::vector<std::string>::iterator i = controlExtraList.begin();
+ i != controlExtraList.end(); ++i) {
+ std::string filenamename = cmsys::SystemTools::GetFilenameName(*i);
+ std::string localcopy = strGenWDIR + "/" + filenamename;
+
+ if (permissionStrictPolicy) {
+ control_tar.SetPermissions(setStrictFiles.count(filenamename)
+ ? permission755
+ : permission644);
+ }
+
+ // if we can copy the file, it means it does exist, let's add it:
+ if (cmsys::SystemTools::CopyFileIfDifferent(*i, localcopy)) {
+ control_tar.Add(localcopy, strGenWDIR.length(), ".");
+ }
+ }
+ }
+ }
+
+ // ar -r your-package-name.deb debian-binary control.tar.* data.tar.*
+ // since debian packages require BSD ar (most Linux distros and even
+ // FreeBSD and NetBSD ship GNU ar) we use a copy of OpenBSD ar here.
+ std::vector<std::string> arFiles;
+ std::string topLevelString = strGenWDIR + "/";
+ arFiles.push_back(topLevelString + "debian-binary");
+ arFiles.push_back(topLevelString + "control.tar.gz");
+ arFiles.push_back(topLevelString + "data.tar" + compression_suffix);
+ std::string outputFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ outputFileName += "/";
+ outputFileName += this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME");
+ int res = ar_append(outputFileName.c_str(), arFiles);
+ if (res != 0) {
+ std::string tmpFile =
+ this->GetOption("GEN_CPACK_TEMPORARY_PACKAGE_FILE_NAME");
+ tmpFile += "/Deb.log";
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Problem creating archive using: " << res << std::endl;
+ return 0;
+ }
+ return 1;
+}
+
+bool cmCPackDebGenerator::SupportsComponentInstallation() const
+{
+ return IsOn("CPACK_DEB_COMPONENT_INSTALL");
+}
+
+std::string cmCPackDebGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ if (componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) {
+ return componentName;
+ }
+
+ if (componentPackageMethod == ONE_PACKAGE) {
+ return std::string("ALL_COMPONENTS_IN_ONE");
+ }
+ // We have to find the name of the COMPONENT GROUP
+ // the current COMPONENT belongs to.
+ std::string groupVar =
+ "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP";
+ if (CM_NULLPTR != GetOption(groupVar)) {
+ return std::string(GetOption(groupVar));
+ } else {
+ return componentName;
+ }
+}
+
+// The following code is taken from OpenBSD ar:
+// http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ar/
+// It has been slightly modified:
+// -return error codes instead exit() in functions
+// -use the stdio file I/O functions instead the file descriptor based ones
+// -merged into one cxx file
+// -no additional options supported
+// The coding style hasn't been modified.
+
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Hugh Smith at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+// include sys/stat.h after sys/types.h
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ARMAG "!<arch>\n" /* ar "magic number" */
+#define SARMAG 8 /* strlen(ARMAG); */
+
+#define AR_EFMT1 "#1/" /* extended format #1 */
+#define ARFMAG "`\n"
+
+/* Header format strings. */
+#define HDR1 "%s%-13d%-12ld%-6u%-6u%-8o%-10lld%2s"
+#define HDR2 "%-16.16s%-12ld%-6u%-6u%-8o%-10lld%2s"
+
+struct ar_hdr
+{
+ char ar_name[16]; /* name */
+ char ar_date[12]; /* modification time */
+ char ar_uid[6]; /* user id */
+ char ar_gid[6]; /* group id */
+ char ar_mode[8]; /* octal file permissions */
+ char ar_size[10]; /* size in bytes */
+ char ar_fmag[2]; /* consistency check */
+};
+
+/* Set up file copy. */
+#define SETCF(from, fromname, to, toname, pad) \
+ { \
+ cf.rFile = from; \
+ cf.rname = fromname; \
+ cf.wFile = to; \
+ cf.wname = toname; \
+ cf.flags = pad; \
+ }
+
+/* File copy structure. */
+typedef struct
+{
+ FILE* rFile; /* read file descriptor */
+ const char* rname; /* read name */
+ FILE* wFile; /* write file descriptor */
+ const char* wname; /* write name */
+#define NOPAD 0x00 /* don't pad */
+#define WPAD 0x02 /* pad on writes */
+ unsigned int flags; /* pad flags */
+} CF;
+
+/* misc.c */
+
+static const char* ar_rname(const char* path)
+{
+ const char* ind = strrchr(path, '/');
+ return (ind) ? ind + 1 : path;
+}
+
+/* archive.c */
+
+typedef struct ar_hdr HDR;
+static char ar_hb[sizeof(HDR) + 1]; /* real header */
+
+static size_t ar_already_written;
+
+/* copy_ar --
+ * Copy size bytes from one file to another - taking care to handle the
+ * extra byte (for odd size files) when reading archives and writing an
+ * extra byte if necessary when adding files to archive. The length of
+ * the object is the long name plus the object itself; the variable
+ * already_written gets set if a long name was written.
+ *
+ * The padding is really unnecessary, and is almost certainly a remnant
+ * of early archive formats where the header included binary data which
+ * a PDP-11 required to start on an even byte boundary. (Or, perhaps,
+ * because 16-bit word addressed copies were faster?) Anyhow, it should
+ * have been ripped out long ago.
+ */
+static int copy_ar(CF* cfp, off_t size)
+{
+ static char pad = '\n';
+ off_t sz = size;
+ size_t nr, nw;
+ char buf[8 * 1024];
+
+ if (sz == 0) {
+ return 0;
+ }
+
+ FILE* from = cfp->rFile;
+ FILE* to = cfp->wFile;
+ while (sz &&
+ (nr = fread(buf, 1, sz < static_cast<off_t>(sizeof(buf))
+ ? static_cast<size_t>(sz)
+ : sizeof(buf),
+ from)) > 0) {
+ sz -= nr;
+ for (size_t off = 0; off < nr; nr -= off, off += nw) {
+ if ((nw = fwrite(buf + off, 1, nr, to)) < nr) {
+ return -1;
+ }
+ }
+ }
+ if (sz) {
+ return -2;
+ }
+
+ if (cfp->flags & WPAD && (size + ar_already_written) & 1 &&
+ fwrite(&pad, 1, 1, to) != 1) {
+ return -4;
+ }
+
+ return 0;
+}
+
+/* put_arobj -- Write an archive member to a file. */
+static int put_arobj(CF* cfp, struct stat* sb)
+{
+ int result = 0;
+ struct ar_hdr* hdr;
+
+ /* If passed an sb structure, reading a file from disk. Get stat(2)
+ * information, build a name and construct a header. (Files are named
+ * by their last component in the archive.) */
+ const char* name = ar_rname(cfp->rname);
+ (void)stat(cfp->rname, sb);
+
+ /* If not truncating names and the name is too long or contains
+ * a space, use extended format 1. */
+ size_t lname = strlen(name);
+ uid_t uid = sb->st_uid;
+ gid_t gid = sb->st_gid;
+ if (uid > USHRT_MAX) {
+ uid = USHRT_MAX;
+ }
+ if (gid > USHRT_MAX) {
+ gid = USHRT_MAX;
+ }
+ if (lname > sizeof(hdr->ar_name) || strchr(name, ' ')) {
+ (void)sprintf(ar_hb, HDR1, AR_EFMT1, (int)lname, (long int)sb->st_mtime,
+ (unsigned)uid, (unsigned)gid, (unsigned)sb->st_mode,
+ (long long)sb->st_size + lname, ARFMAG);
+ } else {
+ lname = 0;
+ (void)sprintf(ar_hb, HDR2, name, (long int)sb->st_mtime, (unsigned)uid,
+ (unsigned)gid, (unsigned)sb->st_mode, (long long)sb->st_size,
+ ARFMAG);
+ }
+ off_t size = sb->st_size;
+
+ if (fwrite(ar_hb, 1, sizeof(HDR), cfp->wFile) != sizeof(HDR)) {
+ return -1;
+ }
+
+ if (lname) {
+ if (fwrite(name, 1, lname, cfp->wFile) != lname) {
+ return -2;
+ }
+ ar_already_written = lname;
+ }
+ result = copy_ar(cfp, size);
+ ar_already_written = 0;
+ return result;
+}
+
+/* append.c */
+
+/* append --
+ * Append files to the archive - modifies original archive or creates
+ * a new archive if named archive does not exist.
+ */
+static int ar_append(const char* archive,
+ const std::vector<std::string>& files)
+{
+ int eval = 0;
+ FILE* aFile = cmSystemTools::Fopen(archive, "wb+");
+ if (aFile != CM_NULLPTR) {
+ fwrite(ARMAG, SARMAG, 1, aFile);
+ if (fseek(aFile, 0, SEEK_END) != -1) {
+ CF cf;
+ struct stat sb;
+ /* Read from disk, write to an archive; pad on write. */
+ SETCF(CM_NULLPTR, CM_NULLPTR, aFile, archive, WPAD);
+ for (std::vector<std::string>::const_iterator fileIt = files.begin();
+ fileIt != files.end(); ++fileIt) {
+ const char* filename = fileIt->c_str();
+ FILE* file = cmSystemTools::Fopen(filename, "rb");
+ if (file == CM_NULLPTR) {
+ eval = -1;
+ continue;
+ }
+ cf.rFile = file;
+ cf.rname = filename;
+ int result = put_arobj(&cf, &sb);
+ (void)fclose(file);
+ if (result != 0) {
+ eval = -2;
+ break;
+ }
+ }
+ } else {
+ eval = -3;
+ }
+ fclose(aFile);
+ } else {
+ eval = -4;
+ }
+ return eval;
+}
diff --git a/Source/CPack/cmCPackDebGenerator.h b/Source/CPack/cmCPackDebGenerator.h
new file mode 100644
index 0000000..bcdc509
--- /dev/null
+++ b/Source/CPack/cmCPackDebGenerator.h
@@ -0,0 +1,76 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackDebGenerator_h
+#define cmCPackDebGenerator_h
+
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackDebGenerator
+ * \brief A generator for Debian packages
+ *
+ */
+class cmCPackDebGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackDebGenerator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackDebGenerator();
+ ~cmCPackDebGenerator() CM_OVERRIDE;
+
+ static bool CanGenerate()
+ {
+#ifdef __APPLE__
+ // on MacOS enable CPackDeb iff dpkg is found
+ std::vector<std::string> locations;
+ locations.push_back("/sw/bin"); // Fink
+ locations.push_back("/opt/local/bin"); // MacPorts
+ return cmSystemTools::FindProgram("dpkg", locations) != "" ? true : false;
+#else
+ // legacy behavior on other systems
+ return true;
+#endif
+ }
+
+protected:
+ int InitializeInternal() CM_OVERRIDE;
+ /**
+ * This method factors out the work done in component packaging case.
+ */
+ int PackageOnePack(std::string const& initialToplevel,
+ std::string const& packageName);
+ /**
+ * The method used to package files when component
+ * install is used. This will create one
+ * archive for each component group.
+ */
+ int PackageComponents(bool ignoreGroup);
+ /**
+ * Special case of component install where all
+ * components will be put in a single installer.
+ */
+ int PackageComponentsAllInOne(const std::string& compInstDirName);
+ int PackageFiles() CM_OVERRIDE;
+ const char* GetOutputExtension() CM_OVERRIDE { return ".deb"; }
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+ std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName) CM_OVERRIDE;
+
+private:
+ int createDeb();
+ std::vector<std::string> packageFiles;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
new file mode 100644
index 0000000..640e437
--- /dev/null
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -0,0 +1,898 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackDragNDropGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmSystemTools.h"
+
+#include <cmsys/FStream.hxx>
+#include <cmsys/RegularExpression.hxx>
+
+#include <iomanip>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#ifdef HAVE_CoreServices
+// For the old LocaleStringToLangAndRegionCodes() function, to convert
+// to the old Script Manager RegionCode values needed for the 'LPic' data
+// structure used for generating multi-lingual SLAs.
+#include <CoreServices/CoreServices.h>
+#endif
+
+static const char* SLAHeader =
+ "data 'LPic' (5000) {\n"
+ " $\"0002 0011 0003 0001 0000 0000 0002 0000\"\n"
+ " $\"0008 0003 0000 0001 0004 0000 0004 0005\"\n"
+ " $\"0000 000E 0006 0001 0005 0007 0000 0007\"\n"
+ " $\"0008 0000 0047 0009 0000 0034 000A 0001\"\n"
+ " $\"0035 000B 0001 0020 000C 0000 0011 000D\"\n"
+ " $\"0000 005B 0004 0000 0033 000F 0001 000C\"\n"
+ " $\"0010 0000 000B 000E 0000\"\n"
+ "};\n"
+ "\n";
+
+static const char* SLASTREnglish =
+ "resource 'STR#' (5002, \"English\") {\n"
+ " {\n"
+ " \"English\",\n"
+ " \"Agree\",\n"
+ " \"Disagree\",\n"
+ " \"Print\",\n"
+ " \"Save...\",\n"
+ " \"You agree to the License Agreement terms when you click \"\n"
+ " \"the \\\"Agree\\\" button.\",\n"
+ " \"Software License Agreement\",\n"
+ " \"This text cannot be saved. This disk may be full or locked, "
+ "or the \"\n"
+ " \"file may be locked.\",\n"
+ " \"Unable to print. Make sure you have selected a printer.\"\n"
+ " }\n"
+ "};\n"
+ "\n";
+
+cmCPackDragNDropGenerator::cmCPackDragNDropGenerator()
+ : singleLicense(false)
+{
+ // default to one package file for components
+ this->componentPackageMethod = ONE_PACKAGE;
+}
+
+cmCPackDragNDropGenerator::~cmCPackDragNDropGenerator()
+{
+}
+
+int cmCPackDragNDropGenerator::InitializeInternal()
+{
+ // Starting with Xcode 4.3, look in "/Applications/Xcode.app" first:
+ //
+ std::vector<std::string> paths;
+ paths.push_back("/Applications/Xcode.app/Contents/Developer/Tools");
+ paths.push_back("/Developer/Tools");
+
+ const std::string hdiutil_path =
+ cmSystemTools::FindProgram("hdiutil", std::vector<std::string>(), false);
+ if (hdiutil_path.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot locate hdiutil command"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_HDIUTIL", hdiutil_path.c_str());
+
+ const std::string setfile_path =
+ cmSystemTools::FindProgram("SetFile", paths, false);
+ if (setfile_path.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot locate SetFile command"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_SETFILE", setfile_path.c_str());
+
+ const std::string rez_path = cmSystemTools::FindProgram("Rez", paths, false);
+ if (rez_path.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot locate Rez command"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_REZ", rez_path.c_str());
+
+ if (this->IsSet("CPACK_DMG_SLA_DIR")) {
+ slaDirectory = this->GetOption("CPACK_DMG_SLA_DIR");
+ if (!slaDirectory.empty() && this->IsSet("CPACK_RESOURCE_FILE_LICENSE")) {
+ std::string license_file =
+ this->GetOption("CPACK_RESOURCE_FILE_LICENSE");
+ if (!license_file.empty() &&
+ (license_file.find("CPack.GenericLicense.txt") ==
+ std::string::npos)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_OUTPUT,
+ "Both CPACK_DMG_SLA_DIR and CPACK_RESOURCE_FILE_LICENSE specified, "
+ "using CPACK_RESOURCE_FILE_LICENSE as a license for all languages."
+ << std::endl);
+ singleLicense = true;
+ }
+ }
+ if (!this->IsSet("CPACK_DMG_SLA_LANGUAGES")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_DMG_SLA_DIR set but no languages defined "
+ "(set CPACK_DMG_SLA_LANGUAGES)"
+ << std::endl);
+ return 0;
+ }
+ if (!cmSystemTools::FileExists(slaDirectory, false)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "CPACK_DMG_SLA_DIR does not exist"
+ << std::endl);
+ return 0;
+ }
+
+ std::vector<std::string> languages;
+ cmSystemTools::ExpandListArgument(
+ this->GetOption("CPACK_DMG_SLA_LANGUAGES"), languages);
+ if (languages.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_DMG_SLA_LANGUAGES set but empty" << std::endl);
+ return 0;
+ }
+ for (size_t i = 0; i < languages.size(); ++i) {
+ std::string license = slaDirectory + "/" + languages[i] + ".license.txt";
+ if (!singleLicense && !cmSystemTools::FileExists(license)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Missing license file "
+ << languages[i] << ".license.txt" << std::endl);
+ return 0;
+ }
+ std::string menu = slaDirectory + "/" + languages[i] + ".menu.txt";
+ if (!cmSystemTools::FileExists(menu)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Missing menu file "
+ << languages[i] << ".menu.txt" << std::endl);
+ return 0;
+ }
+ }
+ }
+
+ return this->Superclass::InitializeInternal();
+}
+
+const char* cmCPackDragNDropGenerator::GetOutputExtension()
+{
+ return ".dmg";
+}
+
+int cmCPackDragNDropGenerator::PackageFiles()
+{
+ // gather which directories to make dmg files for
+ // multiple directories occur if packaging components or groups separately
+
+ // monolith
+ if (this->Components.empty()) {
+ return this->CreateDMG(toplevel, packageFileNames[0]);
+ }
+
+ // component install
+ std::vector<std::string> package_files;
+
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ std::string name = GetComponentInstallDirNameSuffix(compIt->first);
+ package_files.push_back(name);
+ }
+ std::sort(package_files.begin(), package_files.end());
+ package_files.erase(std::unique(package_files.begin(), package_files.end()),
+ package_files.end());
+
+ // loop to create dmg files
+ packageFileNames.clear();
+ for (size_t i = 0; i < package_files.size(); i++) {
+ std::string full_package_name = std::string(toplevel) + std::string("/");
+ if (package_files[i] == "ALL_IN_ONE") {
+ full_package_name += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ } else {
+ full_package_name += package_files[i];
+ }
+ full_package_name += std::string(GetOutputExtension());
+ packageFileNames.push_back(full_package_name);
+
+ std::string src_dir = toplevel;
+ src_dir += "/";
+ src_dir += package_files[i];
+
+ if (0 == this->CreateDMG(src_dir, full_package_name)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+bool cmCPackDragNDropGenerator::CopyFile(std::ostringstream& source,
+ std::ostringstream& target)
+{
+ if (!cmSystemTools::CopyFileIfDifferent(source.str().c_str(),
+ target.str().c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error copying "
+ << source.str() << " to " << target.str() << std::endl);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool cmCPackDragNDropGenerator::CreateEmptyFile(std::ostringstream& target,
+ size_t size)
+{
+ cmsys::ofstream fout(target.str().c_str(), std::ios::out | std::ios::binary);
+ if (!fout) {
+ return false;
+ } else {
+ // Seek to desired size - 1 byte
+ fout.seekp(size - 1, std::ios::beg);
+ char byte = 0;
+ // Write one byte to ensure file grows
+ fout.write(&byte, 1);
+ }
+
+ return true;
+}
+
+bool cmCPackDragNDropGenerator::RunCommand(std::ostringstream& command,
+ std::string* output)
+{
+ int exit_code = 1;
+
+ bool result =
+ cmSystemTools::RunSingleCommand(command.str().c_str(), output, output,
+ &exit_code, 0, this->GeneratorVerbose, 0);
+
+ if (!result || exit_code) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error executing: " << command.str()
+ << std::endl);
+
+ return false;
+ }
+
+ return true;
+}
+
+int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
+ const std::string& output_file)
+{
+ // Get optional arguments ...
+ const std::string cpack_package_icon = this->GetOption("CPACK_PACKAGE_ICON")
+ ? this->GetOption("CPACK_PACKAGE_ICON")
+ : "";
+
+ const std::string cpack_dmg_volume_name =
+ this->GetOption("CPACK_DMG_VOLUME_NAME")
+ ? this->GetOption("CPACK_DMG_VOLUME_NAME")
+ : this->GetOption("CPACK_PACKAGE_FILE_NAME");
+
+ const std::string cpack_dmg_format = this->GetOption("CPACK_DMG_FORMAT")
+ ? this->GetOption("CPACK_DMG_FORMAT")
+ : "UDZO";
+
+ // Get optional arguments ...
+ std::string cpack_license_file =
+ this->GetOption("CPACK_RESOURCE_FILE_LICENSE")
+ ? this->GetOption("CPACK_RESOURCE_FILE_LICENSE")
+ : "";
+
+ const std::string cpack_dmg_background_image =
+ this->GetOption("CPACK_DMG_BACKGROUND_IMAGE")
+ ? this->GetOption("CPACK_DMG_BACKGROUND_IMAGE")
+ : "";
+
+ const std::string cpack_dmg_ds_store = this->GetOption("CPACK_DMG_DS_STORE")
+ ? this->GetOption("CPACK_DMG_DS_STORE")
+ : "";
+
+ const std::string cpack_dmg_languages =
+ this->GetOption("CPACK_DMG_SLA_LANGUAGES")
+ ? this->GetOption("CPACK_DMG_SLA_LANGUAGES")
+ : "";
+
+ const std::string cpack_dmg_ds_store_setup_script =
+ this->GetOption("CPACK_DMG_DS_STORE_SETUP_SCRIPT")
+ ? this->GetOption("CPACK_DMG_DS_STORE_SETUP_SCRIPT")
+ : "";
+
+ const bool cpack_dmg_disable_applications_symlink =
+ this->IsOn("CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK");
+
+ // only put license on dmg if is user provided
+ if (!cpack_license_file.empty() &&
+ cpack_license_file.find("CPack.GenericLicense.txt") !=
+ std::string::npos) {
+ cpack_license_file = "";
+ }
+
+ // use sla_dir if both sla_dir and license_file are set
+ if (!cpack_license_file.empty() && !slaDirectory.empty() && !singleLicense) {
+ cpack_license_file = "";
+ }
+
+ // The staging directory contains everything that will end-up inside the
+ // final disk image ...
+ std::ostringstream staging;
+ staging << src_dir;
+
+ // Add a symlink to /Applications so users can drag-and-drop the bundle
+ // into it unless this behaviour was disabled
+ if (!cpack_dmg_disable_applications_symlink) {
+ std::ostringstream application_link;
+ application_link << staging.str() << "/Applications";
+ cmSystemTools::CreateSymlink("/Applications",
+ application_link.str().c_str());
+ }
+
+ // Optionally add a custom volume icon ...
+ if (!cpack_package_icon.empty()) {
+ std::ostringstream package_icon_source;
+ package_icon_source << cpack_package_icon;
+
+ std::ostringstream package_icon_destination;
+ package_icon_destination << staging.str() << "/.VolumeIcon.icns";
+
+ if (!this->CopyFile(package_icon_source, package_icon_destination)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error copying disk volume icon. "
+ "Check the value of CPACK_PACKAGE_ICON."
+ << std::endl);
+
+ return 0;
+ }
+ }
+
+ // Optionally add a custom .DS_Store file
+ // (e.g. for setting background/layout) ...
+ if (!cpack_dmg_ds_store.empty()) {
+ std::ostringstream package_settings_source;
+ package_settings_source << cpack_dmg_ds_store;
+
+ std::ostringstream package_settings_destination;
+ package_settings_destination << staging.str() << "/.DS_Store";
+
+ if (!this->CopyFile(package_settings_source,
+ package_settings_destination)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error copying disk volume settings file. "
+ "Check the value of CPACK_DMG_DS_STORE."
+ << std::endl);
+
+ return 0;
+ }
+ }
+
+ // Optionally add a custom background image ...
+ // Make sure the background file type is the same as the custom image
+ // and that the file is hidden so it doesn't show up.
+ if (!cpack_dmg_background_image.empty()) {
+ const std::string extension =
+ cmSystemTools::GetFilenameLastExtension(cpack_dmg_background_image);
+ std::ostringstream package_background_source;
+ package_background_source << cpack_dmg_background_image;
+
+ std::ostringstream package_background_destination;
+ package_background_destination << staging.str()
+ << "/.background/background" << extension;
+
+ if (!this->CopyFile(package_background_source,
+ package_background_destination)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error copying disk volume background image. "
+ "Check the value of CPACK_DMG_BACKGROUND_IMAGE."
+ << std::endl);
+
+ return 0;
+ }
+ }
+
+ bool remount_image =
+ !cpack_package_icon.empty() || !cpack_dmg_ds_store_setup_script.empty();
+
+ // Create 1 MB dummy padding file in staging area when we need to remount
+ // image, so we have enough space for storing changes ...
+ if (remount_image) {
+ std::ostringstream dummy_padding;
+ dummy_padding << staging.str() << "/.dummy-padding-file";
+ if (!this->CreateEmptyFile(dummy_padding, 1048576)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error creating dummy padding file."
+ << std::endl);
+
+ return 0;
+ }
+ }
+
+ // Create a temporary read-write disk image ...
+ std::string temp_image = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ temp_image += "/temp.dmg";
+
+ std::ostringstream temp_image_command;
+ temp_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ temp_image_command << " create";
+ temp_image_command << " -ov";
+ temp_image_command << " -srcfolder \"" << staging.str() << "\"";
+ temp_image_command << " -volname \"" << cpack_dmg_volume_name << "\"";
+ temp_image_command << " -format UDRW";
+ temp_image_command << " \"" << temp_image << "\"";
+
+ if (!this->RunCommand(temp_image_command)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error generating temporary disk image." << std::endl);
+
+ return 0;
+ }
+
+ if (remount_image) {
+ // Store that we have a failure so that we always unmount the image
+ // before we exit.
+ bool had_error = false;
+
+ std::ostringstream attach_command;
+ attach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ attach_command << " attach";
+ attach_command << " \"" << temp_image << "\"";
+
+ std::string attach_output;
+ if (!this->RunCommand(attach_command, &attach_output)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error attaching temporary disk image." << std::endl);
+
+ return 0;
+ }
+
+ cmsys::RegularExpression mountpoint_regex(".*(/Volumes/[^\n]+)\n.*");
+ mountpoint_regex.find(attach_output.c_str());
+ std::string const temp_mount = mountpoint_regex.match(1);
+
+ // Remove dummy padding file so we have enough space on RW image ...
+ std::ostringstream dummy_padding;
+ dummy_padding << temp_mount << "/.dummy-padding-file";
+ if (!cmSystemTools::RemoveFile(dummy_padding.str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error removing dummy padding file."
+ << std::endl);
+
+ had_error = true;
+ }
+
+ // Optionally set the custom icon flag for the image ...
+ if (!had_error && !cpack_package_icon.empty()) {
+ std::ostringstream setfile_command;
+ setfile_command << this->GetOption("CPACK_COMMAND_SETFILE");
+ setfile_command << " -a C";
+ setfile_command << " \"" << temp_mount << "\"";
+
+ if (!this->RunCommand(setfile_command)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error assigning custom icon to temporary disk image."
+ << std::endl);
+
+ had_error = true;
+ }
+ }
+
+ // Optionally we can execute a custom apple script to generate
+ // the .DS_Store for the volume folder ...
+ if (!had_error && !cpack_dmg_ds_store_setup_script.empty()) {
+ std::ostringstream setup_script_command;
+ setup_script_command << "osascript"
+ << " \"" << cpack_dmg_ds_store_setup_script << "\""
+ << " \"" << cpack_dmg_volume_name << "\"";
+ std::string error;
+ if (!this->RunCommand(setup_script_command, &error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error executing custom script on disk image."
+ << std::endl
+ << error << std::endl);
+
+ had_error = true;
+ }
+ }
+
+ std::ostringstream detach_command;
+ detach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ detach_command << " detach";
+ detach_command << " \"" << temp_mount << "\"";
+
+ if (!this->RunCommand(detach_command)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error detaching temporary disk image." << std::endl);
+
+ return 0;
+ }
+
+ if (had_error) {
+ return 0;
+ }
+ }
+
+ if (!cpack_license_file.empty() || !slaDirectory.empty()) {
+ // Use old hardcoded style if sla_dir is not set
+ bool oldStyle = slaDirectory.empty();
+ std::string sla_r = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ sla_r += "/sla.r";
+
+ std::vector<std::string> languages;
+ if (!oldStyle) {
+ cmSystemTools::ExpandListArgument(cpack_dmg_languages, languages);
+ }
+
+ cmGeneratedFileStream ofs(sla_r.c_str());
+ ofs << "#include <CoreServices/CoreServices.r>\n\n";
+ if (oldStyle) {
+ ofs << SLAHeader;
+ ofs << "\n";
+ } else {
+ /*
+ * LPic Layout
+ * (https://github.com/pypt/dmg-add-license/blob/master/main.c)
+ * as far as I can tell (no official documentation seems to exist):
+ * struct LPic {
+ * uint16_t default_language; // points to a resid, defaulting to 0,
+ * // which is the first set language
+ * uint16_t length;
+ * struct {
+ * uint16_t language_code;
+ * uint16_t resid;
+ * uint16_t encoding; // Encoding from TextCommon.h,
+ * // forcing MacRoman (0) for now. Might need to
+ * // allow overwrite per license by user later
+ * } item[1];
+ * }
+ */
+
+ // Create vector first for readability, then iterate to write to ofs
+ std::vector<uint16_t> header_data;
+ header_data.push_back(0);
+ header_data.push_back(languages.size());
+ for (size_t i = 0; i < languages.size(); ++i) {
+ CFStringRef language_cfstring = CFStringCreateWithCString(
+ NULL, languages[i].c_str(), kCFStringEncodingUTF8);
+ CFStringRef iso_language =
+ CFLocaleCreateCanonicalLanguageIdentifierFromString(
+ NULL, language_cfstring);
+ if (!iso_language) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, languages[i]
+ << " is not a recognized language" << std::endl);
+ }
+ char* iso_language_cstr = (char*)malloc(65);
+ CFStringGetCString(iso_language, iso_language_cstr, 64,
+ kCFStringEncodingMacRoman);
+ LangCode lang = 0;
+ RegionCode region = 0;
+#ifdef HAVE_CoreServices
+ OSStatus err =
+ LocaleStringToLangAndRegionCodes(iso_language_cstr, &lang, &region);
+ if (err != noErr)
+#endif
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "No language/region code available for "
+ << iso_language_cstr << std::endl);
+ free(iso_language_cstr);
+ return 0;
+ }
+#ifdef HAVE_CoreServices
+ free(iso_language_cstr);
+ header_data.push_back(region);
+ header_data.push_back(i);
+ header_data.push_back(0);
+#endif
+ }
+ ofs << "data 'LPic' (5000) {\n";
+ ofs << std::hex << std::uppercase << std::setfill('0');
+
+ for (size_t i = 0; i < header_data.size(); ++i) {
+ if (i % 8 == 0) {
+ ofs << " $\"";
+ }
+
+ ofs << std::setw(4) << header_data[i];
+
+ if (i % 8 == 7 || i == header_data.size() - 1) {
+ ofs << "\"\n";
+ } else {
+ ofs << " ";
+ }
+ }
+ ofs << "};\n\n";
+ // Reset ofs options
+ ofs << std::dec << std::nouppercase << std::setfill(' ');
+ }
+
+ bool have_write_license_error = false;
+ std::string error;
+
+ if (oldStyle) {
+ if (!this->WriteLicense(ofs, 0, "", cpack_license_file, &error)) {
+ have_write_license_error = true;
+ }
+ } else {
+ for (size_t i = 0; i < languages.size() && !have_write_license_error;
+ ++i) {
+ if (singleLicense) {
+ if (!this->WriteLicense(ofs, i + 5000, languages[i],
+ cpack_license_file, &error)) {
+ have_write_license_error = true;
+ }
+ } else {
+ if (!this->WriteLicense(ofs, i + 5000, languages[i], "", &error)) {
+ have_write_license_error = true;
+ }
+ }
+ }
+ }
+
+ ofs.Close();
+
+ if (have_write_license_error) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error writing license file to SLA."
+ << std::endl
+ << error << std::endl);
+ return 0;
+ }
+
+ // convert to UDCO
+ std::string temp_udco = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ temp_udco += "/temp-udco.dmg";
+
+ std::ostringstream udco_image_command;
+ udco_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ udco_image_command << " convert \"" << temp_image << "\"";
+ udco_image_command << " -format UDCO";
+ udco_image_command << " -ov -o \"" << temp_udco << "\"";
+
+ if (!this->RunCommand(udco_image_command, &error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error converting to UDCO dmg for adding SLA."
+ << std::endl
+ << error << std::endl);
+ return 0;
+ }
+
+ // unflatten dmg
+ std::ostringstream unflatten_command;
+ unflatten_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ unflatten_command << " unflatten ";
+ unflatten_command << "\"" << temp_udco << "\"";
+
+ if (!this->RunCommand(unflatten_command, &error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error unflattening dmg for adding SLA." << std::endl
+ << error
+ << std::endl);
+ return 0;
+ }
+
+ // Rez the SLA
+ std::ostringstream embed_sla_command;
+ embed_sla_command << this->GetOption("CPACK_COMMAND_REZ");
+ const char* sysroot = this->GetOption("CPACK_OSX_SYSROOT");
+ if (sysroot && sysroot[0] != '\0') {
+ embed_sla_command << " -isysroot \"" << sysroot << "\"";
+ }
+ embed_sla_command << " \"" << sla_r << "\"";
+ embed_sla_command << " -a -o ";
+ embed_sla_command << "\"" << temp_udco << "\"";
+
+ if (!this->RunCommand(embed_sla_command, &error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error adding SLA." << std::endl
+ << error
+ << std::endl);
+ return 0;
+ }
+
+ // flatten dmg
+ std::ostringstream flatten_command;
+ flatten_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ flatten_command << " flatten ";
+ flatten_command << "\"" << temp_udco << "\"";
+
+ if (!this->RunCommand(flatten_command, &error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error flattening dmg for adding SLA." << std::endl
+ << error
+ << std::endl);
+ return 0;
+ }
+
+ temp_image = temp_udco;
+ }
+
+ // Create the final compressed read-only disk image ...
+ std::ostringstream final_image_command;
+ final_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ final_image_command << " convert \"" << temp_image << "\"";
+ final_image_command << " -format ";
+ final_image_command << cpack_dmg_format;
+ final_image_command << " -imagekey";
+ final_image_command << " zlib-level=9";
+ final_image_command << " -o \"" << output_file << "\"";
+
+ if (!this->RunCommand(final_image_command)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error compressing disk image."
+ << std::endl);
+
+ return 0;
+ }
+
+ return 1;
+}
+
+bool cmCPackDragNDropGenerator::SupportsComponentInstallation() const
+{
+ return true;
+}
+
+std::string cmCPackDragNDropGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ // we want to group components together that go in the same dmg package
+ std::string package_file_name = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+
+ // we have 3 mutually exclusive modes to work in
+ // 1. all components in one package
+ // 2. each group goes in its own package with left over
+ // components in their own package
+ // 3. ignore groups - if grouping is defined, it is ignored
+ // and each component goes in its own package
+
+ if (this->componentPackageMethod == ONE_PACKAGE) {
+ return "ALL_IN_ONE";
+ }
+
+ if (this->componentPackageMethod == ONE_PACKAGE_PER_GROUP) {
+ // We have to find the name of the COMPONENT GROUP
+ // the current COMPONENT belongs to.
+ std::string groupVar =
+ "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP";
+ const char* _groupName = GetOption(groupVar.c_str());
+ if (_groupName) {
+ std::string groupName = _groupName;
+
+ groupName =
+ GetComponentPackageFileName(package_file_name, groupName, true);
+ return groupName;
+ }
+ }
+
+ return GetComponentPackageFileName(package_file_name, componentName, false);
+}
+
+bool cmCPackDragNDropGenerator::WriteLicense(
+ cmGeneratedFileStream& outputStream, int licenseNumber,
+ std::string licenseLanguage, std::string licenseFile, std::string* error)
+{
+ if (!licenseFile.empty() && !singleLicense) {
+ licenseNumber = 5002;
+ licenseLanguage = "English";
+ }
+
+ // License header
+ outputStream << "data 'TEXT' (" << licenseNumber << ", \"" << licenseLanguage
+ << "\") {\n";
+ // License body
+ std::string actual_license = !licenseFile.empty()
+ ? licenseFile
+ : (slaDirectory + "/" + licenseLanguage + ".license.txt");
+ cmsys::ifstream license_ifs;
+ license_ifs.open(actual_license.c_str());
+ if (license_ifs.is_open()) {
+ while (license_ifs.good()) {
+ std::string line;
+ std::getline(license_ifs, line);
+ if (!line.empty()) {
+ EscapeQuotesAndBackslashes(line);
+ std::vector<std::string> lines;
+ if (!this->BreakLongLine(line, lines, error)) {
+ return false;
+ }
+ for (size_t i = 0; i < lines.size(); ++i) {
+ outputStream << " \"" << lines[i] << "\"\n";
+ }
+ }
+ outputStream << " \"\\n\"\n";
+ }
+ license_ifs.close();
+ }
+
+ // End of License
+ outputStream << "};\n\n";
+ if (!licenseFile.empty() && !singleLicense) {
+ outputStream << SLASTREnglish;
+ } else {
+ // Menu header
+ outputStream << "resource 'STR#' (" << licenseNumber << ", \""
+ << licenseLanguage << "\") {\n";
+ outputStream << " {\n";
+
+ // Menu body
+ cmsys::ifstream menu_ifs;
+ menu_ifs.open(
+ (slaDirectory + "/" + licenseLanguage + ".menu.txt").c_str());
+ if (menu_ifs.is_open()) {
+ size_t lines_written = 0;
+ while (menu_ifs.good()) {
+ // Lines written from original file, not from broken up lines
+ std::string line;
+ std::getline(menu_ifs, line);
+ if (!line.empty()) {
+ EscapeQuotesAndBackslashes(line);
+ std::vector<std::string> lines;
+ if (!this->BreakLongLine(line, lines, error)) {
+ return false;
+ }
+ for (size_t i = 0; i < lines.size(); ++i) {
+ std::string comma;
+ // We need a comma after every complete string,
+ // but not on the very last line
+ if (lines_written != 8 && i == lines.size() - 1) {
+ comma = ",";
+ } else {
+ comma = "";
+ }
+ outputStream << " \"" << lines[i] << "\"" << comma << "\n";
+ }
+ ++lines_written;
+ }
+ }
+ menu_ifs.close();
+ }
+
+ // End of menu
+ outputStream << " }\n";
+ outputStream << "};\n";
+ outputStream << "\n";
+ }
+
+ return true;
+}
+
+bool cmCPackDragNDropGenerator::BreakLongLine(const std::string& line,
+ std::vector<std::string>& lines,
+ std::string* error)
+{
+ const size_t max_line_length = 512;
+ for (size_t i = 0; i < line.size(); i += max_line_length) {
+ size_t line_length = max_line_length;
+ if (i + line_length > line.size()) {
+ line_length = line.size() - i;
+ } else
+ while (line_length > 0 && line[i + line_length - 1] != ' ') {
+ line_length = line_length - 1;
+ }
+
+ if (line_length == 0) {
+ *error = "Please make sure there are no words "
+ "(or character sequences not broken up by spaces or newlines) "
+ "in your license file which are more than 512 characters long.";
+ return false;
+ }
+ lines.push_back(line.substr(i, line_length));
+ }
+ return true;
+}
+
+void cmCPackDragNDropGenerator::EscapeQuotesAndBackslashes(std::string& line)
+{
+ std::string::size_type backslash_pos = line.find('\\');
+ while (backslash_pos != std::string::npos) {
+ line.replace(backslash_pos, 1, "\\\\");
+ backslash_pos = line.find('\\', backslash_pos + 2);
+ }
+
+ std::string::size_type quote_pos = line.find('\"');
+ while (quote_pos != std::string::npos) {
+ line.replace(quote_pos, 1, "\\\"");
+ quote_pos = line.find('\"', quote_pos + 2);
+ }
+}
diff --git a/Source/CPack/cmCPackDragNDropGenerator.h b/Source/CPack/cmCPackDragNDropGenerator.h
new file mode 100644
index 0000000..1392b21
--- /dev/null
+++ b/Source/CPack/cmCPackDragNDropGenerator.h
@@ -0,0 +1,60 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackDragNDropGenerator_h
+#define cmCPackDragNDropGenerator_h
+
+#include "cmCPackGenerator.h"
+
+class cmGeneratedFileStream;
+
+/** \class cmCPackDragNDropGenerator
+ * \brief A generator for OSX drag-n-drop installs
+ */
+class cmCPackDragNDropGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackDragNDropGenerator, cmCPackGenerator);
+
+ cmCPackDragNDropGenerator();
+ virtual ~cmCPackDragNDropGenerator();
+
+protected:
+ virtual int InitializeInternal();
+ virtual const char* GetOutputExtension();
+ int PackageFiles();
+ bool SupportsComponentInstallation() const;
+
+ bool CopyFile(std::ostringstream& source, std::ostringstream& target);
+ bool CreateEmptyFile(std::ostringstream& target, size_t size);
+ bool RunCommand(std::ostringstream& command, std::string* output = 0);
+
+ std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName);
+
+ int CreateDMG(const std::string& src_dir, const std::string& output_file);
+
+ std::string InstallPrefix;
+
+private:
+ std::string slaDirectory;
+ bool singleLicense;
+
+ bool WriteLicense(cmGeneratedFileStream& outputStream, int licenseNumber,
+ std::string licenseLanguage, std::string licenseFile,
+ std::string* error);
+ bool BreakLongLine(const std::string& line, std::vector<std::string>& lines,
+ std::string* error);
+ void EscapeQuotesAndBackslashes(std::string& line);
+};
+
+#endif
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
new file mode 100644
index 0000000..df8bb0f
--- /dev/null
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -0,0 +1,1432 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackGenerator.h"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmXMLSafe.h"
+#include "cmake.h"
+
+#include <algorithm>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/SystemTools.hxx>
+#include <list>
+
+#if defined(__HAIKU__)
+#include <FindDirectory.h>
+#include <StorageDefs.h>
+#endif
+
+cmCPackGenerator::cmCPackGenerator()
+{
+ this->GeneratorVerbose = cmSystemTools::OUTPUT_NONE;
+ this->MakefileMap = CM_NULLPTR;
+ this->Logger = CM_NULLPTR;
+ this->componentPackageMethod = ONE_PACKAGE_PER_GROUP;
+}
+
+cmCPackGenerator::~cmCPackGenerator()
+{
+ this->MakefileMap = CM_NULLPTR;
+}
+
+void cmCPackGeneratorProgress(const char* msg, float prog, void* ptr)
+{
+ cmCPackGenerator* self = static_cast<cmCPackGenerator*>(ptr);
+ self->DisplayVerboseOutput(msg, prog);
+}
+
+void cmCPackGenerator::DisplayVerboseOutput(const char* msg, float progress)
+{
+ (void)progress;
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "" << msg << std::endl);
+}
+
+int cmCPackGenerator::PrepareNames()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Create temp directory." << std::endl);
+
+ // checks CPACK_SET_DESTDIR support
+ if (IsOn("CPACK_SET_DESTDIR")) {
+ if (SETDESTDIR_UNSUPPORTED == SupportsSetDestdir()) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR, "CPACK_SET_DESTDIR is set to ON but the '"
+ << Name << "' generator does NOT support it." << std::endl);
+ return 0;
+ } else if (SETDESTDIR_SHOULD_NOT_BE_USED == SupportsSetDestdir()) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "CPACK_SET_DESTDIR is set to ON but it is "
+ << "usually a bad idea to do that with '" << Name
+ << "' generator. Use at your own risk." << std::endl);
+ }
+ }
+
+ std::string tempDirectory = this->GetOption("CPACK_PACKAGE_DIRECTORY");
+ tempDirectory += "/_CPack_Packages/";
+ const char* toplevelTag = this->GetOption("CPACK_TOPLEVEL_TAG");
+ if (toplevelTag) {
+ tempDirectory += toplevelTag;
+ tempDirectory += "/";
+ }
+ tempDirectory += this->GetOption("CPACK_GENERATOR");
+ std::string topDirectory = tempDirectory;
+ const char* pfname = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ if (!pfname) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_FILE_NAME not specified" << std::endl);
+ return 0;
+ }
+ std::string outName = pfname;
+ tempDirectory += "/" + outName;
+ if (!this->GetOutputExtension()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "No output extension specified"
+ << std::endl);
+ return 0;
+ }
+ outName += this->GetOutputExtension();
+ const char* pdir = this->GetOption("CPACK_PACKAGE_DIRECTORY");
+ if (!pdir) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_DIRECTORY not specified" << std::endl);
+ return 0;
+ }
+
+ std::string destFile = pdir;
+ this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PREFIX", destFile.c_str());
+ destFile += "/" + outName;
+ std::string outFile = topDirectory + "/" + outName;
+ this->SetOptionIfNotSet("CPACK_TOPLEVEL_DIRECTORY", topDirectory.c_str());
+ this->SetOptionIfNotSet("CPACK_TEMPORARY_DIRECTORY", tempDirectory.c_str());
+ this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_NAME", outName.c_str());
+ this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PATH", destFile.c_str());
+ this->SetOptionIfNotSet("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
+ outFile.c_str());
+ this->SetOptionIfNotSet("CPACK_INSTALL_DIRECTORY", this->GetInstallPath());
+ this->SetOptionIfNotSet(
+ "CPACK_NATIVE_INSTALL_DIRECTORY",
+ cmsys::SystemTools::ConvertToOutputPath(this->GetInstallPath()).c_str());
+ this->SetOptionIfNotSet("CPACK_TEMPORARY_INSTALL_DIRECTORY",
+ tempDirectory.c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Look for: CPACK_PACKAGE_DESCRIPTION_FILE" << std::endl);
+ const char* descFileName = this->GetOption("CPACK_PACKAGE_DESCRIPTION_FILE");
+ if (descFileName) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Look for: " << descFileName
+ << std::endl);
+ if (!cmSystemTools::FileExists(descFileName)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find description file name: ["
+ << descFileName << "]" << std::endl);
+ return 0;
+ }
+ cmsys::ifstream ifs(descFileName);
+ if (!ifs) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot open description file name: " << descFileName
+ << std::endl);
+ return 0;
+ }
+ std::ostringstream ostr;
+ std::string line;
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Read description file: " << descFileName << std::endl);
+ while (ifs && cmSystemTools::GetLineFromStream(ifs, line)) {
+ ostr << cmXMLSafe(line) << std::endl;
+ }
+ this->SetOptionIfNotSet("CPACK_PACKAGE_DESCRIPTION", ostr.str().c_str());
+ }
+ if (!this->GetOption("CPACK_PACKAGE_DESCRIPTION")) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Project description not specified. Please specify "
+ "CPACK_PACKAGE_DESCRIPTION or CPACK_PACKAGE_DESCRIPTION_FILE."
+ << std::endl);
+ return 0;
+ }
+
+ this->SetOptionIfNotSet("CPACK_REMOVE_TOPLEVEL_DIRECTORY", "1");
+
+ return 1;
+}
+
+int cmCPackGenerator::InstallProject()
+{
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Install projects" << std::endl);
+ this->CleanTemporaryDirectory();
+
+ std::string bareTempInstallDirectory =
+ this->GetOption("CPACK_TEMPORARY_INSTALL_DIRECTORY");
+ std::string tempInstallDirectoryStr = bareTempInstallDirectory;
+ bool setDestDir = cmSystemTools::IsOn(this->GetOption("CPACK_SET_DESTDIR")) |
+ cmSystemTools::IsInternallyOn(this->GetOption("CPACK_SET_DESTDIR"));
+ if (!setDestDir) {
+ tempInstallDirectoryStr += this->GetPackagingInstallPrefix();
+ }
+
+ const char* tempInstallDirectory = tempInstallDirectoryStr.c_str();
+ int res = 1;
+ if (!cmsys::SystemTools::MakeDirectory(bareTempInstallDirectory.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating temporary directory: "
+ << (tempInstallDirectory ? tempInstallDirectory : "(NULL)")
+ << std::endl);
+ return 0;
+ }
+
+ if (setDestDir) {
+ std::string destDir = "DESTDIR=";
+ destDir += tempInstallDirectory;
+ cmSystemTools::PutEnv(destDir);
+ } else {
+ // Make sure there is no destdir
+ cmSystemTools::PutEnv("DESTDIR=");
+ }
+
+ // If the CPackConfig file sets CPACK_INSTALL_COMMANDS then run them
+ // as listed
+ if (!this->InstallProjectViaInstallCommands(setDestDir,
+ tempInstallDirectory)) {
+ return 0;
+ }
+
+ // If the CPackConfig file sets CPACK_INSTALL_SCRIPT then run them
+ // as listed
+ if (!this->InstallProjectViaInstallScript(setDestDir,
+ tempInstallDirectory)) {
+ return 0;
+ }
+
+ // If the CPackConfig file sets CPACK_INSTALLED_DIRECTORIES
+ // then glob it and copy it to CPACK_TEMPORARY_DIRECTORY
+ // This is used in Source packaging
+ if (!this->InstallProjectViaInstalledDirectories(setDestDir,
+ tempInstallDirectory)) {
+ return 0;
+ }
+
+ // If the project is a CMAKE project then run pre-install
+ // and then read the cmake_install script to run it
+ if (!this->InstallProjectViaInstallCMakeProjects(setDestDir,
+ bareTempInstallDirectory)) {
+ return 0;
+ }
+
+ if (setDestDir) {
+ cmSystemTools::PutEnv("DESTDIR=");
+ }
+
+ return res;
+}
+
+int cmCPackGenerator::InstallProjectViaInstallCommands(
+ bool setDestDir, const std::string& tempInstallDirectory)
+{
+ (void)setDestDir;
+ const char* installCommands = this->GetOption("CPACK_INSTALL_COMMANDS");
+ if (installCommands && *installCommands) {
+ std::string tempInstallDirectoryEnv = "CMAKE_INSTALL_PREFIX=";
+ tempInstallDirectoryEnv += tempInstallDirectory;
+ cmSystemTools::PutEnv(tempInstallDirectoryEnv);
+ std::vector<std::string> installCommandsVector;
+ cmSystemTools::ExpandListArgument(installCommands, installCommandsVector);
+ std::vector<std::string>::iterator it;
+ for (it = installCommandsVector.begin(); it != installCommandsVector.end();
+ ++it) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << *it << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool resB =
+ cmSystemTools::RunSingleCommand(it->c_str(), &output, &output, &retVal,
+ CM_NULLPTR, this->GeneratorVerbose, 0);
+ if (!resB || retVal) {
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/InstallOutput.log";
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << *it << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR, "Problem running install command: "
+ << *it << std::endl
+ << "Please check " << tmpFile << " for errors" << std::endl);
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+int cmCPackGenerator::InstallProjectViaInstalledDirectories(
+ bool setDestDir, const std::string& tempInstallDirectory)
+{
+ (void)setDestDir;
+ (void)tempInstallDirectory;
+ std::vector<cmsys::RegularExpression> ignoreFilesRegex;
+ const char* cpackIgnoreFiles = this->GetOption("CPACK_IGNORE_FILES");
+ if (cpackIgnoreFiles) {
+ std::vector<std::string> ignoreFilesRegexString;
+ cmSystemTools::ExpandListArgument(cpackIgnoreFiles,
+ ignoreFilesRegexString);
+ std::vector<std::string>::iterator it;
+ for (it = ignoreFilesRegexString.begin();
+ it != ignoreFilesRegexString.end(); ++it) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Create ignore files regex for: " << *it << std::endl);
+ ignoreFilesRegex.push_back(it->c_str());
+ }
+ }
+ const char* installDirectories =
+ this->GetOption("CPACK_INSTALLED_DIRECTORIES");
+ if (installDirectories && *installDirectories) {
+ std::vector<std::string> installDirectoriesVector;
+ cmSystemTools::ExpandListArgument(installDirectories,
+ installDirectoriesVector);
+ if (installDirectoriesVector.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_INSTALLED_DIRECTORIES should contain pairs of <directory> and "
+ "<subdirectory>. The <subdirectory> can be '.' to be installed in "
+ "the toplevel directory of installation."
+ << std::endl);
+ return 0;
+ }
+ std::vector<std::string>::iterator it;
+ const std::string& tempDir = tempInstallDirectory;
+ for (it = installDirectoriesVector.begin();
+ it != installDirectoriesVector.end(); ++it) {
+ std::list<std::pair<std::string, std::string> > symlinkedFiles;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Find files" << std::endl);
+ cmsys::Glob gl;
+ std::string top = *it;
+ it++;
+ std::string subdir = *it;
+ std::string findExpr = top;
+ findExpr += "/*";
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Install directory: " << top << std::endl);
+ gl.RecurseOn();
+ gl.SetRecurseListDirs(true);
+ if (!gl.FindFiles(findExpr)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find any files in the installed directory"
+ << std::endl);
+ return 0;
+ }
+ files = gl.GetFiles();
+ std::vector<std::string>::iterator gfit;
+ std::vector<cmsys::RegularExpression>::iterator regIt;
+ for (gfit = files.begin(); gfit != files.end(); ++gfit) {
+ bool skip = false;
+ std::string inFile = *gfit;
+ if (cmSystemTools::FileIsDirectory(*gfit)) {
+ inFile += '/';
+ }
+ for (regIt = ignoreFilesRegex.begin(); regIt != ignoreFilesRegex.end();
+ ++regIt) {
+ if (regIt->find(inFile.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Ignore file: " << inFile << std::endl);
+ skip = true;
+ }
+ }
+ if (skip) {
+ continue;
+ }
+ std::string filePath = tempDir;
+ filePath += "/" + subdir + "/" +
+ cmSystemTools::RelativePath(top.c_str(), gfit->c_str());
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Copy file: "
+ << inFile << " -> " << filePath << std::endl);
+ /* If the file is a symlink we will have to re-create it */
+ if (cmSystemTools::FileIsSymlink(inFile)) {
+ std::string targetFile;
+ std::string inFileRelative =
+ cmSystemTools::RelativePath(top.c_str(), inFile.c_str());
+ cmSystemTools::ReadSymlink(inFile, targetFile);
+ symlinkedFiles.push_back(
+ std::pair<std::string, std::string>(targetFile, inFileRelative));
+ }
+ /* If it is not a symlink then do a plain copy */
+ else if (!(cmSystemTools::CopyFileIfDifferent(inFile.c_str(),
+ filePath.c_str()) &&
+ cmSystemTools::CopyFileTime(inFile.c_str(),
+ filePath.c_str()))) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying file: "
+ << inFile << " -> " << filePath << std::endl);
+ return 0;
+ }
+ }
+ /* rebuild symlinks in the installed tree */
+ if (!symlinkedFiles.empty()) {
+ std::list<std::pair<std::string, std::string> >::iterator symlinkedIt;
+ std::string curDir = cmSystemTools::GetCurrentWorkingDirectory();
+ std::string goToDir = tempDir;
+ goToDir += "/" + subdir;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Change dir to: " << goToDir
+ << std::endl);
+ cmSystemTools::ChangeDirectory(goToDir);
+ for (symlinkedIt = symlinkedFiles.begin();
+ symlinkedIt != symlinkedFiles.end(); ++symlinkedIt) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Will create a symlink: "
+ << symlinkedIt->second << "--> "
+ << symlinkedIt->first << std::endl);
+ // make sure directory exists for symlink
+ std::string destDir =
+ cmSystemTools::GetFilenamePath(symlinkedIt->second);
+ if (!destDir.empty() && !cmSystemTools::MakeDirectory(destDir)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot create dir: "
+ << destDir << "\nTrying to create symlink: "
+ << symlinkedIt->second << "--> "
+ << symlinkedIt->first << std::endl);
+ }
+ if (!cmSystemTools::CreateSymlink(symlinkedIt->first,
+ symlinkedIt->second)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot create symlink: "
+ << symlinkedIt->second << "--> "
+ << symlinkedIt->first << std::endl);
+ return 0;
+ }
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Going back to: " << curDir
+ << std::endl);
+ cmSystemTools::ChangeDirectory(curDir);
+ }
+ }
+ }
+ return 1;
+}
+
+int cmCPackGenerator::InstallProjectViaInstallScript(
+ bool setDestDir, const std::string& tempInstallDirectory)
+{
+ const char* cmakeScripts = this->GetOption("CPACK_INSTALL_SCRIPT");
+ if (cmakeScripts && *cmakeScripts) {
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Install scripts: " << cmakeScripts
+ << std::endl);
+ std::vector<std::string> cmakeScriptsVector;
+ cmSystemTools::ExpandListArgument(cmakeScripts, cmakeScriptsVector);
+ std::vector<std::string>::iterator it;
+ for (it = cmakeScriptsVector.begin(); it != cmakeScriptsVector.end();
+ ++it) {
+ std::string installScript = *it;
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Install script: " << installScript << std::endl);
+
+ if (setDestDir) {
+ // For DESTDIR based packaging, use the *project* CMAKE_INSTALL_PREFIX
+ // underneath the tempInstallDirectory. The value of the project's
+ // CMAKE_INSTALL_PREFIX is sent in here as the value of the
+ // CPACK_INSTALL_PREFIX variable.
+
+ std::string dir;
+ if (this->GetOption("CPACK_INSTALL_PREFIX")) {
+ dir += this->GetOption("CPACK_INSTALL_PREFIX");
+ }
+ this->SetOption("CMAKE_INSTALL_PREFIX", dir.c_str());
+ cmCPackLogger(
+ cmCPackLog::LOG_DEBUG,
+ "- Using DESTDIR + CPACK_INSTALL_PREFIX... (this->SetOption)"
+ << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Setting CMAKE_INSTALL_PREFIX to '" << dir << "'"
+ << std::endl);
+ } else {
+ this->SetOption("CMAKE_INSTALL_PREFIX", tempInstallDirectory.c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Using non-DESTDIR install... (this->SetOption)"
+ << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Setting CMAKE_INSTALL_PREFIX to '"
+ << tempInstallDirectory << "'" << std::endl);
+ }
+
+ this->SetOptionIfNotSet("CMAKE_CURRENT_BINARY_DIR",
+ tempInstallDirectory.c_str());
+ this->SetOptionIfNotSet("CMAKE_CURRENT_SOURCE_DIR",
+ tempInstallDirectory.c_str());
+ int res = this->MakefileMap->ReadListFile(installScript.c_str());
+ if (cmSystemTools::GetErrorOccuredFlag() || !res) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
+ bool setDestDir, const std::string& baseTempInstallDirectory)
+{
+ const char* cmakeProjects = this->GetOption("CPACK_INSTALL_CMAKE_PROJECTS");
+ const char* cmakeGenerator = this->GetOption("CPACK_CMAKE_GENERATOR");
+ std::string absoluteDestFiles;
+ if (cmakeProjects && *cmakeProjects) {
+ if (!cmakeGenerator) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_INSTALL_CMAKE_PROJECTS is specified, but "
+ "CPACK_CMAKE_GENERATOR is not. CPACK_CMAKE_GENERATOR "
+ "is required to install the project."
+ << std::endl);
+ return 0;
+ }
+ std::vector<std::string> cmakeProjectsVector;
+ cmSystemTools::ExpandListArgument(cmakeProjects, cmakeProjectsVector);
+ std::vector<std::string>::iterator it;
+ for (it = cmakeProjectsVector.begin(); it != cmakeProjectsVector.end();
+ ++it) {
+ if (it + 1 == cmakeProjectsVector.end() ||
+ it + 2 == cmakeProjectsVector.end() ||
+ it + 3 == cmakeProjectsVector.end()) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Not enough items on list: CPACK_INSTALL_CMAKE_PROJECTS. "
+ "CPACK_INSTALL_CMAKE_PROJECTS should hold quadruplet of install "
+ "directory, install project name, install component, and install "
+ "subdirectory."
+ << std::endl);
+ return 0;
+ }
+ std::string installDirectory = *it;
+ ++it;
+ std::string installProjectName = *it;
+ ++it;
+ std::string installComponent = *it;
+ ++it;
+ std::string installSubDirectory = *it;
+ std::string installFile = installDirectory + "/cmake_install.cmake";
+
+ std::vector<std::string> componentsVector;
+
+ bool componentInstall = false;
+ /*
+ * We do a component install iff
+ * - the CPack generator support component
+ * - the user did not request Monolithic install
+ * (this works at CPack time too)
+ */
+ if (this->SupportsComponentInstallation() &
+ !(this->IsOn("CPACK_MONOLITHIC_INSTALL"))) {
+ // Determine the installation types for this project (if provided).
+ std::string installTypesVar = "CPACK_" +
+ cmSystemTools::UpperCase(installComponent) + "_INSTALL_TYPES";
+ const char* installTypes = this->GetOption(installTypesVar);
+ if (installTypes && *installTypes) {
+ std::vector<std::string> installTypesVector;
+ cmSystemTools::ExpandListArgument(installTypes, installTypesVector);
+ std::vector<std::string>::iterator installTypeIt;
+ for (installTypeIt = installTypesVector.begin();
+ installTypeIt != installTypesVector.end(); ++installTypeIt) {
+ this->GetInstallationType(installProjectName, *installTypeIt);
+ }
+ }
+
+ // Determine the set of components that will be used in this project
+ std::string componentsVar =
+ "CPACK_COMPONENTS_" + cmSystemTools::UpperCase(installComponent);
+ const char* components = this->GetOption(componentsVar);
+ if (components && *components) {
+ cmSystemTools::ExpandListArgument(components, componentsVector);
+ std::vector<std::string>::iterator compIt;
+ for (compIt = componentsVector.begin();
+ compIt != componentsVector.end(); ++compIt) {
+ GetComponent(installProjectName, *compIt);
+ }
+ componentInstall = true;
+ }
+ }
+ if (componentsVector.empty()) {
+ componentsVector.push_back(installComponent);
+ }
+
+ const char* buildConfigCstr = this->GetOption("CPACK_BUILD_CONFIG");
+ std::string buildConfig = buildConfigCstr ? buildConfigCstr : "";
+ cmGlobalGenerator* globalGenerator =
+ this->MakefileMap->GetCMakeInstance()->CreateGlobalGenerator(
+ cmakeGenerator);
+ if (!globalGenerator) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Specified package generator not found. "
+ "CPACK_CMAKE_GENERATOR value is invalid."
+ << std::endl);
+ return 0;
+ }
+ // set the global flag for unix style paths on cmSystemTools as
+ // soon as the generator is set. This allows gmake to be used
+ // on windows.
+ cmSystemTools::SetForceUnixPaths(globalGenerator->GetForceUnixPaths());
+
+ // Does this generator require pre-install?
+ if (const char* preinstall =
+ globalGenerator->GetPreinstallTargetName()) {
+ std::string buildCommand = globalGenerator->GenerateCMakeBuildCommand(
+ preinstall, buildConfig, "", false);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Install command: " << buildCommand << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Run preinstall target for: "
+ << installProjectName << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool resB = cmSystemTools::RunSingleCommand(
+ buildCommand.c_str(), &output, &output, &retVal,
+ installDirectory.c_str(), this->GeneratorVerbose, 0);
+ if (!resB || retVal) {
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/PreinstallOutput.log";
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << buildCommand << std::endl
+ << "# Directory: " << installDirectory << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR, "Problem running install command: "
+ << buildCommand << std::endl
+ << "Please check " << tmpFile << " for errors" << std::endl);
+ return 0;
+ }
+ }
+ delete globalGenerator;
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Install project: " << installProjectName << std::endl);
+
+ // Run the installation for each component
+ std::vector<std::string>::iterator componentIt;
+ for (componentIt = componentsVector.begin();
+ componentIt != componentsVector.end(); ++componentIt) {
+ std::string tempInstallDirectory = baseTempInstallDirectory;
+ installComponent = *componentIt;
+ if (componentInstall) {
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Install component: "
+ << installComponent << std::endl);
+ }
+
+ cmake cm;
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cm.AddCMakePaths();
+ cm.SetProgressCallback(cmCPackGeneratorProgress, this);
+ cmGlobalGenerator gg(&cm);
+ CM_AUTO_PTR<cmMakefile> mf(
+ new cmMakefile(&gg, cm.GetCurrentSnapshot()));
+ if (!installSubDirectory.empty() && installSubDirectory != "/") {
+ tempInstallDirectory += installSubDirectory;
+ }
+ if (componentInstall) {
+ tempInstallDirectory += "/";
+ // Some CPack generators would rather chose
+ // the local installation directory suffix.
+ // Some (e.g. RPM) use
+ // one install directory for each component **GROUP**
+ // instead of the default
+ // one install directory for each component.
+ tempInstallDirectory +=
+ GetComponentInstallDirNameSuffix(installComponent);
+ if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
+ tempInstallDirectory += "/";
+ tempInstallDirectory += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ }
+ }
+
+ if (!setDestDir) {
+ tempInstallDirectory += this->GetPackagingInstallPrefix();
+ }
+
+ if (setDestDir) {
+ // For DESTDIR based packaging, use the *project*
+ // CMAKE_INSTALL_PREFIX underneath the tempInstallDirectory. The
+ // value of the project's CMAKE_INSTALL_PREFIX is sent in here as
+ // the value of the CPACK_INSTALL_PREFIX variable.
+ //
+ // If DESTDIR has been 'internally set ON' this means that
+ // the underlying CPack specific generator did ask for that
+ // In this case we may override CPACK_INSTALL_PREFIX with
+ // CPACK_PACKAGING_INSTALL_PREFIX
+ // I know this is tricky and awkward but it's the price for
+ // CPACK_SET_DESTDIR backward compatibility.
+ if (cmSystemTools::IsInternallyOn(
+ this->GetOption("CPACK_SET_DESTDIR"))) {
+ this->SetOption("CPACK_INSTALL_PREFIX",
+ this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX"));
+ }
+ std::string dir;
+ if (this->GetOption("CPACK_INSTALL_PREFIX")) {
+ dir += this->GetOption("CPACK_INSTALL_PREFIX");
+ }
+ mf->AddDefinition("CMAKE_INSTALL_PREFIX", dir.c_str());
+
+ cmCPackLogger(
+ cmCPackLog::LOG_DEBUG,
+ "- Using DESTDIR + CPACK_INSTALL_PREFIX... (mf->AddDefinition)"
+ << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Setting CMAKE_INSTALL_PREFIX to '" << dir << "'"
+ << std::endl);
+
+ // Make sure that DESTDIR + CPACK_INSTALL_PREFIX directory
+ // exists:
+ //
+ if (cmSystemTools::StringStartsWith(dir.c_str(), "/")) {
+ dir = tempInstallDirectory + dir;
+ } else {
+ dir = tempInstallDirectory + "/" + dir;
+ }
+ /*
+ * We must re-set DESTDIR for each component
+ * We must not add the CPACK_INSTALL_PREFIX part because
+ * it will be added using the override of CMAKE_INSTALL_PREFIX
+ * The main reason for this awkward trick is that
+ * are using DESTDIR for 2 different reasons:
+ * - Because it was asked by the CPack Generator or the user
+ * using CPACK_SET_DESTDIR
+ * - Because it was already used for component install
+ * in order to put things in subdirs...
+ */
+ cmSystemTools::PutEnv(std::string("DESTDIR=") +
+ tempInstallDirectory);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "- Creating directory: '"
+ << dir << "'" << std::endl);
+
+ if (!cmsys::SystemTools::MakeDirectory(dir.c_str())) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Problem creating temporary directory: " << dir << std::endl);
+ return 0;
+ }
+ } else {
+ mf->AddDefinition("CMAKE_INSTALL_PREFIX",
+ tempInstallDirectory.c_str());
+
+ if (!cmsys::SystemTools::MakeDirectory(
+ tempInstallDirectory.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating temporary directory: "
+ << tempInstallDirectory << std::endl);
+ return 0;
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Using non-DESTDIR install... (mf->AddDefinition)"
+ << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Setting CMAKE_INSTALL_PREFIX to '"
+ << tempInstallDirectory << "'" << std::endl);
+ }
+
+ if (!buildConfig.empty()) {
+ mf->AddDefinition("BUILD_TYPE", buildConfig.c_str());
+ }
+ std::string installComponentLowerCase =
+ cmSystemTools::LowerCase(installComponent);
+ if (installComponentLowerCase != "all") {
+ mf->AddDefinition("CMAKE_INSTALL_COMPONENT",
+ installComponent.c_str());
+ }
+
+ // strip on TRUE, ON, 1, one or several file names, but not on
+ // FALSE, OFF, 0 and an empty string
+ if (!cmSystemTools::IsOff(this->GetOption("CPACK_STRIP_FILES"))) {
+ mf->AddDefinition("CMAKE_INSTALL_DO_STRIP", "1");
+ }
+ // Remember the list of files before installation
+ // of the current component (if we are in component install)
+ const char* InstallPrefix = tempInstallDirectory.c_str();
+ std::vector<std::string> filesBefore;
+ std::string findExpr(InstallPrefix);
+ if (componentInstall) {
+ cmsys::Glob glB;
+ findExpr += "/*";
+ glB.RecurseOn();
+ glB.SetRecurseListDirs(true);
+ glB.FindFiles(findExpr);
+ filesBefore = glB.GetFiles();
+ std::sort(filesBefore.begin(), filesBefore.end());
+ }
+
+ // If CPack was asked to warn on ABSOLUTE INSTALL DESTINATION
+ // then forward request to cmake_install.cmake script
+ if (this->IsOn("CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION")) {
+ mf->AddDefinition("CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
+ }
+ // If current CPack generator does support
+ // ABSOLUTE INSTALL DESTINATION or CPack has been asked for
+ // then ask cmake_install.cmake script to error out
+ // as soon as it occurs (before installing file)
+ if (!SupportsAbsoluteDestination() ||
+ this->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION")) {
+ mf->AddDefinition("CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION",
+ "1");
+ }
+ // do installation
+ int res = mf->ReadListFile(installFile.c_str());
+ // forward definition of CMAKE_ABSOLUTE_DESTINATION_FILES
+ // to CPack (may be used by generators like CPack RPM or DEB)
+ // in order to transparently handle ABSOLUTE PATH
+ if (mf->GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES")) {
+ mf->AddDefinition(
+ "CPACK_ABSOLUTE_DESTINATION_FILES",
+ mf->GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES"));
+ }
+
+ // Now rebuild the list of files after installation
+ // of the current component (if we are in component install)
+ if (componentInstall) {
+ cmsys::Glob glA;
+ glA.RecurseOn();
+ glA.SetRecurseListDirs(true);
+ glA.FindFiles(findExpr);
+ std::vector<std::string> filesAfter = glA.GetFiles();
+ std::sort(filesAfter.begin(), filesAfter.end());
+ std::vector<std::string>::iterator diff;
+ std::vector<std::string> result(filesAfter.size());
+ diff = std::set_difference(filesAfter.begin(), filesAfter.end(),
+ filesBefore.begin(), filesBefore.end(),
+ result.begin());
+
+ std::vector<std::string>::iterator fit;
+ std::string localFileName;
+ // Populate the File field of each component
+ for (fit = result.begin(); fit != diff; ++fit) {
+ localFileName =
+ cmSystemTools::RelativePath(InstallPrefix, fit->c_str());
+ localFileName = localFileName.substr(
+ localFileName.find_first_not_of('/'), std::string::npos);
+ Components[installComponent].Files.push_back(localFileName);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Adding file <"
+ << localFileName << "> to component <"
+ << installComponent << ">" << std::endl);
+ }
+ }
+
+ if (CM_NULLPTR !=
+ mf->GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")) {
+ if (!absoluteDestFiles.empty()) {
+ absoluteDestFiles += ";";
+ }
+ absoluteDestFiles +=
+ mf->GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES");
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Got some ABSOLUTE DESTINATION FILES: "
+ << absoluteDestFiles << std::endl);
+ // define component specific var
+ if (componentInstall) {
+ std::string absoluteDestFileComponent =
+ std::string("CPACK_ABSOLUTE_DESTINATION_FILES") + "_" +
+ GetComponentInstallDirNameSuffix(installComponent);
+ if (CM_NULLPTR != this->GetOption(absoluteDestFileComponent)) {
+ std::string absoluteDestFilesListComponent =
+ this->GetOption(absoluteDestFileComponent);
+ absoluteDestFilesListComponent += ";";
+ absoluteDestFilesListComponent +=
+ mf->GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES");
+ this->SetOption(absoluteDestFileComponent,
+ absoluteDestFilesListComponent.c_str());
+ } else {
+ this->SetOption(
+ absoluteDestFileComponent,
+ mf->GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES"));
+ }
+ }
+ }
+ if (cmSystemTools::GetErrorOccuredFlag() || !res) {
+ return 0;
+ }
+ }
+ }
+ }
+ this->SetOption("CPACK_ABSOLUTE_DESTINATION_FILES",
+ absoluteDestFiles.c_str());
+ return 1;
+}
+
+bool cmCPackGenerator::ReadListFile(const char* moduleName)
+{
+ bool retval;
+ std::string fullPath = this->MakefileMap->GetModulesFile(moduleName);
+ retval = this->MakefileMap->ReadListFile(fullPath.c_str());
+ // include FATAL_ERROR and ERROR in the return status
+ retval = retval && (!cmSystemTools::GetErrorOccuredFlag());
+ return retval;
+}
+
+void cmCPackGenerator::SetOptionIfNotSet(const std::string& op,
+ const char* value)
+{
+ const char* def = this->MakefileMap->GetDefinition(op);
+ if (def && *def) {
+ return;
+ }
+ this->SetOption(op, value);
+}
+
+void cmCPackGenerator::SetOption(const std::string& op, const char* value)
+{
+ if (!value) {
+ this->MakefileMap->RemoveDefinition(op);
+ return;
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, this->GetNameOfClass()
+ << "::SetOption(" << op << ", " << value << ")"
+ << std::endl);
+ this->MakefileMap->AddDefinition(op, value);
+}
+
+int cmCPackGenerator::DoPackage()
+{
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Create package using " << this->Name
+ << std::endl);
+
+ // Prepare CPack internal name and check
+ // values for many CPACK_xxx vars
+ if (!this->PrepareNames()) {
+ return 0;
+ }
+
+ // Digest Component grouping specification
+ if (!this->PrepareGroupingKind()) {
+ return 0;
+ }
+
+ if (cmSystemTools::IsOn(
+ this->GetOption("CPACK_REMOVE_TOPLEVEL_DIRECTORY"))) {
+ const char* toplevelDirectory =
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ if (cmSystemTools::FileExists(toplevelDirectory)) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Remove toplevel directory: "
+ << toplevelDirectory << std::endl);
+ if (!cmSystemTools::RepeatedRemoveDirectory(toplevelDirectory)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem removing toplevel directory: "
+ << toplevelDirectory << std::endl);
+ return 0;
+ }
+ }
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "About to install project "
+ << std::endl);
+
+ if (!this->InstallProject()) {
+ return 0;
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Done install project " << std::endl);
+
+ const char* tempPackageFileName =
+ this->GetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME");
+ const char* tempDirectory = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Find files" << std::endl);
+ cmsys::Glob gl;
+ std::string findExpr = tempDirectory;
+ findExpr += "/*";
+ gl.RecurseOn();
+ gl.SetRecurseListDirs(true);
+ gl.SetRecurseThroughSymlinks(false);
+ if (!gl.FindFiles(findExpr)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find any files in the packaging tree" << std::endl);
+ return 0;
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Create package" << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Package files to: "
+ << (tempPackageFileName ? tempPackageFileName : "(NULL)")
+ << std::endl);
+ if (cmSystemTools::FileExists(tempPackageFileName)) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Remove old package file"
+ << std::endl);
+ cmSystemTools::RemoveFile(tempPackageFileName);
+ }
+ if (cmSystemTools::IsOn(
+ this->GetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY"))) {
+ tempDirectory = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ }
+
+ // The files to be installed
+ files = gl.GetFiles();
+
+ packageFileNames.clear();
+ /* Put at least one file name into the list of
+ * wanted packageFileNames. The specific generator
+ * may update this during PackageFiles.
+ * (either putting several names or updating the provided one)
+ */
+ packageFileNames.push_back(tempPackageFileName ? tempPackageFileName : "");
+ toplevel = tempDirectory;
+ if (!this->PackageFiles() || cmSystemTools::GetErrorOccuredFlag()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem compressing the directory"
+ << std::endl);
+ return 0;
+ }
+
+ /*
+ * Copy the generated packages to final destination
+ * - there may be several of them
+ * - the initially provided name may have changed
+ * (because the specific generator did 'normalize' it)
+ */
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Copying final package(s) ["
+ << packageFileNames.size() << "]:" << std::endl);
+ std::vector<std::string>::iterator it;
+ /* now copy package one by one */
+ for (it = packageFileNames.begin(); it != packageFileNames.end(); ++it) {
+ std::string tmpPF(this->GetOption("CPACK_OUTPUT_FILE_PREFIX"));
+ tempPackageFileName = it->c_str();
+ tmpPF += "/" + cmSystemTools::GetFilenameName(*it);
+ const char* packageFileName = tmpPF.c_str();
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Copy final package(s): "
+ << (tempPackageFileName ? tempPackageFileName : "(NULL)")
+ << " to " << (packageFileName ? packageFileName : "(NULL)")
+ << std::endl);
+ if (!cmSystemTools::CopyFileIfDifferent(tempPackageFileName,
+ packageFileName)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR, "Problem copying the package: "
+ << (tempPackageFileName ? tempPackageFileName : "(NULL)") << " to "
+ << (packageFileName ? packageFileName : "(NULL)") << std::endl);
+ return 0;
+ }
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- package: "
+ << packageFileName << " generated." << std::endl);
+ }
+
+ return 1;
+}
+
+int cmCPackGenerator::Initialize(const std::string& name, cmMakefile* mf)
+{
+ this->MakefileMap = mf;
+ this->Name = name;
+ // set the running generator name
+ this->SetOption("CPACK_GENERATOR", this->Name.c_str());
+ // Load the project specific config file
+ const char* config = this->GetOption("CPACK_PROJECT_CONFIG_FILE");
+ if (config) {
+ mf->ReadListFile(config);
+ }
+ int result = this->InitializeInternal();
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return 0;
+ }
+
+ // If a generator subclass did not already set this option in its
+ // InitializeInternal implementation, and the project did not already set
+ // it, the default value should be:
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/");
+
+ return result;
+}
+
+int cmCPackGenerator::InitializeInternal()
+{
+ return 1;
+}
+
+bool cmCPackGenerator::IsSet(const std::string& name) const
+{
+ return this->MakefileMap->IsSet(name);
+}
+
+bool cmCPackGenerator::IsOn(const std::string& name) const
+{
+ return cmSystemTools::IsOn(GetOption(name));
+}
+
+const char* cmCPackGenerator::GetOption(const std::string& op) const
+{
+ const char* ret = this->MakefileMap->GetDefinition(op);
+ if (!ret) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Warning, GetOption return NULL for: " << op << std::endl);
+ }
+ return ret;
+}
+
+std::vector<std::string> cmCPackGenerator::GetOptions() const
+{
+ return this->MakefileMap->GetDefinitions();
+}
+
+int cmCPackGenerator::PackageFiles()
+{
+ return 0;
+}
+
+const char* cmCPackGenerator::GetInstallPath()
+{
+ if (!this->InstallPath.empty()) {
+ return this->InstallPath.c_str();
+ }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ const char* prgfiles = cmsys::SystemTools::GetEnv("ProgramFiles");
+ const char* sysDrive = cmsys::SystemTools::GetEnv("SystemDrive");
+ if (prgfiles) {
+ this->InstallPath = prgfiles;
+ } else if (sysDrive) {
+ this->InstallPath = sysDrive;
+ this->InstallPath += "/Program Files";
+ } else {
+ this->InstallPath = "c:/Program Files";
+ }
+ this->InstallPath += "/";
+ this->InstallPath += this->GetOption("CPACK_PACKAGE_NAME");
+ this->InstallPath += "-";
+ this->InstallPath += this->GetOption("CPACK_PACKAGE_VERSION");
+#elif defined(__HAIKU__)
+ char dir[B_PATH_NAME_LENGTH];
+ if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) ==
+ B_OK) {
+ this->InstallPath = dir;
+ } else {
+ this->InstallPath = "/boot/system";
+ }
+#else
+ this->InstallPath = "/usr/local/";
+#endif
+ return this->InstallPath.c_str();
+}
+
+const char* cmCPackGenerator::GetPackagingInstallPrefix()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "GetPackagingInstallPrefix: '"
+ << this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX") << "'"
+ << std::endl);
+
+ return this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
+}
+
+std::string cmCPackGenerator::FindTemplate(const char* name)
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Look for template: "
+ << (name ? name : "(NULL)") << std::endl);
+ std::string ffile = this->MakefileMap->GetModulesFile(name);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Found template: " << ffile
+ << std::endl);
+ return ffile;
+}
+
+bool cmCPackGenerator::ConfigureString(const std::string& inString,
+ std::string& outString)
+{
+ this->MakefileMap->ConfigureString(inString, outString, true, false);
+ return true;
+}
+
+bool cmCPackGenerator::ConfigureFile(const char* inName, const char* outName,
+ bool copyOnly /* = false */)
+{
+ return this->MakefileMap->ConfigureFile(inName, outName, copyOnly, true,
+ false) == 1;
+}
+
+int cmCPackGenerator::CleanTemporaryDirectory()
+{
+ std::string tempInstallDirectoryWithPostfix =
+ 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);
+ if (!cmSystemTools::RepeatedRemoveDirectory(tempInstallDirectory)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem removing temporary directory: "
+ << tempInstallDirectory << std::endl);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+cmInstalledFile const* cmCPackGenerator::GetInstalledFile(
+ std::string const& name) const
+{
+ cmake const* cm = this->MakefileMap->GetCMakeInstance();
+ return cm->GetInstalledFile(name);
+}
+
+int cmCPackGenerator::PrepareGroupingKind()
+{
+ // find a component package method specified by the user
+ ComponentPackageMethod method = UNKNOWN_COMPONENT_PACKAGE_METHOD;
+
+ if (this->GetOption("CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE")) {
+ method = ONE_PACKAGE;
+ }
+
+ if (this->GetOption("CPACK_COMPONENTS_IGNORE_GROUPS")) {
+ method = ONE_PACKAGE_PER_COMPONENT;
+ }
+
+ if (this->GetOption("CPACK_COMPONENTS_ONE_PACKAGE_PER_GROUP")) {
+ method = ONE_PACKAGE_PER_GROUP;
+ }
+
+ std::string groupingType;
+
+ // Second way to specify grouping
+ if (CM_NULLPTR != this->GetOption("CPACK_COMPONENTS_GROUPING")) {
+ groupingType = this->GetOption("CPACK_COMPONENTS_GROUPING");
+ }
+
+ if (!groupingType.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "["
+ << this->Name << "]"
+ << " requested component grouping = " << groupingType
+ << std::endl);
+ if (groupingType == "ALL_COMPONENTS_IN_ONE") {
+ method = ONE_PACKAGE;
+ } else if (groupingType == "IGNORE") {
+ method = ONE_PACKAGE_PER_COMPONENT;
+ } else if (groupingType == "ONE_PER_GROUP") {
+ method = ONE_PACKAGE_PER_GROUP;
+ } else {
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING, "["
+ << this->Name << "]"
+ << " requested component grouping type <" << groupingType
+ << "> UNKNOWN not in (ALL_COMPONENTS_IN_ONE,IGNORE,ONE_PER_GROUP)"
+ << std::endl);
+ }
+ }
+
+ // Some components were defined but NO group
+ // fallback to default if not group based
+ if (method == ONE_PACKAGE_PER_GROUP && this->ComponentGroups.empty() &&
+ !this->Components.empty()) {
+ if (componentPackageMethod == ONE_PACKAGE) {
+ method = ONE_PACKAGE;
+ } else {
+ method = ONE_PACKAGE_PER_COMPONENT;
+ }
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING, "["
+ << this->Name << "]"
+ << " One package per component group requested, "
+ << "but NO component groups exist: Ignoring component group."
+ << std::endl);
+ }
+
+ // if user specified packaging method, override the default packaging method
+ if (method != UNKNOWN_COMPONENT_PACKAGE_METHOD) {
+ componentPackageMethod = method;
+ }
+
+ const char* method_names[] = { "ALL_COMPONENTS_IN_ONE", "IGNORE_GROUPS",
+ "ONE_PER_GROUP" };
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "["
+ << this->Name << "]"
+ << " requested component grouping = "
+ << method_names[componentPackageMethod] << std::endl);
+
+ return 1;
+}
+
+std::string cmCPackGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ return componentName;
+}
+std::string cmCPackGenerator::GetComponentPackageFileName(
+ const std::string& initialPackageFileName,
+ const std::string& groupOrComponentName, bool isGroupName)
+{
+
+ /*
+ * the default behavior is to use the
+ * component [group] name as a suffix
+ */
+ std::string suffix = "-" + groupOrComponentName;
+ /* check if we should use DISPLAY name */
+ std::string dispNameVar = "CPACK_" + Name + "_USE_DISPLAY_NAME_IN_FILENAME";
+ if (IsOn(dispNameVar)) {
+ /* the component Group case */
+ if (isGroupName) {
+ std::string groupDispVar = "CPACK_COMPONENT_GROUP_" +
+ cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME";
+ const char* groupDispName = GetOption(groupDispVar);
+ if (groupDispName) {
+ suffix = "-" + std::string(groupDispName);
+ }
+ }
+ /* the [single] component case */
+ else {
+ std::string dispVar = "CPACK_COMPONENT_" +
+ cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME";
+ const char* dispName = GetOption(dispVar);
+ if (dispName) {
+ suffix = "-" + std::string(dispName);
+ }
+ }
+ }
+ return initialPackageFileName + suffix;
+}
+
+enum cmCPackGenerator::CPackSetDestdirSupport
+cmCPackGenerator::SupportsSetDestdir() const
+{
+ return cmCPackGenerator::SETDESTDIR_SUPPORTED;
+}
+
+bool cmCPackGenerator::SupportsAbsoluteDestination() const
+{
+ return true;
+}
+
+bool cmCPackGenerator::SupportsComponentInstallation() const
+{
+ return false;
+}
+
+bool cmCPackGenerator::WantsComponentInstallation() const
+{
+ return (!IsOn("CPACK_MONOLITHIC_INSTALL") && SupportsComponentInstallation()
+ // check that we have at least one group or component
+ && (!this->ComponentGroups.empty() || !this->Components.empty()));
+}
+
+cmCPackInstallationType* cmCPackGenerator::GetInstallationType(
+ const std::string& projectName, const std::string& name)
+{
+ (void)projectName;
+ bool hasInstallationType = this->InstallationTypes.count(name) != 0;
+ cmCPackInstallationType* installType = &this->InstallationTypes[name];
+ if (!hasInstallationType) {
+ // Define the installation type
+ std::string macroPrefix =
+ "CPACK_INSTALL_TYPE_" + cmsys::SystemTools::UpperCase(name);
+ installType->Name = name;
+
+ const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
+ if (displayName && *displayName) {
+ installType->DisplayName = displayName;
+ } else {
+ installType->DisplayName = installType->Name;
+ }
+
+ installType->Index = static_cast<unsigned>(this->InstallationTypes.size());
+ }
+ return installType;
+}
+
+cmCPackComponent* cmCPackGenerator::GetComponent(
+ const std::string& projectName, const std::string& name)
+{
+ bool hasComponent = this->Components.count(name) != 0;
+ cmCPackComponent* component = &this->Components[name];
+ if (!hasComponent) {
+ // Define the component
+ std::string macroPrefix =
+ "CPACK_COMPONENT_" + cmsys::SystemTools::UpperCase(name);
+ component->Name = name;
+ const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
+ if (displayName && *displayName) {
+ component->DisplayName = displayName;
+ } else {
+ component->DisplayName = component->Name;
+ }
+ component->IsHidden = this->IsOn(macroPrefix + "_HIDDEN");
+ component->IsRequired = this->IsOn(macroPrefix + "_REQUIRED");
+ component->IsDisabledByDefault = this->IsOn(macroPrefix + "_DISABLED");
+ component->IsDownloaded = this->IsOn(macroPrefix + "_DOWNLOADED") ||
+ cmSystemTools::IsOn(this->GetOption("CPACK_DOWNLOAD_ALL"));
+
+ const char* archiveFile = this->GetOption(macroPrefix + "_ARCHIVE_FILE");
+ if (archiveFile && *archiveFile) {
+ component->ArchiveFile = archiveFile;
+ }
+
+ const char* groupName = this->GetOption(macroPrefix + "_GROUP");
+ if (groupName && *groupName) {
+ component->Group = GetComponentGroup(projectName, groupName);
+ component->Group->Components.push_back(component);
+ } else {
+ component->Group = CM_NULLPTR;
+ }
+
+ const char* description = this->GetOption(macroPrefix + "_DESCRIPTION");
+ if (description && *description) {
+ component->Description = description;
+ }
+
+ // Determine the installation types.
+ const char* installTypes = this->GetOption(macroPrefix + "_INSTALL_TYPES");
+ if (installTypes && *installTypes) {
+ std::vector<std::string> installTypesVector;
+ cmSystemTools::ExpandListArgument(installTypes, installTypesVector);
+ std::vector<std::string>::iterator installTypesIt;
+ for (installTypesIt = installTypesVector.begin();
+ installTypesIt != installTypesVector.end(); ++installTypesIt) {
+ component->InstallationTypes.push_back(
+ this->GetInstallationType(projectName, *installTypesIt));
+ }
+ }
+
+ // Determine the component dependencies.
+ const char* depends = this->GetOption(macroPrefix + "_DEPENDS");
+ if (depends && *depends) {
+ std::vector<std::string> dependsVector;
+ cmSystemTools::ExpandListArgument(depends, dependsVector);
+ std::vector<std::string>::iterator dependIt;
+ for (dependIt = dependsVector.begin(); dependIt != dependsVector.end();
+ ++dependIt) {
+ cmCPackComponent* child = GetComponent(projectName, *dependIt);
+ component->Dependencies.push_back(child);
+ child->ReverseDependencies.push_back(component);
+ }
+ }
+ }
+ return component;
+}
+
+cmCPackComponentGroup* cmCPackGenerator::GetComponentGroup(
+ const std::string& projectName, const std::string& name)
+{
+ (void)projectName;
+ std::string macroPrefix =
+ "CPACK_COMPONENT_GROUP_" + cmsys::SystemTools::UpperCase(name);
+ bool hasGroup = this->ComponentGroups.count(name) != 0;
+ cmCPackComponentGroup* group = &this->ComponentGroups[name];
+ if (!hasGroup) {
+ // Define the group
+ group->Name = name;
+ const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
+ if (displayName && *displayName) {
+ group->DisplayName = displayName;
+ } else {
+ group->DisplayName = group->Name;
+ }
+
+ const char* description = this->GetOption(macroPrefix + "_DESCRIPTION");
+ if (description && *description) {
+ group->Description = description;
+ }
+ group->IsBold = this->IsOn(macroPrefix + "_BOLD_TITLE");
+ group->IsExpandedByDefault = this->IsOn(macroPrefix + "_EXPANDED");
+ const char* parentGroupName =
+ this->GetOption(macroPrefix + "_PARENT_GROUP");
+ if (parentGroupName && *parentGroupName) {
+ group->ParentGroup = GetComponentGroup(projectName, parentGroupName);
+ group->ParentGroup->Subgroups.push_back(group);
+ } else {
+ group->ParentGroup = CM_NULLPTR;
+ }
+ }
+ return group;
+}
diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h
new file mode 100644
index 0000000..23e4bb7
--- /dev/null
+++ b/Source/CPack/cmCPackGenerator.h
@@ -0,0 +1,331 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackGenerator_h
+#define cmCPackGenerator_h
+
+#include "cmObject.h"
+
+#include "cmSystemTools.h"
+#include <map>
+#include <vector>
+
+#include "cmCPackComponentGroup.h" // cmCPackComponent and friends
+// Forward declarations are insufficient since we use them in
+// std::map data members below...
+
+#define cmCPackTypeMacro(klass, superclass) \
+ cmTypeMacro(klass, superclass); \
+ static cmCPackGenerator* CreateGenerator() { return new klass; } \
+ class cmCPackTypeMacro_UseTrailingSemicolon
+
+#define cmCPackLogger(logType, msg) \
+ do { \
+ std::ostringstream cmCPackLog_msg; \
+ cmCPackLog_msg << msg; \
+ this->Logger->Log(logType, __FILE__, __LINE__, \
+ cmCPackLog_msg.str().c_str()); \
+ } while (0)
+
+#ifdef cerr
+#undef cerr
+#endif
+#define cerr no_cerr_use_cmCPack_Log
+
+#ifdef cout
+#undef cout
+#endif
+#define cout no_cout_use_cmCPack_Log
+
+class cmMakefile;
+class cmCPackLog;
+class cmInstalledFile;
+
+/** \class cmCPackGenerator
+ * \brief A superclass of all CPack Generators
+ *
+ */
+class cmCPackGenerator : public cmObject
+{
+public:
+ cmTypeMacro(cmCPackGenerator, cmObject);
+ /**
+ * If verbose then more information is printed out
+ */
+ void SetVerbose(bool val)
+ {
+ this->GeneratorVerbose =
+ val ? cmSystemTools::OUTPUT_MERGE : cmSystemTools::OUTPUT_NONE;
+ }
+
+ /**
+ * Returns true if the generator may work on this system.
+ * Rational:
+ * Some CPack generator may run on some host and may not on others
+ * (with the same system) because some tools are missing. If the tool
+ * is missing then CPack won't activate (in the CPackGeneratorFactory)
+ * this particular generator.
+ */
+ static bool CanGenerate() { return true; }
+
+ /**
+ * Do the actual whole package processing.
+ * Subclass may redefine it but its usually enough
+ * to redefine @ref PackageFiles, because in fact
+ * this method do call:
+ * - PrepareName
+ * - clean-up temp dirs
+ * - InstallProject (with the appropriate method)
+ * - prepare list of files and/or components to be package
+ * - PackageFiles
+ * - Copy produced packages at the expected place
+ * @return 0 if error.
+ */
+ virtual int DoPackage();
+
+ /**
+ * Initialize generator
+ */
+ int Initialize(const std::string& name, cmMakefile* mf);
+
+ /**
+ * Construct generator
+ */
+ cmCPackGenerator();
+ ~cmCPackGenerator() CM_OVERRIDE;
+
+ //! Set and get the options
+ void SetOption(const std::string& op, const char* value);
+ void SetOptionIfNotSet(const std::string& op, const char* value);
+ const char* GetOption(const std::string& op) const;
+ std::vector<std::string> GetOptions() const;
+ bool IsSet(const std::string& name) const;
+ bool IsOn(const std::string& name) const;
+
+ //! Set the logger
+ void SetLogger(cmCPackLog* log) { this->Logger = log; }
+
+ //! Display verbose information via logger
+ void DisplayVerboseOutput(const char* msg, float progress);
+
+ bool ReadListFile(const char* moduleName);
+
+protected:
+ /**
+ * Prepare common used names by inspecting
+ * several CPACK_xxx var values.
+ */
+ int PrepareNames();
+
+ /**
+ * Install the project using appropriate method.
+ */
+ int InstallProject();
+
+ int CleanTemporaryDirectory();
+
+ cmInstalledFile const* GetInstalledFile(std::string const& name) const;
+
+ virtual const char* GetOutputExtension() { return ".cpack"; }
+ virtual const char* GetOutputPostfix() { return CM_NULLPTR; }
+
+ /**
+ * Prepare requested grouping kind from CPACK_xxx vars
+ * CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE
+ * CPACK_COMPONENTS_IGNORE_GROUPS
+ * or
+ * CPACK_COMPONENTS_ONE_PACKAGE_PER_GROUP
+ * @return 1 on success 0 on failure.
+ */
+ virtual int PrepareGroupingKind();
+
+ /**
+ * Some CPack generators may prefer to have
+ * CPack install all components belonging to the same
+ * [component] group to be install in the same directory.
+ * The default behavior is to install each component in
+ * a separate directory.
+ * @param[in] componentName the name of the component to be installed
+ * @return the name suffix the generator wants for the specified component
+ * default is "componentName"
+ */
+ virtual std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName);
+
+ /**
+ * CPack specific generator may mangle CPACK_PACKAGE_FILE_NAME
+ * with CPACK_COMPONENT_xxxx_<NAME>_DISPLAY_NAME if
+ * CPACK_<GEN>_USE_DISPLAY_NAME_IN_FILENAME is ON.
+ * @param[in] initialPackageFileName the initial package name to be mangled
+ * @param[in] groupOrComponentName the name of the group/component
+ * @param[in] isGroupName true if previous name refers to a group,
+ * false otherwise
+ */
+ virtual std::string GetComponentPackageFileName(
+ const std::string& initialPackageFileName,
+ const std::string& groupOrComponentName, bool isGroupName);
+
+ /**
+ * Package the list of files and/or components which
+ * has been prepared by the beginning of DoPackage.
+ * @pre the @ref toplevel has been filled-in
+ * @pre the list of file @ref files has been populated
+ * @pre packageFileNames contains at least 1 entry
+ * @post packageFileNames may have been updated and contains
+ * the list of packages generated by the specific generator.
+ */
+ virtual int PackageFiles();
+ virtual const char* GetInstallPath();
+ virtual const char* GetPackagingInstallPrefix();
+
+ virtual std::string FindTemplate(const char* name);
+ virtual bool ConfigureFile(const char* inName, const char* outName,
+ bool copyOnly = false);
+ virtual bool ConfigureString(const std::string& input, std::string& output);
+ virtual int InitializeInternal();
+
+ //! Run install commands if specified
+ virtual int InstallProjectViaInstallCommands(
+ bool setDestDir, const std::string& tempInstallDirectory);
+ virtual int InstallProjectViaInstallScript(
+ bool setDestDir, const std::string& tempInstallDirectory);
+ virtual int InstallProjectViaInstalledDirectories(
+ bool setDestDir, const std::string& tempInstallDirectory);
+ virtual int InstallProjectViaInstallCMakeProjects(
+ bool setDestDir, const std::string& tempInstallDirectory);
+
+ /**
+ * The various level of support of
+ * CPACK_SET_DESTDIR used by the generator.
+ */
+ enum CPackSetDestdirSupport
+ {
+ /* the generator works with or without it */
+ SETDESTDIR_SUPPORTED,
+ /* the generator works best if automatically handled */
+ SETDESTDIR_INTERNALLY_SUPPORTED,
+ /* no official support, use at your own risk */
+ SETDESTDIR_SHOULD_NOT_BE_USED,
+ /* officially NOT supported */
+ SETDESTDIR_UNSUPPORTED
+ };
+
+ /**
+ * Does the CPack generator support CPACK_SET_DESTDIR?
+ * The default legacy value is 'SETDESTDIR_SUPPORTED' generator
+ * have to override it in order change this.
+ * @return CPackSetDestdirSupport
+ */
+ virtual enum CPackSetDestdirSupport SupportsSetDestdir() const;
+
+ /**
+ * Does the CPack generator support absolute path
+ * in INSTALL DESTINATION?
+ * The default legacy value is 'true' generator
+ * have to override it in order change this.
+ * @return true if supported false otherwise
+ */
+ virtual bool SupportsAbsoluteDestination() const;
+
+ /**
+ * Does the CPack generator support component installation?.
+ * Some Generators requires the user to set
+ * CPACK_<GENNAME>_COMPONENT_INSTALL in order to make this
+ * method return true.
+ * @return true if supported, false otherwise
+ */
+ virtual bool SupportsComponentInstallation() const;
+ /**
+ * Does the currently running generator want a component installation.
+ * The generator may support component installation but he may
+ * be requiring monolithic install using CPACK_MONOLITHIC_INSTALL.
+ * @return true if component installation is supported and wanted.
+ */
+ virtual bool WantsComponentInstallation() const;
+ virtual cmCPackInstallationType* GetInstallationType(
+ const std::string& projectName, const std::string& name);
+ virtual cmCPackComponent* GetComponent(const std::string& projectName,
+ const std::string& name);
+ virtual cmCPackComponentGroup* GetComponentGroup(
+ const std::string& projectName, const std::string& name);
+
+ cmSystemTools::OutputOption GeneratorVerbose;
+ std::string Name;
+
+ std::string InstallPath;
+
+ /**
+ * The list of package file names.
+ * At beginning of DoPackage the (generic) generator will populate
+ * the list of desired package file names then it will
+ * call the redefined method PackageFiles which is may
+ * either use this set of names (usually on entry there should be
+ * only a single name) or update the vector with the list
+ * of created package file names.
+ */
+ std::vector<std::string> packageFileNames;
+
+ /**
+ * The directory where all the files to be packaged reside.
+ * If the installer support components there will be one
+ * sub-directory for each component. In those directories
+ * one will find the file belonging to the specified component.
+ */
+ std::string toplevel;
+
+ /**
+ * The complete list of files to be packaged.
+ * This list will be populated by DoPackage before
+ * PackageFiles is called.
+ */
+ std::vector<std::string> files;
+
+ std::map<std::string, cmCPackInstallationType> InstallationTypes;
+ /**
+ * The set of components.
+ * If component installation is supported then this map
+ * contains the component specified in CPACK_COMPONENTS_ALL
+ */
+ std::map<std::string, cmCPackComponent> Components;
+ std::map<std::string, cmCPackComponentGroup> ComponentGroups;
+
+ /**
+ * If components are enabled, this enum represents the different
+ * ways of mapping components to package files.
+ */
+ enum ComponentPackageMethod
+ {
+ /* one package for all components */
+ ONE_PACKAGE,
+ /* one package for each component */
+ ONE_PACKAGE_PER_COMPONENT,
+ /* one package for each group,
+ * with left over components in their own package */
+ ONE_PACKAGE_PER_GROUP,
+ UNKNOWN_COMPONENT_PACKAGE_METHOD
+ };
+
+ /**
+ * The component package method
+ * The default is ONE_PACKAGE_PER_GROUP,
+ * and generators may override the default
+ * before PrepareGroupingKind() is called.
+ */
+ ComponentPackageMethod componentPackageMethod;
+
+ cmCPackLog* Logger;
+
+private:
+ cmMakefile* MakefileMap;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx
new file mode 100644
index 0000000..0f0268f
--- /dev/null
+++ b/Source/CPack/cmCPackGeneratorFactory.cxx
@@ -0,0 +1,183 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackGeneratorFactory.h"
+
+#include "IFW/cmCPackIFWGenerator.h"
+#include "cmCPack7zGenerator.h"
+#include "cmCPackGenerator.h"
+#include "cmCPackNSISGenerator.h"
+#include "cmCPackSTGZGenerator.h"
+#include "cmCPackTGZGenerator.h"
+#include "cmCPackTXZGenerator.h"
+#include "cmCPackTarBZip2Generator.h"
+#include "cmCPackTarCompressGenerator.h"
+#include "cmCPackZIPGenerator.h"
+
+#ifdef __APPLE__
+#include "cmCPackBundleGenerator.h"
+#include "cmCPackDragNDropGenerator.h"
+#include "cmCPackOSXX11Generator.h"
+#include "cmCPackPackageMakerGenerator.h"
+#include "cmCPackProductBuildGenerator.h"
+#endif
+
+#ifdef __CYGWIN__
+#include "cmCPackCygwinBinaryGenerator.h"
+#include "cmCPackCygwinSourceGenerator.h"
+#endif
+
+#if !defined(_WIN32) && !defined(__QNXNTO__) && !defined(__BEOS__) && \
+ !defined(__HAIKU__)
+#include "cmCPackDebGenerator.h"
+#include "cmCPackRPMGenerator.h"
+#endif
+
+#ifdef _WIN32
+#include "WiX/cmCPackWIXGenerator.h"
+#endif
+
+#include "cmAlgorithms.h"
+#include "cmCPackLog.h"
+
+cmCPackGeneratorFactory::cmCPackGeneratorFactory()
+{
+ if (cmCPackTGZGenerator::CanGenerate()) {
+ this->RegisterGenerator("TGZ", "Tar GZip compression",
+ cmCPackTGZGenerator::CreateGenerator);
+ }
+ if (cmCPackTXZGenerator::CanGenerate()) {
+ this->RegisterGenerator("TXZ", "Tar XZ compression",
+ cmCPackTXZGenerator::CreateGenerator);
+ }
+ if (cmCPackSTGZGenerator::CanGenerate()) {
+ this->RegisterGenerator("STGZ", "Self extracting Tar GZip compression",
+ cmCPackSTGZGenerator::CreateGenerator);
+ }
+ if (cmCPackNSISGenerator::CanGenerate()) {
+ this->RegisterGenerator("NSIS", "Null Soft Installer",
+ cmCPackNSISGenerator::CreateGenerator);
+ this->RegisterGenerator("NSIS64", "Null Soft Installer (64-bit)",
+ cmCPackNSISGenerator::CreateGenerator64);
+ }
+ if (cmCPackIFWGenerator::CanGenerate()) {
+ this->RegisterGenerator("IFW", "Qt Installer Framework",
+ cmCPackIFWGenerator::CreateGenerator);
+ }
+#ifdef __CYGWIN__
+ if (cmCPackCygwinBinaryGenerator::CanGenerate()) {
+ this->RegisterGenerator("CygwinBinary", "Cygwin Binary Installer",
+ cmCPackCygwinBinaryGenerator::CreateGenerator);
+ }
+ if (cmCPackCygwinSourceGenerator::CanGenerate()) {
+ this->RegisterGenerator("CygwinSource", "Cygwin Source Installer",
+ cmCPackCygwinSourceGenerator::CreateGenerator);
+ }
+#endif
+
+ if (cmCPackZIPGenerator::CanGenerate()) {
+ this->RegisterGenerator("ZIP", "ZIP file format",
+ cmCPackZIPGenerator::CreateGenerator);
+ }
+ if (cmCPack7zGenerator::CanGenerate()) {
+ this->RegisterGenerator("7Z", "7-Zip file format",
+ cmCPack7zGenerator::CreateGenerator);
+ }
+#ifdef _WIN32
+ if (cmCPackWIXGenerator::CanGenerate()) {
+ this->RegisterGenerator("WIX", "MSI file format via WiX tools",
+ cmCPackWIXGenerator::CreateGenerator);
+ }
+#endif
+ if (cmCPackTarBZip2Generator::CanGenerate()) {
+ this->RegisterGenerator("TBZ2", "Tar BZip2 compression",
+ cmCPackTarBZip2Generator::CreateGenerator);
+ }
+ if (cmCPackTarCompressGenerator::CanGenerate()) {
+ this->RegisterGenerator("TZ", "Tar Compress compression",
+ cmCPackTarCompressGenerator::CreateGenerator);
+ }
+#ifdef __APPLE__
+ if (cmCPackDragNDropGenerator::CanGenerate()) {
+ this->RegisterGenerator("DragNDrop", "Mac OSX Drag And Drop",
+ cmCPackDragNDropGenerator::CreateGenerator);
+ }
+ if (cmCPackBundleGenerator::CanGenerate()) {
+ this->RegisterGenerator("Bundle", "Mac OSX bundle",
+ cmCPackBundleGenerator::CreateGenerator);
+ }
+ if (cmCPackPackageMakerGenerator::CanGenerate()) {
+ this->RegisterGenerator("PackageMaker", "Mac OSX Package Maker installer",
+ cmCPackPackageMakerGenerator::CreateGenerator);
+ }
+ if (cmCPackOSXX11Generator::CanGenerate()) {
+ this->RegisterGenerator("OSXX11", "Mac OSX X11 bundle",
+ cmCPackOSXX11Generator::CreateGenerator);
+ }
+ if (cmCPackProductBuildGenerator::CanGenerate()) {
+ this->RegisterGenerator("productbuild", "Mac OSX pkg",
+ cmCPackProductBuildGenerator::CreateGenerator);
+ }
+#endif
+#if !defined(_WIN32) && !defined(__QNXNTO__) && !defined(__BEOS__) && \
+ !defined(__HAIKU__)
+ if (cmCPackDebGenerator::CanGenerate()) {
+ this->RegisterGenerator("DEB", "Debian packages",
+ cmCPackDebGenerator::CreateGenerator);
+ }
+ if (cmCPackRPMGenerator::CanGenerate()) {
+ this->RegisterGenerator("RPM", "RPM packages",
+ cmCPackRPMGenerator::CreateGenerator);
+ }
+#endif
+}
+
+cmCPackGeneratorFactory::~cmCPackGeneratorFactory()
+{
+ cmDeleteAll(this->Generators);
+}
+
+cmCPackGenerator* cmCPackGeneratorFactory::NewGenerator(
+ const std::string& name)
+{
+ cmCPackGenerator* gen = this->NewGeneratorInternal(name);
+ if (!gen) {
+ return CM_NULLPTR;
+ }
+ this->Generators.push_back(gen);
+ gen->SetLogger(this->Logger);
+ return gen;
+}
+
+cmCPackGenerator* cmCPackGeneratorFactory::NewGeneratorInternal(
+ const std::string& name)
+{
+ cmCPackGeneratorFactory::t_GeneratorCreatorsMap::iterator it =
+ this->GeneratorCreators.find(name);
+ if (it == this->GeneratorCreators.end()) {
+ return CM_NULLPTR;
+ }
+ return (it->second)();
+}
+
+void cmCPackGeneratorFactory::RegisterGenerator(
+ const std::string& name, const char* generatorDescription,
+ CreateGeneratorCall* createGenerator)
+{
+ if (!createGenerator) {
+ cmCPack_Log(this->Logger, cmCPackLog::LOG_ERROR,
+ "Cannot register generator" << std::endl);
+ return;
+ }
+ this->GeneratorCreators[name] = createGenerator;
+ this->GeneratorDescriptions[name] = generatorDescription;
+}
diff --git a/Source/CPack/cmCPackGeneratorFactory.h b/Source/CPack/cmCPackGeneratorFactory.h
new file mode 100644
index 0000000..f0ed57a
--- /dev/null
+++ b/Source/CPack/cmCPackGeneratorFactory.h
@@ -0,0 +1,61 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackGeneratorFactory_h
+#define cmCPackGeneratorFactory_h
+
+#include "cmObject.h"
+
+class cmCPackLog;
+class cmCPackGenerator;
+
+/** \class cmCPackGeneratorFactory
+ * \brief A container for CPack generators
+ *
+ */
+class cmCPackGeneratorFactory : public cmObject
+{
+public:
+ cmTypeMacro(cmCPackGeneratorFactory, cmObject);
+
+ cmCPackGeneratorFactory();
+ ~cmCPackGeneratorFactory() CM_OVERRIDE;
+
+ //! Get the generator
+ cmCPackGenerator* NewGenerator(const std::string& name);
+ void DeleteGenerator(cmCPackGenerator* gen);
+
+ typedef cmCPackGenerator* CreateGeneratorCall();
+
+ void RegisterGenerator(const std::string& name,
+ const char* generatorDescription,
+ CreateGeneratorCall* createGenerator);
+
+ void SetLogger(cmCPackLog* logger) { this->Logger = logger; }
+
+ typedef std::map<std::string, std::string> DescriptionsMap;
+ const DescriptionsMap& GetGeneratorsList() const
+ {
+ return this->GeneratorDescriptions;
+ }
+
+private:
+ cmCPackGenerator* NewGeneratorInternal(const std::string& name);
+ std::vector<cmCPackGenerator*> Generators;
+
+ typedef std::map<std::string, CreateGeneratorCall*> t_GeneratorCreatorsMap;
+ t_GeneratorCreatorsMap GeneratorCreators;
+ DescriptionsMap GeneratorDescriptions;
+ cmCPackLog* Logger;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackLog.cxx b/Source/CPack/cmCPackLog.cxx
new file mode 100644
index 0000000..339323e
--- /dev/null
+++ b/Source/CPack/cmCPackLog.cxx
@@ -0,0 +1,190 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackLog.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmSystemTools.h"
+
+cmCPackLog::cmCPackLog()
+{
+ this->Verbose = false;
+ this->Debug = false;
+ this->Quiet = false;
+ this->NewLine = true;
+
+ this->LastTag = cmCPackLog::NOTAG;
+#undef cerr
+#undef cout
+ this->DefaultOutput = &std::cout;
+ this->DefaultError = &std::cerr;
+
+ this->LogOutput = CM_NULLPTR;
+ this->LogOutputCleanup = false;
+}
+
+cmCPackLog::~cmCPackLog()
+{
+ this->SetLogOutputStream(CM_NULLPTR);
+}
+
+void cmCPackLog::SetLogOutputStream(std::ostream* os)
+{
+ if (this->LogOutputCleanup && this->LogOutput) {
+ delete this->LogOutput;
+ }
+ this->LogOutputCleanup = false;
+ this->LogOutput = os;
+}
+
+bool cmCPackLog::SetLogOutputFile(const char* fname)
+{
+ cmGeneratedFileStream* cg = CM_NULLPTR;
+ if (fname) {
+ cg = new cmGeneratedFileStream(fname);
+ }
+ if (cg && !*cg) {
+ delete cg;
+ cg = CM_NULLPTR;
+ }
+ this->SetLogOutputStream(cg);
+ if (!cg) {
+ return false;
+ }
+ this->LogOutputCleanup = true;
+ return true;
+}
+
+void cmCPackLog::Log(int tag, const char* file, int line, const char* msg,
+ size_t length)
+{
+ // By default no logging
+ bool display = false;
+
+ // Display file and line number if debug
+ bool useFileAndLine = this->Debug;
+
+ bool output = false;
+ bool debug = false;
+ bool warning = false;
+ bool error = false;
+ bool verbose = false;
+
+ // When writing in file, add list of tags whenever tag changes.
+ std::string tagString;
+ bool needTagString = false;
+ if (this->LogOutput && this->LastTag != tag) {
+ needTagString = true;
+ }
+
+ if (tag & LOG_OUTPUT) {
+ output = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString = "VERBOSE";
+ }
+ }
+ if (tag & LOG_WARNING) {
+ warning = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString = "WARNING";
+ }
+ }
+ if (tag & LOG_ERROR) {
+ error = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString = "ERROR";
+ }
+ }
+ if (tag & LOG_DEBUG && this->Debug) {
+ debug = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString = "DEBUG";
+ }
+ useFileAndLine = true;
+ }
+ if (tag & LOG_VERBOSE && this->Verbose) {
+ verbose = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString = "VERBOSE";
+ }
+ }
+ if (this->Quiet) {
+ display = false;
+ }
+ if (this->LogOutput) {
+ if (needTagString) {
+ *this->LogOutput << "[" << file << ":" << line << " " << tagString
+ << "] ";
+ }
+ this->LogOutput->write(msg, length);
+ }
+ this->LastTag = tag;
+ if (!display) {
+ return;
+ }
+ if (this->NewLine) {
+ if (error && !this->ErrorPrefix.empty()) {
+ *this->DefaultError << this->ErrorPrefix;
+ } else if (warning && !this->WarningPrefix.empty()) {
+ *this->DefaultError << this->WarningPrefix;
+ } else if (output && !this->OutputPrefix.empty()) {
+ *this->DefaultOutput << this->OutputPrefix;
+ } else if (verbose && !this->VerbosePrefix.empty()) {
+ *this->DefaultOutput << this->VerbosePrefix;
+ } else if (debug && !this->DebugPrefix.empty()) {
+ *this->DefaultOutput << this->DebugPrefix;
+ } else if (!this->Prefix.empty()) {
+ *this->DefaultOutput << this->Prefix;
+ }
+ if (useFileAndLine) {
+ if (error || warning) {
+ *this->DefaultError << file << ":" << line << " ";
+ } else {
+ *this->DefaultOutput << file << ":" << line << " ";
+ }
+ }
+ }
+ if (error || warning) {
+ this->DefaultError->write(msg, length);
+ this->DefaultError->flush();
+ } else {
+ this->DefaultOutput->write(msg, length);
+ this->DefaultOutput->flush();
+ }
+ if (msg[length - 1] == '\n' || length > 2) {
+ this->NewLine = true;
+ }
+
+ if (error) {
+ cmSystemTools::SetErrorOccured();
+ }
+}
diff --git a/Source/CPack/cmCPackLog.h b/Source/CPack/cmCPackLog.h
new file mode 100644
index 0000000..77f0f0b
--- /dev/null
+++ b/Source/CPack/cmCPackLog.h
@@ -0,0 +1,158 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackLog_h
+#define cmCPackLog_h
+
+#include "cmObject.h"
+
+#define cmCPack_Log(ctSelf, logType, msg) \
+ do { \
+ std::ostringstream cmCPackLog_msg; \
+ cmCPackLog_msg << msg; \
+ (ctSelf)->Log(logType, __FILE__, __LINE__, cmCPackLog_msg.str().c_str()); \
+ } while (0)
+
+#ifdef cerr
+#undef cerr
+#endif
+#define cerr no_cerr_use_cmCPack_Log
+
+#ifdef cout
+#undef cout
+#endif
+#define cout no_cout_use_cmCPack_Log
+
+/** \class cmCPackLog
+ * \brief A container for CPack generators
+ *
+ */
+class cmCPackLog : public cmObject
+{
+public:
+ cmTypeMacro(cmCPackLog, cmObject);
+
+ cmCPackLog();
+ ~cmCPackLog() CM_OVERRIDE;
+
+ enum __log_tags
+ {
+ NOTAG = 0,
+ LOG_OUTPUT = 0x1,
+ LOG_VERBOSE = 0x2,
+ LOG_DEBUG = 0x4,
+ LOG_WARNING = 0x8,
+ LOG_ERROR = 0x10
+ };
+
+ //! Various signatures for logging.
+ void Log(const char* file, int line, const char* msg)
+ {
+ this->Log(LOG_OUTPUT, file, line, msg);
+ }
+ void Log(const char* file, int line, const char* msg, size_t length)
+ {
+ this->Log(LOG_OUTPUT, file, line, msg, length);
+ }
+ void Log(int tag, const char* file, int line, const char* msg)
+ {
+ this->Log(tag, file, line, msg, strlen(msg));
+ }
+ void Log(int tag, const char* file, int line, const char* msg,
+ size_t length);
+
+ //! Set Verbose
+ void VerboseOn() { this->SetVerbose(true); }
+ void VerboseOff() { this->SetVerbose(true); }
+ void SetVerbose(bool verb) { this->Verbose = verb; }
+ bool GetVerbose() { return this->Verbose; }
+
+ //! Set Debug
+ void DebugOn() { this->SetDebug(true); }
+ void DebugOff() { this->SetDebug(true); }
+ void SetDebug(bool verb) { this->Debug = verb; }
+ bool GetDebug() { return this->Debug; }
+
+ //! Set Quiet
+ void QuietOn() { this->SetQuiet(true); }
+ void QuietOff() { this->SetQuiet(true); }
+ void SetQuiet(bool verb) { this->Quiet = verb; }
+ bool GetQuiet() { return this->Quiet; }
+
+ //! Set the output stream
+ void SetOutputStream(std::ostream* os) { this->DefaultOutput = os; }
+
+ //! Set the error stream
+ void SetErrorStream(std::ostream* os) { this->DefaultError = os; }
+
+ //! Set the log output stream
+ void SetLogOutputStream(std::ostream* os);
+
+ //! Set the log output file. The cmCPackLog will try to create file. If it
+ // cannot, it will report an error.
+ bool SetLogOutputFile(const char* fname);
+
+ //! Set the various prefixes for the logging. SetPrefix sets the generic
+ // prefix that overwrittes missing ones.
+ void SetPrefix(std::string pfx) { this->Prefix = pfx; }
+ void SetOutputPrefix(std::string pfx) { this->OutputPrefix = pfx; }
+ void SetVerbosePrefix(std::string pfx) { this->VerbosePrefix = pfx; }
+ void SetDebugPrefix(std::string pfx) { this->DebugPrefix = pfx; }
+ void SetWarningPrefix(std::string pfx) { this->WarningPrefix = pfx; }
+ void SetErrorPrefix(std::string pfx) { this->ErrorPrefix = pfx; }
+
+private:
+ bool Verbose;
+ bool Debug;
+ bool Quiet;
+
+ bool NewLine;
+
+ int LastTag;
+
+ std::string Prefix;
+ std::string OutputPrefix;
+ std::string VerbosePrefix;
+ std::string DebugPrefix;
+ std::string WarningPrefix;
+ std::string ErrorPrefix;
+
+ std::ostream* DefaultOutput;
+ std::ostream* DefaultError;
+
+ std::string LogOutputFileName;
+ std::ostream* LogOutput;
+ // Do we need to cleanup log output stream
+ bool LogOutputCleanup;
+};
+
+class cmCPackLogWrite
+{
+public:
+ cmCPackLogWrite(const char* data, size_t length)
+ : Data(data)
+ , Length(length)
+ {
+ }
+
+ const char* Data;
+ size_t Length;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const cmCPackLogWrite& c)
+{
+ os.write(c.Data, c.Length);
+ os.flush();
+ return os;
+}
+
+#endif
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
new file mode 100644
index 0000000..d8ff907
--- /dev/null
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -0,0 +1,918 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackNSISGenerator.h"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include <cmsys/Directory.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/RegularExpression.hxx>
+#include <cmsys/SystemTools.hxx>
+
+/* NSIS uses different command line syntax on Windows and others */
+#ifdef _WIN32
+#define NSIS_OPT "/"
+#else
+#define NSIS_OPT "-"
+#endif
+
+cmCPackNSISGenerator::cmCPackNSISGenerator(bool nsis64)
+{
+ Nsis64 = nsis64;
+}
+
+cmCPackNSISGenerator::~cmCPackNSISGenerator()
+{
+}
+
+int cmCPackNSISGenerator::PackageFiles()
+{
+ // TODO: Fix nsis to force out file name
+
+ std::string nsisInFileName = this->FindTemplate("NSIS.template.in");
+ if (nsisInFileName.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPack error: Could not find NSIS installer template file."
+ << std::endl);
+ return false;
+ }
+ std::string nsisInInstallOptions =
+ this->FindTemplate("NSIS.InstallOptions.ini.in");
+ if (nsisInInstallOptions.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPack error: Could not find NSIS installer options file."
+ << std::endl);
+ return false;
+ }
+
+ std::string nsisFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ std::string tmpFile = nsisFileName;
+ tmpFile += "/NSISOutput.log";
+ std::string nsisInstallOptions = nsisFileName + "/NSIS.InstallOptions.ini";
+ nsisFileName += "/project.nsi";
+ std::ostringstream str;
+ std::vector<std::string>::const_iterator it;
+ for (it = files.begin(); it != files.end(); ++it) {
+ std::string fileN =
+ cmSystemTools::RelativePath(toplevel.c_str(), it->c_str());
+ if (!this->Components.empty()) {
+ // Strip off the component part of the path.
+ fileN = fileN.substr(fileN.find('/') + 1, std::string::npos);
+ }
+ std::replace(fileN.begin(), fileN.end(), '/', '\\');
+ str << " Delete \"$INSTDIR\\" << fileN << "\"" << std::endl;
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Uninstall Files: " << str.str()
+ << std::endl);
+ this->SetOptionIfNotSet("CPACK_NSIS_DELETE_FILES", str.str().c_str());
+ std::vector<std::string> dirs;
+ this->GetListOfSubdirectories(toplevel.c_str(), dirs);
+ std::vector<std::string>::const_iterator sit;
+ std::ostringstream dstr;
+ for (sit = dirs.begin(); sit != dirs.end(); ++sit) {
+ std::string componentName;
+ std::string fileN =
+ cmSystemTools::RelativePath(toplevel.c_str(), sit->c_str());
+ if (fileN.empty()) {
+ continue;
+ }
+ if (!Components.empty()) {
+ // If this is a component installation, strip off the component
+ // part of the path.
+ std::string::size_type slash = fileN.find('/');
+ if (slash != std::string::npos) {
+ // If this is a component installation, determine which component it
+ // is.
+ componentName = fileN.substr(0, slash);
+
+ // Strip off the component part of the path.
+ fileN = fileN.substr(slash + 1, std::string::npos);
+ }
+ }
+ std::replace(fileN.begin(), fileN.end(), '/', '\\');
+ dstr << " RMDir \"$INSTDIR\\" << fileN << "\"" << std::endl;
+ if (!componentName.empty()) {
+ this->Components[componentName].Directories.push_back(fileN);
+ }
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Uninstall Dirs: " << dstr.str()
+ << std::endl);
+ this->SetOptionIfNotSet("CPACK_NSIS_DELETE_DIRECTORIES", dstr.str().c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
+ << nsisInFileName << " to " << nsisFileName << std::endl);
+ if (this->IsSet("CPACK_NSIS_MUI_ICON") ||
+ this->IsSet("CPACK_NSIS_MUI_UNIICON")) {
+ std::string installerIconCode;
+ if (this->IsSet("CPACK_NSIS_MUI_ICON")) {
+ installerIconCode += "!define MUI_ICON \"";
+ installerIconCode += this->GetOption("CPACK_NSIS_MUI_ICON");
+ installerIconCode += "\"\n";
+ }
+ if (this->IsSet("CPACK_NSIS_MUI_UNIICON")) {
+ installerIconCode += "!define MUI_UNICON \"";
+ installerIconCode += this->GetOption("CPACK_NSIS_MUI_UNIICON");
+ installerIconCode += "\"\n";
+ }
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_ICON_CODE",
+ installerIconCode.c_str());
+ }
+ if (this->IsSet("CPACK_PACKAGE_ICON")) {
+ std::string installerIconCode = "!define MUI_HEADERIMAGE_BITMAP \"";
+ installerIconCode += this->GetOption("CPACK_PACKAGE_ICON");
+ installerIconCode += "\"\n";
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_ICON_CODE",
+ installerIconCode.c_str());
+ }
+
+ if (this->IsSet("CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP")) {
+ std::string installerBitmapCode =
+ "!define MUI_WELCOMEFINISHPAGE_BITMAP \"";
+ installerBitmapCode +=
+ this->GetOption("CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP");
+ installerBitmapCode += "\"\n";
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_WELCOMEFINISH_CODE",
+ installerBitmapCode.c_str());
+ }
+
+ if (this->IsSet("CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP")) {
+ std::string installerBitmapCode =
+ "!define MUI_UNWELCOMEFINISHPAGE_BITMAP \"";
+ installerBitmapCode +=
+ this->GetOption("CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP");
+ installerBitmapCode += "\"\n";
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_UNWELCOMEFINISH_CODE",
+ installerBitmapCode.c_str());
+ }
+
+ if (this->IsSet("CPACK_NSIS_MUI_FINISHPAGE_RUN")) {
+ std::string installerRunCode = "!define MUI_FINISHPAGE_RUN \"$INSTDIR\\";
+ installerRunCode += this->GetOption("CPACK_NSIS_EXECUTABLES_DIRECTORY");
+ installerRunCode += "\\";
+ installerRunCode += this->GetOption("CPACK_NSIS_MUI_FINISHPAGE_RUN");
+ installerRunCode += "\"\n";
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE",
+ installerRunCode.c_str());
+ }
+
+ // Setup all of the component sections
+ if (this->Components.empty()) {
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_PAGE_COMPONENTS", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_FULL_INSTALL",
+ "File /r \"${INST_DIR}\\*.*\"");
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTIONS", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTION_LIST", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_SECTION_SELECTED_VARS", "");
+ } else {
+ std::string componentCode;
+ std::string sectionList;
+ std::string selectedVarsList;
+ std::string componentDescriptions;
+ std::string groupDescriptions;
+ std::string installTypesCode;
+ std::string defines;
+ std::ostringstream macrosOut;
+ bool anyDownloadedComponents = false;
+
+ // Create installation types. The order is significant, so we first fill
+ // in a vector based on the indices, and print them in that order.
+ std::vector<cmCPackInstallationType*> installTypes(
+ this->InstallationTypes.size());
+ std::map<std::string, cmCPackInstallationType>::iterator installTypeIt;
+ for (installTypeIt = this->InstallationTypes.begin();
+ installTypeIt != this->InstallationTypes.end(); ++installTypeIt) {
+ installTypes[installTypeIt->second.Index - 1] = &installTypeIt->second;
+ }
+ std::vector<cmCPackInstallationType*>::iterator installTypeIt2;
+ for (installTypeIt2 = installTypes.begin();
+ installTypeIt2 != installTypes.end(); ++installTypeIt2) {
+ installTypesCode += "InstType \"";
+ installTypesCode += (*installTypeIt2)->DisplayName;
+ installTypesCode += "\"\n";
+ }
+
+ // Create installation groups first
+ std::map<std::string, cmCPackComponentGroup>::iterator groupIt;
+ for (groupIt = this->ComponentGroups.begin();
+ groupIt != this->ComponentGroups.end(); ++groupIt) {
+ if (groupIt->second.ParentGroup == CM_NULLPTR) {
+ componentCode +=
+ this->CreateComponentGroupDescription(&groupIt->second, macrosOut);
+ }
+
+ // Add the group description, if any.
+ if (!groupIt->second.Description.empty()) {
+ groupDescriptions += " !insertmacro MUI_DESCRIPTION_TEXT ${" +
+ groupIt->first + "} \"" +
+ this->TranslateNewlines(groupIt->second.Description) + "\"\n";
+ }
+ }
+
+ // Create the remaining components, which aren't associated with groups.
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ if (compIt->second.Files.empty()) {
+ // NSIS cannot cope with components that have no files.
+ continue;
+ }
+
+ anyDownloadedComponents =
+ anyDownloadedComponents || compIt->second.IsDownloaded;
+
+ if (!compIt->second.Group) {
+ componentCode +=
+ this->CreateComponentDescription(&compIt->second, macrosOut);
+ }
+
+ // Add this component to the various section lists.
+ sectionList += " !insertmacro \"${MacroName}\" \"";
+ sectionList += compIt->first;
+ sectionList += "\"\n";
+ selectedVarsList += "Var " + compIt->first + "_selected\n";
+ selectedVarsList += "Var " + compIt->first + "_was_installed\n";
+
+ // Add the component description, if any.
+ if (!compIt->second.Description.empty()) {
+ componentDescriptions += " !insertmacro MUI_DESCRIPTION_TEXT ${" +
+ compIt->first + "} \"" +
+ this->TranslateNewlines(compIt->second.Description) + "\"\n";
+ }
+ }
+
+ componentCode += macrosOut.str();
+
+ if (componentDescriptions.empty() && groupDescriptions.empty()) {
+ // Turn off the "Description" box
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC",
+ "!define MUI_COMPONENTSPAGE_NODESC");
+ } else {
+ componentDescriptions = "!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN\n" +
+ componentDescriptions + groupDescriptions +
+ "!insertmacro MUI_FUNCTION_DESCRIPTION_END\n";
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC",
+ componentDescriptions.c_str());
+ }
+
+ if (anyDownloadedComponents) {
+ defines += "!define CPACK_USES_DOWNLOAD\n";
+ if (cmSystemTools::IsOn(this->GetOption("CPACK_ADD_REMOVE"))) {
+ defines += "!define CPACK_NSIS_ADD_REMOVE\n";
+ }
+ }
+
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES",
+ installTypesCode.c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_PAGE_COMPONENTS",
+ "!insertmacro MUI_PAGE_COMPONENTS");
+ this->SetOptionIfNotSet("CPACK_NSIS_FULL_INSTALL", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTIONS",
+ componentCode.c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTION_LIST",
+ sectionList.c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_SECTION_SELECTED_VARS",
+ selectedVarsList.c_str());
+ this->SetOption("CPACK_NSIS_DEFINES", defines.c_str());
+ }
+
+ this->ConfigureFile(nsisInInstallOptions.c_str(),
+ nsisInstallOptions.c_str());
+ this->ConfigureFile(nsisInFileName.c_str(), nsisFileName.c_str());
+ std::string nsisCmd = "\"";
+ nsisCmd += this->GetOption("CPACK_INSTALLER_PROGRAM");
+ nsisCmd += "\" \"" + nsisFileName + "\"";
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << nsisCmd << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool res =
+ cmSystemTools::RunSingleCommand(nsisCmd.c_str(), &output, &output, &retVal,
+ CM_NULLPTR, this->GeneratorVerbose, 0);
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << nsisCmd << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running NSIS command: "
+ << nsisCmd << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+ return 1;
+}
+
+int cmCPackNSISGenerator::InitializeInternal()
+{
+ if (cmSystemTools::IsOn(
+ this->GetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY"))) {
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING,
+ "NSIS Generator cannot work with CPACK_INCLUDE_TOPLEVEL_DIRECTORY set. "
+ "This option will be reset to 0 (for this generator only)."
+ << std::endl);
+ this->SetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", CM_NULLPTR);
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "cmCPackNSISGenerator::Initialize()"
+ << std::endl);
+ std::vector<std::string> path;
+ std::string nsisPath;
+ bool gotRegValue = false;
+
+#ifdef _WIN32
+ if (Nsis64) {
+ if (!gotRegValue && cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS\\Unicode",
+ nsisPath, cmsys::SystemTools::KeyWOW64_64)) {
+ gotRegValue = true;
+ }
+ if (!gotRegValue && cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS", nsisPath,
+ cmsys::SystemTools::KeyWOW64_64)) {
+ gotRegValue = true;
+ }
+ }
+ if (!gotRegValue && cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS\\Unicode",
+ nsisPath, cmsys::SystemTools::KeyWOW64_32)) {
+ gotRegValue = true;
+ }
+ if (!gotRegValue &&
+ cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS\\Unicode", nsisPath)) {
+ gotRegValue = true;
+ }
+ if (!gotRegValue && cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS", nsisPath,
+ cmsys::SystemTools::KeyWOW64_32)) {
+ gotRegValue = true;
+ }
+ if (!gotRegValue && cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS", nsisPath)) {
+ gotRegValue = true;
+ }
+
+ if (gotRegValue) {
+ path.push_back(nsisPath);
+ }
+#endif
+
+ nsisPath = cmSystemTools::FindProgram("makensis", path, false);
+
+ if (nsisPath.empty()) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Cannot find NSIS compiler makensis: likely it is not installed, "
+ "or not in your PATH"
+ << std::endl);
+
+ if (!gotRegValue) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Could not read NSIS registry value. This is usually caused by "
+ "NSIS not being installed. Please install NSIS from "
+ "http://nsis.sourceforge.net"
+ << std::endl);
+ }
+
+ return 0;
+ }
+
+ std::string nsisCmd = "\"" + nsisPath + "\" " NSIS_OPT "VERSION";
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Test NSIS version: " << nsisCmd
+ << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool resS =
+ cmSystemTools::RunSingleCommand(nsisCmd.c_str(), &output, &output, &retVal,
+ CM_NULLPTR, this->GeneratorVerbose, 0);
+ cmsys::RegularExpression versionRex("v([0-9]+.[0-9]+)");
+ cmsys::RegularExpression versionRexCVS("v(.*)\\.cvs");
+ if (!resS || retVal ||
+ (!versionRex.find(output) && !versionRexCVS.find(output))) {
+ const char* topDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ std::string tmpFile = topDir ? topDir : ".";
+ tmpFile += "/NSISOutput.log";
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << nsisCmd << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR, "Problem checking NSIS version with command: "
+ << nsisCmd << std::endl
+ << "Please check " << tmpFile << " for errors" << std::endl);
+ return 0;
+ }
+ if (versionRex.find(output)) {
+ double nsisVersion = atof(versionRex.match(1).c_str());
+ double minNSISVersion = 2.09;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "NSIS Version: " << nsisVersion
+ << std::endl);
+ if (nsisVersion < minNSISVersion) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPack requires NSIS Version 2.09 or greater. "
+ "NSIS found on the system was: "
+ << nsisVersion << std::endl);
+ return 0;
+ }
+ }
+ if (versionRexCVS.find(output)) {
+ // No version check for NSIS cvs build
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "NSIS Version: CVS "
+ << versionRexCVS.match(1) << std::endl);
+ }
+ this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", nsisPath.c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_EXECUTABLES_DIRECTORY", "bin");
+ const char* cpackPackageExecutables =
+ this->GetOption("CPACK_PACKAGE_EXECUTABLES");
+ const char* cpackPackageDeskTopLinks =
+ this->GetOption("CPACK_CREATE_DESKTOP_LINKS");
+ const char* cpackNsisExecutablesDirectory =
+ this->GetOption("CPACK_NSIS_EXECUTABLES_DIRECTORY");
+ std::vector<std::string> cpackPackageDesktopLinksVector;
+ if (cpackPackageDeskTopLinks) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "CPACK_CREATE_DESKTOP_LINKS: "
+ << cpackPackageDeskTopLinks << std::endl);
+
+ cmSystemTools::ExpandListArgument(cpackPackageDeskTopLinks,
+ cpackPackageDesktopLinksVector);
+ for (std::vector<std::string>::iterator i =
+ cpackPackageDesktopLinksVector.begin();
+ i != cpackPackageDesktopLinksVector.end(); ++i) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "CPACK_CREATE_DESKTOP_LINKS: " << *i << std::endl);
+ }
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "CPACK_CREATE_DESKTOP_LINKS: "
+ << "not set" << std::endl);
+ }
+
+ std::ostringstream str;
+ std::ostringstream deleteStr;
+
+ if (cpackPackageExecutables) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "The cpackPackageExecutables: "
+ << cpackPackageExecutables << "." << std::endl);
+ std::vector<std::string> cpackPackageExecutablesVector;
+ cmSystemTools::ExpandListArgument(cpackPackageExecutables,
+ cpackPackageExecutablesVector);
+ if (cpackPackageExecutablesVector.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
+ "<icon name>."
+ << std::endl);
+ return 0;
+ }
+ std::vector<std::string>::iterator it;
+ for (it = cpackPackageExecutablesVector.begin();
+ it != cpackPackageExecutablesVector.end(); ++it) {
+ std::string execName = *it;
+ ++it;
+ std::string linkName = *it;
+ str << " CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
+ << ".lnk\" \"$INSTDIR\\" << cpackNsisExecutablesDirectory << "\\"
+ << execName << ".exe\"" << std::endl;
+ deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+ << ".lnk\"" << std::endl;
+ // see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
+ // if so add a desktop link
+ if (!cpackPackageDesktopLinksVector.empty() &&
+ std::find(cpackPackageDesktopLinksVector.begin(),
+ cpackPackageDesktopLinksVector.end(),
+ execName) != cpackPackageDesktopLinksVector.end()) {
+ str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
+ str << " CreateShortCut \"$DESKTOP\\" << linkName
+ << ".lnk\" \"$INSTDIR\\" << cpackNsisExecutablesDirectory << "\\"
+ << execName << ".exe\"" << std::endl;
+ deleteStr << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
+ deleteStr << " Delete \"$DESKTOP\\" << linkName << ".lnk\""
+ << std::endl;
+ }
+ }
+ }
+
+ this->CreateMenuLinks(str, deleteStr);
+ this->SetOptionIfNotSet("CPACK_NSIS_CREATE_ICONS", str.str().c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_DELETE_ICONS", deleteStr.str().c_str());
+
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPRESSOR", "lzma");
+
+ return this->Superclass::InitializeInternal();
+}
+
+void cmCPackNSISGenerator::CreateMenuLinks(std::ostream& str,
+ std::ostream& deleteStr)
+{
+ const char* cpackMenuLinks = this->GetOption("CPACK_NSIS_MENU_LINKS");
+ if (!cpackMenuLinks) {
+ return;
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "The cpackMenuLinks: " << cpackMenuLinks << "." << std::endl);
+ std::vector<std::string> cpackMenuLinksVector;
+ cmSystemTools::ExpandListArgument(cpackMenuLinks, cpackMenuLinksVector);
+ if (cpackMenuLinksVector.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_NSIS_MENU_LINKS should contain pairs of <shortcut target> and "
+ "<shortcut label>."
+ << std::endl);
+ return;
+ }
+
+ static cmsys::RegularExpression urlRegex(
+ "^(mailto:|(ftps?|https?|news)://).*$");
+
+ std::vector<std::string>::iterator it;
+ for (it = cpackMenuLinksVector.begin(); it != cpackMenuLinksVector.end();
+ ++it) {
+ std::string sourceName = *it;
+ const bool url = urlRegex.find(sourceName);
+
+ // Convert / to \ in filenames, but not in urls:
+ //
+ if (!url) {
+ std::replace(sourceName.begin(), sourceName.end(), '/', '\\');
+ }
+
+ ++it;
+ std::string linkName = *it;
+ if (!url) {
+ str << " CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
+ << ".lnk\" \"$INSTDIR\\" << sourceName << "\"" << std::endl;
+ deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+ << ".lnk\"" << std::endl;
+ } else {
+ str << " WriteINIStr \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
+ << ".url\" \"InternetShortcut\" \"URL\" \"" << sourceName << "\""
+ << std::endl;
+ deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+ << ".url\"" << std::endl;
+ }
+ // see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
+ // if so add a desktop link
+ std::string desktop = "CPACK_CREATE_DESKTOP_LINK_";
+ desktop += linkName;
+ if (this->IsSet(desktop)) {
+ str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
+ str << " CreateShortCut \"$DESKTOP\\" << linkName
+ << ".lnk\" \"$INSTDIR\\" << sourceName << "\"" << std::endl;
+ deleteStr << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
+ deleteStr << " Delete \"$DESKTOP\\" << linkName << ".lnk\""
+ << std::endl;
+ }
+ }
+}
+
+bool cmCPackNSISGenerator::GetListOfSubdirectories(
+ const char* topdir, std::vector<std::string>& dirs)
+{
+ cmsys::Directory dir;
+ dir.Load(topdir);
+ size_t fileNum;
+ for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) {
+ if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") &&
+ strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..")) {
+ std::string fullPath = topdir;
+ fullPath += "/";
+ fullPath += dir.GetFile(static_cast<unsigned long>(fileNum));
+ if (cmsys::SystemTools::FileIsDirectory(fullPath) &&
+ !cmsys::SystemTools::FileIsSymlink(fullPath)) {
+ if (!this->GetListOfSubdirectories(fullPath.c_str(), dirs)) {
+ return false;
+ }
+ }
+ }
+ }
+ dirs.push_back(topdir);
+ return true;
+}
+
+enum cmCPackGenerator::CPackSetDestdirSupport
+cmCPackNSISGenerator::SupportsSetDestdir() const
+{
+ return cmCPackGenerator::SETDESTDIR_SHOULD_NOT_BE_USED;
+}
+
+bool cmCPackNSISGenerator::SupportsAbsoluteDestination() const
+{
+ return false;
+}
+
+bool cmCPackNSISGenerator::SupportsComponentInstallation() const
+{
+ return true;
+}
+
+std::string cmCPackNSISGenerator::CreateComponentDescription(
+ cmCPackComponent* component, std::ostream& macrosOut)
+{
+ // Basic description of the component
+ std::string componentCode = "Section ";
+ if (component->IsDisabledByDefault) {
+ componentCode += "/o ";
+ }
+ componentCode += "\"";
+ if (component->IsHidden) {
+ componentCode += "-";
+ }
+ componentCode += component->DisplayName + "\" " + component->Name + "\n";
+ if (component->IsRequired) {
+ componentCode += " SectionIn RO\n";
+ } else if (!component->InstallationTypes.empty()) {
+ std::ostringstream out;
+ std::vector<cmCPackInstallationType*>::iterator installTypeIter;
+ for (installTypeIter = component->InstallationTypes.begin();
+ installTypeIter != component->InstallationTypes.end();
+ ++installTypeIter) {
+ out << " " << (*installTypeIter)->Index;
+ }
+ componentCode += " SectionIn" + out.str() + "\n";
+ }
+ componentCode += " SetOutPath \"$INSTDIR\"\n";
+
+ // Create the actual installation commands
+ if (component->IsDownloaded) {
+ if (component->ArchiveFile.empty()) {
+ // Compute the name of the archive.
+ std::string packagesDir = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ packagesDir += ".dummy";
+ std::ostringstream out;
+ out << cmSystemTools::GetFilenameWithoutLastExtension(packagesDir) << "-"
+ << component->Name << ".zip";
+ component->ArchiveFile = out.str();
+ }
+
+ // Create the directory for the upload area
+ const char* userUploadDirectory =
+ this->GetOption("CPACK_UPLOAD_DIRECTORY");
+ std::string uploadDirectory;
+ if (userUploadDirectory && *userUploadDirectory) {
+ uploadDirectory = userUploadDirectory;
+ } else {
+ uploadDirectory = this->GetOption("CPACK_PACKAGE_DIRECTORY");
+ uploadDirectory += "/CPackUploads";
+ }
+ if (!cmSystemTools::FileExists(uploadDirectory.c_str())) {
+ if (!cmSystemTools::MakeDirectory(uploadDirectory.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Unable to create NSIS upload directory "
+ << uploadDirectory << std::endl);
+ return "";
+ }
+ }
+
+ // Remove the old archive, if one exists
+ std::string archiveFile = uploadDirectory + '/' + component->ArchiveFile;
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Building downloaded component archive: " << archiveFile
+ << std::endl);
+ if (cmSystemTools::FileExists(archiveFile.c_str(), true)) {
+ if (!cmSystemTools::RemoveFile(archiveFile)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Unable to remove archive file "
+ << archiveFile << std::endl);
+ return "";
+ }
+ }
+
+ // Find a ZIP program
+ if (!this->IsSet("ZIP_EXECUTABLE")) {
+ this->ReadListFile("CPackZIP.cmake");
+
+ if (!this->IsSet("ZIP_EXECUTABLE")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Unable to find ZIP program"
+ << std::endl);
+ return "";
+ }
+ }
+
+ // The directory where this component's files reside
+ std::string dirName = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ dirName += '/';
+ dirName += component->Name;
+ dirName += '/';
+
+ // Build the list of files to go into this archive, and determine the
+ // size of the installed component.
+ std::string zipListFileName = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ zipListFileName += "/winZip.filelist";
+ bool needQuotesInFile =
+ cmSystemTools::IsOn(this->GetOption("CPACK_ZIP_NEED_QUOTES"));
+ unsigned long totalSize = 0;
+ { // the scope is needed for cmGeneratedFileStream
+ cmGeneratedFileStream out(zipListFileName.c_str());
+ std::vector<std::string>::iterator fileIt;
+ for (fileIt = component->Files.begin(); fileIt != component->Files.end();
+ ++fileIt) {
+ if (needQuotesInFile) {
+ out << "\"";
+ }
+ out << *fileIt;
+ if (needQuotesInFile) {
+ out << "\"";
+ }
+ out << std::endl;
+
+ totalSize += cmSystemTools::FileLength(dirName + *fileIt);
+ }
+ }
+
+ // Build the archive in the upload area
+ std::string cmd = this->GetOption("CPACK_ZIP_COMMAND");
+ cmsys::SystemTools::ReplaceString(cmd, "<ARCHIVE>", archiveFile.c_str());
+ cmsys::SystemTools::ReplaceString(cmd, "<FILELIST>",
+ zipListFileName.c_str());
+ std::string output;
+ int retVal = -1;
+ int res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output, &output,
+ &retVal, dirName.c_str(),
+ cmSystemTools::OUTPUT_NONE, 0);
+ if (!res || retVal) {
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/CompressZip.log";
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << cmd << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running zip command: "
+ << cmd << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return "";
+ }
+
+ // Create the NSIS code to download this file on-the-fly.
+ unsigned long totalSizeInKbytes = (totalSize + 512) / 1024;
+ if (totalSizeInKbytes == 0) {
+ totalSizeInKbytes = 1;
+ }
+ std::ostringstream out;
+ /* clang-format off */
+ out << " AddSize " << totalSizeInKbytes << "\n"
+ << " Push \"" << component->ArchiveFile << "\"\n"
+ << " Call DownloadFile\n"
+ << " ZipDLL::extractall \"$INSTDIR\\"
+ << component->ArchiveFile << "\" \"$INSTDIR\"\n"
+ << " Pop $2 ; error message\n"
+ " StrCmp $2 \"success\" +2 0\n"
+ " MessageBox MB_OK \"Failed to unzip $2\"\n"
+ " Delete $INSTDIR\\$0\n";
+ /* clang-format on */
+ componentCode += out.str();
+ } else {
+ componentCode +=
+ " File /r \"${INST_DIR}\\" + component->Name + "\\*.*\"\n";
+ }
+ componentCode += "SectionEnd\n";
+
+ // Macro used to remove the component
+ macrosOut << "!macro Remove_${" << component->Name << "}\n";
+ macrosOut << " IntCmp $" << component->Name << "_was_installed 0 noremove_"
+ << component->Name << "\n";
+ std::vector<std::string>::iterator pathIt;
+ std::string path;
+ for (pathIt = component->Files.begin(); pathIt != component->Files.end();
+ ++pathIt) {
+ path = *pathIt;
+ std::replace(path.begin(), path.end(), '/', '\\');
+ macrosOut << " Delete \"$INSTDIR\\" << path << "\"\n";
+ }
+ for (pathIt = component->Directories.begin();
+ pathIt != component->Directories.end(); ++pathIt) {
+ path = *pathIt;
+ std::replace(path.begin(), path.end(), '/', '\\');
+ macrosOut << " RMDir \"$INSTDIR\\" << path << "\"\n";
+ }
+ macrosOut << " noremove_" << component->Name << ":\n";
+ macrosOut << "!macroend\n";
+
+ // Macro used to select each of the components that this component
+ // depends on.
+ std::set<cmCPackComponent*> visited;
+ macrosOut << "!macro Select_" << component->Name << "_depends\n";
+ macrosOut << CreateSelectionDependenciesDescription(component, visited);
+ macrosOut << "!macroend\n";
+
+ // Macro used to deselect each of the components that depend on this
+ // component.
+ visited.clear();
+ macrosOut << "!macro Deselect_required_by_" << component->Name << "\n";
+ macrosOut << CreateDeselectionDependenciesDescription(component, visited);
+ macrosOut << "!macroend\n";
+ return componentCode;
+}
+
+std::string cmCPackNSISGenerator::CreateSelectionDependenciesDescription(
+ cmCPackComponent* component, std::set<cmCPackComponent*>& visited)
+{
+ // Don't visit a component twice
+ if (visited.count(component)) {
+ return std::string();
+ }
+ visited.insert(component);
+
+ std::ostringstream out;
+ std::vector<cmCPackComponent*>::iterator dependIt;
+ for (dependIt = component->Dependencies.begin();
+ dependIt != component->Dependencies.end(); ++dependIt) {
+ // Write NSIS code to select this dependency
+ out << " SectionGetFlags ${" << (*dependIt)->Name << "} $0\n";
+ out << " IntOp $0 $0 | ${SF_SELECTED}\n";
+ out << " SectionSetFlags ${" << (*dependIt)->Name << "} $0\n";
+ out << " IntOp $" << (*dependIt)->Name
+ << "_selected 0 + ${SF_SELECTED}\n";
+ // Recurse
+ out << CreateSelectionDependenciesDescription(*dependIt, visited).c_str();
+ }
+
+ return out.str();
+}
+
+std::string cmCPackNSISGenerator::CreateDeselectionDependenciesDescription(
+ cmCPackComponent* component, std::set<cmCPackComponent*>& visited)
+{
+ // Don't visit a component twice
+ if (visited.count(component)) {
+ return std::string();
+ }
+ visited.insert(component);
+
+ std::ostringstream out;
+ std::vector<cmCPackComponent*>::iterator dependIt;
+ for (dependIt = component->ReverseDependencies.begin();
+ dependIt != component->ReverseDependencies.end(); ++dependIt) {
+ // Write NSIS code to deselect this dependency
+ out << " SectionGetFlags ${" << (*dependIt)->Name << "} $0\n";
+ out << " IntOp $1 ${SF_SELECTED} ~\n";
+ out << " IntOp $0 $0 & $1\n";
+ out << " SectionSetFlags ${" << (*dependIt)->Name << "} $0\n";
+ out << " IntOp $" << (*dependIt)->Name << "_selected 0 + 0\n";
+
+ // Recurse
+ out
+ << CreateDeselectionDependenciesDescription(*dependIt, visited).c_str();
+ }
+
+ return out.str();
+}
+
+std::string cmCPackNSISGenerator::CreateComponentGroupDescription(
+ cmCPackComponentGroup* group, std::ostream& macrosOut)
+{
+ if (group->Components.empty() && group->Subgroups.empty()) {
+ // Silently skip empty groups. NSIS doesn't support them.
+ return std::string();
+ }
+
+ std::string code = "SectionGroup ";
+ if (group->IsExpandedByDefault) {
+ code += "/e ";
+ }
+ if (group->IsBold) {
+ code += "\"!" + group->DisplayName + "\" " + group->Name + "\n";
+ } else {
+ code += "\"" + group->DisplayName + "\" " + group->Name + "\n";
+ }
+
+ std::vector<cmCPackComponentGroup*>::iterator groupIt;
+ for (groupIt = group->Subgroups.begin(); groupIt != group->Subgroups.end();
+ ++groupIt) {
+ code += this->CreateComponentGroupDescription(*groupIt, macrosOut);
+ }
+
+ std::vector<cmCPackComponent*>::iterator comp;
+ for (comp = group->Components.begin(); comp != group->Components.end();
+ ++comp) {
+ if ((*comp)->Files.empty()) {
+ continue;
+ }
+
+ code += this->CreateComponentDescription(*comp, macrosOut);
+ }
+ code += "SectionGroupEnd\n";
+ return code;
+}
+
+std::string cmCPackNSISGenerator::TranslateNewlines(std::string str)
+{
+ cmSystemTools::ReplaceString(str, "\n", "$\\r$\\n");
+ return str;
+}
diff --git a/Source/CPack/cmCPackNSISGenerator.h b/Source/CPack/cmCPackNSISGenerator.h
new file mode 100644
index 0000000..4923cf0
--- /dev/null
+++ b/Source/CPack/cmCPackNSISGenerator.h
@@ -0,0 +1,85 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackNSISGenerator_h
+#define cmCPackNSISGenerator_h
+
+#include "cmCPackGenerator.h"
+
+#include <set>
+
+/** \class cmCPackNSISGenerator
+ * \brief A generator for NSIS files
+ *
+ * http://people.freebsd.org/~kientzle/libarchive/
+ */
+class cmCPackNSISGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackNSISGenerator, cmCPackGenerator);
+
+ static cmCPackGenerator* CreateGenerator64()
+ {
+ return new cmCPackNSISGenerator(true);
+ }
+
+ /**
+ * Construct generator
+ */
+ cmCPackNSISGenerator(bool nsis64 = false);
+ ~cmCPackNSISGenerator() CM_OVERRIDE;
+
+protected:
+ int InitializeInternal() CM_OVERRIDE;
+ void CreateMenuLinks(std::ostream& str, std::ostream& deleteStr);
+ int PackageFiles() CM_OVERRIDE;
+ const char* GetOutputExtension() CM_OVERRIDE { return ".exe"; }
+ const char* GetOutputPostfix() CM_OVERRIDE { return "win32"; }
+
+ bool GetListOfSubdirectories(const char* dir,
+ std::vector<std::string>& dirs);
+
+ enum cmCPackGenerator::CPackSetDestdirSupport SupportsSetDestdir() const
+ CM_OVERRIDE;
+ bool SupportsAbsoluteDestination() const CM_OVERRIDE;
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+
+ /// Produce a string that contains the NSIS code to describe a
+ /// particular component. Any added macros will be emitted via
+ /// macrosOut.
+ std::string CreateComponentDescription(cmCPackComponent* component,
+ std::ostream& macrosOut);
+
+ /// Produce NSIS code that selects all of the components that this component
+ /// depends on, recursively.
+ std::string CreateSelectionDependenciesDescription(
+ cmCPackComponent* component, std::set<cmCPackComponent*>& visited);
+
+ /// Produce NSIS code that de-selects all of the components that are
+ /// dependent on this component, recursively.
+ std::string CreateDeselectionDependenciesDescription(
+ cmCPackComponent* component, std::set<cmCPackComponent*>& visited);
+
+ /// Produce a string that contains the NSIS code to describe a
+ /// particular component group, including its components. Any
+ /// added macros will be emitted via macrosOut.
+ std::string CreateComponentGroupDescription(cmCPackComponentGroup* group,
+ std::ostream& macrosOut);
+
+ /// Translations any newlines found in the string into \\r\\n, so that the
+ /// resulting string can be used within NSIS.
+ static std::string TranslateNewlines(std::string str);
+
+ bool Nsis64;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackOSXX11Generator.cxx b/Source/CPack/cmCPackOSXX11Generator.cxx
new file mode 100644
index 0000000..c0d2553
--- /dev/null
+++ b/Source/CPack/cmCPackOSXX11Generator.cxx
@@ -0,0 +1,291 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackOSXX11Generator.h"
+
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cmsys/Glob.hxx>
+#include <cmsys/SystemTools.hxx>
+#include <sys/stat.h>
+
+cmCPackOSXX11Generator::cmCPackOSXX11Generator()
+{
+}
+
+cmCPackOSXX11Generator::~cmCPackOSXX11Generator()
+{
+}
+
+int cmCPackOSXX11Generator::PackageFiles()
+{
+ // TODO: Use toplevel ?
+ // It is used! Is this an obsolete comment?
+
+ const char* cpackPackageExecutables =
+ this->GetOption("CPACK_PACKAGE_EXECUTABLES");
+ if (cpackPackageExecutables) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "The cpackPackageExecutables: "
+ << cpackPackageExecutables << "." << std::endl);
+ std::ostringstream str;
+ std::ostringstream deleteStr;
+ std::vector<std::string> cpackPackageExecutablesVector;
+ cmSystemTools::ExpandListArgument(cpackPackageExecutables,
+ cpackPackageExecutablesVector);
+ if (cpackPackageExecutablesVector.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
+ "<icon name>."
+ << std::endl);
+ return 0;
+ }
+ std::vector<std::string>::iterator it;
+ for (it = cpackPackageExecutablesVector.begin();
+ it != cpackPackageExecutablesVector.end(); ++it) {
+ std::string cpackExecutableName = *it;
+ ++it;
+ this->SetOptionIfNotSet("CPACK_EXECUTABLE_NAME",
+ cpackExecutableName.c_str());
+ }
+ }
+
+ // Disk image directories
+ std::string diskImageDirectory = toplevel;
+ std::string diskImageBackgroundImageDir =
+ diskImageDirectory + "/.background";
+
+ // App bundle directories
+ std::string packageDirFileName = toplevel;
+ packageDirFileName += "/";
+ packageDirFileName += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ packageDirFileName += ".app";
+ std::string contentsDirectory = packageDirFileName + "/Contents";
+ std::string resourcesDirectory = contentsDirectory + "/Resources";
+ std::string appDirectory = contentsDirectory + "/MacOS";
+ std::string scriptDirectory = resourcesDirectory + "/Scripts";
+ std::string resourceFileName = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ resourceFileName += ".rsrc";
+
+ const char* dir = resourcesDirectory.c_str();
+ const char* appdir = appDirectory.c_str();
+ const char* scrDir = scriptDirectory.c_str();
+ const char* contDir = contentsDirectory.c_str();
+ const char* rsrcFile = resourceFileName.c_str();
+ const char* iconFile = this->GetOption("CPACK_PACKAGE_ICON");
+ if (iconFile) {
+ std::string iconFileName = cmsys::SystemTools::GetFilenameName(iconFile);
+ if (!cmSystemTools::FileExists(iconFile)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find icon file: "
+ << iconFile
+ << ". Please check CPACK_PACKAGE_ICON setting."
+ << std::endl);
+ return 0;
+ }
+ std::string destFileName = resourcesDirectory + "/" + iconFileName;
+ this->ConfigureFile(iconFile, destFileName.c_str(), true);
+ this->SetOptionIfNotSet("CPACK_APPLE_GUI_ICON", iconFileName.c_str());
+ }
+
+ std::string applicationsLinkName = diskImageDirectory + "/Applications";
+ cmSystemTools::CreateSymlink("/Applications", applicationsLinkName.c_str());
+
+ if (!this->CopyResourcePlistFile("VolumeIcon.icns",
+ diskImageDirectory.c_str(),
+ ".VolumeIcon.icns", true) ||
+ !this->CopyResourcePlistFile("DS_Store", diskImageDirectory.c_str(),
+ ".DS_Store", true) ||
+ !this->CopyResourcePlistFile("background.png",
+ diskImageBackgroundImageDir.c_str(),
+ "background.png", true) ||
+ !this->CopyResourcePlistFile("RuntimeScript", dir) ||
+ !this->CopyResourcePlistFile("OSXX11.Info.plist", contDir,
+ "Info.plist") ||
+ !this->CopyResourcePlistFile("OSXX11.main.scpt", scrDir, "main.scpt",
+ true) ||
+ !this->CopyResourcePlistFile("OSXScriptLauncher.rsrc", dir, rsrcFile,
+ true) ||
+ !this->CopyResourcePlistFile("OSXScriptLauncher", appdir,
+ this->GetOption("CPACK_PACKAGE_FILE_NAME"),
+ true)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files"
+ << std::endl);
+ return 0;
+ }
+
+ // Two of the files need to have execute permission, so ensure they do:
+ std::string runTimeScript = dir;
+ runTimeScript += "/";
+ runTimeScript += "RuntimeScript";
+
+ std::string appScriptName = appdir;
+ appScriptName += "/";
+ appScriptName += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+
+ mode_t mode;
+ if (cmsys::SystemTools::GetPermissions(runTimeScript.c_str(), mode)) {
+ mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
+ cmsys::SystemTools::SetPermissions(runTimeScript.c_str(), mode);
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "Setting: " << runTimeScript << " to permission: " << mode
+ << std::endl);
+ }
+
+ if (cmsys::SystemTools::GetPermissions(appScriptName.c_str(), mode)) {
+ mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
+ cmsys::SystemTools::SetPermissions(appScriptName.c_str(), mode);
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "Setting: " << appScriptName << " to permission: " << mode
+ << std::endl);
+ }
+
+ std::string output;
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/hdiutilOutput.log";
+ std::ostringstream dmgCmd;
+ dmgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM_DISK_IMAGE")
+ << "\" create -ov -format UDZO -srcfolder \"" << diskImageDirectory
+ << "\" \"" << packageFileNames[0] << "\"";
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Compress disk image using command: "
+ << dmgCmd.str() << std::endl);
+ // since we get random dashboard failures with this one
+ // try running it more than once
+ int retVal = 1;
+ int numTries = 10;
+ bool res = false;
+ while (numTries > 0) {
+ res =
+ cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output, &output,
+ &retVal, 0, this->GeneratorVerbose, 0);
+ if (res && !retVal) {
+ numTries = -1;
+ break;
+ }
+ cmSystemTools::Delay(500);
+ numTries--;
+ }
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << dmgCmd.str() << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running hdiutil command: "
+ << dmgCmd.str() << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+
+ return 1;
+}
+
+int cmCPackOSXX11Generator::InitializeInternal()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "cmCPackOSXX11Generator::Initialize()"
+ << std::endl);
+ std::vector<std::string> path;
+ std::string pkgPath = cmSystemTools::FindProgram("hdiutil", path, false);
+ if (pkgPath.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find hdiutil compiler"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE",
+ pkgPath.c_str());
+
+ return this->Superclass::InitializeInternal();
+}
+
+/*
+bool cmCPackOSXX11Generator::CopyCreateResourceFile(const std::string& name)
+{
+ std::string uname = cmSystemTools::UpperCase(name);
+ std::string cpackVar = "CPACK_RESOURCE_FILE_" + uname;
+ const char* inFileName = this->GetOption(cpackVar.c_str());
+ if ( !inFileName )
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "CPack option: " << cpackVar.c_str()
+ << " not specified. It should point to "
+ << (name ? name : "(NULL)")
+ << ".rtf, " << name
+ << ".html, or " << name << ".txt file" << std::endl);
+ return false;
+ }
+ if ( !cmSystemTools::FileExists(inFileName) )
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find "
+ << (name ? name : "(NULL)")
+ << " resource file: " << inFileName << std::endl);
+ return false;
+ }
+ std::string ext = cmSystemTools::GetFilenameLastExtension(inFileName);
+ if ( ext != ".rtfd" && ext != ".rtf" && ext != ".html" && ext != ".txt" )
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Bad file extension specified: "
+ << ext << ". Currently only .rtfd, .rtf, .html, and .txt files allowed."
+ << std::endl);
+ return false;
+ }
+
+ std::string destFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ destFileName += "/Resources/";
+ destFileName += name + ext;
+
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
+ << (inFileName ? inFileName : "(NULL)")
+ << " to " << destFileName << std::endl);
+ this->ConfigureFile(inFileName, destFileName.c_str());
+ return true;
+}
+*/
+
+bool cmCPackOSXX11Generator::CopyResourcePlistFile(
+ const std::string& name, const std::string& dir,
+ const char* outputFileName /* = 0 */, bool copyOnly /* = false */)
+{
+ std::string inFName = "CPack.";
+ inFName += name;
+ inFName += ".in";
+ std::string inFileName = this->FindTemplate(inFName.c_str());
+ if (inFileName.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find input file: " << inFName << std::endl);
+ return false;
+ }
+
+ if (!outputFileName) {
+ outputFileName = name.c_str();
+ }
+
+ std::string destFileName = dir;
+ destFileName += "/";
+ destFileName += outputFileName;
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
+ << inFileName << " to " << destFileName << std::endl);
+ this->ConfigureFile(inFileName.c_str(), destFileName.c_str(), copyOnly);
+ return true;
+}
+
+const char* cmCPackOSXX11Generator::GetPackagingInstallPrefix()
+{
+ this->InstallPrefix = "/";
+ this->InstallPrefix += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ this->InstallPrefix += ".app/Contents/Resources";
+ return this->InstallPrefix.c_str();
+}
diff --git a/Source/CPack/cmCPackOSXX11Generator.h b/Source/CPack/cmCPackOSXX11Generator.h
new file mode 100644
index 0000000..adc05d2
--- /dev/null
+++ b/Source/CPack/cmCPackOSXX11Generator.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackOSXX11Generator_h
+#define cmCPackOSXX11Generator_h
+
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackOSXX11Generator
+ * \brief A generator for OSX X11 modules
+ *
+ * Based on Gimp.app
+ */
+class cmCPackOSXX11Generator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackOSXX11Generator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackOSXX11Generator();
+ virtual ~cmCPackOSXX11Generator();
+
+protected:
+ virtual int InitializeInternal();
+ int PackageFiles();
+ virtual const char* GetPackagingInstallPrefix();
+ virtual const char* GetOutputExtension() { return ".dmg"; }
+
+ // bool CopyCreateResourceFile(const std::string& name,
+ // const std::string& dir);
+ bool CopyResourcePlistFile(const std::string& name, const std::string& dir,
+ const char* outputFileName = 0,
+ bool copyOnly = false);
+ std::string InstallPrefix;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackPKGGenerator.cxx b/Source/CPack/cmCPackPKGGenerator.cxx
new file mode 100644
index 0000000..19b587a
--- /dev/null
+++ b/Source/CPack/cmCPackPKGGenerator.cxx
@@ -0,0 +1,367 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCPackPKGGenerator.h"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+#include <cmsys/Glob.hxx>
+#include <cmsys/SystemTools.hxx>
+
+cmCPackPKGGenerator::cmCPackPKGGenerator()
+{
+ this->componentPackageMethod = ONE_PACKAGE;
+}
+
+cmCPackPKGGenerator::~cmCPackPKGGenerator()
+{
+}
+
+bool cmCPackPKGGenerator::SupportsComponentInstallation() const
+{
+ return true;
+}
+
+int cmCPackPKGGenerator::InitializeInternal()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "cmCPackPKGGenerator::Initialize()"
+ << std::endl);
+
+ return this->Superclass::InitializeInternal();
+}
+
+std::string cmCPackPKGGenerator::GetPackageName(
+ const cmCPackComponent& component)
+{
+ if (component.ArchiveFile.empty()) {
+ std::string packagesDir = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ packagesDir += ".dummy";
+ std::ostringstream out;
+ out << cmSystemTools::GetFilenameWithoutLastExtension(packagesDir) << "-"
+ << component.Name << ".pkg";
+ return out.str();
+ } else {
+ return component.ArchiveFile + ".pkg";
+ }
+}
+
+void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile)
+{
+ std::string distributionTemplate =
+ this->FindTemplate("CPack.distribution.dist.in");
+ if (distributionTemplate.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find input file: "
+ << distributionTemplate << std::endl);
+ return;
+ }
+
+ std::string distributionFile = metapackageFile;
+ distributionFile += "/Contents/distribution.dist";
+
+ // Create the choice outline, which provides a tree-based view of
+ // the components in their groups.
+ std::ostringstream choiceOut;
+ cmXMLWriter xout(choiceOut, 1);
+ 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 == 0) {
+ CreateChoiceOutline(groupIt->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) {
+ xout.StartElement("line");
+ xout.Attribute("choice", compIt->first + "Choice");
+ xout.Content(""); // Avoid self-closing tag.
+ xout.EndElement();
+ }
+ }
+ if (!this->PostFlightComponent.Name.empty()) {
+ xout.StartElement("line");
+ xout.Attribute("choice", PostFlightComponent.Name + "Choice");
+ xout.Content(""); // Avoid self-closing tag.
+ xout.EndElement();
+ }
+ xout.EndElement(); // choices-outline>
+
+ // Create the actual choices
+ for (groupIt = this->ComponentGroups.begin();
+ groupIt != this->ComponentGroups.end(); ++groupIt) {
+ CreateChoice(groupIt->second, xout);
+ }
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ CreateChoice(compIt->second, xout);
+ }
+
+ if (!this->PostFlightComponent.Name.empty()) {
+ CreateChoice(PostFlightComponent, xout);
+ }
+
+ this->SetOption("CPACK_PACKAGEMAKER_CHOICES", choiceOut.str().c_str());
+
+ // Create the distribution.dist file in the metapackage to turn it
+ // into a distribution package.
+ this->ConfigureFile(distributionTemplate.c_str(), distributionFile.c_str());
+}
+
+void cmCPackPKGGenerator::CreateChoiceOutline(
+ const cmCPackComponentGroup& group, cmXMLWriter& xout)
+{
+ 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);
+ }
+
+ std::vector<cmCPackComponent*>::const_iterator compIt;
+ for (compIt = group.Components.begin(); compIt != group.Components.end();
+ ++compIt) {
+ xout.StartElement("line");
+ xout.Attribute("choice", (*compIt)->Name + "Choice");
+ xout.Content(""); // Avoid self-closing tag.
+ xout.EndElement();
+ }
+ xout.EndElement();
+}
+
+void cmCPackPKGGenerator::CreateChoice(const cmCPackComponentGroup& group,
+ cmXMLWriter& xout)
+{
+ xout.StartElement("choice");
+ xout.Attribute("id", group.Name + "Choice");
+ xout.Attribute("title", group.DisplayName);
+ xout.Attribute("start_selected", "true");
+ xout.Attribute("start_enabled", "true");
+ xout.Attribute("start_visible", "true");
+ if (!group.Description.empty()) {
+ xout.Attribute("description", group.Description);
+ }
+ xout.EndElement();
+}
+
+void cmCPackPKGGenerator::CreateChoice(const cmCPackComponent& component,
+ cmXMLWriter& xout)
+{
+ std::string packageId = "com.";
+ packageId += this->GetOption("CPACK_PACKAGE_VENDOR");
+ packageId += '.';
+ packageId += this->GetOption("CPACK_PACKAGE_NAME");
+ packageId += '.';
+ packageId += component.Name;
+
+ xout.StartElement("choice");
+ xout.Attribute("id", component.Name + "Choice");
+ xout.Attribute("title", component.DisplayName);
+ xout.Attribute(
+ "start_selected",
+ component.IsDisabledByDefault && !component.IsRequired ? "false" : "true");
+ xout.Attribute("start_enabled", component.IsRequired ? "false" : "true");
+ xout.Attribute("start_visible", component.IsHidden ? "false" : "true");
+ if (!component.Description.empty()) {
+ xout.Attribute("description", component.Description);
+ }
+ if (!component.Dependencies.empty() ||
+ !component.ReverseDependencies.empty()) {
+ // The "selected" expression is evaluated each time any choice is
+ // selected, for all choices *except* the one that the user
+ // selected. A component is marked selected if it has been
+ // selected (my.choice.selected in Javascript) and all of the
+ // components it depends on have been selected (transitively) or
+ // if any of the components that depend on it have been selected
+ // (transitively). Assume that we have components A, B, C, D, and
+ // E, where each component depends on the previous component (B
+ // depends on A, C depends on B, D depends on C, and E depends on
+ // D). The expression we build for the component C will be
+ // my.choice.selected && B && A || D || E
+ // This way, selecting C will automatically select everything it depends
+ // on (B and A), while selecting something that depends on C--either D
+ // or E--will automatically cause C to get selected.
+ std::ostringstream selected("my.choice.selected");
+ std::set<const cmCPackComponent*> visited;
+ AddDependencyAttributes(component, visited, selected);
+ visited.clear();
+ AddReverseDependencyAttributes(component, visited, selected);
+ xout.Attribute("selected", selected.str());
+ }
+ xout.StartElement("pkg-ref");
+ xout.Attribute("id", packageId);
+ xout.EndElement(); // pkg-ref
+ xout.EndElement(); // choice
+
+ // Create a description of the package associated with this
+ // component.
+ std::string relativePackageLocation = "Contents/Packages/";
+ relativePackageLocation += this->GetPackageName(component);
+
+ // Determine the installed size of the package.
+ std::string dirName = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ dirName += '/';
+ dirName += component.Name;
+ dirName += this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
+ unsigned long installedSize =
+ component.GetInstalledSizeInKbytes(dirName.c_str());
+
+ xout.StartElement("pkg-ref");
+ xout.Attribute("id", packageId);
+ xout.Attribute("version", this->GetOption("CPACK_PACKAGE_VERSION"));
+ xout.Attribute("installKBytes", installedSize);
+ xout.Attribute("auth", "Admin");
+ xout.Attribute("onConclusion", "None");
+ if (component.IsDownloaded) {
+ xout.Content(this->GetOption("CPACK_DOWNLOAD_SITE"));
+ xout.Content(this->GetPackageName(component));
+ } else {
+ xout.Content("file:./");
+ xout.Content(relativePackageLocation);
+ }
+ xout.EndElement(); // pkg-ref
+}
+
+void cmCPackPKGGenerator::AddDependencyAttributes(
+ const cmCPackComponent& component,
+ std::set<const cmCPackComponent*>& visited, std::ostringstream& out)
+{
+ if (visited.find(&component) != visited.end()) {
+ return;
+ }
+ 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);
+ }
+}
+
+void cmCPackPKGGenerator::AddReverseDependencyAttributes(
+ const cmCPackComponent& component,
+ std::set<const cmCPackComponent*>& visited, std::ostringstream& out)
+{
+ if (visited.find(&component) != visited.end()) {
+ return;
+ }
+ 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);
+ }
+}
+
+bool cmCPackPKGGenerator::CopyCreateResourceFile(const std::string& name,
+ const std::string& dirName)
+{
+ std::string uname = cmSystemTools::UpperCase(name);
+ std::string cpackVar = "CPACK_RESOURCE_FILE_" + uname;
+ const char* inFileName = this->GetOption(cpackVar.c_str());
+ if (!inFileName) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "CPack option: "
+ << cpackVar.c_str()
+ << " not specified. It should point to "
+ << (!name.empty() ? name : "<empty>") << ".rtf, " << name
+ << ".html, or " << name << ".txt file" << std::endl);
+ return false;
+ }
+ if (!cmSystemTools::FileExists(inFileName)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find "
+ << (!name.empty() ? name : "<empty>")
+ << " resource file: " << inFileName << std::endl);
+ return false;
+ }
+ std::string ext = cmSystemTools::GetFilenameLastExtension(inFileName);
+ if (ext != ".rtfd" && ext != ".rtf" && ext != ".html" && ext != ".txt") {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR, "Bad file extension specified: "
+ << ext
+ << ". Currently only .rtfd, .rtf, .html, and .txt files allowed."
+ << std::endl);
+ return false;
+ }
+
+ std::string destFileName = dirName;
+ destFileName += '/';
+ destFileName += name + ext;
+
+ // Set this so that distribution.dist gets the right name (without
+ // the path).
+ this->SetOption(("CPACK_RESOURCE_FILE_" + uname + "_NOPATH").c_str(),
+ (name + ext).c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Configure file: " << (inFileName ? inFileName : "(NULL)")
+ << " to " << destFileName << std::endl);
+ this->ConfigureFile(inFileName, destFileName.c_str());
+ return true;
+}
+
+bool cmCPackPKGGenerator::CopyResourcePlistFile(const std::string& name,
+ const char* outName)
+{
+ if (!outName) {
+ outName = name.c_str();
+ }
+
+ std::string inFName = "CPack.";
+ inFName += name;
+ inFName += ".in";
+ std::string inFileName = this->FindTemplate(inFName.c_str());
+ if (inFileName.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find input file: " << inFName << std::endl);
+ return false;
+ }
+
+ std::string destFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ destFileName += "/";
+ destFileName += outName;
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
+ << inFileName << " to " << destFileName << std::endl);
+ this->ConfigureFile(inFileName.c_str(), destFileName.c_str());
+ return true;
+}
+
+int cmCPackPKGGenerator::CopyInstallScript(const std::string& resdir,
+ const std::string& script,
+ const std::string& name)
+{
+ std::string dst = resdir;
+ dst += "/";
+ dst += name;
+ cmSystemTools::CopyFileAlways(script.c_str(), dst.c_str());
+ cmSystemTools::SetPermissions(dst.c_str(), 0777);
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "copy script : " << script << "\ninto " << dst << std::endl);
+
+ return 1;
+}
diff --git a/Source/CPack/cmCPackPKGGenerator.h b/Source/CPack/cmCPackPKGGenerator.h
new file mode 100644
index 0000000..8d10943
--- /dev/null
+++ b/Source/CPack/cmCPackPKGGenerator.h
@@ -0,0 +1,96 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackPKGGenerator_h
+#define cmCPackPKGGenerator_h
+
+#include "cmCPackGenerator.h"
+
+class cmCPackComponent;
+class cmXMLWriter;
+
+/** \class cmCPackPKGGenerator
+ * \brief A generator for pkg files
+ *
+ */
+class cmCPackPKGGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackPKGGenerator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackPKGGenerator();
+ virtual ~cmCPackPKGGenerator();
+
+ virtual bool SupportsComponentInstallation() const;
+
+protected:
+ virtual int InitializeInternal();
+ virtual const char* GetOutputPostfix() { return "darwin"; }
+
+ // Copies or creates the resource file with the given name to the
+ // package or package staging directory dirName. The variable
+ // CPACK_RESOURCE_FILE_${NAME} (where ${NAME} is the uppercased
+ // version of name) specifies the input file to use for this file,
+ // which will be configured via ConfigureFile.
+ bool CopyCreateResourceFile(const std::string& name,
+ const std::string& dirName);
+ bool CopyResourcePlistFile(const std::string& name, const char* outName = 0);
+
+ int CopyInstallScript(const std::string& resdir, const std::string& script,
+ const std::string& name);
+
+ // Retrieve the name of package file that will be generated for this
+ // component. The name is just the file name with extension, and
+ // does not include the subdirectory.
+ std::string GetPackageName(const cmCPackComponent& component);
+
+ // Writes a distribution.dist file, which turns a metapackage into a
+ // full-fledged distribution. This file is used to describe
+ // inter-component dependencies. metapackageFile is the name of the
+ // metapackage for the distribution. Only valid for a
+ // component-based install.
+ void WriteDistributionFile(const char* metapackageFile);
+
+ // Subroutine of WriteDistributionFile that writes out the
+ // dependency attributes for inter-component dependencies.
+ void AddDependencyAttributes(const cmCPackComponent& component,
+ std::set<const cmCPackComponent*>& visited,
+ std::ostringstream& out);
+
+ // Subroutine of WriteDistributionFile that writes out the
+ // reverse dependency attributes for inter-component dependencies.
+ void AddReverseDependencyAttributes(
+ const cmCPackComponent& component,
+ std::set<const cmCPackComponent*>& visited, std::ostringstream& out);
+
+ // Generates XML that encodes the hierarchy of component groups and
+ // their components in a form that can be used by distribution
+ // metapackages.
+ void CreateChoiceOutline(const cmCPackComponentGroup& group,
+ cmXMLWriter& xout);
+
+ /// Create the "choice" XML element to describe a component group
+ /// for the installer GUI.
+ void CreateChoice(const cmCPackComponentGroup& group, cmXMLWriter& xout);
+
+ /// Create the "choice" XML element to describe a component for the
+ /// installer GUI.
+ void CreateChoice(const cmCPackComponent& component, cmXMLWriter& xout);
+
+ // The PostFlight component when creating a metapackage
+ cmCPackComponent PostFlightComponent;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackPackageMakerGenerator.cxx b/Source/CPack/cmCPackPackageMakerGenerator.cxx
new file mode 100644
index 0000000..ce329ca
--- /dev/null
+++ b/Source/CPack/cmCPackPackageMakerGenerator.cxx
@@ -0,0 +1,584 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCPackPackageMakerGenerator.h"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/SystemTools.hxx>
+
+#include <assert.h>
+
+static inline unsigned int getVersion(unsigned int major, unsigned int minor)
+{
+ assert(major < 256 && minor < 256);
+ return ((major & 0xFF) << 16 | minor);
+}
+
+cmCPackPackageMakerGenerator::cmCPackPackageMakerGenerator()
+{
+ this->PackageMakerVersion = 0.0;
+ this->PackageCompatibilityVersion = getVersion(10, 4);
+}
+
+cmCPackPackageMakerGenerator::~cmCPackPackageMakerGenerator()
+{
+}
+
+bool cmCPackPackageMakerGenerator::SupportsComponentInstallation() const
+{
+ return this->PackageCompatibilityVersion >= getVersion(10, 4);
+}
+
+int cmCPackPackageMakerGenerator::PackageFiles()
+{
+ // TODO: Use toplevel
+ // It is used! Is this an obsolete comment?
+
+ std::string resDir; // Where this package's resources will go.
+ std::string packageDirFileName =
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ if (this->Components.empty()) {
+ packageDirFileName += ".pkg";
+ resDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ resDir += "/Resources";
+ } else {
+ packageDirFileName += ".mpkg";
+ if (!cmsys::SystemTools::MakeDirectory(packageDirFileName.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "unable to create package directory " << packageDirFileName
+ << std::endl);
+ return 0;
+ }
+
+ resDir = packageDirFileName;
+ resDir += "/Contents";
+ if (!cmsys::SystemTools::MakeDirectory(resDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "unable to create package subdirectory " << resDir
+ << std::endl);
+ return 0;
+ }
+
+ resDir += "/Resources";
+ if (!cmsys::SystemTools::MakeDirectory(resDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "unable to create package subdirectory " << resDir
+ << std::endl);
+ return 0;
+ }
+
+ resDir += "/en.lproj";
+ }
+
+ const char* preflight = this->GetOption("CPACK_PREFLIGHT_SCRIPT");
+ const char* postflight = this->GetOption("CPACK_POSTFLIGHT_SCRIPT");
+ const char* postupgrade = this->GetOption("CPACK_POSTUPGRADE_SCRIPT");
+
+ if (this->Components.empty()) {
+ // Create directory structure
+ std::string preflightDirName = resDir + "/PreFlight";
+ std::string postflightDirName = resDir + "/PostFlight";
+ // if preflight or postflight scripts not there create directories
+ // of the same name, I think this makes it work
+ if (!preflight) {
+ if (!cmsys::SystemTools::MakeDirectory(preflightDirName.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating installer directory: "
+ << preflightDirName << std::endl);
+ return 0;
+ }
+ }
+ if (!postflight) {
+ if (!cmsys::SystemTools::MakeDirectory(postflightDirName.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating installer directory: "
+ << postflightDirName << std::endl);
+ return 0;
+ }
+ }
+ // if preflight, postflight, or postupgrade are set
+ // then copy them into the resource directory and make
+ // them executable
+ if (preflight) {
+ this->CopyInstallScript(resDir.c_str(), preflight, "preflight");
+ }
+ if (postflight) {
+ this->CopyInstallScript(resDir.c_str(), postflight, "postflight");
+ }
+ if (postupgrade) {
+ this->CopyInstallScript(resDir.c_str(), postupgrade, "postupgrade");
+ }
+ } else if (postflight) {
+ // create a postflight component to house the script
+ this->PostFlightComponent.Name = "PostFlight";
+ this->PostFlightComponent.DisplayName = "PostFlight";
+ this->PostFlightComponent.Description = "PostFlight";
+ this->PostFlightComponent.IsHidden = true;
+
+ // empty directory for pkg contents
+ std::string packageDir = toplevel + "/" + PostFlightComponent.Name;
+ if (!cmsys::SystemTools::MakeDirectory(packageDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating component packages directory: "
+ << packageDir << std::endl);
+ return 0;
+ }
+
+ // create package
+ std::string packageFileDir = packageDirFileName + "/Contents/Packages/";
+ if (!cmsys::SystemTools::MakeDirectory(packageFileDir.c_str())) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Problem creating component PostFlight Packages directory: "
+ << packageFileDir << std::endl);
+ return 0;
+ }
+ std::string packageFile =
+ packageFileDir + this->GetPackageName(PostFlightComponent);
+ if (!this->GenerateComponentPackage(
+ packageFile.c_str(), packageDir.c_str(), PostFlightComponent)) {
+ return 0;
+ }
+
+ // copy postflight script into resource directory of .pkg
+ std::string resourceDir = packageFile + "/Contents/Resources";
+ this->CopyInstallScript(resourceDir.c_str(), postflight, "postflight");
+ }
+
+ if (!this->Components.empty()) {
+ // Create the directory where component packages will be built.
+ std::string basePackageDir = packageDirFileName;
+ basePackageDir += "/Contents/Packages";
+ if (!cmsys::SystemTools::MakeDirectory(basePackageDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating component packages directory: "
+ << basePackageDir << std::endl);
+ return 0;
+ }
+
+ // Create the directory where downloaded component packages will
+ // be placed.
+ const char* userUploadDirectory =
+ this->GetOption("CPACK_UPLOAD_DIRECTORY");
+ std::string uploadDirectory;
+ if (userUploadDirectory && *userUploadDirectory) {
+ uploadDirectory = userUploadDirectory;
+ } else {
+ uploadDirectory = this->GetOption("CPACK_PACKAGE_DIRECTORY");
+ uploadDirectory += "/CPackUploads";
+ }
+
+ // Create packages for each component
+ bool warnedAboutDownloadCompatibility = false;
+
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ std::string packageFile;
+ if (compIt->second.IsDownloaded) {
+ if (this->PackageCompatibilityVersion >= getVersion(10, 5) &&
+ this->PackageMakerVersion >= 3.0) {
+ // Build this package within the upload directory.
+ packageFile = uploadDirectory;
+
+ if (!cmSystemTools::FileExists(uploadDirectory.c_str())) {
+ if (!cmSystemTools::MakeDirectory(uploadDirectory.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Unable to create package upload directory "
+ << uploadDirectory << std::endl);
+ return 0;
+ }
+ }
+ } else if (!warnedAboutDownloadCompatibility) {
+ if (this->PackageCompatibilityVersion < getVersion(10, 5)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING,
+ "CPack warning: please set CPACK_OSX_PACKAGE_VERSION to 10.5 "
+ "or greater enable downloaded packages. CPack will build a "
+ "non-downloaded package."
+ << std::endl);
+ }
+
+ if (this->PackageMakerVersion < 3) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "CPack warning: unable to build downloaded "
+ "packages with PackageMaker versions prior "
+ "to 3.0. CPack will build a non-downloaded package."
+ << std::endl);
+ }
+
+ warnedAboutDownloadCompatibility = true;
+ }
+ }
+
+ if (packageFile.empty()) {
+ // Build this package within the overall distribution
+ // metapackage.
+ packageFile = basePackageDir;
+
+ // We're not downloading this component, even if the user
+ // requested it.
+ compIt->second.IsDownloaded = false;
+ }
+
+ packageFile += '/';
+ packageFile += GetPackageName(compIt->second);
+
+ std::string packageDir = toplevel;
+ packageDir += '/';
+ packageDir += compIt->first;
+ if (!this->GenerateComponentPackage(
+ packageFile.c_str(), packageDir.c_str(), compIt->second)) {
+ return 0;
+ }
+ }
+ }
+ this->SetOption("CPACK_MODULE_VERSION_SUFFIX", "");
+
+ // Copy or create all of the resource files we need.
+ if (!this->CopyCreateResourceFile("License", resDir.c_str()) ||
+ !this->CopyCreateResourceFile("ReadMe", resDir.c_str()) ||
+ !this->CopyCreateResourceFile("Welcome", resDir.c_str()) ||
+ !this->CopyResourcePlistFile("Info.plist") ||
+ !this->CopyResourcePlistFile("Description.plist")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files"
+ << std::endl);
+ return 0;
+ }
+
+ if (this->Components.empty()) {
+ // Use PackageMaker to build the package.
+ std::ostringstream pkgCmd;
+ pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
+ << "\" -build -p \"" << packageDirFileName << "\"";
+ if (this->Components.empty()) {
+ pkgCmd << " -f \"" << this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ } else {
+ pkgCmd << " -mi \"" << this->GetOption("CPACK_TEMPORARY_DIRECTORY")
+ << "/packages/";
+ }
+ pkgCmd << "\" -r \"" << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")
+ << "/Resources\" -i \""
+ << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")
+ << "/Info.plist\" -d \""
+ << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")
+ << "/Description.plist\"";
+ if (this->PackageMakerVersion > 2.0) {
+ pkgCmd << " -v";
+ }
+ if (!RunPackageMaker(pkgCmd.str().c_str(), packageDirFileName.c_str()))
+ return 0;
+ } else {
+ // We have built the package in place. Generate the
+ // distribution.dist file to describe it for the installer.
+ WriteDistributionFile(packageDirFileName.c_str());
+ }
+
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/hdiutilOutput.log";
+ std::ostringstream dmgCmd;
+ dmgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM_DISK_IMAGE")
+ << "\" create -ov -format UDZO -srcfolder \"" << packageDirFileName
+ << "\" \"" << packageFileNames[0] << "\"";
+ std::string output;
+ int retVal = 1;
+ int numTries = 10;
+ bool res = false;
+ while (numTries > 0) {
+ res =
+ cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output, &output,
+ &retVal, 0, this->GeneratorVerbose, 0);
+ if (res && !retVal) {
+ numTries = -1;
+ break;
+ }
+ cmSystemTools::Delay(500);
+ numTries--;
+ }
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << dmgCmd.str() << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running hdiutil command: "
+ << dmgCmd.str() << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+
+ return 1;
+}
+
+int cmCPackPackageMakerGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
+
+ // Starting with Xcode 4.3, PackageMaker is a separate app, and you
+ // can put it anywhere you want. So... use a variable for its location.
+ // People who put it in unexpected places can use the variable to tell
+ // us where it is.
+ //
+ // Use the following locations, in "most recent installation" order,
+ // to search for the PackageMaker app. Assume people who copy it into
+ // the new Xcode 4.3 app in "/Applications" will copy it into the nested
+ // Applications folder inside the Xcode bundle itself. Or directly in
+ // the "/Applications" directory.
+ //
+ // If found, save result in the CPACK_INSTALLER_PROGRAM variable.
+
+ std::vector<std::string> paths;
+ paths.push_back("/Applications/Xcode.app/Contents/Applications"
+ "/PackageMaker.app/Contents/MacOS");
+ paths.push_back("/Applications/Utilities"
+ "/PackageMaker.app/Contents/MacOS");
+ paths.push_back("/Applications"
+ "/PackageMaker.app/Contents/MacOS");
+ paths.push_back("/Developer/Applications/Utilities"
+ "/PackageMaker.app/Contents/MacOS");
+ paths.push_back("/Developer/Applications"
+ "/PackageMaker.app/Contents/MacOS");
+
+ std::string pkgPath;
+ const char* inst_program = this->GetOption("CPACK_INSTALLER_PROGRAM");
+ if (inst_program && *inst_program) {
+ pkgPath = inst_program;
+ } else {
+ pkgPath = cmSystemTools::FindProgram("PackageMaker", paths, false);
+ if (pkgPath.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find PackageMaker compiler"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", pkgPath.c_str());
+ }
+
+ // Get path to the real PackageMaker, not a symlink:
+ pkgPath = cmSystemTools::GetRealPath(pkgPath.c_str());
+ // Up from there to find the version.plist file in the "Contents" dir:
+ std::string contents_dir;
+ contents_dir = cmSystemTools::GetFilenamePath(pkgPath);
+ contents_dir = cmSystemTools::GetFilenamePath(contents_dir);
+
+ std::string versionFile = contents_dir + "/version.plist";
+
+ if (!cmSystemTools::FileExists(versionFile.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find PackageMaker compiler version file: "
+ << versionFile << std::endl);
+ return 0;
+ }
+
+ cmsys::ifstream ifs(versionFile.c_str());
+ if (!ifs) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot open PackageMaker compiler version file"
+ << std::endl);
+ return 0;
+ }
+
+ // Check the PackageMaker version
+ cmsys::RegularExpression rexKey("<key>CFBundleShortVersionString</key>");
+ cmsys::RegularExpression rexVersion("<string>([0-9]+.[0-9.]+)</string>");
+ std::string line;
+ bool foundKey = false;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ if (rexKey.find(line)) {
+ foundKey = true;
+ break;
+ }
+ }
+ if (!foundKey) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Cannot find CFBundleShortVersionString in the PackageMaker compiler "
+ "version file"
+ << std::endl);
+ return 0;
+ }
+ if (!cmSystemTools::GetLineFromStream(ifs, line) || !rexVersion.find(line)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem reading the PackageMaker compiler version file: "
+ << versionFile << std::endl);
+ return 0;
+ }
+ this->PackageMakerVersion = atof(rexVersion.match(1).c_str());
+ if (this->PackageMakerVersion < 1.0) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Require PackageMaker 1.0 or higher"
+ << std::endl);
+ return 0;
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "PackageMaker version is: "
+ << this->PackageMakerVersion << std::endl);
+
+ // Determine the package compatibility version. If it wasn't
+ // specified by the user, we define it based on which features the
+ // user requested.
+ const char* packageCompat = this->GetOption("CPACK_OSX_PACKAGE_VERSION");
+ if (packageCompat && *packageCompat) {
+ unsigned int majorVersion = 10;
+ unsigned int minorVersion = 5;
+ int res = sscanf(packageCompat, "%u.%u", &majorVersion, &minorVersion);
+ if (res == 2) {
+ this->PackageCompatibilityVersion =
+ getVersion(majorVersion, minorVersion);
+ }
+ } else if (this->GetOption("CPACK_DOWNLOAD_SITE")) {
+ this->SetOption("CPACK_OSX_PACKAGE_VERSION", "10.5");
+ this->PackageCompatibilityVersion = getVersion(10, 5);
+ } else if (this->GetOption("CPACK_COMPONENTS_ALL")) {
+ this->SetOption("CPACK_OSX_PACKAGE_VERSION", "10.4");
+ this->PackageCompatibilityVersion = getVersion(10, 4);
+ } else {
+ this->SetOption("CPACK_OSX_PACKAGE_VERSION", "10.3");
+ this->PackageCompatibilityVersion = getVersion(10, 3);
+ }
+
+ std::vector<std::string> no_paths;
+ pkgPath = cmSystemTools::FindProgram("hdiutil", no_paths, false);
+ if (pkgPath.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find hdiutil compiler"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE",
+ pkgPath.c_str());
+
+ return this->Superclass::InitializeInternal();
+}
+
+bool cmCPackPackageMakerGenerator::RunPackageMaker(const char* command,
+ const char* packageFile)
+{
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/PackageMakerOutput.log";
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << command << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool res = cmSystemTools::RunSingleCommand(
+ command, &output, &output, &retVal, 0, this->GeneratorVerbose, 0);
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running package maker"
+ << std::endl);
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << command << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR, "Problem running PackageMaker command: "
+ << command << std::endl
+ << "Please check " << tmpFile << " for errors" << std::endl);
+ return false;
+ }
+ // sometimes the command finishes but the directory is not yet
+ // created, so try 10 times to see if it shows up
+ int tries = 10;
+ while (tries > 0 && !cmSystemTools::FileExists(packageFile)) {
+ cmSystemTools::Delay(500);
+ tries--;
+ }
+ if (!cmSystemTools::FileExists(packageFile)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running PackageMaker command: "
+ << command << std::endl
+ << "Package not created: " << packageFile << std::endl);
+ return false;
+ }
+
+ return true;
+}
+
+bool cmCPackPackageMakerGenerator::GenerateComponentPackage(
+ const char* packageFile, const char* packageDir,
+ const cmCPackComponent& component)
+{
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Building component package: "
+ << packageFile << std::endl);
+
+ // The command that will be used to run PackageMaker
+ std::ostringstream pkgCmd;
+
+ if (this->PackageCompatibilityVersion < getVersion(10, 5) ||
+ this->PackageMakerVersion < 3.0) {
+ // Create Description.plist and Info.plist files for normal Mac OS
+ // X packages, which work on Mac OS X 10.3 and newer.
+ std::string descriptionFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ descriptionFile += '/' + component.Name + "-Description.plist";
+ cmsys::ofstream out(descriptionFile.c_str());
+ cmXMLWriter xout(out);
+ xout.StartDocument();
+ xout.Doctype("plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\""
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"");
+ xout.StartElement("plist");
+ xout.Attribute("version", "1.4");
+ xout.StartElement("dict");
+ xout.Element("key", "IFPkgDescriptionTitle");
+ xout.Element("string", component.DisplayName);
+ xout.Element("key", "IFPkgDescriptionVersion");
+ xout.Element("string", this->GetOption("CPACK_PACKAGE_VERSION"));
+ xout.Element("key", "IFPkgDescriptionDescription");
+ xout.Element("string", component.Description);
+ xout.EndElement(); // dict
+ xout.EndElement(); // plist
+ xout.EndDocument();
+ out.close();
+
+ // Create the Info.plist file for this component
+ std::string moduleVersionSuffix = ".";
+ moduleVersionSuffix += component.Name;
+ this->SetOption("CPACK_MODULE_VERSION_SUFFIX",
+ moduleVersionSuffix.c_str());
+ std::string infoFileName = component.Name;
+ infoFileName += "-Info.plist";
+ if (!this->CopyResourcePlistFile("Info.plist", infoFileName.c_str())) {
+ return false;
+ }
+
+ pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
+ << "\" -build -p \"" << packageFile << "\""
+ << " -f \"" << packageDir << "\""
+ << " -i \"" << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/"
+ << infoFileName << "\""
+ << " -d \"" << descriptionFile << "\"";
+ } else {
+ // Create a "flat" package on Mac OS X 10.5 and newer. Flat
+ // packages are stored in a single file, rather than a directory
+ // like normal packages, and can be downloaded by the installer
+ // on-the-fly in Mac OS X 10.5 or newer. Thus, we need to create
+ // flat packages when the packages will be downloaded on the fly.
+ std::string pkgId = "com.";
+ pkgId += this->GetOption("CPACK_PACKAGE_VENDOR");
+ pkgId += '.';
+ pkgId += this->GetOption("CPACK_PACKAGE_NAME");
+ pkgId += '.';
+ pkgId += component.Name;
+
+ pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
+ << "\" --root \"" << packageDir << "\""
+ << " --id " << pkgId << " --target "
+ << this->GetOption("CPACK_OSX_PACKAGE_VERSION") << " --out \""
+ << packageFile << "\"";
+ }
+
+ // Run PackageMaker
+ return RunPackageMaker(pkgCmd.str().c_str(), packageFile);
+}
diff --git a/Source/CPack/cmCPackPackageMakerGenerator.h b/Source/CPack/cmCPackPackageMakerGenerator.h
new file mode 100644
index 0000000..5192377
--- /dev/null
+++ b/Source/CPack/cmCPackPackageMakerGenerator.h
@@ -0,0 +1,60 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackPackageMakerGenerator_h
+#define cmCPackPackageMakerGenerator_h
+
+#include "cmCPackPKGGenerator.h"
+
+class cmCPackComponent;
+
+/** \class cmCPackPackageMakerGenerator
+ * \brief A generator for PackageMaker files
+ *
+ * http://developer.apple.com/documentation/Darwin
+ * /Reference/ManPages/man1/packagemaker.1.html
+ */
+class cmCPackPackageMakerGenerator : public cmCPackPKGGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackPackageMakerGenerator, cmCPackPKGGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackPackageMakerGenerator();
+ virtual ~cmCPackPackageMakerGenerator();
+ bool SupportsComponentInstallation() const;
+
+protected:
+ virtual int InitializeInternal();
+ int PackageFiles();
+ virtual const char* GetOutputExtension() { return ".dmg"; }
+
+ // Run PackageMaker with the given command line, which will (if
+ // successful) produce the given package file. Returns true if
+ // PackageMaker succeeds, false otherwise.
+ bool RunPackageMaker(const char* command, const char* packageFile);
+
+ // Generate a package in the file packageFile for the given
+ // component. All of the files within this component are stored in
+ // the directory packageDir. Returns true if successful, false
+ // otherwise.
+ bool GenerateComponentPackage(const char* packageFile,
+ const char* packageDir,
+ const cmCPackComponent& component);
+
+ double PackageMakerVersion;
+ unsigned int PackageCompatibilityVersion;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackProductBuildGenerator.cxx b/Source/CPack/cmCPackProductBuildGenerator.cxx
new file mode 100644
index 0000000..c2a13d0
--- /dev/null
+++ b/Source/CPack/cmCPackProductBuildGenerator.cxx
@@ -0,0 +1,231 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCPackProductBuildGenerator.h"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cmsys/Glob.hxx>
+#include <cmsys/SystemTools.hxx>
+
+cmCPackProductBuildGenerator::cmCPackProductBuildGenerator()
+{
+ this->componentPackageMethod = ONE_PACKAGE;
+}
+
+cmCPackProductBuildGenerator::~cmCPackProductBuildGenerator()
+{
+}
+
+int cmCPackProductBuildGenerator::PackageFiles()
+{
+ // TODO: Use toplevel
+ // It is used! Is this an obsolete comment?
+
+ std::string packageDirFileName =
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+
+ // Create the directory where component packages will be built.
+ std::string basePackageDir = packageDirFileName;
+ basePackageDir += "/Contents/Packages";
+ if (!cmsys::SystemTools::MakeDirectory(basePackageDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating component packages directory: "
+ << basePackageDir << std::endl);
+ return 0;
+ }
+
+ if (!this->Components.empty()) {
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ std::string packageDir = toplevel;
+ packageDir += '/';
+ packageDir += compIt->first;
+ if (!this->GenerateComponentPackage(basePackageDir,
+ GetPackageName(compIt->second),
+ packageDir, &compIt->second)) {
+ return 0;
+ }
+ }
+ } else {
+ if (!this->GenerateComponentPackage(basePackageDir,
+ this->GetOption("CPACK_PACKAGE_NAME"),
+ toplevel, NULL)) {
+ return 0;
+ }
+ }
+
+ // Copy or create all of the resource files we need.
+ std::string resDir = packageDirFileName + "/Contents";
+ if (!this->CopyCreateResourceFile("License", resDir.c_str()) ||
+ !this->CopyCreateResourceFile("ReadMe", resDir.c_str()) ||
+ !this->CopyCreateResourceFile("Welcome", resDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files"
+ << std::endl);
+ return 0;
+ }
+
+ // combine package(s) into a distribution
+ WriteDistributionFile(packageDirFileName.c_str());
+ std::ostringstream pkgCmd;
+
+ std::string version = this->GetOption("CPACK_PACKAGE_VERSION");
+ std::string productbuild = this->GetOption("CPACK_COMMAND_PRODUCTBUILD");
+
+ pkgCmd << productbuild << " --distribution \"" << packageDirFileName
+ << "/Contents/distribution.dist\""
+ << " --package-path \"" << packageDirFileName << "/Contents/Packages"
+ << "\""
+ << " --resources \"" << resDir << "\""
+ << " --version \"" << version << "\""
+ << " \"" << packageFileNames[0] << "\"";
+
+ // Run ProductBuild
+ return RunProductBuild(pkgCmd.str());
+}
+
+int cmCPackProductBuildGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/Applications");
+
+ std::vector<std::string> no_paths;
+ std::string program =
+ cmSystemTools::FindProgram("pkgbuild", no_paths, false);
+ if (program.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find pkgbuild executable"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_PKGBUILD", program.c_str());
+
+ program = cmSystemTools::FindProgram("productbuild", no_paths, false);
+ if (program.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find productbuild executable"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_PRODUCTBUILD", program.c_str());
+
+ return this->Superclass::InitializeInternal();
+}
+
+bool cmCPackProductBuildGenerator::RunProductBuild(const std::string& command)
+{
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/ProductBuildOutput.log";
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << command << std::endl);
+ std::string output, error_output;
+ int retVal = 1;
+ bool res =
+ cmSystemTools::RunSingleCommand(command.c_str(), &output, &error_output,
+ &retVal, 0, this->GeneratorVerbose, 0);
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running command" << std::endl);
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << command << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running command: " << command << std::endl
+ << "Please check " << tmpFile
+ << " for errors" << std::endl);
+ return false;
+ }
+ return true;
+}
+
+bool cmCPackProductBuildGenerator::GenerateComponentPackage(
+ const std::string& packageFileDir, const std::string& packageFileName,
+ const std::string& packageDir, const cmCPackComponent* component)
+{
+ std::string packageFile = packageFileDir;
+ packageFile += '/';
+ packageFile += packageFileName;
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Building component package: "
+ << packageFile << std::endl);
+
+ const char* comp_name = component ? component->Name.c_str() : NULL;
+
+ const char* preflight = this->GetComponentScript("PREFLIGHT", comp_name);
+ const char* postflight = this->GetComponentScript("POSTFLIGHT", comp_name);
+
+ std::string resDir = packageFileDir;
+ if (component) {
+ resDir += "/";
+ resDir += component->Name;
+ }
+ std::string scriptDir = resDir + "/scripts";
+
+ if (!cmsys::SystemTools::MakeDirectory(scriptDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating installer directory: " << scriptDir
+ << std::endl);
+ return 0;
+ }
+
+ // if preflight, postflight, or postupgrade are set
+ // then copy them into the script directory and make
+ // them executable
+ if (preflight) {
+ this->CopyInstallScript(scriptDir.c_str(), preflight, "preinstall");
+ }
+ if (postflight) {
+ this->CopyInstallScript(scriptDir.c_str(), postflight, "postinstall");
+ }
+
+ // The command that will be used to run ProductBuild
+ std::ostringstream pkgCmd;
+
+ std::string pkgId = "com.";
+ pkgId += this->GetOption("CPACK_PACKAGE_VENDOR");
+ pkgId += '.';
+ pkgId += this->GetOption("CPACK_PACKAGE_NAME");
+ if (component) {
+ pkgId += '.';
+ pkgId += component->Name;
+ }
+
+ std::string version = this->GetOption("CPACK_PACKAGE_VERSION");
+ std::string pkgbuild = this->GetOption("CPACK_COMMAND_PKGBUILD");
+
+ pkgCmd << pkgbuild << " --root \"" << packageDir << "\""
+ << " --identifier \"" << pkgId << "\""
+ << " --scripts \"" << scriptDir << "\""
+ << " --version \"" << version << "\""
+ << " --install-location \"/\""
+ << " \"" << packageFile << "\"";
+
+ // Run ProductBuild
+ return RunProductBuild(pkgCmd.str());
+}
+
+const char* cmCPackProductBuildGenerator::GetComponentScript(
+ const char* script, const char* component_name)
+{
+ std::string scriptname = std::string("CPACK_") + script + "_";
+ if (component_name) {
+ scriptname += cmSystemTools::UpperCase(component_name);
+ scriptname += "_";
+ }
+ scriptname += "SCRIPT";
+
+ return this->GetOption(scriptname);
+}
diff --git a/Source/CPack/cmCPackProductBuildGenerator.h b/Source/CPack/cmCPackProductBuildGenerator.h
new file mode 100644
index 0000000..b05b50a
--- /dev/null
+++ b/Source/CPack/cmCPackProductBuildGenerator.h
@@ -0,0 +1,58 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackProductBuildGenerator_h
+#define cmCPackProductBuildGenerator_h
+
+#include "cmCPackPKGGenerator.h"
+
+class cmCPackComponent;
+
+/** \class cmCPackProductBuildGenerator
+ * \brief A generator for ProductBuild files
+ *
+ */
+class cmCPackProductBuildGenerator : public cmCPackPKGGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackProductBuildGenerator, cmCPackPKGGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackProductBuildGenerator();
+ virtual ~cmCPackProductBuildGenerator();
+
+protected:
+ virtual int InitializeInternal();
+ int PackageFiles();
+ virtual const char* GetOutputExtension() { return ".pkg"; }
+
+ // Run ProductBuild with the given command line, which will (if
+ // successful) produce the given package file. Returns true if
+ // ProductBuild succeeds, false otherwise.
+ bool RunProductBuild(const std::string& command);
+
+ // Generate a package in the file packageFile for the given
+ // component. All of the files within this component are stored in
+ // the directory packageDir. Returns true if successful, false
+ // otherwise.
+ bool GenerateComponentPackage(const std::string& packageFileDir,
+ const std::string& packageFileName,
+ const std::string& packageDir,
+ const cmCPackComponent* component);
+
+ const char* GetComponentScript(const char* script,
+ const char* script_component);
+};
+
+#endif
diff --git a/Source/CPack/cmCPackRPMGenerator.cxx b/Source/CPack/cmCPackRPMGenerator.cxx
new file mode 100644
index 0000000..2568d17
--- /dev/null
+++ b/Source/CPack/cmCPackRPMGenerator.cxx
@@ -0,0 +1,253 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCPackRPMGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmSystemTools.h"
+
+cmCPackRPMGenerator::cmCPackRPMGenerator()
+{
+}
+
+cmCPackRPMGenerator::~cmCPackRPMGenerator()
+{
+}
+
+int cmCPackRPMGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
+ if (cmSystemTools::IsOff(this->GetOption("CPACK_SET_DESTDIR"))) {
+ this->SetOption("CPACK_SET_DESTDIR", "I_ON");
+ }
+ /* Replace space in CPACK_PACKAGE_NAME in order to avoid
+ * rpmbuild scream on unwanted space in filename issue
+ * Moreover RPM file do not usually embed space in filename
+ */
+ if (this->GetOption("CPACK_PACKAGE_NAME")) {
+ std::string packageName = this->GetOption("CPACK_PACKAGE_NAME");
+ std::replace(packageName.begin(), packageName.end(), ' ', '-');
+ this->SetOption("CPACK_PACKAGE_NAME", packageName.c_str());
+ }
+ /* same for CPACK_PACKAGE_FILE_NAME */
+ if (this->GetOption("CPACK_PACKAGE_FILE_NAME")) {
+ std::string packageName = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ std::replace(packageName.begin(), packageName.end(), ' ', '-');
+ this->SetOption("CPACK_PACKAGE_FILE_NAME", packageName.c_str());
+ }
+ return this->Superclass::InitializeInternal();
+}
+
+void cmCPackRPMGenerator::AddGeneratedPackageNames()
+{
+ // add the generated packages to package file names list
+ std::string fileNames(this->GetOption("GEN_CPACK_OUTPUT_FILES"));
+ const char sep = ';';
+ std::string::size_type pos1 = 0;
+ std::string::size_type pos2 = fileNames.find(sep, pos1 + 1);
+ while (pos2 != std::string::npos) {
+ packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
+ pos1 = pos2 + 1;
+ pos2 = fileNames.find(sep, pos1 + 1);
+ }
+ packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
+}
+
+int cmCPackRPMGenerator::PackageOnePack(std::string const& initialToplevel,
+ std::string const& packageName)
+{
+ int retval = 1;
+ // Begin the archive for this pack
+ std::string localToplevel(initialToplevel);
+ std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel));
+ std::string outputFileName(
+ GetComponentPackageFileName(this->GetOption("CPACK_PACKAGE_FILE_NAME"),
+ packageName, true) +
+ this->GetOutputExtension());
+
+ localToplevel += "/" + packageName;
+ /* replace the TEMP DIRECTORY with the component one */
+ this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
+ packageFileName += "/" + outputFileName;
+ /* replace proposed CPACK_OUTPUT_FILE_NAME */
+ this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
+ /* replace the TEMPORARY package file name */
+ this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
+ packageFileName.c_str());
+ // Tell CPackRPM.cmake the name of the component NAME.
+ this->SetOption("CPACK_RPM_PACKAGE_COMPONENT", packageName.c_str());
+ // Tell CPackRPM.cmake the path where the component is.
+ std::string component_path = "/";
+ component_path += packageName;
+ this->SetOption("CPACK_RPM_PACKAGE_COMPONENT_PART_PATH",
+ component_path.c_str());
+ if (!this->ReadListFile("CPackRPM.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while execution CPackRPM.cmake"
+ << std::endl);
+ retval = 0;
+ }
+
+ return retval;
+}
+
+int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
+{
+ int retval = 1;
+ /* Reset package file name list it will be populated during the
+ * component packaging run*/
+ packageFileNames.clear();
+ std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+
+ // The default behavior is to have one package by component group
+ // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
+ if (!ignoreGroup) {
+ std::map<std::string, cmCPackComponentGroup>::iterator compGIt;
+ for (compGIt = this->ComponentGroups.begin();
+ compGIt != this->ComponentGroups.end(); ++compGIt) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Packaging component group: "
+ << compGIt->first << std::endl);
+ retval &= PackageOnePack(initialTopLevel, compGIt->first);
+ }
+ // Handle Orphan components (components not belonging to any groups)
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ // Does the component belong to a group?
+ if (compIt->second.Group == CM_NULLPTR) {
+ cmCPackLogger(
+ cmCPackLog::LOG_VERBOSE, "Component <"
+ << compIt->second.Name
+ << "> does not belong to any group, package it separately."
+ << std::endl);
+ retval &= PackageOnePack(initialTopLevel, compIt->first);
+ }
+ }
+ }
+ // CPACK_COMPONENTS_IGNORE_GROUPS is set
+ // We build 1 package per component
+ else {
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ retval &= PackageOnePack(initialTopLevel, compIt->first);
+ }
+ }
+
+ if (retval) {
+ AddGeneratedPackageNames();
+ }
+
+ return retval;
+}
+
+int cmCPackRPMGenerator::PackageComponentsAllInOne(
+ const std::string& compInstDirName)
+{
+ int retval = 1;
+ /* Reset package file name list it will be populated during the
+ * component packaging run*/
+ packageFileNames.clear();
+ std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Packaging all groups in one package..."
+ "(CPACK_COMPONENTS_ALL_[GROUPS_]IN_ONE_PACKAGE is set)"
+ << std::endl);
+
+ // The ALL GROUPS in ONE package case
+ std::string localToplevel(initialTopLevel);
+ std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel));
+ std::string outputFileName(
+ std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) +
+ this->GetOutputExtension());
+ // all GROUP in one vs all COMPONENT in one
+ localToplevel += "/" + compInstDirName;
+
+ /* replace the TEMP DIRECTORY with the component one */
+ this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
+ packageFileName += "/" + outputFileName;
+ /* replace proposed CPACK_OUTPUT_FILE_NAME */
+ this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
+ /* replace the TEMPORARY package file name */
+ this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
+ packageFileName.c_str());
+
+ if (!compInstDirName.empty()) {
+ // Tell CPackRPM.cmake the path where the component is.
+ std::string component_path = "/";
+ component_path += compInstDirName;
+ this->SetOption("CPACK_RPM_PACKAGE_COMPONENT_PART_PATH",
+ component_path.c_str());
+ }
+
+ if (this->ReadListFile("CPackRPM.cmake")) {
+ AddGeneratedPackageNames();
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while execution CPackRPM.cmake"
+ << std::endl);
+ retval = 0;
+ }
+
+ return retval;
+}
+
+int cmCPackRPMGenerator::PackageFiles()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl);
+
+ /* Are we in the component packaging case */
+ if (WantsComponentInstallation()) {
+ // CASE 1 : COMPONENT ALL-IN-ONE package
+ // If ALL COMPONENTS in ONE package has been requested
+ // then the package file is unique and should be open here.
+ if (componentPackageMethod == ONE_PACKAGE) {
+ return PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE");
+ }
+ // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
+ // There will be 1 package for each component group
+ // however one may require to ignore component group and
+ // in this case you'll get 1 package for each component.
+ else {
+ return PackageComponents(componentPackageMethod ==
+ ONE_PACKAGE_PER_COMPONENT);
+ }
+ }
+ // CASE 3 : NON COMPONENT package.
+ else {
+ return PackageComponentsAllInOne("");
+ }
+}
+
+bool cmCPackRPMGenerator::SupportsComponentInstallation() const
+{
+ return IsOn("CPACK_RPM_COMPONENT_INSTALL");
+}
+
+std::string cmCPackRPMGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ if (componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) {
+ return componentName;
+ }
+
+ if (componentPackageMethod == ONE_PACKAGE) {
+ return std::string("ALL_COMPONENTS_IN_ONE");
+ }
+ // We have to find the name of the COMPONENT GROUP
+ // the current COMPONENT belongs to.
+ std::string groupVar =
+ "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP";
+ if (CM_NULLPTR != GetOption(groupVar)) {
+ return std::string(GetOption(groupVar));
+ } else {
+ return componentName;
+ }
+}
diff --git a/Source/CPack/cmCPackRPMGenerator.h b/Source/CPack/cmCPackRPMGenerator.h
new file mode 100644
index 0000000..4baef08
--- /dev/null
+++ b/Source/CPack/cmCPackRPMGenerator.h
@@ -0,0 +1,78 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackRPMGenerator_h
+#define cmCPackRPMGenerator_h
+
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackRPMGenerator
+ * \brief A generator for RPM packages
+ * The idea of the CPack RPM generator is to use
+ * as minimal C++ code as possible.
+ * Ideally the C++ part of the CPack RPM generator
+ * will only 'execute' (aka ->ReadListFile) several
+ * CMake macros files.
+ */
+class cmCPackRPMGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackRPMGenerator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackRPMGenerator();
+ ~cmCPackRPMGenerator() CM_OVERRIDE;
+
+ static bool CanGenerate()
+ {
+#ifdef __APPLE__
+ // on MacOS enable CPackRPM iff rpmbuild is found
+ std::vector<std::string> locations;
+ locations.push_back("/sw/bin"); // Fink
+ locations.push_back("/opt/local/bin"); // MacPorts
+ return cmSystemTools::FindProgram("rpmbuild") != "" ? true : false;
+#else
+ // legacy behavior on other systems
+ return true;
+#endif
+ }
+
+protected:
+ int InitializeInternal() CM_OVERRIDE;
+ int PackageFiles() CM_OVERRIDE;
+ /**
+ * This method factors out the work done in component packaging case.
+ */
+ int PackageOnePack(std::string const& initialToplevel,
+ std::string const& packageName);
+ /**
+ * The method used to package files when component
+ * install is used. This will create one
+ * archive for each component group.
+ */
+ int PackageComponents(bool ignoreGroup);
+ /**
+ * Special case of component install where all
+ * components will be put in a single installer.
+ */
+ int PackageComponentsAllInOne(const std::string& compInstDirName);
+ const char* GetOutputExtension() CM_OVERRIDE { return ".rpm"; }
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+ std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName) CM_OVERRIDE;
+
+ void AddGeneratedPackageNames();
+};
+
+#endif
diff --git a/Source/CPack/cmCPackSTGZGenerator.cxx b/Source/CPack/cmCPackSTGZGenerator.cxx
new file mode 100644
index 0000000..4d07a7e
--- /dev/null
+++ b/Source/CPack/cmCPackSTGZGenerator.cxx
@@ -0,0 +1,125 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackSTGZGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cmsys/FStream.hxx>
+
+#include <sys/types.h>
+// include sys/stat.h after sys/types.h
+#include <sys/stat.h>
+
+cmCPackSTGZGenerator::cmCPackSTGZGenerator()
+{
+}
+
+cmCPackSTGZGenerator::~cmCPackSTGZGenerator()
+{
+}
+
+int cmCPackSTGZGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "0");
+
+ std::string inFile = this->FindTemplate("CPack.STGZ_Header.sh.in");
+ if (inFile.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find template file: " << inFile << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_STGZ_HEADER_FILE", inFile.c_str());
+ this->SetOptionIfNotSet("CPACK_AT_SIGN", "@");
+
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackSTGZGenerator::PackageFiles()
+{
+ bool retval = true;
+ if (!this->Superclass::PackageFiles()) {
+ return 0;
+ }
+
+ /* TGZ generator (our Superclass) may
+ * have generated several packages (component packaging)
+ * so we must iterate over generated packages.
+ */
+ for (std::vector<std::string>::iterator it = packageFileNames.begin();
+ it != packageFileNames.end(); ++it) {
+ retval &= cmSystemTools::SetPermissions((*it).c_str(),
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ S_IREAD | S_IWRITE | S_IEXEC
+#else
+ S_IRUSR | S_IWUSR | S_IXUSR |
+ S_IRGRP | S_IWGRP | S_IXGRP |
+ S_IROTH | S_IWOTH | S_IXOTH
+#endif
+ );
+ }
+ return retval;
+}
+
+int cmCPackSTGZGenerator::GenerateHeader(std::ostream* os)
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Writing header" << std::endl);
+ std::ostringstream str;
+ int counter = 0;
+
+ std::string inLicFile = this->GetOption("CPACK_RESOURCE_FILE_LICENSE");
+ std::string line;
+ cmsys::ifstream ilfs(inLicFile.c_str());
+ std::string licenseText;
+ while (cmSystemTools::GetLineFromStream(ilfs, line)) {
+ licenseText += line + "\n";
+ }
+ this->SetOptionIfNotSet("CPACK_RESOURCE_FILE_LICENSE_CONTENT",
+ licenseText.c_str());
+
+ const char headerLengthTag[] = "###CPACK_HEADER_LENGTH###";
+
+ // Create the header
+ std::string inFile = this->GetOption("CPACK_STGZ_HEADER_FILE");
+ cmsys::ifstream ifs(inFile.c_str());
+ std::string packageHeaderText;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ packageHeaderText += line + "\n";
+ }
+
+ // Configure in the values
+ std::string res;
+ this->ConfigureString(packageHeaderText, res);
+
+ // Count the lines
+ const char* ptr = res.c_str();
+ while (*ptr) {
+ if (*ptr == '\n') {
+ counter++;
+ }
+ ++ptr;
+ }
+ counter++;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Number of lines: " << counter
+ << std::endl);
+ char buffer[1024];
+ sprintf(buffer, "%d", counter);
+ cmSystemTools::ReplaceString(res, headerLengthTag, buffer);
+
+ // Write in file
+ *os << res;
+ return this->Superclass::GenerateHeader(os);
+}
diff --git a/Source/CPack/cmCPackSTGZGenerator.h b/Source/CPack/cmCPackSTGZGenerator.h
new file mode 100644
index 0000000..94cc8aa
--- /dev/null
+++ b/Source/CPack/cmCPackSTGZGenerator.h
@@ -0,0 +1,40 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackSTGZGenerator_h
+#define cmCPackSTGZGenerator_h
+
+#include "cmCPackTGZGenerator.h"
+
+/** \class cmCPackSTGZGenerator
+ * \brief A generator for Self extractable TGZ files
+ *
+ */
+class cmCPackSTGZGenerator : public cmCPackTGZGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackSTGZGenerator, cmCPackTGZGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackSTGZGenerator();
+ ~cmCPackSTGZGenerator() CM_OVERRIDE;
+
+protected:
+ int PackageFiles() CM_OVERRIDE;
+ int InitializeInternal() CM_OVERRIDE;
+ int GenerateHeader(std::ostream* os) CM_OVERRIDE;
+ const char* GetOutputExtension() CM_OVERRIDE { return ".sh"; }
+};
+
+#endif
diff --git a/Source/CPack/cmCPackTGZGenerator.cxx b/Source/CPack/cmCPackTGZGenerator.cxx
new file mode 100644
index 0000000..7c5c245
--- /dev/null
+++ b/Source/CPack/cmCPackTGZGenerator.cxx
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackTGZGenerator.h"
+
+cmCPackTGZGenerator::cmCPackTGZGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressGZip, "paxr")
+{
+}
+
+cmCPackTGZGenerator::~cmCPackTGZGenerator()
+{
+}
diff --git a/Source/CPack/cmCPackTGZGenerator.h b/Source/CPack/cmCPackTGZGenerator.h
new file mode 100644
index 0000000..cb7620c
--- /dev/null
+++ b/Source/CPack/cmCPackTGZGenerator.h
@@ -0,0 +1,36 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackTGZGenerator_h
+#define cmCPackTGZGenerator_h
+
+#include "cmCPackArchiveGenerator.h"
+
+/** \class cmCPackTGZGenerator
+ * \brief A generator for TGZ files
+ *
+ */
+class cmCPackTGZGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackTGZGenerator, cmCPackArchiveGenerator);
+ /**
+ * Construct generator
+ */
+ cmCPackTGZGenerator();
+ ~cmCPackTGZGenerator() CM_OVERRIDE;
+
+protected:
+ const char* GetOutputExtension() CM_OVERRIDE { return ".tar.gz"; }
+};
+
+#endif
diff --git a/Source/CPack/cmCPackTXZGenerator.cxx b/Source/CPack/cmCPackTXZGenerator.cxx
new file mode 100644
index 0000000..d17a164
--- /dev/null
+++ b/Source/CPack/cmCPackTXZGenerator.cxx
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackTXZGenerator.h"
+
+cmCPackTXZGenerator::cmCPackTXZGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressXZ, "paxr")
+{
+}
+
+cmCPackTXZGenerator::~cmCPackTXZGenerator()
+{
+}
diff --git a/Source/CPack/cmCPackTXZGenerator.h b/Source/CPack/cmCPackTXZGenerator.h
new file mode 100644
index 0000000..87c92ef
--- /dev/null
+++ b/Source/CPack/cmCPackTXZGenerator.h
@@ -0,0 +1,36 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackTXZGenerator_h
+#define cmCPackTXZGenerator_h
+
+#include "cmCPackArchiveGenerator.h"
+
+/** \class cmCPackTXZGenerator
+ * \brief A generator for TXZ files
+ *
+ */
+class cmCPackTXZGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackTXZGenerator, cmCPackArchiveGenerator);
+ /**
+ * Construct generator
+ */
+ cmCPackTXZGenerator();
+ ~cmCPackTXZGenerator() CM_OVERRIDE;
+
+protected:
+ const char* GetOutputExtension() CM_OVERRIDE { return ".tar.xz"; }
+};
+
+#endif
diff --git a/Source/CPack/cmCPackTarBZip2Generator.cxx b/Source/CPack/cmCPackTarBZip2Generator.cxx
new file mode 100644
index 0000000..694d392
--- /dev/null
+++ b/Source/CPack/cmCPackTarBZip2Generator.cxx
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackTarBZip2Generator.h"
+
+cmCPackTarBZip2Generator::cmCPackTarBZip2Generator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressBZip2, "paxr")
+{
+}
+
+cmCPackTarBZip2Generator::~cmCPackTarBZip2Generator()
+{
+}
diff --git a/Source/CPack/cmCPackTarBZip2Generator.h b/Source/CPack/cmCPackTarBZip2Generator.h
new file mode 100644
index 0000000..6fec882
--- /dev/null
+++ b/Source/CPack/cmCPackTarBZip2Generator.h
@@ -0,0 +1,35 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackTarBZip2Generator_h
+#define cmCPackTarBZip2Generator_h
+
+#include "cmCPackArchiveGenerator.h"
+
+/** \class cmCPackTarBZip2Generator
+ * \brief A generator for TarBZip2 files
+ */
+class cmCPackTarBZip2Generator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackTarBZip2Generator, cmCPackArchiveGenerator);
+ /**
+ * Construct generator
+ */
+ cmCPackTarBZip2Generator();
+ ~cmCPackTarBZip2Generator() CM_OVERRIDE;
+
+protected:
+ const char* GetOutputExtension() CM_OVERRIDE { return ".tar.bz2"; }
+};
+
+#endif
diff --git a/Source/CPack/cmCPackTarCompressGenerator.cxx b/Source/CPack/cmCPackTarCompressGenerator.cxx
new file mode 100644
index 0000000..aec6893
--- /dev/null
+++ b/Source/CPack/cmCPackTarCompressGenerator.cxx
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackTarCompressGenerator.h"
+
+cmCPackTarCompressGenerator::cmCPackTarCompressGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressCompress, "paxr")
+{
+}
+
+cmCPackTarCompressGenerator::~cmCPackTarCompressGenerator()
+{
+}
diff --git a/Source/CPack/cmCPackTarCompressGenerator.h b/Source/CPack/cmCPackTarCompressGenerator.h
new file mode 100644
index 0000000..02926a2
--- /dev/null
+++ b/Source/CPack/cmCPackTarCompressGenerator.h
@@ -0,0 +1,35 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackTarCompressGenerator_h
+#define cmCPackTarCompressGenerator_h
+
+#include "cmCPackTGZGenerator.h"
+
+/** \class cmCPackTarCompressGenerator
+ * \brief A generator for TarCompress files
+ */
+class cmCPackTarCompressGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackTarCompressGenerator, cmCPackArchiveGenerator);
+ /**
+ * Construct generator
+ */
+ cmCPackTarCompressGenerator();
+ ~cmCPackTarCompressGenerator() CM_OVERRIDE;
+
+protected:
+ const char* GetOutputExtension() CM_OVERRIDE { return ".tar.Z"; }
+};
+
+#endif
diff --git a/Source/CPack/cmCPackZIPGenerator.cxx b/Source/CPack/cmCPackZIPGenerator.cxx
new file mode 100644
index 0000000..9b42e6d
--- /dev/null
+++ b/Source/CPack/cmCPackZIPGenerator.cxx
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackZIPGenerator.h"
+
+cmCPackZIPGenerator::cmCPackZIPGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressNone, "zip")
+{
+}
+
+cmCPackZIPGenerator::~cmCPackZIPGenerator()
+{
+}
diff --git a/Source/CPack/cmCPackZIPGenerator.h b/Source/CPack/cmCPackZIPGenerator.h
new file mode 100644
index 0000000..1130826
--- /dev/null
+++ b/Source/CPack/cmCPackZIPGenerator.h
@@ -0,0 +1,36 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackZIPGenerator_h
+#define cmCPackZIPGenerator_h
+
+#include "cmCPackArchiveGenerator.h"
+
+/** \class cmCPackZIPGenerator
+ * \brief A generator for ZIP files
+ */
+class cmCPackZIPGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackZIPGenerator, cmCPackArchiveGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackZIPGenerator();
+ ~cmCPackZIPGenerator() CM_OVERRIDE;
+
+protected:
+ const char* GetOutputExtension() CM_OVERRIDE { return ".zip"; }
+};
+
+#endif
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
new file mode 100644
index 0000000..771519c
--- /dev/null
+++ b/Source/CPack/cpack.cxx
@@ -0,0 +1,429 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSystemTools.h"
+
+// Need these for documentation support.
+#include "cmCPackGenerator.h"
+#include "cmCPackGeneratorFactory.h"
+#include "cmDocumentation.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmake.h"
+#include "cmake.h"
+
+#include "cmCPackLog.h"
+
+#include <cmsys/CommandLineArguments.hxx>
+#include <cmsys/Encoding.hxx>
+#include <cmsys/SystemTools.hxx>
+
+static const char* cmDocumentationName[][2] = {
+ { CM_NULLPTR, " cpack - Packaging driver provided by CMake." },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+static const char* cmDocumentationUsage[][2] = {
+ { CM_NULLPTR, " cpack -G <generator> [options]" },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+static const char* cmDocumentationOptions[][2] = {
+ { "-G <generator>", "Use the specified generator to generate package." },
+ { "-C <Configuration>", "Specify the project configuration" },
+ { "-D <var>=<value>", "Set a CPack variable." },
+ { "--config <config file>", "Specify the config file." },
+ { "--verbose,-V", "enable verbose output" },
+ { "--debug", "enable debug output (for CPack developers)" },
+ { "-P <package name>", "override/define CPACK_PACKAGE_NAME" },
+ { "-R <package version>", "override/define CPACK_PACKAGE_VERSION" },
+ { "-B <package directory>", "override/define CPACK_PACKAGE_DIRECTORY" },
+ { "--vendor <vendor name>", "override/define CPACK_PACKAGE_VENDOR" },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+int cpackUnknownArgument(const char*, void*)
+{
+ return 1;
+}
+
+struct cpackDefinitions
+{
+ typedef std::map<std::string, std::string> MapType;
+ MapType Map;
+ cmCPackLog* Log;
+};
+
+int cpackDefinitionArgument(const char* argument, const char* cValue,
+ void* call_data)
+{
+ (void)argument;
+ cpackDefinitions* def = static_cast<cpackDefinitions*>(call_data);
+ std::string value = cValue;
+ size_t pos = value.find_first_of('=');
+ if (pos == std::string::npos) {
+ cmCPack_Log(def->Log, cmCPackLog::LOG_ERROR,
+ "Please specify CPack definitions as: KEY=VALUE" << std::endl);
+ return 0;
+ }
+ std::string key = value.substr(0, pos);
+ value = value.c_str() + pos + 1;
+ def->Map[key] = value;
+ cmCPack_Log(def->Log, cmCPackLog::LOG_DEBUG, "Set CPack variable: "
+ << key << " to \"" << value << "\"" << std::endl);
+ return 1;
+}
+
+// this is CPack.
+int main(int argc, char const* const* argv)
+{
+ cmsys::Encoding::CommandLineArguments args =
+ cmsys::Encoding::CommandLineArguments::Main(argc, argv);
+ argc = args.argc();
+ argv = args.argv();
+
+ cmSystemTools::FindCMakeResources(argv[0]);
+ cmCPackLog log;
+
+ log.SetErrorPrefix("CPack Error: ");
+ log.SetWarningPrefix("CPack Warning: ");
+ log.SetOutputPrefix("CPack: ");
+ log.SetVerbosePrefix("CPack Verbose: ");
+
+ cmSystemTools::EnableMSVCDebugHook();
+
+ if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Current working directory cannot be established."
+ << std::endl);
+ return 1;
+ }
+
+ std::string generator;
+ bool help = false;
+ bool helpVersion = false;
+ bool verbose = false;
+ bool debug = false;
+ std::string helpFull;
+ std::string helpMAN;
+ std::string helpHTML;
+
+ std::string cpackProjectName;
+ std::string cpackProjectDirectory;
+ std::string cpackBuildConfig;
+ std::string cpackProjectVersion;
+ std::string cpackProjectPatch;
+ std::string cpackProjectVendor;
+ std::string cpackConfigFile;
+
+ cpackDefinitions definitions;
+ definitions.Log = &log;
+
+ cpackConfigFile = "";
+
+ cmsys::CommandLineArguments arg;
+ arg.Initialize(argc, argv);
+ typedef cmsys::CommandLineArguments argT;
+ // Help arguments
+ arg.AddArgument("--help", argT::NO_ARGUMENT, &help, "CPack help");
+ arg.AddArgument("--help-full", argT::SPACE_ARGUMENT, &helpFull,
+ "CPack help");
+ arg.AddArgument("--help-html", argT::SPACE_ARGUMENT, &helpHTML,
+ "CPack help");
+ arg.AddArgument("--help-man", argT::SPACE_ARGUMENT, &helpMAN, "CPack help");
+ arg.AddArgument("--version", argT::NO_ARGUMENT, &helpVersion, "CPack help");
+
+ arg.AddArgument("-V", argT::NO_ARGUMENT, &verbose, "CPack verbose");
+ arg.AddArgument("--verbose", argT::NO_ARGUMENT, &verbose, "-V");
+ arg.AddArgument("--debug", argT::NO_ARGUMENT, &debug, "-V");
+ arg.AddArgument("--config", argT::SPACE_ARGUMENT, &cpackConfigFile,
+ "CPack configuration file");
+ arg.AddArgument("-C", argT::SPACE_ARGUMENT, &cpackBuildConfig,
+ "CPack build configuration");
+ arg.AddArgument("-G", argT::SPACE_ARGUMENT, &generator, "CPack generator");
+ arg.AddArgument("-P", argT::SPACE_ARGUMENT, &cpackProjectName,
+ "CPack project name");
+ arg.AddArgument("-R", argT::SPACE_ARGUMENT, &cpackProjectVersion,
+ "CPack project version");
+ arg.AddArgument("-B", argT::SPACE_ARGUMENT, &cpackProjectDirectory,
+ "CPack project directory");
+ arg.AddArgument("--patch", argT::SPACE_ARGUMENT, &cpackProjectPatch,
+ "CPack project patch");
+ arg.AddArgument("--vendor", argT::SPACE_ARGUMENT, &cpackProjectVendor,
+ "CPack project vendor");
+ arg.AddCallback("-D", argT::SPACE_ARGUMENT, cpackDefinitionArgument,
+ &definitions, "CPack Definitions");
+ arg.SetUnknownArgumentCallback(cpackUnknownArgument);
+
+ // Parse command line
+ int parsed = arg.Parse();
+
+ // Setup logging
+ if (verbose) {
+ log.SetVerbose(verbose);
+ cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Verbose" << std::endl);
+ }
+ if (debug) {
+ log.SetDebug(debug);
+ cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Debug" << std::endl);
+ }
+
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
+ "Read CPack config file: " << cpackConfigFile << std::endl);
+
+ cmake cminst;
+ cminst.SetHomeDirectory("");
+ cminst.SetHomeOutputDirectory("");
+ cminst.GetCurrentSnapshot().SetDefaultDefinitions();
+ cminst.GetState()->RemoveUnscriptableCommands();
+ cmGlobalGenerator cmgg(&cminst);
+ CM_AUTO_PTR<cmMakefile> globalMF(
+ new cmMakefile(&cmgg, cminst.GetCurrentSnapshot()));
+#if defined(__CYGWIN__)
+ globalMF->AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0");
+#endif
+
+ bool cpackConfigFileSpecified = true;
+ if (cpackConfigFile.empty()) {
+ cpackConfigFile = cmSystemTools::GetCurrentWorkingDirectory();
+ cpackConfigFile += "/CPackConfig.cmake";
+ cpackConfigFileSpecified = false;
+ }
+
+ cmCPackGeneratorFactory generators;
+ generators.SetLogger(&log);
+ cmCPackGenerator* cpackGenerator = CM_NULLPTR;
+
+ cmDocumentation doc;
+ doc.addCPackStandardDocSections();
+ /* Were we invoked to display doc or to do some work ?
+ * Unlike cmake launching cpack with zero argument
+ * should launch cpack using "cpackConfigFile" if it exists
+ * in the current directory.
+ */
+ help = doc.CheckOptions(argc, argv, "-G") && argc != 1;
+
+ // This part is used for cpack documentation lookup as well.
+ cminst.AddCMakePaths();
+
+ if (parsed && !help) {
+ // find out which system cpack is running on, so it can setup the search
+ // paths, so FIND_XXX() commands can be used in scripts
+ std::string systemFile =
+ globalMF->GetModulesFile("CMakeDetermineSystem.cmake");
+ if (!globalMF->ReadListFile(systemFile.c_str())) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Error reading CMakeDetermineSystem.cmake" << std::endl);
+ return 1;
+ }
+
+ systemFile =
+ globalMF->GetModulesFile("CMakeSystemSpecificInformation.cmake");
+ if (!globalMF->ReadListFile(systemFile.c_str())) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Error reading CMakeSystemSpecificInformation.cmake"
+ << std::endl);
+ return 1;
+ }
+
+ if (!cpackBuildConfig.empty()) {
+ globalMF->AddDefinition("CPACK_BUILD_CONFIG", cpackBuildConfig.c_str());
+ }
+
+ if (cmSystemTools::FileExists(cpackConfigFile.c_str())) {
+ cpackConfigFile = cmSystemTools::CollapseFullPath(cpackConfigFile);
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
+ "Read CPack configuration file: " << cpackConfigFile
+ << std::endl);
+ if (!globalMF->ReadListFile(cpackConfigFile.c_str())) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Problem reading CPack config file: \""
+ << cpackConfigFile << "\"" << std::endl);
+ return 1;
+ }
+ } else if (cpackConfigFileSpecified) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Cannot find CPack config file: \"" << cpackConfigFile
+ << "\"" << std::endl);
+ return 1;
+ }
+
+ if (!generator.empty()) {
+ globalMF->AddDefinition("CPACK_GENERATOR", generator.c_str());
+ }
+ if (!cpackProjectName.empty()) {
+ globalMF->AddDefinition("CPACK_PACKAGE_NAME", cpackProjectName.c_str());
+ }
+ if (!cpackProjectVersion.empty()) {
+ globalMF->AddDefinition("CPACK_PACKAGE_VERSION",
+ cpackProjectVersion.c_str());
+ }
+ if (!cpackProjectVendor.empty()) {
+ globalMF->AddDefinition("CPACK_PACKAGE_VENDOR",
+ cpackProjectVendor.c_str());
+ }
+ // if this is not empty it has been set on the command line
+ // go for it. Command line override values set in config file.
+ if (!cpackProjectDirectory.empty()) {
+ globalMF->AddDefinition("CPACK_PACKAGE_DIRECTORY",
+ cpackProjectDirectory.c_str());
+ }
+ // The value has not been set on the command line
+ else {
+ // get a default value (current working directory)
+ cpackProjectDirectory = cmsys::SystemTools::GetCurrentWorkingDirectory();
+ // use default value iff no value has been provided by the config file
+ if (!globalMF->IsSet("CPACK_PACKAGE_DIRECTORY")) {
+ globalMF->AddDefinition("CPACK_PACKAGE_DIRECTORY",
+ cpackProjectDirectory.c_str());
+ }
+ }
+ cpackDefinitions::MapType::iterator cdit;
+ for (cdit = definitions.Map.begin(); cdit != definitions.Map.end();
+ ++cdit) {
+ globalMF->AddDefinition(cdit->first, cdit->second.c_str());
+ }
+
+ const char* cpackModulesPath =
+ globalMF->GetDefinition("CPACK_MODULE_PATH");
+ if (cpackModulesPath) {
+ globalMF->AddDefinition("CMAKE_MODULE_PATH", cpackModulesPath);
+ }
+ const char* genList = globalMF->GetDefinition("CPACK_GENERATOR");
+ if (!genList) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "CPack generator not specified"
+ << std::endl);
+ } else {
+ std::vector<std::string> generatorsVector;
+ cmSystemTools::ExpandListArgument(genList, generatorsVector);
+ std::vector<std::string>::iterator it;
+ for (it = generatorsVector.begin(); it != generatorsVector.end(); ++it) {
+ const char* gen = it->c_str();
+ cmMakefile::ScopePushPop raii(globalMF.get());
+ cmMakefile* mf = globalMF.get();
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
+ "Specified generator: " << gen << std::endl);
+ if (parsed && !mf->GetDefinition("CPACK_PACKAGE_NAME")) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "CPack project name not specified" << std::endl);
+ parsed = 0;
+ }
+ if (parsed &&
+ !(mf->GetDefinition("CPACK_PACKAGE_VERSION") ||
+ (mf->GetDefinition("CPACK_PACKAGE_VERSION_MAJOR") &&
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR") &&
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH")))) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "CPack project version not specified"
+ << std::endl
+ << "Specify CPACK_PACKAGE_VERSION, or "
+ "CPACK_PACKAGE_VERSION_MAJOR, "
+ "CPACK_PACKAGE_VERSION_MINOR, and "
+ "CPACK_PACKAGE_VERSION_PATCH."
+ << std::endl);
+ parsed = 0;
+ }
+ if (parsed) {
+ cpackGenerator = generators.NewGenerator(gen);
+ if (!cpackGenerator) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Cannot initialize CPack generator: " << gen
+ << std::endl);
+ parsed = 0;
+ }
+ if (parsed && !cpackGenerator->Initialize(gen, mf)) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Cannot initialize the generator " << gen
+ << std::endl);
+ parsed = 0;
+ }
+
+ if (!mf->GetDefinition("CPACK_INSTALL_COMMANDS") &&
+ !mf->GetDefinition("CPACK_INSTALLED_DIRECTORIES") &&
+ !mf->GetDefinition("CPACK_INSTALL_CMAKE_PROJECTS")) {
+ cmCPack_Log(
+ &log, cmCPackLog::LOG_ERROR,
+ "Please specify build tree of the project that uses CMake "
+ "using CPACK_INSTALL_CMAKE_PROJECTS, specify "
+ "CPACK_INSTALL_COMMANDS, or specify "
+ "CPACK_INSTALLED_DIRECTORIES."
+ << std::endl);
+ parsed = 0;
+ }
+ if (parsed) {
+ const char* projName = mf->GetDefinition("CPACK_PACKAGE_NAME");
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, "Use generator: "
+ << cpackGenerator->GetNameOfClass() << std::endl);
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
+ "For project: " << projName << std::endl);
+
+ const char* projVersion =
+ mf->GetDefinition("CPACK_PACKAGE_VERSION");
+ if (!projVersion) {
+ const char* projVersionMajor =
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_MAJOR");
+ const char* projVersionMinor =
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR");
+ const char* projVersionPatch =
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH");
+ std::ostringstream ostr;
+ ostr << projVersionMajor << "." << projVersionMinor << "."
+ << projVersionPatch;
+ mf->AddDefinition("CPACK_PACKAGE_VERSION", ostr.str().c_str());
+ }
+
+ int res = cpackGenerator->DoPackage();
+ if (!res) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Error when generating package: " << projName
+ << std::endl);
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* In this case we are building the documentation object
+ * instance in order to create appropriate structure
+ * in order to satisfy the appropriate --help-xxx request
+ */
+ if (help) {
+ // Construct and print requested documentation.
+
+ doc.SetName("cpack");
+ doc.SetSection("Name", cmDocumentationName);
+ doc.SetSection("Usage", cmDocumentationUsage);
+ doc.PrependSection("Options", cmDocumentationOptions);
+
+ std::vector<cmDocumentationEntry> v;
+ cmCPackGeneratorFactory::DescriptionsMap::const_iterator generatorIt;
+ for (generatorIt = generators.GetGeneratorsList().begin();
+ generatorIt != generators.GetGeneratorsList().end(); ++generatorIt) {
+ cmDocumentationEntry e;
+ e.Name = generatorIt->first;
+ e.Brief = generatorIt->second;
+ v.push_back(e);
+ }
+ doc.SetSection("Generators", v);
+
+#undef cout
+ return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
+#define cout no_cout_use_cmCPack_Log
+ }
+
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/Source/CPack/cygwin.readme b/Source/CPack/cygwin.readme
new file mode 100644
index 0000000..c0cd4b9
--- /dev/null
+++ b/Source/CPack/cygwin.readme
@@ -0,0 +1,69 @@
+http://cygwin.com/setup.html
+
+
+Need to produce two tar files:
+
+Source-
+
+- create subdirs
+- copy src
+- duplicate src
+- configure files into duplicate src
+ CPack.cygwin-readme.in
+ CPack.cygwin-install.sh.in
+ CPack.setup.hint.in
+- diff duplicate src and orig src
+- write diff into toplevel
+- create tar file call super class
+
+cmake-2.2.3-1
+
+
+1. a source release
+cmake-2.2.3-2-src.tar.bz2
+
+cmake-2.2.3-2.patch has cmake-2.2.3/CYGWIN-PATCHES/cmake.README cmake-2.2.3/CYGWIN-PATCHES/setup.hint
+cmake-2.2.3-2.sh -> script to create cygwin release
+cmake-2.2.3.tar.bz2 -> unmodified cmake sources for 2.2.3
+
+
+
+
+
+2 a binary release
+cmake-2.2.3-2.tar.bz2
+
+normal binary release with use as the root of the tree:
+
+Here is the bootstrap command used:
+
+ ${SOURCE_DIR}/bootstrap --prefix=/usr --datadir=/share/cmake-${VER} \
+ --docdir=/share/doc/cmake-${VER} --mandir=/share/man
+
+CMAKE_DOC_DIR /share/doc/${PKG}-${VER}
+CMAKE_MAN_DIR /share/man
+CMAKE_DATA_DIR /share/${PKG}-${VER}
+
+Here is the directory stucture:
+
+usr/bin/cmake.exe
+usr/share/doc/cmake-2.2.3/MANIFEST ***
+usr/share/doc/Cygwin/cmake-2.2.3-2.README ****
+usr/share/cmake-2.2.3/Modules
+
+
+
+usr/bin
+usr/share/cmake-2.2.3/include
+usr/share/cmake-2.2.3/Modules/Platform
+usr/share/cmake-2.2.3/Modules
+usr/share/cmake-2.2.3/Templates
+usr/share/cmake-2.2.3
+usr/share/doc/cmake-2.2.3
+usr/share/doc/Cygwin
+usr/share/doc
+usr/share/man/man1
+usr/share/man
+usr/share
+usr
+
diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx
new file mode 100644
index 0000000..0e08e1c
--- /dev/null
+++ b/Source/CTest/cmCTestBZR.cxx
@@ -0,0 +1,474 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestBZR.h"
+
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+#include <cm_expat.h>
+
+extern "C" int cmBZRXMLParserUnknownEncodingHandler(void*,
+ const XML_Char* name,
+ XML_Encoding* info)
+{
+ static const int latin1[] = {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011,
+ 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A,
+ 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, 0x0022, 0x0023,
+ 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C,
+ 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035,
+ 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E,
+ 0x003F, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059,
+ 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060, 0x0061, 0x0062,
+ 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B,
+ 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074,
+ 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D,
+ 0x007E, 0x007F, 0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020,
+ 0x2021, 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x017D, 0x008F,
+ 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC,
+ 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x017E, 0x0178, 0x00A0, 0x00A1,
+ 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA,
+ 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3,
+ 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC,
+ 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5,
+ 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE,
+ 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0,
+ 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9,
+ 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2,
+ 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB,
+ 0x00FC, 0x00FD, 0x00FE, 0x00FF
+ };
+
+ // The BZR xml output plugin can use some encodings that are not
+ // recognized by expat. This will lead to an error, e.g. "Error
+ // parsing bzr log xml: unknown encoding", the following is a
+ // workaround for these unknown encodings.
+ if (name == std::string("ascii") || name == std::string("cp1252") ||
+ name == std::string("ANSI_X3.4-1968")) {
+ for (unsigned int i = 0; i < 256; ++i) {
+ info->map[i] = latin1[i];
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+cmCTestBZR::cmCTestBZR(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
+{
+ this->PriorRev = this->Unknown;
+ // Even though it is specified in the documentation, with bzr 1.13
+ // BZR_PROGRESS_BAR has no effect. In the future this bug might be fixed.
+ // Since it doesn't hurt, we specify this environment variable.
+ cmSystemTools::PutEnv("BZR_PROGRESS_BAR=none");
+}
+
+cmCTestBZR::~cmCTestBZR()
+{
+}
+
+class cmCTestBZR::InfoParser : public cmCTestVC::LineParser
+{
+public:
+ InfoParser(cmCTestBZR* bzr, const char* prefix)
+ : BZR(bzr)
+ , CheckOutFound(false)
+ {
+ this->SetLog(&bzr->Log, prefix);
+ this->RegexCheckOut.compile("checkout of branch: *([^\t\r\n]+)$");
+ this->RegexParent.compile("parent branch: *([^\t\r\n]+)$");
+ }
+
+private:
+ cmCTestBZR* BZR;
+ bool CheckOutFound;
+ cmsys::RegularExpression RegexCheckOut;
+ cmsys::RegularExpression RegexParent;
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexCheckOut.find(this->Line)) {
+ this->BZR->URL = this->RegexCheckOut.match(1);
+ CheckOutFound = true;
+ } else if (!CheckOutFound && this->RegexParent.find(this->Line)) {
+ this->BZR->URL = this->RegexParent.match(1);
+ }
+ return true;
+ }
+};
+
+class cmCTestBZR::RevnoParser : public cmCTestVC::LineParser
+{
+public:
+ RevnoParser(cmCTestBZR* bzr, const char* prefix, std::string& rev)
+ : Rev(rev)
+ {
+ this->SetLog(&bzr->Log, prefix);
+ this->RegexRevno.compile("^([0-9]+)$");
+ }
+
+private:
+ std::string& Rev;
+ cmsys::RegularExpression RegexRevno;
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexRevno.find(this->Line)) {
+ this->Rev = this->RegexRevno.match(1);
+ }
+ return true;
+ }
+};
+
+std::string cmCTestBZR::LoadInfo()
+{
+ // Run "bzr info" to get the repository info from the work tree.
+ const char* bzr = this->CommandLineTool.c_str();
+ const char* bzr_info[] = { bzr, "info", CM_NULLPTR };
+ InfoParser iout(this, "info-out> ");
+ OutputLogger ierr(this->Log, "info-err> ");
+ this->RunChild(bzr_info, &iout, &ierr);
+
+ // Run "bzr revno" to get the repository revision number from the work tree.
+ const char* bzr_revno[] = { bzr, "revno", CM_NULLPTR };
+ std::string rev;
+ RevnoParser rout(this, "revno-out> ", rev);
+ OutputLogger rerr(this->Log, "revno-err> ");
+ this->RunChild(bzr_revno, &rout, &rerr);
+
+ return rev;
+}
+
+void cmCTestBZR::NoteOldRevision()
+{
+ this->OldRevision = this->LoadInfo();
+ this->Log << "Revision before update: " << this->OldRevision << "\n";
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Old revision of repository is: "
+ << this->OldRevision << "\n");
+ this->PriorRev.Rev = this->OldRevision;
+}
+
+void cmCTestBZR::NoteNewRevision()
+{
+ this->NewRevision = this->LoadInfo();
+ this->Log << "Revision after update: " << this->NewRevision << "\n";
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " New revision of repository is: "
+ << this->NewRevision << "\n");
+ this->Log << "URL = " << this->URL << "\n";
+}
+
+class cmCTestBZR::LogParser : public cmCTestVC::OutputLogger,
+ private cmXMLParser
+{
+public:
+ LogParser(cmCTestBZR* bzr, const char* prefix)
+ : OutputLogger(bzr->Log, prefix)
+ , BZR(bzr)
+ , EmailRegex("(.*) <([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+)>")
+ {
+ this->InitializeParser();
+ }
+ ~LogParser() CM_OVERRIDE { this->CleanupParser(); }
+
+ int InitializeParser() CM_OVERRIDE
+ {
+ int res = cmXMLParser::InitializeParser();
+ if (res) {
+ XML_SetUnknownEncodingHandler(static_cast<XML_Parser>(this->Parser),
+ cmBZRXMLParserUnknownEncodingHandler,
+ CM_NULLPTR);
+ }
+ return res;
+ }
+
+private:
+ cmCTestBZR* BZR;
+
+ typedef cmCTestBZR::Revision Revision;
+ typedef cmCTestBZR::Change Change;
+ Revision Rev;
+ std::vector<Change> Changes;
+ Change CurChange;
+ std::vector<char> CData;
+
+ cmsys::RegularExpression EmailRegex;
+
+ bool ProcessChunk(const char* data, int length) CM_OVERRIDE
+ {
+ this->OutputLogger::ProcessChunk(data, length);
+ this->ParseChunk(data, length);
+ return true;
+ }
+
+ void StartElement(const std::string& name, const char**) CM_OVERRIDE
+ {
+ this->CData.clear();
+ if (name == "log") {
+ this->Rev = Revision();
+ this->Changes.clear();
+ }
+ // affected-files can contain blocks of
+ // modified, unknown, renamed, kind-changed, removed, conflicts, added
+ else if (name == "modified" || name == "renamed" ||
+ name == "kind-changed") {
+ this->CurChange = Change();
+ this->CurChange.Action = 'M';
+ } else if (name == "added") {
+ this->CurChange = Change();
+ this->CurChange = 'A';
+ } else if (name == "removed") {
+ this->CurChange = Change();
+ this->CurChange = 'D';
+ } else if (name == "unknown" || name == "conflicts") {
+ // Should not happen here
+ this->CurChange = Change();
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) CM_OVERRIDE
+ {
+ this->CData.insert(this->CData.end(), data, data + length);
+ }
+
+ void EndElement(const std::string& name) CM_OVERRIDE
+ {
+ if (name == "log") {
+ this->BZR->DoRevision(this->Rev, this->Changes);
+ } else if (!this->CData.empty() &&
+ (name == "file" || name == "directory")) {
+ this->CurChange.Path.assign(&this->CData[0], this->CData.size());
+ cmSystemTools::ConvertToUnixSlashes(this->CurChange.Path);
+ this->Changes.push_back(this->CurChange);
+ } else if (!this->CData.empty() && name == "symlink") {
+ // symlinks have an arobase at the end in the log
+ this->CurChange.Path.assign(&this->CData[0], this->CData.size() - 1);
+ cmSystemTools::ConvertToUnixSlashes(this->CurChange.Path);
+ this->Changes.push_back(this->CurChange);
+ } else if (!this->CData.empty() && name == "committer") {
+ this->Rev.Author.assign(&this->CData[0], this->CData.size());
+ if (this->EmailRegex.find(this->Rev.Author)) {
+ this->Rev.Author = this->EmailRegex.match(1);
+ this->Rev.EMail = this->EmailRegex.match(2);
+ }
+ } else if (!this->CData.empty() && name == "timestamp") {
+ this->Rev.Date.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "message") {
+ this->Rev.Log.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "revno") {
+ this->Rev.Rev.assign(&this->CData[0], this->CData.size());
+ }
+ this->CData.clear();
+ }
+
+ void ReportError(int, int, const char* msg) CM_OVERRIDE
+ {
+ this->BZR->Log << "Error parsing bzr log xml: " << msg << "\n";
+ }
+};
+
+class cmCTestBZR::UpdateParser : public cmCTestVC::LineParser
+{
+public:
+ UpdateParser(cmCTestBZR* bzr, const char* prefix)
+ : BZR(bzr)
+ {
+ this->SetLog(&bzr->Log, prefix);
+ this->RegexUpdate.compile("^([-+R?XCP ])([NDKM ])([* ]) +(.+)$");
+ }
+
+private:
+ cmCTestBZR* BZR;
+ cmsys::RegularExpression RegexUpdate;
+
+ bool ProcessChunk(const char* first, int length) CM_OVERRIDE
+ {
+ bool last_is_new_line = (*first == '\r' || *first == '\n');
+
+ const char* const last = first + length;
+ for (const char* c = first; c != last; ++c) {
+ if (*c == '\r' || *c == '\n') {
+ if (!last_is_new_line) {
+ // Log this line.
+ if (this->Log && this->Prefix) {
+ *this->Log << this->Prefix << this->Line << "\n";
+ }
+
+ // Hand this line to the subclass implementation.
+ if (!this->ProcessLine()) {
+ this->Line = "";
+ return false;
+ }
+
+ this->Line = "";
+ last_is_new_line = true;
+ }
+ } else {
+ // Append this character to the line under construction.
+ this->Line.append(1, *c);
+ last_is_new_line = false;
+ }
+ }
+ return true;
+ }
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexUpdate.find(this->Line)) {
+ this->DoPath(this->RegexUpdate.match(1)[0],
+ this->RegexUpdate.match(2)[0],
+ this->RegexUpdate.match(3)[0], this->RegexUpdate.match(4));
+ }
+ return true;
+ }
+
+ void DoPath(char c0, char c1, char c2, std::string path)
+ {
+ if (path.empty()) {
+ return;
+ }
+ cmSystemTools::ConvertToUnixSlashes(path);
+
+ const std::string dir = cmSystemTools::GetFilenamePath(path);
+ const std::string name = cmSystemTools::GetFilenameName(path);
+
+ if (c0 == 'C') {
+ this->BZR->Dirs[dir][name].Status = PathConflicting;
+ return;
+ }
+
+ if (c1 == 'M' || c1 == 'K' || c1 == 'N' || c1 == 'D' || c2 == '*') {
+ this->BZR->Dirs[dir][name].Status = PathUpdated;
+ return;
+ }
+ }
+};
+
+bool cmCTestBZR::UpdateImpl()
+{
+ // Get user-specified update options.
+ std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
+ if (opts.empty()) {
+ opts = this->CTest->GetCTestConfiguration("BZRUpdateOptions");
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+
+ // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
+
+ // Use "bzr pull" to update the working tree.
+ std::vector<char const*> bzr_update;
+ bzr_update.push_back(this->CommandLineTool.c_str());
+ bzr_update.push_back("pull");
+
+ for (std::vector<std::string>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai) {
+ bzr_update.push_back(ai->c_str());
+ }
+
+ bzr_update.push_back(this->URL.c_str());
+
+ bzr_update.push_back(CM_NULLPTR);
+
+ // For some reason bzr uses stderr to display the update status.
+ OutputLogger out(this->Log, "pull-out> ");
+ UpdateParser err(this, "pull-err> ");
+ return this->RunUpdateCommand(&bzr_update[0], &out, &err);
+}
+
+void cmCTestBZR::LoadRevisions()
+{
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Gathering version information (one . per revision):\n"
+ " "
+ << std::flush);
+
+ // We are interested in every revision included in the update.
+ this->Revisions.clear();
+ std::string revs;
+ if (atoi(this->OldRevision.c_str()) <= atoi(this->NewRevision.c_str())) {
+ // DoRevision takes care of discarding the information about OldRevision
+ revs = this->OldRevision + ".." + this->NewRevision;
+ } else {
+ return;
+ }
+
+ // Run "bzr log" to get all global revisions of interest.
+ const char* bzr = this->CommandLineTool.c_str();
+ const char* bzr_log[] = {
+ bzr, "log", "-v", "-r", revs.c_str(), "--xml", this->URL.c_str(),
+ CM_NULLPTR
+ };
+ {
+ LogParser out(this, "log-out> ");
+ OutputLogger err(this->Log, "log-err> ");
+ this->RunChild(bzr_log, &out, &err);
+ }
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
+}
+
+class cmCTestBZR::StatusParser : public cmCTestVC::LineParser
+{
+public:
+ StatusParser(cmCTestBZR* bzr, const char* prefix)
+ : BZR(bzr)
+ {
+ this->SetLog(&bzr->Log, prefix);
+ this->RegexStatus.compile("^([-+R?XCP ])([NDKM ])([* ]) +(.+)$");
+ }
+
+private:
+ cmCTestBZR* BZR;
+ cmsys::RegularExpression RegexStatus;
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexStatus.find(this->Line)) {
+ this->DoPath(this->RegexStatus.match(1)[0],
+ this->RegexStatus.match(2)[0],
+ this->RegexStatus.match(3)[0], this->RegexStatus.match(4));
+ }
+ return true;
+ }
+
+ void DoPath(char c0, char c1, char c2, std::string path)
+ {
+ if (path.empty()) {
+ return;
+ }
+ cmSystemTools::ConvertToUnixSlashes(path);
+
+ if (c0 == 'C') {
+ this->BZR->DoModification(PathConflicting, path);
+ return;
+ }
+
+ if (c0 == '+' || c0 == 'R' || c0 == 'P' || c1 == 'M' || c1 == 'K' ||
+ c1 == 'N' || c1 == 'D' || c2 == '*') {
+ this->BZR->DoModification(PathModified, path);
+ return;
+ }
+ }
+};
+
+void cmCTestBZR::LoadModifications()
+{
+ // Run "bzr status" which reports local modifications.
+ const char* bzr = this->CommandLineTool.c_str();
+ const char* bzr_status[] = { bzr, "status", "-SV", CM_NULLPTR };
+ StatusParser out(this, "status-out> ");
+ OutputLogger err(this->Log, "status-err> ");
+ this->RunChild(bzr_status, &out, &err);
+}
diff --git a/Source/CTest/cmCTestBZR.h b/Source/CTest/cmCTestBZR.h
new file mode 100644
index 0000000..0f05d38
--- /dev/null
+++ b/Source/CTest/cmCTestBZR.h
@@ -0,0 +1,55 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestBZR_h
+#define cmCTestBZR_h
+
+#include "cmCTestGlobalVC.h"
+
+/** \class cmCTestBZR
+ * \brief Interaction with bzr command-line tool
+ *
+ */
+class cmCTestBZR : public cmCTestGlobalVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestBZR(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestBZR() CM_OVERRIDE;
+
+private:
+ // Implement cmCTestVC internal API.
+ void NoteOldRevision() CM_OVERRIDE;
+ void NoteNewRevision() CM_OVERRIDE;
+ bool UpdateImpl() CM_OVERRIDE;
+
+ // URL of repository directory checked out in the working tree.
+ std::string URL;
+
+ std::string LoadInfo();
+ void LoadModifications() CM_OVERRIDE;
+ void LoadRevisions() CM_OVERRIDE;
+
+ // Parsing helper classes.
+ class InfoParser;
+ class RevnoParser;
+ class LogParser;
+ class UpdateParser;
+ class StatusParser;
+ friend class InfoParser;
+ friend class RevnoParser;
+ friend class LogParser;
+ friend class UpdateParser;
+ friend class StatusParser;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestBatchTestHandler.cxx b/Source/CTest/cmCTestBatchTestHandler.cxx
new file mode 100644
index 0000000..70f84cb
--- /dev/null
+++ b/Source/CTest/cmCTestBatchTestHandler.cxx
@@ -0,0 +1,131 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCTestBatchTestHandler.h"
+
+#include "cmCTest.h"
+#include "cmProcess.h"
+#include "cmStandardIncludes.h"
+#include "cmSystemTools.h"
+#include <stdlib.h>
+
+cmCTestBatchTestHandler::~cmCTestBatchTestHandler()
+{
+}
+
+void cmCTestBatchTestHandler::RunTests()
+{
+ this->WriteBatchScript();
+ this->SubmitBatchScript();
+}
+
+void cmCTestBatchTestHandler::WriteBatchScript()
+{
+ this->Script = this->CTest->GetBinaryDir() + "/Testing/CTestBatch.txt";
+ cmsys::ofstream fout;
+ fout.open(this->Script.c_str());
+ fout << "#!/bin/sh\n";
+
+ for (TestMap::iterator i = this->Tests.begin(); i != this->Tests.end();
+ ++i) {
+ this->WriteSrunArgs(i->first, fout);
+ this->WriteTestCommand(i->first, fout);
+ fout << "\n";
+ }
+ fout.flush();
+ fout.close();
+}
+
+void cmCTestBatchTestHandler::WriteSrunArgs(int test, std::ostream& fout)
+{
+ cmCTestTestHandler::cmCTestTestProperties* properties =
+ this->Properties[test];
+
+ fout << "srun ";
+ // fout << "--jobid=" << test << " ";
+ fout << "-J=" << properties->Name << " ";
+
+ // Write dependency information
+ /*if(!this->Tests[test].empty())
+ {
+ fout << "-P=afterany";
+ for(TestSet::iterator i = this->Tests[test].begin();
+ i != this->Tests[test].end(); ++i)
+ {
+ fout << ":" << *i;
+ }
+ fout << " ";
+ }*/
+ if (properties->RunSerial) {
+ fout << "--exclusive ";
+ }
+ if (properties->Processors > 1) {
+ fout << "-n" << properties->Processors << " ";
+ }
+}
+
+void cmCTestBatchTestHandler::WriteTestCommand(int test, std::ostream& fout)
+{
+ std::vector<std::string> args = this->Properties[test]->Args;
+ std::vector<std::string> processArgs;
+ std::string command;
+
+ command = this->TestHandler->FindTheExecutable(args[1].c_str());
+ command = cmSystemTools::ConvertToOutputPath(command.c_str());
+
+ // Prepends memcheck args to our command string if this is a memcheck
+ this->TestHandler->GenerateTestCommand(processArgs, test);
+ processArgs.push_back(command);
+
+ for (std::vector<std::string>::iterator arg = processArgs.begin();
+ arg != processArgs.end(); ++arg) {
+ fout << *arg << " ";
+ }
+
+ std::vector<std::string>::iterator i = args.begin();
+ ++i; // the test name
+ ++i; // the executable (command)
+ if (args.size() > 2) {
+ fout << "'";
+ }
+ while (i != args.end()) {
+ fout << "\"" << *i << "\""; // args to the test executable
+ ++i;
+
+ if (i == args.end() && args.size() > 2) {
+ fout << "'";
+ }
+ fout << " ";
+ }
+ // TODO ZACH build TestResult.FullCommandLine
+ // this->TestResult.FullCommandLine = this->TestCommand;
+}
+
+void cmCTestBatchTestHandler::SubmitBatchScript()
+{
+ cmProcess sbatch;
+ std::vector<std::string> args;
+ args.push_back(this->Script);
+ args.push_back("-o");
+ args.push_back(this->CTest->GetBinaryDir() + "/Testing/CTestBatch.txt");
+
+ sbatch.SetCommand("sbatch");
+ sbatch.SetCommandArguments(args);
+ /*if(sbatch.StartProcess())
+ {
+ //success condition
+ }
+ else
+ {
+ //fail condition
+ }*/
+}
diff --git a/Source/CTest/cmCTestBatchTestHandler.h b/Source/CTest/cmCTestBatchTestHandler.h
new file mode 100644
index 0000000..17cc234
--- /dev/null
+++ b/Source/CTest/cmCTestBatchTestHandler.h
@@ -0,0 +1,44 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCTestBatchTestHandler_h
+#define cmCTestBatchTestHandler_h
+
+#include <cmStandardIncludes.h>
+
+#include <cmCTestMultiProcessHandler.h>
+#include <cmCTestRunTest.h>
+#include <cmCTestTestHandler.h>
+#include <cmsys/FStream.hxx>
+
+/** \class cmCTestBatchTestHandler
+ * \brief run parallel ctest
+ *
+ * cmCTestBatchTestHandler
+ */
+class cmCTestBatchTestHandler : public cmCTestMultiProcessHandler
+{
+public:
+ ~cmCTestBatchTestHandler() CM_OVERRIDE;
+ void RunTests() CM_OVERRIDE;
+
+protected:
+ void WriteBatchScript();
+ void WriteSrunArgs(int test, std::ostream& fout);
+ void WriteTestCommand(int test, std::ostream& fout);
+
+ void SubmitBatchScript();
+
+ std::string Script;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
new file mode 100644
index 0000000..eddbddc
--- /dev/null
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -0,0 +1,457 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCTestBuildAndTestHandler.h"
+
+#include "cmCTest.h"
+#include "cmCTestTestHandler.h"
+#include "cmGlobalGenerator.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+#include <cmsys/Process.h>
+
+cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler()
+{
+ this->BuildTwoConfig = false;
+ this->BuildNoClean = false;
+ this->BuildNoCMake = false;
+ this->Timeout = 0;
+}
+
+void cmCTestBuildAndTestHandler::Initialize()
+{
+ this->BuildTargets.clear();
+ this->Superclass::Initialize();
+}
+
+const char* cmCTestBuildAndTestHandler::GetOutput()
+{
+ return this->Output.c_str();
+}
+int cmCTestBuildAndTestHandler::ProcessHandler()
+{
+ this->Output = "";
+ std::string output;
+ cmSystemTools::ResetErrorOccuredFlag();
+ int retv = this->RunCMakeAndTest(&this->Output);
+ cmSystemTools::ResetErrorOccuredFlag();
+ return retv;
+}
+
+int cmCTestBuildAndTestHandler::RunCMake(std::string* outstring,
+ std::ostringstream& out,
+ std::string& cmakeOutString,
+ std::string& cwd, cmake* cm)
+{
+ unsigned int k;
+ std::vector<std::string> args;
+ args.push_back(cmSystemTools::GetCMakeCommand());
+ args.push_back(this->SourceDir);
+ if (!this->BuildGenerator.empty()) {
+ std::string generator = "-G";
+ generator += this->BuildGenerator;
+ args.push_back(generator);
+ }
+ if (!this->BuildGeneratorPlatform.empty()) {
+ std::string platform = "-A";
+ platform += this->BuildGeneratorPlatform;
+ args.push_back(platform);
+ }
+ if (!this->BuildGeneratorToolset.empty()) {
+ std::string toolset = "-T";
+ toolset += this->BuildGeneratorToolset;
+ args.push_back(toolset);
+ }
+
+ const char* config = CM_NULLPTR;
+ if (!this->CTest->GetConfigType().empty()) {
+ config = this->CTest->GetConfigType().c_str();
+ }
+#ifdef CMAKE_INTDIR
+ if (!config) {
+ config = CMAKE_INTDIR;
+ }
+#endif
+
+ if (config) {
+ std::string btype = "-DCMAKE_BUILD_TYPE:STRING=" + std::string(config);
+ args.push_back(btype);
+ }
+
+ for (k = 0; k < this->BuildOptions.size(); ++k) {
+ args.push_back(this->BuildOptions[k]);
+ }
+ if (cm->Run(args) != 0) {
+ out << "Error: cmake execution failed\n";
+ out << cmakeOutString << "\n";
+ // return to the original directory
+ cmSystemTools::ChangeDirectory(cwd);
+ if (outstring) {
+ *outstring = out.str();
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, out.str() << std::endl);
+ }
+ return 1;
+ }
+ // do another config?
+ if (this->BuildTwoConfig) {
+ if (cm->Run(args) != 0) {
+ out << "Error: cmake execution failed\n";
+ out << cmakeOutString << "\n";
+ // return to the original directory
+ cmSystemTools::ChangeDirectory(cwd);
+ if (outstring) {
+ *outstring = out.str();
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, out.str() << std::endl);
+ }
+ return 1;
+ }
+ }
+ out << "======== CMake output ======\n";
+ out << cmakeOutString;
+ out << "======== End CMake output ======\n";
+ return 0;
+}
+
+void CMakeMessageCallback(const char* m, const char*, bool&, void* s)
+{
+ std::string* out = (std::string*)s;
+ *out += m;
+ *out += "\n";
+}
+
+void CMakeProgressCallback(const char* msg, float, void* s)
+{
+ std::string* out = (std::string*)s;
+ *out += msg;
+ *out += "\n";
+}
+
+void CMakeOutputCallback(const char* m, size_t len, void* s)
+{
+ std::string* out = (std::string*)s;
+ out->append(m, len);
+}
+
+class cmCTestBuildAndTestCaptureRAII
+{
+ cmake& CM;
+
+public:
+ cmCTestBuildAndTestCaptureRAII(cmake& cm, std::string& s)
+ : CM(cm)
+ {
+ cmSystemTools::SetMessageCallback(CMakeMessageCallback, &s);
+ cmSystemTools::SetStdoutCallback(CMakeOutputCallback, &s);
+ cmSystemTools::SetStderrCallback(CMakeOutputCallback, &s);
+ this->CM.SetProgressCallback(CMakeProgressCallback, &s);
+ }
+ ~cmCTestBuildAndTestCaptureRAII()
+ {
+ this->CM.SetProgressCallback(CM_NULLPTR, CM_NULLPTR);
+ cmSystemTools::SetStderrCallback(CM_NULLPTR, CM_NULLPTR);
+ cmSystemTools::SetStdoutCallback(CM_NULLPTR, CM_NULLPTR);
+ cmSystemTools::SetMessageCallback(CM_NULLPTR, CM_NULLPTR);
+ }
+};
+
+int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
+{
+ // if the generator and make program are not specified then it is an error
+ if (this->BuildGenerator.empty()) {
+ if (outstring) {
+ *outstring = "--build-and-test requires that the generator "
+ "be provided using the --build-generator "
+ "command line option. ";
+ }
+ return 1;
+ }
+
+ cmake cm;
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ std::string cmakeOutString;
+ cmCTestBuildAndTestCaptureRAII captureRAII(cm, cmakeOutString);
+ static_cast<void>(captureRAII);
+ std::ostringstream out;
+
+ if (this->CTest->GetConfigType().empty() && !this->ConfigSample.empty()) {
+ // use the config sample to set the ConfigType
+ std::string fullPath;
+ std::string resultingConfig;
+ std::vector<std::string> extraPaths;
+ std::vector<std::string> failed;
+ fullPath = cmCTestTestHandler::FindExecutable(
+ this->CTest, this->ConfigSample.c_str(), resultingConfig, extraPaths,
+ failed);
+ if (!fullPath.empty() && !resultingConfig.empty()) {
+ this->CTest->SetConfigType(resultingConfig.c_str());
+ }
+ out << "Using config sample with results: " << fullPath << " and "
+ << resultingConfig << std::endl;
+ }
+
+ // we need to honor the timeout specified, the timeout include cmake, build
+ // and test time
+ double clock_start = cmSystemTools::GetTime();
+
+ // make sure the binary dir is there
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ out << "Internal cmake changing into directory: " << this->BinaryDir
+ << std::endl;
+ if (!cmSystemTools::FileIsDirectory(this->BinaryDir)) {
+ cmSystemTools::MakeDirectory(this->BinaryDir.c_str());
+ }
+ cmSystemTools::ChangeDirectory(this->BinaryDir);
+
+ if (this->BuildNoCMake) {
+ // Make the generator available for the Build call below.
+ cm.SetGlobalGenerator(cm.CreateGlobalGenerator(this->BuildGenerator));
+ cm.SetGeneratorPlatform(this->BuildGeneratorPlatform);
+ cm.SetGeneratorToolset(this->BuildGeneratorToolset);
+
+ // Load the cache to make CMAKE_MAKE_PROGRAM available.
+ cm.LoadCache(this->BinaryDir);
+ } else {
+ // do the cmake step, no timeout here since it is not a sub process
+ if (this->RunCMake(outstring, out, cmakeOutString, cwd, &cm)) {
+ return 1;
+ }
+ }
+
+ // do the build
+ std::vector<std::string>::iterator tarIt;
+ if (this->BuildTargets.empty()) {
+ this->BuildTargets.push_back("");
+ }
+ for (tarIt = this->BuildTargets.begin(); tarIt != this->BuildTargets.end();
+ ++tarIt) {
+ double remainingTime = 0;
+ if (this->Timeout > 0) {
+ remainingTime = this->Timeout - cmSystemTools::GetTime() + clock_start;
+ if (remainingTime <= 0) {
+ if (outstring) {
+ *outstring = "--build-and-test timeout exceeded. ";
+ }
+ return 1;
+ }
+ }
+ std::string output;
+ const char* config = CM_NULLPTR;
+ if (!this->CTest->GetConfigType().empty()) {
+ config = this->CTest->GetConfigType().c_str();
+ }
+#ifdef CMAKE_INTDIR
+ if (!config) {
+ config = CMAKE_INTDIR;
+ }
+#endif
+ if (!config) {
+ config = "Debug";
+ }
+ int retVal = cm.GetGlobalGenerator()->Build(
+ this->SourceDir, this->BinaryDir, this->BuildProject, *tarIt, output,
+ this->BuildMakeProgram, config, !this->BuildNoClean, false, false,
+ remainingTime);
+ out << output;
+ // if the build failed then return
+ if (retVal) {
+ if (outstring) {
+ *outstring = out.str();
+ }
+ return 1;
+ }
+ }
+ if (outstring) {
+ *outstring = out.str();
+ }
+
+ // if no test was specified then we are done
+ if (this->TestCommand.empty()) {
+ return 0;
+ }
+
+ // now run the compiled test if we can find it
+ // store the final location in fullPath
+ std::string fullPath;
+ std::string resultingConfig;
+ std::vector<std::string> extraPaths;
+ // if this->ExecutableDirectory is set try that as well
+ if (!this->ExecutableDirectory.empty()) {
+ std::string tempPath = this->ExecutableDirectory;
+ tempPath += "/";
+ tempPath += this->TestCommand;
+ extraPaths.push_back(tempPath);
+ }
+ std::vector<std::string> failed;
+ fullPath =
+ cmCTestTestHandler::FindExecutable(this->CTest, this->TestCommand.c_str(),
+ resultingConfig, extraPaths, failed);
+
+ if (!cmSystemTools::FileExists(fullPath.c_str())) {
+ out << "Could not find path to executable, perhaps it was not built: "
+ << this->TestCommand << "\n";
+ out << "tried to find it in these places:\n";
+ out << fullPath << "\n";
+ for (unsigned int i = 0; i < failed.size(); ++i) {
+ out << failed[i] << "\n";
+ }
+ if (outstring) {
+ *outstring = out.str();
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, out.str());
+ }
+ // return to the original directory
+ cmSystemTools::ChangeDirectory(cwd);
+ return 1;
+ }
+
+ std::vector<const char*> testCommand;
+ testCommand.push_back(fullPath.c_str());
+ for (size_t k = 0; k < this->TestCommandArgs.size(); ++k) {
+ testCommand.push_back(this->TestCommandArgs[k].c_str());
+ }
+ testCommand.push_back(CM_NULLPTR);
+ std::string outs;
+ int retval = 0;
+ // run the test from the this->BuildRunDir if set
+ if (!this->BuildRunDir.empty()) {
+ out << "Run test in directory: " << this->BuildRunDir << "\n";
+ cmSystemTools::ChangeDirectory(this->BuildRunDir);
+ }
+ out << "Running test command: \"" << fullPath << "\"";
+ for (size_t k = 0; k < this->TestCommandArgs.size(); ++k) {
+ out << " \"" << this->TestCommandArgs[k] << "\"";
+ }
+ out << "\n";
+
+ // how much time is remaining
+ double remainingTime = 0;
+ if (this->Timeout > 0) {
+ remainingTime = this->Timeout - cmSystemTools::GetTime() + clock_start;
+ if (remainingTime <= 0) {
+ if (outstring) {
+ *outstring = "--build-and-test timeout exceeded. ";
+ }
+ return 1;
+ }
+ }
+
+ int runTestRes = this->CTest->RunTest(testCommand, &outs, &retval,
+ CM_NULLPTR, remainingTime, CM_NULLPTR);
+
+ if (runTestRes != cmsysProcess_State_Exited || retval != 0) {
+ out << "Test command failed: " << testCommand[0] << "\n";
+ retval = 1;
+ }
+
+ out << outs << "\n";
+ if (outstring) {
+ *outstring = out.str();
+ } else {
+ cmCTestLog(this->CTest, OUTPUT, out.str() << std::endl);
+ }
+ return retval;
+}
+
+int cmCTestBuildAndTestHandler::ProcessCommandLineArguments(
+ const std::string& currentArg, size_t& idx,
+ const std::vector<std::string>& allArgs)
+{
+ // --build-and-test options
+ if (currentArg.find("--build-and-test", 0) == 0 &&
+ idx < allArgs.size() - 1) {
+ if (idx + 2 < allArgs.size()) {
+ idx++;
+ this->SourceDir = allArgs[idx];
+ idx++;
+ this->BinaryDir = allArgs[idx];
+ // dir must exist before CollapseFullPath is called
+ cmSystemTools::MakeDirectory(this->BinaryDir.c_str());
+ this->BinaryDir = cmSystemTools::CollapseFullPath(this->BinaryDir);
+ this->SourceDir = cmSystemTools::CollapseFullPath(this->SourceDir);
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "--build-and-test must have source and binary dir"
+ << std::endl);
+ return 0;
+ }
+ }
+ if (currentArg.find("--build-target", 0) == 0 && idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildTargets.push_back(allArgs[idx]);
+ }
+ if (currentArg.find("--build-nocmake", 0) == 0) {
+ this->BuildNoCMake = true;
+ }
+ if (currentArg.find("--build-run-dir", 0) == 0 && idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildRunDir = allArgs[idx];
+ }
+ if (currentArg.find("--build-two-config", 0) == 0) {
+ this->BuildTwoConfig = true;
+ }
+ if (currentArg.find("--build-exe-dir", 0) == 0 && idx < allArgs.size() - 1) {
+ idx++;
+ this->ExecutableDirectory = allArgs[idx];
+ }
+ if (currentArg.find("--test-timeout", 0) == 0 && idx < allArgs.size() - 1) {
+ idx++;
+ this->Timeout = atof(allArgs[idx].c_str());
+ }
+ if (currentArg == "--build-generator" && idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildGenerator = allArgs[idx];
+ }
+ if (currentArg == "--build-generator-platform" && idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildGeneratorPlatform = allArgs[idx];
+ }
+ if (currentArg == "--build-generator-toolset" && idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildGeneratorToolset = allArgs[idx];
+ }
+ if (currentArg.find("--build-project", 0) == 0 && idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildProject = allArgs[idx];
+ }
+ if (currentArg.find("--build-makeprogram", 0) == 0 &&
+ idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildMakeProgram = allArgs[idx];
+ }
+ if (currentArg.find("--build-config-sample", 0) == 0 &&
+ idx < allArgs.size() - 1) {
+ idx++;
+ this->ConfigSample = allArgs[idx];
+ }
+ if (currentArg.find("--build-noclean", 0) == 0) {
+ this->BuildNoClean = true;
+ }
+ if (currentArg.find("--build-options", 0) == 0) {
+ while (idx + 1 < allArgs.size() && allArgs[idx + 1] != "--build-target" &&
+ allArgs[idx + 1] != "--test-command") {
+ ++idx;
+ this->BuildOptions.push_back(allArgs[idx]);
+ }
+ }
+ if (currentArg.find("--test-command", 0) == 0 && idx < allArgs.size() - 1) {
+ ++idx;
+ this->TestCommand = allArgs[idx];
+ while (idx + 1 < allArgs.size()) {
+ ++idx;
+ this->TestCommandArgs.push_back(allArgs[idx]);
+ }
+ }
+ return 1;
+}
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.h b/Source/CTest/cmCTestBuildAndTestHandler.h
new file mode 100644
index 0000000..2aa90a4
--- /dev/null
+++ b/Source/CTest/cmCTestBuildAndTestHandler.h
@@ -0,0 +1,77 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCTestBuildAndTestHandler_h
+#define cmCTestBuildAndTestHandler_h
+
+#include "cmCTestGenericHandler.h"
+#include "cmListFileCache.h"
+
+class cmake;
+
+/** \class cmCTestBuildAndTestHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestBuildAndTestHandler : public cmCTestGenericHandler
+{
+public:
+ cmTypeMacro(cmCTestBuildAndTestHandler, cmCTestGenericHandler);
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() CM_OVERRIDE;
+
+ //! Set all the build and test arguments
+ int ProcessCommandLineArguments(const std::string& currentArg, size_t& idx,
+ const std::vector<std::string>& allArgs)
+ CM_OVERRIDE;
+
+ /*
+ * Get the output variable
+ */
+ const char* GetOutput();
+
+ cmCTestBuildAndTestHandler();
+
+ void Initialize() CM_OVERRIDE;
+
+protected:
+ ///! 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, std::string& cwd, cmake* cm);
+
+ std::string Output;
+
+ std::string BuildGenerator;
+ std::string BuildGeneratorPlatform;
+ std::string BuildGeneratorToolset;
+ std::vector<std::string> BuildOptions;
+ bool BuildTwoConfig;
+ std::string BuildMakeProgram;
+ std::string ConfigSample;
+ std::string SourceDir;
+ std::string BinaryDir;
+ std::string BuildProject;
+ std::string TestCommand;
+ bool BuildNoClean;
+ std::string BuildRunDir;
+ std::string ExecutableDirectory;
+ std::vector<std::string> TestCommandArgs;
+ std::vector<std::string> BuildTargets;
+ bool BuildNoCMake;
+ double Timeout;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx
new file mode 100644
index 0000000..408a1a8
--- /dev/null
+++ b/Source/CTest/cmCTestBuildCommand.cxx
@@ -0,0 +1,180 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestBuildCommand.h"
+
+#include "cmCTest.h"
+#include "cmCTestBuildHandler.h"
+#include "cmCTestGenericHandler.h"
+#include "cmGlobalGenerator.h"
+#include "cmake.h"
+
+cmCTestBuildCommand::cmCTestBuildCommand()
+{
+ this->GlobalGenerator = CM_NULLPTR;
+ this->Arguments[ctb_NUMBER_ERRORS] = "NUMBER_ERRORS";
+ this->Arguments[ctb_NUMBER_WARNINGS] = "NUMBER_WARNINGS";
+ this->Arguments[ctb_TARGET] = "TARGET";
+ this->Arguments[ctb_CONFIGURATION] = "CONFIGURATION";
+ this->Arguments[ctb_FLAGS] = "FLAGS";
+ this->Arguments[ctb_PROJECT_NAME] = "PROJECT_NAME";
+ this->Arguments[ctb_LAST] = CM_NULLPTR;
+ this->Last = ctb_LAST;
+}
+
+cmCTestBuildCommand::~cmCTestBuildCommand()
+{
+ if (this->GlobalGenerator) {
+ delete this->GlobalGenerator;
+ this->GlobalGenerator = CM_NULLPTR;
+ }
+}
+
+cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
+{
+ cmCTestGenericHandler* handler = this->CTest->GetInitializedHandler("build");
+ if (!handler) {
+ this->SetError("internal CTest error. Cannot instantiate build handler");
+ return CM_NULLPTR;
+ }
+ this->Handler = (cmCTestBuildHandler*)handler;
+
+ const char* ctestBuildCommand =
+ this->Makefile->GetDefinition("CTEST_BUILD_COMMAND");
+ if (ctestBuildCommand && *ctestBuildCommand) {
+ this->CTest->SetCTestConfiguration("MakeCommand", ctestBuildCommand,
+ this->Quiet);
+ } else {
+ const char* cmakeGeneratorName =
+ this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR");
+ const char* cmakeProjectName =
+ (this->Values[ctb_PROJECT_NAME] && *this->Values[ctb_PROJECT_NAME])
+ ? this->Values[ctb_PROJECT_NAME]
+ : this->Makefile->GetDefinition("CTEST_PROJECT_NAME");
+
+ // Build configuration is determined by: CONFIGURATION argument,
+ // or CTEST_BUILD_CONFIGURATION script variable, or
+ // CTEST_CONFIGURATION_TYPE script variable, or ctest -C command
+ // line argument... in that order.
+ //
+ const char* ctestBuildConfiguration =
+ this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION");
+ const char* cmakeBuildConfiguration =
+ (this->Values[ctb_CONFIGURATION] && *this->Values[ctb_CONFIGURATION])
+ ? this->Values[ctb_CONFIGURATION]
+ : ((ctestBuildConfiguration && *ctestBuildConfiguration)
+ ? ctestBuildConfiguration
+ : this->CTest->GetConfigType().c_str());
+
+ const char* cmakeBuildAdditionalFlags =
+ (this->Values[ctb_FLAGS] && *this->Values[ctb_FLAGS])
+ ? this->Values[ctb_FLAGS]
+ : this->Makefile->GetDefinition("CTEST_BUILD_FLAGS");
+ const char* cmakeBuildTarget =
+ (this->Values[ctb_TARGET] && *this->Values[ctb_TARGET])
+ ? this->Values[ctb_TARGET]
+ : this->Makefile->GetDefinition("CTEST_BUILD_TARGET");
+
+ if (cmakeGeneratorName && *cmakeGeneratorName && cmakeProjectName &&
+ *cmakeProjectName) {
+ if (!cmakeBuildConfiguration) {
+ cmakeBuildConfiguration = "Release";
+ }
+ if (this->GlobalGenerator) {
+ if (this->GlobalGenerator->GetName() != cmakeGeneratorName) {
+ delete this->GlobalGenerator;
+ this->GlobalGenerator = CM_NULLPTR;
+ }
+ }
+ if (!this->GlobalGenerator) {
+ this->GlobalGenerator =
+ this->Makefile->GetCMakeInstance()->CreateGlobalGenerator(
+ cmakeGeneratorName);
+ if (!this->GlobalGenerator) {
+ std::string e = "could not create generator named \"";
+ e += cmakeGeneratorName;
+ e += "\"";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e);
+ cmSystemTools::SetFatalErrorOccured();
+ return CM_NULLPTR;
+ }
+ }
+ if (strlen(cmakeBuildConfiguration) == 0) {
+ const char* config = CM_NULLPTR;
+#ifdef CMAKE_INTDIR
+ config = CMAKE_INTDIR;
+#endif
+ if (!config) {
+ config = "Debug";
+ }
+ cmakeBuildConfiguration = config;
+ }
+
+ std::string dir = this->CTest->GetCTestConfiguration("BuildDirectory");
+ std::string buildCommand =
+ this->GlobalGenerator->GenerateCMakeBuildCommand(
+ cmakeBuildTarget ? cmakeBuildTarget : "", cmakeBuildConfiguration,
+ cmakeBuildAdditionalFlags ? cmakeBuildAdditionalFlags : "",
+ this->Makefile->IgnoreErrorsCMP0061());
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "SetMakeCommand:" << buildCommand << "\n",
+ this->Quiet);
+ this->CTest->SetCTestConfiguration("MakeCommand", buildCommand.c_str(),
+ this->Quiet);
+ } else {
+ std::ostringstream ostr;
+ /* clang-format off */
+ ostr << "has no project to build. If this is a "
+ "\"built with CMake\" project, verify that CTEST_CMAKE_GENERATOR "
+ "and CTEST_PROJECT_NAME are set."
+ "\n"
+ "CTEST_PROJECT_NAME is usually set in CTestConfig.cmake. Verify "
+ "that CTestConfig.cmake exists, or CTEST_PROJECT_NAME "
+ "is set in the script, or PROJECT_NAME is passed as an argument "
+ "to ctest_build."
+ "\n"
+ "Alternatively, set CTEST_BUILD_COMMAND to build the project "
+ "with a custom command line.";
+ /* clang-format on */
+ this->SetError(ostr.str());
+ return CM_NULLPTR;
+ }
+ }
+
+ if (const char* useLaunchers =
+ this->Makefile->GetDefinition("CTEST_USE_LAUNCHERS")) {
+ this->CTest->SetCTestConfiguration("UseLaunchers", useLaunchers,
+ this->Quiet);
+ }
+
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
+
+bool cmCTestBuildCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ bool ret = cmCTestHandlerCommand::InitialPass(args, status);
+ if (this->Values[ctb_NUMBER_ERRORS] && *this->Values[ctb_NUMBER_ERRORS]) {
+ std::ostringstream str;
+ str << this->Handler->GetTotalErrors();
+ this->Makefile->AddDefinition(this->Values[ctb_NUMBER_ERRORS],
+ str.str().c_str());
+ }
+ if (this->Values[ctb_NUMBER_WARNINGS] &&
+ *this->Values[ctb_NUMBER_WARNINGS]) {
+ std::ostringstream str;
+ str << this->Handler->GetTotalWarnings();
+ this->Makefile->AddDefinition(this->Values[ctb_NUMBER_WARNINGS],
+ str.str().c_str());
+ }
+ return ret;
+}
diff --git a/Source/CTest/cmCTestBuildCommand.h b/Source/CTest/cmCTestBuildCommand.h
new file mode 100644
index 0000000..92ae216
--- /dev/null
+++ b/Source/CTest/cmCTestBuildCommand.h
@@ -0,0 +1,71 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestBuildCommand_h
+#define cmCTestBuildCommand_h
+
+#include "cmCTestHandlerCommand.h"
+
+class cmGlobalGenerator;
+class cmCTestBuildHandler;
+
+/** \class cmCTestBuild
+ * \brief Run a ctest script
+ *
+ * cmCTestBuildCommand defineds the command to build the project.
+ */
+class cmCTestBuildCommand : public cmCTestHandlerCommand
+{
+public:
+ cmCTestBuildCommand();
+ ~cmCTestBuildCommand() CM_OVERRIDE;
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestBuildCommand* ni = new cmCTestBuildCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return ni;
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "ctest_build"; }
+
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ cmTypeMacro(cmCTestBuildCommand, cmCTestHandlerCommand);
+
+ cmGlobalGenerator* GlobalGenerator;
+
+protected:
+ cmCTestBuildHandler* Handler;
+ enum
+ {
+ ctb_BUILD = ct_LAST,
+ ctb_NUMBER_ERRORS,
+ ctb_NUMBER_WARNINGS,
+ ctb_TARGET,
+ ctb_CONFIGURATION,
+ ctb_FLAGS,
+ ctb_PROJECT_NAME,
+ ctb_LAST
+ };
+
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
new file mode 100644
index 0000000..f96ef6d
--- /dev/null
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -0,0 +1,1168 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCTestBuildHandler.h"
+
+#include "cmAlgorithms.h"
+#include "cmCTest.h"
+#include "cmFileTimeComparison.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+//#include <cmsys/RegularExpression.hxx>
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Process.h>
+
+// used for sleep
+#ifdef _WIN32
+#include "windows.h"
+#endif
+
+#include <float.h>
+#include <math.h>
+#include <stdlib.h>
+#include <time.h>
+
+static const char* cmCTestErrorMatches[] = {
+ "^[Bb]us [Ee]rror",
+ "^[Ss]egmentation [Vv]iolation",
+ "^[Ss]egmentation [Ff]ault",
+ ":.*[Pp]ermission [Dd]enied",
+ "([^ :]+):([0-9]+): ([^ \\t])",
+ "([^:]+): error[ \\t]*[0-9]+[ \\t]*:",
+ "^Error ([0-9]+):",
+ "^Fatal",
+ "^Error: ",
+ "^Error ",
+ "[0-9] ERROR: ",
+ "^\"[^\"]+\", line [0-9]+: [^Ww]",
+ "^cc[^C]*CC: ERROR File = ([^,]+), Line = ([0-9]+)",
+ "^ld([^:])*:([ \\t])*ERROR([^:])*:",
+ "^ild:([ \\t])*\\(undefined symbol\\)",
+ "([^ :]+) : (error|fatal error|catastrophic error)",
+ "([^:]+): (Error:|error|undefined reference|multiply defined)",
+ "([^:]+)\\(([^\\)]+)\\) ?: (error|fatal error|catastrophic error)",
+ "^fatal error C[0-9]+:",
+ ": syntax error ",
+ "^collect2: ld returned 1 exit status",
+ "ld terminated with signal",
+ "Unsatisfied symbol",
+ "^Unresolved:",
+ "Undefined symbol",
+ "^Undefined[ \\t]+first referenced",
+ "^CMake Error.*:",
+ ":[ \\t]cannot find",
+ ":[ \\t]can't find",
+ ": \\*\\*\\* No rule to make target [`'].*\\'. Stop",
+ ": \\*\\*\\* 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]\\)",
+ "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.",
+ "s:616 string too big",
+ "make: Fatal error: ",
+ "ld: 0711-993 Error occurred while writing to the output file:",
+ "ld: fatal: ",
+ "final link failed:",
+ "make: \\*\\*\\*.*Error",
+ "make\\[.*\\]: \\*\\*\\*.*Error",
+ "\\*\\*\\* Error code",
+ "nternal error:",
+ "Makefile:[0-9]+: \\*\\*\\* .* Stop\\.",
+ ": No such file or directory",
+ ": Invalid argument",
+ "^The project cannot be built\\.",
+ "^\\[ERROR\\]",
+ "^Command .* failed with exit code",
+ CM_NULLPTR
+};
+
+static const char* cmCTestErrorExceptions[] = {
+ "instantiated from ",
+ "candidates are:",
+ ": warning",
+ ": \\(Warning\\)",
+ ": note",
+ "Note:",
+ "makefile:",
+ "Makefile:",
+ ":[ \\t]+Where:",
+ "([^ :]+):([0-9]+): Warning",
+ "------ Build started: .* ------",
+ CM_NULLPTR
+};
+
+static const char* cmCTestWarningMatches[] = {
+ "([^ :]+):([0-9]+): warning:",
+ "([^ :]+):([0-9]+): note:",
+ "^cc[^C]*CC: WARNING File = ([^,]+), Line = ([0-9]+)",
+ "^ld([^:])*:([ \\t])*WARNING([^:])*:",
+ "([^:]+): warning ([0-9]+):",
+ "^\"[^\"]+\", 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]\\)",
+ "^cxx: Warning:",
+ ".*file: .* has no symbols",
+ "([^ :]+):([0-9]+): (Warning|Warnung)",
+ "\\([0-9]*\\): remark #[0-9]*",
+ "\".*\", line [0-9]+: remark\\([0-9]*\\):",
+ "cc-[0-9]* CC: REMARK File = .*, Line = [0-9]*",
+ "^CMake Warning.*:",
+ "^\\[WARNING\\]",
+ CM_NULLPTR
+};
+
+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",
+ "WARNING 84 :",
+ "WARNING 47 :",
+ "makefile:",
+ "Makefile:",
+ "warning: Clock skew detected. Your build may be incomplete.",
+ "/usr/openwin/include/GL/[^:]+:",
+ "bind_at_load",
+ "XrmQGetResource",
+ "IceFlush",
+ "warning LNK4089: all references to [^ \\t]+ discarded by .OPT:REF",
+ "ld32: WARNING 85: definition of dataKey in",
+ "cc: warning 422: Unknown option \"\\+b",
+ "_with_warning_C",
+ CM_NULLPTR
+};
+
+struct cmCTestBuildCompileErrorWarningRex
+{
+ const char* RegularExpressionString;
+ int FileIndex;
+ int LineIndex;
+};
+
+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 },
+ { "^([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 },
+ { CM_NULLPTR, 0, 0 }
+};
+
+cmCTestBuildHandler::cmCTestBuildHandler()
+{
+ this->MaxPreContext = 10;
+ this->MaxPostContext = 10;
+
+ this->MaxErrors = 50;
+ this->MaxWarnings = 50;
+
+ this->LastErrorOrWarning = this->ErrorsAndWarnings.end();
+
+ this->UseCTestLaunch = false;
+}
+
+void cmCTestBuildHandler::Initialize()
+{
+ this->Superclass::Initialize();
+ this->StartBuild = "";
+ this->EndBuild = "";
+ this->CustomErrorMatches.clear();
+ this->CustomErrorExceptions.clear();
+ this->CustomWarningMatches.clear();
+ this->CustomWarningExceptions.clear();
+ this->ReallyCustomWarningMatches.clear();
+ this->ReallyCustomWarningExceptions.clear();
+ this->ErrorWarningFileLineRegex.clear();
+
+ this->ErrorMatchRegex.clear();
+ this->ErrorExceptionRegex.clear();
+ this->WarningMatchRegex.clear();
+ this->WarningExceptionRegex.clear();
+ this->BuildProcessingQueue.clear();
+ this->BuildProcessingErrorQueue.clear();
+ this->BuildOutputLogSize = 0;
+ this->CurrentProcessingLine.clear();
+
+ this->SimplifySourceDir = "";
+ this->SimplifyBuildDir = "";
+ this->OutputLineCounter = 0;
+ this->ErrorsAndWarnings.clear();
+ this->LastErrorOrWarning = this->ErrorsAndWarnings.end();
+ this->PostContextCount = 0;
+ this->MaxPreContext = 10;
+ this->MaxPostContext = 10;
+ this->PreContext.clear();
+
+ this->TotalErrors = 0;
+ this->TotalWarnings = 0;
+ this->LastTickChar = 0;
+
+ this->ErrorQuotaReached = false;
+ this->WarningQuotaReached = false;
+
+ this->MaxErrors = 50;
+ this->MaxWarnings = 50;
+
+ this->UseCTestLaunch = false;
+}
+
+void cmCTestBuildHandler::PopulateCustomVectors(cmMakefile* mf)
+{
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_ERROR_MATCH",
+ this->CustomErrorMatches);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_ERROR_EXCEPTION",
+ this->CustomErrorExceptions);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_WARNING_MATCH",
+ this->CustomWarningMatches);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_WARNING_EXCEPTION",
+ this->CustomWarningExceptions);
+ this->CTest->PopulateCustomInteger(
+ mf, "CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS", this->MaxErrors);
+ this->CTest->PopulateCustomInteger(
+ mf, "CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS", this->MaxWarnings);
+
+ int n = -1;
+ this->CTest->PopulateCustomInteger(mf, "CTEST_CUSTOM_ERROR_PRE_CONTEXT", n);
+ if (n != -1) {
+ this->MaxPreContext = static_cast<size_t>(n);
+ }
+
+ n = -1;
+ this->CTest->PopulateCustomInteger(mf, "CTEST_CUSTOM_ERROR_POST_CONTEXT", n);
+ if (n != -1) {
+ this->MaxPostContext = static_cast<size_t>(n);
+ }
+
+ // Record the user-specified custom warning rules.
+ if (const char* customWarningMatchers =
+ mf->GetDefinition("CTEST_CUSTOM_WARNING_MATCH")) {
+ cmSystemTools::ExpandListArgument(customWarningMatchers,
+ this->ReallyCustomWarningMatches);
+ }
+ if (const char* customWarningExceptions =
+ mf->GetDefinition("CTEST_CUSTOM_WARNING_EXCEPTION")) {
+ cmSystemTools::ExpandListArgument(customWarningExceptions,
+ this->ReallyCustomWarningExceptions);
+ }
+}
+
+std::string cmCTestBuildHandler::GetMakeCommand()
+{
+ std::string makeCommand = this->CTest->GetCTestConfiguration("MakeCommand");
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "MakeCommand:" << makeCommand << "\n", this->Quiet);
+
+ std::string configType = this->CTest->GetConfigType();
+ if (configType == "") {
+ configType =
+ this->CTest->GetCTestConfiguration("DefaultCTestConfigurationType");
+ }
+ if (configType == "") {
+ configType = "Release";
+ }
+
+ cmSystemTools::ReplaceString(makeCommand, "${CTEST_CONFIGURATION_TYPE}",
+ configType.c_str());
+
+ return makeCommand;
+}
+
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
+int cmCTestBuildHandler::ProcessHandler()
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "Build project" << std::endl,
+ this->Quiet);
+
+ // do we have time for this
+ if (this->CTest->GetRemainingTimeAllowed() < 120) {
+ return 0;
+ }
+
+ int entry;
+ for (entry = 0; cmCTestWarningErrorFileLine[entry].RegularExpressionString;
+ ++entry) {
+ cmCTestBuildHandler::cmCTestCompileErrorWarningRex r;
+ if (r.RegularExpression.compile(
+ cmCTestWarningErrorFileLine[entry].RegularExpressionString)) {
+ r.FileIndex = cmCTestWarningErrorFileLine[entry].FileIndex;
+ r.LineIndex = cmCTestWarningErrorFileLine[entry].LineIndex;
+ this->ErrorWarningFileLineRegex.push_back(r);
+ } else {
+ cmCTestLog(
+ this->CTest, ERROR_MESSAGE, "Problem Compiling regular expression: "
+ << cmCTestWarningErrorFileLine[entry].RegularExpressionString
+ << std::endl);
+ }
+ }
+
+ // Determine build command and build directory
+ std::string makeCommand = this->GetMakeCommand();
+ if (makeCommand.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find MakeCommand key in the DartConfiguration.tcl"
+ << std::endl);
+ return -1;
+ }
+
+ const std::string& buildDirectory =
+ this->CTest->GetCTestConfiguration("BuildDirectory");
+ if (buildDirectory.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find BuildDirectory key in the DartConfiguration.tcl"
+ << std::endl);
+ return -1;
+ }
+
+ std::string const& useLaunchers =
+ this->CTest->GetCTestConfiguration("UseLaunchers");
+ this->UseCTestLaunch = cmSystemTools::IsOn(useLaunchers.c_str());
+
+ // Create a last build log
+ cmGeneratedFileStream ofs;
+ double elapsed_time_start = cmSystemTools::GetTime();
+ if (!this->StartLogFile("Build", ofs)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create build log file"
+ << std::endl);
+ }
+
+ // Create lists of regular expression strings for errors, error exceptions,
+ // warnings and warning exceptions.
+ std::vector<std::string>::size_type cc;
+ for (cc = 0; cmCTestErrorMatches[cc]; cc++) {
+ this->CustomErrorMatches.push_back(cmCTestErrorMatches[cc]);
+ }
+ for (cc = 0; cmCTestErrorExceptions[cc]; cc++) {
+ this->CustomErrorExceptions.push_back(cmCTestErrorExceptions[cc]);
+ }
+ for (cc = 0; cmCTestWarningMatches[cc]; cc++) {
+ this->CustomWarningMatches.push_back(cmCTestWarningMatches[cc]);
+ }
+
+ for (cc = 0; cmCTestWarningExceptions[cc]; cc++) {
+ this->CustomWarningExceptions.push_back(cmCTestWarningExceptions[cc]);
+ }
+
+ // Pre-compile regular expressions objects for all regular expressions
+ std::vector<std::string>::iterator it;
+
+#define cmCTestBuildHandlerPopulateRegexVector(strings, regexes) \
+ regexes.clear(); \
+ cmCTestOptionalLog(this->CTest, DEBUG, \
+ this << "Add " #regexes << std::endl, this->Quiet); \
+ for (it = strings.begin(); it != strings.end(); ++it) { \
+ cmCTestOptionalLog(this->CTest, DEBUG, \
+ "Add " #strings ": " << *it << std::endl, \
+ this->Quiet); \
+ regexes.push_back(it->c_str()); \
+ }
+ cmCTestBuildHandlerPopulateRegexVector(this->CustomErrorMatches,
+ this->ErrorMatchRegex);
+ cmCTestBuildHandlerPopulateRegexVector(this->CustomErrorExceptions,
+ this->ErrorExceptionRegex);
+ cmCTestBuildHandlerPopulateRegexVector(this->CustomWarningMatches,
+ this->WarningMatchRegex);
+ cmCTestBuildHandlerPopulateRegexVector(this->CustomWarningExceptions,
+ this->WarningExceptionRegex);
+
+ // Determine source and binary tree substitutions to simplify the output.
+ this->SimplifySourceDir = "";
+ this->SimplifyBuildDir = "";
+ if (this->CTest->GetCTestConfiguration("SourceDirectory").size() > 20) {
+ std::string srcdir =
+ this->CTest->GetCTestConfiguration("SourceDirectory") + "/";
+ std::string srcdirrep;
+ for (cc = srcdir.size() - 2; cc > 0; cc--) {
+ if (srcdir[cc] == '/') {
+ srcdirrep = srcdir.c_str() + cc;
+ srcdirrep = "/..." + srcdirrep;
+ srcdir = srcdir.substr(0, cc + 1);
+ break;
+ }
+ }
+ this->SimplifySourceDir = srcdir;
+ }
+ if (this->CTest->GetCTestConfiguration("BuildDirectory").size() > 20) {
+ std::string bindir =
+ this->CTest->GetCTestConfiguration("BuildDirectory") + "/";
+ std::string bindirrep;
+ for (cc = bindir.size() - 2; cc > 0; cc--) {
+ if (bindir[cc] == '/') {
+ bindirrep = bindir.c_str() + cc;
+ bindirrep = "/..." + bindirrep;
+ bindir = bindir.substr(0, cc + 1);
+ break;
+ }
+ }
+ this->SimplifyBuildDir = bindir;
+ }
+
+ // Ok, let's do the build
+
+ // Remember start build time
+ this->StartBuild = this->CTest->CurrentTime();
+ this->StartBuildTime = cmSystemTools::GetTime();
+ int retVal = 0;
+ int res = cmsysProcess_State_Exited;
+ if (!this->CTest->GetShowOnly()) {
+ res = this->RunMakeCommand(makeCommand.c_str(), &retVal,
+ buildDirectory.c_str(), 0, ofs);
+ } else {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Build with command: " << makeCommand << std::endl,
+ this->Quiet);
+ }
+
+ // Remember end build time and calculate elapsed time
+ this->EndBuild = this->CTest->CurrentTime();
+ this->EndBuildTime = cmSystemTools::GetTime();
+ double elapsed_build_time = cmSystemTools::GetTime() - elapsed_time_start;
+
+ // Cleanups strings in the errors and warnings list.
+ t_ErrorsAndWarningsVector::iterator evit;
+ if (!this->SimplifySourceDir.empty()) {
+ for (evit = this->ErrorsAndWarnings.begin();
+ evit != this->ErrorsAndWarnings.end(); ++evit) {
+ cmSystemTools::ReplaceString(evit->Text, this->SimplifySourceDir.c_str(),
+ "/.../");
+ cmSystemTools::ReplaceString(evit->PreContext,
+ this->SimplifySourceDir.c_str(), "/.../");
+ cmSystemTools::ReplaceString(evit->PostContext,
+ this->SimplifySourceDir.c_str(), "/.../");
+ }
+ }
+
+ if (!this->SimplifyBuildDir.empty()) {
+ for (evit = this->ErrorsAndWarnings.begin();
+ evit != this->ErrorsAndWarnings.end(); ++evit) {
+ cmSystemTools::ReplaceString(evit->Text, this->SimplifyBuildDir.c_str(),
+ "/.../");
+ cmSystemTools::ReplaceString(evit->PreContext,
+ this->SimplifyBuildDir.c_str(), "/.../");
+ cmSystemTools::ReplaceString(evit->PostContext,
+ this->SimplifyBuildDir.c_str(), "/.../");
+ }
+ }
+
+ // Generate XML output
+ cmGeneratedFileStream xofs;
+ if (!this->StartResultingXML(cmCTest::PartBuild, "Build", xofs)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create build XML file"
+ << std::endl);
+ return -1;
+ }
+ cmXMLWriter xml(xofs);
+ this->GenerateXMLHeader(xml);
+ if (this->UseCTestLaunch) {
+ this->GenerateXMLLaunched(xml);
+ } else {
+ this->GenerateXMLLogScraped(xml);
+ }
+ this->GenerateXMLFooter(xml, elapsed_build_time);
+
+ if (res != cmsysProcess_State_Exited || retVal || this->TotalErrors > 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Error(s) when building project"
+ << std::endl);
+ }
+
+ // Display message about number of errors and warnings
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " "
+ << this->TotalErrors
+ << (this->TotalErrors >= this->MaxErrors ? " or more" : "")
+ << " Compiler errors" << std::endl);
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " "
+ << this->TotalWarnings
+ << (this->TotalWarnings >= this->MaxWarnings ? " or more" : "")
+ << " Compiler warnings" << std::endl);
+
+ return retVal;
+}
+
+void cmCTestBuildHandler::GenerateXMLHeader(cmXMLWriter& xml)
+{
+ this->CTest->StartXML(xml, this->AppendXML);
+ xml.StartElement("Build");
+ xml.Element("StartDateTime", this->StartBuild);
+ xml.Element("StartBuildTime",
+ static_cast<unsigned int>(this->StartBuildTime));
+ xml.Element("BuildCommand", this->GetMakeCommand());
+}
+
+class cmCTestBuildHandler::FragmentCompare
+{
+public:
+ FragmentCompare(cmFileTimeComparison* ftc)
+ : FTC(ftc)
+ {
+ }
+ FragmentCompare()
+ : FTC(CM_NULLPTR)
+ {
+ }
+ bool operator()(std::string const& l, std::string const& r)
+ {
+ // Order files by modification time. Use lexicographic order
+ // among files with the same time.
+ int result;
+ if (this->FTC->FileTimeCompare(l.c_str(), r.c_str(), &result) &&
+ result != 0) {
+ return result < 0;
+ } else {
+ return l < r;
+ }
+ }
+
+private:
+ cmFileTimeComparison* FTC;
+};
+
+void cmCTestBuildHandler::GenerateXMLLaunched(cmXMLWriter& xml)
+{
+ if (this->CTestLaunchDir.empty()) {
+ return;
+ }
+
+ // Sort XML fragments in chronological order.
+ cmFileTimeComparison ftc;
+ FragmentCompare fragmentCompare(&ftc);
+ typedef std::set<std::string, FragmentCompare> Fragments;
+ Fragments fragments(fragmentCompare);
+
+ // only report the first 50 warnings and first 50 errors
+ int numErrorsAllowed = this->MaxErrors;
+ int numWarningsAllowed = this->MaxWarnings;
+ // Identify fragments on disk.
+ cmsys::Directory launchDir;
+ launchDir.Load(this->CTestLaunchDir);
+ unsigned long n = launchDir.GetNumberOfFiles();
+ for (unsigned long i = 0; i < n; ++i) {
+ const char* fname = launchDir.GetFile(i);
+ if (this->IsLaunchedErrorFile(fname) && numErrorsAllowed) {
+ numErrorsAllowed--;
+ fragments.insert(this->CTestLaunchDir + "/" + fname);
+ ++this->TotalErrors;
+ } else if (this->IsLaunchedWarningFile(fname) && numWarningsAllowed) {
+ numWarningsAllowed--;
+ fragments.insert(this->CTestLaunchDir + "/" + fname);
+ ++this->TotalWarnings;
+ }
+ }
+
+ // Copy the fragments into the final XML file.
+ for (Fragments::const_iterator fi = fragments.begin(); fi != fragments.end();
+ ++fi) {
+ xml.FragmentFile(fi->c_str());
+ }
+}
+
+void cmCTestBuildHandler::GenerateXMLLogScraped(cmXMLWriter& xml)
+{
+ std::vector<cmCTestBuildErrorWarning>& ew = this->ErrorsAndWarnings;
+ std::vector<cmCTestBuildErrorWarning>::iterator it;
+
+ // only report the first 50 warnings and first 50 errors
+ int numErrorsAllowed = this->MaxErrors;
+ int numWarningsAllowed = this->MaxWarnings;
+ std::string srcdir = this->CTest->GetCTestConfiguration("SourceDirectory");
+ // make sure the source dir is in the correct case on windows
+ // via a call to collapse full path.
+ srcdir = cmSystemTools::CollapseFullPath(srcdir);
+ srcdir += "/";
+ for (it = ew.begin();
+ it != ew.end() && (numErrorsAllowed || numWarningsAllowed); it++) {
+ cmCTestBuildErrorWarning* cm = &(*it);
+ if ((cm->Error && numErrorsAllowed) ||
+ (!cm->Error && numWarningsAllowed)) {
+ if (cm->Error) {
+ numErrorsAllowed--;
+ } else {
+ numWarningsAllowed--;
+ }
+ xml.StartElement(cm->Error ? "Error" : "Warning");
+ xml.Element("BuildLogLine", cm->LogLine);
+ xml.Element("Text", cm->Text);
+ std::vector<cmCTestCompileErrorWarningRex>::iterator rit;
+ for (rit = this->ErrorWarningFileLineRegex.begin();
+ rit != this->ErrorWarningFileLineRegex.end(); ++rit) {
+ cmsys::RegularExpression* re = &rit->RegularExpression;
+ if (re->find(cm->Text.c_str())) {
+ cm->SourceFile = re->match(rit->FileIndex);
+ // At this point we need to make this->SourceFile relative to
+ // the source root of the project, so cvs links will work
+ cmSystemTools::ConvertToUnixSlashes(cm->SourceFile);
+ if (cm->SourceFile.find("/.../") != cm->SourceFile.npos) {
+ cmSystemTools::ReplaceString(cm->SourceFile, "/.../", "");
+ std::string::size_type p = cm->SourceFile.find('/');
+ if (p != cm->SourceFile.npos) {
+ cm->SourceFile =
+ cm->SourceFile.substr(p + 1, cm->SourceFile.size() - p);
+ }
+ } else {
+ // make sure it is a full path with the correct case
+ cm->SourceFile = cmSystemTools::CollapseFullPath(cm->SourceFile);
+ cmSystemTools::ReplaceString(cm->SourceFile, srcdir.c_str(), "");
+ }
+ cm->LineNumber = atoi(re->match(rit->LineIndex).c_str());
+ break;
+ }
+ }
+ if (!cm->SourceFile.empty() && cm->LineNumber >= 0) {
+ if (!cm->SourceFile.empty()) {
+ xml.Element("SourceFile", cm->SourceFile);
+ }
+ if (!cm->SourceFileTail.empty()) {
+ xml.Element("SourceFileTail", cm->SourceFileTail);
+ }
+ if (cm->LineNumber >= 0) {
+ xml.Element("SourceLineNumber", cm->LineNumber);
+ }
+ }
+ xml.Element("PreContext", cm->PreContext);
+ xml.StartElement("PostContext");
+ xml.Content(cm->PostContext);
+ // is this the last warning or error, if so notify
+ if ((cm->Error && !numErrorsAllowed) ||
+ (!cm->Error && !numWarningsAllowed)) {
+ xml.Content("\nThe maximum number of reported warnings or errors "
+ "has been reached!!!\n");
+ }
+ xml.EndElement(); // PostContext
+ xml.Element("RepeatCount", "0");
+ xml.EndElement(); // "Error" / "Warning"
+ }
+ }
+}
+
+void cmCTestBuildHandler::GenerateXMLFooter(cmXMLWriter& xml,
+ double elapsed_build_time)
+{
+ xml.StartElement("Log");
+ xml.Attribute("Encoding", "base64");
+ xml.Attribute("Compression", "bin/gzip");
+ xml.EndElement(); // Log
+
+ xml.Element("EndDateTime", this->EndBuild);
+ xml.Element("EndBuildTime", static_cast<unsigned int>(this->EndBuildTime));
+ xml.Element("ElapsedMinutes",
+ static_cast<int>(elapsed_build_time / 6) / 10.0);
+ xml.EndElement(); // Build
+ this->CTest->EndXML(xml);
+}
+
+bool cmCTestBuildHandler::IsLaunchedErrorFile(const char* fname)
+{
+ // error-{hash}.xml
+ return (cmHasLiteralPrefix(fname, "error-") &&
+ strcmp(fname + strlen(fname) - 4, ".xml") == 0);
+}
+
+bool cmCTestBuildHandler::IsLaunchedWarningFile(const char* fname)
+{
+ // warning-{hash}.xml
+ return (cmHasLiteralPrefix(fname, "warning-") &&
+ strcmp(fname + strlen(fname) - 4, ".xml") == 0);
+}
+
+//######################################################################
+//######################################################################
+//######################################################################
+//######################################################################
+
+class cmCTestBuildHandler::LaunchHelper
+{
+public:
+ LaunchHelper(cmCTestBuildHandler* handler);
+ ~LaunchHelper();
+
+private:
+ cmCTestBuildHandler* Handler;
+ cmCTest* CTest;
+
+ void WriteLauncherConfig();
+ void WriteScrapeMatchers(const char* purpose,
+ std::vector<std::string> const& matchers);
+};
+
+cmCTestBuildHandler::LaunchHelper::LaunchHelper(cmCTestBuildHandler* handler)
+ : Handler(handler)
+ , CTest(handler->CTest)
+{
+ std::string tag = this->CTest->GetCurrentTag();
+ if (tag.empty()) {
+ // This is not for a dashboard submission, so there is no XML.
+ // Skip enabling the launchers.
+ this->Handler->UseCTestLaunch = false;
+ } else {
+ // Compute a directory in which to store launcher fragments.
+ std::string& launchDir = this->Handler->CTestLaunchDir;
+ launchDir = this->CTest->GetBinaryDir();
+ launchDir += "/Testing/";
+ launchDir += tag;
+ launchDir += "/Build";
+
+ // Clean out any existing launcher fragments.
+ cmSystemTools::RemoveADirectory(launchDir);
+
+ if (this->Handler->UseCTestLaunch) {
+ // Enable launcher fragments.
+ cmSystemTools::MakeDirectory(launchDir.c_str());
+ this->WriteLauncherConfig();
+ std::string launchEnv = "CTEST_LAUNCH_LOGS=";
+ launchEnv += launchDir;
+ cmSystemTools::PutEnv(launchEnv);
+ }
+ }
+
+ // If not using launchers, make sure they passthru.
+ if (!this->Handler->UseCTestLaunch) {
+ cmSystemTools::UnsetEnv("CTEST_LAUNCH_LOGS");
+ }
+}
+
+cmCTestBuildHandler::LaunchHelper::~LaunchHelper()
+{
+ if (this->Handler->UseCTestLaunch) {
+ cmSystemTools::UnsetEnv("CTEST_LAUNCH_LOGS");
+ }
+}
+
+void cmCTestBuildHandler::LaunchHelper::WriteLauncherConfig()
+{
+ this->WriteScrapeMatchers("Warning",
+ this->Handler->ReallyCustomWarningMatches);
+ this->WriteScrapeMatchers("WarningSuppress",
+ this->Handler->ReallyCustomWarningExceptions);
+
+ // Give some testing configuration information to the launcher.
+ std::string fname = this->Handler->CTestLaunchDir;
+ fname += "/CTestLaunchConfig.cmake";
+ cmGeneratedFileStream fout(fname.c_str());
+ std::string srcdir = this->CTest->GetCTestConfiguration("SourceDirectory");
+ fout << "set(CTEST_SOURCE_DIRECTORY \"" << srcdir << "\")\n";
+}
+
+void cmCTestBuildHandler::LaunchHelper::WriteScrapeMatchers(
+ const char* purpose, std::vector<std::string> const& matchers)
+{
+ if (matchers.empty()) {
+ return;
+ }
+ std::string fname = this->Handler->CTestLaunchDir;
+ fname += "/Custom";
+ fname += purpose;
+ fname += ".txt";
+ cmGeneratedFileStream fout(fname.c_str());
+ for (std::vector<std::string>::const_iterator mi = matchers.begin();
+ mi != matchers.end(); ++mi) {
+ fout << *mi << "\n";
+ }
+}
+
+int cmCTestBuildHandler::RunMakeCommand(const char* command, int* retVal,
+ const char* dir, int timeout,
+ std::ostream& ofs)
+{
+ // First generate the command and arguments
+ std::vector<std::string> args = cmSystemTools::ParseArguments(command);
+
+ if (args.empty()) {
+ return false;
+ }
+
+ std::vector<const char*> argv;
+ for (std::vector<std::string>::const_iterator a = args.begin();
+ a != args.end(); ++a) {
+ argv.push_back(a->c_str());
+ }
+ argv.push_back(CM_NULLPTR);
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run command:",
+ this->Quiet);
+ std::vector<const char*>::iterator ait;
+ for (ait = argv.begin(); ait != argv.end() && *ait; ++ait) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " \"" << *ait << "\"", this->Quiet);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl,
+ this->Quiet);
+
+ // Optionally use make rule launchers to record errors and warnings.
+ LaunchHelper launchHelper(this);
+ static_cast<void>(launchHelper);
+
+ // Now create process object
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ cmsysProcess_SetTimeout(cp, timeout);
+ cmsysProcess_Execute(cp);
+
+ // Initialize tick's
+ std::string::size_type tick = 0;
+ const std::string::size_type tick_len = 1024;
+
+ char* data;
+ int length;
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_PROGRESS_OUTPUT, " Each symbol represents "
+ << tick_len << " bytes of output." << std::endl
+ << (this->UseCTestLaunch
+ ? ""
+ : " '!' represents an error and '*' a warning.\n")
+ << " " << std::flush,
+ this->Quiet);
+
+ // Initialize building structures
+ this->BuildProcessingQueue.clear();
+ this->OutputLineCounter = 0;
+ this->ErrorsAndWarnings.clear();
+ this->TotalErrors = 0;
+ this->TotalWarnings = 0;
+ this->BuildOutputLogSize = 0;
+ this->LastTickChar = '.';
+ this->WarningQuotaReached = false;
+ this->ErrorQuotaReached = false;
+
+ // For every chunk of data
+ int res;
+ while ((res = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR))) {
+ // Replace '\0' with '\n', since '\0' does not really make sense. This is
+ // for Visual Studio output
+ for (int cc = 0; cc < length; ++cc) {
+ if (data[cc] == 0) {
+ data[cc] = '\n';
+ }
+ }
+
+ // Process the chunk of data
+ if (res == cmsysProcess_Pipe_STDERR) {
+ this->ProcessBuffer(data, length, tick, tick_len, ofs,
+ &this->BuildProcessingErrorQueue);
+ } else {
+ this->ProcessBuffer(data, length, tick, tick_len, ofs,
+ &this->BuildProcessingQueue);
+ }
+ }
+
+ this->ProcessBuffer(CM_NULLPTR, 0, tick, tick_len, ofs,
+ &this->BuildProcessingQueue);
+ this->ProcessBuffer(CM_NULLPTR, 0, tick, tick_len, ofs,
+ &this->BuildProcessingErrorQueue);
+ cmCTestOptionalLog(this->CTest, HANDLER_PROGRESS_OUTPUT, " Size of output: "
+ << ((this->BuildOutputLogSize + 512) / 1024) << "K"
+ << std::endl,
+ this->Quiet);
+
+ // Properly handle output of the build command
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+ int result = cmsysProcess_GetState(cp);
+
+ if (result == cmsysProcess_State_Exited) {
+ if (retVal) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Command exited with the value: " << *retVal
+ << std::endl,
+ this->Quiet);
+ // if a non zero return value
+ if (*retVal) {
+ // If there was an error running command, report that on the
+ // dashboard.
+ cmCTestBuildErrorWarning errorwarning;
+ errorwarning.LogLine = 1;
+ errorwarning.Text =
+ "*** WARNING non-zero return value in ctest from: ";
+ errorwarning.Text += argv[0];
+ errorwarning.PreContext = "";
+ errorwarning.PostContext = "";
+ errorwarning.Error = false;
+ this->ErrorsAndWarnings.push_back(errorwarning);
+ this->TotalWarnings++;
+ }
+ }
+ } else if (result == cmsysProcess_State_Exception) {
+ if (retVal) {
+ *retVal = cmsysProcess_GetExitException(cp);
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "There was an exception: " << *retVal << std::endl,
+ this->Quiet);
+ }
+ } else if (result == cmsysProcess_State_Expired) {
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "There was a timeout" << std::endl, this->Quiet);
+ } else if (result == cmsysProcess_State_Error) {
+ // If there was an error running command, report that on the dashboard.
+ cmCTestBuildErrorWarning errorwarning;
+ errorwarning.LogLine = 1;
+ errorwarning.Text = "*** ERROR executing: ";
+ errorwarning.Text += cmsysProcess_GetErrorString(cp);
+ errorwarning.PreContext = "";
+ errorwarning.PostContext = "";
+ errorwarning.Error = true;
+ this->ErrorsAndWarnings.push_back(errorwarning);
+ this->TotalErrors++;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "There was an error: "
+ << cmsysProcess_GetErrorString(cp) << std::endl);
+ }
+
+ cmsysProcess_Delete(cp);
+ return result;
+}
+
+//######################################################################
+//######################################################################
+//######################################################################
+//######################################################################
+
+void cmCTestBuildHandler::ProcessBuffer(const char* data, int length,
+ size_t& tick, size_t tick_len,
+ std::ostream& ofs,
+ t_BuildProcessingQueueType* queue)
+{
+ const std::string::size_type tick_line_len = 50;
+ const char* ptr;
+ for (ptr = data; ptr < data + length; ptr++) {
+ queue->push_back(*ptr);
+ }
+ this->BuildOutputLogSize += length;
+
+ // until there are any lines left in the buffer
+ while (1) {
+ // Find the end of line
+ t_BuildProcessingQueueType::iterator it;
+ for (it = queue->begin(); it != queue->end(); ++it) {
+ if (*it == '\n') {
+ break;
+ }
+ }
+
+ // Once certain number of errors or warnings reached, ignore future errors
+ // or warnings.
+ if (this->TotalWarnings >= this->MaxWarnings) {
+ this->WarningQuotaReached = true;
+ }
+ if (this->TotalErrors >= this->MaxErrors) {
+ this->ErrorQuotaReached = true;
+ }
+
+ // If the end of line was found
+ if (it != queue->end()) {
+ // Create a contiguous array for the line
+ this->CurrentProcessingLine.clear();
+ this->CurrentProcessingLine.insert(this->CurrentProcessingLine.end(),
+ queue->begin(), it);
+ this->CurrentProcessingLine.push_back(0);
+ const char* line = &*this->CurrentProcessingLine.begin();
+
+ // Process the line
+ int lineType = this->ProcessSingleLine(line);
+
+ // Erase the line from the queue
+ queue->erase(queue->begin(), it + 1);
+
+ // Depending on the line type, produce error or warning, or nothing
+ cmCTestBuildErrorWarning errorwarning;
+ bool found = false;
+ switch (lineType) {
+ case b_WARNING_LINE:
+ this->LastTickChar = '*';
+ errorwarning.Error = false;
+ found = true;
+ this->TotalWarnings++;
+ break;
+ case b_ERROR_LINE:
+ this->LastTickChar = '!';
+ errorwarning.Error = true;
+ found = true;
+ this->TotalErrors++;
+ break;
+ }
+ if (found) {
+ // This is an error or warning, so generate report
+ errorwarning.LogLine = static_cast<int>(this->OutputLineCounter + 1);
+ errorwarning.Text = line;
+ errorwarning.PreContext = "";
+ errorwarning.PostContext = "";
+
+ // Copy pre-context to report
+ std::deque<std::string>::iterator pcit;
+ for (pcit = this->PreContext.begin(); pcit != this->PreContext.end();
+ ++pcit) {
+ errorwarning.PreContext += *pcit + "\n";
+ }
+ this->PreContext.clear();
+
+ // Store report
+ this->ErrorsAndWarnings.push_back(errorwarning);
+ this->LastErrorOrWarning = this->ErrorsAndWarnings.end() - 1;
+ this->PostContextCount = 0;
+ } else {
+ // This is not an error or warning.
+ // So, figure out if this is a post-context line
+ if (!this->ErrorsAndWarnings.empty() &&
+ this->LastErrorOrWarning != this->ErrorsAndWarnings.end() &&
+ this->PostContextCount < this->MaxPostContext) {
+ this->PostContextCount++;
+ this->LastErrorOrWarning->PostContext += line;
+ if (this->PostContextCount < this->MaxPostContext) {
+ this->LastErrorOrWarning->PostContext += "\n";
+ }
+ } else {
+ // Otherwise store pre-context for the next error
+ this->PreContext.push_back(line);
+ if (this->PreContext.size() > this->MaxPreContext) {
+ this->PreContext.erase(this->PreContext.begin(),
+ this->PreContext.end() -
+ this->MaxPreContext);
+ }
+ }
+ }
+ this->OutputLineCounter++;
+ } else {
+ break;
+ }
+ }
+
+ // Now that the buffer is processed, display missing ticks
+ int tickDisplayed = false;
+ while (this->BuildOutputLogSize > (tick * tick_len)) {
+ tick++;
+ cmCTestOptionalLog(this->CTest, HANDLER_PROGRESS_OUTPUT,
+ this->LastTickChar, this->Quiet);
+ tickDisplayed = true;
+ if (tick % tick_line_len == 0 && tick > 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_PROGRESS_OUTPUT, " Size: "
+ << ((this->BuildOutputLogSize + 512) / 1024) << "K"
+ << std::endl
+ << " ",
+ this->Quiet);
+ }
+ }
+ if (tickDisplayed) {
+ this->LastTickChar = '.';
+ }
+
+ // And if this is verbose output, display the content of the chunk
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(data, length));
+
+ // Always store the chunk to the file
+ ofs << cmCTestLogWrite(data, length);
+}
+
+int cmCTestBuildHandler::ProcessSingleLine(const char* data)
+{
+ if (this->UseCTestLaunch) {
+ // No log scraping when using launchers.
+ return b_REGULAR_LINE;
+ }
+
+ cmCTestOptionalLog(this->CTest, DEBUG, "Line: [" << data << "]" << std::endl,
+ this->Quiet);
+
+ std::vector<cmsys::RegularExpression>::iterator it;
+
+ int warningLine = 0;
+ int errorLine = 0;
+
+ // Check for regular expressions
+
+ if (!this->ErrorQuotaReached) {
+ // Errors
+ int wrxCnt = 0;
+ for (it = this->ErrorMatchRegex.begin(); it != this->ErrorMatchRegex.end();
+ ++it) {
+ if (it->find(data)) {
+ errorLine = 1;
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ " Error Line: " << data << " (matches: "
+ << this->CustomErrorMatches[wrxCnt]
+ << ")" << std::endl,
+ this->Quiet);
+ break;
+ }
+ wrxCnt++;
+ }
+ // Error exceptions
+ wrxCnt = 0;
+ for (it = this->ErrorExceptionRegex.begin();
+ it != this->ErrorExceptionRegex.end(); ++it) {
+ if (it->find(data)) {
+ errorLine = 0;
+ cmCTestOptionalLog(this->CTest, DEBUG, " Not an error Line: "
+ << data << " (matches: "
+ << this->CustomErrorExceptions[wrxCnt] << ")"
+ << std::endl,
+ this->Quiet);
+ break;
+ }
+ wrxCnt++;
+ }
+ }
+ if (!this->WarningQuotaReached) {
+ // Warnings
+ int wrxCnt = 0;
+ for (it = this->WarningMatchRegex.begin();
+ it != this->WarningMatchRegex.end(); ++it) {
+ if (it->find(data)) {
+ warningLine = 1;
+ cmCTestOptionalLog(this->CTest, DEBUG, " Warning Line: "
+ << data << " (matches: "
+ << this->CustomWarningMatches[wrxCnt] << ")"
+ << std::endl,
+ this->Quiet);
+ break;
+ }
+ wrxCnt++;
+ }
+
+ wrxCnt = 0;
+ // Warning exceptions
+ for (it = this->WarningExceptionRegex.begin();
+ it != this->WarningExceptionRegex.end(); ++it) {
+ if (it->find(data)) {
+ warningLine = 0;
+ cmCTestOptionalLog(this->CTest, DEBUG, " Not a warning Line: "
+ << data << " (matches: "
+ << this->CustomWarningExceptions[wrxCnt] << ")"
+ << std::endl,
+ this->Quiet);
+ break;
+ }
+ wrxCnt++;
+ }
+ }
+ if (errorLine) {
+ return b_ERROR_LINE;
+ }
+ if (warningLine) {
+ return b_WARNING_LINE;
+ }
+ return b_REGULAR_LINE;
+}
diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h
new file mode 100644
index 0000000..8cc5f01
--- /dev/null
+++ b/Source/CTest/cmCTestBuildHandler.h
@@ -0,0 +1,155 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCTestBuildHandler_h
+#define cmCTestBuildHandler_h
+
+#include "cmCTestGenericHandler.h"
+
+#include "cmListFileCache.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+#include <deque>
+
+class cmMakefile;
+class cmXMLWriter;
+
+/** \class cmCTestBuildHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestBuildHandler : public cmCTestGenericHandler
+{
+public:
+ cmTypeMacro(cmCTestBuildHandler, cmCTestGenericHandler);
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() CM_OVERRIDE;
+
+ cmCTestBuildHandler();
+
+ void PopulateCustomVectors(cmMakefile* mf) CM_OVERRIDE;
+
+ /**
+ * Initialize handler
+ */
+ void Initialize() CM_OVERRIDE;
+
+ int GetTotalErrors() { return this->TotalErrors; }
+ int GetTotalWarnings() { return this->TotalWarnings; }
+
+private:
+ std::string GetMakeCommand();
+
+ //! 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 timeout, std::ostream& ofs);
+
+ enum
+ {
+ b_REGULAR_LINE,
+ b_WARNING_LINE,
+ b_ERROR_LINE
+ };
+
+ class cmCTestCompileErrorWarningRex
+ {
+ public:
+ cmCTestCompileErrorWarningRex() {}
+ int FileIndex;
+ int LineIndex;
+ cmsys::RegularExpression RegularExpression;
+ };
+
+ struct cmCTestBuildErrorWarning
+ {
+ bool Error;
+ int LogLine;
+ std::string Text;
+ std::string SourceFile;
+ std::string SourceFileTail;
+ int LineNumber;
+ std::string PreContext;
+ std::string PostContext;
+ };
+
+ // generate the XML output
+ void GenerateXMLHeader(cmXMLWriter& xml);
+ void GenerateXMLLaunched(cmXMLWriter& xml);
+ void GenerateXMLLogScraped(cmXMLWriter& xml);
+ void GenerateXMLFooter(cmXMLWriter& xml, double elapsed_build_time);
+ bool IsLaunchedErrorFile(const char* fname);
+ bool IsLaunchedWarningFile(const char* fname);
+
+ std::string StartBuild;
+ std::string EndBuild;
+ double StartBuildTime;
+ double EndBuildTime;
+
+ std::vector<std::string> CustomErrorMatches;
+ std::vector<std::string> CustomErrorExceptions;
+ std::vector<std::string> CustomWarningMatches;
+ std::vector<std::string> CustomWarningExceptions;
+ std::vector<std::string> ReallyCustomWarningMatches;
+ std::vector<std::string> ReallyCustomWarningExceptions;
+ std::vector<cmCTestCompileErrorWarningRex> ErrorWarningFileLineRegex;
+
+ std::vector<cmsys::RegularExpression> ErrorMatchRegex;
+ std::vector<cmsys::RegularExpression> ErrorExceptionRegex;
+ std::vector<cmsys::RegularExpression> WarningMatchRegex;
+ std::vector<cmsys::RegularExpression> WarningExceptionRegex;
+
+ typedef std::deque<char> t_BuildProcessingQueueType;
+
+ void ProcessBuffer(const char* data, int length, size_t& tick,
+ size_t tick_len, std::ostream& ofs,
+ t_BuildProcessingQueueType* queue);
+ int ProcessSingleLine(const char* data);
+
+ t_BuildProcessingQueueType BuildProcessingQueue;
+ t_BuildProcessingQueueType BuildProcessingErrorQueue;
+ size_t BuildOutputLogSize;
+ std::vector<char> CurrentProcessingLine;
+
+ std::string SimplifySourceDir;
+ std::string SimplifyBuildDir;
+ size_t OutputLineCounter;
+ typedef std::vector<cmCTestBuildErrorWarning> t_ErrorsAndWarningsVector;
+ t_ErrorsAndWarningsVector ErrorsAndWarnings;
+ t_ErrorsAndWarningsVector::iterator LastErrorOrWarning;
+ size_t PostContextCount;
+ size_t MaxPreContext;
+ size_t MaxPostContext;
+ std::deque<std::string> PreContext;
+
+ int TotalErrors;
+ int TotalWarnings;
+ char LastTickChar;
+
+ bool ErrorQuotaReached;
+ bool WarningQuotaReached;
+
+ int MaxErrors;
+ int MaxWarnings;
+
+ bool UseCTestLaunch;
+ std::string CTestLaunchDir;
+ class LaunchHelper;
+ friend class LaunchHelper;
+ class FragmentCompare;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx
new file mode 100644
index 0000000..37bdf9a
--- /dev/null
+++ b/Source/CTest/cmCTestCVS.cxx
@@ -0,0 +1,288 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestCVS.h"
+
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+
+#include <cmsys/FStream.hxx>
+#include <cmsys/RegularExpression.hxx>
+
+cmCTestCVS::cmCTestCVS(cmCTest* ct, std::ostream& log)
+ : cmCTestVC(ct, log)
+{
+}
+
+cmCTestCVS::~cmCTestCVS()
+{
+}
+
+class cmCTestCVS::UpdateParser : public cmCTestVC::LineParser
+{
+public:
+ UpdateParser(cmCTestCVS* cvs, const char* prefix)
+ : CVS(cvs)
+ {
+ this->SetLog(&cvs->Log, prefix);
+ // See "man cvs", section "update output".
+ this->RegexFileUpdated.compile("^([UP]) *(.*)");
+ this->RegexFileModified.compile("^([MRA]) *(.*)");
+ this->RegexFileConflicting.compile("^([C]) *(.*)");
+ this->RegexFileRemoved1.compile(
+ "cvs[^ ]* update: `?([^']*)'? is no longer in the repository");
+ this->RegexFileRemoved2.compile(
+ "cvs[^ ]* update: "
+ "warning: `?([^']*)'? is not \\(any longer\\) pertinent");
+ }
+
+private:
+ cmCTestCVS* CVS;
+ cmsys::RegularExpression RegexFileUpdated;
+ cmsys::RegularExpression RegexFileModified;
+ cmsys::RegularExpression RegexFileConflicting;
+ cmsys::RegularExpression RegexFileRemoved1;
+ cmsys::RegularExpression RegexFileRemoved2;
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexFileUpdated.find(this->Line)) {
+ this->DoFile(PathUpdated, this->RegexFileUpdated.match(2));
+ } else if (this->RegexFileModified.find(this->Line)) {
+ this->DoFile(PathModified, this->RegexFileModified.match(2));
+ } else if (this->RegexFileConflicting.find(this->Line)) {
+ this->DoFile(PathConflicting, this->RegexFileConflicting.match(2));
+ } else if (this->RegexFileRemoved1.find(this->Line)) {
+ this->DoFile(PathUpdated, this->RegexFileRemoved1.match(1));
+ } else if (this->RegexFileRemoved2.find(this->Line)) {
+ this->DoFile(PathUpdated, this->RegexFileRemoved2.match(1));
+ }
+ return true;
+ }
+
+ void DoFile(PathStatus status, std::string const& file)
+ {
+ std::string dir = cmSystemTools::GetFilenamePath(file);
+ std::string name = cmSystemTools::GetFilenameName(file);
+ this->CVS->Dirs[dir][name] = status;
+ }
+};
+
+bool cmCTestCVS::UpdateImpl()
+{
+ // Get user-specified update options.
+ std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
+ if (opts.empty()) {
+ opts = this->CTest->GetCTestConfiguration("CVSUpdateOptions");
+ if (opts.empty()) {
+ opts = "-dP";
+ }
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+
+ // Specify the start time for nightly testing.
+ if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
+ args.push_back("-D" + this->GetNightlyTime() + " UTC");
+ }
+
+ // Run "cvs update" to update the work tree.
+ std::vector<char const*> cvs_update;
+ cvs_update.push_back(this->CommandLineTool.c_str());
+ cvs_update.push_back("-z3");
+ cvs_update.push_back("update");
+ for (std::vector<std::string>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai) {
+ cvs_update.push_back(ai->c_str());
+ }
+ cvs_update.push_back(CM_NULLPTR);
+
+ UpdateParser out(this, "up-out> ");
+ UpdateParser err(this, "up-err> ");
+ return this->RunUpdateCommand(&cvs_update[0], &out, &err);
+}
+
+class cmCTestCVS::LogParser : public cmCTestVC::LineParser
+{
+public:
+ typedef cmCTestCVS::Revision Revision;
+ LogParser(cmCTestCVS* cvs, const char* prefix, std::vector<Revision>& revs)
+ : CVS(cvs)
+ , Revisions(revs)
+ , Section(SectionHeader)
+ {
+ this->SetLog(&cvs->Log, prefix),
+ this->RegexRevision.compile("^revision +([^ ]*) *$");
+ this->RegexBranches.compile("^branches: .*$");
+ this->RegexPerson.compile("^date: +([^;]+); +author: +([^;]+);");
+ }
+
+private:
+ cmCTestCVS* CVS;
+ std::vector<Revision>& Revisions;
+ cmsys::RegularExpression RegexRevision;
+ cmsys::RegularExpression RegexBranches;
+ cmsys::RegularExpression RegexPerson;
+ enum SectionType
+ {
+ SectionHeader,
+ SectionRevisions,
+ SectionEnd
+ };
+ SectionType Section;
+ Revision Rev;
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->Line == ("======================================="
+ "======================================")) {
+ // This line ends the revision list.
+ if (this->Section == SectionRevisions) {
+ this->FinishRevision();
+ }
+ this->Section = SectionEnd;
+ } else if (this->Line == "----------------------------") {
+ // This line divides revisions from the header and each other.
+ if (this->Section == SectionHeader) {
+ this->Section = SectionRevisions;
+ } else if (this->Section == SectionRevisions) {
+ this->FinishRevision();
+ }
+ } else if (this->Section == SectionRevisions) {
+ if (!this->Rev.Log.empty()) {
+ // Continue the existing log.
+ this->Rev.Log += this->Line;
+ this->Rev.Log += "\n";
+ } else if (this->Rev.Rev.empty() &&
+ this->RegexRevision.find(this->Line)) {
+ this->Rev.Rev = this->RegexRevision.match(1);
+ } else if (this->Rev.Date.empty() &&
+ this->RegexPerson.find(this->Line)) {
+ this->Rev.Date = this->RegexPerson.match(1);
+ this->Rev.Author = this->RegexPerson.match(2);
+ } else if (!this->RegexBranches.find(this->Line)) {
+ // Start the log.
+ this->Rev.Log += this->Line;
+ this->Rev.Log += "\n";
+ }
+ }
+ return this->Section != SectionEnd;
+ }
+
+ void FinishRevision()
+ {
+ if (!this->Rev.Rev.empty()) {
+ // Record this revision.
+ /* clang-format off */
+ this->CVS->Log << "Found revision " << this->Rev.Rev << "\n"
+ << " author = " << this->Rev.Author << "\n"
+ << " date = " << this->Rev.Date << "\n";
+ /* clang-format on */
+ this->Revisions.push_back(this->Rev);
+
+ // We only need two revisions.
+ if (this->Revisions.size() >= 2) {
+ this->Section = SectionEnd;
+ }
+ }
+ this->Rev = Revision();
+ }
+};
+
+std::string cmCTestCVS::ComputeBranchFlag(std::string const& dir)
+{
+ // Compute the tag file location for this directory.
+ std::string tagFile = this->SourceDirectory;
+ if (!dir.empty()) {
+ tagFile += "/";
+ tagFile += dir;
+ }
+ tagFile += "/CVS/Tag";
+
+ // Lookup the branch in the tag file, if any.
+ std::string tagLine;
+ cmsys::ifstream tagStream(tagFile.c_str());
+ if (tagStream && cmSystemTools::GetLineFromStream(tagStream, tagLine) &&
+ tagLine.size() > 1 && tagLine[0] == 'T') {
+ // Use the branch specified in the tag file.
+ std::string flag = "-r";
+ flag += tagLine.substr(1);
+ return flag;
+ } else {
+ // Use the default branch.
+ return "-b";
+ }
+}
+
+void cmCTestCVS::LoadRevisions(std::string const& file, const char* branchFlag,
+ std::vector<Revision>& revisions)
+{
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
+
+ // Run "cvs log" to get revisions of this file on this branch.
+ const char* cvs = this->CommandLineTool.c_str();
+ const char* cvs_log[] = { cvs, "log", "-N",
+ branchFlag, file.c_str(), CM_NULLPTR };
+
+ LogParser out(this, "log-out> ", revisions);
+ OutputLogger err(this->Log, "log-err> ");
+ this->RunChild(cvs_log, &out, &err);
+}
+
+void cmCTestCVS::WriteXMLDirectory(cmXMLWriter& xml, std::string const& path,
+ Directory const& dir)
+{
+ const char* slash = path.empty() ? "" : "/";
+ xml.StartElement("Directory");
+ xml.Element("Name", path);
+
+ // Lookup the branch checked out in the working tree.
+ std::string branchFlag = this->ComputeBranchFlag(path);
+
+ // Load revisions and write an entry for each file in this directory.
+ std::vector<Revision> revisions;
+ for (Directory::const_iterator fi = dir.begin(); fi != dir.end(); ++fi) {
+ std::string full = path + slash + fi->first;
+
+ // Load two real or unknown revisions.
+ revisions.clear();
+ if (fi->second != PathUpdated) {
+ // For local modifications the current rev is unknown and the
+ // prior rev is the latest from cvs.
+ revisions.push_back(this->Unknown);
+ }
+ this->LoadRevisions(full, branchFlag.c_str(), revisions);
+ revisions.resize(2, this->Unknown);
+
+ // Write the entry for this file with these revisions.
+ File f(fi->second, &revisions[0], &revisions[1]);
+ this->WriteXMLEntry(xml, path, fi->first, full, f);
+ }
+ xml.EndElement(); // Directory
+}
+
+bool cmCTestCVS::WriteXMLUpdates(cmXMLWriter& xml)
+{
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Gathering version information (one . per updated file):\n"
+ " "
+ << std::flush);
+
+ for (std::map<std::string, Directory>::const_iterator di =
+ this->Dirs.begin();
+ di != this->Dirs.end(); ++di) {
+ this->WriteXMLDirectory(xml, di->first, di->second);
+ }
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
+
+ return true;
+}
diff --git a/Source/CTest/cmCTestCVS.h b/Source/CTest/cmCTestCVS.h
new file mode 100644
index 0000000..4d5e6a9
--- /dev/null
+++ b/Source/CTest/cmCTestCVS.h
@@ -0,0 +1,53 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestCVS_h
+#define cmCTestCVS_h
+
+#include "cmCTestVC.h"
+
+/** \class cmCTestCVS
+ * \brief Interaction with cvs command-line tool
+ *
+ */
+class cmCTestCVS : public cmCTestVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestCVS(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestCVS() CM_OVERRIDE;
+
+private:
+ // Implement cmCTestVC internal API.
+ bool UpdateImpl() CM_OVERRIDE;
+ bool WriteXMLUpdates(cmXMLWriter& xml) CM_OVERRIDE;
+
+ // Update status for files in each directory.
+ class Directory : public std::map<std::string, PathStatus>
+ {
+ };
+ std::map<std::string, Directory> Dirs;
+
+ std::string ComputeBranchFlag(std::string const& dir);
+ void LoadRevisions(std::string const& file, const char* branchFlag,
+ std::vector<Revision>& revisions);
+ void WriteXMLDirectory(cmXMLWriter& xml, std::string const& path,
+ Directory const& dir);
+
+ // Parsing helper classes.
+ class UpdateParser;
+ class LogParser;
+ friend class UpdateParser;
+ friend class LogParser;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestCommand.h b/Source/CTest/cmCTestCommand.h
new file mode 100644
index 0000000..b0c9206
--- /dev/null
+++ b/Source/CTest/cmCTestCommand.h
@@ -0,0 +1,42 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestCommand_h
+#define cmCTestCommand_h
+
+#include "cmCommand.h"
+
+class cmCTest;
+class cmCTestScriptHandler;
+
+/** \class cmCTestCommand
+ * \brief A superclass for all commands added to the CTestScriptHandler
+ *
+ * cmCTestCommand is the superclass for all commands that will be added to
+ * the ctest script handlers parser.
+ *
+ */
+class cmCTestCommand : public cmCommand
+{
+public:
+ cmCTestCommand()
+ {
+ this->CTest = CM_NULLPTR;
+ this->CTestScriptHandler = CM_NULLPTR;
+ }
+
+ cmCTest* CTest;
+ cmCTestScriptHandler* CTestScriptHandler;
+
+ cmTypeMacro(cmCTestCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx
new file mode 100644
index 0000000..a823704
--- /dev/null
+++ b/Source/CTest/cmCTestConfigureCommand.cxx
@@ -0,0 +1,151 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestConfigureCommand.h"
+
+#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
+#include "cmGlobalGenerator.h"
+
+cmCTestConfigureCommand::cmCTestConfigureCommand()
+{
+ this->Arguments[ctc_OPTIONS] = "OPTIONS";
+ this->Arguments[ctc_LAST] = CM_NULLPTR;
+ this->Last = ctc_LAST;
+}
+
+cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
+{
+ std::vector<std::string> options;
+
+ if (this->Values[ctc_OPTIONS]) {
+ cmSystemTools::ExpandListArgument(this->Values[ctc_OPTIONS], options);
+ }
+
+ if (this->CTest->GetCTestConfiguration("BuildDirectory").empty()) {
+ this->SetError(
+ "Build directory not specified. Either use BUILD "
+ "argument to CTEST_CONFIGURE command or set CTEST_BINARY_DIRECTORY "
+ "variable");
+ return CM_NULLPTR;
+ }
+
+ const char* ctestConfigureCommand =
+ this->Makefile->GetDefinition("CTEST_CONFIGURE_COMMAND");
+
+ if (ctestConfigureCommand && *ctestConfigureCommand) {
+ this->CTest->SetCTestConfiguration("ConfigureCommand",
+ ctestConfigureCommand, this->Quiet);
+ } else {
+ const char* cmakeGeneratorName =
+ this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR");
+ if (cmakeGeneratorName && *cmakeGeneratorName) {
+ const std::string& source_dir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+ if (source_dir.empty()) {
+ this->SetError(
+ "Source directory not specified. Either use SOURCE "
+ "argument to CTEST_CONFIGURE command or set CTEST_SOURCE_DIRECTORY "
+ "variable");
+ return CM_NULLPTR;
+ }
+
+ const std::string cmakelists_file = source_dir + "/CMakeLists.txt";
+ if (!cmSystemTools::FileExists(cmakelists_file.c_str())) {
+ std::ostringstream e;
+ e << "CMakeLists.txt file does not exist [" << cmakelists_file << "]";
+ this->SetError(e.str());
+ return CM_NULLPTR;
+ }
+
+ bool multiConfig = false;
+ bool cmakeBuildTypeInOptions = false;
+
+ cmGlobalGenerator* gg =
+ this->Makefile->GetCMakeInstance()->CreateGlobalGenerator(
+ cmakeGeneratorName);
+ if (gg) {
+ multiConfig = gg->IsMultiConfig();
+ delete gg;
+ }
+
+ std::string cmakeConfigureCommand = "\"";
+ cmakeConfigureCommand += cmSystemTools::GetCMakeCommand();
+ cmakeConfigureCommand += "\"";
+
+ std::vector<std::string>::const_iterator it;
+ std::string option;
+ for (it = options.begin(); it != options.end(); ++it) {
+ option = *it;
+
+ cmakeConfigureCommand += " \"";
+ cmakeConfigureCommand += option;
+ cmakeConfigureCommand += "\"";
+
+ if ((CM_NULLPTR != strstr(option.c_str(), "CMAKE_BUILD_TYPE=")) ||
+ (CM_NULLPTR !=
+ strstr(option.c_str(), "CMAKE_BUILD_TYPE:STRING="))) {
+ cmakeBuildTypeInOptions = true;
+ }
+ }
+
+ if (!multiConfig && !cmakeBuildTypeInOptions &&
+ !this->CTest->GetConfigType().empty()) {
+ cmakeConfigureCommand += " \"-DCMAKE_BUILD_TYPE:STRING=";
+ cmakeConfigureCommand += this->CTest->GetConfigType();
+ cmakeConfigureCommand += "\"";
+ }
+
+ cmakeConfigureCommand += " \"-G";
+ cmakeConfigureCommand += cmakeGeneratorName;
+ cmakeConfigureCommand += "\"";
+
+ const char* cmakeGeneratorPlatform =
+ this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR_PLATFORM");
+ if (cmakeGeneratorPlatform && *cmakeGeneratorPlatform) {
+ cmakeConfigureCommand += " \"-A";
+ cmakeConfigureCommand += cmakeGeneratorPlatform;
+ cmakeConfigureCommand += "\"";
+ }
+
+ const char* cmakeGeneratorToolset =
+ this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR_TOOLSET");
+ if (cmakeGeneratorToolset && *cmakeGeneratorToolset) {
+ cmakeConfigureCommand += " \"-T";
+ cmakeConfigureCommand += cmakeGeneratorToolset;
+ cmakeConfigureCommand += "\"";
+ }
+
+ cmakeConfigureCommand += " \"";
+ cmakeConfigureCommand += source_dir;
+ cmakeConfigureCommand += "\"";
+
+ this->CTest->SetCTestConfiguration(
+ "ConfigureCommand", cmakeConfigureCommand.c_str(), this->Quiet);
+ } else {
+ this->SetError(
+ "Configure command is not specified. If this is a "
+ "\"built with CMake\" project, set CTEST_CMAKE_GENERATOR. If not, "
+ "set CTEST_CONFIGURE_COMMAND.");
+ return CM_NULLPTR;
+ }
+ }
+
+ cmCTestGenericHandler* handler =
+ this->CTest->GetInitializedHandler("configure");
+ if (!handler) {
+ this->SetError(
+ "internal CTest error. Cannot instantiate configure handler");
+ return CM_NULLPTR;
+ }
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
diff --git a/Source/CTest/cmCTestConfigureCommand.h b/Source/CTest/cmCTestConfigureCommand.h
new file mode 100644
index 0000000..a97f9f0
--- /dev/null
+++ b/Source/CTest/cmCTestConfigureCommand.h
@@ -0,0 +1,56 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestConfigureCommand_h
+#define cmCTestConfigureCommand_h
+
+#include "cmCTestHandlerCommand.h"
+
+/** \class cmCTestConfigure
+ * \brief Run a ctest script
+ *
+ * cmCTestConfigureCommand defineds the command to configures the project.
+ */
+class cmCTestConfigureCommand : public cmCTestHandlerCommand
+{
+public:
+ cmCTestConfigureCommand();
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestConfigureCommand* ni = new cmCTestConfigureCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return ni;
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "ctest_configure"; }
+
+ cmTypeMacro(cmCTestConfigureCommand, cmCTestHandlerCommand);
+
+protected:
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
+
+ enum
+ {
+ ctc_FIRST = ct_LAST,
+ ctc_OPTIONS,
+ ctc_LAST
+ };
+};
+
+#endif
diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx
new file mode 100644
index 0000000..b99455f
--- /dev/null
+++ b/Source/CTest/cmCTestConfigureHandler.cxx
@@ -0,0 +1,112 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCTestConfigureHandler.h"
+
+#include "cmCTest.h"
+#include "cmGeneratedFileStream.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+#include <cmsys/Process.h>
+
+cmCTestConfigureHandler::cmCTestConfigureHandler()
+{
+}
+
+void cmCTestConfigureHandler::Initialize()
+{
+ this->Superclass::Initialize();
+}
+
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
+int cmCTestConfigureHandler::ProcessHandler()
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "Configure project" << std::endl, this->Quiet);
+ std::string cCommand =
+ this->CTest->GetCTestConfiguration("ConfigureCommand");
+ if (cCommand.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find ConfigureCommand key in the DartConfiguration.tcl"
+ << std::endl);
+ return -1;
+ }
+
+ std::string buildDirectory =
+ this->CTest->GetCTestConfiguration("BuildDirectory");
+ if (buildDirectory.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find BuildDirectory key in the DartConfiguration.tcl"
+ << std::endl);
+ return -1;
+ }
+
+ double elapsed_time_start = cmSystemTools::GetTime();
+ std::string output;
+ int retVal = 0;
+ int res = 0;
+ if (!this->CTest->GetShowOnly()) {
+ cmGeneratedFileStream os;
+ if (!this->StartResultingXML(cmCTest::PartConfigure, "Configure", os)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open configure file"
+ << std::endl);
+ return 1;
+ }
+ std::string start_time = this->CTest->CurrentTime();
+ unsigned int start_time_time =
+ static_cast<unsigned int>(cmSystemTools::GetTime());
+
+ cmGeneratedFileStream ofs;
+ this->StartLogFile("Configure", ofs);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Configure with command: " << cCommand << std::endl,
+ this->Quiet);
+ res = this->CTest->RunMakeCommand(cCommand.c_str(), output, &retVal,
+ buildDirectory.c_str(), 0, ofs);
+
+ if (ofs) {
+ ofs.close();
+ }
+
+ if (os) {
+ cmXMLWriter xml(os);
+ this->CTest->StartXML(xml, this->AppendXML);
+ xml.StartElement("Configure");
+ xml.Element("StartDateTime", start_time);
+ xml.Element("StartConfigureTime", start_time_time);
+ xml.Element("ConfigureCommand", cCommand);
+ cmCTestOptionalLog(this->CTest, DEBUG, "End" << std::endl, this->Quiet);
+ xml.Element("Log", output);
+ xml.Element("ConfigureStatus", retVal);
+ xml.Element("EndDateTime", this->CTest->CurrentTime());
+ xml.Element("EndConfigureTime",
+ static_cast<unsigned int>(cmSystemTools::GetTime()));
+ xml.Element(
+ "ElapsedMinutes",
+ static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start) / 6) /
+ 10.0);
+ xml.EndElement(); // Configure
+ this->CTest->EndXML(xml);
+ }
+ } else {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Configure with command: " << cCommand << std::endl,
+ this->Quiet);
+ }
+ if (!res || retVal) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error(s) when configuring the project" << std::endl);
+ return -1;
+ }
+ return 0;
+}
diff --git a/Source/CTest/cmCTestConfigureHandler.h b/Source/CTest/cmCTestConfigureHandler.h
new file mode 100644
index 0000000..a7de939
--- /dev/null
+++ b/Source/CTest/cmCTestConfigureHandler.h
@@ -0,0 +1,39 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCTestConfigureHandler_h
+#define cmCTestConfigureHandler_h
+
+#include "cmCTestGenericHandler.h"
+
+#include "cmListFileCache.h"
+
+/** \class cmCTestConfigureHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestConfigureHandler : public cmCTestGenericHandler
+{
+public:
+ cmTypeMacro(cmCTestConfigureHandler, cmCTestGenericHandler);
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() CM_OVERRIDE;
+
+ cmCTestConfigureHandler();
+
+ void Initialize() CM_OVERRIDE;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx
new file mode 100644
index 0000000..86e3ce4
--- /dev/null
+++ b/Source/CTest/cmCTestCoverageCommand.cxx
@@ -0,0 +1,68 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestCoverageCommand.h"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+
+cmCTestCoverageCommand::cmCTestCoverageCommand()
+{
+ this->LabelsMentioned = false;
+}
+
+cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler()
+{
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CoverageCommand", "CTEST_COVERAGE_COMMAND", this->Quiet);
+ 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 CM_NULLPTR;
+ }
+
+ // If a LABELS option was given, select only files with the labels.
+ if (this->LabelsMentioned) {
+ handler->SetLabelFilter(this->Labels);
+ }
+
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
+
+bool cmCTestCoverageCommand::CheckArgumentKeyword(std::string const& arg)
+{
+ // Look for arguments specific to this command.
+ if (arg == "LABELS") {
+ this->ArgumentDoing = ArgumentDoingLabels;
+ this->LabelsMentioned = true;
+ return true;
+ }
+
+ // Look for other arguments.
+ return this->Superclass::CheckArgumentKeyword(arg);
+}
+
+bool cmCTestCoverageCommand::CheckArgumentValue(std::string const& arg)
+{
+ // Handle states specific to this command.
+ if (this->ArgumentDoing == ArgumentDoingLabels) {
+ this->Labels.insert(arg);
+ return true;
+ }
+
+ // Look for other arguments.
+ return this->Superclass::CheckArgumentValue(arg);
+}
diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h
new file mode 100644
index 0000000..ffd5fec
--- /dev/null
+++ b/Source/CTest/cmCTestCoverageCommand.h
@@ -0,0 +1,61 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestCoverageCommand_h
+#define cmCTestCoverageCommand_h
+
+#include "cmCTestHandlerCommand.h"
+
+/** \class cmCTestCoverage
+ * \brief Run a ctest script
+ *
+ * cmCTestCoverageCommand defineds the command to test the project.
+ */
+class cmCTestCoverageCommand : public cmCTestHandlerCommand
+{
+public:
+ cmCTestCoverageCommand();
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestCoverageCommand* ni = new cmCTestCoverageCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return ni;
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "ctest_coverage"; }
+
+ cmTypeMacro(cmCTestCoverageCommand, cmCTestHandlerCommand);
+
+protected:
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
+
+ bool CheckArgumentKeyword(std::string const& arg) CM_OVERRIDE;
+ bool CheckArgumentValue(std::string const& arg) CM_OVERRIDE;
+
+ enum
+ {
+ ArgumentDoingLabels = Superclass::ArgumentDoingLast1,
+ ArgumentDoingLast2
+ };
+
+ bool LabelsMentioned;
+ std::set<std::string> Labels;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
new file mode 100644
index 0000000..7102533
--- /dev/null
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -0,0 +1,2359 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestCoverageHandler.h"
+
+#include "cmCTest.h"
+#include "cmGeneratedFileStream.h"
+#include "cmMakefile.h"
+#include "cmParseBlanketJSCoverage.h"
+#include "cmParseCacheCoverage.h"
+#include "cmParseCoberturaCoverage.h"
+#include "cmParseDelphiCoverage.h"
+#include "cmParseGTMCoverage.h"
+#include "cmParseJacocoCoverage.h"
+#include "cmParsePHPCoverage.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/Process.h>
+#include <cmsys/RegularExpression.hxx>
+
+#include <float.h>
+#include <math.h>
+#include <stdlib.h>
+
+#define SAFEDIV(x, y) (((y) != 0) ? ((x) / (y)) : (0))
+
+class cmCTestRunProcess
+{
+public:
+ cmCTestRunProcess()
+ {
+ this->Process = cmsysProcess_New();
+ this->PipeState = -1;
+ this->TimeOut = -1;
+ }
+ ~cmCTestRunProcess()
+ {
+ if (!(this->PipeState == -1) &&
+ !(this->PipeState == cmsysProcess_Pipe_None) &&
+ !(this->PipeState == cmsysProcess_Pipe_Timeout)) {
+ this->WaitForExit();
+ }
+ cmsysProcess_Delete(this->Process);
+ }
+ void SetCommand(const char* command)
+ {
+ this->CommandLineStrings.clear();
+ this->CommandLineStrings.push_back(command);
+ ;
+ }
+ void AddArgument(const char* arg)
+ {
+ if (arg) {
+ this->CommandLineStrings.push_back(arg);
+ }
+ }
+ void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; }
+ void SetTimeout(double t) { this->TimeOut = t; }
+ bool StartProcess()
+ {
+ std::vector<const char*> args;
+ for (std::vector<std::string>::iterator i =
+ this->CommandLineStrings.begin();
+ i != this->CommandLineStrings.end(); ++i) {
+ args.push_back(i->c_str());
+ }
+ args.push_back(CM_NULLPTR); // null terminate
+ cmsysProcess_SetCommand(this->Process, &*args.begin());
+ if (!this->WorkingDirectory.empty()) {
+ cmsysProcess_SetWorkingDirectory(this->Process,
+ this->WorkingDirectory.c_str());
+ }
+
+ cmsysProcess_SetOption(this->Process, cmsysProcess_Option_HideWindow, 1);
+ if (this->TimeOut != -1) {
+ cmsysProcess_SetTimeout(this->Process, this->TimeOut);
+ }
+ cmsysProcess_Execute(this->Process);
+ this->PipeState = cmsysProcess_GetState(this->Process);
+ // if the process is running or exited return true
+ return this->PipeState == cmsysProcess_State_Executing ||
+ this->PipeState == cmsysProcess_State_Exited;
+ }
+ void SetStdoutFile(const char* fname)
+ {
+ cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDOUT, fname);
+ }
+ void SetStderrFile(const char* fname)
+ {
+ cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDERR, fname);
+ }
+ int WaitForExit(double* timeout = CM_NULLPTR)
+ {
+ this->PipeState = cmsysProcess_WaitForExit(this->Process, timeout);
+ return this->PipeState;
+ }
+ int GetProcessState() { return this->PipeState; }
+private:
+ int PipeState;
+ cmsysProcess* Process;
+ std::vector<std::string> CommandLineStrings;
+ std::string WorkingDirectory;
+ double TimeOut;
+};
+
+cmCTestCoverageHandler::cmCTestCoverageHandler()
+{
+}
+
+void cmCTestCoverageHandler::Initialize()
+{
+ this->Superclass::Initialize();
+ this->CustomCoverageExclude.clear();
+ this->SourceLabels.clear();
+ this->TargetDirs.clear();
+ this->LabelIdMap.clear();
+ this->Labels.clear();
+ this->LabelFilter.clear();
+}
+
+void cmCTestCoverageHandler::CleanCoverageLogFiles(std::ostream& log)
+{
+ std::string logGlob = this->CTest->GetCTestConfiguration("BuildDirectory");
+ logGlob += "/Testing/";
+ logGlob += this->CTest->GetCurrentTag();
+ logGlob += "/CoverageLog*";
+ cmsys::Glob gl;
+ gl.FindFiles(logGlob);
+ std::vector<std::string> const& files = gl.GetFiles();
+ for (std::vector<std::string>::const_iterator fi = files.begin();
+ fi != files.end(); ++fi) {
+ log << "Removing old coverage log: " << *fi << "\n";
+ cmSystemTools::RemoveFile(*fi);
+ }
+}
+
+bool cmCTestCoverageHandler::StartCoverageLogFile(
+ cmGeneratedFileStream& covLogFile, int logFileCount)
+{
+ char covLogFilename[1024];
+ sprintf(covLogFilename, "CoverageLog-%d", logFileCount);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Open file: " << covLogFilename << std::endl,
+ this->Quiet);
+ if (!this->StartResultingXML(cmCTest::PartCoverage, covLogFilename,
+ covLogFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open log file: " << covLogFilename << std::endl);
+ return false;
+ }
+ return true;
+}
+
+void cmCTestCoverageHandler::EndCoverageLogFile(cmGeneratedFileStream& ostr,
+ int logFileCount)
+{
+ char covLogFilename[1024];
+ sprintf(covLogFilename, "CoverageLog-%d.xml", logFileCount);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Close file: " << covLogFilename << std::endl,
+ this->Quiet);
+ ostr.Close();
+}
+
+void cmCTestCoverageHandler::StartCoverageLogXML(cmXMLWriter& xml)
+{
+ this->CTest->StartXML(xml, this->AppendXML);
+ xml.StartElement("CoverageLog");
+ xml.Element("StartDateTime", this->CTest->CurrentTime());
+ xml.Element("StartTime",
+ static_cast<unsigned int>(cmSystemTools::GetTime()));
+}
+
+void cmCTestCoverageHandler::EndCoverageLogXML(cmXMLWriter& xml)
+{
+ xml.Element("EndDateTime", this->CTest->CurrentTime());
+ xml.Element("EndTime", static_cast<unsigned int>(cmSystemTools::GetTime()));
+ xml.EndElement(); // CoverageLog
+ this->CTest->EndXML(xml);
+}
+
+bool cmCTestCoverageHandler::ShouldIDoCoverage(const char* file,
+ const char* srcDir,
+ const char* binDir)
+{
+ if (this->IsFilteredOut(file)) {
+ return false;
+ }
+
+ std::vector<cmsys::RegularExpression>::iterator sit;
+ for (sit = this->CustomCoverageExcludeRegex.begin();
+ sit != this->CustomCoverageExcludeRegex.end(); ++sit) {
+ if (sit->find(file)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " File "
+ << file << " is excluded in CTestCustom.ctest"
+ << std::endl;
+ , this->Quiet);
+ return false;
+ }
+ }
+
+ std::string fSrcDir = cmSystemTools::CollapseFullPath(srcDir);
+ std::string fBinDir = cmSystemTools::CollapseFullPath(binDir);
+ std::string fFile = cmSystemTools::CollapseFullPath(file);
+ bool sourceSubDir = cmSystemTools::IsSubDirectory(fFile, fSrcDir);
+ bool buildSubDir = cmSystemTools::IsSubDirectory(fFile, fBinDir);
+ // Always check parent directory of the file.
+ std::string fileDir = cmSystemTools::GetFilenamePath(fFile);
+ std::string checkDir;
+
+ // We also need to check the binary/source directory pair.
+ if (sourceSubDir && buildSubDir) {
+ if (fSrcDir.size() > fBinDir.size()) {
+ checkDir = fSrcDir;
+ } else {
+ checkDir = fBinDir;
+ }
+ } else if (sourceSubDir) {
+ checkDir = fSrcDir;
+ } else if (buildSubDir) {
+ checkDir = fBinDir;
+ }
+ std::string ndc = cmSystemTools::FileExistsInParentDirectories(
+ ".NoDartCoverage", fFile.c_str(), checkDir.c_str());
+ if (!ndc.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found: " << ndc << " so skip coverage of " << file
+ << std::endl,
+ this->Quiet);
+ return false;
+ }
+
+ // By now checkDir should be set to parent directory of the file.
+ // Get the relative path to the file an apply it to the opposite directory.
+ // If it is the same as fileDir, then ignore, otherwise check.
+ std::string relPath;
+ if (!checkDir.empty()) {
+ relPath = cmSystemTools::RelativePath(checkDir.c_str(), fFile.c_str());
+ } else {
+ relPath = fFile;
+ }
+ if (checkDir == fSrcDir) {
+ checkDir = fBinDir;
+ } else {
+ checkDir = fSrcDir;
+ }
+ fFile = checkDir + "/" + relPath;
+ fFile = cmSystemTools::GetFilenamePath(fFile);
+
+ if (fileDir == fFile) {
+ // This is in-source build, so we trust the previous check.
+ return true;
+ }
+
+ ndc = cmSystemTools::FileExistsInParentDirectories(
+ ".NoDartCoverage", fFile.c_str(), checkDir.c_str());
+ if (!ndc.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found: " << ndc << " so skip coverage of: " << file
+ << std::endl,
+ this->Quiet);
+ return false;
+ }
+ // Ok, nothing in source tree, nothing in binary tree
+ return true;
+}
+
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
+int cmCTestCoverageHandler::ProcessHandler()
+{
+ this->CTest->ClearSubmitFiles(cmCTest::PartCoverage);
+ int error = 0;
+ // do we have time for this
+ if (this->CTest->GetRemainingTimeAllowed() < 120) {
+ return error;
+ }
+
+ std::string coverage_start_time = this->CTest->CurrentTime();
+ unsigned int coverage_start_time_time =
+ static_cast<unsigned int>(cmSystemTools::GetTime());
+ std::string sourceDir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+ std::string binaryDir = this->CTest->GetCTestConfiguration("BuildDirectory");
+
+ this->LoadLabels();
+
+ cmGeneratedFileStream ofs;
+ double elapsed_time_start = cmSystemTools::GetTime();
+ if (!this->StartLogFile("Coverage", ofs)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create LastCoverage.log file" << std::endl);
+ }
+
+ ofs << "Performing coverage: " << elapsed_time_start << std::endl;
+ this->CleanCoverageLogFiles(ofs);
+
+ cmSystemTools::ConvertToUnixSlashes(sourceDir);
+ cmSystemTools::ConvertToUnixSlashes(binaryDir);
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "Performing coverage" << std::endl, this->Quiet);
+
+ cmCTestCoverageHandlerContainer cont;
+ cont.Error = error;
+ cont.SourceDir = sourceDir;
+ cont.BinaryDir = binaryDir;
+ cont.OFS = &ofs;
+ cont.Quiet = this->Quiet;
+
+ // setup the regex exclude stuff
+ this->CustomCoverageExcludeRegex.clear();
+ std::vector<std::string>::iterator rexIt;
+ for (rexIt = this->CustomCoverageExclude.begin();
+ rexIt != this->CustomCoverageExclude.end(); ++rexIt) {
+ this->CustomCoverageExcludeRegex.push_back(
+ cmsys::RegularExpression(rexIt->c_str()));
+ }
+
+ if (this->HandleBullseyeCoverage(&cont)) {
+ return cont.Error;
+ }
+ int file_count = 0;
+ file_count += this->HandleGCovCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+ file_count += this->HandleLCovCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+ file_count += this->HandleTracePyCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+ file_count += this->HandlePHPCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+ file_count += this->HandleCoberturaCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+
+ file_count += this->HandleMumpsCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+
+ file_count += this->HandleJacocoCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+
+ file_count += this->HandleBlanketJSCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+
+ file_count += this->HandleDelphiCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+ std::set<std::string> uncovered = this->FindUncoveredFiles(&cont);
+
+ if (file_count == 0 && this->ExtraCoverageGlobs.empty()) {
+ cmCTestOptionalLog(
+ this->CTest, WARNING,
+ " Cannot find any coverage files. Ignoring Coverage request."
+ << std::endl,
+ this->Quiet);
+ return error;
+ }
+ cmGeneratedFileStream covSumFile;
+ cmGeneratedFileStream covLogFile;
+ cmXMLWriter covSumXML(covSumFile);
+ cmXMLWriter covLogXML(covLogFile);
+
+ if (!this->StartResultingXML(cmCTest::PartCoverage, "Coverage",
+ covSumFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open coverage summary file."
+ << std::endl);
+ return -1;
+ }
+ covSumFile.setf(std::ios::fixed, std::ios::floatfield);
+ covSumFile.precision(2);
+
+ this->CTest->StartXML(covSumXML, this->AppendXML);
+ // Produce output xml files
+
+ covSumXML.StartElement("Coverage");
+ covSumXML.Element("StartDateTime", coverage_start_time);
+ covSumXML.Element("StartTime", coverage_start_time_time);
+ int logFileCount = 0;
+ if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
+ return -1;
+ }
+ this->StartCoverageLogXML(covLogXML);
+ cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator fileIterator;
+ int cnt = 0;
+ long total_tested = 0;
+ long total_untested = 0;
+ // std::string fullSourceDir = sourceDir + "/";
+ // std::string fullBinaryDir = binaryDir + "/";
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, std::endl, this->Quiet);
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ " Accumulating results (each . represents one file):" << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+
+ std::vector<std::string> errorsWhileAccumulating;
+
+ file_count = 0;
+ for (fileIterator = cont.TotalCoverage.begin();
+ fileIterator != cont.TotalCoverage.end(); ++fileIterator) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "." << std::flush,
+ this->Quiet);
+ file_count++;
+ if (file_count % 50 == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " processed: "
+ << file_count << " out of "
+ << cont.TotalCoverage.size() << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ }
+
+ const std::string fullFileName = fileIterator->first;
+ bool shouldIDoCoverage = this->ShouldIDoCoverage(
+ fullFileName.c_str(), sourceDir.c_str(), binaryDir.c_str());
+ if (!shouldIDoCoverage) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ ".NoDartCoverage found, so skip coverage check for: "
+ << fullFileName << std::endl,
+ this->Quiet);
+ continue;
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Process file: " << fullFileName << std::endl,
+ this->Quiet);
+
+ if (!cmSystemTools::FileExists(fullFileName.c_str())) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find file: " << fullFileName << std::endl);
+ continue;
+ }
+
+ if (++cnt % 100 == 0) {
+ this->EndCoverageLogXML(covLogXML);
+ this->EndCoverageLogFile(covLogFile, logFileCount);
+ logFileCount++;
+ if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
+ return -1;
+ }
+ this->StartCoverageLogXML(covLogXML);
+ }
+
+ const std::string fileName = cmSystemTools::GetFilenameName(fullFileName);
+ std::string shortFileName =
+ this->CTest->GetShortPathToFile(fullFileName.c_str());
+ const cmCTestCoverageHandlerContainer::SingleFileCoverageVector& fcov =
+ fileIterator->second;
+ covLogXML.StartElement("File");
+ covLogXML.Attribute("Name", fileName);
+ covLogXML.Attribute("FullPath", shortFileName);
+ covLogXML.StartElement("Report");
+
+ cmsys::ifstream ifs(fullFileName.c_str());
+ if (!ifs) {
+ std::ostringstream ostr;
+ ostr << "Cannot open source file: " << fullFileName;
+ errorsWhileAccumulating.push_back(ostr.str());
+ error++;
+ continue;
+ }
+
+ int tested = 0;
+ int untested = 0;
+
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector::size_type cc;
+ std::string line;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Actually performing coverage for: " << fullFileName
+ << std::endl,
+ this->Quiet);
+ for (cc = 0; cc < fcov.size(); cc++) {
+ if (!cmSystemTools::GetLineFromStream(ifs, line) &&
+ cc != fcov.size() - 1) {
+ std::ostringstream ostr;
+ ostr << "Problem reading source file: " << fullFileName
+ << " line:" << cc << " out total: " << fcov.size() - 1;
+ errorsWhileAccumulating.push_back(ostr.str());
+ error++;
+ break;
+ }
+ covLogXML.StartElement("Line");
+ covLogXML.Attribute("Number", cc);
+ covLogXML.Attribute("Count", fcov[cc]);
+ covLogXML.Content(line);
+ covLogXML.EndElement(); // Line
+ if (fcov[cc] == 0) {
+ untested++;
+ } else if (fcov[cc] > 0) {
+ tested++;
+ }
+ }
+ if (cmSystemTools::GetLineFromStream(ifs, line)) {
+ std::ostringstream ostr;
+ ostr << "Looks like there are more lines in the file: " << fullFileName;
+ errorsWhileAccumulating.push_back(ostr.str());
+ }
+ float cper = 0;
+ float cmet = 0;
+ if (tested + untested > 0) {
+ cper = (100 * SAFEDIV(static_cast<float>(tested),
+ static_cast<float>(tested + untested)));
+ cmet = (SAFEDIV(static_cast<float>(tested + 10),
+ static_cast<float>(tested + untested + 10)));
+ }
+ total_tested += tested;
+ total_untested += untested;
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
+ covSumXML.StartElement("File");
+ covSumXML.Attribute("Name", fileName);
+ covSumXML.Attribute("FullPath",
+ this->CTest->GetShortPathToFile(fullFileName.c_str()));
+ covSumXML.Attribute("Covered", tested + untested > 0 ? "true" : "false");
+ covSumXML.Element("LOCTested", tested);
+ covSumXML.Element("LOCUnTested", untested);
+ covSumXML.Element("PercentCoverage", cper);
+ covSumXML.Element("CoverageMetric", cmet);
+ this->WriteXMLLabels(covSumXML, shortFileName);
+ covSumXML.EndElement(); // File
+ }
+
+ // Handle all the files in the extra coverage globs that have no cov data
+ for (std::set<std::string>::iterator i = uncovered.begin();
+ i != uncovered.end(); ++i) {
+ std::string fileName = cmSystemTools::GetFilenameName(*i);
+ std::string fullPath = cont.SourceDir + "/" + *i;
+
+ covLogXML.StartElement("File");
+ covLogXML.Attribute("Name", fileName);
+ covLogXML.Attribute("FullPath", *i);
+ covLogXML.StartElement("Report");
+
+ cmsys::ifstream ifs(fullPath.c_str());
+ if (!ifs) {
+ std::ostringstream ostr;
+ ostr << "Cannot open source file: " << fullPath;
+ errorsWhileAccumulating.push_back(ostr.str());
+ error++;
+ continue;
+ }
+ int untested = 0;
+ std::string line;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Actually performing coverage for: " << *i << std::endl,
+ this->Quiet);
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ covLogXML.StartElement("Line");
+ covLogXML.Attribute("Number", untested);
+ covLogXML.Attribute("Count", 0);
+ covLogXML.Content(line);
+ covLogXML.EndElement(); // Line
+ untested++;
+ }
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
+
+ total_untested += untested;
+ covSumXML.StartElement("File");
+ covSumXML.Attribute("Name", fileName);
+ covSumXML.Attribute("FullPath", *i);
+ covSumXML.Attribute("Covered", "true");
+ covSumXML.Element("LOCTested", 0);
+ covSumXML.Element("LOCUnTested", untested);
+ covSumXML.Element("PercentCoverage", 0);
+ covSumXML.Element("CoverageMetric", 0);
+ this->WriteXMLLabels(covSumXML, *i);
+ covSumXML.EndElement(); // File
+ }
+
+ this->EndCoverageLogXML(covLogXML);
+ this->EndCoverageLogFile(covLogFile, logFileCount);
+
+ if (!errorsWhileAccumulating.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error(s) while accumulating results:" << std::endl);
+ std::vector<std::string>::iterator erIt;
+ for (erIt = errorsWhileAccumulating.begin();
+ erIt != errorsWhileAccumulating.end(); ++erIt) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " " << *erIt << std::endl);
+ }
+ }
+
+ long total_lines = total_tested + total_untested;
+ float percent_coverage = 100 *
+ SAFEDIV(static_cast<float>(total_tested), static_cast<float>(total_lines));
+ if (total_lines == 0) {
+ percent_coverage = 0;
+ }
+
+ std::string end_time = this->CTest->CurrentTime();
+
+ covSumXML.Element("LOCTested", total_tested);
+ covSumXML.Element("LOCUntested", total_untested);
+ covSumXML.Element("LOC", total_lines);
+ covSumXML.Element("PercentCoverage", percent_coverage);
+ covSumXML.Element("EndDateTime", end_time);
+ covSumXML.Element("EndTime",
+ static_cast<unsigned int>(cmSystemTools::GetTime()));
+ covSumXML.Element(
+ "ElapsedMinutes",
+ static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start) / 6) /
+ 10.0);
+ covSumXML.EndElement(); // Coverage
+ this->CTest->EndXML(covSumXML);
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, ""
+ << std::endl
+ << "\tCovered LOC: " << total_tested << std::endl
+ << "\tNot covered LOC: " << total_untested << std::endl
+ << "\tTotal LOC: " << total_lines << std::endl
+ << "\tPercentage Coverage: "
+ << std::setiosflags(std::ios::fixed) << std::setprecision(2)
+ << (percent_coverage) << "%" << std::endl);
+
+ ofs << "\tCovered LOC: " << total_tested << std::endl
+ << "\tNot covered LOC: " << total_untested << std::endl
+ << "\tTotal LOC: " << total_lines << std::endl
+ << "\tPercentage Coverage: " << std::setiosflags(std::ios::fixed)
+ << std::setprecision(2) << (percent_coverage) << "%" << std::endl;
+
+ if (error) {
+ return -1;
+ }
+ return 0;
+}
+
+void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile* mf)
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Add coverage exclude regular expressions." << std::endl,
+ this->Quiet);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_COVERAGE_EXCLUDE",
+ this->CustomCoverageExclude);
+ this->CTest->PopulateCustomVector(mf, "CTEST_EXTRA_COVERAGE_GLOB",
+ this->ExtraCoverageGlobs);
+ std::vector<std::string>::iterator it;
+ for (it = this->CustomCoverageExclude.begin();
+ it != this->CustomCoverageExclude.end(); ++it) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Add coverage exclude: " << *it << std::endl,
+ this->Quiet);
+ }
+ for (it = this->ExtraCoverageGlobs.begin();
+ it != this->ExtraCoverageGlobs.end(); ++it) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Add coverage glob: " << *it << std::endl,
+ this->Quiet);
+ }
+}
+
+// Fix for issue #4971 where the case of the drive letter component of
+// the filenames might be different when analyzing gcov output.
+//
+// Compare file names: fnc(fn1) == fnc(fn2) // fnc == file name compare
+//
+#ifdef _WIN32
+#define fnc(s) cmSystemTools::LowerCase(s)
+#else
+#define fnc(s) s
+#endif
+
+bool IsFileInDir(const std::string& infile, const std::string& indir)
+{
+ std::string file = cmSystemTools::CollapseFullPath(infile);
+ std::string dir = cmSystemTools::CollapseFullPath(indir);
+
+ return file.size() > dir.size() &&
+ fnc(file.substr(0, dir.size())) == fnc(dir) && file[dir.size()] == '/';
+}
+
+int cmCTestCoverageHandler::HandlePHPCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParsePHPCoverage cov(*cont, this->CTest);
+ std::string coverageDir = this->CTest->GetBinaryDir() + "/xdebugCoverage";
+ if (cmSystemTools::FileIsDirectory(coverageDir)) {
+ cov.ReadPHPCoverageDirectory(coverageDir.c_str());
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
+int cmCTestCoverageHandler::HandleCoberturaCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParseCoberturaCoverage cov(*cont, this->CTest);
+
+ // Assume the coverage.xml is in the binary directory
+ // check for the COBERTURADIR environment variable,
+ // if it doesn't exist or is empty, assume the
+ // binary directory is used.
+ std::string coverageXMLFile;
+ const char* covDir = cmSystemTools::GetEnv("COBERTURADIR");
+ if (covDir && strlen(covDir) != 0) {
+ coverageXMLFile = std::string(covDir);
+ } else {
+ coverageXMLFile = this->CTest->GetBinaryDir();
+ }
+ // build the find file string with the directory from above
+ coverageXMLFile += "/coverage.xml";
+
+ if (cmSystemTools::FileExists(coverageXMLFile.c_str())) {
+ // If file exists, parse it
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Parsing Cobertura XML file: " << coverageXMLFile
+ << std::endl,
+ this->Quiet);
+ cov.ReadCoverageXML(coverageXMLFile.c_str());
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find Cobertura XML file: " << coverageXMLFile
+ << std::endl,
+ this->Quiet);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
+int cmCTestCoverageHandler::HandleMumpsCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ // try gtm coverage
+ cmParseGTMCoverage cov(*cont, this->CTest);
+ std::string coverageFile =
+ this->CTest->GetBinaryDir() + "/gtm_coverage.mcov";
+ if (cmSystemTools::FileExists(coverageFile.c_str())) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Parsing Cache Coverage: " << coverageFile << std::endl,
+ this->Quiet);
+ cov.ReadCoverageFile(coverageFile.c_str());
+ return static_cast<int>(cont->TotalCoverage.size());
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find GTM coverage file: " << coverageFile
+ << std::endl,
+ this->Quiet);
+ }
+ cmParseCacheCoverage ccov(*cont, this->CTest);
+ coverageFile = this->CTest->GetBinaryDir() + "/cache_coverage.cmcov";
+ if (cmSystemTools::FileExists(coverageFile.c_str())) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Parsing Cache Coverage: " << coverageFile << std::endl,
+ this->Quiet);
+ ccov.ReadCoverageFile(coverageFile.c_str());
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find Cache coverage file: " << coverageFile
+ << std::endl,
+ this->Quiet);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
+struct cmCTestCoverageHandlerLocale
+{
+ cmCTestCoverageHandlerLocale()
+ {
+ if (const char* l = cmSystemTools::GetEnv("LC_ALL")) {
+ lc_all = l;
+ }
+ if (lc_all != "C") {
+ cmSystemTools::PutEnv("LC_ALL=C");
+ }
+ }
+ ~cmCTestCoverageHandlerLocale()
+ {
+ if (!lc_all.empty()) {
+ cmSystemTools::PutEnv("LC_ALL=" + lc_all);
+ } else {
+ cmSystemTools::UnsetEnv("LC_ALL");
+ }
+ }
+ std::string lc_all;
+};
+
+int cmCTestCoverageHandler::HandleJacocoCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParseJacocoCoverage cov = cmParseJacocoCoverage(*cont, this->CTest);
+
+ // Search in the source directory.
+ cmsys::Glob g1;
+ std::vector<std::string> files;
+ g1.SetRecurse(true);
+
+ std::string SourceDir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+ std::string coverageFile = SourceDir + "/*jacoco.xml";
+
+ g1.FindFiles(coverageFile);
+ files = g1.GetFiles();
+
+ // ...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());
+ }
+
+ if (!files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found Jacoco Files, Performing Coverage" << std::endl,
+ this->Quiet);
+ cov.LoadCoverageData(files);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find Jacoco coverage files: " << coverageFile
+ << std::endl,
+ this->Quiet);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
+int cmCTestCoverageHandler::HandleDelphiCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParseDelphiCoverage cov = cmParseDelphiCoverage(*cont, this->CTest);
+ cmsys::Glob g;
+ std::vector<std::string> files;
+ g.SetRecurse(true);
+
+ std::string BinDir = this->CTest->GetBinaryDir();
+ std::string coverageFile = BinDir + "/*(*.pas).html";
+
+ g.FindFiles(coverageFile);
+ files = g.GetFiles();
+ if (!files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found Delphi HTML Files, Performing Coverage"
+ << std::endl,
+ this->Quiet);
+ cov.LoadCoverageData(files);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find Delphi coverage files: " << coverageFile
+ << std::endl,
+ this->Quiet);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
+int cmCTestCoverageHandler::HandleBlanketJSCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParseBlanketJSCoverage cov = cmParseBlanketJSCoverage(*cont, this->CTest);
+ std::string SourceDir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+
+ // Look for something other than output.json, still JSON extension.
+ std::string coverageFile = SourceDir + "/*.json";
+ cmsys::Glob g;
+ std::vector<std::string> files;
+ std::vector<std::string> blanketFiles;
+ g.FindFiles(coverageFile);
+ files = g.GetFiles();
+ // Ensure that the JSON files found are the result of the
+ // Blanket.js output. Check for the "node-jscoverage"
+ // string on the second line
+ std::string line;
+ for (unsigned int fileEntry = 0; fileEntry < files.size(); fileEntry++) {
+ cmsys::ifstream in(files[fileEntry].c_str());
+ cmSystemTools::GetLineFromStream(in, line);
+ cmSystemTools::GetLineFromStream(in, line);
+ if (line.find("node-jscoverage") != line.npos) {
+ blanketFiles.push_back(files[fileEntry]);
+ }
+ }
+ // Take all files with the node-jscoverage string and parse those
+ if (!blanketFiles.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found BlanketJS output JSON, Performing Coverage"
+ << std::endl,
+ this->Quiet);
+ cov.LoadCoverageData(files);
+ } else {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find BlanketJS coverage files: " << coverageFile << std::endl,
+ this->Quiet);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+int cmCTestCoverageHandler::HandleGCovCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ std::string gcovCommand =
+ this->CTest->GetCTestConfiguration("CoverageCommand");
+ if (gcovCommand.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Could not find gcov."
+ << std::endl);
+ return 0;
+ }
+ std::string gcovExtraFlags =
+ this->CTest->GetCTestConfiguration("CoverageExtraFlags");
+
+ // Immediately skip to next coverage option since codecov is only for Intel
+ // compiler
+ if (gcovCommand == "codecov") {
+ return 0;
+ }
+
+ // Style 1
+ std::string st1gcovOutputRex1 =
+ "[0-9]+\\.[0-9]+% of [0-9]+ (source |)lines executed in file (.*)$";
+ std::string st1gcovOutputRex2 = "^Creating (.*\\.gcov)\\.";
+ cmsys::RegularExpression st1re1(st1gcovOutputRex1.c_str());
+ cmsys::RegularExpression st1re2(st1gcovOutputRex2.c_str());
+
+ // Style 2
+ std::string st2gcovOutputRex1 = "^File *[`'](.*)'$";
+ std::string st2gcovOutputRex2 =
+ "Lines executed: *[0-9]+\\.[0-9]+% of [0-9]+$";
+ std::string st2gcovOutputRex3 = "^(.*)reating [`'](.*\\.gcov)'";
+ std::string st2gcovOutputRex4 = "^(.*):unexpected EOF *$";
+ std::string st2gcovOutputRex5 = "^(.*):cannot open source file*$";
+ std::string st2gcovOutputRex6 =
+ "^(.*):source file is newer than graph file `(.*)'$";
+ cmsys::RegularExpression st2re1(st2gcovOutputRex1.c_str());
+ cmsys::RegularExpression st2re2(st2gcovOutputRex2.c_str());
+ cmsys::RegularExpression st2re3(st2gcovOutputRex3.c_str());
+ cmsys::RegularExpression st2re4(st2gcovOutputRex4.c_str());
+ cmsys::RegularExpression st2re5(st2gcovOutputRex5.c_str());
+ cmsys::RegularExpression st2re6(st2gcovOutputRex6.c_str());
+
+ std::vector<std::string> files;
+ this->FindGCovFiles(files);
+ std::vector<std::string>::iterator it;
+
+ if (files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find any GCov coverage files." << std::endl,
+ this->Quiet);
+ // No coverage files is a valid thing, so the exit code is 0
+ return 0;
+ }
+
+ std::string testingDir = this->CTest->GetBinaryDir() + "/Testing";
+ std::string tempDir = testingDir + "/CoverageInfo";
+ std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::MakeDirectory(tempDir.c_str());
+ cmSystemTools::ChangeDirectory(tempDir);
+
+ int gcovStyle = 0;
+
+ std::set<std::string> missingFiles;
+
+ std::string actualSourceFile = "";
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ " Processing coverage (each . represents one file):" << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ int file_count = 0;
+
+ // make sure output from gcov is in English!
+ cmCTestCoverageHandlerLocale locale_C;
+ static_cast<void>(locale_C);
+
+ // files is a list of *.da and *.gcda files with coverage data in them.
+ // These are binary files that you give as input to gcov so that it will
+ // give us text output we can analyze to summarize coverage.
+ //
+ for (it = files.begin(); it != files.end(); ++it) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "." << std::flush,
+ this->Quiet);
+
+ // Call gcov to get coverage data for this *.gcda file:
+ //
+ std::string fileDir = cmSystemTools::GetFilenamePath(*it);
+ std::string command = "\"" + gcovCommand + "\" " + gcovExtraFlags + " " +
+ "-o \"" + fileDir + "\" " + "\"" + *it + "\"";
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ command << std::endl, this->Quiet);
+
+ std::string output = "";
+ std::string errors = "";
+ int retVal = 0;
+ *cont->OFS << "* Run coverage for: " << fileDir << std::endl;
+ *cont->OFS << " Command: " << command << std::endl;
+ int res =
+ this->CTest->RunCommand(command.c_str(), &output, &errors, &retVal,
+ tempDir.c_str(), 0 /*this->TimeOut*/);
+
+ *cont->OFS << " Output: " << output << std::endl;
+ *cont->OFS << " Errors: " << errors << std::endl;
+ if (!res) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem running coverage on file: " << *it << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Command produced error: " << errors << std::endl);
+ cont->Error++;
+ continue;
+ }
+ if (retVal != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Coverage command returned: "
+ << retVal << " while processing: " << *it << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Command produced error: " << cont->Error << std::endl);
+ }
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "--------------------------------------------------------------"
+ << std::endl
+ << output << std::endl
+ << "--------------------------------------------------------------"
+ << std::endl,
+ this->Quiet);
+
+ std::vector<std::string> lines;
+ std::vector<std::string>::iterator line;
+
+ cmSystemTools::Split(output.c_str(), lines);
+
+ for (line = lines.begin(); line != lines.end(); ++line) {
+ std::string sourceFile;
+ std::string gcovFile;
+
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Line: [" << *line << "]" << std::endl, this->Quiet);
+
+ if (line->empty()) {
+ // Ignore empty line; probably style 2
+ } else if (st1re1.find(line->c_str())) {
+ if (gcovStyle == 0) {
+ gcovStyle = 1;
+ }
+ if (gcovStyle != 1) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e1"
+ << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ actualSourceFile = "";
+ sourceFile = st1re1.match(2);
+ } else if (st1re2.find(line->c_str())) {
+ if (gcovStyle == 0) {
+ gcovStyle = 1;
+ }
+ if (gcovStyle != 1) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e2"
+ << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ gcovFile = st1re2.match(1);
+ } else if (st2re1.find(line->c_str())) {
+ if (gcovStyle == 0) {
+ gcovStyle = 2;
+ }
+ if (gcovStyle != 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e3"
+ << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ actualSourceFile = "";
+ sourceFile = st2re1.match(1);
+ } else if (st2re2.find(line->c_str())) {
+ if (gcovStyle == 0) {
+ gcovStyle = 2;
+ }
+ if (gcovStyle != 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e4"
+ << std::endl);
+ cont->Error++;
+ break;
+ }
+ } else if (st2re3.find(line->c_str())) {
+ if (gcovStyle == 0) {
+ gcovStyle = 2;
+ }
+ if (gcovStyle != 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e5"
+ << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ gcovFile = st2re3.match(2);
+ } else if (st2re4.find(line->c_str())) {
+ if (gcovStyle == 0) {
+ gcovStyle = 2;
+ }
+ if (gcovStyle != 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e6"
+ << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "Warning: " << st2re4.match(1)
+ << " had unexpected EOF" << std::endl,
+ this->Quiet);
+ } else if (st2re5.find(line->c_str())) {
+ if (gcovStyle == 0) {
+ gcovStyle = 2;
+ }
+ if (gcovStyle != 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e7"
+ << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ cmCTestOptionalLog(this->CTest, WARNING, "Warning: Cannot open file: "
+ << st2re5.match(1) << std::endl,
+ this->Quiet);
+ } else if (st2re6.find(line->c_str())) {
+ if (gcovStyle == 0) {
+ gcovStyle = 2;
+ }
+ if (gcovStyle != 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e8"
+ << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ cmCTestOptionalLog(this->CTest, WARNING, "Warning: File: "
+ << st2re6.match(1) << " is newer than "
+ << st2re6.match(2) << std::endl,
+ this->Quiet);
+ } else {
+ // gcov 4.7 can have output lines saying "No executable lines" and
+ // "Removing 'filename.gcov'"... Don't log those as "errors."
+ if (*line != "No executable lines" &&
+ !cmSystemTools::StringStartsWith(line->c_str(), "Removing ")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output line: ["
+ << *line << "]" << std::endl);
+ cont->Error++;
+ // abort();
+ }
+ }
+
+ // If the last line of gcov output gave us a valid value for gcovFile,
+ // and we have an actualSourceFile, then insert a (or add to existing)
+ // SingleFileCoverageVector for actualSourceFile:
+ //
+ if (!gcovFile.empty() && !actualSourceFile.empty()) {
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& vec =
+ cont->TotalCoverage[actualSourceFile];
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " in gcovFile: " << gcovFile << std::endl,
+ this->Quiet);
+
+ cmsys::ifstream ifile(gcovFile.c_str());
+ if (!ifile) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open file: " << gcovFile << std::endl);
+ } else {
+ long cnt = -1;
+ std::string nl;
+ while (cmSystemTools::GetLineFromStream(ifile, nl)) {
+ cnt++;
+
+ // TODO: Handle gcov 3.0 non-coverage lines
+
+ // Skip empty lines
+ if (nl.empty()) {
+ continue;
+ }
+
+ // Skip unused lines
+ if (nl.size() < 12) {
+ continue;
+ }
+
+ // Read the coverage count from the beginning of the gcov output
+ // line
+ std::string prefix = nl.substr(0, 12);
+ int cov = atoi(prefix.c_str());
+
+ // Read the line number starting at the 10th character of the gcov
+ // output line
+ std::string lineNumber = nl.substr(10, 5);
+
+ int lineIdx = atoi(lineNumber.c_str()) - 1;
+ if (lineIdx >= 0) {
+ while (vec.size() <= static_cast<size_t>(lineIdx)) {
+ vec.push_back(-1);
+ }
+
+ // Initially all entries are -1 (not used). If we get coverage
+ // information, increment it to 0 first.
+ if (vec[lineIdx] < 0) {
+ if (cov > 0 || prefix.find('#') != prefix.npos) {
+ vec[lineIdx] = 0;
+ }
+ }
+
+ vec[lineIdx] += cov;
+ }
+ }
+ }
+
+ actualSourceFile = "";
+ }
+
+ if (!sourceFile.empty() && actualSourceFile.empty()) {
+ gcovFile = "";
+
+ // Is it in the source dir or the binary dir?
+ //
+ if (IsFileInDir(sourceFile, cont->SourceDir)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " produced s: " << sourceFile << std::endl,
+ this->Quiet);
+ *cont->OFS << " produced in source dir: " << sourceFile
+ << std::endl;
+ actualSourceFile = cmSystemTools::CollapseFullPath(sourceFile);
+ } else if (IsFileInDir(sourceFile, cont->BinaryDir)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " produced b: " << sourceFile << std::endl,
+ this->Quiet);
+ *cont->OFS << " produced in binary dir: " << sourceFile
+ << std::endl;
+ actualSourceFile = cmSystemTools::CollapseFullPath(sourceFile);
+ }
+
+ if (actualSourceFile.empty()) {
+ if (missingFiles.find(sourceFile) == missingFiles.end()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Something went wrong" << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Cannot find file: [" << sourceFile << "]"
+ << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " in source dir: [" << cont->SourceDir << "]"
+ << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " or binary dir: [" << cont->BinaryDir.size()
+ << "]" << std::endl,
+ this->Quiet);
+ *cont->OFS << " Something went wrong. Cannot find file: "
+ << sourceFile << " in source dir: " << cont->SourceDir
+ << " or binary dir: " << cont->BinaryDir << std::endl;
+
+ missingFiles.insert(sourceFile);
+ }
+ }
+ }
+ }
+
+ file_count++;
+
+ if (file_count % 50 == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " processed: " << file_count << " out of "
+ << files.size() << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ }
+ }
+
+ cmSystemTools::ChangeDirectory(currentDirectory);
+ return file_count;
+}
+
+int cmCTestCoverageHandler::HandleLCovCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ std::string lcovCommand =
+ this->CTest->GetCTestConfiguration("CoverageCommand");
+ std::string lcovExtraFlags =
+ this->CTest->GetCTestConfiguration("CoverageExtraFlags");
+ if (lcovCommand != "codecov") {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Not a valid Intel Coverage command." << std::endl,
+ this->Quiet);
+ return 0;
+ }
+ // There is only percentage completed output from LCOV
+ std::string st2lcovOutputRex3 = "[0-9]+%";
+ cmsys::RegularExpression st2re3(st2lcovOutputRex3.c_str());
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " This is coverage command: " << lcovCommand << std::endl,
+ this->Quiet);
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " These are coverage command flags: " << lcovExtraFlags
+ << std::endl,
+ this->Quiet);
+
+ std::vector<std::string> files;
+ if (!this->FindLCovFiles(files)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error while finding LCov files.\n");
+ return 0;
+ }
+ std::vector<std::string>::iterator it;
+
+ if (files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find any LCov coverage files." << std::endl,
+ this->Quiet);
+ // No coverage files is a valid thing, so the exit code is 0
+ return 0;
+ }
+ std::string testingDir = this->CTest->GetBinaryDir();
+ std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();
+
+ std::set<std::string> missingFiles;
+
+ std::string actualSourceFile = "";
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ " Processing coverage (each . represents one file):" << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ int file_count = 0;
+
+ // make sure output from lcov is in English!
+ cmCTestCoverageHandlerLocale locale_C;
+ static_cast<void>(locale_C);
+
+ // In intel compiler we have to call codecov only once in each executable
+ // directory. It collects all *.dyn files to generate .dpi file.
+ for (it = files.begin(); it != files.end(); ++it) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "." << std::flush,
+ this->Quiet);
+ std::string fileDir = cmSystemTools::GetFilenamePath(*it);
+ cmSystemTools::ChangeDirectory(fileDir);
+ std::string command = "\"" + lcovCommand + "\" " + lcovExtraFlags + " ";
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Current coverage dir: " << fileDir << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ command << std::endl, this->Quiet);
+
+ std::string output = "";
+ std::string errors = "";
+ int retVal = 0;
+ *cont->OFS << "* Run coverage for: " << fileDir << std::endl;
+ *cont->OFS << " Command: " << command << std::endl;
+ int res =
+ this->CTest->RunCommand(command.c_str(), &output, &errors, &retVal,
+ fileDir.c_str(), 0 /*this->TimeOut*/);
+
+ *cont->OFS << " Output: " << output << std::endl;
+ *cont->OFS << " Errors: " << errors << std::endl;
+ if (!res) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem running coverage on file: " << *it << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Command produced error: " << errors << std::endl);
+ cont->Error++;
+ continue;
+ }
+ if (retVal != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Coverage command returned: "
+ << retVal << " while processing: " << *it << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Command produced error: " << cont->Error << std::endl);
+ }
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "--------------------------------------------------------------"
+ << std::endl
+ << output << std::endl
+ << "--------------------------------------------------------------"
+ << std::endl,
+ this->Quiet);
+
+ std::vector<std::string> lines;
+ std::vector<std::string>::iterator line;
+
+ cmSystemTools::Split(output.c_str(), lines);
+
+ for (line = lines.begin(); line != lines.end(); ++line) {
+ std::string sourceFile;
+ std::string lcovFile;
+
+ if (line->empty()) {
+ // Ignore empty line
+ }
+ // Look for LCOV files in binary directory
+ // Intel Compiler creates a CodeCoverage dir for each subfolder and
+ // each subfolder has LCOV files
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOff();
+ std::string dir;
+ std::vector<std::string> lcovFiles;
+ dir = this->CTest->GetBinaryDir();
+ std::string daGlob;
+ daGlob = dir;
+ daGlob += "/*.LCOV";
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " 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());
+
+ for (std::vector<std::string>::iterator a = lcovFiles.begin();
+ a != lcovFiles.end(); ++a) {
+ lcovFile = *a;
+ cmsys::ifstream srcead(lcovFile.c_str());
+ if (!srcead) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open file: " << lcovFile << std::endl);
+ }
+ std::string srcname;
+
+ int success = cmSystemTools::GetLineFromStream(srcead, srcname);
+ if (!success) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error while parsing lcov file '"
+ << lcovFile << "':"
+ << " No source file name found!" << std::endl);
+ return 0;
+ }
+ srcname = srcname.substr(18);
+ // We can directly read found LCOV files to determine the source
+ // files
+ sourceFile = srcname;
+ actualSourceFile = srcname;
+
+ for (std::vector<std::string>::iterator t = lcovFiles.begin();
+ t != lcovFiles.end(); ++t) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found LCOV File: " << *t << std::endl,
+ this->Quiet);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "SourceFile: " << sourceFile << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "lCovFile: " << lcovFile << std::endl, this->Quiet);
+
+ // If we have some LCOV files to process
+ if (!lcovFile.empty() && !actualSourceFile.empty()) {
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& vec =
+ cont->TotalCoverage[actualSourceFile];
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " in lcovFile: " << lcovFile << std::endl,
+ this->Quiet);
+
+ cmsys::ifstream ifile(lcovFile.c_str());
+ if (!ifile) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open file: " << lcovFile << std::endl);
+ } else {
+ long cnt = -1;
+ std::string nl;
+
+ // Skip the first line
+ cmSystemTools::GetLineFromStream(ifile, nl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "File is ready, start reading." << std::endl,
+ this->Quiet);
+ while (cmSystemTools::GetLineFromStream(ifile, nl)) {
+ cnt++;
+
+ // Skip empty lines
+ if (nl.empty()) {
+ continue;
+ }
+
+ // Skip unused lines
+ if (nl.size() < 12) {
+ continue;
+ }
+
+ // Read the coverage count from the beginning of the lcov
+ // output line
+ std::string prefix = nl.substr(0, 17);
+ int cov = atoi(prefix.c_str());
+
+ // Read the line number starting at the 17th character of the
+ // lcov output line
+ std::string lineNumber = nl.substr(17, 7);
+
+ int lineIdx = atoi(lineNumber.c_str()) - 1;
+ if (lineIdx >= 0) {
+ while (vec.size() <= static_cast<size_t>(lineIdx)) {
+ vec.push_back(-1);
+ }
+
+ // Initially all entries are -1 (not used). If we get coverage
+ // information, increment it to 0 first.
+ if (vec[lineIdx] < 0) {
+ if (cov > 0 || prefix.find('#') != prefix.npos) {
+ vec[lineIdx] = 0;
+ }
+ }
+
+ vec[lineIdx] += cov;
+ }
+ }
+ }
+
+ actualSourceFile = "";
+ }
+ }
+ }
+
+ file_count++;
+
+ if (file_count % 50 == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " processed: " << file_count << " out of "
+ << files.size() << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ }
+ }
+
+ cmSystemTools::ChangeDirectory(currentDirectory);
+ return file_count;
+}
+
+void cmCTestCoverageHandler::FindGCovFiles(std::vector<std::string>& files)
+{
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOff();
+
+ for (LabelMapType::const_iterator lmi = this->TargetDirs.begin();
+ lmi != this->TargetDirs.end(); ++lmi) {
+ // Skip targets containing no interesting labels.
+ if (!this->IntersectsFilter(lmi->second)) {
+ continue;
+ }
+
+ // Coverage files appear next to their object files in the target
+ // support directory.
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " globbing for coverage in: " << lmi->first << std::endl, this->Quiet);
+ std::string daGlob = lmi->first;
+ daGlob += "/*.da";
+ gl.FindFiles(daGlob);
+ files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
+ daGlob = lmi->first;
+ daGlob += "/*.gcda";
+ gl.FindFiles(daGlob);
+ files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
+ }
+}
+
+bool cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files)
+{
+ cmsys::Glob gl;
+ gl.RecurseOff(); // No need of recurse if -prof_dir${BUILD_DIR} flag is
+ // used while compiling.
+ gl.RecurseThroughSymlinksOff();
+ std::string prevBinaryDir;
+ std::string buildDir = this->CTest->GetCTestConfiguration("BuildDirectory");
+ if (cmSystemTools::ChangeDirectory(buildDir)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Error changing directory to "
+ << buildDir << std::endl);
+ return false;
+ }
+
+ // Run profmerge to merge all *.dyn files into dpi files
+ if (!cmSystemTools::RunSingleCommand("profmerge")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Error while running profmerge.\n");
+ return false;
+ }
+
+ prevBinaryDir = cmSystemTools::GetCurrentWorkingDirectory();
+
+ // DPI file should appear in build directory
+ std::string daGlob;
+ daGlob = prevBinaryDir;
+ daGlob += "/*.dpi";
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " looking for dpi files in: " << daGlob << std::endl,
+ this->Quiet);
+ if (!gl.FindFiles(daGlob)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error while finding files matching " << daGlob << std::endl);
+ return false;
+ }
+ files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Now searching in: " << daGlob << std::endl, this->Quiet);
+ return true;
+}
+
+int cmCTestCoverageHandler::HandleTracePyCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOff();
+ std::string daGlob = cont->BinaryDir + "/*.cover";
+ gl.FindFiles(daGlob);
+ std::vector<std::string> files = gl.GetFiles();
+
+ if (files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find any Python Trace.py coverage files."
+ << std::endl,
+ this->Quiet);
+ // No coverage files is a valid thing, so the exit code is 0
+ return 0;
+ }
+
+ std::string testingDir = this->CTest->GetBinaryDir() + "/Testing";
+ std::string tempDir = testingDir + "/CoverageInfo";
+ std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::MakeDirectory(tempDir.c_str());
+ cmSystemTools::ChangeDirectory(tempDir);
+
+ cmSystemTools::ChangeDirectory(currentDirectory);
+
+ std::vector<std::string>::iterator fileIt;
+ int file_count = 0;
+ for (fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
+ std::string fileName = this->FindFile(cont, *fileIt);
+ if (fileName.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find source Python file corresponding to: "
+ << *fileIt << std::endl);
+ continue;
+ }
+
+ std::string actualSourceFile = cmSystemTools::CollapseFullPath(fileName);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Check coverage for file: " << actualSourceFile
+ << std::endl,
+ this->Quiet);
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector* vec =
+ &cont->TotalCoverage[actualSourceFile];
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " in file: " << *fileIt << std::endl, this->Quiet);
+ cmsys::ifstream ifile(fileIt->c_str());
+ if (!ifile) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open file: " << *fileIt << std::endl);
+ } else {
+ long cnt = -1;
+ std::string nl;
+ while (cmSystemTools::GetLineFromStream(ifile, nl)) {
+ cnt++;
+
+ // Skip empty lines
+ if (nl.empty()) {
+ continue;
+ }
+
+ // Skip unused lines
+ if (nl.size() < 12) {
+ continue;
+ }
+
+ // Read the coverage count from the beginning of the Trace.py output
+ // line
+ std::string prefix = nl.substr(0, 6);
+ if (prefix[5] != ' ' && prefix[5] != ':') {
+ // This is a hack. We should really do something more elaborate
+ prefix = nl.substr(0, 7);
+ if (prefix[6] != ' ' && prefix[6] != ':') {
+ prefix = nl.substr(0, 8);
+ if (prefix[7] != ' ' && prefix[7] != ':') {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Currently the limit is maximum coverage of 999999"
+ << std::endl);
+ }
+ }
+ }
+ int cov = atoi(prefix.c_str());
+ if (prefix[prefix.size() - 1] != ':') {
+ // This line does not have ':' so no coverage here. That said,
+ // Trace.py does not handle not covered lines versus comments etc.
+ // So, this will be set to 0.
+ cov = 0;
+ }
+ cmCTestOptionalLog(
+ this->CTest, DEBUG,
+ "Prefix: " << prefix << " cov: " << cov << std::endl, this->Quiet);
+ // Read the line number starting at the 10th character of the gcov
+ // output line
+ long lineIdx = cnt;
+ if (lineIdx >= 0) {
+ while (vec->size() <= static_cast<size_t>(lineIdx)) {
+ vec->push_back(-1);
+ }
+ // Initially all entries are -1 (not used). If we get coverage
+ // information, increment it to 0 first.
+ if ((*vec)[lineIdx] < 0) {
+ if (cov >= 0) {
+ (*vec)[lineIdx] = 0;
+ }
+ }
+ (*vec)[lineIdx] += cov;
+ }
+ }
+ }
+ ++file_count;
+ }
+ cmSystemTools::ChangeDirectory(currentDirectory);
+ return file_count;
+}
+
+std::string cmCTestCoverageHandler::FindFile(
+ cmCTestCoverageHandlerContainer* cont, std::string const& fileName)
+{
+ std::string fileNameNoE =
+ cmSystemTools::GetFilenameWithoutLastExtension(fileName);
+ // First check in source and binary directory
+ std::string fullName = cont->SourceDir + "/" + fileNameNoE + ".py";
+ if (cmSystemTools::FileExists(fullName.c_str())) {
+ return fullName;
+ }
+ fullName = cont->BinaryDir + "/" + fileNameNoE + ".py";
+ if (cmSystemTools::FileExists(fullName.c_str())) {
+ return fullName;
+ }
+ return "";
+}
+
+// This is a header put on each marked up source file
+namespace {
+const char* bullseyeHelp[] = {
+ " Coverage produced by bullseye covbr tool: ",
+ " www.bullseye.com/help/ref_covbr.html",
+ " * An arrow --> indicates incomplete coverage.",
+ " * An X indicates a function that was invoked, a switch label that ",
+ " was exercised, a try-block that finished, or an exception handler ",
+ " that was invoked.",
+ " * A T or F indicates a boolean decision that evaluated true or false,",
+ " respectively.",
+ " * A t or f indicates a boolean condition within a decision if the ",
+ " condition evaluated true or false, respectively.",
+ " * A k indicates a constant decision or condition.",
+ " * The slash / means this probe is excluded from summary results. ",
+ CM_NULLPTR
+};
+}
+
+int cmCTestCoverageHandler::RunBullseyeCoverageBranch(
+ cmCTestCoverageHandlerContainer* cont,
+ std::set<std::string>& coveredFileNames, std::vector<std::string>& files,
+ std::vector<std::string>& filesFullPath)
+{
+ if (files.size() != filesFullPath.size()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Files and full path files not the same size?:\n");
+ return 0;
+ }
+ // create the output stream for the CoverageLog-N.xml file
+ cmGeneratedFileStream covLogFile;
+ cmXMLWriter covLogXML(covLogFile);
+ int logFileCount = 0;
+ if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
+ return -1;
+ }
+ this->StartCoverageLogXML(covLogXML);
+ // for each file run covbr on that file to get the coverage
+ // information for that file
+ std::string outputFile;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "run covbr: " << std::endl, this->Quiet);
+
+ if (!this->RunBullseyeCommand(cont, "covbr", CM_NULLPTR, outputFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "error running covbr for."
+ << "\n");
+ return -1;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "covbr output in " << outputFile << std::endl,
+ this->Quiet);
+ // open the output file
+ cmsys::ifstream fin(outputFile.c_str());
+ if (!fin) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open coverage file: " << outputFile << std::endl);
+ return 0;
+ }
+ std::map<std::string, std::string> fileMap;
+ std::vector<std::string>::iterator fp = filesFullPath.begin();
+ for (std::vector<std::string>::iterator f = files.begin(); f != files.end();
+ ++f, ++fp) {
+ fileMap[*f] = *fp;
+ }
+
+ int count = 0; // keep count of the number of files
+ // Now parse each line from the bullseye cov log file
+ std::string lineIn;
+ bool valid = false; // are we in a valid output file
+ int line = 0; // line of the current file
+ std::string file;
+ while (cmSystemTools::GetLineFromStream(fin, lineIn)) {
+ bool startFile = false;
+ if (lineIn.size() > 1 && lineIn[lineIn.size() - 1] == ':') {
+ file = lineIn.substr(0, lineIn.size() - 1);
+ if (coveredFileNames.find(file) != coveredFileNames.end()) {
+ startFile = true;
+ }
+ }
+ if (startFile) {
+ // if we are in a valid file close it because a new one started
+ if (valid) {
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
+ }
+ // only allow 100 files in each log file
+ if (count != 0 && count % 100 == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "start a new log file: " << count << std::endl,
+ this->Quiet);
+ this->EndCoverageLogXML(covLogXML);
+ this->EndCoverageLogFile(covLogFile, logFileCount);
+ logFileCount++;
+ if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
+ return -1;
+ }
+ this->StartCoverageLogXML(covLogXML);
+ count++; // move on one
+ }
+ std::map<std::string, std::string>::iterator i = fileMap.find(file);
+ // if the file should be covered write out the header for that file
+ if (i != fileMap.end()) {
+ // we have a new file so count it in the output
+ count++;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Produce coverage for file: " << file << " "
+ << count << std::endl,
+ this->Quiet);
+ // start the file output
+ covLogXML.StartElement("File");
+ covLogXML.Attribute("Name", i->first);
+ covLogXML.Attribute(
+ "FullPath", this->CTest->GetShortPathToFile(i->second.c_str()));
+ covLogXML.StartElement("Report");
+ // write the bullseye header
+ line = 0;
+ for (int k = 0; bullseyeHelp[k] != CM_NULLPTR; ++k) {
+ covLogXML.StartElement("Line");
+ covLogXML.Attribute("Number", line);
+ covLogXML.Attribute("Count", -1);
+ covLogXML.Content(bullseyeHelp[k]);
+ covLogXML.EndElement(); // Line
+ line++;
+ }
+ valid = true; // we are in a valid file section
+ } else {
+ // this is not a file that we want coverage for
+ valid = false;
+ }
+ }
+ // we are not at a start file, and we are in a valid file output the line
+ else if (valid) {
+ covLogXML.StartElement("Line");
+ covLogXML.Attribute("Number", line);
+ covLogXML.Attribute("Count", -1);
+ covLogXML.Content(lineIn);
+ covLogXML.EndElement(); // Line
+ line++;
+ }
+ }
+ // if we ran out of lines a valid file then close that file
+ if (valid) {
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
+ }
+ this->EndCoverageLogXML(covLogXML);
+ this->EndCoverageLogFile(covLogFile, logFileCount);
+ return 1;
+}
+
+int cmCTestCoverageHandler::RunBullseyeCommand(
+ cmCTestCoverageHandlerContainer* cont, const char* cmd, const char* arg,
+ std::string& outputFile)
+{
+ std::string program = cmSystemTools::FindProgram(cmd);
+ if (program.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find :" << cmd << "\n");
+ return 0;
+ }
+ if (arg) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run : " << program << " " << arg << "\n", this->Quiet);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run : " << program << "\n", this->Quiet);
+ }
+ // create a process object and start it
+ cmCTestRunProcess runCoverageSrc;
+ runCoverageSrc.SetCommand(program.c_str());
+ runCoverageSrc.AddArgument(arg);
+ std::string stdoutFile = cont->BinaryDir + "/Testing/Temporary/";
+ stdoutFile += this->GetCTestInstance()->GetCurrentTag();
+ stdoutFile += "-";
+ stdoutFile += cmd;
+ std::string stderrFile = stdoutFile;
+ stdoutFile += ".stdout";
+ stderrFile += ".stderr";
+ runCoverageSrc.SetStdoutFile(stdoutFile.c_str());
+ runCoverageSrc.SetStderrFile(stderrFile.c_str());
+ if (!runCoverageSrc.StartProcess()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Could not run : " << program << " " << arg << "\n"
+ << "kwsys process state : "
+ << runCoverageSrc.GetProcessState());
+ return 0;
+ }
+ // since we set the output file names wait for it to end
+ runCoverageSrc.WaitForExit();
+ outputFile = stdoutFile;
+ return 1;
+}
+
+int cmCTestCoverageHandler::RunBullseyeSourceSummary(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ // Run the covsrc command and create a temp outputfile
+ std::string outputFile;
+ if (!this->RunBullseyeCommand(cont, "covsrc", "-c", outputFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "error running covsrc:\n");
+ return 0;
+ }
+
+ std::ostream& tmpLog = *cont->OFS;
+ // copen the Coverage.xml file in the Testing directory
+ cmGeneratedFileStream covSumFile;
+ cmXMLWriter xml(covSumFile);
+ if (!this->StartResultingXML(cmCTest::PartCoverage, "Coverage",
+ covSumFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open coverage summary file."
+ << std::endl);
+ return 0;
+ }
+ this->CTest->StartXML(xml, this->AppendXML);
+ double elapsed_time_start = cmSystemTools::GetTime();
+ std::string coverage_start_time = this->CTest->CurrentTime();
+ xml.StartElement("Coverage");
+ xml.Element("StartDateTime", coverage_start_time);
+ xml.Element("StartTime",
+ static_cast<unsigned int>(cmSystemTools::GetTime()));
+ std::string stdline;
+ std::string errline;
+ // expected output:
+ // first line is:
+ // "Source","Function Coverage","out of","%","C/D Coverage","out of","%"
+ // after that data follows in that format
+ std::string sourceFile;
+ int functionsCalled = 0;
+ int totalFunctions = 0;
+ int percentFunction = 0;
+ int branchCovered = 0;
+ int totalBranches = 0;
+ int percentBranch = 0;
+ double total_tested = 0;
+ double total_untested = 0;
+ double total_functions = 0;
+ double percent_coverage = 0;
+ double number_files = 0;
+ std::vector<std::string> coveredFiles;
+ std::vector<std::string> coveredFilesFullPath;
+ // Read and parse the summary output file
+ cmsys::ifstream fin(outputFile.c_str());
+ if (!fin) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open coverage summary file: " << outputFile
+ << std::endl);
+ return 0;
+ }
+ std::set<std::string> coveredFileNames;
+ while (cmSystemTools::GetLineFromStream(fin, stdline)) {
+ // if we have a line of output from stdout
+ if (!stdline.empty()) {
+ // parse the comma separated output
+ this->ParseBullsEyeCovsrcLine(
+ stdline, sourceFile, functionsCalled, totalFunctions, percentFunction,
+ branchCovered, totalBranches, percentBranch);
+ // The first line is the header
+ if (sourceFile == "Source" || sourceFile == "Total") {
+ continue;
+ }
+ std::string file = sourceFile;
+ coveredFileNames.insert(file);
+ if (!cmSystemTools::FileIsFullPath(sourceFile.c_str())) {
+ // file will be relative to the binary dir
+ file = cont->BinaryDir;
+ file += "/";
+ file += sourceFile;
+ }
+ file = cmSystemTools::CollapseFullPath(file);
+ bool shouldIDoCoverage = this->ShouldIDoCoverage(
+ file.c_str(), cont->SourceDir.c_str(), cont->BinaryDir.c_str());
+ if (!shouldIDoCoverage) {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ ".NoDartCoverage found, so skip coverage check for: " << file
+ << std::endl,
+ this->Quiet);
+ continue;
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Doing coverage for: " << file << std::endl,
+ this->Quiet);
+
+ coveredFiles.push_back(sourceFile);
+ coveredFilesFullPath.push_back(file);
+
+ number_files++;
+ total_functions += totalFunctions;
+ total_tested += functionsCalled;
+ total_untested += (totalFunctions - functionsCalled);
+
+ std::string fileName = cmSystemTools::GetFilenameName(file);
+ std::string shortFileName =
+ this->CTest->GetShortPathToFile(file.c_str());
+
+ float cper = static_cast<float>(percentBranch + percentFunction);
+ if (totalBranches > 0) {
+ cper /= 2.0f;
+ }
+ percent_coverage += static_cast<double>(cper);
+ float cmet = static_cast<float>(percentFunction + percentBranch);
+ if (totalBranches > 0) {
+ cmet /= 2.0f;
+ }
+ cmet /= 100.0f;
+ tmpLog << stdline << "\n";
+ tmpLog << fileName << "\n";
+ tmpLog << "functionsCalled: " << functionsCalled / 100 << "\n";
+ tmpLog << "totalFunctions: " << totalFunctions / 100 << "\n";
+ tmpLog << "percentFunction: " << percentFunction << "\n";
+ tmpLog << "branchCovered: " << branchCovered << "\n";
+ tmpLog << "totalBranches: " << totalBranches << "\n";
+ tmpLog << "percentBranch: " << percentBranch << "\n";
+ tmpLog << "percentCoverage: " << percent_coverage << "\n";
+ tmpLog << "coverage metric: " << cmet << "\n";
+ xml.StartElement("File");
+ xml.Attribute("Name", sourceFile);
+ xml.Attribute("FullPath", shortFileName);
+ xml.Attribute("Covered", cmet > 0 ? "true" : "false");
+ xml.Element("BranchesTested", branchCovered);
+ xml.Element("BranchesUnTested", totalBranches - branchCovered);
+ xml.Element("FunctionsTested", functionsCalled);
+ xml.Element("FunctionsUnTested", totalFunctions - functionsCalled);
+ // Hack for conversion of function to loc assume a function
+ // has 100 lines of code
+ xml.Element("LOCTested", functionsCalled * 100);
+ xml.Element("LOCUnTested", (totalFunctions - functionsCalled) * 100);
+ xml.Element("PercentCoverage", cper);
+ xml.Element("CoverageMetric", cmet);
+ this->WriteXMLLabels(xml, shortFileName);
+ xml.EndElement(); // File
+ }
+ }
+ std::string end_time = this->CTest->CurrentTime();
+ xml.Element("LOCTested", total_tested);
+ xml.Element("LOCUntested", total_untested);
+ xml.Element("LOC", total_functions);
+ xml.Element("PercentCoverage", SAFEDIV(percent_coverage, number_files));
+ xml.Element("EndDateTime", end_time);
+ xml.Element("EndTime", static_cast<unsigned int>(cmSystemTools::GetTime()));
+ xml.Element(
+ "ElapsedMinutes",
+ static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start) / 6) /
+ 10.0);
+ xml.EndElement(); // Coverage
+ this->CTest->EndXML(xml);
+
+ // Now create the coverage information for each file
+ return this->RunBullseyeCoverageBranch(cont, coveredFileNames, coveredFiles,
+ coveredFilesFullPath);
+}
+
+int cmCTestCoverageHandler::HandleBullseyeCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ const char* covfile = cmSystemTools::GetEnv("COVFILE");
+ if (!covfile || strlen(covfile) == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " COVFILE environment variable not found, not running "
+ " bullseye\n",
+ this->Quiet);
+ return 0;
+ }
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " run covsrc with COVFILE=[" << covfile << "]" << std::endl, this->Quiet);
+ if (!this->RunBullseyeSourceSummary(cont)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error running bullseye summary.\n");
+ return 0;
+ }
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "HandleBullseyeCoverage return 1 " << std::endl,
+ this->Quiet);
+ return 1;
+}
+
+bool cmCTestCoverageHandler::GetNextInt(std::string const& inputLine,
+ std::string::size_type& pos,
+ int& value)
+{
+ std::string::size_type start = pos;
+ pos = inputLine.find(',', start);
+ value = atoi(inputLine.substr(start, pos).c_str());
+ if (pos == inputLine.npos) {
+ return true;
+ }
+ pos++;
+ return true;
+}
+
+bool cmCTestCoverageHandler::ParseBullsEyeCovsrcLine(
+ std::string const& inputLine, std::string& sourceFile, int& functionsCalled,
+ int& totalFunctions, int& percentFunction, int& branchCovered,
+ int& totalBranches, int& percentBranch)
+{
+ // find the first comma
+ std::string::size_type pos = inputLine.find(',');
+ if (pos == inputLine.npos) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error parsing string : " << inputLine << "\n");
+ return false;
+ }
+ // the source file has "" around it so extract out the file name
+ sourceFile = inputLine.substr(1, pos - 2);
+ pos++;
+ if (!this->GetNextInt(inputLine, pos, functionsCalled)) {
+ return false;
+ }
+ if (!this->GetNextInt(inputLine, pos, totalFunctions)) {
+ return false;
+ }
+ if (!this->GetNextInt(inputLine, pos, percentFunction)) {
+ return false;
+ }
+ if (!this->GetNextInt(inputLine, pos, branchCovered)) {
+ return false;
+ }
+ if (!this->GetNextInt(inputLine, pos, totalBranches)) {
+ return false;
+ }
+ if (!this->GetNextInt(inputLine, pos, percentBranch)) {
+ return false;
+ }
+ // should be at the end now
+ if (pos != inputLine.npos) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Error parsing input : "
+ << inputLine << " last pos not npos = " << pos << "\n");
+ }
+ return true;
+}
+
+int cmCTestCoverageHandler::GetLabelId(std::string const& label)
+{
+ LabelIdMapType::iterator i = this->LabelIdMap.find(label);
+ if (i == this->LabelIdMap.end()) {
+ int n = int(this->Labels.size());
+ this->Labels.push_back(label);
+ LabelIdMapType::value_type entry(label, n);
+ i = this->LabelIdMap.insert(entry).first;
+ }
+ return i->second;
+}
+
+void cmCTestCoverageHandler::LoadLabels()
+{
+ std::string fileList = this->CTest->GetBinaryDir();
+ fileList += cmake::GetCMakeFilesDirectory();
+ fileList += "/TargetDirectories.txt";
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " target directory list [" << fileList << "]\n",
+ this->Quiet);
+ cmsys::ifstream finList(fileList.c_str());
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(finList, line)) {
+ this->LoadLabels(line.c_str());
+ }
+}
+
+void cmCTestCoverageHandler::LoadLabels(const char* dir)
+{
+ LabelSet& dirLabels = this->TargetDirs[dir];
+ std::string fname = dir;
+ fname += "/Labels.txt";
+ cmsys::ifstream fin(fname.c_str());
+ if (!fin) {
+ return;
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " loading labels from [" << fname << "]\n", this->Quiet);
+ bool inTarget = true;
+ std::string source;
+ std::string line;
+ std::vector<int> targetLabels;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (line.empty() || line[0] == '#') {
+ // Ignore blank and comment lines.
+ continue;
+ } else if (line[0] == ' ') {
+ // Label lines appear indented by one space.
+ std::string label = line.substr(1);
+ int id = this->GetLabelId(label);
+ dirLabels.insert(id);
+ if (inTarget) {
+ targetLabels.push_back(id);
+ } else {
+ this->SourceLabels[source].insert(id);
+ }
+ } else {
+ // Non-indented lines specify a source file name. The first one
+ // is the end of the target-wide labels.
+ inTarget = false;
+
+ source = this->CTest->GetShortPathToFile(line.c_str());
+
+ // Label the source with the target labels.
+ LabelSet& labelSet = this->SourceLabels[source];
+ labelSet.insert(targetLabels.begin(), targetLabels.end());
+ }
+ }
+}
+
+void cmCTestCoverageHandler::WriteXMLLabels(cmXMLWriter& xml,
+ std::string const& source)
+{
+ LabelMapType::const_iterator li = this->SourceLabels.find(source);
+ if (li != this->SourceLabels.end() && !li->second.empty()) {
+ xml.StartElement("Labels");
+ for (LabelSet::const_iterator lsi = li->second.begin();
+ lsi != li->second.end(); ++lsi) {
+ xml.Element("Label", this->Labels[*lsi]);
+ }
+ xml.EndElement(); // Labels
+ }
+}
+
+void cmCTestCoverageHandler::SetLabelFilter(
+ std::set<std::string> const& labels)
+{
+ this->LabelFilter.clear();
+ for (std::set<std::string>::const_iterator li = labels.begin();
+ li != labels.end(); ++li) {
+ this->LabelFilter.insert(this->GetLabelId(*li));
+ }
+}
+
+bool cmCTestCoverageHandler::IntersectsFilter(LabelSet const& labels)
+{
+ // If there is no label filter then nothing is filtered out.
+ if (this->LabelFilter.empty()) {
+ return true;
+ }
+
+ std::vector<int> ids;
+ std::set_intersection(labels.begin(), labels.end(),
+ this->LabelFilter.begin(), this->LabelFilter.end(),
+ std::back_inserter(ids));
+ return !ids.empty();
+}
+
+bool cmCTestCoverageHandler::IsFilteredOut(std::string const& source)
+{
+ // If there is no label filter then nothing is filtered out.
+ if (this->LabelFilter.empty()) {
+ return false;
+ }
+
+ // The source is filtered out if it does not have any labels in
+ // common with the filter set.
+ std::string shortSrc = this->CTest->GetShortPathToFile(source.c_str());
+ LabelMapType::const_iterator li = this->SourceLabels.find(shortSrc);
+ if (li != this->SourceLabels.end()) {
+ return !this->IntersectsFilter(li->second);
+ }
+ return true;
+}
+
+std::set<std::string> cmCTestCoverageHandler::FindUncoveredFiles(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ std::set<std::string> extraMatches;
+
+ for (std::vector<std::string>::iterator i = this->ExtraCoverageGlobs.begin();
+ i != this->ExtraCoverageGlobs.end(); ++i) {
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOff();
+ std::string glob = cont->SourceDir + "/" + *i;
+ gl.FindFiles(glob);
+ std::vector<std::string> files = gl.GetFiles();
+ for (std::vector<std::string>::iterator f = files.begin();
+ f != files.end(); ++f) {
+ if (this->ShouldIDoCoverage(f->c_str(), cont->SourceDir.c_str(),
+ cont->BinaryDir.c_str())) {
+ extraMatches.insert(this->CTest->GetShortPathToFile(f->c_str()));
+ }
+ }
+ }
+
+ if (!extraMatches.empty()) {
+ for (cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator i =
+ cont->TotalCoverage.begin();
+ i != cont->TotalCoverage.end(); ++i) {
+ std::string shortPath =
+ this->CTest->GetShortPathToFile(i->first.c_str());
+ extraMatches.erase(shortPath);
+ }
+ }
+ return extraMatches;
+}
diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h
new file mode 100644
index 0000000..60fea48
--- /dev/null
+++ b/Source/CTest/cmCTestCoverageHandler.h
@@ -0,0 +1,155 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCTestCoverageHandler_h
+#define cmCTestCoverageHandler_h
+
+#include "cmCTestGenericHandler.h"
+
+#include "cmListFileCache.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+class cmGeneratedFileStream;
+class cmXMLWriter;
+class cmCTestCoverageHandlerContainer
+{
+public:
+ int Error;
+ std::string SourceDir;
+ std::string BinaryDir;
+ typedef std::vector<int> SingleFileCoverageVector;
+ typedef std::map<std::string, SingleFileCoverageVector> TotalCoverageMap;
+ TotalCoverageMap TotalCoverage;
+ std::ostream* OFS;
+ bool Quiet;
+};
+/** \class cmCTestCoverageHandler
+ * \brief A class that handles coverage computation for ctest
+ *
+ */
+class cmCTestCoverageHandler : public cmCTestGenericHandler
+{
+public:
+ cmTypeMacro(cmCTestCoverageHandler, cmCTestGenericHandler);
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() CM_OVERRIDE;
+
+ cmCTestCoverageHandler();
+
+ void Initialize() CM_OVERRIDE;
+
+ /**
+ * This method is called when reading CTest custom file
+ */
+ void PopulateCustomVectors(cmMakefile* mf) CM_OVERRIDE;
+
+ /** Report coverage only for sources with these labels. */
+ void SetLabelFilter(std::set<std::string> const& labels);
+
+private:
+ bool ShouldIDoCoverage(const char* file, const char* srcDir,
+ const char* binDir);
+ void CleanCoverageLogFiles(std::ostream& log);
+ bool StartCoverageLogFile(cmGeneratedFileStream& ostr, int logFileCount);
+ void EndCoverageLogFile(cmGeneratedFileStream& ostr, int logFileCount);
+
+ void StartCoverageLogXML(cmXMLWriter& xml);
+ void EndCoverageLogXML(cmXMLWriter& xml);
+
+ //! Handle coverage using GCC's GCov
+ int HandleGCovCoverage(cmCTestCoverageHandlerContainer* cont);
+ void FindGCovFiles(std::vector<std::string>& files);
+
+ //! Handle coverage using Intel's LCov
+ int HandleLCovCoverage(cmCTestCoverageHandlerContainer* cont);
+ bool FindLCovFiles(std::vector<std::string>& files);
+
+ //! Handle coverage using xdebug php coverage
+ int HandlePHPCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for Python with coverage.py
+ int HandleCoberturaCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for mumps
+ int HandleMumpsCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for Jacoco
+ int HandleJacocoCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for Delphi (Pascal)
+ int HandleDelphiCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for Jacoco
+ int HandleBlanketJSCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage using Bullseye
+ int HandleBullseyeCoverage(cmCTestCoverageHandlerContainer* cont);
+ int RunBullseyeSourceSummary(cmCTestCoverageHandlerContainer* cont);
+ int RunBullseyeCoverageBranch(cmCTestCoverageHandlerContainer* cont,
+ std::set<std::string>& coveredFileNames,
+ std::vector<std::string>& files,
+ std::vector<std::string>& filesFullPath);
+
+ int RunBullseyeCommand(cmCTestCoverageHandlerContainer* cont,
+ const char* cmd, const char* arg,
+ std::string& outputFile);
+ bool ParseBullsEyeCovsrcLine(std::string const& inputLine,
+ std::string& sourceFile, int& functionsCalled,
+ int& totalFunctions, int& percentFunction,
+ int& branchCovered, int& totalBranches,
+ int& percentBranch);
+ bool GetNextInt(std::string const& inputLine, std::string::size_type& pos,
+ int& value);
+ //! Handle Python coverage using Python's Trace.py
+ int HandleTracePyCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ // Find the source file based on the source and build tree. This is used for
+ // Trace.py mode, since that one does not tell us where the source file is.
+ std::string FindFile(cmCTestCoverageHandlerContainer* cont,
+ std::string const& fileName);
+
+ std::set<std::string> FindUncoveredFiles(
+ cmCTestCoverageHandlerContainer* cont);
+ std::vector<std::string> CustomCoverageExclude;
+ std::vector<cmsys::RegularExpression> CustomCoverageExcludeRegex;
+ std::vector<std::string> ExtraCoverageGlobs;
+
+ // Map from source file to label ids.
+ class LabelSet : public std::set<int>
+ {
+ };
+ typedef std::map<std::string, LabelSet> LabelMapType;
+ LabelMapType SourceLabels;
+ LabelMapType TargetDirs;
+
+ // Map from label name to label id.
+ typedef std::map<std::string, int> LabelIdMapType;
+ LabelIdMapType LabelIdMap;
+ std::vector<std::string> Labels;
+ int GetLabelId(std::string const& label);
+
+ // Label reading and writing methods.
+ void LoadLabels();
+ void LoadLabels(const char* dir);
+ void WriteXMLLabels(cmXMLWriter& xml, std::string const& source);
+
+ // Label-based filtering.
+ std::set<int> LabelFilter;
+ bool IntersectsFilter(LabelSet const& labels);
+ bool IsFilteredOut(std::string const& source);
+};
+
+#endif
diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx
new file mode 100644
index 0000000..6b8e5b5
--- /dev/null
+++ b/Source/CTest/cmCTestCurl.cxx
@@ -0,0 +1,249 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestCurl.h"
+
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+
+cmCTestCurl::cmCTestCurl(cmCTest* ctest)
+{
+ this->CTest = ctest;
+ this->SetProxyType();
+ this->UseHttp10 = false;
+ // In windows, this will init the winsock stuff
+ ::curl_global_init(CURL_GLOBAL_ALL);
+ // default is to verify https
+ this->VerifyPeerOff = false;
+ this->VerifyHostOff = false;
+ this->TimeOutSeconds = 0;
+ this->Curl = curl_easy_init();
+}
+
+cmCTestCurl::~cmCTestCurl()
+{
+ ::curl_easy_cleanup(this->Curl);
+ ::curl_global_cleanup();
+}
+
+std::string cmCTestCurl::Escape(std::string const& source)
+{
+ char* data1 = curl_easy_escape(this->Curl, source.c_str(), 0);
+ std::string ret = data1;
+ curl_free(data1);
+ return ret;
+}
+
+namespace {
+static size_t curlWriteMemoryCallback(void* ptr, size_t size, size_t nmemb,
+ void* data)
+{
+ int realsize = (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);
+ return realsize;
+}
+
+static size_t curlDebugCallback(CURL*, curl_infotype, char* chPtr, size_t size,
+ void* data)
+{
+ std::vector<char>* vec = static_cast<std::vector<char>*>(data);
+ vec->insert(vec->end(), chPtr, chPtr + size);
+
+ return size;
+}
+}
+
+void cmCTestCurl::SetCurlOptions(std::vector<std::string> const& args)
+{
+ for (std::vector<std::string>::const_iterator i = args.begin();
+ i != args.end(); ++i) {
+ if (*i == "CURLOPT_SSL_VERIFYPEER_OFF") {
+ this->VerifyPeerOff = true;
+ }
+ if (*i == "CURLOPT_SSL_VERIFYHOST_OFF") {
+ this->VerifyHostOff = true;
+ }
+ }
+}
+
+bool cmCTestCurl::InitCurl()
+{
+ if (!this->Curl) {
+ return false;
+ }
+ if (this->VerifyPeerOff) {
+ curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYPEER, 0);
+ }
+ if (this->VerifyHostOff) {
+ curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYHOST, 0);
+ }
+ if (!this->HTTPProxy.empty()) {
+ curl_easy_setopt(this->Curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
+ curl_easy_setopt(this->Curl, CURLOPT_PROXYTYPE, this->HTTPProxyType);
+ if (!this->HTTPProxyAuth.empty()) {
+ curl_easy_setopt(this->Curl, CURLOPT_PROXYUSERPWD,
+ this->HTTPProxyAuth.c_str());
+ }
+ }
+ if (this->UseHttp10) {
+ curl_easy_setopt(this->Curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ }
+ // enable HTTP ERROR parsing
+ curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+ return true;
+}
+
+bool cmCTestCurl::UploadFile(std::string const& local_file,
+ std::string const& url, std::string const& fields,
+ std::string& response)
+{
+ response = "";
+ if (!this->InitCurl()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
+ return false;
+ }
+ /* enable uploading */
+ curl_easy_setopt(this->Curl, CURLOPT_UPLOAD, 1);
+ // if there is little to no activity for too long stop submitting
+ if (this->TimeOutSeconds) {
+ ::curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_LIMIT, 1);
+ ::curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_TIME,
+ this->TimeOutSeconds);
+ }
+ /* HTTP PUT please */
+ ::curl_easy_setopt(this->Curl, CURLOPT_PUT, 1);
+ ::curl_easy_setopt(this->Curl, CURLOPT_VERBOSE, 1);
+
+ FILE* ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
+ if (!ftpfile) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Could not open file for upload: " << local_file << "\n");
+ return false;
+ }
+ // set the url
+ std::string upload_url = url;
+ upload_url += "?";
+ upload_url += fields;
+ ::curl_easy_setopt(this->Curl, CURLOPT_URL, upload_url.c_str());
+ // now specify which file to upload
+ ::curl_easy_setopt(this->Curl, CURLOPT_INFILE, ftpfile);
+ unsigned long filelen = cmSystemTools::FileLength(local_file);
+ // and give the size of the upload (optional)
+ ::curl_easy_setopt(this->Curl, CURLOPT_INFILESIZE,
+ static_cast<long>(filelen));
+ ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
+ curlWriteMemoryCallback);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION, curlDebugCallback);
+ // Be sure to set Content-Type to satisfy fussy modsecurity rules
+ struct curl_slist* headers =
+ ::curl_slist_append(CM_NULLPTR, "Content-Type: text/xml");
+ ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, headers);
+ std::vector<char> responseData;
+ std::vector<char> debugData;
+ ::curl_easy_setopt(this->Curl, CURLOPT_FILE, (void*)&responseData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, (void*)&debugData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+ // Now run off and do what you've been told!
+ ::curl_easy_perform(this->Curl);
+ ::fclose(ftpfile);
+ ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, NULL);
+ ::curl_slist_free_all(headers);
+
+ if (!responseData.empty()) {
+ response = std::string(responseData.begin(), responseData.end());
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Curl response: ["
+ << response << "]\n");
+ }
+ std::string curlDebug;
+ if (!debugData.empty()) {
+ curlDebug = std::string(debugData.begin(), debugData.end());
+ cmCTestLog(this->CTest, DEBUG, "Curl debug: [" << curlDebug << "]\n");
+ }
+ if (response.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "No response from server.\n"
+ << curlDebug);
+ return false;
+ }
+ return true;
+}
+
+bool cmCTestCurl::HttpRequest(std::string const& url,
+ std::string const& fields, std::string& response)
+{
+ response = "";
+ cmCTestLog(this->CTest, DEBUG, "HttpRequest\n"
+ << "url: " << url << "\n"
+ << "fields " << fields << "\n");
+ if (!this->InitCurl()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
+ return false;
+ }
+ curl_easy_setopt(this->Curl, CURLOPT_POST, 1);
+ curl_easy_setopt(this->Curl, CURLOPT_POSTFIELDS, fields.c_str());
+ ::curl_easy_setopt(this->Curl, CURLOPT_URL, url.c_str());
+ ::curl_easy_setopt(this->Curl, CURLOPT_FOLLOWLOCATION, 1);
+ // set response options
+ ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
+ curlWriteMemoryCallback);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION, curlDebugCallback);
+ std::vector<char> responseData;
+ std::vector<char> debugData;
+ ::curl_easy_setopt(this->Curl, CURLOPT_FILE, (void*)&responseData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, (void*)&debugData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+
+ CURLcode res = ::curl_easy_perform(this->Curl);
+
+ if (!responseData.empty()) {
+ response = std::string(responseData.begin(), responseData.end());
+ cmCTestLog(this->CTest, DEBUG, "Curl response: [" << response << "]\n");
+ }
+ if (!debugData.empty()) {
+ std::string curlDebug = std::string(debugData.begin(), debugData.end());
+ cmCTestLog(this->CTest, DEBUG, "Curl debug: [" << curlDebug << "]\n");
+ }
+ cmCTestLog(this->CTest, DEBUG, "Curl res: " << res << "\n");
+ return (res == 0);
+}
+
+void cmCTestCurl::SetProxyType()
+{
+ if (cmSystemTools::GetEnv("HTTP_PROXY")) {
+ this->HTTPProxy = cmSystemTools::GetEnv("HTTP_PROXY");
+ if (cmSystemTools::GetEnv("HTTP_PROXY_PORT")) {
+ this->HTTPProxy += ":";
+ this->HTTPProxy += cmSystemTools::GetEnv("HTTP_PROXY_PORT");
+ }
+ if (cmSystemTools::GetEnv("HTTP_PROXY_TYPE")) {
+ // this is the default
+ this->HTTPProxyType = CURLPROXY_HTTP;
+ std::string type = cmSystemTools::GetEnv("HTTP_PROXY_TYPE");
+ // HTTP/SOCKS4/SOCKS5
+ if (type == "HTTP") {
+ this->HTTPProxyType = CURLPROXY_HTTP;
+ } else if (type == "SOCKS4") {
+ this->HTTPProxyType = CURLPROXY_SOCKS4;
+ } else if (type == "SOCKS5") {
+ this->HTTPProxyType = CURLPROXY_SOCKS5;
+ }
+ }
+ if (cmSystemTools::GetEnv("HTTP_PROXY_USER")) {
+ this->HTTPProxyAuth = cmSystemTools::GetEnv("HTTP_PROXY_USER");
+ }
+ if (cmSystemTools::GetEnv("HTTP_PROXY_PASSWD")) {
+ this->HTTPProxyAuth += ":";
+ this->HTTPProxyAuth += cmSystemTools::GetEnv("HTTP_PROXY_PASSWD");
+ }
+ }
+}
diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h
new file mode 100644
index 0000000..82601e3
--- /dev/null
+++ b/Source/CTest/cmCTestCurl.h
@@ -0,0 +1,53 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestCurl_h
+#define cmCTestCurl_h
+
+#include "cmStandardIncludes.h"
+
+#include "cm_curl.h"
+
+class cmCTest;
+
+class cmCTestCurl
+{
+public:
+ cmCTestCurl(cmCTest*);
+ ~cmCTestCurl();
+ bool UploadFile(std::string const& url, std::string const& file,
+ std::string const& fields, std::string& response);
+ bool HttpRequest(std::string const& url, std::string const& fields,
+ std::string& response);
+ // currently only supports CURLOPT_SSL_VERIFYPEER_OFF
+ // and CURLOPT_SSL_VERIFYHOST_OFF
+ void SetCurlOptions(std::vector<std::string> const& args);
+ void SetUseHttp10On() { this->UseHttp10 = true; }
+ void SetTimeOutSeconds(int s) { this->TimeOutSeconds = s; }
+ std::string Escape(std::string const& source);
+
+protected:
+ void SetProxyType();
+ bool InitCurl();
+
+private:
+ cmCTest* CTest;
+ CURL* Curl;
+ std::string HTTPProxyAuth;
+ std::string HTTPProxy;
+ curl_proxytype HTTPProxyType;
+ bool VerifyHostOff;
+ bool VerifyPeerOff;
+ bool UseHttp10;
+ int TimeOutSeconds;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
new file mode 100644
index 0000000..1bda9be
--- /dev/null
+++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
@@ -0,0 +1,32 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestEmptyBinaryDirectoryCommand.h"
+
+#include "cmCTestScriptHandler.h"
+
+bool cmCTestEmptyBinaryDirectoryCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() != 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ if (!cmCTestScriptHandler::EmptyBinaryDirectory(args[0].c_str())) {
+ std::ostringstream ostr;
+ ostr << "problem removing the binary directory: " << args[0];
+ this->SetError(ostr.str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h
new file mode 100644
index 0000000..acacbcb
--- /dev/null
+++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h
@@ -0,0 +1,58 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestEmptyBinaryDirectoryCommand_h
+#define cmCTestEmptyBinaryDirectoryCommand_h
+
+#include "cmCTestCommand.h"
+
+/** \class cmCTestEmptyBinaryDirectory
+ * \brief Run a ctest script
+ *
+ * cmLibrarysCommand defines a list of executable (i.e., test)
+ * programs to create.
+ */
+class cmCTestEmptyBinaryDirectoryCommand : public cmCTestCommand
+{
+public:
+ cmCTestEmptyBinaryDirectoryCommand() {}
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestEmptyBinaryDirectoryCommand* ni =
+ new cmCTestEmptyBinaryDirectoryCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return ni;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE
+ {
+ return "ctest_empty_binary_directory";
+ }
+
+ cmTypeMacro(cmCTestEmptyBinaryDirectoryCommand, cmCTestCommand);
+};
+
+#endif
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
new file mode 100644
index 0000000..61dbe33
--- /dev/null
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -0,0 +1,664 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestGIT.h"
+
+#include "cmAlgorithms.h"
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+
+#include <cmsys/FStream.hxx>
+#include <cmsys/Process.h>
+#include <cmsys/RegularExpression.hxx>
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <time.h>
+
+static unsigned int cmCTestGITVersion(unsigned int epic, unsigned int major,
+ unsigned int minor, unsigned int fix)
+{
+ // 1.6.5.0 maps to 10605000
+ return fix + minor * 1000 + major * 100000 + epic * 10000000;
+}
+
+cmCTestGIT::cmCTestGIT(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
+{
+ this->PriorRev = this->Unknown;
+ this->CurrentGitVersion = 0;
+}
+
+cmCTestGIT::~cmCTestGIT()
+{
+}
+
+class cmCTestGIT::OneLineParser : public cmCTestVC::LineParser
+{
+public:
+ OneLineParser(cmCTestGIT* git, const char* prefix, std::string& l)
+ : Line1(l)
+ {
+ this->SetLog(&git->Log, prefix);
+ }
+
+private:
+ std::string& Line1;
+ bool ProcessLine() CM_OVERRIDE
+ {
+ // Only the first line is of interest.
+ this->Line1 = this->Line;
+ return false;
+ }
+};
+
+std::string cmCTestGIT::GetWorkingRevision()
+{
+ // Run plumbing "git rev-list" to get work tree revision.
+ const char* git = this->CommandLineTool.c_str();
+ const char* git_rev_list[] = { git, "rev-list", "-n", "1",
+ "HEAD", "--", CM_NULLPTR };
+ std::string rev;
+ OneLineParser out(this, "rl-out> ", rev);
+ OutputLogger err(this->Log, "rl-err> ");
+ this->RunChild(git_rev_list, &out, &err);
+ return rev;
+}
+
+void cmCTestGIT::NoteOldRevision()
+{
+ this->OldRevision = this->GetWorkingRevision();
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Old revision of repository is: "
+ << this->OldRevision << "\n");
+ this->PriorRev.Rev = this->OldRevision;
+}
+
+void cmCTestGIT::NoteNewRevision()
+{
+ this->NewRevision = this->GetWorkingRevision();
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " New revision of repository is: "
+ << this->NewRevision << "\n");
+}
+
+std::string cmCTestGIT::FindGitDir()
+{
+ std::string git_dir;
+
+ // Run "git rev-parse --git-dir" to locate the real .git directory.
+ const char* git = this->CommandLineTool.c_str();
+ char const* git_rev_parse[] = { git, "rev-parse", "--git-dir", CM_NULLPTR };
+ std::string git_dir_line;
+ OneLineParser rev_parse_out(this, "rev-parse-out> ", git_dir_line);
+ OutputLogger rev_parse_err(this->Log, "rev-parse-err> ");
+ if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err)) {
+ git_dir = git_dir_line;
+ }
+ if (git_dir.empty()) {
+ git_dir = ".git";
+ }
+
+ // Git reports a relative path only when the .git directory is in
+ // the current directory.
+ if (git_dir[0] == '.') {
+ git_dir = this->SourceDirectory + "/" + git_dir;
+ }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ else if (git_dir[0] == '/') {
+ // Cygwin Git reports a full path that Cygwin understands, but we
+ // are a Windows application. Run "cygpath" to get Windows path.
+ std::string cygpath_exe = cmSystemTools::GetFilenamePath(git);
+ cygpath_exe += "/cygpath.exe";
+ if (cmSystemTools::FileExists(cygpath_exe.c_str())) {
+ char const* cygpath[] = { cygpath_exe.c_str(), "-w", git_dir.c_str(),
+ 0 };
+ OneLineParser cygpath_out(this, "cygpath-out> ", git_dir_line);
+ OutputLogger cygpath_err(this->Log, "cygpath-err> ");
+ if (this->RunChild(cygpath, &cygpath_out, &cygpath_err)) {
+ git_dir = git_dir_line;
+ }
+ }
+ }
+#endif
+ return git_dir;
+}
+
+std::string cmCTestGIT::FindTopDir()
+{
+ std::string top_dir = this->SourceDirectory;
+
+ // Run "git rev-parse --show-cdup" to locate the top of the tree.
+ const char* git = this->CommandLineTool.c_str();
+ char const* git_rev_parse[] = { git, "rev-parse", "--show-cdup",
+ CM_NULLPTR };
+ std::string cdup;
+ OneLineParser rev_parse_out(this, "rev-parse-out> ", cdup);
+ OutputLogger rev_parse_err(this->Log, "rev-parse-err> ");
+ if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err) &&
+ !cdup.empty()) {
+ top_dir += "/";
+ top_dir += cdup;
+ top_dir = cmSystemTools::CollapseFullPath(top_dir);
+ }
+ return top_dir;
+}
+
+bool cmCTestGIT::UpdateByFetchAndReset()
+{
+ const char* git = this->CommandLineTool.c_str();
+
+ // Use "git fetch" to get remote commits.
+ std::vector<char const*> git_fetch;
+ git_fetch.push_back(git);
+ git_fetch.push_back("fetch");
+
+ // Add user-specified update options.
+ std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
+ if (opts.empty()) {
+ opts = this->CTest->GetCTestConfiguration("GITUpdateOptions");
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ for (std::vector<std::string>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai) {
+ git_fetch.push_back(ai->c_str());
+ }
+
+ // Sentinel argument.
+ git_fetch.push_back(CM_NULLPTR);
+
+ // Fetch upstream refs.
+ OutputLogger fetch_out(this->Log, "fetch-out> ");
+ OutputLogger fetch_err(this->Log, "fetch-err> ");
+ if (!this->RunUpdateCommand(&git_fetch[0], &fetch_out, &fetch_err)) {
+ return false;
+ }
+
+ // Identify the merge head that would be used by "git pull".
+ std::string sha1;
+ {
+ std::string fetch_head = this->FindGitDir() + "/FETCH_HEAD";
+ cmsys::ifstream fin(fetch_head.c_str(), std::ios::in | std::ios::binary);
+ if (!fin) {
+ this->Log << "Unable to open " << fetch_head << "\n";
+ return false;
+ }
+ std::string line;
+ while (sha1.empty() && cmSystemTools::GetLineFromStream(fin, line)) {
+ this->Log << "FETCH_HEAD> " << line << "\n";
+ if (line.find("\tnot-for-merge\t") == line.npos) {
+ std::string::size_type pos = line.find('\t');
+ if (pos != line.npos) {
+ sha1 = line.substr(0, pos);
+ }
+ }
+ }
+ if (sha1.empty()) {
+ this->Log << "FETCH_HEAD has no upstream branch candidate!\n";
+ return false;
+ }
+ }
+
+ // Reset the local branch to point at that tracked from upstream.
+ char const* git_reset[] = { git, "reset", "--hard", sha1.c_str(),
+ CM_NULLPTR };
+ OutputLogger reset_out(this->Log, "reset-out> ");
+ OutputLogger reset_err(this->Log, "reset-err> ");
+ return this->RunChild(&git_reset[0], &reset_out, &reset_err);
+}
+
+bool cmCTestGIT::UpdateByCustom(std::string const& custom)
+{
+ std::vector<std::string> git_custom_command;
+ cmSystemTools::ExpandListArgument(custom, git_custom_command, true);
+ std::vector<char const*> git_custom;
+ for (std::vector<std::string>::const_iterator i = git_custom_command.begin();
+ i != git_custom_command.end(); ++i) {
+ git_custom.push_back(i->c_str());
+ }
+ git_custom.push_back(CM_NULLPTR);
+
+ OutputLogger custom_out(this->Log, "custom-out> ");
+ OutputLogger custom_err(this->Log, "custom-err> ");
+ return this->RunUpdateCommand(&git_custom[0], &custom_out, &custom_err);
+}
+
+bool cmCTestGIT::UpdateInternal()
+{
+ std::string custom = this->CTest->GetCTestConfiguration("GITUpdateCustom");
+ if (!custom.empty()) {
+ return this->UpdateByCustom(custom);
+ }
+ return this->UpdateByFetchAndReset();
+}
+
+bool cmCTestGIT::UpdateImpl()
+{
+ if (!this->UpdateInternal()) {
+ return false;
+ }
+
+ std::string top_dir = this->FindTopDir();
+ const char* git = this->CommandLineTool.c_str();
+ const char* recursive = "--recursive";
+ const char* sync_recursive = "--recursive";
+
+ // Git < 1.6.5 did not support submodule --recursive
+ if (this->GetGitVersion() < cmCTestGITVersion(1, 6, 5, 0)) {
+ recursive = CM_NULLPTR;
+ // No need to require >= 1.6.5 if there are no submodules.
+ if (cmSystemTools::FileExists((top_dir + "/.gitmodules").c_str())) {
+ this->Log << "Git < 1.6.5 cannot update submodules recursively\n";
+ }
+ }
+
+ // Git < 1.8.1 did not support sync --recursive
+ if (this->GetGitVersion() < cmCTestGITVersion(1, 8, 1, 0)) {
+ sync_recursive = CM_NULLPTR;
+ // No need to require >= 1.8.1 if there are no submodules.
+ if (cmSystemTools::FileExists((top_dir + "/.gitmodules").c_str())) {
+ this->Log << "Git < 1.8.1 cannot synchronize submodules recursively\n";
+ }
+ }
+
+ OutputLogger submodule_out(this->Log, "submodule-out> ");
+ OutputLogger submodule_err(this->Log, "submodule-err> ");
+
+ bool ret;
+
+ std::string init_submodules =
+ this->CTest->GetCTestConfiguration("GITInitSubmodules");
+ if (cmSystemTools::IsOn(init_submodules.c_str())) {
+ char const* git_submodule_init[] = { git, "submodule", "init",
+ CM_NULLPTR };
+ ret = this->RunChild(git_submodule_init, &submodule_out, &submodule_err,
+ top_dir.c_str());
+
+ if (!ret) {
+ return false;
+ }
+ }
+
+ char const* git_submodule_sync[] = { git, "submodule", "sync",
+ sync_recursive, CM_NULLPTR };
+ ret = this->RunChild(git_submodule_sync, &submodule_out, &submodule_err,
+ top_dir.c_str());
+
+ if (!ret) {
+ return false;
+ }
+
+ char const* git_submodule[] = { git, "submodule", "update", recursive,
+ CM_NULLPTR };
+ return this->RunChild(git_submodule, &submodule_out, &submodule_err,
+ top_dir.c_str());
+}
+
+unsigned int cmCTestGIT::GetGitVersion()
+{
+ if (!this->CurrentGitVersion) {
+ const char* git = this->CommandLineTool.c_str();
+ char const* git_version[] = { git, "--version", CM_NULLPTR };
+ std::string version;
+ OneLineParser version_out(this, "version-out> ", version);
+ OutputLogger version_err(this->Log, "version-err> ");
+ unsigned int v[4] = { 0, 0, 0, 0 };
+ if (this->RunChild(git_version, &version_out, &version_err) &&
+ sscanf(version.c_str(), "git version %u.%u.%u.%u", &v[0], &v[1], &v[2],
+ &v[3]) >= 3) {
+ this->CurrentGitVersion = cmCTestGITVersion(v[0], v[1], v[2], v[3]);
+ }
+ }
+ return this->CurrentGitVersion;
+}
+
+/* Diff format:
+
+ :src-mode dst-mode src-sha1 dst-sha1 status\0
+ src-path\0
+ [dst-path\0]
+
+ The format is repeated for every file changed. The [dst-path\0]
+ line appears only for lines with status 'C' or 'R'. See 'git help
+ diff-tree' for details.
+*/
+class cmCTestGIT::DiffParser : public cmCTestVC::LineParser
+{
+public:
+ DiffParser(cmCTestGIT* git, const char* prefix)
+ : LineParser('\0', false)
+ , GIT(git)
+ , DiffField(DiffFieldNone)
+ {
+ this->SetLog(&git->Log, prefix);
+ }
+
+ typedef cmCTestGIT::Change Change;
+ std::vector<Change> Changes;
+
+protected:
+ cmCTestGIT* GIT;
+ enum DiffFieldType
+ {
+ DiffFieldNone,
+ DiffFieldChange,
+ DiffFieldSrc,
+ DiffFieldDst
+ };
+ DiffFieldType DiffField;
+ Change CurChange;
+
+ void DiffReset()
+ {
+ this->DiffField = DiffFieldNone;
+ this->Changes.clear();
+ }
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->Line[0] == ':') {
+ this->DiffField = DiffFieldChange;
+ this->CurChange = Change();
+ }
+ if (this->DiffField == DiffFieldChange) {
+ // :src-mode dst-mode src-sha1 dst-sha1 status
+ if (this->Line[0] != ':') {
+ this->DiffField = DiffFieldNone;
+ return true;
+ }
+ const char* src_mode_first = this->Line.c_str() + 1;
+ const char* src_mode_last = this->ConsumeField(src_mode_first);
+ const char* dst_mode_first = this->ConsumeSpace(src_mode_last);
+ const char* dst_mode_last = this->ConsumeField(dst_mode_first);
+ const char* src_sha1_first = this->ConsumeSpace(dst_mode_last);
+ const char* src_sha1_last = this->ConsumeField(src_sha1_first);
+ const char* dst_sha1_first = this->ConsumeSpace(src_sha1_last);
+ const char* dst_sha1_last = this->ConsumeField(dst_sha1_first);
+ const char* status_first = this->ConsumeSpace(dst_sha1_last);
+ const char* status_last = this->ConsumeField(status_first);
+ if (status_first != status_last) {
+ this->CurChange.Action = *status_first;
+ this->DiffField = DiffFieldSrc;
+ } else {
+ this->DiffField = DiffFieldNone;
+ }
+ } else if (this->DiffField == DiffFieldSrc) {
+ // src-path
+ if (this->CurChange.Action == 'C') {
+ // Convert copy to addition of destination.
+ this->CurChange.Action = 'A';
+ this->DiffField = DiffFieldDst;
+ } else if (this->CurChange.Action == 'R') {
+ // Convert rename to deletion of source and addition of destination.
+ this->CurChange.Action = 'D';
+ this->CurChange.Path = this->Line;
+ this->Changes.push_back(this->CurChange);
+
+ this->CurChange = Change('A');
+ this->DiffField = DiffFieldDst;
+ } else {
+ this->CurChange.Path = this->Line;
+ this->Changes.push_back(this->CurChange);
+ this->DiffField = this->DiffFieldNone;
+ }
+ } else if (this->DiffField == DiffFieldDst) {
+ // dst-path
+ this->CurChange.Path = this->Line;
+ this->Changes.push_back(this->CurChange);
+ this->DiffField = this->DiffFieldNone;
+ }
+ return true;
+ }
+
+ const char* ConsumeSpace(const char* c)
+ {
+ while (*c && isspace(*c)) {
+ ++c;
+ }
+ return c;
+ }
+ const char* ConsumeField(const char* c)
+ {
+ while (*c && !isspace(*c)) {
+ ++c;
+ }
+ return c;
+ }
+};
+
+/* Commit format:
+
+ commit ...\n
+ tree ...\n
+ parent ...\n
+ author ...\n
+ committer ...\n
+ \n
+ Log message indented by (4) spaces\n
+ (even blank lines have the spaces)\n
+ [[
+ \n
+ [Diff format]
+ OR
+ \0
+ ]]
+
+ The header may have more fields. See 'git help diff-tree'.
+*/
+class cmCTestGIT::CommitParser : public cmCTestGIT::DiffParser
+{
+public:
+ CommitParser(cmCTestGIT* git, const char* prefix)
+ : DiffParser(git, prefix)
+ , Section(SectionHeader)
+ {
+ this->Separator = SectionSep[this->Section];
+ }
+
+private:
+ typedef cmCTestGIT::Revision Revision;
+ enum SectionType
+ {
+ SectionHeader,
+ SectionBody,
+ SectionDiff,
+ SectionCount
+ };
+ static char const SectionSep[SectionCount];
+ SectionType Section;
+ Revision Rev;
+
+ struct Person
+ {
+ std::string Name;
+ std::string EMail;
+ unsigned long Time;
+ long TimeZone;
+ Person()
+ : Name()
+ , EMail()
+ , Time(0)
+ , TimeZone(0)
+ {
+ }
+ };
+
+ void ParsePerson(const char* str, Person& person)
+ {
+ // Person Name <person@domain.com> 1234567890 +0000
+ const char* c = str;
+ while (*c && isspace(*c)) {
+ ++c;
+ }
+
+ const char* name_first = c;
+ while (*c && *c != '<') {
+ ++c;
+ }
+ const char* name_last = c;
+ while (name_last != name_first && isspace(*(name_last - 1))) {
+ --name_last;
+ }
+ person.Name.assign(name_first, name_last - name_first);
+
+ const char* email_first = *c ? ++c : c;
+ while (*c && *c != '>') {
+ ++c;
+ }
+ const char* email_last = *c ? c++ : c;
+ person.EMail.assign(email_first, email_last - email_first);
+
+ person.Time = strtoul(c, (char**)&c, 10);
+ person.TimeZone = strtol(c, (char**)&c, 10);
+ }
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->Line.empty()) {
+ if (this->Section == SectionBody && this->LineEnd == '\0') {
+ // Skip SectionDiff
+ this->NextSection();
+ }
+ this->NextSection();
+ } else {
+ switch (this->Section) {
+ case SectionHeader:
+ this->DoHeaderLine();
+ break;
+ case SectionBody:
+ this->DoBodyLine();
+ break;
+ case SectionDiff:
+ this->DiffParser::ProcessLine();
+ break;
+ case SectionCount:
+ break; // never happens
+ }
+ }
+ return true;
+ }
+
+ void NextSection()
+ {
+ this->Section = SectionType((this->Section + 1) % SectionCount);
+ this->Separator = SectionSep[this->Section];
+ if (this->Section == SectionHeader) {
+ this->GIT->DoRevision(this->Rev, this->Changes);
+ this->Rev = Revision();
+ this->DiffReset();
+ }
+ }
+
+ void DoHeaderLine()
+ {
+ // Look for header fields that we need.
+ if (cmHasLiteralPrefix(this->Line.c_str(), "commit ")) {
+ this->Rev.Rev = this->Line.c_str() + 7;
+ } else if (cmHasLiteralPrefix(this->Line.c_str(), "author ")) {
+ Person author;
+ this->ParsePerson(this->Line.c_str() + 7, author);
+ this->Rev.Author = author.Name;
+ this->Rev.EMail = author.EMail;
+ this->Rev.Date = this->FormatDateTime(author);
+ } else if (cmHasLiteralPrefix(this->Line.c_str(), "committer ")) {
+ Person committer;
+ this->ParsePerson(this->Line.c_str() + 10, committer);
+ this->Rev.Committer = committer.Name;
+ this->Rev.CommitterEMail = committer.EMail;
+ this->Rev.CommitDate = this->FormatDateTime(committer);
+ }
+ }
+
+ void DoBodyLine()
+ {
+ // Commit log lines are indented by 4 spaces.
+ if (this->Line.size() >= 4) {
+ this->Rev.Log += this->Line.substr(4);
+ }
+ this->Rev.Log += "\n";
+ }
+
+ std::string FormatDateTime(Person const& person)
+ {
+ // Convert the time to a human-readable format that is also easy
+ // to machine-parse: "CCYY-MM-DD hh:mm:ss".
+ time_t seconds = static_cast<time_t>(person.Time);
+ struct tm* t = gmtime(&seconds);
+ char dt[1024];
+ sprintf(dt, "%04d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900,
+ t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+ std::string out = dt;
+
+ // Add the time-zone field "+zone" or "-zone".
+ char tz[32];
+ if (person.TimeZone >= 0) {
+ sprintf(tz, " +%04ld", person.TimeZone);
+ } else {
+ sprintf(tz, " -%04ld", -person.TimeZone);
+ }
+ out += tz;
+ return out;
+ }
+};
+
+char const cmCTestGIT::CommitParser::SectionSep[SectionCount] = { '\n', '\n',
+ '\0' };
+
+void cmCTestGIT::LoadRevisions()
+{
+ // Use 'git rev-list ... | git diff-tree ...' to get revisions.
+ std::string range = this->OldRevision + ".." + this->NewRevision;
+ const char* git = this->CommandLineTool.c_str();
+ const char* git_rev_list[] = { git, "rev-list", "--reverse",
+ range.c_str(), "--", CM_NULLPTR };
+ const char* git_diff_tree[] = {
+ git, "diff-tree", "--stdin", "--always", "-z",
+ "-r", "--pretty=raw", "--encoding=utf-8", CM_NULLPTR
+ };
+ this->Log << this->ComputeCommandLine(git_rev_list) << " | "
+ << this->ComputeCommandLine(git_diff_tree) << "\n";
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_AddCommand(cp, git_rev_list);
+ cmsysProcess_AddCommand(cp, git_diff_tree);
+ cmsysProcess_SetWorkingDirectory(cp, this->SourceDirectory.c_str());
+
+ CommitParser out(this, "dt-out> ");
+ OutputLogger err(this->Log, "dt-err> ");
+ this->RunProcess(cp, &out, &err);
+
+ // Send one extra zero-byte to terminate the last record.
+ out.Process("", 1);
+
+ cmsysProcess_Delete(cp);
+}
+
+void cmCTestGIT::LoadModifications()
+{
+ const char* git = this->CommandLineTool.c_str();
+
+ // Use 'git update-index' to refresh the index w.r.t. the work tree.
+ const char* git_update_index[] = { git, "update-index", "--refresh",
+ CM_NULLPTR };
+ OutputLogger ui_out(this->Log, "ui-out> ");
+ OutputLogger ui_err(this->Log, "ui-err> ");
+ this->RunChild(git_update_index, &ui_out, &ui_err);
+
+ // Use 'git diff-index' to get modified files.
+ const char* git_diff_index[] = { git, "diff-index", "-z",
+ "HEAD", "--", CM_NULLPTR };
+ DiffParser out(this, "di-out> ");
+ OutputLogger err(this->Log, "di-err> ");
+ this->RunChild(git_diff_index, &out, &err);
+
+ for (std::vector<Change>::const_iterator ci = out.Changes.begin();
+ ci != out.Changes.end(); ++ci) {
+ this->DoModification(PathModified, ci->Path);
+ }
+}
diff --git a/Source/CTest/cmCTestGIT.h b/Source/CTest/cmCTestGIT.h
new file mode 100644
index 0000000..85298cb
--- /dev/null
+++ b/Source/CTest/cmCTestGIT.h
@@ -0,0 +1,58 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestGIT_h
+#define cmCTestGIT_h
+
+#include "cmCTestGlobalVC.h"
+
+/** \class cmCTestGIT
+ * \brief Interaction with git command-line tool
+ *
+ */
+class cmCTestGIT : public cmCTestGlobalVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestGIT(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestGIT() CM_OVERRIDE;
+
+private:
+ unsigned int CurrentGitVersion;
+ unsigned int GetGitVersion();
+ std::string GetWorkingRevision();
+ void NoteOldRevision() CM_OVERRIDE;
+ void NoteNewRevision() CM_OVERRIDE;
+ bool UpdateImpl() CM_OVERRIDE;
+
+ std::string FindGitDir();
+ std::string FindTopDir();
+
+ bool UpdateByFetchAndReset();
+ bool UpdateByCustom(std::string const& custom);
+ bool UpdateInternal();
+
+ void LoadRevisions() CM_OVERRIDE;
+ void LoadModifications() CM_OVERRIDE;
+
+ // "public" needed by older Sun compilers
+public:
+ // Parsing helper classes.
+ class OneLineParser;
+ class DiffParser;
+ class CommitParser;
+ friend class OneLineParser;
+ friend class DiffParser;
+ friend class CommitParser;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestGenericHandler.cxx b/Source/CTest/cmCTestGenericHandler.cxx
new file mode 100644
index 0000000..7755ee9
--- /dev/null
+++ b/Source/CTest/cmCTestGenericHandler.cxx
@@ -0,0 +1,145 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCTestGenericHandler.h"
+
+#include "cmSystemTools.h"
+
+#include "cmCTest.h"
+
+cmCTestGenericHandler::cmCTestGenericHandler()
+{
+ this->HandlerVerbose = cmSystemTools::OUTPUT_NONE;
+ this->CTest = CM_NULLPTR;
+ this->SubmitIndex = 0;
+ this->AppendXML = false;
+ this->Quiet = false;
+ this->TestLoad = 0;
+}
+
+cmCTestGenericHandler::~cmCTestGenericHandler()
+{
+}
+
+void cmCTestGenericHandler::SetOption(const std::string& op, const char* value)
+{
+ if (!value) {
+ cmCTestGenericHandler::t_StringToString::iterator remit =
+ this->Options.find(op);
+ if (remit != this->Options.end()) {
+ this->Options.erase(remit);
+ }
+ return;
+ }
+
+ this->Options[op] = value;
+}
+
+void cmCTestGenericHandler::SetPersistentOption(const std::string& op,
+ const char* value)
+{
+ this->SetOption(op, value);
+ if (!value) {
+ cmCTestGenericHandler::t_StringToString::iterator remit =
+ this->PersistentOptions.find(op);
+ if (remit != this->PersistentOptions.end()) {
+ this->PersistentOptions.erase(remit);
+ }
+ return;
+ }
+
+ this->PersistentOptions[op] = value;
+}
+
+void cmCTestGenericHandler::Initialize()
+{
+ this->AppendXML = false;
+ this->TestLoad = 0;
+ this->Options.clear();
+ t_StringToString::iterator it;
+ for (it = this->PersistentOptions.begin();
+ it != this->PersistentOptions.end(); ++it) {
+ this->Options[it->first] = it->second;
+ }
+}
+
+const char* cmCTestGenericHandler::GetOption(const std::string& op)
+{
+ cmCTestGenericHandler::t_StringToString::iterator remit =
+ this->Options.find(op);
+ if (remit == this->Options.end()) {
+ return CM_NULLPTR;
+ }
+ return remit->second.c_str();
+}
+
+bool cmCTestGenericHandler::StartResultingXML(cmCTest::Part part,
+ const char* name,
+ cmGeneratedFileStream& xofs)
+{
+ if (!name) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create resulting XML file without providing the name"
+ << std::endl;);
+ return false;
+ }
+ std::ostringstream ostr;
+ ostr << name;
+ if (this->SubmitIndex > 0) {
+ ostr << "_" << this->SubmitIndex;
+ }
+ ostr << ".xml";
+ if (this->CTest->GetCurrentTag().empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Current Tag empty, this may mean NightlyStartTime / "
+ "CTEST_NIGHTLY_START_TIME was not set correctly. Or "
+ "maybe you forgot to call ctest_start() before calling "
+ "ctest_configure()."
+ << std::endl);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ if (!this->CTest->OpenOutputFile(this->CTest->GetCurrentTag(), ostr.str(),
+ xofs, true)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create resulting XML file: "
+ << ostr.str() << std::endl);
+ return false;
+ }
+ this->CTest->AddSubmitFile(part, ostr.str().c_str());
+ return true;
+}
+
+bool cmCTestGenericHandler::StartLogFile(const char* name,
+ cmGeneratedFileStream& xofs)
+{
+ if (!name) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create log file without providing the name"
+ << std::endl;);
+ return false;
+ }
+ std::ostringstream ostr;
+ ostr << "Last" << name;
+ if (this->SubmitIndex > 0) {
+ ostr << "_" << this->SubmitIndex;
+ }
+ if (!this->CTest->GetCurrentTag().empty()) {
+ ostr << "_" << this->CTest->GetCurrentTag();
+ }
+ ostr << ".log";
+ if (!this->CTest->OpenOutputFile("Temporary", ostr.str(), xofs)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create log file: " << ostr.str() << std::endl);
+ return false;
+ }
+ return true;
+}
diff --git a/Source/CTest/cmCTestGenericHandler.h b/Source/CTest/cmCTestGenericHandler.h
new file mode 100644
index 0000000..9949c3a
--- /dev/null
+++ b/Source/CTest/cmCTestGenericHandler.h
@@ -0,0 +1,113 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCTestGenericHandler_h
+#define cmCTestGenericHandler_h
+
+#include "cmObject.h"
+
+#include "cmCTest.h"
+#include "cmSystemTools.h" //OutputOption
+
+class cmMakefile;
+class cmCTestCommand;
+class cmGeneratedFileStream;
+
+/** \class cmCTestGenericHandler
+ * \brief A superclass of all CTest Handlers
+ *
+ */
+class cmCTestGenericHandler : public cmObject
+{
+public:
+ /**
+ * If verbose then more informaiton is printed out
+ */
+ void SetVerbose(bool val)
+ {
+ this->HandlerVerbose =
+ val ? cmSystemTools::OUTPUT_MERGE : cmSystemTools::OUTPUT_NONE;
+ }
+
+ /**
+ * Populate internals from CTest custom scripts
+ */
+ virtual void PopulateCustomVectors(cmMakefile*) {}
+
+ /**
+ * Do the actual processing. Subclass has to override it.
+ * Return < 0 if error.
+ */
+ virtual int ProcessHandler() = 0;
+
+ /**
+ * Process command line arguments that are applicable for the handler
+ */
+ virtual int ProcessCommandLineArguments(
+ const std::string& /*currentArg*/, size_t& /*idx*/,
+ const std::vector<std::string>& /*allArgs*/)
+ {
+ return 1;
+ }
+
+ /**
+ * Initialize handler
+ */
+ virtual void Initialize();
+
+ /**
+ * Set the CTest instance
+ */
+ void SetCTestInstance(cmCTest* ctest) { this->CTest = ctest; }
+ cmCTest* GetCTestInstance() { return this->CTest; }
+
+ /**
+ * Construct handler
+ */
+ cmCTestGenericHandler();
+ ~cmCTestGenericHandler() CM_OVERRIDE;
+
+ typedef std::map<std::string, std::string> t_StringToString;
+
+ void SetPersistentOption(const std::string& op, const char* value);
+ void SetOption(const std::string& op, const char* value);
+ const char* GetOption(const std::string& op);
+
+ void SetCommand(cmCTestCommand* command) { this->Command = command; }
+
+ void SetSubmitIndex(int idx) { this->SubmitIndex = idx; }
+ int GetSubmitIndex() { return this->SubmitIndex; }
+
+ void SetAppendXML(bool b) { this->AppendXML = b; }
+ void SetQuiet(bool b) { this->Quiet = b; }
+ bool GetQuiet() { return this->Quiet; }
+ void SetTestLoad(unsigned long load) { this->TestLoad = load; }
+ unsigned long GetTestLoad() const { return this->TestLoad; }
+
+protected:
+ bool StartResultingXML(cmCTest::Part part, const char* name,
+ cmGeneratedFileStream& xofs);
+ bool StartLogFile(const char* name, cmGeneratedFileStream& xofs);
+
+ bool AppendXML;
+ bool Quiet;
+ unsigned long TestLoad;
+ cmSystemTools::OutputOption HandlerVerbose;
+ cmCTest* CTest;
+ t_StringToString Options;
+ t_StringToString PersistentOptions;
+
+ cmCTestCommand* Command;
+ int SubmitIndex;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestGlobalVC.cxx b/Source/CTest/cmCTestGlobalVC.cxx
new file mode 100644
index 0000000..0c7ca4d
--- /dev/null
+++ b/Source/CTest/cmCTestGlobalVC.cxx
@@ -0,0 +1,131 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestGlobalVC.h"
+
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+cmCTestGlobalVC::cmCTestGlobalVC(cmCTest* ct, std::ostream& log)
+ : cmCTestVC(ct, log)
+{
+ this->PriorRev = this->Unknown;
+}
+
+cmCTestGlobalVC::~cmCTestGlobalVC()
+{
+}
+
+const char* cmCTestGlobalVC::LocalPath(std::string const& path)
+{
+ return path.c_str();
+}
+
+void cmCTestGlobalVC::DoRevision(Revision const& revision,
+ std::vector<Change> const& changes)
+{
+ // Ignore changes in the old revision.
+ if (revision.Rev == this->OldRevision) {
+ this->PriorRev = revision;
+ return;
+ }
+
+ // Indicate we found a revision.
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
+
+ // Store the revision.
+ this->Revisions.push_back(revision);
+
+ // Report this revision.
+ Revision const& rev = this->Revisions.back();
+ /* clang-format off */
+ this->Log << "Found revision " << rev.Rev << "\n"
+ << " author = " << rev.Author << "\n"
+ << " date = " << rev.Date << "\n";
+ /* clang-format on */
+
+ // Update information about revisions of the changed files.
+ for (std::vector<Change>::const_iterator ci = changes.begin();
+ ci != changes.end(); ++ci) {
+ if (const char* local = this->LocalPath(ci->Path)) {
+ std::string dir = cmSystemTools::GetFilenamePath(local);
+ std::string name = cmSystemTools::GetFilenameName(local);
+ File& file = this->Dirs[dir][name];
+ file.PriorRev = file.Rev ? file.Rev : &this->PriorRev;
+ file.Rev = &rev;
+ this->Log << " " << ci->Action << " " << local << " "
+ << "\n";
+ }
+ }
+}
+
+void cmCTestGlobalVC::DoModification(PathStatus status,
+ std::string const& path)
+{
+ std::string dir = cmSystemTools::GetFilenamePath(path);
+ std::string name = cmSystemTools::GetFilenameName(path);
+ File& file = this->Dirs[dir][name];
+ file.Status = status;
+ // For local modifications the current rev is unknown and the
+ // prior rev is the latest from svn.
+ if (!file.Rev && !file.PriorRev) {
+ file.PriorRev = &this->PriorRev;
+ }
+}
+
+void cmCTestGlobalVC::WriteXMLDirectory(cmXMLWriter& xml,
+ std::string const& path,
+ Directory const& dir)
+{
+ const char* slash = path.empty() ? "" : "/";
+ xml.StartElement("Directory");
+ xml.Element("Name", path);
+ for (Directory::const_iterator fi = dir.begin(); fi != dir.end(); ++fi) {
+ std::string full = path + slash + fi->first;
+ this->WriteXMLEntry(xml, path, fi->first, full, fi->second);
+ }
+ xml.EndElement(); // Directory
+}
+
+void cmCTestGlobalVC::WriteXMLGlobal(cmXMLWriter& xml)
+{
+ if (!this->NewRevision.empty()) {
+ xml.Element("Revision", this->NewRevision);
+ }
+ if (!this->OldRevision.empty() && this->OldRevision != this->NewRevision) {
+ xml.Element("PriorRevision", this->OldRevision);
+ }
+}
+
+bool cmCTestGlobalVC::WriteXMLUpdates(cmXMLWriter& xml)
+{
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Gathering version information (one . per revision):\n"
+ " "
+ << std::flush);
+ this->LoadRevisions();
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
+
+ this->LoadModifications();
+
+ this->WriteXMLGlobal(xml);
+
+ for (std::map<std::string, Directory>::const_iterator di =
+ this->Dirs.begin();
+ di != this->Dirs.end(); ++di) {
+ this->WriteXMLDirectory(xml, di->first, di->second);
+ }
+
+ return true;
+}
diff --git a/Source/CTest/cmCTestGlobalVC.h b/Source/CTest/cmCTestGlobalVC.h
new file mode 100644
index 0000000..7ea3440
--- /dev/null
+++ b/Source/CTest/cmCTestGlobalVC.h
@@ -0,0 +1,75 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestGlobalVC_h
+#define cmCTestGlobalVC_h
+
+#include "cmCTestVC.h"
+
+#include <list>
+
+/** \class cmCTestGlobalVC
+ * \brief Base class for handling globally-versioned trees
+ *
+ */
+class cmCTestGlobalVC : public cmCTestVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestGlobalVC(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestGlobalVC() CM_OVERRIDE;
+
+protected:
+ // Implement cmCTestVC internal API.
+ bool WriteXMLUpdates(cmXMLWriter& xml) CM_OVERRIDE;
+
+ /** Represent a vcs-reported action for one path in a revision. */
+ struct Change
+ {
+ char Action;
+ std::string Path;
+ Change(char a = '?')
+ : Action(a)
+ {
+ }
+ };
+
+ // Update status for files in each directory.
+ class Directory : public std::map<std::string, File>
+ {
+ };
+ std::map<std::string, Directory> Dirs;
+
+ // Old and new repository revisions.
+ std::string OldRevision;
+ std::string NewRevision;
+
+ // Information known about old revision.
+ Revision PriorRev;
+
+ // Information about revisions from a svn log.
+ std::list<Revision> Revisions;
+
+ virtual const char* LocalPath(std::string const& path);
+
+ virtual void DoRevision(Revision const& revision,
+ std::vector<Change> const& changes);
+ virtual void DoModification(PathStatus status, std::string const& path);
+ virtual void LoadModifications() = 0;
+ virtual void LoadRevisions() = 0;
+
+ virtual void WriteXMLGlobal(cmXMLWriter& xml);
+ void WriteXMLDirectory(cmXMLWriter& xml, std::string const& path,
+ Directory const& dir);
+};
+
+#endif
diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx
new file mode 100644
index 0000000..eb3d611
--- /dev/null
+++ b/Source/CTest/cmCTestHG.cxx
@@ -0,0 +1,311 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestHG.h"
+
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+cmCTestHG::cmCTestHG(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
+{
+ this->PriorRev = this->Unknown;
+}
+
+cmCTestHG::~cmCTestHG()
+{
+}
+
+class cmCTestHG::IdentifyParser : public cmCTestVC::LineParser
+{
+public:
+ IdentifyParser(cmCTestHG* hg, const char* prefix, std::string& rev)
+ : Rev(rev)
+ {
+ this->SetLog(&hg->Log, prefix);
+ this->RegexIdentify.compile("^([0-9a-f]+)");
+ }
+
+private:
+ std::string& Rev;
+ cmsys::RegularExpression RegexIdentify;
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexIdentify.find(this->Line)) {
+ this->Rev = this->RegexIdentify.match(1);
+ return false;
+ }
+ return true;
+ }
+};
+
+class cmCTestHG::StatusParser : public cmCTestVC::LineParser
+{
+public:
+ StatusParser(cmCTestHG* hg, const char* prefix)
+ : HG(hg)
+ {
+ this->SetLog(&hg->Log, prefix);
+ this->RegexStatus.compile("([MARC!?I]) (.*)");
+ }
+
+private:
+ cmCTestHG* HG;
+ cmsys::RegularExpression RegexStatus;
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexStatus.find(this->Line)) {
+ this->DoPath(this->RegexStatus.match(1)[0], this->RegexStatus.match(2));
+ }
+ return true;
+ }
+
+ void DoPath(char status, std::string const& path)
+ {
+ if (path.empty()) {
+ return;
+ }
+
+ // See "hg help status". Note that there is no 'conflict' status.
+ switch (status) {
+ case 'M':
+ case 'A':
+ case '!':
+ case 'R':
+ this->HG->DoModification(PathModified, path);
+ break;
+ case 'I':
+ case '?':
+ case 'C':
+ case ' ':
+ default:
+ break;
+ }
+ }
+};
+
+std::string cmCTestHG::GetWorkingRevision()
+{
+ // Run plumbing "hg identify" to get work tree revision.
+ const char* hg = this->CommandLineTool.c_str();
+ const char* hg_identify[] = { hg, "identify", "-i", CM_NULLPTR };
+ std::string rev;
+ IdentifyParser out(this, "rev-out> ", rev);
+ OutputLogger err(this->Log, "rev-err> ");
+ this->RunChild(hg_identify, &out, &err);
+ return rev;
+}
+
+void cmCTestHG::NoteOldRevision()
+{
+ this->OldRevision = this->GetWorkingRevision();
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Old revision of repository is: "
+ << this->OldRevision << "\n");
+ this->PriorRev.Rev = this->OldRevision;
+}
+
+void cmCTestHG::NoteNewRevision()
+{
+ this->NewRevision = this->GetWorkingRevision();
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " New revision of repository is: "
+ << this->NewRevision << "\n");
+}
+
+bool cmCTestHG::UpdateImpl()
+{
+ // Use "hg pull" followed by "hg update" to update the working tree.
+ {
+ const char* hg = this->CommandLineTool.c_str();
+ const char* hg_pull[] = { hg, "pull", "-v", CM_NULLPTR };
+ OutputLogger out(this->Log, "pull-out> ");
+ OutputLogger err(this->Log, "pull-err> ");
+ this->RunChild(&hg_pull[0], &out, &err);
+ }
+
+ // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
+
+ std::vector<char const*> hg_update;
+ hg_update.push_back(this->CommandLineTool.c_str());
+ hg_update.push_back("update");
+ hg_update.push_back("-v");
+
+ // Add user-specified update options.
+ std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
+ if (opts.empty()) {
+ opts = this->CTest->GetCTestConfiguration("HGUpdateOptions");
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ for (std::vector<std::string>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai) {
+ hg_update.push_back(ai->c_str());
+ }
+
+ // Sentinel argument.
+ hg_update.push_back(CM_NULLPTR);
+
+ OutputLogger out(this->Log, "update-out> ");
+ OutputLogger err(this->Log, "update-err> ");
+ return this->RunUpdateCommand(&hg_update[0], &out, &err);
+}
+
+class cmCTestHG::LogParser : public cmCTestVC::OutputLogger,
+ private cmXMLParser
+{
+public:
+ LogParser(cmCTestHG* hg, const char* prefix)
+ : OutputLogger(hg->Log, prefix)
+ , HG(hg)
+ {
+ this->InitializeParser();
+ }
+ ~LogParser() CM_OVERRIDE { this->CleanupParser(); }
+private:
+ cmCTestHG* HG;
+
+ typedef cmCTestHG::Revision Revision;
+ typedef cmCTestHG::Change Change;
+ Revision Rev;
+ std::vector<Change> Changes;
+ Change CurChange;
+ std::vector<char> CData;
+
+ bool ProcessChunk(const char* data, int length) CM_OVERRIDE
+ {
+ this->OutputLogger::ProcessChunk(data, length);
+ this->ParseChunk(data, length);
+ return true;
+ }
+
+ void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
+ {
+ this->CData.clear();
+ if (name == "logentry") {
+ this->Rev = Revision();
+ if (const char* rev = this->FindAttribute(atts, "revision")) {
+ this->Rev.Rev = rev;
+ }
+ this->Changes.clear();
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) CM_OVERRIDE
+ {
+ this->CData.insert(this->CData.end(), data, data + length);
+ }
+
+ void EndElement(const std::string& name) CM_OVERRIDE
+ {
+ if (name == "logentry") {
+ this->HG->DoRevision(this->Rev, this->Changes);
+ } else if (!this->CData.empty() && name == "author") {
+ this->Rev.Author.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "email") {
+ this->Rev.EMail.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "date") {
+ this->Rev.Date.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "msg") {
+ this->Rev.Log.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "files") {
+ std::vector<std::string> paths = this->SplitCData();
+ for (unsigned int i = 0; i < paths.size(); ++i) {
+ // Updated by default, will be modified using file_adds and
+ // file_dels.
+ this->CurChange = Change('U');
+ this->CurChange.Path = paths[i];
+ this->Changes.push_back(this->CurChange);
+ }
+ } else if (!this->CData.empty() && name == "file_adds") {
+ std::string added_paths(this->CData.begin(), this->CData.end());
+ for (unsigned int i = 0; i < this->Changes.size(); ++i) {
+ if (added_paths.find(this->Changes[i].Path) != std::string::npos) {
+ this->Changes[i].Action = 'A';
+ }
+ }
+ } else if (!this->CData.empty() && name == "file_dels") {
+ std::string added_paths(this->CData.begin(), this->CData.end());
+ for (unsigned int i = 0; i < this->Changes.size(); ++i) {
+ if (added_paths.find(this->Changes[i].Path) != std::string::npos) {
+ this->Changes[i].Action = 'D';
+ }
+ }
+ }
+ this->CData.clear();
+ }
+
+ std::vector<std::string> SplitCData()
+ {
+ std::vector<std::string> output;
+ std::string currPath;
+ for (unsigned int i = 0; i < this->CData.size(); ++i) {
+ if (this->CData[i] != ' ') {
+ currPath += this->CData[i];
+ } else {
+ output.push_back(currPath);
+ currPath = "";
+ }
+ }
+ output.push_back(currPath);
+ return output;
+ }
+
+ void ReportError(int, int, const char* msg) CM_OVERRIDE
+ {
+ this->HG->Log << "Error parsing hg log xml: " << msg << "\n";
+ }
+};
+
+void cmCTestHG::LoadRevisions()
+{
+ // Use 'hg log' to get revisions in a xml format.
+ //
+ // TODO: This should use plumbing or python code to be more precise.
+ // The "list of strings" templates like {files} will not work when
+ // the project has spaces in the path. Also, they may not have
+ // proper XML escapes.
+ std::string range = this->OldRevision + ":" + this->NewRevision;
+ const char* hg = this->CommandLineTool.c_str();
+ const char* hgXMLTemplate = "<logentry\n"
+ " revision=\"{node|short}\">\n"
+ " <author>{author|person}</author>\n"
+ " <email>{author|email}</email>\n"
+ " <date>{date|isodate}</date>\n"
+ " <msg>{desc}</msg>\n"
+ " <files>{files}</files>\n"
+ " <file_adds>{file_adds}</file_adds>\n"
+ " <file_dels>{file_dels}</file_dels>\n"
+ "</logentry>\n";
+ const char* hg_log[] = {
+ hg, "log", "--removed", "-r", range.c_str(),
+ "--template", hgXMLTemplate, CM_NULLPTR
+ };
+
+ LogParser out(this, "log-out> ");
+ out.Process("<?xml version=\"1.0\"?>\n"
+ "<log>\n");
+ OutputLogger err(this->Log, "log-err> ");
+ this->RunChild(hg_log, &out, &err);
+ out.Process("</log>\n");
+}
+
+void cmCTestHG::LoadModifications()
+{
+ // Use 'hg status' to get modified files.
+ const char* hg = this->CommandLineTool.c_str();
+ const char* hg_status[] = { hg, "status", CM_NULLPTR };
+ StatusParser out(this, "status-out> ");
+ OutputLogger err(this->Log, "status-err> ");
+ this->RunChild(hg_status, &out, &err);
+}
diff --git a/Source/CTest/cmCTestHG.h b/Source/CTest/cmCTestHG.h
new file mode 100644
index 0000000..c4ce08c
--- /dev/null
+++ b/Source/CTest/cmCTestHG.h
@@ -0,0 +1,47 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestHG_h
+#define cmCTestHG_h
+
+#include "cmCTestGlobalVC.h"
+
+/** \class cmCTestHG
+ * \brief Interaction with Mercurial command-line tool
+ *
+ */
+class cmCTestHG : public cmCTestGlobalVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestHG(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestHG() CM_OVERRIDE;
+
+private:
+ std::string GetWorkingRevision();
+ void NoteOldRevision() CM_OVERRIDE;
+ void NoteNewRevision() CM_OVERRIDE;
+ bool UpdateImpl() CM_OVERRIDE;
+
+ void LoadRevisions() CM_OVERRIDE;
+ void LoadModifications() CM_OVERRIDE;
+
+ // Parsing helper classes.
+ class IdentifyParser;
+ class StatusParser;
+ class LogParser;
+ friend class IdentifyParser;
+ friend class StatusParser;
+ friend class LogParser;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx
new file mode 100644
index 0000000..e1361a1
--- /dev/null
+++ b/Source/CTest/cmCTestHandlerCommand.cxx
@@ -0,0 +1,189 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestHandlerCommand.h"
+
+#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
+
+cmCTestHandlerCommand::cmCTestHandlerCommand()
+{
+ const size_t INIT_SIZE = 100;
+ size_t cc;
+ this->Arguments.reserve(INIT_SIZE);
+ for (cc = 0; cc < INIT_SIZE; ++cc) {
+ this->Arguments.push_back(CM_NULLPTR);
+ }
+ this->Arguments[ct_RETURN_VALUE] = "RETURN_VALUE";
+ this->Arguments[ct_SOURCE] = "SOURCE";
+ this->Arguments[ct_BUILD] = "BUILD";
+ this->Arguments[ct_SUBMIT_INDEX] = "SUBMIT_INDEX";
+ this->Last = ct_LAST;
+ this->AppendXML = false;
+ this->Quiet = false;
+}
+
+bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ // Allocate space for argument values.
+ this->Values.clear();
+ this->Values.resize(this->Last, CM_NULLPTR);
+
+ // Process input arguments.
+ this->ArgumentDoing = ArgumentDoingNone;
+ for (unsigned int i = 0; i < args.size(); ++i) {
+ // Check this argument.
+ if (!this->CheckArgumentKeyword(args[i]) &&
+ !this->CheckArgumentValue(args[i])) {
+ std::ostringstream e;
+ e << "called with unknown argument \"" << args[i] << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Quit if an argument is invalid.
+ if (this->ArgumentDoing == ArgumentDoingError) {
+ return false;
+ }
+ }
+
+ // Set the config type of this ctest to the current value of the
+ // CTEST_CONFIGURATION_TYPE script variable if it is defined.
+ // The current script value trumps the -C argument on the command
+ // line.
+ const char* ctestConfigType =
+ this->Makefile->GetDefinition("CTEST_CONFIGURATION_TYPE");
+ if (ctestConfigType) {
+ this->CTest->SetConfigType(ctestConfigType);
+ }
+
+ if (this->Values[ct_BUILD]) {
+ this->CTest->SetCTestConfiguration(
+ "BuildDirectory",
+ cmSystemTools::CollapseFullPath(this->Values[ct_BUILD]).c_str(),
+ this->Quiet);
+ } else {
+ const char* bdir =
+ this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY");
+ if (bdir) {
+ this->CTest->SetCTestConfiguration(
+ "BuildDirectory", cmSystemTools::CollapseFullPath(bdir).c_str(),
+ this->Quiet);
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "CTEST_BINARY_DIRECTORY not set"
+ << std::endl;);
+ }
+ }
+ if (this->Values[ct_SOURCE]) {
+ cmCTestLog(this->CTest, DEBUG, "Set source directory to: "
+ << this->Values[ct_SOURCE] << std::endl);
+ this->CTest->SetCTestConfiguration(
+ "SourceDirectory",
+ cmSystemTools::CollapseFullPath(this->Values[ct_SOURCE]).c_str(),
+ this->Quiet);
+ } else {
+ this->CTest->SetCTestConfiguration(
+ "SourceDirectory",
+ cmSystemTools::CollapseFullPath(
+ this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY"))
+ .c_str(),
+ this->Quiet);
+ }
+
+ if (const char* changeId =
+ this->Makefile->GetDefinition("CTEST_CHANGE_ID")) {
+ this->CTest->SetCTestConfiguration("ChangeId", changeId, this->Quiet);
+ }
+
+ cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl;);
+ cmCTestGenericHandler* handler = this->InitializeHandler();
+ if (!handler) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot instantiate test handler "
+ << this->GetName() << std::endl);
+ return false;
+ }
+
+ handler->SetAppendXML(this->AppendXML);
+
+ handler->PopulateCustomVectors(this->Makefile);
+ if (this->Values[ct_SUBMIT_INDEX]) {
+ if (!this->CTest->GetDropSiteCDash() &&
+ this->CTest->GetDartVersion() <= 1) {
+ cmCTestLog(
+ this->CTest, ERROR_MESSAGE,
+ "Dart before version 2.0 does not support collecting submissions."
+ << std::endl
+ << "Please upgrade the server to Dart 2 or higher, or do not use "
+ "SUBMIT_INDEX."
+ << std::endl);
+ } else {
+ handler->SetSubmitIndex(atoi(this->Values[ct_SUBMIT_INDEX]));
+ }
+ }
+ std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::ChangeDirectory(
+ this->CTest->GetCTestConfiguration("BuildDirectory"));
+ int res = handler->ProcessHandler();
+ if (this->Values[ct_RETURN_VALUE] && *this->Values[ct_RETURN_VALUE]) {
+ std::ostringstream str;
+ str << res;
+ this->Makefile->AddDefinition(this->Values[ct_RETURN_VALUE],
+ str.str().c_str());
+ }
+ cmSystemTools::ChangeDirectory(current_dir);
+ return true;
+}
+
+bool cmCTestHandlerCommand::CheckArgumentKeyword(std::string const& arg)
+{
+ // Look for non-value arguments common to all commands.
+ if (arg == "APPEND") {
+ this->ArgumentDoing = ArgumentDoingNone;
+ this->AppendXML = true;
+ return true;
+ }
+ if (arg == "QUIET") {
+ this->ArgumentDoing = ArgumentDoingNone;
+ this->Quiet = true;
+ return true;
+ }
+
+ // Check for a keyword in our argument/value table.
+ for (unsigned int k = 0; k < this->Arguments.size(); ++k) {
+ if (this->Arguments[k] && arg == this->Arguments[k]) {
+ this->ArgumentDoing = ArgumentDoingKeyword;
+ this->ArgumentIndex = k;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmCTestHandlerCommand::CheckArgumentValue(std::string const& arg)
+{
+ if (this->ArgumentDoing == ArgumentDoingKeyword) {
+ this->ArgumentDoing = ArgumentDoingNone;
+ unsigned int k = this->ArgumentIndex;
+ if (this->Values[k]) {
+ std::ostringstream e;
+ e << "Called with more than one value for " << this->Arguments[k];
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ this->ArgumentDoing = ArgumentDoingError;
+ return true;
+ }
+ this->Values[k] = arg.c_str();
+ cmCTestLog(this->CTest, DEBUG, "Set " << this->Arguments[k] << " to "
+ << arg << "\n");
+ return true;
+ }
+ return false;
+}
diff --git a/Source/CTest/cmCTestHandlerCommand.h b/Source/CTest/cmCTestHandlerCommand.h
new file mode 100644
index 0000000..0468bbc
--- /dev/null
+++ b/Source/CTest/cmCTestHandlerCommand.h
@@ -0,0 +1,78 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestHandlerCommand_h
+#define cmCTestHandlerCommand_h
+
+#include "cmCTestCommand.h"
+
+class cmCTestGenericHandler;
+
+/** \class cmCTestHandler
+ * \brief Run a ctest script
+ *
+ * cmCTestHandlerCommand defineds the command to test the project.
+ */
+class cmCTestHandlerCommand : public cmCTestCommand
+{
+public:
+ cmCTestHandlerCommand();
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ cmTypeMacro(cmCTestHandlerCommand, cmCTestCommand);
+
+ enum
+ {
+ ct_NONE,
+ ct_RETURN_VALUE,
+ ct_BUILD,
+ ct_SOURCE,
+ ct_SUBMIT_INDEX,
+ ct_LAST
+ };
+
+protected:
+ virtual cmCTestGenericHandler* InitializeHandler() = 0;
+
+ // Command argument handling.
+ virtual bool CheckArgumentKeyword(std::string const& arg);
+ virtual bool CheckArgumentValue(std::string const& arg);
+ enum
+ {
+ ArgumentDoingNone,
+ ArgumentDoingError,
+ ArgumentDoingKeyword,
+ ArgumentDoingLast1
+ };
+ int ArgumentDoing;
+ unsigned int ArgumentIndex;
+
+ bool AppendXML;
+ bool Quiet;
+
+ std::string ReturnVariable;
+ std::vector<const char*> Arguments;
+ std::vector<const char*> Values;
+ size_t Last;
+};
+
+#define CTEST_COMMAND_APPEND_OPTION_DOCS \
+ "The APPEND option marks results for append to those previously " \
+ "submitted to a dashboard server since the last ctest_start. " \
+ "Append semantics are defined by the dashboard server in use."
+
+#endif
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
new file mode 100644
index 0000000..3eed79e
--- /dev/null
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -0,0 +1,631 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestLaunch.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+#include <cmsys/FStream.hxx>
+#include <cmsys/MD5.h>
+#include <cmsys/Process.h>
+#include <cmsys/RegularExpression.hxx>
+
+#ifdef _WIN32
+#include <fcntl.h> // for _O_BINARY
+#include <io.h> // for _setmode
+#include <stdio.h> // for std{out,err} and fileno
+#endif
+
+cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
+{
+ this->Passthru = true;
+ this->Process = CM_NULLPTR;
+ this->ExitCode = 1;
+ this->CWD = cmSystemTools::GetCurrentWorkingDirectory();
+
+ if (!this->ParseArguments(argc, argv)) {
+ return;
+ }
+
+ this->ComputeFileNames();
+
+ this->ScrapeRulesLoaded = false;
+ this->HaveOut = false;
+ this->HaveErr = false;
+ this->Process = cmsysProcess_New();
+}
+
+cmCTestLaunch::~cmCTestLaunch()
+{
+ cmsysProcess_Delete(this->Process);
+ if (!this->Passthru) {
+ cmSystemTools::RemoveFile(this->LogOut);
+ cmSystemTools::RemoveFile(this->LogErr);
+ }
+}
+
+bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
+{
+ // Launcher options occur first and are separated from the real
+ // command line by a '--' option.
+ enum Doing
+ {
+ DoingNone,
+ DoingOutput,
+ DoingSource,
+ DoingLanguage,
+ DoingTargetName,
+ DoingTargetType,
+ DoingBuildDir,
+ DoingCount,
+ DoingFilterPrefix
+ };
+ Doing doing = DoingNone;
+ int arg0 = 0;
+ for (int i = 1; !arg0 && i < argc; ++i) {
+ const char* arg = argv[i];
+ if (strcmp(arg, "--") == 0) {
+ arg0 = i + 1;
+ } else if (strcmp(arg, "--output") == 0) {
+ doing = DoingOutput;
+ } else if (strcmp(arg, "--source") == 0) {
+ doing = DoingSource;
+ } else if (strcmp(arg, "--language") == 0) {
+ doing = DoingLanguage;
+ } else if (strcmp(arg, "--target-name") == 0) {
+ doing = DoingTargetName;
+ } else if (strcmp(arg, "--target-type") == 0) {
+ doing = DoingTargetType;
+ } else if (strcmp(arg, "--build-dir") == 0) {
+ doing = DoingBuildDir;
+ } else if (strcmp(arg, "--filter-prefix") == 0) {
+ doing = DoingFilterPrefix;
+ } else if (doing == DoingOutput) {
+ this->OptionOutput = arg;
+ doing = DoingNone;
+ } else if (doing == DoingSource) {
+ this->OptionSource = arg;
+ doing = DoingNone;
+ } else if (doing == DoingLanguage) {
+ this->OptionLanguage = arg;
+ if (this->OptionLanguage == "CXX") {
+ this->OptionLanguage = "C++";
+ }
+ doing = DoingNone;
+ } else if (doing == DoingTargetName) {
+ this->OptionTargetName = arg;
+ doing = DoingNone;
+ } else if (doing == DoingTargetType) {
+ this->OptionTargetType = arg;
+ doing = DoingNone;
+ } else if (doing == DoingBuildDir) {
+ this->OptionBuildDir = arg;
+ doing = DoingNone;
+ } else if (doing == DoingFilterPrefix) {
+ this->OptionFilterPrefix = arg;
+ doing = DoingNone;
+ }
+ }
+
+ // Extract the real command line.
+ if (arg0) {
+ this->RealArgC = argc - arg0;
+ this->RealArgV = argv + arg0;
+ for (int i = 0; i < this->RealArgC; ++i) {
+ this->HandleRealArg(this->RealArgV[i]);
+ }
+ return true;
+ } else {
+ this->RealArgC = 0;
+ this->RealArgV = CM_NULLPTR;
+ std::cerr << "No launch/command separator ('--') found!\n";
+ return false;
+ }
+}
+
+void cmCTestLaunch::HandleRealArg(const char* arg)
+{
+#ifdef _WIN32
+ // Expand response file arguments.
+ if (arg[0] == '@' && cmSystemTools::FileExists(arg + 1)) {
+ cmsys::ifstream fin(arg + 1);
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ cmSystemTools::ParseWindowsCommandLine(line.c_str(), this->RealArgs);
+ }
+ return;
+ }
+#endif
+ this->RealArgs.push_back(arg);
+}
+
+void cmCTestLaunch::ComputeFileNames()
+{
+ // We just passthru the behavior of the real command unless the
+ // CTEST_LAUNCH_LOGS environment variable is set.
+ const char* d = getenv("CTEST_LAUNCH_LOGS");
+ if (!(d && *d)) {
+ return;
+ }
+ this->Passthru = false;
+
+ // The environment variable specifies the directory into which we
+ // generate build logs.
+ this->LogDir = d;
+ cmSystemTools::ConvertToUnixSlashes(this->LogDir);
+ this->LogDir += "/";
+
+ // We hash the input command working dir and command line to obtain
+ // a repeatable and (probably) unique name for log files.
+ char hash[32];
+ cmsysMD5* md5 = cmsysMD5_New();
+ cmsysMD5_Initialize(md5);
+ cmsysMD5_Append(md5, (unsigned char const*)(this->CWD.c_str()), -1);
+ for (std::vector<std::string>::const_iterator ai = this->RealArgs.begin();
+ ai != this->RealArgs.end(); ++ai) {
+ cmsysMD5_Append(md5, (unsigned char const*)ai->c_str(), -1);
+ }
+ cmsysMD5_FinalizeHex(md5, hash);
+ cmsysMD5_Delete(md5);
+ this->LogHash.assign(hash, 32);
+
+ // We store stdout and stderr in temporary log files.
+ this->LogOut = this->LogDir;
+ this->LogOut += "launch-";
+ this->LogOut += this->LogHash;
+ this->LogOut += "-out.txt";
+ this->LogErr = this->LogDir;
+ this->LogErr += "launch-";
+ this->LogErr += this->LogHash;
+ this->LogErr += "-err.txt";
+}
+
+void cmCTestLaunch::RunChild()
+{
+ // Ignore noopt make rules
+ if (this->RealArgs.empty() || this->RealArgs[0] == ":") {
+ this->ExitCode = 0;
+ return;
+ }
+
+ // Prepare to run the real command.
+ cmsysProcess* cp = this->Process;
+ cmsysProcess_SetCommand(cp, this->RealArgV);
+
+ cmsys::ofstream fout;
+ cmsys::ofstream ferr;
+ if (this->Passthru) {
+ // In passthru mode we just share the output pipes.
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
+ } else {
+ // In full mode we record the child output pipes to log files.
+ fout.open(this->LogOut.c_str(), std::ios::out | std::ios::binary);
+ ferr.open(this->LogErr.c_str(), std::ios::out | std::ios::binary);
+ }
+
+#ifdef _WIN32
+ // Do this so that newline transformation is not done when writing to cout
+ // and cerr below.
+ _setmode(fileno(stdout), _O_BINARY);
+ _setmode(fileno(stderr), _O_BINARY);
+#endif
+
+ // Run the real command.
+ cmsysProcess_Execute(cp);
+
+ // Record child stdout and stderr if necessary.
+ if (!this->Passthru) {
+ char* data = CM_NULLPTR;
+ int length = 0;
+ while (int p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR)) {
+ if (p == cmsysProcess_Pipe_STDOUT) {
+ fout.write(data, length);
+ std::cout.write(data, length);
+ this->HaveOut = true;
+ } else if (p == cmsysProcess_Pipe_STDERR) {
+ ferr.write(data, length);
+ std::cerr.write(data, length);
+ this->HaveErr = true;
+ }
+ }
+ }
+
+ // Wait for the real command to finish.
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+ this->ExitCode = cmsysProcess_GetExitValue(cp);
+}
+
+int cmCTestLaunch::Run()
+{
+ if (!this->Process) {
+ std::cerr << "Could not allocate cmsysProcess instance!\n";
+ return -1;
+ }
+
+ this->RunChild();
+
+ if (this->CheckResults()) {
+ return this->ExitCode;
+ }
+
+ this->LoadConfig();
+ this->WriteXML();
+
+ return this->ExitCode;
+}
+
+void cmCTestLaunch::LoadLabels()
+{
+ if (this->OptionBuildDir.empty() || this->OptionTargetName.empty()) {
+ return;
+ }
+
+ // Labels are listed in per-target files.
+ std::string fname = this->OptionBuildDir;
+ fname += cmake::GetCMakeFilesDirectory();
+ fname += "/";
+ fname += this->OptionTargetName;
+ fname += ".dir/Labels.txt";
+
+ // We are interested in per-target labels for this source file.
+ std::string source = this->OptionSource;
+ cmSystemTools::ConvertToUnixSlashes(source);
+
+ // Load the labels file.
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+ if (!fin) {
+ return;
+ }
+ bool inTarget = true;
+ bool inSource = false;
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (line.empty() || line[0] == '#') {
+ // Ignore blank and comment lines.
+ continue;
+ } else if (line[0] == ' ') {
+ // Label lines appear indented by one space.
+ if (inTarget || inSource) {
+ this->Labels.insert(line.c_str() + 1);
+ }
+ } else if (!this->OptionSource.empty() && !inSource) {
+ // Non-indented lines specify a source file name. The first one
+ // is the end of the target-wide labels. Use labels following a
+ // matching source.
+ inTarget = false;
+ inSource = this->SourceMatches(line, source);
+ } else {
+ return;
+ }
+ }
+}
+
+bool cmCTestLaunch::SourceMatches(std::string const& lhs,
+ std::string const& rhs)
+{
+ // TODO: Case sensitivity, UseRelativePaths, etc. Note that both
+ // paths in the comparison get generated by CMake. This is done for
+ // every source in the target, so it should be efficient (cannot use
+ // cmSystemTools::IsSameFile).
+ return lhs == rhs;
+}
+
+bool cmCTestLaunch::IsError() const
+{
+ return this->ExitCode != 0;
+}
+
+void cmCTestLaunch::WriteXML()
+{
+ // Name the xml file.
+ std::string logXML = this->LogDir;
+ logXML += this->IsError() ? "error-" : "warning-";
+ logXML += this->LogHash;
+ logXML += ".xml";
+
+ // Use cmGeneratedFileStream to atomically create the report file.
+ cmGeneratedFileStream fxml(logXML.c_str());
+ cmXMLWriter xml(fxml, 2);
+ xml.StartElement("Failure");
+ xml.Attribute("type", this->IsError() ? "Error" : "Warning");
+ this->WriteXMLAction(xml);
+ this->WriteXMLCommand(xml);
+ this->WriteXMLResult(xml);
+ this->WriteXMLLabels(xml);
+ xml.EndElement(); // Failure
+}
+
+void cmCTestLaunch::WriteXMLAction(cmXMLWriter& xml)
+{
+ xml.Comment("Meta-information about the build action");
+ xml.StartElement("Action");
+
+ // TargetName
+ if (!this->OptionTargetName.empty()) {
+ xml.Element("TargetName", this->OptionTargetName);
+ }
+
+ // Language
+ if (!this->OptionLanguage.empty()) {
+ xml.Element("Language", this->OptionLanguage);
+ }
+
+ // SourceFile
+ if (!this->OptionSource.empty()) {
+ std::string source = this->OptionSource;
+ cmSystemTools::ConvertToUnixSlashes(source);
+
+ // If file is in source tree use its relative location.
+ if (cmSystemTools::FileIsFullPath(this->SourceDir.c_str()) &&
+ cmSystemTools::FileIsFullPath(source.c_str()) &&
+ cmSystemTools::IsSubDirectory(source, this->SourceDir)) {
+ source =
+ cmSystemTools::RelativePath(this->SourceDir.c_str(), source.c_str());
+ }
+
+ xml.Element("SourceFile", source);
+ }
+
+ // OutputFile
+ if (!this->OptionOutput.empty()) {
+ xml.Element("OutputFile", this->OptionOutput);
+ }
+
+ // OutputType
+ const char* outputType = CM_NULLPTR;
+ if (!this->OptionTargetType.empty()) {
+ if (this->OptionTargetType == "EXECUTABLE") {
+ outputType = "executable";
+ } else if (this->OptionTargetType == "SHARED_LIBRARY") {
+ outputType = "shared library";
+ } else if (this->OptionTargetType == "MODULE_LIBRARY") {
+ outputType = "module library";
+ } else if (this->OptionTargetType == "STATIC_LIBRARY") {
+ outputType = "static library";
+ }
+ } else if (!this->OptionSource.empty()) {
+ outputType = "object file";
+ }
+ if (outputType) {
+ xml.Element("OutputType", outputType);
+ }
+
+ xml.EndElement(); // Action
+}
+
+void cmCTestLaunch::WriteXMLCommand(cmXMLWriter& xml)
+{
+ xml.Comment("Details of command");
+ xml.StartElement("Command");
+ if (!this->CWD.empty()) {
+ xml.Element("WorkingDirectory", this->CWD);
+ }
+ for (std::vector<std::string>::const_iterator ai = this->RealArgs.begin();
+ ai != this->RealArgs.end(); ++ai) {
+ xml.Element("Argument", *ai);
+ }
+ xml.EndElement(); // Command
+}
+
+void cmCTestLaunch::WriteXMLResult(cmXMLWriter& xml)
+{
+ xml.Comment("Result of command");
+ xml.StartElement("Result");
+
+ // StdOut
+ xml.StartElement("StdOut");
+ this->DumpFileToXML(xml, this->LogOut);
+ xml.EndElement(); // StdOut
+
+ // StdErr
+ xml.StartElement("StdErr");
+ this->DumpFileToXML(xml, this->LogErr);
+ xml.EndElement(); // StdErr
+
+ // ExitCondition
+ xml.StartElement("ExitCondition");
+ cmsysProcess* cp = this->Process;
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Starting:
+ xml.Content("No process has been executed");
+ break;
+ case cmsysProcess_State_Executing:
+ xml.Content("The process is still executing");
+ break;
+ case cmsysProcess_State_Disowned:
+ xml.Content("Disowned");
+ break;
+ case cmsysProcess_State_Killed:
+ xml.Content("Killed by parent");
+ break;
+
+ case cmsysProcess_State_Expired:
+ xml.Content("Killed when timeout expired");
+ break;
+ case cmsysProcess_State_Exited:
+ xml.Content(this->ExitCode);
+ break;
+ case cmsysProcess_State_Exception:
+ xml.Content("Terminated abnormally: ");
+ xml.Content(cmsysProcess_GetExceptionString(cp));
+ break;
+ case cmsysProcess_State_Error:
+ xml.Content("Error administrating child process: ");
+ xml.Content(cmsysProcess_GetErrorString(cp));
+ break;
+ };
+ xml.EndElement(); // ExitCondition
+
+ xml.EndElement(); // Result
+}
+
+void cmCTestLaunch::WriteXMLLabels(cmXMLWriter& xml)
+{
+ this->LoadLabels();
+ if (!this->Labels.empty()) {
+ xml.Comment("Interested parties");
+ xml.StartElement("Labels");
+ for (std::set<std::string>::const_iterator li = this->Labels.begin();
+ li != this->Labels.end(); ++li) {
+ xml.Element("Label", *li);
+ }
+ xml.EndElement(); // Labels
+ }
+}
+
+void cmCTestLaunch::DumpFileToXML(cmXMLWriter& xml, std::string const& fname)
+{
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+
+ std::string line;
+ const char* sep = "";
+
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (MatchesFilterPrefix(line)) {
+ continue;
+ }
+
+ xml.Content(sep);
+ xml.Content(line);
+ sep = "\n";
+ }
+}
+
+bool cmCTestLaunch::CheckResults()
+{
+ // Skip XML in passthru mode.
+ if (this->Passthru) {
+ return true;
+ }
+
+ // We always report failure for error conditions.
+ if (this->IsError()) {
+ return false;
+ }
+
+ // Scrape the output logs to look for warnings.
+ if ((this->HaveErr && this->ScrapeLog(this->LogErr)) ||
+ (this->HaveOut && this->ScrapeLog(this->LogOut))) {
+ return false;
+ }
+ return true;
+}
+
+void cmCTestLaunch::LoadScrapeRules()
+{
+ if (this->ScrapeRulesLoaded) {
+ return;
+ }
+ this->ScrapeRulesLoaded = true;
+
+ // Common compiler warning formats. These are much simpler than the
+ // full log-scraping expressions because we do not need to extract
+ // file and line information.
+ this->RegexWarning.push_back("(^|[ :])[Ww][Aa][Rr][Nn][Ii][Nn][Gg]");
+ this->RegexWarning.push_back("(^|[ :])[Rr][Ee][Mm][Aa][Rr][Kk]");
+ this->RegexWarning.push_back("(^|[ :])[Nn][Oo][Tt][Ee]");
+
+ // Load custom match rules given to us by CTest.
+ this->LoadScrapeRules("Warning", this->RegexWarning);
+ this->LoadScrapeRules("WarningSuppress", this->RegexWarningSuppress);
+}
+
+void cmCTestLaunch::LoadScrapeRules(
+ const char* purpose, std::vector<cmsys::RegularExpression>& regexps)
+{
+ std::string fname = this->LogDir;
+ fname += "Custom";
+ fname += purpose;
+ fname += ".txt";
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+ std::string line;
+ cmsys::RegularExpression rex;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (rex.compile(line.c_str())) {
+ regexps.push_back(rex);
+ }
+ }
+}
+
+bool cmCTestLaunch::ScrapeLog(std::string const& fname)
+{
+ this->LoadScrapeRules();
+
+ // Look for log file lines matching warning expressions but not
+ // suppression expressions.
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (MatchesFilterPrefix(line)) {
+ continue;
+ }
+
+ if (this->Match(line, this->RegexWarning) &&
+ !this->Match(line, this->RegexWarningSuppress)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmCTestLaunch::Match(std::string const& line,
+ std::vector<cmsys::RegularExpression>& regexps)
+{
+ for (std::vector<cmsys::RegularExpression>::iterator ri = regexps.begin();
+ ri != regexps.end(); ++ri) {
+ if (ri->find(line.c_str())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmCTestLaunch::MatchesFilterPrefix(std::string const& line) const
+{
+ return !this->OptionFilterPrefix.empty() &&
+ cmSystemTools::StringStartsWith(line, this->OptionFilterPrefix.c_str());
+}
+
+int cmCTestLaunch::Main(int argc, const char* const argv[])
+{
+ if (argc == 2) {
+ std::cerr << "ctest --launch: this mode is for internal CTest use only"
+ << std::endl;
+ return 1;
+ }
+ cmCTestLaunch self(argc, argv);
+ return self.Run();
+}
+
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmake.h"
+#include <cm_auto_ptr.hxx>
+void cmCTestLaunch::LoadConfig()
+{
+ cmake cm;
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator gg(&cm);
+ CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(&gg, cm.GetCurrentSnapshot()));
+ std::string fname = this->LogDir;
+ fname += "CTestLaunchConfig.cmake";
+ if (cmSystemTools::FileExists(fname.c_str()) &&
+ mf->ReadListFile(fname.c_str())) {
+ this->SourceDir = mf->GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
+ cmSystemTools::ConvertToUnixSlashes(this->SourceDir);
+ }
+}
diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h
new file mode 100644
index 0000000..cbcc9ec
--- /dev/null
+++ b/Source/CTest/cmCTestLaunch.h
@@ -0,0 +1,109 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestLaunch_h
+#define cmCTestLaunch_h
+
+#include "cmStandardIncludes.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+class cmXMLWriter;
+
+/** \class cmCTestLaunch
+ * \brief Launcher for make rules to report results for ctest
+ *
+ * This implements the 'ctest --launch' tool.
+ */
+class cmCTestLaunch
+{
+public:
+ /** Entry point from ctest executable main(). */
+ static int Main(int argc, const char* const argv[]);
+
+private:
+ // Initialize the launcher from its command line.
+ cmCTestLaunch(int argc, const char* const* argv);
+ ~cmCTestLaunch();
+
+ // Run the real command.
+ int Run();
+ void RunChild();
+
+ // Methods to check the result of the real command.
+ bool IsError() const;
+ bool CheckResults();
+
+ // Launcher options specified before the real command.
+ std::string OptionOutput;
+ std::string OptionSource;
+ std::string OptionLanguage;
+ std::string OptionTargetName;
+ std::string OptionTargetType;
+ std::string OptionBuildDir;
+ std::string OptionFilterPrefix;
+ bool ParseArguments(int argc, const char* const* argv);
+
+ // The real command line appearing after launcher arguments.
+ int RealArgC;
+ const char* const* RealArgV;
+ std::string CWD;
+
+ // The real command line after response file expansion.
+ std::vector<std::string> RealArgs;
+ void HandleRealArg(const char* arg);
+
+ // A hash of the real command line is unique and unlikely to collide.
+ std::string LogHash;
+ void ComputeFileNames();
+
+ bool Passthru;
+ struct cmsysProcess_s* Process;
+ int ExitCode;
+
+ // Temporary log files for stdout and stderr of real command.
+ std::string LogDir;
+ std::string LogOut;
+ std::string LogErr;
+ bool HaveOut;
+ bool HaveErr;
+
+ // Labels associated with the build rule.
+ std::set<std::string> Labels;
+ void LoadLabels();
+ bool SourceMatches(std::string const& lhs, std::string const& rhs);
+
+ // Regular expressions to match warnings and their exceptions.
+ bool ScrapeRulesLoaded;
+ std::vector<cmsys::RegularExpression> RegexWarning;
+ std::vector<cmsys::RegularExpression> RegexWarningSuppress;
+ void LoadScrapeRules();
+ void LoadScrapeRules(const char* purpose,
+ std::vector<cmsys::RegularExpression>& regexps);
+ bool ScrapeLog(std::string const& fname);
+ bool Match(std::string const& line,
+ std::vector<cmsys::RegularExpression>& regexps);
+ bool MatchesFilterPrefix(std::string const& line) const;
+
+ // Methods to generate the xml fragment.
+ void WriteXML();
+ void WriteXMLAction(cmXMLWriter& xml);
+ void WriteXMLCommand(cmXMLWriter& xml);
+ void WriteXMLResult(cmXMLWriter& xml);
+ void WriteXMLLabels(cmXMLWriter& xml);
+ void DumpFileToXML(cmXMLWriter& xml, std::string const& fname);
+
+ // Configuration
+ void LoadConfig();
+ std::string SourceDir;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestMemCheckCommand.cxx b/Source/CTest/cmCTestMemCheckCommand.cxx
new file mode 100644
index 0000000..d53dcd0
--- /dev/null
+++ b/Source/CTest/cmCTestMemCheckCommand.cxx
@@ -0,0 +1,39 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestMemCheckCommand.h"
+
+#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
+
+cmCTestGenericHandler* cmCTestMemCheckCommand::InitializeActualHandler()
+{
+ cmCTestGenericHandler* handler =
+ this->CTest->GetInitializedHandler("memcheck");
+
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckType", "CTEST_MEMORYCHECK_TYPE", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckSanitizerOptions",
+ "CTEST_MEMORYCHECK_SANITIZER_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckCommand", "CTEST_MEMORYCHECK_COMMAND",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckCommandOptions",
+ "CTEST_MEMORYCHECK_COMMAND_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckSuppressionFile",
+ "CTEST_MEMORYCHECK_SUPPRESSIONS_FILE", this->Quiet);
+
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
diff --git a/Source/CTest/cmCTestMemCheckCommand.h b/Source/CTest/cmCTestMemCheckCommand.h
new file mode 100644
index 0000000..2ba33ae
--- /dev/null
+++ b/Source/CTest/cmCTestMemCheckCommand.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestMemCheckCommand_h
+#define cmCTestMemCheckCommand_h
+
+#include "cmCTestTestCommand.h"
+
+class cmCTestGenericHandler;
+
+/** \class cmCTestMemCheck
+ * \brief Run a ctest script
+ *
+ * cmCTestMemCheckCommand defineds the command to test the project.
+ */
+class cmCTestMemCheckCommand : public cmCTestTestCommand
+{
+public:
+ cmCTestMemCheckCommand() {}
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestMemCheckCommand* ni = new cmCTestMemCheckCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return ni;
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "ctest_memcheck"; }
+
+ cmTypeMacro(cmCTestMemCheckCommand, cmCTestTestCommand);
+
+protected:
+ cmCTestGenericHandler* InitializeActualHandler() CM_OVERRIDE;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx
new file mode 100644
index 0000000..dfa8a1a
--- /dev/null
+++ b/Source/CTest/cmCTestMemCheckHandler.cxx
@@ -0,0 +1,1071 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCTestMemCheckHandler.h"
+
+#include "cmCTest.h"
+#include "cmGeneratedFileStream.h"
+#include "cmMakefile.h"
+#include "cmXMLParser.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+#include <cmsys/Base64.h>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/Process.h>
+#include <cmsys/RegularExpression.hxx>
+
+#include <float.h>
+#include <math.h>
+#include <stdlib.h>
+
+struct CatToErrorType
+{
+ const char* ErrorCategory;
+ int ErrorCode;
+};
+
+static CatToErrorType cmCTestMemCheckBoundsChecker[] = {
+ // Error tags
+ { "Write Overrun", cmCTestMemCheckHandler::ABW },
+ { "Read Overrun", cmCTestMemCheckHandler::ABR },
+ { "Memory Overrun", cmCTestMemCheckHandler::ABW },
+ { "Allocation Conflict", cmCTestMemCheckHandler::FMM },
+ { "Bad Pointer Use", cmCTestMemCheckHandler::FMW },
+ { "Dangling Pointer", cmCTestMemCheckHandler::FMR },
+ { CM_NULLPTR, 0 }
+};
+
+static void xmlReportError(int line, const char* msg, void* data)
+{
+ cmCTest* ctest = (cmCTest*)data;
+ cmCTestLog(ctest, ERROR_MESSAGE, "Error parsing XML in stream at line "
+ << line << ": " << msg << std::endl);
+}
+
+// parse the xml file containing the results of last BoundsChecker run
+class cmBoundsCheckerParser : public cmXMLParser
+{
+public:
+ cmBoundsCheckerParser(cmCTest* c)
+ {
+ this->CTest = c;
+ this->SetErrorCallback(xmlReportError, (void*)c);
+ }
+ void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
+ {
+ if (name == "MemoryLeak" || name == "ResourceLeak") {
+ this->Errors.push_back(cmCTestMemCheckHandler::MLK);
+ } else if (name == "Error" || name == "Dangling Pointer") {
+ this->ParseError(atts);
+ }
+ // Create the log
+ std::ostringstream ostr;
+ ostr << name << ":\n";
+ int i = 0;
+ for (; atts[i] != CM_NULLPTR; i += 2) {
+ ostr << " " << atts[i] << " - " << atts[i + 1] << "\n";
+ }
+ ostr << "\n";
+ this->Log += ostr.str();
+ }
+ void EndElement(const std::string&) CM_OVERRIDE {}
+
+ const char* GetAttribute(const char* name, const char** atts)
+ {
+ int i = 0;
+ for (; atts[i] != CM_NULLPTR; ++i) {
+ if (strcmp(name, atts[i]) == 0) {
+ return atts[i + 1];
+ }
+ }
+ return CM_NULLPTR;
+ }
+ void ParseError(const char** atts)
+ {
+ CatToErrorType* ptr = cmCTestMemCheckBoundsChecker;
+ const char* cat = this->GetAttribute("ErrorCategory", atts);
+ if (!cat) {
+ this->Errors.push_back(cmCTestMemCheckHandler::ABW); // do not know
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "No Category found in Bounds checker XML\n");
+ return;
+ }
+ while (ptr->ErrorCategory && cat) {
+ if (strcmp(ptr->ErrorCategory, cat) == 0) {
+ this->Errors.push_back(ptr->ErrorCode);
+ return; // found it we are done
+ }
+ ptr++;
+ }
+ if (ptr->ErrorCategory) {
+ this->Errors.push_back(cmCTestMemCheckHandler::ABW); // do not know
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Found unknown Bounds Checker error " << ptr->ErrorCategory
+ << std::endl);
+ }
+ }
+ cmCTest* CTest;
+ std::vector<int> Errors;
+ std::string Log;
+};
+
+#define BOUNDS_CHECKER_MARKER \
+ "******######*****Begin BOUNDS CHECKER XML******######******"
+
+cmCTestMemCheckHandler::cmCTestMemCheckHandler()
+{
+ this->MemCheck = true;
+ this->CustomMaximumPassedTestOutputSize = 0;
+ this->CustomMaximumFailedTestOutputSize = 0;
+ this->LogWithPID = false;
+}
+
+void cmCTestMemCheckHandler::Initialize()
+{
+ this->Superclass::Initialize();
+ this->LogWithPID = false;
+ this->CustomMaximumPassedTestOutputSize = 0;
+ this->CustomMaximumFailedTestOutputSize = 0;
+ this->MemoryTester = "";
+ this->MemoryTesterDynamicOptions.clear();
+ this->MemoryTesterOptions.clear();
+ this->MemoryTesterStyle = UNKNOWN;
+ this->MemoryTesterOutputFile = "";
+}
+
+int cmCTestMemCheckHandler::PreProcessHandler()
+{
+ if (!this->InitializeMemoryChecking()) {
+ return 0;
+ }
+
+ if (!this->ExecuteCommands(this->CustomPreMemCheck)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem executing pre-memcheck command(s)." << std::endl);
+ return 0;
+ }
+ return 1;
+}
+
+int cmCTestMemCheckHandler::PostProcessHandler()
+{
+ if (!this->ExecuteCommands(this->CustomPostMemCheck)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem executing post-memcheck command(s)." << std::endl);
+ return 0;
+ }
+ return 1;
+}
+
+void cmCTestMemCheckHandler::GenerateTestCommand(
+ std::vector<std::string>& args, int test)
+{
+ std::vector<std::string>::size_type pp;
+ std::string index;
+ std::ostringstream stream;
+ std::string memcheckcommand =
+ cmSystemTools::ConvertToOutputPath(this->MemoryTester.c_str());
+ stream << test;
+ index = stream.str();
+ for (pp = 0; pp < this->MemoryTesterDynamicOptions.size(); pp++) {
+ std::string arg = this->MemoryTesterDynamicOptions[pp];
+ std::string::size_type pos = arg.find("??");
+ if (pos != std::string::npos) {
+ arg.replace(pos, 2, index);
+ }
+ args.push_back(arg);
+ memcheckcommand += " \"";
+ memcheckcommand += arg;
+ memcheckcommand += "\"";
+ }
+ // Create a copy of the memory tester environment variable.
+ // This is used for memory testing programs that pass options
+ // via environment varaibles.
+ std::string memTesterEnvironmentVariable =
+ this->MemoryTesterEnvironmentVariable;
+ for (pp = 0; pp < this->MemoryTesterOptions.size(); pp++) {
+ if (!memTesterEnvironmentVariable.empty()) {
+ // If we are using env to pass options, append all the options to
+ // this string with space separation.
+ memTesterEnvironmentVariable += " " + this->MemoryTesterOptions[pp];
+ }
+ // for regular options just add them to args and memcheckcommand
+ // which is just used for display
+ else {
+ args.push_back(this->MemoryTesterOptions[pp]);
+ memcheckcommand += " \"";
+ memcheckcommand += this->MemoryTesterOptions[pp];
+ memcheckcommand += "\"";
+ }
+ }
+ // if this is an env option type, then add the env string as a single
+ // argument.
+ if (!memTesterEnvironmentVariable.empty()) {
+ std::string::size_type pos = memTesterEnvironmentVariable.find("??");
+ if (pos != std::string::npos) {
+ memTesterEnvironmentVariable.replace(pos, 2, index);
+ }
+ memcheckcommand += " " + memTesterEnvironmentVariable;
+ args.push_back(memTesterEnvironmentVariable);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Memory check command: " << memcheckcommand << std::endl,
+ this->Quiet);
+}
+
+void cmCTestMemCheckHandler::InitializeResultsVectors()
+{
+ // fill these members
+ // cmsys::vector<std::string> ResultStrings;
+ // cmsys::vector<std::string> ResultStringsLong;
+ // cmsys::vector<int> GlobalResults;
+ this->ResultStringsLong.clear();
+ this->ResultStrings.clear();
+ this->GlobalResults.clear();
+ // If we are working with style checkers that dynamically fill
+ // the results strings then return.
+ if (this->MemoryTesterStyle > cmCTestMemCheckHandler::BOUNDS_CHECKER) {
+ return;
+ }
+
+ // define the standard set of errors
+ //----------------------------------------------------------------------
+ static const char* cmCTestMemCheckResultStrings[] = {
+ "ABR", "ABW", "ABWL", "COR", "EXU", "FFM", "FIM", "FMM",
+ "FMR", "FMW", "FUM", "IPR", "IPW", "MAF", "MLK", "MPK",
+ "NPR", "ODS", "PAR", "PLK", "UMC", "UMR", CM_NULLPTR
+ };
+ static const char* cmCTestMemCheckResultLongStrings[] = {
+ "Threading Problem",
+ "ABW",
+ "ABWL",
+ "COR",
+ "EXU",
+ "FFM",
+ "FIM",
+ "Mismatched deallocation",
+ "FMR",
+ "FMW",
+ "FUM",
+ "IPR",
+ "IPW",
+ "MAF",
+ "Memory Leak",
+ "Potential Memory Leak",
+ "NPR",
+ "ODS",
+ "Invalid syscall param",
+ "PLK",
+ "Uninitialized Memory Conditional",
+ "Uninitialized Memory Read",
+ CM_NULLPTR
+ };
+ this->GlobalResults.clear();
+ for (int i = 0; cmCTestMemCheckResultStrings[i] != CM_NULLPTR; ++i) {
+ this->ResultStrings.push_back(cmCTestMemCheckResultStrings[i]);
+ this->ResultStringsLong.push_back(cmCTestMemCheckResultLongStrings[i]);
+ this->GlobalResults.push_back(0);
+ }
+}
+
+void cmCTestMemCheckHandler::PopulateCustomVectors(cmMakefile* mf)
+{
+ this->cmCTestTestHandler::PopulateCustomVectors(mf);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_MEMCHECK",
+ this->CustomPreMemCheck);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_POST_MEMCHECK",
+ this->CustomPostMemCheck);
+
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_MEMCHECK_IGNORE",
+ this->CustomTestsIgnore);
+ std::string cmake = cmSystemTools::GetCMakeCommand();
+ this->CTest->SetCTestConfiguration("CMakeCommand", cmake.c_str(),
+ this->Quiet);
+}
+
+void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml)
+{
+ if (!this->CTest->GetProduceXML()) {
+ return;
+ }
+ this->CTest->StartXML(xml, this->AppendXML);
+ xml.StartElement("DynamicAnalysis");
+ switch (this->MemoryTesterStyle) {
+ case cmCTestMemCheckHandler::VALGRIND:
+ xml.Attribute("Checker", "Valgrind");
+ break;
+ case cmCTestMemCheckHandler::PURIFY:
+ xml.Attribute("Checker", "Purify");
+ break;
+ case cmCTestMemCheckHandler::BOUNDS_CHECKER:
+ xml.Attribute("Checker", "BoundsChecker");
+ break;
+ case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+ xml.Attribute("Checker", "AddressSanitizer");
+ break;
+ case cmCTestMemCheckHandler::THREAD_SANITIZER:
+ xml.Attribute("Checker", "ThreadSanitizer");
+ break;
+ case cmCTestMemCheckHandler::MEMORY_SANITIZER:
+ xml.Attribute("Checker", "MemorySanitizer");
+ break;
+ case cmCTestMemCheckHandler::UB_SANITIZER:
+ xml.Attribute("Checker", "UndefinedBehaviorSanitizer");
+ break;
+ default:
+ xml.Attribute("Checker", "Unknown");
+ }
+
+ xml.Element("StartDateTime", this->StartTest);
+ xml.Element("StartTestTime", this->StartTestTime);
+ xml.StartElement("TestList");
+ cmCTestMemCheckHandler::TestResultsVector::size_type cc;
+ for (cc = 0; cc < this->TestResults.size(); cc++) {
+ cmCTestTestResult* result = &this->TestResults[cc];
+ std::string testPath = result->Path + "/" + result->Name;
+ xml.Element("Test", this->CTest->GetShortPathToFile(testPath.c_str()));
+ }
+ xml.EndElement(); // TestList
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "-- Processing memory checking output: ", this->Quiet);
+ size_t total = this->TestResults.size();
+ size_t step = total / 10;
+ size_t current = 0;
+ for (cc = 0; cc < this->TestResults.size(); cc++) {
+ cmCTestTestResult* result = &this->TestResults[cc];
+ std::string memcheckstr;
+ std::vector<int> memcheckresults(this->ResultStrings.size(), 0);
+ bool res = this->ProcessMemCheckOutput(result->Output, memcheckstr,
+ memcheckresults);
+ if (res && result->Status == cmCTestMemCheckHandler::COMPLETED) {
+ continue;
+ }
+ this->CleanTestOutput(
+ memcheckstr,
+ static_cast<size_t>(this->CustomMaximumFailedTestOutputSize));
+ this->WriteTestResultHeader(xml, result);
+ xml.StartElement("Results");
+ for (std::vector<int>::size_type kk = 0; kk < memcheckresults.size();
+ ++kk) {
+ if (memcheckresults[kk]) {
+ xml.StartElement("Defect");
+ xml.Attribute("type", this->ResultStringsLong[kk]);
+ xml.Content(memcheckresults[kk]);
+ xml.EndElement(); // Defect
+ }
+ this->GlobalResults[kk] += memcheckresults[kk];
+ }
+ xml.EndElement(); // Results
+
+ xml.StartElement("Log");
+ if (this->CTest->ShouldCompressMemCheckOutput()) {
+ this->CTest->CompressString(memcheckstr);
+ xml.Attribute("compression", "gzip");
+ xml.Attribute("encoding", "base64");
+ }
+ xml.Content(memcheckstr);
+ xml.EndElement(); // Log
+
+ this->WriteTestResultFooter(xml, result);
+ if (current < cc) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "#" << std::flush,
+ this->Quiet);
+ current += step;
+ }
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, std::endl, this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "Memory checking results:" << std::endl, this->Quiet);
+ xml.StartElement("DefectList");
+ for (cc = 0; cc < this->GlobalResults.size(); cc++) {
+ if (this->GlobalResults[cc]) {
+#ifdef cerr
+#undef cerr
+#endif
+ std::cerr.width(35);
+#define cerr no_cerr
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ this->ResultStringsLong[cc]
+ << " - " << this->GlobalResults[cc] << std::endl,
+ this->Quiet);
+ xml.StartElement("Defect");
+ xml.Attribute("Type", this->ResultStringsLong[cc]);
+ xml.EndElement();
+ }
+ }
+ xml.EndElement(); // DefectList
+
+ xml.Element("EndDateTime", this->EndTest);
+ xml.Element("EndTestTime", this->EndTestTime);
+ xml.Element("ElapsedMinutes",
+ static_cast<int>(this->ElapsedTestingTime / 6) / 10.0);
+
+ xml.EndElement(); // DynamicAnalysis
+ this->CTest->EndXML(xml);
+}
+
+bool cmCTestMemCheckHandler::InitializeMemoryChecking()
+{
+ this->MemoryTesterEnvironmentVariable = "";
+ this->MemoryTester = "";
+ // Setup the command
+ if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("MemoryCheckCommand").c_str())) {
+ this->MemoryTester =
+ this->CTest->GetCTestConfiguration("MemoryCheckCommand");
+ std::string testerName =
+ cmSystemTools::GetFilenameName(this->MemoryTester);
+ // determine the checker type
+ if (testerName.find("valgrind") != std::string::npos ||
+ this->CTest->GetCTestConfiguration("MemoryCheckType") == "Valgrind") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
+ } else if (testerName.find("purify") != std::string::npos) {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
+ } else if (testerName.find("BC") != std::string::npos) {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
+ } else {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::UNKNOWN;
+ }
+ } else if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("PurifyCommand").c_str())) {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("PurifyCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
+ } else if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("ValgrindCommand")
+ .c_str())) {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("ValgrindCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
+ } else if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("BoundsCheckerCommand")
+ .c_str())) {
+ this->MemoryTester =
+ this->CTest->GetCTestConfiguration("BoundsCheckerCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "AddressSanitizer") {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::ADDRESS_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "ThreadSanitizer") {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::THREAD_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "MemorySanitizer") {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::MEMORY_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "UndefinedBehaviorSanitizer") {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::UB_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ // Check the MemoryCheckType
+ if (this->MemoryTesterStyle == cmCTestMemCheckHandler::UNKNOWN) {
+ std::string checkType =
+ this->CTest->GetCTestConfiguration("MemoryCheckType");
+ if (checkType == "Purify") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
+ } else if (checkType == "BoundsChecker") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
+ } else if (checkType == "Valgrind") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
+ }
+ }
+ if (this->MemoryTester.empty()) {
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "Memory checker (MemoryCheckCommand) "
+ "not set, or cannot find the specified program."
+ << std::endl,
+ this->Quiet);
+ return false;
+ }
+
+ // Setup the options
+ std::string memoryTesterOptions;
+ if (!this->CTest->GetCTestConfiguration("MemoryCheckCommandOptions")
+ .empty()) {
+ memoryTesterOptions =
+ this->CTest->GetCTestConfiguration("MemoryCheckCommandOptions");
+ } else if (!this->CTest->GetCTestConfiguration("ValgrindCommandOptions")
+ .empty()) {
+ memoryTesterOptions =
+ this->CTest->GetCTestConfiguration("ValgrindCommandOptions");
+ }
+ this->MemoryTesterOptions =
+ cmSystemTools::ParseArguments(memoryTesterOptions.c_str());
+
+ this->MemoryTesterOutputFile =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/MemoryChecker.??.log";
+
+ switch (this->MemoryTesterStyle) {
+ case cmCTestMemCheckHandler::VALGRIND: {
+ if (this->MemoryTesterOptions.empty()) {
+ this->MemoryTesterOptions.push_back("-q");
+ this->MemoryTesterOptions.push_back("--tool=memcheck");
+ this->MemoryTesterOptions.push_back("--leak-check=yes");
+ this->MemoryTesterOptions.push_back("--show-reachable=yes");
+ this->MemoryTesterOptions.push_back("--num-callers=50");
+ }
+ if (!this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .empty()) {
+ if (!cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .c_str())) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find memory checker suppression file: "
+ << this->CTest->GetCTestConfiguration(
+ "MemoryCheckSuppressionFile")
+ << std::endl);
+ return false;
+ }
+ std::string suppressions = "--suppressions=" +
+ this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile");
+ this->MemoryTesterOptions.push_back(suppressions);
+ }
+ std::string outputFile = "--log-file=" + this->MemoryTesterOutputFile;
+ this->MemoryTesterDynamicOptions.push_back(outputFile);
+ break;
+ }
+ case cmCTestMemCheckHandler::PURIFY: {
+ std::string outputFile;
+#ifdef _WIN32
+ if (this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .size()) {
+ if (!cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .c_str())) {
+ cmCTestLog(
+ this->CTest, ERROR_MESSAGE,
+ "Cannot find memory checker suppression file: "
+ << this->CTest
+ ->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .c_str()
+ << std::endl);
+ return false;
+ }
+ std::string filterFiles = "/FilterFiles=" +
+ this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile");
+ this->MemoryTesterOptions.push_back(filterFiles);
+ }
+ outputFile = "/SAVETEXTDATA=";
+#else
+ outputFile = "-log-file=";
+#endif
+ outputFile += this->MemoryTesterOutputFile;
+ this->MemoryTesterDynamicOptions.push_back(outputFile);
+ break;
+ }
+ case cmCTestMemCheckHandler::BOUNDS_CHECKER: {
+ this->BoundsCheckerXMLFile = this->MemoryTesterOutputFile;
+ std::string dpbdFile = this->CTest->GetBinaryDir() +
+ "/Testing/Temporary/MemoryChecker.??.DPbd";
+ this->BoundsCheckerDPBDFile = dpbdFile;
+ this->MemoryTesterDynamicOptions.push_back("/B");
+ this->MemoryTesterDynamicOptions.push_back(dpbdFile);
+ this->MemoryTesterDynamicOptions.push_back("/X");
+ this->MemoryTesterDynamicOptions.push_back(this->MemoryTesterOutputFile);
+ this->MemoryTesterOptions.push_back("/M");
+ break;
+ }
+ // these are almost the same but the env var used is different
+ case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+ case cmCTestMemCheckHandler::THREAD_SANITIZER:
+ case cmCTestMemCheckHandler::MEMORY_SANITIZER:
+ case cmCTestMemCheckHandler::UB_SANITIZER: {
+ // To pass arguments to ThreadSanitizer the environment variable
+ // TSAN_OPTIONS is used. This is done with the cmake -E env command.
+ // The MemoryTesterDynamicOptions is setup with the -E env
+ // Then the MemoryTesterEnvironmentVariable gets the
+ // TSAN_OPTIONS string with the log_path in it.
+ this->MemoryTesterDynamicOptions.push_back("-E");
+ this->MemoryTesterDynamicOptions.push_back("env");
+ std::string envVar;
+ std::string extraOptions =
+ this->CTest->GetCTestConfiguration("MemoryCheckSanitizerOptions");
+ if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::ADDRESS_SANITIZER) {
+ envVar = "ASAN_OPTIONS";
+ extraOptions += " detect_leaks=1";
+ } else if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::THREAD_SANITIZER) {
+ envVar = "TSAN_OPTIONS";
+ } else if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::MEMORY_SANITIZER) {
+ envVar = "MSAN_OPTIONS";
+ } else if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::UB_SANITIZER) {
+ envVar = "UBSAN_OPTIONS";
+ }
+ std::string outputFile =
+ envVar + "=log_path=\"" + this->MemoryTesterOutputFile + "\" ";
+ this->MemoryTesterEnvironmentVariable = outputFile + extraOptions;
+ break;
+ }
+ default:
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Do not understand memory checker: " << this->MemoryTester
+ << std::endl);
+ return false;
+ }
+
+ this->InitializeResultsVectors();
+ // std::vector<std::string>::size_type cc;
+ // for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
+ // {
+ // this->MemoryTesterGlobalResults[cc] = 0;
+ // }
+ return true;
+}
+
+bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str,
+ std::string& log,
+ std::vector<int>& results)
+{
+ if (this->MemoryTesterStyle == cmCTestMemCheckHandler::VALGRIND) {
+ return this->ProcessMemCheckValgrindOutput(str, log, results);
+ } else if (this->MemoryTesterStyle == cmCTestMemCheckHandler::PURIFY) {
+ return this->ProcessMemCheckPurifyOutput(str, log, results);
+ } else if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::ADDRESS_SANITIZER ||
+ this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::THREAD_SANITIZER ||
+ this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::MEMORY_SANITIZER ||
+ this->MemoryTesterStyle == cmCTestMemCheckHandler::UB_SANITIZER) {
+ return this->ProcessMemCheckSanitizerOutput(str, log, results);
+ } else if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::BOUNDS_CHECKER) {
+ return this->ProcessMemCheckBoundsCheckerOutput(str, log, results);
+ } else {
+ log.append("\nMemory checking style used was: ");
+ log.append("None that I know");
+ log = str;
+ }
+ return true;
+}
+
+std::vector<int>::size_type cmCTestMemCheckHandler::FindOrAddWarning(
+ const std::string& warning)
+{
+ for (std::vector<std::string>::size_type i = 0;
+ i < this->ResultStrings.size(); ++i) {
+ if (this->ResultStrings[i] == warning) {
+ return i;
+ }
+ }
+ this->GlobalResults.push_back(0); // this must stay the same size
+ this->ResultStrings.push_back(warning);
+ this->ResultStringsLong.push_back(warning);
+ return this->ResultStrings.size() - 1;
+}
+bool cmCTestMemCheckHandler::ProcessMemCheckSanitizerOutput(
+ const std::string& str, std::string& log, std::vector<int>& result)
+{
+ std::string regex;
+ switch (this->MemoryTesterStyle) {
+ case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+ regex = "ERROR: AddressSanitizer: (.*) on.*";
+ break;
+ case cmCTestMemCheckHandler::THREAD_SANITIZER:
+ regex = "WARNING: ThreadSanitizer: (.*) \\(pid=.*\\)";
+ break;
+ case cmCTestMemCheckHandler::MEMORY_SANITIZER:
+ regex = "WARNING: MemorySanitizer: (.*)";
+ break;
+ case cmCTestMemCheckHandler::UB_SANITIZER:
+ regex = "runtime error: (.*)";
+ break;
+ default:
+ break;
+ }
+ cmsys::RegularExpression sanitizerWarning(regex);
+ cmsys::RegularExpression leakWarning("(Direct|Indirect) leak of .*");
+ int defects = 0;
+ std::vector<std::string> lines;
+ cmSystemTools::Split(str.c_str(), lines);
+ std::ostringstream ostr;
+ log = "";
+ for (std::vector<std::string>::iterator i = lines.begin(); i != lines.end();
+ ++i) {
+ std::string resultFound;
+ if (leakWarning.find(*i)) {
+ resultFound = leakWarning.match(1) + " leak";
+ } else if (sanitizerWarning.find(*i)) {
+ resultFound = sanitizerWarning.match(1);
+ }
+ if (!resultFound.empty()) {
+ std::vector<int>::size_type idx = this->FindOrAddWarning(resultFound);
+ if (result.empty() || idx > result.size() - 1) {
+ result.push_back(1);
+ } else {
+ result[idx]++;
+ }
+ defects++;
+ ostr << "<b>" << this->ResultStrings[idx] << "</b> ";
+ }
+ ostr << *i << std::endl;
+ }
+ log = ostr.str();
+ return defects == 0;
+}
+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);
+ std::ostringstream ostr;
+ log = "";
+
+ cmsys::RegularExpression pfW("^\\[[WEI]\\] ([A-Z][A-Z][A-Z][A-Z]*): ");
+
+ int defects = 0;
+
+ for (std::vector<std::string>::iterator i = lines.begin(); i != lines.end();
+ ++i) {
+ std::vector<int>::size_type failure = this->ResultStrings.size();
+ if (pfW.find(*i)) {
+ std::vector<int>::size_type cc;
+ for (cc = 0; cc < this->ResultStrings.size(); cc++) {
+ if (pfW.match(1) == this->ResultStrings[cc]) {
+ failure = cc;
+ break;
+ }
+ }
+ if (cc == this->ResultStrings.size()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown Purify memory fault: "
+ << pfW.match(1) << std::endl);
+ ostr << "*** Unknown Purify memory fault: " << pfW.match(1)
+ << std::endl;
+ }
+ }
+ if (failure != this->ResultStrings.size()) {
+ ostr << "<b>" << this->ResultStrings[failure] << "</b> ";
+ results[failure]++;
+ defects++;
+ }
+ ostr << *i << std::endl;
+ }
+
+ log = ostr.str();
+ return defects == 0;
+}
+
+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);
+ bool unlimitedOutput = false;
+ if (str.find("CTEST_FULL_OUTPUT") != str.npos ||
+ this->CustomMaximumFailedTestOutputSize == 0) {
+ unlimitedOutput = true;
+ }
+
+ std::string::size_type cc;
+
+ std::ostringstream ostr;
+ log = "";
+
+ int defects = 0;
+
+ cmsys::RegularExpression valgrindLine("^==[0-9][0-9]*==");
+
+ cmsys::RegularExpression vgFIM(
+ "== .*Invalid free\\(\\) / delete / delete\\[\\]");
+ cmsys::RegularExpression vgFMM(
+ "== .*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,]+");
+ cmsys::RegularExpression vgMLK2(
+ "== .*[0-9,]+ \\([0-9,]+ direct, [0-9,]+ indirect\\)"
+ " bytes in [0-9,]+ blocks are definitely lost"
+ " in loss record [0-9,]+ of [0-9,]+");
+ cmsys::RegularExpression vgPAR(
+ "== .*Syscall param .* (contains|points to) unaddressable byte\\(s\\)");
+ cmsys::RegularExpression vgMPK1(
+ "== .*[0-9,]+ bytes in [0-9,]+ blocks are possibly lost in"
+ " loss record [0-9,]+ of [0-9,]+");
+ cmsys::RegularExpression vgMPK2(
+ "== .*[0-9,]+ bytes in [0-9,]+ blocks are still reachable"
+ " in loss record [0-9,]+ of [0-9,]+");
+ cmsys::RegularExpression vgUMC(
+ "== .*Conditional jump or move depends on uninitialised value\\(s\\)");
+ cmsys::RegularExpression vgUMR1(
+ "== .*Use of uninitialised value of size [0-9,]+");
+ cmsys::RegularExpression vgUMR2("== .*Invalid read of size [0-9,]+");
+ cmsys::RegularExpression vgUMR3("== .*Jump to the invalid address ");
+ cmsys::RegularExpression vgUMR4(
+ "== .*Syscall param .* contains "
+ "uninitialised or unaddressable byte\\(s\\)");
+ cmsys::RegularExpression vgUMR5("== .*Syscall param .* uninitialised");
+ cmsys::RegularExpression vgIPW("== .*Invalid write of size [0-9,]+");
+ cmsys::RegularExpression vgABR("== .*pthread_mutex_unlock: mutex is "
+ "locked by a different thread");
+ std::vector<std::string::size_type> nonValGrindOutput;
+ double sttime = cmSystemTools::GetTime();
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Start test: " << lines.size() << std::endl, this->Quiet);
+ std::string::size_type totalOutputSize = 0;
+ for (cc = 0; cc < lines.size(); cc++) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "test line " << lines[cc] << std::endl, this->Quiet);
+
+ if (valgrindLine.find(lines[cc])) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "valgrind line " << lines[cc] << std::endl,
+ this->Quiet);
+ int failure = cmCTestMemCheckHandler::NO_MEMORY_FAULT;
+ if (vgFIM.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::FIM;
+ } else if (vgFMM.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::FMM;
+ } else if (vgMLK1.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::MLK;
+ } else if (vgMLK2.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::MLK;
+ } else if (vgPAR.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::PAR;
+ } else if (vgMPK1.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::MPK;
+ } else if (vgMPK2.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::MPK;
+ } else if (vgUMC.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::UMC;
+ } else if (vgUMR1.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::UMR;
+ } else if (vgUMR2.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::UMR;
+ } else if (vgUMR3.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::UMR;
+ } else if (vgUMR4.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::UMR;
+ } else if (vgUMR5.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::UMR;
+ } else if (vgIPW.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::IPW;
+ } else if (vgABR.find(lines[cc])) {
+ failure = cmCTestMemCheckHandler::ABR;
+ }
+
+ if (failure != cmCTestMemCheckHandler::NO_MEMORY_FAULT) {
+ ostr << "<b>" << this->ResultStrings[failure] << "</b> ";
+ results[failure]++;
+ defects++;
+ }
+ totalOutputSize += lines[cc].size();
+ ostr << lines[cc] << std::endl;
+ } else {
+ nonValGrindOutput.push_back(cc);
+ }
+ }
+ // Now put all all the non valgrind output into the test output
+ // This should be last in case it gets truncated by the output
+ // limiting code
+ for (std::vector<std::string::size_type>::iterator i =
+ nonValGrindOutput.begin();
+ i != nonValGrindOutput.end(); ++i) {
+ totalOutputSize += lines[*i].size();
+ ostr << lines[*i] << std::endl;
+ if (!unlimitedOutput &&
+ totalOutputSize >
+ static_cast<size_t>(this->CustomMaximumFailedTestOutputSize)) {
+ ostr << "....\n";
+ ostr << "Test Output for this test has been truncated see testing"
+ " machine logs for full output,\n";
+ ostr << "or put CTEST_FULL_OUTPUT in the output of "
+ "this test program.\n";
+ break; // stop the copy of output if we are full
+ }
+ }
+ cmCTestOptionalLog(this->CTest, DEBUG, "End test (elapsed: "
+ << (cmSystemTools::GetTime() - sttime) << std::endl,
+ this->Quiet);
+ log = ostr.str();
+ return defects == 0;
+}
+
+bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput(
+ const std::string& str, std::string& log, std::vector<int>& results)
+{
+ log = "";
+ double sttime = cmSystemTools::GetTime();
+ std::vector<std::string> lines;
+ cmSystemTools::Split(str.c_str(), lines);
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Start test: " << lines.size() << std::endl, this->Quiet);
+ std::vector<std::string>::size_type cc;
+ for (cc = 0; cc < lines.size(); cc++) {
+ if (lines[cc] == BOUNDS_CHECKER_MARKER) {
+ break;
+ }
+ }
+ cmBoundsCheckerParser parser(this->CTest);
+ parser.InitializeParser();
+ if (cc < lines.size()) {
+ for (cc++; cc < lines.size(); ++cc) {
+ std::string& theLine = lines[cc];
+ // check for command line arguments that are not escaped
+ // correctly by BC
+ if (theLine.find("TargetArgs=") != theLine.npos) {
+ // skip this because BC gets it wrong and we can't parse it
+ } else if (!parser.ParseChunk(theLine.c_str(), theLine.size())) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error in ParseChunk: " << theLine << std::endl);
+ }
+ }
+ }
+ int defects = 0;
+ for (cc = 0; cc < parser.Errors.size(); ++cc) {
+ results[parser.Errors[cc]]++;
+ defects++;
+ }
+ cmCTestOptionalLog(this->CTest, DEBUG, "End test (elapsed: "
+ << (cmSystemTools::GetTime() - sttime) << std::endl,
+ this->Quiet);
+ if (defects) {
+ // only put the output of Bounds Checker if there were
+ // errors or leaks detected
+ log = parser.Log;
+ return false;
+ }
+ return true;
+}
+
+// PostProcessTest memcheck results
+void cmCTestMemCheckHandler::PostProcessTest(cmCTestTestResult& res, int test)
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "PostProcessTest memcheck results for : " << res.Name
+ << std::endl,
+ this->Quiet);
+ if (this->MemoryTesterStyle == cmCTestMemCheckHandler::BOUNDS_CHECKER) {
+ this->PostProcessBoundsCheckerTest(res, test);
+ } else {
+ std::vector<std::string> files;
+ this->TestOutputFileNames(test, files);
+ for (std::vector<std::string>::iterator i = files.begin();
+ i != files.end(); ++i) {
+ this->AppendMemTesterOutput(res, *i);
+ }
+ }
+}
+
+// This method puts the bounds checker output file into the output
+// for the test
+void cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(
+ cmCTestTestResult& res, int test)
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "PostProcessBoundsCheckerTest for : " << res.Name
+ << std::endl,
+ this->Quiet);
+ std::vector<std::string> files;
+ this->TestOutputFileNames(test, files);
+ if (files.empty()) {
+ return;
+ }
+ std::string ofile = files[0];
+ if (ofile.empty()) {
+ return;
+ }
+ // put a scope around this to close ifs so the file can be removed
+ {
+ cmsys::ifstream ifs(ofile.c_str());
+ if (!ifs) {
+ std::string log = "Cannot read memory tester output file: " + ofile;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl);
+ return;
+ }
+ res.Output += BOUNDS_CHECKER_MARKER;
+ res.Output += "\n";
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ res.Output += line;
+ res.Output += "\n";
+ }
+ }
+ cmSystemTools::Delay(1000);
+ cmSystemTools::RemoveFile(this->BoundsCheckerDPBDFile);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Remove: " << this->BoundsCheckerDPBDFile << std::endl,
+ this->Quiet);
+ cmSystemTools::RemoveFile(this->BoundsCheckerXMLFile);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Remove: " << this->BoundsCheckerXMLFile << std::endl,
+ this->Quiet);
+}
+
+void cmCTestMemCheckHandler::AppendMemTesterOutput(cmCTestTestResult& res,
+ std::string const& ofile)
+{
+ if (ofile.empty()) {
+ return;
+ }
+ // put ifs in scope so file can be deleted if needed
+ {
+ cmsys::ifstream ifs(ofile.c_str());
+ if (!ifs) {
+ std::string log = "Cannot read memory tester output file: " + ofile;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl);
+ return;
+ }
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ res.Output += line;
+ res.Output += "\n";
+ }
+ }
+ if (this->LogWithPID) {
+ cmSystemTools::RemoveFile(ofile);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Remove: " << ofile << "\n", this->Quiet);
+ }
+}
+
+void cmCTestMemCheckHandler::TestOutputFileNames(
+ int test, std::vector<std::string>& files)
+{
+ std::string index;
+ std::ostringstream stream;
+ stream << test;
+ index = stream.str();
+ std::string ofile = this->MemoryTesterOutputFile;
+ std::string::size_type pos = ofile.find("??");
+ ofile.replace(pos, 2, index);
+ if (this->LogWithPID) {
+ ofile += ".*";
+ cmsys::Glob g;
+ g.FindFiles(ofile);
+ if (g.GetFiles().empty()) {
+ std::string log = "Cannot find memory tester output file: " + ofile;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl);
+ ofile = "";
+ } else {
+ files = g.GetFiles();
+ return;
+ }
+ } else if (!cmSystemTools::FileExists(ofile.c_str())) {
+ std::string log = "Cannot find memory tester output file: " + ofile;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl);
+ ofile = "";
+ }
+ files.push_back(ofile);
+}
diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h
new file mode 100644
index 0000000..a005d54
--- /dev/null
+++ b/Source/CTest/cmCTestMemCheckHandler.h
@@ -0,0 +1,160 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCTestMemCheckHandler_h
+#define cmCTestMemCheckHandler_h
+
+#include "cmCTestTestHandler.h"
+
+#include "cmListFileCache.h"
+#include <string>
+#include <vector>
+
+class cmMakefile;
+class cmXMLWriter;
+
+/** \class cmCTestMemCheckHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestMemCheckHandler : public cmCTestTestHandler
+{
+ friend class cmCTestRunTest;
+
+public:
+ cmTypeMacro(cmCTestMemCheckHandler, cmCTestTestHandler);
+
+ void PopulateCustomVectors(cmMakefile* mf) CM_OVERRIDE;
+
+ cmCTestMemCheckHandler();
+
+ void Initialize() CM_OVERRIDE;
+
+protected:
+ int PreProcessHandler() CM_OVERRIDE;
+ int PostProcessHandler() CM_OVERRIDE;
+ void GenerateTestCommand(std::vector<std::string>& args,
+ int test) CM_OVERRIDE;
+
+private:
+ enum
+ { // Memory checkers
+ UNKNOWN = 0,
+ VALGRIND,
+ PURIFY,
+ BOUNDS_CHECKER,
+ // checkers after here do not use the standard error list
+ ADDRESS_SANITIZER,
+ THREAD_SANITIZER,
+ MEMORY_SANITIZER,
+ UB_SANITIZER
+ };
+
+public:
+ enum
+ { // Memory faults
+ ABR = 0,
+ ABW,
+ ABWL,
+ COR,
+ EXU,
+ FFM,
+ FIM,
+ FMM,
+ FMR,
+ FMW,
+ FUM,
+ IPR,
+ IPW,
+ MAF,
+ MLK,
+ MPK,
+ NPR,
+ ODS,
+ PAR,
+ PLK,
+ UMC,
+ UMR,
+ NO_MEMORY_FAULT
+ };
+
+private:
+ enum
+ { // Program statuses
+ NOT_RUN = 0,
+ TIMEOUT,
+ SEGFAULT,
+ ILLEGAL,
+ INTERRUPT,
+ NUMERICAL,
+ OTHER_FAULT,
+ FAILED,
+ BAD_COMMAND,
+ COMPLETED
+ };
+ std::string BoundsCheckerDPBDFile;
+ std::string BoundsCheckerXMLFile;
+ std::string MemoryTester;
+ std::vector<std::string> MemoryTesterDynamicOptions;
+ std::vector<std::string> MemoryTesterOptions;
+ int MemoryTesterStyle;
+ std::string MemoryTesterOutputFile;
+ std::string MemoryTesterEnvironmentVariable;
+ // these are used to store the types of errors that can show up
+ std::vector<std::string> ResultStrings;
+ std::vector<std::string> ResultStringsLong;
+ std::vector<int> GlobalResults;
+ bool LogWithPID; // does log file add pid
+
+ std::vector<int>::size_type FindOrAddWarning(const std::string& warning);
+ // initialize the ResultStrings and ResultStringsLong for
+ // this type of checker
+ void InitializeResultsVectors();
+
+ ///! Initialize memory checking subsystem.
+ bool InitializeMemoryChecking();
+
+ /**
+ * Generate the Dart compatible output
+ */
+ void GenerateDartOutput(cmXMLWriter& xml) CM_OVERRIDE;
+
+ std::vector<std::string> CustomPreMemCheck;
+ std::vector<std::string> CustomPostMemCheck;
+
+ //! Parse Valgrind/Purify/Bounds Checker result out of the output
+ // string. After running, log holds the output and results hold the
+ // different memmory errors.
+ bool ProcessMemCheckOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckValgrindOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckPurifyOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckSanitizerOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckBoundsCheckerOutput(const std::string& str,
+ std::string& log,
+ std::vector<int>& results);
+
+ void PostProcessTest(cmCTestTestResult& res, int test);
+ void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test);
+
+ ///! append MemoryTesterOutputFile to the test log
+ void AppendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res,
+ std::string const& filename);
+
+ ///! generate the output filename for the given test index
+ void TestOutputFileNames(int test, std::vector<std::string>& files);
+};
+
+#endif
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
new file mode 100644
index 0000000..ae97d32
--- /dev/null
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -0,0 +1,836 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestMultiProcessHandler.h"
+
+#include "cmCTest.h"
+#include "cmCTestScriptHandler.h"
+#include "cmProcess.h"
+#include "cmStandardIncludes.h"
+#include "cmSystemTools.h"
+#include <cmsys/FStream.hxx>
+#include <cmsys/SystemInformation.hxx>
+#include <float.h>
+#include <list>
+#include <math.h>
+#include <stack>
+#include <stdlib.h>
+
+class TestComparator
+{
+public:
+ TestComparator(cmCTestMultiProcessHandler* handler)
+ : Handler(handler)
+ {
+ }
+ ~TestComparator() {}
+
+ // Sorts tests in descending order of cost
+ bool operator()(int index1, int index2) const
+ {
+ return Handler->Properties[index1]->Cost >
+ Handler->Properties[index2]->Cost;
+ }
+
+private:
+ cmCTestMultiProcessHandler* Handler;
+};
+
+cmCTestMultiProcessHandler::cmCTestMultiProcessHandler()
+{
+ this->ParallelLevel = 1;
+ this->TestLoad = 0;
+ this->Completed = 0;
+ this->RunningCount = 0;
+ this->StopTimePassed = false;
+ this->HasCycles = false;
+ this->SerialTestRunning = false;
+}
+
+cmCTestMultiProcessHandler::~cmCTestMultiProcessHandler()
+{
+}
+
+// Set the tests
+void cmCTestMultiProcessHandler::SetTests(TestMap& tests,
+ PropertiesMap& properties)
+{
+ this->Tests = tests;
+ this->Properties = properties;
+ this->Total = this->Tests.size();
+ // set test run map to false for all
+ for (TestMap::iterator i = this->Tests.begin(); i != this->Tests.end();
+ ++i) {
+ this->TestRunningMap[i->first] = false;
+ this->TestFinishMap[i->first] = false;
+ }
+ if (!this->CTest->GetShowOnly()) {
+ this->ReadCostData();
+ this->HasCycles = !this->CheckCycles();
+ if (this->HasCycles) {
+ return;
+ }
+ this->CreateTestCostList();
+ }
+}
+
+// Set the max number of tests that can be run at the same time.
+void cmCTestMultiProcessHandler::SetParallelLevel(size_t level)
+{
+ this->ParallelLevel = level < 1 ? 1 : level;
+}
+
+void cmCTestMultiProcessHandler::SetTestLoad(unsigned long load)
+{
+ this->TestLoad = load;
+}
+
+void cmCTestMultiProcessHandler::RunTests()
+{
+ this->CheckResume();
+ if (this->HasCycles) {
+ return;
+ }
+ this->TestHandler->SetMaxIndex(this->FindMaxIndex());
+ this->StartNextTests();
+ while (!this->Tests.empty()) {
+ if (this->StopTimePassed) {
+ return;
+ }
+ this->CheckOutput();
+ this->StartNextTests();
+ }
+ // let all running tests finish
+ while (this->CheckOutput()) {
+ }
+ this->MarkFinished();
+ this->UpdateCostData();
+}
+
+void cmCTestMultiProcessHandler::StartTestProcess(int test)
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "test " << test << "\n", this->Quiet);
+ this->TestRunningMap[test] = true; // mark the test as running
+ // now remove the test itself
+ this->EraseTest(test);
+ this->RunningCount += GetProcessorsUsed(test);
+
+ cmCTestRunTest* testRun = new cmCTestRunTest(this->TestHandler);
+ if (this->CTest->GetRepeatUntilFail()) {
+ testRun->SetRunUntilFailOn();
+ testRun->SetNumberOfRuns(this->CTest->GetTestRepeat());
+ }
+ testRun->SetIndex(test);
+ testRun->SetTestProperties(this->Properties[test]);
+
+ std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::ChangeDirectory(this->Properties[test]->Directory);
+
+ // Lock the resources we'll be using
+ this->LockResources(test);
+
+ if (testRun->StartTest(this->Total)) {
+ this->RunningTests.insert(testRun);
+ } else if (testRun->IsStopTimePassed()) {
+ this->StopTimePassed = true;
+ delete testRun;
+ return;
+ } else {
+
+ for (TestMap::iterator j = this->Tests.begin(); j != this->Tests.end();
+ ++j) {
+ j->second.erase(test);
+ }
+
+ this->UnlockResources(test);
+ this->Completed++;
+ this->TestFinishMap[test] = true;
+ this->TestRunningMap[test] = false;
+ this->RunningCount -= GetProcessorsUsed(test);
+ testRun->EndTest(this->Completed, this->Total, false);
+ this->Failed->push_back(this->Properties[test]->Name);
+ delete testRun;
+ }
+ cmSystemTools::ChangeDirectory(current_dir);
+}
+
+void cmCTestMultiProcessHandler::LockResources(int index)
+{
+ this->LockedResources.insert(
+ this->Properties[index]->LockedResources.begin(),
+ this->Properties[index]->LockedResources.end());
+
+ if (this->Properties[index]->RunSerial) {
+ this->SerialTestRunning = true;
+ }
+}
+
+void cmCTestMultiProcessHandler::UnlockResources(int index)
+{
+ for (std::set<std::string>::iterator i =
+ this->Properties[index]->LockedResources.begin();
+ i != this->Properties[index]->LockedResources.end(); ++i) {
+ this->LockedResources.erase(*i);
+ }
+ if (this->Properties[index]->RunSerial) {
+ this->SerialTestRunning = false;
+ }
+}
+
+void cmCTestMultiProcessHandler::EraseTest(int test)
+{
+ this->Tests.erase(test);
+ this->SortedTests.erase(
+ std::find(this->SortedTests.begin(), this->SortedTests.end(), test));
+}
+
+inline size_t cmCTestMultiProcessHandler::GetProcessorsUsed(int test)
+{
+ size_t processors = static_cast<int>(this->Properties[test]->Processors);
+ // If processors setting is set higher than the -j
+ // setting, we default to using all of the process slots.
+ if (processors > this->ParallelLevel) {
+ processors = this->ParallelLevel;
+ }
+ return processors;
+}
+
+std::string cmCTestMultiProcessHandler::GetName(int test)
+{
+ return this->Properties[test]->Name;
+}
+
+bool cmCTestMultiProcessHandler::StartTest(int test)
+{
+ // Check for locked resources
+ for (std::set<std::string>::iterator i =
+ this->Properties[test]->LockedResources.begin();
+ i != this->Properties[test]->LockedResources.end(); ++i) {
+ if (this->LockedResources.find(*i) != this->LockedResources.end()) {
+ return false;
+ }
+ }
+
+ // if there are no depends left then run this test
+ if (this->Tests[test].empty()) {
+ this->StartTestProcess(test);
+ return true;
+ }
+ // This test was not able to start because it is waiting
+ // on depends to run
+ return false;
+}
+
+void cmCTestMultiProcessHandler::StartNextTests()
+{
+ size_t numToStart = 0;
+ if (this->RunningCount < this->ParallelLevel) {
+ numToStart = this->ParallelLevel - this->RunningCount;
+ }
+
+ if (numToStart == 0) {
+ return;
+ }
+
+ // Don't start any new tests if one with the RUN_SERIAL property
+ // is already running.
+ if (this->SerialTestRunning) {
+ return;
+ }
+
+ bool allTestsFailedTestLoadCheck = false;
+ bool usedFakeLoadForTesting = false;
+ size_t minProcessorsRequired = this->ParallelLevel;
+ std::string testWithMinProcessors = "";
+
+ cmsys::SystemInformation info;
+
+ unsigned long systemLoad = 0;
+ size_t spareLoad = 0;
+ if (this->TestLoad > 0) {
+ // Activate possible wait.
+ allTestsFailedTestLoadCheck = true;
+
+ // Check for a fake load average value used in testing.
+ if (const char* fake_load_value =
+ cmSystemTools::GetEnv("__CTEST_FAKE_LOAD_AVERAGE_FOR_TESTING")) {
+ usedFakeLoadForTesting = true;
+ if (!cmSystemTools::StringToULong(fake_load_value, &systemLoad)) {
+ cmSystemTools::Error("Failed to parse fake load value: ",
+ fake_load_value);
+ }
+ }
+ // If it's not set, look up the true load average.
+ else {
+ systemLoad = static_cast<unsigned long>(ceil(info.GetLoadAverage()));
+ }
+ spareLoad =
+ (this->TestLoad > systemLoad ? this->TestLoad - systemLoad : 0);
+
+ // Don't start more tests than the spare load can support.
+ if (numToStart > spareLoad) {
+ numToStart = spareLoad;
+ }
+ }
+
+ TestList copy = this->SortedTests;
+ for (TestList::iterator test = copy.begin(); test != copy.end(); ++test) {
+ // Take a nap if we're currently performing a RUN_SERIAL test.
+ if (this->SerialTestRunning) {
+ break;
+ }
+ // We can only start a RUN_SERIAL test if no other tests are also running.
+ if (this->Properties[*test]->RunSerial && this->RunningCount > 0) {
+ continue;
+ }
+
+ size_t processors = GetProcessorsUsed(*test);
+ bool testLoadOk = true;
+ if (this->TestLoad > 0) {
+ if (processors <= spareLoad) {
+ cmCTestLog(this->CTest, DEBUG, "OK to run "
+ << GetName(*test) << ", it requires " << processors
+ << " procs & system load is: " << systemLoad
+ << std::endl);
+ allTestsFailedTestLoadCheck = false;
+ } else {
+ testLoadOk = false;
+ }
+ }
+
+ if (processors <= minProcessorsRequired) {
+ minProcessorsRequired = processors;
+ testWithMinProcessors = GetName(*test);
+ }
+
+ if (testLoadOk && processors <= numToStart && this->StartTest(*test)) {
+ if (this->StopTimePassed) {
+ return;
+ }
+
+ numToStart -= processors;
+ } else if (numToStart == 0) {
+ break;
+ }
+ }
+
+ if (allTestsFailedTestLoadCheck) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***** WAITING, ");
+ if (this->SerialTestRunning) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ "Waiting for RUN_SERIAL test to finish.");
+ } else {
+ /* clang-format off */
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ "System Load: " << systemLoad << ", "
+ "Max Allowed Load: " << this->TestLoad << ", "
+ "Smallest test " << testWithMinProcessors <<
+ " requires " << minProcessorsRequired);
+ /* clang-format on */
+ }
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "*****" << std::endl);
+
+ if (usedFakeLoadForTesting) {
+ // Break out of the infinite loop of waiting for our fake load
+ // to come down.
+ this->StopTimePassed = true;
+ } else {
+ // Wait between 1 and 5 seconds before trying again.
+ cmCTestScriptHandler::SleepInSeconds(cmSystemTools::RandomSeed() % 5 +
+ 1);
+ }
+ }
+}
+
+bool cmCTestMultiProcessHandler::CheckOutput()
+{
+ // no more output we are done
+ if (this->RunningTests.empty()) {
+ return false;
+ }
+ std::vector<cmCTestRunTest*> finished;
+ std::string out, err;
+ for (std::set<cmCTestRunTest*>::const_iterator i =
+ this->RunningTests.begin();
+ i != this->RunningTests.end(); ++i) {
+ cmCTestRunTest* p = *i;
+ if (!p->CheckOutput()) {
+ finished.push_back(p);
+ }
+ }
+ for (std::vector<cmCTestRunTest*>::iterator i = finished.begin();
+ i != finished.end(); ++i) {
+ this->Completed++;
+ cmCTestRunTest* p = *i;
+ int test = p->GetIndex();
+
+ bool testResult = p->EndTest(this->Completed, this->Total, true);
+ if (p->StartAgain()) {
+ this->Completed--; // remove the completed test because run again
+ continue;
+ }
+ if (testResult) {
+ this->Passed->push_back(p->GetTestProperties()->Name);
+ } else {
+ this->Failed->push_back(p->GetTestProperties()->Name);
+ }
+ for (TestMap::iterator j = this->Tests.begin(); j != this->Tests.end();
+ ++j) {
+ j->second.erase(test);
+ }
+ this->TestFinishMap[test] = true;
+ this->TestRunningMap[test] = false;
+ this->RunningTests.erase(p);
+ this->WriteCheckpoint(test);
+ this->UnlockResources(test);
+ this->RunningCount -= GetProcessorsUsed(test);
+ delete p;
+ }
+ return true;
+}
+
+void cmCTestMultiProcessHandler::UpdateCostData()
+{
+ std::string fname = this->CTest->GetCostDataFile();
+ std::string tmpout = fname + ".tmp";
+ cmsys::ofstream fout;
+ fout.open(tmpout.c_str());
+
+ PropertiesMap temp = this->Properties;
+
+ if (cmSystemTools::FileExists(fname.c_str())) {
+ cmsys::ifstream fin;
+ fin.open(fname.c_str());
+
+ std::string line;
+ while (std::getline(fin, line)) {
+ if (line == "---") {
+ break;
+ }
+ std::vector<cmsys::String> parts = cmSystemTools::SplitString(line, ' ');
+ // Format: <name> <previous_runs> <avg_cost>
+ if (parts.size() < 3) {
+ break;
+ }
+
+ std::string name = parts[0];
+ int prev = atoi(parts[1].c_str());
+ float cost = static_cast<float>(atof(parts[2].c_str()));
+
+ int index = this->SearchByName(name);
+ if (index == -1) {
+ // This test is not in memory. We just rewrite the entry
+ fout << name << " " << prev << " " << cost << "\n";
+ } else {
+ // Update with our new average cost
+ fout << name << " " << this->Properties[index]->PreviousRuns << " "
+ << this->Properties[index]->Cost << "\n";
+ temp.erase(index);
+ }
+ }
+ fin.close();
+ cmSystemTools::RemoveFile(fname);
+ }
+
+ // Add all tests not previously listed in the file
+ for (PropertiesMap::iterator i = temp.begin(); i != temp.end(); ++i) {
+ fout << i->second->Name << " " << i->second->PreviousRuns << " "
+ << i->second->Cost << "\n";
+ }
+
+ // Write list of failed tests
+ fout << "---\n";
+ for (std::vector<std::string>::iterator i = this->Failed->begin();
+ i != this->Failed->end(); ++i) {
+ fout << *i << "\n";
+ }
+ fout.close();
+ cmSystemTools::RenameFile(tmpout.c_str(), fname.c_str());
+}
+
+void cmCTestMultiProcessHandler::ReadCostData()
+{
+ std::string fname = this->CTest->GetCostDataFile();
+
+ if (cmSystemTools::FileExists(fname.c_str(), true)) {
+ cmsys::ifstream fin;
+ fin.open(fname.c_str());
+ std::string line;
+ while (std::getline(fin, line)) {
+ if (line == "---") {
+ break;
+ }
+
+ std::vector<cmsys::String> parts = cmSystemTools::SplitString(line, ' ');
+
+ // Probably an older version of the file, will be fixed next run
+ if (parts.size() < 3) {
+ fin.close();
+ return;
+ }
+
+ std::string name = parts[0];
+ int prev = atoi(parts[1].c_str());
+ float cost = static_cast<float>(atof(parts[2].c_str()));
+
+ int index = this->SearchByName(name);
+ if (index == -1) {
+ continue;
+ }
+
+ this->Properties[index]->PreviousRuns = prev;
+ // When not running in parallel mode, don't use cost data
+ if (this->ParallelLevel > 1 && this->Properties[index] &&
+ this->Properties[index]->Cost == 0) {
+ this->Properties[index]->Cost = cost;
+ }
+ }
+ // Next part of the file is the failed tests
+ while (std::getline(fin, line)) {
+ if (line != "") {
+ this->LastTestsFailed.push_back(line);
+ }
+ }
+ fin.close();
+ }
+}
+
+int cmCTestMultiProcessHandler::SearchByName(std::string const& name)
+{
+ int index = -1;
+
+ for (PropertiesMap::iterator i = this->Properties.begin();
+ i != this->Properties.end(); ++i) {
+ if (i->second->Name == name) {
+ index = i->first;
+ }
+ }
+ return index;
+}
+
+void cmCTestMultiProcessHandler::CreateTestCostList()
+{
+ if (this->ParallelLevel > 1) {
+ CreateParallelTestCostList();
+ } else {
+ CreateSerialTestCostList();
+ }
+}
+
+void cmCTestMultiProcessHandler::CreateParallelTestCostList()
+{
+ TestSet alreadySortedTests;
+
+ std::list<TestSet> priorityStack;
+ priorityStack.push_back(TestSet());
+ TestSet& topLevel = priorityStack.back();
+
+ // In parallel test runs add previously failed tests to the front
+ // of the cost list and queue other tests for further sorting
+ for (TestMap::const_iterator i = this->Tests.begin(); i != this->Tests.end();
+ ++i) {
+ if (std::find(this->LastTestsFailed.begin(), this->LastTestsFailed.end(),
+ this->Properties[i->first]->Name) !=
+ this->LastTestsFailed.end()) {
+ // If the test failed last time, it should be run first.
+ this->SortedTests.push_back(i->first);
+ alreadySortedTests.insert(i->first);
+ } else {
+ topLevel.insert(i->first);
+ }
+ }
+
+ // In parallel test runs repeatedly move dependencies of the tests on
+ // the current dependency level to the next level until no
+ // further dependencies exist.
+ while (priorityStack.back().size()) {
+ TestSet& previousSet = priorityStack.back();
+ priorityStack.push_back(TestSet());
+ TestSet& currentSet = priorityStack.back();
+
+ for (TestSet::const_iterator i = previousSet.begin();
+ i != previousSet.end(); ++i) {
+ TestSet const& dependencies = this->Tests[*i];
+ currentSet.insert(dependencies.begin(), dependencies.end());
+ }
+
+ for (TestSet::const_iterator i = currentSet.begin(); i != currentSet.end();
+ ++i) {
+ previousSet.erase(*i);
+ }
+ }
+
+ // Remove the empty dependency level
+ priorityStack.pop_back();
+
+ // 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);
+
+ TestList sortedCopy;
+
+ sortedCopy.insert(sortedCopy.end(), currentSet.begin(), currentSet.end());
+
+ std::stable_sort(sortedCopy.begin(), sortedCopy.end(), comp);
+
+ for (TestList::const_iterator j = sortedCopy.begin();
+ j != sortedCopy.end(); ++j) {
+ if (alreadySortedTests.find(*j) == alreadySortedTests.end()) {
+ this->SortedTests.push_back(*j);
+ alreadySortedTests.insert(*j);
+ }
+ }
+ }
+}
+
+void cmCTestMultiProcessHandler::GetAllTestDependencies(int test,
+ TestList& dependencies)
+{
+ TestSet const& dependencySet = this->Tests[test];
+ for (TestSet::const_iterator i = dependencySet.begin();
+ i != dependencySet.end(); ++i) {
+ GetAllTestDependencies(*i, dependencies);
+ dependencies.push_back(*i);
+ }
+}
+
+void cmCTestMultiProcessHandler::CreateSerialTestCostList()
+{
+ TestList presortedList;
+
+ for (TestMap::iterator i = this->Tests.begin(); i != this->Tests.end();
+ ++i) {
+ presortedList.push_back(i->first);
+ }
+
+ TestComparator comp(this);
+ std::stable_sort(presortedList.begin(), presortedList.end(), comp);
+
+ TestSet alreadySortedTests;
+
+ for (TestList::const_iterator i = presortedList.begin();
+ i != presortedList.end(); ++i) {
+ int test = *i;
+
+ if (alreadySortedTests.find(test) != alreadySortedTests.end()) {
+ continue;
+ }
+
+ TestList dependencies;
+ GetAllTestDependencies(test, dependencies);
+
+ for (TestList::const_iterator j = dependencies.begin();
+ j != dependencies.end(); ++j) {
+ int testDependency = *j;
+
+ if (alreadySortedTests.find(testDependency) ==
+ alreadySortedTests.end()) {
+ alreadySortedTests.insert(testDependency);
+ this->SortedTests.push_back(testDependency);
+ }
+ }
+
+ alreadySortedTests.insert(test);
+ this->SortedTests.push_back(test);
+ }
+}
+
+void cmCTestMultiProcessHandler::WriteCheckpoint(int index)
+{
+ std::string fname =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/CTestCheckpoint.txt";
+ cmsys::ofstream fout;
+ fout.open(fname.c_str(), std::ios::app);
+ fout << index << "\n";
+ fout.close();
+}
+
+void cmCTestMultiProcessHandler::MarkFinished()
+{
+ std::string fname =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/CTestCheckpoint.txt";
+ cmSystemTools::RemoveFile(fname);
+}
+
+// For ShowOnly mode
+void cmCTestMultiProcessHandler::PrintTestList()
+{
+ this->TestHandler->SetMaxIndex(this->FindMaxIndex());
+ int count = 0;
+
+ for (PropertiesMap::iterator it = this->Properties.begin();
+ it != this->Properties.end(); ++it) {
+ count++;
+ cmCTestTestHandler::cmCTestTestProperties& p = *it->second;
+
+ // push working dir
+ std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::ChangeDirectory(p.Directory);
+
+ cmCTestRunTest testRun(this->TestHandler);
+ testRun.SetIndex(p.Index);
+ testRun.SetTestProperties(&p);
+ testRun.ComputeArguments(); // logs the command in verbose mode
+
+ if (!p.Labels.empty()) // print the labels
+ {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Labels:",
+ this->Quiet);
+ }
+ for (std::vector<std::string>::iterator label = p.Labels.begin();
+ label != p.Labels.end(); ++label) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " " << *label,
+ this->Quiet);
+ }
+ if (!p.Labels.empty()) // print the labels
+ {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl,
+ this->Quiet);
+ }
+
+ if (this->TestHandler->MemCheck) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Memory Check",
+ this->Quiet);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Test", this->Quiet);
+ }
+ std::ostringstream indexStr;
+ indexStr << " #" << p.Index << ":";
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ std::setw(3 + getNumWidth(this->TestHandler->GetMaxIndex()))
+ << indexStr.str(),
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, p.Name << std::endl,
+ this->Quiet);
+ // pop working dir
+ cmSystemTools::ChangeDirectory(current_dir);
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, std::endl
+ << "Total Tests: " << this->Total << std::endl,
+ this->Quiet);
+}
+
+void cmCTestMultiProcessHandler::PrintLabels()
+{
+ std::set<std::string> allLabels;
+ for (PropertiesMap::iterator it = this->Properties.begin();
+ it != this->Properties.end(); ++it) {
+ cmCTestTestHandler::cmCTestTestProperties& p = *it->second;
+ allLabels.insert(p.Labels.begin(), p.Labels.end());
+ }
+
+ if (!allLabels.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "All Labels:" << std::endl,
+ this->Quiet);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "No Labels Exist" << std::endl, this->Quiet);
+ }
+ for (std::set<std::string>::iterator label = allLabels.begin();
+ label != allLabels.end(); ++label) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " " << *label << std::endl, this->Quiet);
+ }
+}
+
+void cmCTestMultiProcessHandler::CheckResume()
+{
+ std::string fname =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/CTestCheckpoint.txt";
+ if (this->CTest->GetFailover()) {
+ if (cmSystemTools::FileExists(fname.c_str(), true)) {
+ *this->TestHandler->LogFile
+ << "Resuming previously interrupted test set" << std::endl
+ << "----------------------------------------------------------"
+ << std::endl;
+
+ cmsys::ifstream fin;
+ fin.open(fname.c_str());
+ std::string line;
+ while (std::getline(fin, line)) {
+ int index = atoi(line.c_str());
+ this->RemoveTest(index);
+ }
+ fin.close();
+ }
+ } else if (cmSystemTools::FileExists(fname.c_str(), true)) {
+ cmSystemTools::RemoveFile(fname);
+ }
+}
+
+void cmCTestMultiProcessHandler::RemoveTest(int index)
+{
+ this->EraseTest(index);
+ this->Properties.erase(index);
+ this->TestRunningMap[index] = false;
+ this->TestFinishMap[index] = true;
+ this->Completed++;
+}
+
+int cmCTestMultiProcessHandler::FindMaxIndex()
+{
+ int max = 0;
+ cmCTestMultiProcessHandler::TestMap::iterator i = this->Tests.begin();
+ for (; i != this->Tests.end(); ++i) {
+ if (i->first > max) {
+ max = i->first;
+ }
+ }
+ return max;
+}
+
+// Returns true if no cycles exist in the dependency graph
+bool cmCTestMultiProcessHandler::CheckCycles()
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Checking test dependency graph..." << std::endl,
+ this->Quiet);
+ for (TestMap::iterator it = this->Tests.begin(); it != this->Tests.end();
+ ++it) {
+ // DFS from each element to itself
+ int root = it->first;
+ std::set<int> visited;
+ std::stack<int> s;
+ s.push(root);
+ while (!s.empty()) {
+ int test = s.top();
+ s.pop();
+ if (visited.insert(test).second) {
+ for (TestSet::iterator d = this->Tests[test].begin();
+ d != this->Tests[test].end(); ++d) {
+ if (*d == root) {
+ // cycle exists
+ cmCTestLog(
+ this->CTest, ERROR_MESSAGE,
+ "Error: a cycle exists in the test dependency graph "
+ "for the test \""
+ << this->Properties[root]->Name
+ << "\".\nPlease fix the cycle and run ctest again.\n");
+ return false;
+ } else {
+ s.push(*d);
+ }
+ }
+ }
+ }
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Checking test dependency graph end" << std::endl,
+ this->Quiet);
+ return true;
+}
diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h
new file mode 100644
index 0000000..9ec1528
--- /dev/null
+++ b/Source/CTest/cmCTestMultiProcessHandler.h
@@ -0,0 +1,142 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestMultiProcessHandler_h
+#define cmCTestMultiProcessHandler_h
+
+#include <cmCTestTestHandler.h>
+
+#include <cmCTestRunTest.h>
+
+/** \class cmCTestMultiProcessHandler
+ * \brief run parallel ctest
+ *
+ * cmCTestMultiProcessHandler
+ */
+class cmCTestMultiProcessHandler
+{
+ friend class TestComparator;
+
+public:
+ struct TestSet : public std::set<int>
+ {
+ };
+ struct TestMap : public std::map<int, TestSet>
+ {
+ };
+ struct TestList : public std::vector<int>
+ {
+ };
+ struct PropertiesMap
+ : public std::map<int, cmCTestTestHandler::cmCTestTestProperties*>
+ {
+ };
+
+ cmCTestMultiProcessHandler();
+ virtual ~cmCTestMultiProcessHandler();
+ // Set the tests
+ void SetTests(TestMap& tests, PropertiesMap& properties);
+ // Set the max number of tests that can be run at the same time.
+ void SetParallelLevel(size_t);
+ void SetTestLoad(unsigned long load);
+ virtual void RunTests();
+ void PrintTestList();
+ void PrintLabels();
+
+ void SetPassFailVectors(std::vector<std::string>* passed,
+ std::vector<std::string>* failed)
+ {
+ this->Passed = passed;
+ this->Failed = failed;
+ }
+ void SetTestResults(std::vector<cmCTestTestHandler::cmCTestTestResult>* r)
+ {
+ this->TestResults = r;
+ }
+
+ void SetCTest(cmCTest* ctest) { this->CTest = ctest; }
+
+ void SetTestHandler(cmCTestTestHandler* handler)
+ {
+ this->TestHandler = handler;
+ }
+
+ cmCTestTestHandler* GetTestHandler() { return this->TestHandler; }
+
+ void SetQuiet(bool b) { this->Quiet = b; }
+protected:
+ // Start the next test or tests as many as are allowed by
+ // ParallelLevel
+ void StartNextTests();
+ void StartTestProcess(int test);
+ bool StartTest(int test);
+ // Mark the checkpoint for the given test
+ void WriteCheckpoint(int index);
+
+ void UpdateCostData();
+ void ReadCostData();
+ // Return index of a test based on its name
+ int SearchByName(std::string const& name);
+
+ void CreateTestCostList();
+
+ void GetAllTestDependencies(int test, TestList& dependencies);
+ void CreateSerialTestCostList();
+
+ void CreateParallelTestCostList();
+
+ // Removes the checkpoint file
+ void MarkFinished();
+ void EraseTest(int index);
+ // Return true if there are still tests running
+ // check all running processes for output and exit case
+ bool CheckOutput();
+ void RemoveTest(int index);
+ // Check if we need to resume an interrupted test set
+ void CheckResume();
+ // Check if there are any circular dependencies
+ bool CheckCycles();
+ int FindMaxIndex();
+ inline size_t GetProcessorsUsed(int index);
+ std::string GetName(int index);
+
+ void LockResources(int index);
+ void UnlockResources(int index);
+ // map from test number to set of depend tests
+ TestMap Tests;
+ TestList SortedTests;
+ // Total number of tests we'll be running
+ size_t Total;
+ // Number of tests that are complete
+ size_t Completed;
+ size_t RunningCount;
+ bool StopTimePassed;
+ // list of test properties (indices concurrent to the test map)
+ PropertiesMap Properties;
+ std::map<int, bool> TestRunningMap;
+ std::map<int, bool> TestFinishMap;
+ std::map<int, std::string> TestOutput;
+ std::vector<std::string>* Passed;
+ std::vector<std::string>* Failed;
+ std::vector<std::string> LastTestsFailed;
+ std::set<std::string> LockedResources;
+ std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults;
+ size_t ParallelLevel; // max number of process that can be run at once
+ unsigned long TestLoad;
+ std::set<cmCTestRunTest*> RunningTests; // current running tests
+ cmCTestTestHandler* TestHandler;
+ cmCTest* CTest;
+ bool HasCycles;
+ bool Quiet;
+ bool SerialTestRunning;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx
new file mode 100644
index 0000000..d4a32f1
--- /dev/null
+++ b/Source/CTest/cmCTestP4.cxx
@@ -0,0 +1,534 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2013 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestP4.h"
+
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+
+#include <cmsys/Process.h>
+#include <cmsys/RegularExpression.hxx>
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <time.h>
+
+cmCTestP4::cmCTestP4(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
+{
+ this->PriorRev = this->Unknown;
+}
+
+cmCTestP4::~cmCTestP4()
+{
+}
+
+class cmCTestP4::IdentifyParser : public cmCTestVC::LineParser
+{
+public:
+ IdentifyParser(cmCTestP4* p4, const char* prefix, std::string& rev)
+ : Rev(rev)
+ {
+ this->SetLog(&p4->Log, prefix);
+ this->RegexIdentify.compile("^Change ([0-9]+) on");
+ }
+
+private:
+ std::string& Rev;
+ cmsys::RegularExpression RegexIdentify;
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexIdentify.find(this->Line)) {
+ this->Rev = this->RegexIdentify.match(1);
+ return false;
+ }
+ return true;
+ }
+};
+
+class cmCTestP4::ChangesParser : public cmCTestVC::LineParser
+{
+public:
+ ChangesParser(cmCTestP4* p4, const char* prefix)
+ : P4(p4)
+ {
+ this->SetLog(&P4->Log, prefix);
+ this->RegexIdentify.compile("^Change ([0-9]+) on");
+ }
+
+private:
+ cmsys::RegularExpression RegexIdentify;
+ cmCTestP4* P4;
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexIdentify.find(this->Line)) {
+ P4->ChangeLists.push_back(this->RegexIdentify.match(1));
+ }
+ return true;
+ }
+};
+
+class cmCTestP4::UserParser : public cmCTestVC::LineParser
+{
+public:
+ UserParser(cmCTestP4* p4, const char* prefix)
+ : P4(p4)
+ {
+ this->SetLog(&P4->Log, prefix);
+ this->RegexUser.compile("^(.+) <(.*)> \\((.*)\\) accessed (.*)$");
+ }
+
+private:
+ cmsys::RegularExpression RegexUser;
+ cmCTestP4* P4;
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexUser.find(this->Line)) {
+ User NewUser;
+
+ NewUser.UserName = this->RegexUser.match(1);
+ NewUser.EMail = this->RegexUser.match(2);
+ NewUser.Name = this->RegexUser.match(3);
+ NewUser.AccessTime = this->RegexUser.match(4);
+ P4->Users[this->RegexUser.match(1)] = NewUser;
+
+ return false;
+ }
+ return true;
+ }
+};
+
+/* Diff format:
+==== //depot/file#rev - /absolute/path/to/file ====
+(diff data)
+==== //depot/file2#rev - /absolute/path/to/file2 ====
+(diff data)
+==== //depot/file3#rev - /absolute/path/to/file3 ====
+==== //depot/file4#rev - /absolute/path/to/file4 ====
+(diff data)
+*/
+class cmCTestP4::DiffParser : public cmCTestVC::LineParser
+{
+public:
+ DiffParser(cmCTestP4* p4, const char* prefix)
+ : P4(p4)
+ , AlreadyNotified(false)
+ {
+ this->SetLog(&P4->Log, prefix);
+ this->RegexDiff.compile("^==== (.*)#[0-9]+ - (.*)");
+ }
+
+private:
+ cmCTestP4* P4;
+ bool AlreadyNotified;
+ std::string CurrentPath;
+ cmsys::RegularExpression RegexDiff;
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (!this->Line.empty() && this->Line[0] == '=' &&
+ this->RegexDiff.find(this->Line)) {
+ CurrentPath = this->RegexDiff.match(1);
+ AlreadyNotified = false;
+ } else {
+ if (!AlreadyNotified) {
+ P4->DoModification(PathModified, CurrentPath);
+ AlreadyNotified = true;
+ }
+ }
+ return true;
+ }
+};
+
+cmCTestP4::User cmCTestP4::GetUserData(const std::string& username)
+{
+ std::map<std::string, cmCTestP4::User>::const_iterator it =
+ Users.find(username);
+
+ if (it == Users.end()) {
+ std::vector<char const*> p4_users;
+ SetP4Options(p4_users);
+ p4_users.push_back("users");
+ p4_users.push_back("-m");
+ p4_users.push_back("1");
+ p4_users.push_back(username.c_str());
+ p4_users.push_back(CM_NULLPTR);
+
+ UserParser out(this, "users-out> ");
+ OutputLogger err(this->Log, "users-err> ");
+ RunChild(&p4_users[0], &out, &err);
+
+ // The user should now be added to the map. Search again.
+ it = Users.find(username);
+ if (it == Users.end()) {
+ return cmCTestP4::User();
+ }
+ }
+
+ return it->second;
+}
+
+/* Commit format:
+
+Change 1111111 by user@client on 2013/09/26 11:50:36
+
+ text
+ text
+
+Affected files ...
+
+... //path/to/file#rev edit
+... //path/to/file#rev add
+... //path/to/file#rev delete
+... //path/to/file#rev integrate
+*/
+class cmCTestP4::DescribeParser : public cmCTestVC::LineParser
+{
+public:
+ DescribeParser(cmCTestP4* p4, const char* prefix)
+ : LineParser('\n', false)
+ , P4(p4)
+ , Section(SectionHeader)
+ {
+ this->SetLog(&P4->Log, prefix);
+ this->RegexHeader.compile("^Change ([0-9]+) by (.+)@(.+) on (.*)$");
+ this->RegexDiff.compile("^\\.\\.\\. (.*)#[0-9]+ ([^ ]+)$");
+ }
+
+private:
+ cmsys::RegularExpression RegexHeader;
+ cmsys::RegularExpression RegexDiff;
+ cmCTestP4* P4;
+
+ typedef cmCTestP4::Revision Revision;
+ typedef cmCTestP4::Change Change;
+ std::vector<Change> Changes;
+ enum SectionType
+ {
+ SectionHeader,
+ SectionBody,
+ SectionDiffHeader,
+ SectionDiff,
+ SectionCount
+ };
+ SectionType Section;
+ Revision Rev;
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->Line.empty()) {
+ this->NextSection();
+ } else {
+ switch (this->Section) {
+ case SectionHeader:
+ this->DoHeaderLine();
+ break;
+ case SectionBody:
+ this->DoBodyLine();
+ break;
+ case SectionDiffHeader:
+ break; // nothing to do
+ case SectionDiff:
+ this->DoDiffLine();
+ break;
+ case SectionCount:
+ break; // never happens
+ }
+ }
+ return true;
+ }
+
+ void NextSection()
+ {
+ if (this->Section == SectionDiff) {
+ this->P4->DoRevision(this->Rev, this->Changes);
+ this->Rev = Revision();
+ }
+
+ this->Section = SectionType((this->Section + 1) % SectionCount);
+ }
+
+ void DoHeaderLine()
+ {
+ if (this->RegexHeader.find(this->Line)) {
+ this->Rev.Rev = this->RegexHeader.match(1);
+ this->Rev.Date = this->RegexHeader.match(4);
+
+ cmCTestP4::User user = P4->GetUserData(this->RegexHeader.match(2));
+ this->Rev.Author = user.Name;
+ this->Rev.EMail = user.EMail;
+
+ this->Rev.Committer = this->Rev.Author;
+ this->Rev.CommitterEMail = this->Rev.EMail;
+ this->Rev.CommitDate = this->Rev.Date;
+ }
+ }
+
+ void DoBodyLine()
+ {
+ if (this->Line[0] == '\t') {
+ this->Rev.Log += this->Line.substr(1);
+ }
+ this->Rev.Log += "\n";
+ }
+
+ void DoDiffLine()
+ {
+ if (this->RegexDiff.find(this->Line)) {
+ Change change;
+ std::string Path = this->RegexDiff.match(1);
+ if (Path.length() > 2 && Path[0] == '/' && Path[1] == '/') {
+ size_t found = Path.find('/', 2);
+ if (found != std::string::npos) {
+ Path = Path.substr(found + 1);
+ }
+ }
+
+ change.Path = Path;
+ std::string action = this->RegexDiff.match(2);
+
+ if (action == "add") {
+ change.Action = 'A';
+ } else if (action == "delete") {
+ change.Action = 'D';
+ } else if (action == "edit" || action == "integrate") {
+ change.Action = 'M';
+ }
+
+ Changes.push_back(change);
+ }
+ }
+};
+
+void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions)
+{
+ if (P4Options.empty()) {
+ const char* p4 = this->CommandLineTool.c_str();
+ P4Options.push_back(p4);
+
+ // The CTEST_P4_CLIENT variable sets the P4 client used when issuing
+ // Perforce commands, if it's different from the default one.
+ std::string client = this->CTest->GetCTestConfiguration("P4Client");
+ if (!client.empty()) {
+ P4Options.push_back("-c");
+ P4Options.push_back(client);
+ }
+
+ // Set the message language to be English, in case the P4 admin
+ // has localized them
+ P4Options.push_back("-L");
+ P4Options.push_back("en");
+
+ // 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());
+ }
+
+ CommandOptions.clear();
+ for (std::vector<std::string>::iterator i = P4Options.begin();
+ i != P4Options.end(); ++i) {
+ CommandOptions.push_back(i->c_str());
+ }
+}
+
+std::string cmCTestP4::GetWorkingRevision()
+{
+ std::vector<char const*> p4_identify;
+ SetP4Options(p4_identify);
+
+ p4_identify.push_back("changes");
+ p4_identify.push_back("-m");
+ p4_identify.push_back("1");
+ p4_identify.push_back("-t");
+
+ std::string source = this->SourceDirectory + "/...#have";
+ p4_identify.push_back(source.c_str());
+ p4_identify.push_back(CM_NULLPTR);
+
+ std::string rev;
+ IdentifyParser out(this, "p4_changes-out> ", rev);
+ OutputLogger err(this->Log, "p4_changes-err> ");
+
+ bool result = RunChild(&p4_identify[0], &out, &err);
+
+ // If there was a problem contacting the server return "<unknown>"
+ if (!result) {
+ return "<unknown>";
+ }
+
+ if (rev.empty()) {
+ return "0";
+ } else {
+ return rev;
+ }
+}
+
+void cmCTestP4::NoteOldRevision()
+{
+ this->OldRevision = this->GetWorkingRevision();
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Old revision of repository is: "
+ << this->OldRevision << "\n");
+ this->PriorRev.Rev = this->OldRevision;
+}
+
+void cmCTestP4::NoteNewRevision()
+{
+ this->NewRevision = this->GetWorkingRevision();
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " New revision of repository is: "
+ << this->NewRevision << "\n");
+}
+
+void cmCTestP4::LoadRevisions()
+{
+ std::vector<char const*> p4_changes;
+ SetP4Options(p4_changes);
+
+ // Use 'p4 changes ...@old,new' to get a list of changelists
+ std::string range = this->SourceDirectory + "/...";
+
+ // If any revision is unknown it means we couldn't contact the server.
+ // Do not process updates
+ if (this->OldRevision == "<unknown>" || this->NewRevision == "<unknown>") {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " At least one of the revisions "
+ << "is unknown. No repository changes will be reported.\n");
+ return;
+ }
+
+ range.append("@")
+ .append(this->OldRevision)
+ .append(",")
+ .append(this->NewRevision);
+
+ p4_changes.push_back("changes");
+ p4_changes.push_back(range.c_str());
+ p4_changes.push_back(CM_NULLPTR);
+
+ ChangesParser out(this, "p4_changes-out> ");
+ OutputLogger err(this->Log, "p4_changes-err> ");
+
+ ChangeLists.clear();
+ this->RunChild(&p4_changes[0], &out, &err);
+
+ if (ChangeLists.empty()) {
+ return;
+ }
+
+ // 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) {
+ SetP4Options(p4_describe);
+ p4_describe.push_back("describe");
+ p4_describe.push_back("-s");
+ p4_describe.push_back(i->c_str());
+ p4_describe.push_back(CM_NULLPTR);
+
+ DescribeParser outDescribe(this, "p4_describe-out> ");
+ OutputLogger errDescribe(this->Log, "p4_describe-err> ");
+ this->RunChild(&p4_describe[0], &outDescribe, &errDescribe);
+ }
+}
+
+void cmCTestP4::LoadModifications()
+{
+ std::vector<char const*> p4_diff;
+ SetP4Options(p4_diff);
+
+ p4_diff.push_back("diff");
+
+ // Ideally we would use -Od but not all clients support it
+ p4_diff.push_back("-dn");
+ std::string source = this->SourceDirectory + "/...";
+ p4_diff.push_back(source.c_str());
+ p4_diff.push_back(CM_NULLPTR);
+
+ DiffParser out(this, "p4_diff-out> ");
+ OutputLogger err(this->Log, "p4_diff-err> ");
+ this->RunChild(&p4_diff[0], &out, &err);
+}
+
+bool cmCTestP4::UpdateCustom(const std::string& custom)
+{
+ std::vector<std::string> p4_custom_command;
+ cmSystemTools::ExpandListArgument(custom, p4_custom_command, true);
+
+ std::vector<char const*> p4_custom;
+ for (std::vector<std::string>::const_iterator i = p4_custom_command.begin();
+ i != p4_custom_command.end(); ++i) {
+ p4_custom.push_back(i->c_str());
+ }
+ p4_custom.push_back(CM_NULLPTR);
+
+ OutputLogger custom_out(this->Log, "p4_customsync-out> ");
+ OutputLogger custom_err(this->Log, "p4_customsync-err> ");
+
+ return this->RunUpdateCommand(&p4_custom[0], &custom_out, &custom_err);
+}
+
+bool cmCTestP4::UpdateImpl()
+{
+ std::string custom = this->CTest->GetCTestConfiguration("P4UpdateCustom");
+ if (!custom.empty()) {
+ return this->UpdateCustom(custom);
+ }
+
+ // If we couldn't get a revision number before updating, abort.
+ if (this->OldRevision == "<unknown>") {
+ this->UpdateCommandLine = "Unknown current revision";
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " Unknown current revision\n");
+ return false;
+ }
+
+ std::vector<char const*> p4_sync;
+ SetP4Options(p4_sync);
+
+ p4_sync.push_back("sync");
+
+ // Get user-specified update options.
+ std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
+ if (opts.empty()) {
+ opts = this->CTest->GetCTestConfiguration("P4UpdateOptions");
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ for (std::vector<std::string>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai) {
+ p4_sync.push_back(ai->c_str());
+ }
+
+ std::string source = this->SourceDirectory + "/...";
+
+ // Specify the start time for nightly testing.
+ if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
+ std::string date = this->GetNightlyTime();
+ // CTest reports the date as YYYY-MM-DD, Perforce needs it as YYYY/MM/DD
+ std::replace(date.begin(), date.end(), '-', '/');
+
+ // Revision specification: /...@"YYYY/MM/DD HH:MM:SS"
+ source.append("@\"").append(date).append("\"");
+ }
+
+ p4_sync.push_back(source.c_str());
+ p4_sync.push_back(CM_NULLPTR);
+
+ OutputLogger out(this->Log, "p4_sync-out> ");
+ OutputLogger err(this->Log, "p4_sync-err> ");
+
+ return this->RunUpdateCommand(&p4_sync[0], &out, &err);
+}
diff --git a/Source/CTest/cmCTestP4.h b/Source/CTest/cmCTestP4.h
new file mode 100644
index 0000000..84e4f96
--- /dev/null
+++ b/Source/CTest/cmCTestP4.h
@@ -0,0 +1,78 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2013 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestP4_h
+#define cmCTestP4_h
+
+#include "cmCTestGlobalVC.h"
+
+#include <map>
+#include <vector>
+
+/** \class cmCTestP4
+ * \brief Interaction with the Perforce command-line tool
+ *
+ */
+class cmCTestP4 : public cmCTestGlobalVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestP4(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestP4() CM_OVERRIDE;
+
+private:
+ std::vector<std::string> ChangeLists;
+
+ struct User
+ {
+ std::string UserName;
+ std::string Name;
+ std::string EMail;
+ std::string AccessTime;
+
+ User()
+ : UserName()
+ , Name()
+ , EMail()
+ , AccessTime()
+ {
+ }
+ };
+ std::map<std::string, User> Users;
+ std::vector<std::string> P4Options;
+
+ User GetUserData(const std::string& username);
+ void SetP4Options(std::vector<char const*>& options);
+
+ std::string GetWorkingRevision();
+ void NoteOldRevision() CM_OVERRIDE;
+ void NoteNewRevision() CM_OVERRIDE;
+ bool UpdateImpl() CM_OVERRIDE;
+ bool UpdateCustom(const std::string& custom);
+
+ void LoadRevisions() CM_OVERRIDE;
+ void LoadModifications() CM_OVERRIDE;
+
+ // Parsing helper classes.
+ class IdentifyParser;
+ class ChangesParser;
+ class UserParser;
+ class DescribeParser;
+ class DiffParser;
+ friend class IdentifyParser;
+ friend class ChangesParser;
+ friend class UserParser;
+ friend class DescribeParser;
+ friend class DiffParser;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.cxx b/Source/CTest/cmCTestReadCustomFilesCommand.cxx
new file mode 100644
index 0000000..fec23e9
--- /dev/null
+++ b/Source/CTest/cmCTestReadCustomFilesCommand.cxx
@@ -0,0 +1,30 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestReadCustomFilesCommand.h"
+
+#include "cmCTest.h"
+
+bool cmCTestReadCustomFilesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.empty()) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::vector<std::string>::const_iterator dit;
+ for (dit = args.begin(); dit != args.end(); ++dit) {
+ this->CTest->ReadCustomConfigurationFileTree(dit->c_str(), this->Makefile);
+ }
+
+ return true;
+}
diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.h b/Source/CTest/cmCTestReadCustomFilesCommand.h
new file mode 100644
index 0000000..6cce7c8
--- /dev/null
+++ b/Source/CTest/cmCTestReadCustomFilesCommand.h
@@ -0,0 +1,53 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestReadCustomFilesCommand_h
+#define cmCTestReadCustomFilesCommand_h
+
+#include "cmCTestCommand.h"
+
+/** \class cmCTestReadCustomFiles
+ * \brief Run a ctest script
+ *
+ * cmLibrarysCommand defines a list of executable (i.e., test)
+ * programs to create.
+ */
+class cmCTestReadCustomFilesCommand : public cmCTestCommand
+{
+public:
+ cmCTestReadCustomFilesCommand() {}
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestReadCustomFilesCommand* ni = new cmCTestReadCustomFilesCommand;
+ ni->CTest = this->CTest;
+ return ni;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "ctest_read_custom_files"; }
+
+ cmTypeMacro(cmCTestReadCustomFilesCommand, cmCTestCommand);
+};
+
+#endif
diff --git a/Source/CTest/cmCTestRunScriptCommand.cxx b/Source/CTest/cmCTestRunScriptCommand.cxx
new file mode 100644
index 0000000..6b5e6ed
--- /dev/null
+++ b/Source/CTest/cmCTestRunScriptCommand.cxx
@@ -0,0 +1,53 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestRunScriptCommand.h"
+
+#include "cmCTestScriptHandler.h"
+
+bool cmCTestRunScriptCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.empty()) {
+ this->CTestScriptHandler->RunCurrentScript();
+ return true;
+ }
+
+ bool np = false;
+ unsigned int i = 0;
+ if (args[i] == "NEW_PROCESS") {
+ np = true;
+ i++;
+ }
+ int start = i;
+ // run each script
+ std::string returnVariable;
+ for (i = start; i < args.size(); ++i) {
+ if (args[i] == "RETURN_VALUE") {
+ ++i;
+ if (i < args.size()) {
+ returnVariable = args[i];
+ }
+ }
+ }
+ for (i = start; i < args.size(); ++i) {
+ if (args[i] == "RETURN_VALUE") {
+ ++i;
+ } else {
+ int ret;
+ cmCTestScriptHandler::RunScript(this->CTest, args[i].c_str(), !np, &ret);
+ std::ostringstream str;
+ str << ret;
+ this->Makefile->AddDefinition(returnVariable, str.str().c_str());
+ }
+ }
+ return true;
+}
diff --git a/Source/CTest/cmCTestRunScriptCommand.h b/Source/CTest/cmCTestRunScriptCommand.h
new file mode 100644
index 0000000..9ea0999
--- /dev/null
+++ b/Source/CTest/cmCTestRunScriptCommand.h
@@ -0,0 +1,54 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestRunScriptCommand_h
+#define cmCTestRunScriptCommand_h
+
+#include "cmCTestCommand.h"
+
+/** \class cmCTestRunScript
+ * \brief Run a ctest script
+ *
+ * cmLibrarysCommand defines a list of executable (i.e., test)
+ * programs to create.
+ */
+class cmCTestRunScriptCommand : public cmCTestCommand
+{
+public:
+ cmCTestRunScriptCommand() {}
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestRunScriptCommand* ni = new cmCTestRunScriptCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return ni;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "ctest_run_script"; }
+
+ cmTypeMacro(cmCTestRunScriptCommand, cmCTestCommand);
+};
+
+#endif
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
new file mode 100644
index 0000000..9e3802a
--- /dev/null
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -0,0 +1,744 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCTestRunTest.h"
+
+#include "cmCTest.h"
+#include "cmCTestMemCheckHandler.h"
+#include "cmSystemTools.h"
+#include "cm_curl.h"
+
+#include <cm_zlib.h>
+#include <cmsys/Base64.h>
+
+cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler)
+{
+ this->CTest = handler->CTest;
+ this->TestHandler = handler;
+ this->TestProcess = CM_NULLPTR;
+ this->TestResult.ExecutionTime = 0;
+ this->TestResult.ReturnValue = 0;
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ this->TestResult.TestCount = 0;
+ this->TestResult.Properties = CM_NULLPTR;
+ this->ProcessOutput = "";
+ this->CompressedOutput = "";
+ this->CompressionRatio = 2;
+ this->StopTimePassed = false;
+ 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
+}
+
+cmCTestRunTest::~cmCTestRunTest()
+{
+}
+
+bool cmCTestRunTest::CheckOutput()
+{
+ // Read lines for up to 0.1 seconds of total time.
+ double timeout = 0.1;
+ double timeEnd = cmSystemTools::GetTime() + timeout;
+ std::string line;
+ while ((timeout = timeEnd - cmSystemTools::GetTime(), timeout > 0)) {
+ int p = this->TestProcess->GetNextOutputLine(line, timeout);
+ if (p == cmsysProcess_Pipe_None) {
+ // Process has terminated and all output read.
+ return false;
+ } else if (p == cmsysProcess_Pipe_STDOUT) {
+ // Store this line of output.
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex()
+ << ": " << line << std::endl);
+ this->ProcessOutput += line;
+ this->ProcessOutput += "\n";
+
+ // Check for TIMEOUT_AFTER_MATCH property.
+ if (!this->TestProperties->TimeoutRegularExpressions.empty()) {
+ std::vector<
+ std::pair<cmsys::RegularExpression, std::string> >::iterator regIt;
+ for (regIt = this->TestProperties->TimeoutRegularExpressions.begin();
+ regIt != this->TestProperties->TimeoutRegularExpressions.end();
+ ++regIt) {
+ if (regIt->first.find(this->ProcessOutput.c_str())) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex()
+ << ": "
+ << "Test timeout changed to "
+ << this->TestProperties->AlternateTimeout
+ << std::endl);
+ this->TestProcess->ResetStartTime();
+ this->TestProcess->ChangeTimeout(
+ this->TestProperties->AlternateTimeout);
+ this->TestProperties->TimeoutRegularExpressions.clear();
+ break;
+ }
+ }
+ }
+ } else // if(p == cmsysProcess_Pipe_Timeout)
+ {
+ break;
+ }
+ }
+ return true;
+}
+
+// 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_ERROR || 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);
+
+ 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->ShouldCompressMemCheckOutput())) {
+ this->CompressOutput();
+ }
+
+ this->WriteLogOutputTop(completed, total);
+ std::string reason;
+ bool passed = true;
+ int res =
+ started ? this->TestProcess->GetProcessStatus() : cmsysProcess_State_Error;
+ int retVal = this->TestProcess->GetExitValue();
+ std::vector<std::pair<cmsys::RegularExpression, std::string> >::iterator
+ passIt;
+ bool forceFail = false;
+ bool outputTestErrorsToConsole = false;
+ if (!this->TestProperties->RequiredRegularExpressions.empty()) {
+ bool found = false;
+ for (passIt = this->TestProperties->RequiredRegularExpressions.begin();
+ passIt != this->TestProperties->RequiredRegularExpressions.end();
+ ++passIt) {
+ if (passIt->first.find(this->ProcessOutput.c_str())) {
+ found = true;
+ reason = "Required regular expression found.";
+ break;
+ }
+ }
+ if (!found) {
+ reason = "Required regular expression not found.";
+ forceFail = true;
+ }
+ reason += "Regex=[";
+ for (passIt = this->TestProperties->RequiredRegularExpressions.begin();
+ passIt != this->TestProperties->RequiredRegularExpressions.end();
+ ++passIt) {
+ reason += passIt->second;
+ reason += "\n";
+ }
+ reason += "]";
+ }
+ if (!this->TestProperties->ErrorRegularExpressions.empty()) {
+ for (passIt = this->TestProperties->ErrorRegularExpressions.begin();
+ passIt != this->TestProperties->ErrorRegularExpressions.end();
+ ++passIt) {
+ if (passIt->first.find(this->ProcessOutput.c_str())) {
+ reason = "Error regular expression found in output.";
+ reason += " Regex=[";
+ reason += passIt->second;
+ reason += "]";
+ forceFail = true;
+ break;
+ }
+ }
+ }
+ if (res == cmsysProcess_State_Exited) {
+ bool success = !forceFail &&
+ (retVal == 0 ||
+ !this->TestProperties->RequiredRegularExpressions.empty());
+ if (this->TestProperties->SkipReturnCode >= 0 &&
+ this->TestProperties->SkipReturnCode == retVal) {
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Skipped ");
+ } else if ((success && !this->TestProperties->WillFail) ||
+ (!success && this->TestProperties->WillFail)) {
+ this->TestResult.Status = cmCTestTestHandler::COMPLETED;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Passed ");
+ } else {
+ this->TestResult.Status = cmCTestTestHandler::FAILED;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed " << reason);
+ outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
+ }
+ } else if (res == cmsysProcess_State_Expired) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout ");
+ this->TestResult.Status = cmCTestTestHandler::TIMEOUT;
+ outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
+ } else if (res == cmsysProcess_State_Exception) {
+ outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Exception: ");
+ switch (this->TestProcess->GetExitException()) {
+ case cmsysProcess_Exception_Fault:
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "SegFault");
+ this->TestResult.Status = cmCTestTestHandler::SEGFAULT;
+ break;
+ case cmsysProcess_Exception_Illegal:
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "Illegal");
+ this->TestResult.Status = cmCTestTestHandler::ILLEGAL;
+ break;
+ case cmsysProcess_Exception_Interrupt:
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "Interrupt");
+ this->TestResult.Status = cmCTestTestHandler::INTERRUPT;
+ break;
+ case cmsysProcess_Exception_Numerical:
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "Numerical");
+ this->TestResult.Status = cmCTestTestHandler::NUMERICAL;
+ break;
+ default:
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "Other");
+ this->TestResult.Status = cmCTestTestHandler::OTHER_FAULT;
+ }
+ } else // cmsysProcess_State_Error
+ {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Not Run ");
+ }
+
+ passed = this->TestResult.Status == cmCTestTestHandler::COMPLETED;
+ char buf[1024];
+ sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime());
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, buf << "\n");
+
+ if (outputTestErrorsToConsole) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, this->ProcessOutput << std::endl);
+ }
+
+ if (this->TestHandler->LogFile) {
+ *this->TestHandler->LogFile << "Test time = " << buf << std::endl;
+ }
+
+ // Set the working directory to the tests directory
+ std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::ChangeDirectory(this->TestProperties->Directory);
+
+ this->DartProcessing();
+
+ // restore working directory
+ cmSystemTools::ChangeDirectory(oldpath);
+
+ // if this is doing MemCheck then all the output needs to be put into
+ // Output since that is what is parsed by cmCTestMemCheckHandler
+ if (!this->TestHandler->MemCheck && started) {
+ this->TestHandler->CleanTestOutput(
+ this->ProcessOutput,
+ static_cast<size_t>(
+ this->TestResult.Status == cmCTestTestHandler::COMPLETED
+ ? this->TestHandler->CustomMaximumPassedTestOutputSize
+ : this->TestHandler->CustomMaximumFailedTestOutputSize));
+ }
+ this->TestResult.Reason = reason;
+ if (this->TestHandler->LogFile) {
+ bool pass = true;
+ const char* reasonType = "Test Pass Reason";
+ if (this->TestResult.Status != cmCTestTestHandler::COMPLETED &&
+ this->TestResult.Status != cmCTestTestHandler::NOT_RUN) {
+ reasonType = "Test Fail Reason";
+ pass = false;
+ }
+ double ttime = this->TestProcess->GetTotalTime();
+ int hours = static_cast<int>(ttime / (60 * 60));
+ int minutes = static_cast<int>(ttime / 60) % 60;
+ int seconds = static_cast<int>(ttime) % 60;
+ char buffer[100];
+ sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
+ *this->TestHandler->LogFile
+ << "----------------------------------------------------------"
+ << std::endl;
+ if (!this->TestResult.Reason.empty()) {
+ *this->TestHandler->LogFile << reasonType << ":\n"
+ << this->TestResult.Reason << "\n";
+ } else {
+ if (pass) {
+ *this->TestHandler->LogFile << "Test Passed.\n";
+ } else {
+ *this->TestHandler->LogFile << "Test Failed.\n";
+ }
+ }
+ *this->TestHandler->LogFile
+ << "\"" << this->TestProperties->Name
+ << "\" end time: " << this->CTest->CurrentTime() << std::endl
+ << "\"" << this->TestProperties->Name << "\" time elapsed: " << buffer
+ << std::endl
+ << "----------------------------------------------------------"
+ << std::endl
+ << std::endl;
+ }
+ // 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();
+ this->TestResult.Output =
+ compress ? this->CompressedOutput : this->ProcessOutput;
+ this->TestResult.CompressOutput = compress;
+ this->TestResult.ReturnValue = this->TestProcess->GetExitValue();
+ this->TestResult.CompletionStatus = "Completed";
+ this->TestResult.ExecutionTime = this->TestProcess->GetTotalTime();
+ this->MemCheckPostProcess();
+ this->ComputeWeightedCost();
+ }
+ // If the test does not need to rerun push the current TestResult onto the
+ // TestHandler vector
+ if (!this->NeedsToRerun()) {
+ this->TestHandler->TestResults.push_back(this->TestResult);
+ }
+ delete this->TestProcess;
+ return passed;
+}
+
+bool cmCTestRunTest::StartAgain()
+{
+ if (!this->RunAgain) {
+ return false;
+ }
+ this->RunAgain = false; // reset
+ // change to tests directory
+ std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::ChangeDirectory(this->TestProperties->Directory);
+ this->StartTest(this->TotalNumberOfTests);
+ // change back
+ cmSystemTools::ChangeDirectory(current_dir);
+ return true;
+}
+
+bool cmCTestRunTest::NeedsToRerun()
+{
+ this->NumberOfRunsLeft--;
+ if (this->NumberOfRunsLeft == 0) {
+ return false;
+ }
+ // if number of runs left is not 0, and we are running until
+ // we find a failed test, then return true so the test can be
+ // restarted
+ if (this->RunUntilFail &&
+ this->TestResult.Status == cmCTestTestHandler::COMPLETED) {
+ this->RunAgain = true;
+ return true;
+ }
+ return false;
+}
+void cmCTestRunTest::ComputeWeightedCost()
+{
+ double prev = static_cast<double>(this->TestProperties->PreviousRuns);
+ double avgcost = static_cast<double>(this->TestProperties->Cost);
+ double current = this->TestResult.ExecutionTime;
+
+ if (this->TestResult.Status == cmCTestTestHandler::COMPLETED) {
+ this->TestProperties->Cost =
+ static_cast<float>(((prev * avgcost) + current) / (prev + 1.0));
+ this->TestProperties->PreviousRuns++;
+ }
+}
+
+void cmCTestRunTest::MemCheckPostProcess()
+{
+ if (!this->TestHandler->MemCheck) {
+ return;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index
+ << ": process test output now: "
+ << this->TestProperties->Name << " "
+ << this->TestResult.Name << std::endl,
+ this->TestHandler->GetQuiet());
+ cmCTestMemCheckHandler* handler =
+ static_cast<cmCTestMemCheckHandler*>(this->TestHandler);
+ handler->PostProcessTest(this->TestResult, this->Index);
+}
+
+// Starts the execution of a test. Returns once it has started
+bool cmCTestRunTest::StartTest(size_t total)
+{
+ this->TotalNumberOfTests = total; // save for rerun case
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(2 * getNumWidth(total) + 8)
+ << "Start "
+ << std::setw(getNumWidth(this->TestHandler->GetMaxIndex()))
+ << this->TestProperties->Index << ": "
+ << this->TestProperties->Name << std::endl);
+ this->ComputeArguments();
+ std::vector<std::string>& args = this->TestProperties->Args;
+ this->TestResult.Properties = this->TestProperties;
+ this->TestResult.ExecutionTime = 0;
+ 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;
+
+ if (args.size() >= 2 && args[1] == "NOT_AVAILABLE") {
+ this->TestProcess = new cmProcess;
+ std::string msg;
+ if (this->CTest->GetConfigType().empty()) {
+ msg = "Test not available without configuration.";
+ msg += " (Missing \"-C <config>\"?)";
+ } else {
+ msg = "Test not available in configuration \"";
+ msg += this->CTest->GetConfigType();
+ msg += "\".";
+ }
+ *this->TestHandler->LogFile << msg << std::endl;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, msg << std::endl);
+ this->TestResult.Output = msg;
+ this->TestResult.FullCommandLine = "";
+ this->TestResult.CompletionStatus = "Not Run";
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ return false;
+ }
+
+ // Check if all required files exist
+ for (std::vector<std::string>::iterator i =
+ this->TestProperties->RequiredFiles.begin();
+ i != this->TestProperties->RequiredFiles.end(); ++i) {
+ std::string file = *i;
+
+ if (!cmSystemTools::FileExists(file.c_str())) {
+ // Required file was not found
+ this->TestProcess = new cmProcess;
+ *this->TestHandler->LogFile << "Unable to find required file: " << file
+ << std::endl;
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to find required file: " << file << std::endl);
+ this->TestResult.Output = "Unable to find required file: " + file;
+ this->TestResult.FullCommandLine = "";
+ this->TestResult.CompletionStatus = "Not Run";
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ return false;
+ }
+ }
+ // log and return if we did not find the executable
+ if (this->ActualCommand == "") {
+ // if the command was not found create a TestResult object
+ // that has that information
+ this->TestProcess = new cmProcess;
+ *this->TestHandler->LogFile << "Unable to find executable: " << args[1]
+ << std::endl;
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to find executable: " << args[1] << std::endl);
+ this->TestResult.Output = "Unable to find executable: " + args[1];
+ this->TestResult.FullCommandLine = "";
+ this->TestResult.CompletionStatus = "Not Run";
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ return false;
+ }
+ this->StartTime = this->CTest->CurrentTime();
+
+ double timeout = this->ResolveTimeout();
+
+ if (this->StopTimePassed) {
+ return false;
+ }
+ return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout,
+ &this->TestProperties->Environment);
+}
+
+void cmCTestRunTest::ComputeArguments()
+{
+ this->Arguments.clear(); // reset becaue this might be a rerun
+ std::vector<std::string>::const_iterator j =
+ this->TestProperties->Args.begin();
+ ++j; // skip test name
+ // find the test executable
+ if (this->TestHandler->MemCheck) {
+ cmCTestMemCheckHandler* handler =
+ static_cast<cmCTestMemCheckHandler*>(this->TestHandler);
+ this->ActualCommand = handler->MemoryTester;
+ this->TestProperties->Args[1] = this->TestHandler->FindTheExecutable(
+ this->TestProperties->Args[1].c_str());
+ } else {
+ this->ActualCommand = this->TestHandler->FindTheExecutable(
+ this->TestProperties->Args[1].c_str());
+ ++j; // skip the executable (it will be actualCommand)
+ }
+ std::string testCommand =
+ cmSystemTools::ConvertToOutputPath(this->ActualCommand.c_str());
+
+ // Prepends memcheck args to our command string
+ this->TestHandler->GenerateTestCommand(this->Arguments, this->Index);
+ for (std::vector<std::string>::iterator i = this->Arguments.begin();
+ i != this->Arguments.end(); ++i) {
+ testCommand += " \"";
+ testCommand += *i;
+ testCommand += "\"";
+ }
+
+ for (; j != this->TestProperties->Args.end(); ++j) {
+ testCommand += " \"";
+ testCommand += *j;
+ testCommand += "\"";
+ this->Arguments.push_back(*j);
+ }
+ this->TestResult.FullCommandLine = testCommand;
+
+ // Print the test command in verbose mode
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
+ << this->Index << ": "
+ << (this->TestHandler->MemCheck ? "MemCheck" : "Test")
+ << " command: " << testCommand << std::endl);
+
+ // Print any test-specific env vars in verbose mode
+ if (!this->TestProperties->Environment.empty()) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index
+ << ": "
+ << "Environment variables: " << std::endl);
+ }
+ for (std::vector<std::string>::const_iterator e =
+ this->TestProperties->Environment.begin();
+ e != this->TestProperties->Environment.end(); ++e) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index << ": " << *e
+ << std::endl);
+ }
+}
+
+void cmCTestRunTest::DartProcessing()
+{
+ if (!this->ProcessOutput.empty() &&
+ this->ProcessOutput.find("<DartMeasurement") !=
+ this->ProcessOutput.npos) {
+ if (this->TestHandler->DartStuff.find(this->ProcessOutput.c_str())) {
+ this->TestResult.DartString = this->TestHandler->DartStuff.match(1);
+ // keep searching and replacing until none are left
+ while (this->TestHandler->DartStuff1.find(this->ProcessOutput.c_str())) {
+ // replace the exact match for the string
+ cmSystemTools::ReplaceString(
+ this->ProcessOutput, this->TestHandler->DartStuff1.match(1).c_str(),
+ "");
+ }
+ }
+ }
+}
+
+double cmCTestRunTest::ResolveTimeout()
+{
+ double timeout = this->TestProperties->Timeout;
+
+ if (this->CTest->GetStopTime() == "") {
+ return timeout;
+ }
+ struct tm* lctime;
+ time_t current_time = time(CM_NULLPTR);
+ lctime = gmtime(&current_time);
+ int gm_hour = lctime->tm_hour;
+ time_t gm_time = mktime(lctime);
+ lctime = localtime(&current_time);
+ int local_hour = lctime->tm_hour;
+
+ int tzone_offset = local_hour - gm_hour;
+ if (gm_time > current_time && gm_hour < local_hour) {
+ // this means gm_time is on the next day
+ tzone_offset -= 24;
+ } else if (gm_time < current_time && gm_hour > local_hour) {
+ // this means gm_time is on the previous day
+ tzone_offset += 24;
+ }
+
+ tzone_offset *= 100;
+ char buf[1024];
+ // add todays year day and month to the time in str because
+ // curl_getdate no longer assumes the day is today
+ sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900,
+ lctime->tm_mon + 1, lctime->tm_mday,
+ this->CTest->GetStopTime().c_str(), tzone_offset);
+
+ time_t stop_time = curl_getdate(buf, &current_time);
+ if (stop_time == -1) {
+ return timeout;
+ }
+
+ // the stop time refers to the next day
+ if (this->CTest->NextDayStopTime) {
+ stop_time += 24 * 60 * 60;
+ }
+ int stop_timeout =
+ static_cast<int>(stop_time - current_time) % (24 * 60 * 60);
+ this->CTest->LastStopTimeout = stop_timeout;
+
+ if (stop_timeout <= 0 || stop_timeout > this->CTest->LastStopTimeout) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. "
+ "Stopping all tests."
+ << std::endl);
+ this->StopTimePassed = true;
+ return 0;
+ }
+ return timeout == 0 ? stop_timeout
+ : (timeout < stop_timeout ? timeout : stop_timeout);
+}
+
+bool cmCTestRunTest::ForkProcess(double testTimeOut, bool explicitTimeout,
+ std::vector<std::string>* environment)
+{
+ this->TestProcess = new cmProcess;
+ this->TestProcess->SetId(this->Index);
+ this->TestProcess->SetWorkingDirectory(
+ this->TestProperties->Directory.c_str());
+ this->TestProcess->SetCommand(this->ActualCommand.c_str());
+ this->TestProcess->SetCommandArguments(this->Arguments);
+
+ // determine how much time we have
+ double timeout = this->CTest->GetRemainingTimeAllowed() - 120;
+ if (this->CTest->GetTimeOut() > 0 && this->CTest->GetTimeOut() < timeout) {
+ timeout = this->CTest->GetTimeOut();
+ }
+ if (testTimeOut > 0 &&
+ testTimeOut < this->CTest->GetRemainingTimeAllowed()) {
+ timeout = testTimeOut;
+ }
+ // always have at least 1 second if we got to here
+ if (timeout <= 0) {
+ timeout = 1;
+ }
+ // handle timeout explicitly set to 0
+ if (testTimeOut == 0 && explicitTimeout) {
+ timeout = 0;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index
+ << ": "
+ << "Test timeout computed to be: " << timeout << "\n",
+ this->TestHandler->GetQuiet());
+
+ this->TestProcess->SetTimeout(timeout);
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ cmSystemTools::SaveRestoreEnvironment sre;
+#endif
+
+ if (environment && !environment->empty()) {
+ cmSystemTools::AppendEnv(*environment);
+ }
+
+ return this->TestProcess->StartProcess();
+}
+
+void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total)
+{
+ // if this is the last or only run of this test
+ // then print out completed / total
+ // Only issue is if a test fails and we are running until fail
+ // then it will never print out the completed / total, same would
+ // got for run until pass. Trick is when this is called we don't
+ // yet know if we are passing or failing.
+ if (this->NumberOfRunsLeft == 1) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(getNumWidth(total))
+ << completed << "/");
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(getNumWidth(total))
+ << total << " ");
+ }
+ // if this is one of several runs of a test just print blank space
+ // to keep things neat
+ else {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(getNumWidth(total))
+ << " "
+ << " ");
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(getNumWidth(total))
+ << " "
+ << " ");
+ }
+
+ if (this->TestHandler->MemCheck) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "MemCheck");
+ } else {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "Test");
+ }
+
+ std::ostringstream indexStr;
+ indexStr << " #" << this->Index << ":";
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ std::setw(3 + getNumWidth(this->TestHandler->GetMaxIndex()))
+ << indexStr.str());
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
+ const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth();
+ std::string outname = this->TestProperties->Name + " ";
+ outname.resize(maxTestNameWidth + 4, '.');
+
+ *this->TestHandler->LogFile << this->TestProperties->Index << "/"
+ << this->TestHandler->TotalNumberOfTests
+ << " Testing: " << this->TestProperties->Name
+ << std::endl;
+ *this->TestHandler->LogFile << this->TestProperties->Index << "/"
+ << this->TestHandler->TotalNumberOfTests
+ << " Test: " << this->TestProperties->Name
+ << std::endl;
+ *this->TestHandler->LogFile << "Command: \"" << this->ActualCommand << "\"";
+
+ for (std::vector<std::string>::iterator i = this->Arguments.begin();
+ i != this->Arguments.end(); ++i) {
+ *this->TestHandler->LogFile << " \"" << *i << "\"";
+ }
+ *this->TestHandler->LogFile
+ << std::endl
+ << "Directory: " << this->TestProperties->Directory << std::endl
+ << "\"" << this->TestProperties->Name
+ << "\" start time: " << this->StartTime << std::endl;
+
+ *this->TestHandler->LogFile
+ << "Output:" << std::endl
+ << "----------------------------------------------------------"
+ << std::endl;
+ *this->TestHandler->LogFile << this->ProcessOutput << "<end of output>"
+ << std::endl;
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str());
+ cmCTestLog(this->CTest, DEBUG, "Testing " << this->TestProperties->Name
+ << " ... ");
+}
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
new file mode 100644
index 0000000..3dcc026
--- /dev/null
+++ b/Source/CTest/cmCTestRunTest.h
@@ -0,0 +1,125 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestRunTest_h
+#define cmCTestRunTest_h
+
+#include <cmCTestTestHandler.h>
+
+#include <cmProcess.h>
+
+/** \class cmRunTest
+ * \brief represents a single test to be run
+ *
+ * cmRunTest contains the information related to running a single test
+ */
+class cmCTestRunTest
+{
+public:
+ cmCTestRunTest(cmCTestTestHandler* handler);
+ ~cmCTestRunTest();
+
+ void SetNumberOfRuns(int n) { this->NumberOfRunsLeft = n; }
+ void SetRunUntilFailOn() { this->RunUntilFail = true; }
+ void SetTestProperties(cmCTestTestHandler::cmCTestTestProperties* prop)
+ {
+ this->TestProperties = prop;
+ }
+
+ cmCTestTestHandler::cmCTestTestProperties* GetTestProperties()
+ {
+ return this->TestProperties;
+ }
+
+ void SetIndex(int i) { this->Index = i; }
+
+ int GetIndex() { return this->Index; }
+
+ std::string GetProcessOutput() { return this->ProcessOutput; }
+
+ bool IsStopTimePassed() { return this->StopTimePassed; }
+
+ cmCTestTestHandler::cmCTestTestResult GetTestResults()
+ {
+ return this->TestResult;
+ }
+
+ // Read and store output. Returns true if it must be called again.
+ bool CheckOutput();
+
+ // Compresses the output, writing to CompressedOutput
+ void CompressOutput();
+
+ // launch the test process, return whether it started correctly
+ bool StartTest(size_t total);
+ // capture and report the test results
+ bool EndTest(size_t completed, size_t total, bool started);
+ // Called by ctest -N to log the command string
+ void ComputeArguments();
+
+ void ComputeWeightedCost();
+
+ bool StartAgain();
+
+private:
+ bool NeedsToRerun();
+ void DartProcessing();
+ void ExeNotFound(std::string exe);
+ // Figures out a final timeout which is min(STOP_TIME, NOW+TIMEOUT)
+ double ResolveTimeout();
+ bool ForkProcess(double testTimeOut, bool explicitTimeout,
+ std::vector<std::string>* environment);
+ void WriteLogOutputTop(size_t completed, size_t total);
+ // Run post processing of the process output for MemCheck
+ void MemCheckPostProcess();
+
+ cmCTestTestHandler::cmCTestTestProperties* TestProperties;
+ // Pointer back to the "parent"; the handler that invoked this test run
+ cmCTestTestHandler* TestHandler;
+ cmCTest* CTest;
+ cmProcess* TestProcess;
+ // If the executable to run is ctest, don't create a new process;
+ // just instantiate a new cmTest. (Can be disabled for a single test
+ // if this option is set to false.)
+ // bool OptimizeForCTest;
+
+ bool UsePrefixCommand;
+ std::string PrefixCommand;
+
+ std::string ProcessOutput;
+ std::string CompressedOutput;
+ double CompressionRatio;
+ // The test results
+ cmCTestTestHandler::cmCTestTestResult TestResult;
+ int Index;
+ std::string StartTime;
+ std::string ActualCommand;
+ std::vector<std::string> Arguments;
+ bool StopTimePassed;
+ bool RunUntilFail;
+ int NumberOfRunsLeft;
+ bool RunAgain;
+ size_t TotalNumberOfTests;
+};
+
+inline int getNumWidth(size_t n)
+{
+ int numWidth = 1;
+ if (n >= 10) {
+ numWidth = 2;
+ }
+ if (n >= 100) {
+ numWidth = 3;
+ }
+ return numWidth;
+}
+
+#endif
diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx
new file mode 100644
index 0000000..eae0c6c
--- /dev/null
+++ b/Source/CTest/cmCTestSVN.cxx
@@ -0,0 +1,561 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestSVN.h"
+
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include "cmXMLWriter.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+struct cmCTestSVN::Revision : public cmCTestVC::Revision
+{
+ cmCTestSVN::SVNInfo* SVNInfo;
+};
+
+cmCTestSVN::cmCTestSVN(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
+{
+ this->PriorRev = this->Unknown;
+}
+
+cmCTestSVN::~cmCTestSVN()
+{
+}
+
+void cmCTestSVN::CleanupImpl()
+{
+ std::vector<const char*> svn_cleanup;
+ svn_cleanup.push_back("cleanup");
+ OutputLogger out(this->Log, "cleanup-out> ");
+ OutputLogger err(this->Log, "cleanup-err> ");
+ this->RunSVNCommand(svn_cleanup, &out, &err);
+}
+
+class cmCTestSVN::InfoParser : public cmCTestVC::LineParser
+{
+public:
+ InfoParser(cmCTestSVN* svn, const char* prefix, std::string& rev,
+ SVNInfo& svninfo)
+ : Rev(rev)
+ , SVNRepo(svninfo)
+ {
+ this->SetLog(&svn->Log, prefix);
+ this->RegexRev.compile("^Revision: ([0-9]+)");
+ this->RegexURL.compile("^URL: +([^ ]+) *$");
+ this->RegexRoot.compile("^Repository Root: +([^ ]+) *$");
+ }
+
+private:
+ std::string& Rev;
+ cmCTestSVN::SVNInfo& SVNRepo;
+ cmsys::RegularExpression RegexRev;
+ cmsys::RegularExpression RegexURL;
+ cmsys::RegularExpression RegexRoot;
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexRev.find(this->Line)) {
+ this->Rev = this->RegexRev.match(1);
+ } else if (this->RegexURL.find(this->Line)) {
+ this->SVNRepo.URL = this->RegexURL.match(1);
+ } else if (this->RegexRoot.find(this->Line)) {
+ this->SVNRepo.Root = this->RegexRoot.match(1);
+ }
+ return true;
+ }
+};
+
+static bool cmCTestSVNPathStarts(std::string const& p1, std::string const& p2)
+{
+ // Does path p1 start with path p2?
+ if (p1.size() == p2.size()) {
+ return p1 == p2;
+ } else if (p1.size() > p2.size() && p1[p2.size()] == '/') {
+ return strncmp(p1.c_str(), p2.c_str(), p2.size()) == 0;
+ } else {
+ return false;
+ }
+}
+
+std::string cmCTestSVN::LoadInfo(SVNInfo& svninfo)
+{
+ // Run "svn info" to get the repository info from the work tree.
+ std::vector<const char*> svn_info;
+ svn_info.push_back("info");
+ svn_info.push_back(svninfo.LocalPath.c_str());
+ std::string rev;
+ InfoParser out(this, "info-out> ", rev, svninfo);
+ OutputLogger err(this->Log, "info-err> ");
+ this->RunSVNCommand(svn_info, &out, &err);
+ return rev;
+}
+
+void cmCTestSVN::NoteOldRevision()
+{
+ // Info for root repository
+ this->Repositories.push_back(SVNInfo(""));
+ this->RootInfo = &(this->Repositories.back());
+ // Info for the external repositories
+ this->LoadExternals();
+
+ // Get info for all the repositories
+ std::list<SVNInfo>::iterator itbeg = this->Repositories.begin();
+ std::list<SVNInfo>::iterator itend = this->Repositories.end();
+ for (; itbeg != itend; itbeg++) {
+ SVNInfo& svninfo = *itbeg;
+ svninfo.OldRevision = this->LoadInfo(svninfo);
+ this->Log << "Revision for repository '" << svninfo.LocalPath
+ << "' before update: " << svninfo.OldRevision << "\n";
+ cmCTestLog(
+ this->CTest, HANDLER_OUTPUT, " Old revision of external repository '"
+ << svninfo.LocalPath << "' is: " << svninfo.OldRevision << "\n");
+ }
+
+ // Set the global old revision to the one of the root
+ this->OldRevision = this->RootInfo->OldRevision;
+ this->PriorRev.Rev = this->OldRevision;
+}
+
+void cmCTestSVN::NoteNewRevision()
+{
+ // Get info for the external repositories
+ std::list<SVNInfo>::iterator itbeg = this->Repositories.begin();
+ std::list<SVNInfo>::iterator itend = this->Repositories.end();
+ for (; itbeg != itend; itbeg++) {
+ SVNInfo& svninfo = *itbeg;
+ svninfo.NewRevision = this->LoadInfo(svninfo);
+ this->Log << "Revision for repository '" << svninfo.LocalPath
+ << "' after update: " << svninfo.NewRevision << "\n";
+ cmCTestLog(
+ this->CTest, HANDLER_OUTPUT, " New revision of external repository '"
+ << svninfo.LocalPath << "' is: " << svninfo.NewRevision << "\n");
+
+ // svninfo.Root = ""; // uncomment to test GuessBase
+ this->Log << "Repository '" << svninfo.LocalPath
+ << "' URL = " << svninfo.URL << "\n";
+ this->Log << "Repository '" << svninfo.LocalPath
+ << "' Root = " << svninfo.Root << "\n";
+
+ // Compute the base path the working tree has checked out under
+ // the repository root.
+ if (!svninfo.Root.empty() &&
+ cmCTestSVNPathStarts(svninfo.URL, svninfo.Root)) {
+ svninfo.Base =
+ cmCTest::DecodeURL(svninfo.URL.substr(svninfo.Root.size()));
+ svninfo.Base += "/";
+ }
+ this->Log << "Repository '" << svninfo.LocalPath
+ << "' Base = " << svninfo.Base << "\n";
+ }
+
+ // Set the global new revision to the one of the root
+ this->NewRevision = this->RootInfo->NewRevision;
+}
+
+void cmCTestSVN::GuessBase(SVNInfo& svninfo,
+ std::vector<Change> const& changes)
+{
+ // Subversion did not give us a good repository root so we need to
+ // guess the base path from the URL and the paths in a revision with
+ // changes under it.
+
+ // Consider each possible URL suffix from longest to shortest.
+ for (std::string::size_type slash = svninfo.URL.find('/');
+ svninfo.Base.empty() && slash != std::string::npos;
+ slash = svninfo.URL.find('/', slash + 1)) {
+ // If the URL suffix is a prefix of at least one path then it is the base.
+ std::string base = cmCTest::DecodeURL(svninfo.URL.substr(slash));
+ for (std::vector<Change>::const_iterator ci = changes.begin();
+ svninfo.Base.empty() && ci != changes.end(); ++ci) {
+ if (cmCTestSVNPathStarts(ci->Path, base)) {
+ svninfo.Base = base;
+ }
+ }
+ }
+
+ // We always append a slash so that we know paths beginning in the
+ // base lie under its path. If no base was found then the working
+ // tree must be a checkout of the entire repo and this will match
+ // the leading slash in all paths.
+ svninfo.Base += "/";
+
+ this->Log << "Guessed Base = " << svninfo.Base << "\n";
+}
+
+class cmCTestSVN::UpdateParser : public cmCTestVC::LineParser
+{
+public:
+ UpdateParser(cmCTestSVN* svn, const char* prefix)
+ : SVN(svn)
+ {
+ this->SetLog(&svn->Log, prefix);
+ this->RegexUpdate.compile("^([ADUCGE ])([ADUCGE ])[B ] +(.+)$");
+ }
+
+private:
+ cmCTestSVN* SVN;
+ cmsys::RegularExpression RegexUpdate;
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexUpdate.find(this->Line)) {
+ this->DoPath(this->RegexUpdate.match(1)[0],
+ this->RegexUpdate.match(2)[0], this->RegexUpdate.match(3));
+ }
+ return true;
+ }
+
+ void DoPath(char path_status, char prop_status, std::string const& path)
+ {
+ char status = (path_status != ' ') ? path_status : prop_status;
+ std::string dir = cmSystemTools::GetFilenamePath(path);
+ std::string name = cmSystemTools::GetFilenameName(path);
+ // See "svn help update".
+ switch (status) {
+ case 'G':
+ this->SVN->Dirs[dir][name].Status = PathModified;
+ break;
+ case 'C':
+ this->SVN->Dirs[dir][name].Status = PathConflicting;
+ break;
+ case 'A':
+ case 'D':
+ case 'U':
+ this->SVN->Dirs[dir][name].Status = PathUpdated;
+ break;
+ case 'E': // TODO?
+ case '?':
+ case ' ':
+ default:
+ break;
+ }
+ }
+};
+
+bool cmCTestSVN::UpdateImpl()
+{
+ // Get user-specified update options.
+ std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
+ if (opts.empty()) {
+ opts = this->CTest->GetCTestConfiguration("SVNUpdateOptions");
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+
+ // Specify the start time for nightly testing.
+ if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
+ args.push_back("-r{" + this->GetNightlyTime() + " +0000}");
+ }
+
+ std::vector<char const*> svn_update;
+ svn_update.push_back("update");
+ for (std::vector<std::string>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai) {
+ svn_update.push_back(ai->c_str());
+ }
+
+ UpdateParser out(this, "up-out> ");
+ OutputLogger err(this->Log, "up-err> ");
+ return this->RunSVNCommand(svn_update, &out, &err);
+}
+
+bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters,
+ OutputParser* out, OutputParser* err)
+{
+ if (parameters.empty()) {
+ return false;
+ }
+
+ std::vector<char const*> args;
+ args.push_back(this->CommandLineTool.c_str());
+
+ args.insert(args.end(), parameters.begin(), parameters.end());
+
+ args.push_back("--non-interactive");
+
+ std::string userOptions = this->CTest->GetCTestConfiguration("SVNOptions");
+
+ std::vector<std::string> parsedUserOptions =
+ cmSystemTools::ParseArguments(userOptions.c_str());
+ for (std::vector<std::string>::iterator i = parsedUserOptions.begin();
+ i != parsedUserOptions.end(); ++i) {
+ args.push_back(i->c_str());
+ }
+
+ args.push_back(CM_NULLPTR);
+
+ if (strcmp(parameters[0], "update") == 0) {
+ return RunUpdateCommand(&args[0], out, err);
+ } else {
+ return RunChild(&args[0], out, err);
+ }
+}
+
+class cmCTestSVN::LogParser : public cmCTestVC::OutputLogger,
+ private cmXMLParser
+{
+public:
+ LogParser(cmCTestSVN* svn, const char* prefix, SVNInfo& svninfo)
+ : OutputLogger(svn->Log, prefix)
+ , SVN(svn)
+ , SVNRepo(svninfo)
+ {
+ this->InitializeParser();
+ }
+ ~LogParser() CM_OVERRIDE { this->CleanupParser(); }
+private:
+ cmCTestSVN* SVN;
+ cmCTestSVN::SVNInfo& SVNRepo;
+
+ typedef cmCTestSVN::Revision Revision;
+ typedef cmCTestSVN::Change Change;
+ Revision Rev;
+ std::vector<Change> Changes;
+ Change CurChange;
+ std::vector<char> CData;
+
+ bool ProcessChunk(const char* data, int length) CM_OVERRIDE
+ {
+ this->OutputLogger::ProcessChunk(data, length);
+ this->ParseChunk(data, length);
+ return true;
+ }
+
+ void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
+ {
+ this->CData.clear();
+ if (name == "logentry") {
+ this->Rev = Revision();
+ this->Rev.SVNInfo = &SVNRepo;
+ if (const char* rev = this->FindAttribute(atts, "revision")) {
+ this->Rev.Rev = rev;
+ }
+ this->Changes.clear();
+ } else if (name == "path") {
+ this->CurChange = Change();
+ if (const char* action = this->FindAttribute(atts, "action")) {
+ this->CurChange.Action = action[0];
+ }
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) CM_OVERRIDE
+ {
+ this->CData.insert(this->CData.end(), data, data + length);
+ }
+
+ void EndElement(const std::string& name) CM_OVERRIDE
+ {
+ if (name == "logentry") {
+ this->SVN->DoRevisionSVN(this->Rev, this->Changes);
+ } else if (!this->CData.empty() && name == "path") {
+ std::string orig_path(&this->CData[0], this->CData.size());
+ std::string new_path = SVNRepo.BuildLocalPath(orig_path);
+ this->CurChange.Path.assign(new_path);
+ this->Changes.push_back(this->CurChange);
+ } else if (!this->CData.empty() && name == "author") {
+ this->Rev.Author.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "date") {
+ this->Rev.Date.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "msg") {
+ this->Rev.Log.assign(&this->CData[0], this->CData.size());
+ }
+ this->CData.clear();
+ }
+
+ void ReportError(int, int, const char* msg) CM_OVERRIDE
+ {
+ this->SVN->Log << "Error parsing svn log xml: " << msg << "\n";
+ }
+};
+
+void cmCTestSVN::LoadRevisions()
+{
+ // Get revisions for all the external repositories
+ std::list<SVNInfo>::iterator itbeg = this->Repositories.begin();
+ std::list<SVNInfo>::iterator itend = this->Repositories.end();
+ for (; itbeg != itend; itbeg++) {
+ SVNInfo& svninfo = *itbeg;
+ LoadRevisions(svninfo);
+ }
+}
+
+void cmCTestSVN::LoadRevisions(SVNInfo& svninfo)
+{
+ // We are interested in every revision included in the update.
+ std::string revs;
+ if (atoi(svninfo.OldRevision.c_str()) < atoi(svninfo.NewRevision.c_str())) {
+ revs = "-r" + svninfo.OldRevision + ":" + svninfo.NewRevision;
+ } else {
+ revs = "-r" + svninfo.NewRevision;
+ }
+
+ // Run "svn log" to get all global revisions of interest.
+ std::vector<const char*> svn_log;
+ svn_log.push_back("log");
+ svn_log.push_back("--xml");
+ svn_log.push_back("-v");
+ svn_log.push_back(revs.c_str());
+ svn_log.push_back(svninfo.LocalPath.c_str());
+ LogParser out(this, "log-out> ", svninfo);
+ OutputLogger err(this->Log, "log-err> ");
+ this->RunSVNCommand(svn_log, &out, &err);
+}
+
+void cmCTestSVN::DoRevisionSVN(Revision const& revision,
+ std::vector<Change> const& changes)
+{
+ // Guess the base checkout path from the changes if necessary.
+ if (this->RootInfo->Base.empty() && !changes.empty()) {
+ this->GuessBase(*this->RootInfo, changes);
+ }
+
+ // Ignore changes in the old revision for external repositories
+ if (revision.Rev == revision.SVNInfo->OldRevision &&
+ revision.SVNInfo->LocalPath != "") {
+ return;
+ }
+
+ this->cmCTestGlobalVC::DoRevision(revision, changes);
+}
+
+class cmCTestSVN::StatusParser : public cmCTestVC::LineParser
+{
+public:
+ StatusParser(cmCTestSVN* svn, const char* prefix)
+ : SVN(svn)
+ {
+ this->SetLog(&svn->Log, prefix);
+ this->RegexStatus.compile("^([ACDIMRX?!~ ])([CM ])[ L]... +(.+)$");
+ }
+
+private:
+ cmCTestSVN* SVN;
+ cmsys::RegularExpression RegexStatus;
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexStatus.find(this->Line)) {
+ this->DoPath(this->RegexStatus.match(1)[0],
+ this->RegexStatus.match(2)[0], this->RegexStatus.match(3));
+ }
+ return true;
+ }
+
+ void DoPath(char path_status, char prop_status, std::string const& path)
+ {
+ char status = (path_status != ' ') ? path_status : prop_status;
+ // See "svn help status".
+ switch (status) {
+ case 'M':
+ case '!':
+ case 'A':
+ case 'D':
+ case 'R':
+ this->SVN->DoModification(PathModified, path);
+ break;
+ case 'C':
+ case '~':
+ this->SVN->DoModification(PathConflicting, path);
+ break;
+ case 'X':
+ case 'I':
+ case '?':
+ case ' ':
+ default:
+ break;
+ }
+ }
+};
+
+void cmCTestSVN::LoadModifications()
+{
+ // Run "svn status" which reports local modifications.
+ std::vector<const char*> svn_status;
+ svn_status.push_back("status");
+ StatusParser out(this, "status-out> ");
+ OutputLogger err(this->Log, "status-err> ");
+ this->RunSVNCommand(svn_status, &out, &err);
+}
+
+void cmCTestSVN::WriteXMLGlobal(cmXMLWriter& xml)
+{
+ this->cmCTestGlobalVC::WriteXMLGlobal(xml);
+
+ xml.Element("SVNPath", this->RootInfo->Base);
+}
+
+class cmCTestSVN::ExternalParser : public cmCTestVC::LineParser
+{
+public:
+ ExternalParser(cmCTestSVN* svn, const char* prefix)
+ : SVN(svn)
+ {
+ this->SetLog(&svn->Log, prefix);
+ this->RegexExternal.compile("^X..... +(.+)$");
+ }
+
+private:
+ cmCTestSVN* SVN;
+ cmsys::RegularExpression RegexExternal;
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexExternal.find(this->Line)) {
+ this->DoPath(this->RegexExternal.match(1));
+ }
+ return true;
+ }
+
+ void DoPath(std::string const& path)
+ {
+ // Get local path relative to the source directory
+ std::string local_path;
+ 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;
+ } else {
+ local_path = path;
+ }
+ this->SVN->Repositories.push_back(SVNInfo(local_path.c_str()));
+ }
+};
+
+void cmCTestSVN::LoadExternals()
+{
+ // Run "svn status" to get the list of external repositories
+ std::vector<const char*> svn_status;
+ svn_status.push_back("status");
+ ExternalParser out(this, "external-out> ");
+ OutputLogger err(this->Log, "external-err> ");
+ this->RunSVNCommand(svn_status, &out, &err);
+}
+
+std::string cmCTestSVN::SVNInfo::BuildLocalPath(std::string const& path) const
+{
+ std::string local_path;
+
+ // Add local path prefix if not empty
+ if (!this->LocalPath.empty()) {
+ local_path += this->LocalPath;
+ local_path += "/";
+ }
+
+ // 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());
+ } else {
+ local_path += path;
+ }
+
+ return local_path;
+}
diff --git a/Source/CTest/cmCTestSVN.h b/Source/CTest/cmCTestSVN.h
new file mode 100644
index 0000000..4f3eb88
--- /dev/null
+++ b/Source/CTest/cmCTestSVN.h
@@ -0,0 +1,105 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestSVN_h
+#define cmCTestSVN_h
+
+#include "cmCTestGlobalVC.h"
+
+#include <list>
+
+/** \class cmCTestSVN
+ * \brief Interaction with subversion command-line tool
+ *
+ */
+class cmCTestSVN : public cmCTestGlobalVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestSVN(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestSVN() CM_OVERRIDE;
+
+private:
+ // Implement cmCTestVC internal API.
+ void CleanupImpl() CM_OVERRIDE;
+ void NoteOldRevision() CM_OVERRIDE;
+ void NoteNewRevision() CM_OVERRIDE;
+ bool UpdateImpl() CM_OVERRIDE;
+
+ bool RunSVNCommand(std::vector<char const*> const& parameters,
+ OutputParser* out, OutputParser* err);
+
+ // Information about an SVN repository (root repository or external)
+ struct SVNInfo
+ {
+
+ SVNInfo(const char* path)
+ : LocalPath(path)
+ {
+ }
+ // Remove base from the filename
+ std::string BuildLocalPath(std::string const& path) const;
+
+ // LocalPath relative to the main source directory.
+ std::string LocalPath;
+
+ // URL of repository directory checked out in the working tree.
+ std::string URL;
+
+ // URL of repository root directory.
+ std::string Root;
+
+ // Directory under repository root checked out in working tree.
+ std::string Base;
+
+ // Old and new repository revisions.
+ std::string OldRevision;
+ std::string NewRevision;
+ };
+
+ // Extended revision structure to include info about external it refers to.
+ struct Revision;
+ friend struct Revision;
+
+ // Info of all the repositories (root, externals and nested ones).
+ std::list<SVNInfo> Repositories;
+
+ // Pointer to the infos of the root repository.
+ SVNInfo* RootInfo;
+
+ std::string LoadInfo(SVNInfo& svninfo);
+ void LoadExternals();
+ void LoadModifications() CM_OVERRIDE;
+ void LoadRevisions() CM_OVERRIDE;
+ void LoadRevisions(SVNInfo& svninfo);
+
+ void GuessBase(SVNInfo& svninfo, std::vector<Change> const& changes);
+
+ void DoRevisionSVN(Revision const& revision,
+ std::vector<Change> const& changes);
+
+ void WriteXMLGlobal(cmXMLWriter& xml) CM_OVERRIDE;
+
+ // Parsing helper classes.
+ class InfoParser;
+ class LogParser;
+ class StatusParser;
+ class UpdateParser;
+ class ExternalParser;
+ friend class InfoParser;
+ friend class LogParser;
+ friend class StatusParser;
+ friend class UpdateParser;
+ friend class ExternalParser;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
new file mode 100644
index 0000000..b747c64
--- /dev/null
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -0,0 +1,987 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCTestScriptHandler.h"
+
+#include "cmCTest.h"
+#include "cmFunctionBlocker.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmake.h"
+
+//#include <cmsys/RegularExpression.hxx>
+#include <cmsys/Directory.hxx>
+#include <cmsys/Process.h>
+
+// used for sleep
+#ifdef _WIN32
+#include "windows.h"
+#endif
+
+#include <float.h>
+#include <math.h>
+#include <stdlib.h>
+#include <time.h>
+
+// needed for sleep
+#if !defined(_WIN32)
+#include <unistd.h>
+#endif
+
+#include "cmCTestBuildCommand.h"
+#include "cmCTestConfigureCommand.h"
+#include "cmCTestCoverageCommand.h"
+#include "cmCTestEmptyBinaryDirectoryCommand.h"
+#include "cmCTestMemCheckCommand.h"
+#include "cmCTestReadCustomFilesCommand.h"
+#include "cmCTestRunScriptCommand.h"
+#include "cmCTestSleepCommand.h"
+#include "cmCTestStartCommand.h"
+#include "cmCTestSubmitCommand.h"
+#include "cmCTestTestCommand.h"
+#include "cmCTestUpdateCommand.h"
+#include "cmCTestUploadCommand.h"
+
+#define CTEST_INITIAL_CMAKE_OUTPUT_FILE_NAME "CTestInitialCMakeOutput.log"
+
+// used to keep elapsed time up to date
+class cmCTestScriptFunctionBlocker : public cmFunctionBlocker
+{
+public:
+ cmCTestScriptFunctionBlocker() {}
+ ~cmCTestScriptFunctionBlocker() CM_OVERRIDE {}
+ bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf,
+ cmExecutionStatus&) CM_OVERRIDE;
+ // virtual bool ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf);
+ // virtual void ScopeEnded(cmMakefile &mf);
+
+ cmCTestScriptHandler* CTestScriptHandler;
+};
+
+// simply update the time and don't block anything
+bool cmCTestScriptFunctionBlocker::IsFunctionBlocked(const cmListFileFunction&,
+ cmMakefile&,
+ cmExecutionStatus&)
+{
+ this->CTestScriptHandler->UpdateElapsedTime();
+ return false;
+}
+
+cmCTestScriptHandler::cmCTestScriptHandler()
+{
+ this->Backup = false;
+ this->EmptyBinDir = false;
+ this->EmptyBinDirOnce = false;
+ this->Makefile = CM_NULLPTR;
+ this->CMake = CM_NULLPTR;
+ this->GlobalGenerator = CM_NULLPTR;
+
+ this->ScriptStartTime = 0;
+
+ // the *60 is becuase the settings are in minutes but GetTime is seconds
+ this->MinimumInterval = 30 * 60;
+ this->ContinuousDuration = -1;
+}
+
+void cmCTestScriptHandler::Initialize()
+{
+ this->Superclass::Initialize();
+ this->Backup = false;
+ this->EmptyBinDir = false;
+ this->EmptyBinDirOnce = false;
+
+ this->SourceDir = "";
+ this->BinaryDir = "";
+ this->BackupSourceDir = "";
+ this->BackupBinaryDir = "";
+ this->CTestRoot = "";
+ this->CVSCheckOut = "";
+ this->CTestCmd = "";
+ this->UpdateCmd = "";
+ this->CTestEnv = "";
+ this->InitialCache = "";
+ this->CMakeCmd = "";
+ this->CMOutFile = "";
+ this->ExtraUpdates.clear();
+
+ this->MinimumInterval = 20 * 60;
+ this->ContinuousDuration = -1;
+
+ // what time in seconds did this script start running
+ this->ScriptStartTime = 0;
+
+ delete this->Makefile;
+ this->Makefile = CM_NULLPTR;
+
+ delete this->GlobalGenerator;
+ this->GlobalGenerator = CM_NULLPTR;
+
+ delete this->CMake;
+}
+
+cmCTestScriptHandler::~cmCTestScriptHandler()
+{
+ delete this->Makefile;
+ delete this->GlobalGenerator;
+ delete this->CMake;
+}
+
+// just adds an argument to the vector
+void cmCTestScriptHandler::AddConfigurationScript(const char* script,
+ bool pscope)
+{
+ this->ConfigurationScripts.push_back(script);
+ this->ScriptProcessScope.push_back(pscope);
+}
+
+// the generic entry point for handling scripts, this routine will run all
+// the scripts provides a -S arguments
+int cmCTestScriptHandler::ProcessHandler()
+{
+ int res = 0;
+ for (size_t i = 0; i < this->ConfigurationScripts.size(); ++i) {
+ // for each script run it
+ res |= this->RunConfigurationScript(
+ cmSystemTools::CollapseFullPath(this->ConfigurationScripts[i]),
+ this->ScriptProcessScope[i]);
+ }
+ if (res) {
+ return -1;
+ }
+ return 0;
+}
+
+void cmCTestScriptHandler::UpdateElapsedTime()
+{
+ if (this->Makefile) {
+ // set the current elapsed time
+ char timeString[20];
+ int itime = static_cast<unsigned int>(cmSystemTools::GetTime() -
+ this->ScriptStartTime);
+ sprintf(timeString, "%i", itime);
+ this->Makefile->AddDefinition("CTEST_ELAPSED_TIME", timeString);
+ }
+}
+
+void cmCTestScriptHandler::AddCTestCommand(cmCTestCommand* command)
+{
+ cmCTestCommand* newCom = command;
+ newCom->CTest = this->CTest;
+ newCom->CTestScriptHandler = this;
+ this->CMake->GetState()->AddCommand(newCom);
+}
+
+int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
+{
+ // execute the script passing in the arguments to the script as well as the
+ // arguments from this invocation of cmake
+ std::vector<const char*> argv;
+ argv.push_back(cmSystemTools::GetCTestCommand().c_str());
+ argv.push_back("-SR");
+ argv.push_back(total_script_arg.c_str());
+
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Executable for CTest is: "
+ << cmSystemTools::GetCTestCommand() << "\n");
+
+ // now pass through all the other arguments
+ std::vector<std::string>& initArgs =
+ this->CTest->GetInitialCommandLineArguments();
+ //*** need to make sure this does not have the current script ***
+ for (size_t i = 1; i < initArgs.size(); ++i) {
+ argv.push_back(initArgs[i].c_str());
+ }
+ argv.push_back(CM_NULLPTR);
+
+ // Now create process object
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, &*argv.begin());
+ // cmsysProcess_SetWorkingDirectory(cp, dir);
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ // cmsysProcess_SetTimeout(cp, timeout);
+ cmsysProcess_Execute(cp);
+
+ std::vector<char> out;
+ std::vector<char> err;
+ std::string line;
+ int pipe = cmSystemTools::WaitForLine(cp, line, 100.0, out, err);
+ while (pipe != cmsysProcess_Pipe_None) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Output: " << line
+ << "\n");
+ if (pipe == cmsysProcess_Pipe_STDERR) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, line << "\n");
+ } else if (pipe == cmsysProcess_Pipe_STDOUT) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n");
+ }
+ pipe = cmSystemTools::WaitForLine(cp, line, 100, out, err);
+ }
+
+ // Properly handle output of the build command
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+ int result = cmsysProcess_GetState(cp);
+ int retVal = 0;
+ bool failed = false;
+ if (result == cmsysProcess_State_Exited) {
+ retVal = cmsysProcess_GetExitValue(cp);
+ } else if (result == cmsysProcess_State_Exception) {
+ retVal = cmsysProcess_GetExitException(cp);
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was an exception: "
+ << cmsysProcess_GetExceptionString(cp) << " " << retVal
+ << std::endl);
+ failed = true;
+ } else if (result == cmsysProcess_State_Expired) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was a timeout"
+ << std::endl);
+ failed = true;
+ } else if (result == cmsysProcess_State_Error) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "\tError executing ctest: "
+ << cmsysProcess_GetErrorString(cp) << std::endl);
+ failed = true;
+ }
+ cmsysProcess_Delete(cp);
+ if (failed) {
+ std::ostringstream message;
+ message << "Error running command: [";
+ message << result << "] ";
+ for (std::vector<const char*>::iterator i = argv.begin(); i != argv.end();
+ ++i) {
+ if (*i) {
+ message << *i << " ";
+ }
+ }
+ cmCTestLog(this->CTest, ERROR_MESSAGE, message.str() << argv[0]
+ << std::endl);
+ return -1;
+ }
+ return retVal;
+}
+
+static void ctestScriptProgressCallback(const char* m, float, void* cd)
+{
+ cmCTest* ctest = static_cast<cmCTest*>(cd);
+ if (m && *m) {
+ cmCTestLog(ctest, HANDLER_OUTPUT, "-- " << m << std::endl);
+ }
+}
+
+void cmCTestScriptHandler::CreateCMake()
+{
+ // create a cmake instance to read the configuration script
+ if (this->CMake) {
+ delete this->CMake;
+ delete this->GlobalGenerator;
+ delete this->Makefile;
+ }
+ this->CMake = new cmake;
+ this->CMake->SetHomeDirectory("");
+ this->CMake->SetHomeOutputDirectory("");
+ this->CMake->GetCurrentSnapshot().SetDefaultDefinitions();
+ this->CMake->AddCMakePaths();
+ this->GlobalGenerator = new cmGlobalGenerator(this->CMake);
+
+ cmState::Snapshot snapshot = this->CMake->GetCurrentSnapshot();
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ snapshot.GetDirectory().SetCurrentSource(cwd);
+ snapshot.GetDirectory().SetCurrentBinary(cwd);
+ this->Makefile = new cmMakefile(this->GlobalGenerator, snapshot);
+
+ this->CMake->SetProgressCallback(ctestScriptProgressCallback, this->CTest);
+
+ // remove all cmake commands which are not scriptable, since they can't be
+ // used in ctest scripts
+ this->CMake->GetState()->RemoveUnscriptableCommands();
+
+ // add any ctest specific commands, probably should have common superclass
+ // for ctest commands to clean this up. If a couple more commands are
+ // created with the same format lets do that - ken
+ this->AddCTestCommand(new cmCTestBuildCommand);
+ this->AddCTestCommand(new cmCTestConfigureCommand);
+ this->AddCTestCommand(new cmCTestCoverageCommand);
+ this->AddCTestCommand(new cmCTestEmptyBinaryDirectoryCommand);
+ this->AddCTestCommand(new cmCTestMemCheckCommand);
+ this->AddCTestCommand(new cmCTestReadCustomFilesCommand);
+ this->AddCTestCommand(new cmCTestRunScriptCommand);
+ this->AddCTestCommand(new cmCTestSleepCommand);
+ this->AddCTestCommand(new cmCTestStartCommand);
+ this->AddCTestCommand(new cmCTestSubmitCommand);
+ this->AddCTestCommand(new cmCTestTestCommand);
+ this->AddCTestCommand(new cmCTestUpdateCommand);
+ this->AddCTestCommand(new cmCTestUploadCommand);
+}
+
+// this sets up some variables for the script to use, creates the required
+// cmake instance and generators, and then reads in the script
+int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
+{
+ // Reset the error flag so that the script is read in no matter what
+ cmSystemTools::ResetErrorOccuredFlag();
+
+ // if the argument has a , in it then it needs to be broken into the fist
+ // argument (which is the script) and the second argument which will be
+ // passed into the scripts as S_ARG
+ std::string script = total_script_arg;
+ std::string script_arg;
+ const std::string::size_type comma_pos = total_script_arg.find(',');
+ if (comma_pos != std::string::npos) {
+ script = total_script_arg.substr(0, comma_pos);
+ script_arg = total_script_arg.substr(comma_pos + 1);
+ }
+ // make sure the file exists
+ if (!cmSystemTools::FileExists(script.c_str())) {
+ cmSystemTools::Error("Cannot find file: ", script.c_str());
+ return 1;
+ }
+
+ // read in the list file to fill the cache
+ // create a cmake instance to read the configuration script
+ this->CreateCMake();
+
+ // set a variable with the path to the current script
+ this->Makefile->AddDefinition(
+ "CTEST_SCRIPT_DIRECTORY", cmSystemTools::GetFilenamePath(script).c_str());
+ this->Makefile->AddDefinition(
+ "CTEST_SCRIPT_NAME", cmSystemTools::GetFilenameName(script).c_str());
+ this->Makefile->AddDefinition("CTEST_EXECUTABLE_NAME",
+ cmSystemTools::GetCTestCommand().c_str());
+ this->Makefile->AddDefinition("CMAKE_EXECUTABLE_NAME",
+ cmSystemTools::GetCMakeCommand().c_str());
+ this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", true);
+ this->UpdateElapsedTime();
+
+ // add the script arg if defined
+ if (!script_arg.empty()) {
+ this->Makefile->AddDefinition("CTEST_SCRIPT_ARG", script_arg.c_str());
+ }
+
+#if defined(__CYGWIN__)
+ this->Makefile->AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0");
+#endif
+
+ // always add a function blocker to update the elapsed time
+ cmCTestScriptFunctionBlocker* f = new cmCTestScriptFunctionBlocker();
+ f->CTestScriptHandler = this;
+ this->Makefile->AddFunctionBlocker(f);
+
+ /* Execute CTestScriptMode.cmake, which loads CMakeDetermineSystem and
+ CMakeSystemSpecificInformation, so
+ that variables like CMAKE_SYSTEM and also the search paths for libraries,
+ header and executables are set correctly and can be used. Makes new-style
+ ctest scripting easier. */
+ std::string systemFile =
+ this->Makefile->GetModulesFile("CTestScriptMode.cmake");
+ if (!this->Makefile->ReadListFile(systemFile.c_str()) ||
+ cmSystemTools::GetErrorOccuredFlag()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Error in read:" << systemFile
+ << "\n");
+ return 2;
+ }
+
+ // Add definitions of variables passed in on the command line:
+ const std::map<std::string, std::string>& defs =
+ this->CTest->GetDefinitions();
+ for (std::map<std::string, std::string>::const_iterator it = defs.begin();
+ it != defs.end(); ++it) {
+ this->Makefile->AddDefinition(it->first, it->second.c_str());
+ }
+
+ // finally read in the script
+ if (!this->Makefile->ReadListFile(script.c_str()) ||
+ cmSystemTools::GetErrorOccuredFlag()) {
+ // Reset the error flag so that it can run more than
+ // one script with an error when you use ctest_run_script.
+ cmSystemTools::ResetErrorOccuredFlag();
+ return 2;
+ }
+
+ return 0;
+}
+
+// extract variabels from the script to set ivars
+int cmCTestScriptHandler::ExtractVariables()
+{
+ // Temporary variables
+ const char* minInterval;
+ const char* contDuration;
+
+ this->SourceDir =
+ this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
+ this->BinaryDir =
+ this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY");
+
+ // add in translations for src and bin
+ cmSystemTools::AddKeepPath(this->SourceDir);
+ cmSystemTools::AddKeepPath(this->BinaryDir);
+
+ this->CTestCmd = this->Makefile->GetSafeDefinition("CTEST_COMMAND");
+ this->CVSCheckOut = this->Makefile->GetSafeDefinition("CTEST_CVS_CHECKOUT");
+ this->CTestRoot = this->Makefile->GetSafeDefinition("CTEST_DASHBOARD_ROOT");
+ this->UpdateCmd = this->Makefile->GetSafeDefinition("CTEST_UPDATE_COMMAND");
+ if (this->UpdateCmd.empty()) {
+ this->UpdateCmd = this->Makefile->GetSafeDefinition("CTEST_CVS_COMMAND");
+ }
+ this->CTestEnv = this->Makefile->GetSafeDefinition("CTEST_ENVIRONMENT");
+ this->InitialCache =
+ this->Makefile->GetSafeDefinition("CTEST_INITIAL_CACHE");
+ this->CMakeCmd = this->Makefile->GetSafeDefinition("CTEST_CMAKE_COMMAND");
+ this->CMOutFile =
+ this->Makefile->GetSafeDefinition("CTEST_CMAKE_OUTPUT_FILE_NAME");
+
+ this->Backup = this->Makefile->IsOn("CTEST_BACKUP_AND_RESTORE");
+ this->EmptyBinDir =
+ this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY");
+ this->EmptyBinDirOnce =
+ this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY_ONCE");
+
+ minInterval =
+ this->Makefile->GetDefinition("CTEST_CONTINUOUS_MINIMUM_INTERVAL");
+ contDuration = this->Makefile->GetDefinition("CTEST_CONTINUOUS_DURATION");
+
+ char updateVar[40];
+ int i;
+ for (i = 1; i < 10; ++i) {
+ sprintf(updateVar, "CTEST_EXTRA_UPDATES_%i", i);
+ const char* updateVal = this->Makefile->GetDefinition(updateVar);
+ if (updateVal) {
+ if (this->UpdateCmd.empty()) {
+ cmSystemTools::Error(
+ updateVar, " specified without specifying CTEST_CVS_COMMAND.");
+ return 12;
+ }
+ this->ExtraUpdates.push_back(updateVal);
+ }
+ }
+
+ // in order to backup and restore we also must have the cvs root
+ if (this->Backup && this->CVSCheckOut.empty()) {
+ cmSystemTools::Error(
+ "Backup was requested without specifying CTEST_CVS_CHECKOUT.");
+ return 3;
+ }
+
+ // make sure the required info is here
+ if (this->SourceDir.empty() || this->BinaryDir.empty() ||
+ this->CTestCmd.empty()) {
+ std::string msg = "CTEST_SOURCE_DIRECTORY = ";
+ msg += (!this->SourceDir.empty()) ? this->SourceDir.c_str() : "(Null)";
+ msg += "\nCTEST_BINARY_DIRECTORY = ";
+ msg += (!this->BinaryDir.empty()) ? this->BinaryDir.c_str() : "(Null)";
+ 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());
+ return 4;
+ }
+
+ // if the dashboard root isn't specified then we can compute it from the
+ // this->SourceDir
+ if (this->CTestRoot.empty()) {
+ this->CTestRoot = cmSystemTools::GetFilenamePath(this->SourceDir);
+ }
+
+ // the script may override the minimum continuous interval
+ if (minInterval) {
+ this->MinimumInterval = 60 * atof(minInterval);
+ }
+ if (contDuration) {
+ this->ContinuousDuration = 60.0 * atof(contDuration);
+ }
+
+ this->UpdateElapsedTime();
+
+ return 0;
+}
+
+void cmCTestScriptHandler::SleepInSeconds(unsigned int secondsToWait)
+{
+#if defined(_WIN32)
+ Sleep(1000 * secondsToWait);
+#else
+ sleep(secondsToWait);
+#endif
+}
+
+// run a specific script
+int cmCTestScriptHandler::RunConfigurationScript(
+ const std::string& total_script_arg, bool pscope)
+{
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ cmSystemTools::SaveRestoreEnvironment sre;
+#endif
+
+ int result;
+
+ this->ScriptStartTime = cmSystemTools::GetTime();
+
+ // read in the script
+ if (pscope) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading Script: " << total_script_arg << std::endl);
+ result = this->ReadInScript(total_script_arg);
+ } else {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Executing Script: " << total_script_arg << std::endl);
+ result = this->ExecuteScript(total_script_arg);
+ }
+ if (result) {
+ return result;
+ }
+
+ // only run the curent script if we should
+ if (this->Makefile && this->Makefile->IsOn("CTEST_RUN_CURRENT_SCRIPT")) {
+ return this->RunCurrentScript();
+ }
+ return result;
+}
+
+int cmCTestScriptHandler::RunCurrentScript()
+{
+ int result;
+
+ // do not run twice
+ this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", false);
+
+ // no popup widows
+ cmSystemTools::SetRunCommandHideConsole(true);
+
+ // extract the vars from the cache and store in ivars
+ result = this->ExtractVariables();
+ if (result) {
+ return result;
+ }
+
+ // set any environment variables
+ if (!this->CTestEnv.empty()) {
+ std::vector<std::string> envArgs;
+ cmSystemTools::ExpandListArgument(this->CTestEnv, envArgs);
+ cmSystemTools::AppendEnv(envArgs);
+ }
+
+ // now that we have done most of the error checking finally run the
+ // dashboard, we may be asked to repeatedly run this dashboard, such as
+ // for a continuous, do we ned to run it more than once?
+ if (this->ContinuousDuration >= 0) {
+ this->UpdateElapsedTime();
+ double ending_time = cmSystemTools::GetTime() + this->ContinuousDuration;
+ if (this->EmptyBinDirOnce) {
+ this->EmptyBinDir = true;
+ }
+ do {
+ double interval = cmSystemTools::GetTime();
+ result = this->RunConfigurationDashboard();
+ interval = cmSystemTools::GetTime() - interval;
+ if (interval < this->MinimumInterval) {
+ this->SleepInSeconds(
+ static_cast<unsigned int>(this->MinimumInterval - interval));
+ }
+ if (this->EmptyBinDirOnce) {
+ this->EmptyBinDir = false;
+ }
+ } while (cmSystemTools::GetTime() < ending_time);
+ }
+ // otherwise just run it once
+ else {
+ result = this->RunConfigurationDashboard();
+ }
+
+ return result;
+}
+
+int cmCTestScriptHandler::CheckOutSourceDir()
+{
+ std::string command;
+ std::string output;
+ int retVal;
+ bool res;
+
+ if (!cmSystemTools::FileExists(this->SourceDir.c_str()) &&
+ !this->CVSCheckOut.empty()) {
+ // we must now checkout the src dir
+ output = "";
+ 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, 0 /*this->TimeOut*/);
+ if (!res || retVal != 0) {
+ cmSystemTools::Error("Unable to perform cvs checkout:\n",
+ output.c_str());
+ return 6;
+ }
+ }
+ return 0;
+}
+
+int cmCTestScriptHandler::BackupDirectories()
+{
+ int retVal;
+
+ // compute the backup names
+ this->BackupSourceDir = this->SourceDir;
+ this->BackupSourceDir += "_CMakeBackup";
+ this->BackupBinaryDir = this->BinaryDir;
+ this->BackupBinaryDir += "_CMakeBackup";
+
+ // backup the binary and src directories if requested
+ if (this->Backup) {
+ // if for some reason those directories exist then first delete them
+ if (cmSystemTools::FileExists(this->BackupSourceDir.c_str())) {
+ cmSystemTools::RemoveADirectory(this->BackupSourceDir);
+ }
+ if (cmSystemTools::FileExists(this->BackupBinaryDir.c_str())) {
+ cmSystemTools::RemoveADirectory(this->BackupBinaryDir);
+ }
+
+ // first rename the src and binary directories
+ rename(this->SourceDir.c_str(), this->BackupSourceDir.c_str());
+ rename(this->BinaryDir.c_str(), this->BackupBinaryDir.c_str());
+
+ // we must now checkout the src dir
+ retVal = this->CheckOutSourceDir();
+ if (retVal) {
+ this->RestoreBackupDirectories();
+ return retVal;
+ }
+ }
+
+ return 0;
+}
+
+int cmCTestScriptHandler::PerformExtraUpdates()
+{
+ std::string command;
+ std::string output;
+ int retVal;
+ bool res;
+
+ // do an initial cvs update as required
+ command = this->UpdateCmd;
+ std::vector<std::string>::iterator it;
+ for (it = this->ExtraUpdates.begin(); it != this->ExtraUpdates.end(); ++it) {
+ std::vector<std::string> cvsArgs;
+ cmSystemTools::ExpandListArgument(*it, cvsArgs);
+ if (cvsArgs.size() == 2) {
+ std::string fullCommand = command;
+ fullCommand += " update ";
+ fullCommand += cvsArgs[1];
+ output = "";
+ retVal = 0;
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run Update: " << fullCommand << std::endl);
+ res = cmSystemTools::RunSingleCommand(
+ fullCommand.c_str(), &output, &output, &retVal, cvsArgs[0].c_str(),
+ this->HandlerVerbose, 0 /*this->TimeOut*/);
+ if (!res || retVal != 0) {
+ cmSystemTools::Error("Unable to perform extra updates:\n", it->c_str(),
+ "\nWith output:\n", output.c_str());
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+// run a single dashboard entry
+int cmCTestScriptHandler::RunConfigurationDashboard()
+{
+ // local variables
+ std::string command;
+ std::string output;
+ int retVal;
+ bool res;
+
+ // make sure the src directory is there, if it isn't then we might be able
+ // to check it out from cvs
+ retVal = this->CheckOutSourceDir();
+ if (retVal) {
+ return retVal;
+ }
+
+ // backup the dirs if requested
+ retVal = this->BackupDirectories();
+ if (retVal) {
+ return retVal;
+ }
+
+ // clear the binary directory?
+ if (this->EmptyBinDir) {
+ if (!cmCTestScriptHandler::EmptyBinaryDirectory(this->BinaryDir.c_str())) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem removing the binary directory" << std::endl);
+ }
+ }
+
+ // make sure the binary directory exists if it isn't the srcdir
+ if (!cmSystemTools::FileExists(this->BinaryDir.c_str()) &&
+ this->SourceDir != this->BinaryDir) {
+ if (!cmSystemTools::MakeDirectory(this->BinaryDir.c_str())) {
+ cmSystemTools::Error("Unable to create the binary directory:\n",
+ this->BinaryDir.c_str());
+ this->RestoreBackupDirectories();
+ return 7;
+ }
+ }
+
+ // if the binary directory and the source directory are the same,
+ // and we are starting with an empty binary directory, then that means
+ // we must check out the source tree
+ if (this->EmptyBinDir && this->SourceDir == this->BinaryDir) {
+ // make sure we have the required info
+ if (this->CVSCheckOut.empty()) {
+ cmSystemTools::Error(
+ "You have specified the source and binary "
+ "directories to be the same (an in source build). You have also "
+ "specified that the binary directory is to be erased. This means "
+ "that the source will have to be checked out from CVS. But you have "
+ "not specified CTEST_CVS_CHECKOUT");
+ return 8;
+ }
+
+ // we must now checkout the src dir
+ retVal = this->CheckOutSourceDir();
+ if (retVal) {
+ this->RestoreBackupDirectories();
+ return retVal;
+ }
+ }
+
+ // backup the dirs if requested
+ retVal = this->PerformExtraUpdates();
+ if (retVal) {
+ return retVal;
+ }
+
+ // put the initial cache into the bin dir
+ if (!this->InitialCache.empty()) {
+ if (!this->WriteInitialCache(this->BinaryDir.c_str(),
+ this->InitialCache.c_str())) {
+ this->RestoreBackupDirectories();
+ return 9;
+ }
+ }
+
+ // do an initial cmake to setup the DartConfig file
+ int cmakeFailed = 0;
+ std::string cmakeFailedOuput;
+ if (!this->CMakeCmd.empty()) {
+ command = this->CMakeCmd;
+ command += " \"";
+ command += this->SourceDir;
+ output = "";
+ command += "\"";
+ retVal = 0;
+ 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(),
+ this->HandlerVerbose, 0 /*this->TimeOut*/);
+
+ if (!this->CMOutFile.empty()) {
+ std::string cmakeOutputFile = this->CMOutFile;
+ if (!cmSystemTools::FileIsFullPath(cmakeOutputFile.c_str())) {
+ cmakeOutputFile = this->BinaryDir + "/" + cmakeOutputFile;
+ }
+
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Write CMake output to file: " << cmakeOutputFile
+ << std::endl);
+ cmGeneratedFileStream fout(cmakeOutputFile.c_str());
+ if (fout) {
+ fout << output.c_str();
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open CMake output file: "
+ << cmakeOutputFile << " for writing" << std::endl);
+ }
+ }
+ if (!res || retVal != 0) {
+ // even if this fails continue to the next step
+ cmakeFailed = 1;
+ cmakeFailedOuput = output;
+ }
+ }
+
+ // run ctest, it may be more than one command in here
+ std::vector<std::string> ctestCommands;
+ cmSystemTools::ExpandListArgument(this->CTestCmd, ctestCommands);
+ // for each variable/argument do a putenv
+ for (unsigned i = 0; i < ctestCommands.size(); ++i) {
+ command = ctestCommands[i];
+ output = "";
+ retVal = 0;
+ 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(),
+ this->HandlerVerbose, 0 /*this->TimeOut*/);
+
+ // did something critical fail in ctest
+ if (!res || cmakeFailed || retVal & cmCTest::BUILD_ERRORS) {
+ this->RestoreBackupDirectories();
+ if (cmakeFailed) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to run cmake:" << std::endl
+ << cmakeFailedOuput << std::endl);
+ return 10;
+ }
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to run ctest:" << std::endl
+ << "command: " << command << std::endl
+ << "output: " << output << std::endl);
+ if (!res) {
+ return 11;
+ }
+ return retVal * 100;
+ }
+ }
+
+ // if all was succesful, delete the backup dirs to free up disk space
+ if (this->Backup) {
+ cmSystemTools::RemoveADirectory(this->BackupSourceDir);
+ cmSystemTools::RemoveADirectory(this->BackupBinaryDir);
+ }
+
+ return 0;
+}
+
+bool cmCTestScriptHandler::WriteInitialCache(const char* directory,
+ const char* text)
+{
+ std::string cacheFile = directory;
+ cacheFile += "/CMakeCache.txt";
+ cmGeneratedFileStream fout(cacheFile.c_str());
+ if (!fout) {
+ return false;
+ }
+
+ if (text != CM_NULLPTR) {
+ fout.write(text, strlen(text));
+ }
+
+ // Make sure the operating system has finished writing the file
+ // before closing it. This will ensure the file is finished before
+ // the check below.
+ fout.flush();
+ fout.close();
+ return true;
+}
+
+void cmCTestScriptHandler::RestoreBackupDirectories()
+{
+ // if we backed up the dirs and the build failed, then restore
+ // the backed up dirs
+ if (this->Backup) {
+ // if for some reason those directories exist then first delete them
+ if (cmSystemTools::FileExists(this->SourceDir.c_str())) {
+ cmSystemTools::RemoveADirectory(this->SourceDir);
+ }
+ if (cmSystemTools::FileExists(this->BinaryDir.c_str())) {
+ cmSystemTools::RemoveADirectory(this->BinaryDir);
+ }
+ // rename the src and binary directories
+ rename(this->BackupSourceDir.c_str(), this->SourceDir.c_str());
+ rename(this->BackupBinaryDir.c_str(), this->BinaryDir.c_str());
+ }
+}
+
+bool cmCTestScriptHandler::RunScript(cmCTest* ctest, const char* sname,
+ bool InProcess, int* returnValue)
+{
+ cmCTestScriptHandler* sh = new cmCTestScriptHandler();
+ sh->SetCTestInstance(ctest);
+ sh->AddConfigurationScript(sname, InProcess);
+ int res = sh->ProcessHandler();
+ if (returnValue) {
+ *returnValue = res;
+ }
+ delete sh;
+ return true;
+}
+
+bool cmCTestScriptHandler::EmptyBinaryDirectory(const char* sname)
+{
+ // try to avoid deleting root
+ if (!sname || strlen(sname) < 2) {
+ return false;
+ }
+
+ // consider non existing target directory a success
+ if (!cmSystemTools::FileExists(sname)) {
+ return true;
+ }
+
+ // try to avoid deleting directories that we shouldn't
+ std::string check = sname;
+ check += "/CMakeCache.txt";
+
+ if (!cmSystemTools::FileExists(check.c_str())) {
+ return false;
+ }
+
+ for (int i = 0; i < 5; ++i) {
+ if (TryToRemoveBinaryDirectoryOnce(sname)) {
+ return true;
+ }
+ cmSystemTools::Delay(100);
+ }
+
+ return false;
+}
+
+bool cmCTestScriptHandler::TryToRemoveBinaryDirectoryOnce(
+ const std::string& directoryPath)
+{
+ cmsys::Directory directory;
+ directory.Load(directoryPath);
+
+ for (unsigned long i = 0; i < directory.GetNumberOfFiles(); ++i) {
+ std::string path = directory.GetFile(i);
+
+ if (path == "." || path == ".." || path == "CMakeCache.txt") {
+ continue;
+ }
+
+ std::string fullPath = directoryPath + std::string("/") + path;
+
+ bool isDirectory = cmSystemTools::FileIsDirectory(fullPath) &&
+ !cmSystemTools::FileIsSymlink(fullPath);
+
+ if (isDirectory) {
+ if (!cmSystemTools::RemoveADirectory(fullPath)) {
+ return false;
+ }
+ } else {
+ if (!cmSystemTools::RemoveFile(fullPath)) {
+ return false;
+ }
+ }
+ }
+
+ return cmSystemTools::RemoveADirectory(directoryPath);
+}
+
+double cmCTestScriptHandler::GetRemainingTimeAllowed()
+{
+ if (!this->Makefile) {
+ return 1.0e7;
+ }
+
+ const char* timelimitS = this->Makefile->GetDefinition("CTEST_TIME_LIMIT");
+
+ if (!timelimitS) {
+ return 1.0e7;
+ }
+
+ double timelimit = atof(timelimitS);
+
+ return timelimit - cmSystemTools::GetTime() + this->ScriptStartTime;
+}
diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h
new file mode 100644
index 0000000..4403030
--- /dev/null
+++ b/Source/CTest/cmCTestScriptHandler.h
@@ -0,0 +1,172 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCTestScriptHandler_h
+#define cmCTestScriptHandler_h
+
+#include "cmCTestGenericHandler.h"
+
+#include "cmListFileCache.h"
+
+class cmMakefile;
+class cmGlobalGenerator;
+class cmake;
+class cmCTestCommand;
+
+/** \class cmCTestScriptHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ * CTest script is controlled using several variables that script has to
+ * specify and some optional ones. Required ones are:
+ * CTEST_SOURCE_DIRECTORY - Source directory of the project
+ * CTEST_BINARY_DIRECTORY - Binary directory of the project
+ * CTEST_COMMAND - Testing commands
+ *
+ * Optional variables are:
+ * CTEST_BACKUP_AND_RESTORE
+ * CTEST_CMAKE_COMMAND
+ * CTEST_CMAKE_OUTPUT_FILE_NAME
+ * CTEST_CONTINUOUS_DURATION
+ * CTEST_CONTINUOUS_MINIMUM_INTERVAL
+ * CTEST_CVS_CHECKOUT
+ * CTEST_CVS_COMMAND
+ * CTEST_UPDATE_COMMAND
+ * CTEST_DASHBOARD_ROOT
+ * CTEST_ENVIRONMENT
+ * CTEST_INITIAL_CACHE
+ * CTEST_START_WITH_EMPTY_BINARY_DIRECTORY
+ * CTEST_START_WITH_EMPTY_BINARY_DIRECTORY_ONCE
+ *
+ * In addition the following variables can be used. The number can be 1-10.
+ * CTEST_EXTRA_UPDATES_1
+ * CTEST_EXTRA_UPDATES_2
+ * ...
+ * CTEST_EXTRA_UPDATES_10
+ *
+ * CTest script can use the following arguments CTest provides:
+ * CTEST_SCRIPT_ARG
+ * CTEST_SCRIPT_DIRECTORY
+ * CTEST_SCRIPT_NAME
+ *
+ */
+class cmCTestScriptHandler : public cmCTestGenericHandler
+{
+public:
+ cmTypeMacro(cmCTestScriptHandler, cmCTestGenericHandler);
+
+ /**
+ * Add a script to run, and if is should run in the current process
+ */
+ void AddConfigurationScript(const char*, bool pscope);
+
+ /**
+ * Run a dashboard using a specified confiuration script
+ */
+ int ProcessHandler() CM_OVERRIDE;
+
+ /*
+ * Run a script
+ */
+ static bool RunScript(cmCTest* ctest, const char* script, bool InProcess,
+ int* returnValue);
+ int RunCurrentScript();
+
+ /*
+ * Empty Binary Directory
+ */
+ static bool EmptyBinaryDirectory(const char* dir);
+
+ /*
+ * Write an initial CMakeCache.txt from the given contents.
+ */
+ static bool WriteInitialCache(const char* directory, const char* text);
+
+ /*
+ * Some elapsed time handling functions
+ */
+ static void SleepInSeconds(unsigned int secondsToWait);
+ void UpdateElapsedTime();
+
+ /**
+ * Return the time remaianing that the script is allowed to run in
+ * seconds if the user has set the variable CTEST_TIME_LIMIT. If that has
+ * not been set it returns 1e7 seconds
+ */
+ double GetRemainingTimeAllowed();
+
+ cmCTestScriptHandler();
+ ~cmCTestScriptHandler() CM_OVERRIDE;
+
+ void Initialize() CM_OVERRIDE;
+
+ void CreateCMake();
+ cmake* GetCMake() { return this->CMake; }
+private:
+ // reads in a script
+ int ReadInScript(const std::string& total_script_arg);
+ int ExecuteScript(const std::string& total_script_arg);
+
+ // extract vars from the script to set ivars
+ int ExtractVariables();
+
+ // perform a CVS checkout of the source dir
+ int CheckOutSourceDir();
+
+ // perform any extra cvs updates that were requested
+ int PerformExtraUpdates();
+
+ // backup and restore dirs
+ int BackupDirectories();
+ void RestoreBackupDirectories();
+
+ int RunConfigurationScript(const std::string& script, bool pscope);
+ int RunConfigurationDashboard();
+
+ // Add ctest command
+ void AddCTestCommand(cmCTestCommand* command);
+
+ // Try to remove the binary directory once
+ static bool TryToRemoveBinaryDirectoryOnce(const std::string& directoryPath);
+
+ std::vector<std::string> ConfigurationScripts;
+ std::vector<bool> ScriptProcessScope;
+
+ bool Backup;
+ bool EmptyBinDir;
+ bool EmptyBinDirOnce;
+
+ std::string SourceDir;
+ std::string BinaryDir;
+ std::string BackupSourceDir;
+ std::string BackupBinaryDir;
+ std::string CTestRoot;
+ std::string CVSCheckOut;
+ std::string CTestCmd;
+ std::string UpdateCmd;
+ std::string CTestEnv;
+ std::string InitialCache;
+ std::string CMakeCmd;
+ std::string CMOutFile;
+ std::vector<std::string> ExtraUpdates;
+
+ double MinimumInterval;
+ double ContinuousDuration;
+
+ // what time in seconds did this script start running
+ double ScriptStartTime;
+
+ cmMakefile* Makefile;
+ cmGlobalGenerator* GlobalGenerator;
+ cmake* CMake;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestSleepCommand.cxx b/Source/CTest/cmCTestSleepCommand.cxx
new file mode 100644
index 0000000..a6dd6bc
--- /dev/null
+++ b/Source/CTest/cmCTestSleepCommand.cxx
@@ -0,0 +1,49 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestSleepCommand.h"
+
+#include "cmCTestScriptHandler.h"
+#include <stdlib.h> // required for atoi
+
+bool cmCTestSleepCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.empty()) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // sleep for specified seconds
+ unsigned int time1 = atoi(args[0].c_str());
+ if (args.size() == 1) {
+ cmCTestScriptHandler::SleepInSeconds(time1);
+ // update the elapsed time since it could have slept for a while
+ this->CTestScriptHandler->UpdateElapsedTime();
+ return true;
+ }
+
+ // sleep up to a duration
+ if (args.size() == 3) {
+ unsigned int duration = atoi(args[1].c_str());
+ unsigned int time2 = atoi(args[2].c_str());
+ if (time1 + duration > time2) {
+ duration = (time1 + duration - time2);
+ cmCTestScriptHandler::SleepInSeconds(duration);
+ // update the elapsed time since it could have slept for a while
+ this->CTestScriptHandler->UpdateElapsedTime();
+ }
+ return true;
+ }
+
+ this->SetError("called with incorrect number of arguments");
+ return false;
+}
diff --git a/Source/CTest/cmCTestSleepCommand.h b/Source/CTest/cmCTestSleepCommand.h
new file mode 100644
index 0000000..7981fa2
--- /dev/null
+++ b/Source/CTest/cmCTestSleepCommand.h
@@ -0,0 +1,54 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestSleepCommand_h
+#define cmCTestSleepCommand_h
+
+#include "cmCTestCommand.h"
+
+/** \class cmCTestSleep
+ * \brief Run a ctest script
+ *
+ * cmLibrarysCommand defines a list of executable (i.e., test)
+ * programs to create.
+ */
+class cmCTestSleepCommand : public cmCTestCommand
+{
+public:
+ cmCTestSleepCommand() {}
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestSleepCommand* ni = new cmCTestSleepCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return ni;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "ctest_sleep"; }
+
+ cmTypeMacro(cmCTestSleepCommand, cmCTestCommand);
+};
+
+#endif
diff --git a/Source/CTest/cmCTestStartCommand.cxx b/Source/CTest/cmCTestStartCommand.cxx
new file mode 100644
index 0000000..c64d16b
--- /dev/null
+++ b/Source/CTest/cmCTestStartCommand.cxx
@@ -0,0 +1,160 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestStartCommand.h"
+
+#include "cmCTest.h"
+#include "cmCTestVC.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+
+cmCTestStartCommand::cmCTestStartCommand()
+{
+ this->CreateNewTag = true;
+ this->Quiet = false;
+}
+
+bool cmCTestStartCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.empty()) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ size_t cnt = 0;
+ const char* smodel = args[cnt].c_str();
+ const char* src_dir = CM_NULLPTR;
+ const char* bld_dir = CM_NULLPTR;
+
+ cnt++;
+
+ this->CTest->SetSpecificTrack(CM_NULLPTR);
+ if (cnt < args.size() - 1) {
+ if (args[cnt] == "TRACK") {
+ cnt++;
+ this->CTest->SetSpecificTrack(args[cnt].c_str());
+ cnt++;
+ }
+ }
+
+ if (cnt < args.size()) {
+ if (args[cnt] == "APPEND") {
+ cnt++;
+ this->CreateNewTag = false;
+ }
+ }
+ if (cnt < args.size()) {
+ if (args[cnt] == "QUIET") {
+ cnt++;
+ this->Quiet = true;
+ }
+ }
+
+ if (cnt < args.size()) {
+ src_dir = args[cnt].c_str();
+ cnt++;
+ if (cnt < args.size()) {
+ bld_dir = args[cnt].c_str();
+ }
+ }
+ if (!src_dir) {
+ src_dir = this->Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY");
+ }
+ if (!bld_dir) {
+ bld_dir = this->Makefile->GetDefinition("CTEST_BINARY_DIRECTORY");
+ }
+ if (!src_dir) {
+ this->SetError("source directory not specified. Specify source directory "
+ "as an argument or set CTEST_SOURCE_DIRECTORY");
+ return false;
+ }
+ if (!bld_dir) {
+ this->SetError("binary directory not specified. Specify binary directory "
+ "as an argument or set CTEST_BINARY_DIRECTORY");
+ return false;
+ }
+
+ cmSystemTools::AddKeepPath(src_dir);
+ cmSystemTools::AddKeepPath(bld_dir);
+
+ this->CTest->EmptyCTestConfiguration();
+
+ std::string sourceDir = cmSystemTools::CollapseFullPath(src_dir);
+ std::string binaryDir = cmSystemTools::CollapseFullPath(bld_dir);
+ this->CTest->SetCTestConfiguration("SourceDirectory", sourceDir.c_str(),
+ this->Quiet);
+ this->CTest->SetCTestConfiguration("BuildDirectory", binaryDir.c_str(),
+ this->Quiet);
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "Run dashboard with model "
+ << smodel << std::endl
+ << " Source directory: " << src_dir << std::endl
+ << " Build directory: " << bld_dir << std::endl,
+ this->Quiet);
+ const char* track = this->CTest->GetSpecificTrack();
+ if (track) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Track: " << track << std::endl, this->Quiet);
+ }
+
+ // Log startup actions.
+ std::string startLogFile = binaryDir + "/Testing/Temporary/LastStart.log";
+ cmGeneratedFileStream ofs(startLogFile.c_str());
+ if (!ofs) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create log file: LastStart.log" << std::endl);
+ return false;
+ }
+
+ // Make sure the source directory exists.
+ if (!this->InitialCheckout(ofs, sourceDir)) {
+ return false;
+ }
+ if (!cmSystemTools::FileIsDirectory(sourceDir)) {
+ std::ostringstream e;
+ e << "given source path\n"
+ << " " << sourceDir << "\n"
+ << "which is not an existing directory. "
+ << "Set CTEST_CHECKOUT_COMMAND to a command line to create it.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", "OFF");
+ this->CTest->SetSuppressUpdatingCTestConfiguration(true);
+ int model = this->CTest->GetTestModelFromString(smodel);
+ this->CTest->SetTestModel(model);
+ this->CTest->SetProduceXML(true);
+
+ return this->CTest->InitializeFromCommand(this);
+}
+
+bool cmCTestStartCommand::InitialCheckout(std::ostream& ofs,
+ std::string const& sourceDir)
+{
+ // Use the user-provided command to create the source tree.
+ const char* initialCheckoutCommand =
+ this->Makefile->GetDefinition("CTEST_CHECKOUT_COMMAND");
+ if (!initialCheckoutCommand) {
+ initialCheckoutCommand =
+ this->Makefile->GetDefinition("CTEST_CVS_CHECKOUT");
+ }
+ if (initialCheckoutCommand) {
+ // Use a generic VC object to run and log the command.
+ cmCTestVC vc(this->CTest, ofs);
+ vc.SetSourceDirectory(sourceDir);
+ if (!vc.InitialCheckout(initialCheckoutCommand)) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/Source/CTest/cmCTestStartCommand.h b/Source/CTest/cmCTestStartCommand.h
new file mode 100644
index 0000000..e3f8f8b
--- /dev/null
+++ b/Source/CTest/cmCTestStartCommand.h
@@ -0,0 +1,70 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestStartCommand_h
+#define cmCTestStartCommand_h
+
+#include "cmCTestCommand.h"
+
+/** \class cmCTestStart
+ * \brief Run a ctest script
+ *
+ * cmCTestStartCommand defineds the command to start the nightly testing.
+ */
+class cmCTestStartCommand : public cmCTestCommand
+{
+public:
+ cmCTestStartCommand();
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestStartCommand* ni = new cmCTestStartCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ ni->CreateNewTag = this->CreateNewTag;
+ ni->Quiet = this->Quiet;
+ return ni;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * Will this invocation of ctest_start create a new TAG file?
+ */
+ bool ShouldCreateNewTag() { return this->CreateNewTag; }
+
+ /**
+ * Should this invocation of ctest_start output non-error messages?
+ */
+ bool ShouldBeQuiet() { return this->Quiet; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "ctest_start"; }
+
+ cmTypeMacro(cmCTestStartCommand, cmCTestCommand);
+
+private:
+ bool InitialCheckout(std::ostream& ofs, std::string const& sourceDir);
+ bool CreateNewTag;
+ bool Quiet;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
new file mode 100644
index 0000000..54da383
--- /dev/null
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -0,0 +1,258 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestSubmitCommand.h"
+
+#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
+#include "cmCTestSubmitHandler.h"
+
+cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
+{
+ const char* ctestDropMethod =
+ this->Makefile->GetDefinition("CTEST_DROP_METHOD");
+ const char* ctestDropSite = this->Makefile->GetDefinition("CTEST_DROP_SITE");
+ const char* ctestDropLocation =
+ this->Makefile->GetDefinition("CTEST_DROP_LOCATION");
+ const char* ctestTriggerSite =
+ this->Makefile->GetDefinition("CTEST_TRIGGER_SITE");
+ bool ctestDropSiteCDash = this->Makefile->IsOn("CTEST_DROP_SITE_CDASH");
+ const char* ctestProjectName =
+ this->Makefile->GetDefinition("CTEST_PROJECT_NAME");
+ if (!ctestDropMethod) {
+ ctestDropMethod = "http";
+ }
+
+ if (!ctestDropSite) {
+ // error: CDash requires CTEST_DROP_SITE definition
+ // in CTestConfig.cmake
+ }
+ if (!ctestDropLocation) {
+ // error: CDash requires CTEST_DROP_LOCATION definition
+ // in CTestConfig.cmake
+ }
+ this->CTest->SetCTestConfiguration("ProjectName", ctestProjectName,
+ this->Quiet);
+ this->CTest->SetCTestConfiguration("DropMethod", ctestDropMethod,
+ this->Quiet);
+ this->CTest->SetCTestConfiguration("DropSite", ctestDropSite, this->Quiet);
+ this->CTest->SetCTestConfiguration("DropLocation", ctestDropLocation,
+ this->Quiet);
+
+ this->CTest->SetCTestConfiguration(
+ "IsCDash", ctestDropSiteCDash ? "TRUE" : "FALSE", this->Quiet);
+
+ // Only propagate TriggerSite for non-CDash projects:
+ //
+ if (!ctestDropSiteCDash) {
+ this->CTest->SetCTestConfiguration("TriggerSite", ctestTriggerSite,
+ this->Quiet);
+ }
+
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CurlOptions", "CTEST_CURL_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "DropSiteUser", "CTEST_DROP_SITE_USER", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "DropSitePassword", "CTEST_DROP_SITE_PASSWORD",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "ScpCommand", "CTEST_SCP_COMMAND", this->Quiet);
+
+ const char* notesFilesVariable =
+ 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);
+ }
+
+ 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)) {
+ this->SetError("problem submitting extra files.");
+ return CM_NULLPTR;
+ }
+ }
+
+ cmCTestGenericHandler* handler =
+ this->CTest->GetInitializedHandler("submit");
+ if (!handler) {
+ this->SetError("internal CTest error. Cannot instantiate submit handler");
+ return CM_NULLPTR;
+ }
+
+ // If no FILES or PARTS given, *all* PARTS are submitted by default.
+ //
+ // If FILES are given, but not PARTS, only the FILES are submitted
+ // and *no* PARTS are submitted.
+ // (This is why we select the empty "noParts" set in the
+ // FilesMentioned block below...)
+ //
+ // If PARTS are given, only the selected PARTS are submitted.
+ //
+ // If both PARTS and FILES are given, only the selected PARTS *and*
+ // all the given FILES are submitted.
+
+ // If given explicit FILES to submit, pass them to the handler.
+ //
+ if (this->FilesMentioned) {
+ // Intentionally select *no* PARTS. (Pass an empty set.) If PARTS
+ // were also explicitly mentioned, they will be selected below...
+ // But FILES with no PARTS mentioned should just submit the FILES
+ // without any of the default parts.
+ //
+ std::set<cmCTest::Part> noParts;
+ static_cast<cmCTestSubmitHandler*>(handler)->SelectParts(noParts);
+
+ static_cast<cmCTestSubmitHandler*>(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);
+ }
+
+ 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->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());
+ }
+ return handler;
+}
+
+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 cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg)
+{
+ if (this->CDashUpload) {
+ if (arg == "CDASH_UPLOAD") {
+ this->ArgumentDoing = ArgumentDoingCDashUpload;
+ return true;
+ }
+
+ if (arg == "CDASH_UPLOAD_TYPE") {
+ this->ArgumentDoing = ArgumentDoingCDashUploadType;
+ return true;
+ }
+ } else {
+ // Look for arguments specific to this command.
+ if (arg == "PARTS") {
+ this->ArgumentDoing = ArgumentDoingParts;
+ this->PartsMentioned = true;
+ return true;
+ }
+
+ if (arg == "FILES") {
+ this->ArgumentDoing = ArgumentDoingFiles;
+ this->FilesMentioned = true;
+ return true;
+ }
+
+ if (arg == "RETRY_COUNT") {
+ this->ArgumentDoing = ArgumentDoingRetryCount;
+ return true;
+ }
+
+ if (arg == "RETRY_DELAY") {
+ this->ArgumentDoing = ArgumentDoingRetryDelay;
+ return true;
+ }
+
+ if (arg == "INTERNAL_TEST_CHECKSUM") {
+ this->InternalTest = true;
+ return true;
+ }
+ }
+
+ // Look for other arguments.
+ return this->Superclass::CheckArgumentKeyword(arg);
+}
+
+bool cmCTestSubmitCommand::CheckArgumentValue(std::string const& arg)
+{
+ // Handle states specific to this command.
+ if (this->ArgumentDoing == ArgumentDoingParts) {
+ cmCTest::Part p = this->CTest->GetPartFromName(arg.c_str());
+ if (p != cmCTest::PartCount) {
+ this->Parts.insert(p);
+ } else {
+ std::ostringstream e;
+ e << "Part name \"" << arg << "\" is invalid.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ this->ArgumentDoing = ArgumentDoingError;
+ }
+ return true;
+ }
+
+ if (this->ArgumentDoing == ArgumentDoingFiles) {
+ if (cmSystemTools::FileExists(arg.c_str())) {
+ this->Files.insert(arg);
+ } else {
+ std::ostringstream e;
+ e << "File \"" << arg << "\" does not exist. Cannot submit "
+ << "a non-existent file.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ this->ArgumentDoing = ArgumentDoingError;
+ }
+ return true;
+ }
+
+ if (this->ArgumentDoing == ArgumentDoingRetryCount) {
+ this->RetryCount = arg;
+ return true;
+ }
+
+ if (this->ArgumentDoing == ArgumentDoingRetryDelay) {
+ this->RetryDelay = arg;
+ return true;
+ }
+
+ if (this->ArgumentDoing == ArgumentDoingCDashUpload) {
+ this->ArgumentDoing = ArgumentDoingNone;
+ this->CDashUploadFile = arg;
+ return true;
+ }
+
+ if (this->ArgumentDoing == ArgumentDoingCDashUploadType) {
+ this->ArgumentDoing = ArgumentDoingNone;
+ this->CDashUploadType = arg;
+ return true;
+ }
+
+ // Look for other arguments.
+ return this->Superclass::CheckArgumentValue(arg);
+}
diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h
new file mode 100644
index 0000000..7c3d6cd
--- /dev/null
+++ b/Source/CTest/cmCTestSubmitCommand.h
@@ -0,0 +1,88 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestSubmitCommand_h
+#define cmCTestSubmitCommand_h
+
+#include "cmCTestHandlerCommand.h"
+
+#include "cmCTest.h"
+
+/** \class cmCTestSubmit
+ * \brief Run a ctest script
+ *
+ * cmCTestSubmitCommand defineds the command to submit the test results for
+ * the project.
+ */
+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() CM_OVERRIDE
+ {
+ cmCTestSubmitCommand* ni = new cmCTestSubmitCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return ni;
+ }
+
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "ctest_submit"; }
+
+ cmTypeMacro(cmCTestSubmitCommand, cmCTestHandlerCommand);
+
+protected:
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
+
+ bool CheckArgumentKeyword(std::string const& arg) CM_OVERRIDE;
+ bool CheckArgumentValue(std::string const& arg) CM_OVERRIDE;
+
+ enum
+ {
+ ArgumentDoingParts = Superclass::ArgumentDoingLast1,
+ ArgumentDoingFiles,
+ ArgumentDoingRetryDelay,
+ ArgumentDoingRetryCount,
+ ArgumentDoingCDashUpload,
+ ArgumentDoingCDashUploadType,
+ ArgumentDoingLast2
+ };
+
+ bool PartsMentioned;
+ std::set<cmCTest::Part> Parts;
+ bool FilesMentioned;
+ bool InternalTest;
+ cmCTest::SetOfStrings Files;
+ std::string RetryCount;
+ std::string RetryDelay;
+ bool CDashUpload;
+ std::string CDashUploadFile;
+ std::string CDashUploadType;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
new file mode 100644
index 0000000..67388ad
--- /dev/null
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -0,0 +1,1529 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestSubmitHandler.h"
+
+#include "cmCTest.h"
+#include "cmCTestScriptHandler.h"
+#include "cmGeneratedFileStream.h"
+#include "cmState.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+#include "cmXMLParser.h"
+#include "cmake.h"
+
+#include <cmsys/Base64.h>
+#include <cmsys/Process.h>
+
+// For XML-RPC submission
+#include "cm_xmlrpc.h"
+
+#include <cm_jsoncpp_reader.h>
+// For curl submission
+#include "cmCTestCurl.h"
+#include "cmCurl.h"
+
+#include <sys/stat.h>
+
+#define SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT 120
+
+typedef std::vector<char> cmCTestSubmitHandlerVectorOfChar;
+
+class cmCTestSubmitHandler::ResponseParser : public cmXMLParser
+{
+public:
+ ResponseParser() { this->Status = STATUS_OK; }
+ ~ResponseParser() CM_OVERRIDE {}
+
+public:
+ enum StatusType
+ {
+ STATUS_OK,
+ STATUS_WARNING,
+ STATUS_ERROR
+ };
+
+ StatusType Status;
+ std::string CDashVersion;
+ std::string Filename;
+ std::string MD5;
+ std::string Message;
+
+private:
+ std::vector<char> CurrentValue;
+
+ std::string GetCurrentValue()
+ {
+ std::string val;
+ if (!this->CurrentValue.empty()) {
+ val.assign(&this->CurrentValue[0], this->CurrentValue.size());
+ }
+ return val;
+ }
+
+ void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
+ {
+ this->CurrentValue.clear();
+ if (name == "cdash") {
+ this->CDashVersion = this->FindAttribute(atts, "version");
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) CM_OVERRIDE
+ {
+ this->CurrentValue.insert(this->CurrentValue.end(), data, data + length);
+ }
+
+ void EndElement(const std::string& name) CM_OVERRIDE
+ {
+ if (name == "status") {
+ std::string status = cmSystemTools::UpperCase(this->GetCurrentValue());
+ if (status == "OK" || status == "SUCCESS") {
+ this->Status = STATUS_OK;
+ } else if (status == "WARNING") {
+ this->Status = STATUS_WARNING;
+ } else {
+ this->Status = STATUS_ERROR;
+ }
+ } else if (name == "filename") {
+ this->Filename = this->GetCurrentValue();
+ } else if (name == "md5") {
+ this->MD5 = this->GetCurrentValue();
+ } else if (name == "message") {
+ this->Message = this->GetCurrentValue();
+ }
+ }
+};
+
+static size_t cmCTestSubmitHandlerWriteMemoryCallback(void* ptr, size_t size,
+ size_t nmemb, void* data)
+{
+ int realsize = (int)(size * nmemb);
+
+ cmCTestSubmitHandlerVectorOfChar* vec =
+ static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
+ const char* chPtr = static_cast<char*>(ptr);
+ vec->insert(vec->end(), chPtr, chPtr + realsize);
+
+ return realsize;
+}
+
+static size_t cmCTestSubmitHandlerCurlDebugCallback(CURL*, curl_infotype,
+ char* chPtr, size_t size,
+ void* data)
+{
+ cmCTestSubmitHandlerVectorOfChar* vec =
+ static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
+ vec->insert(vec->end(), chPtr, chPtr + size);
+
+ return size;
+}
+
+cmCTestSubmitHandler::cmCTestSubmitHandler()
+ : HTTPProxy()
+ , FTPProxy()
+{
+ this->Initialize();
+}
+
+void cmCTestSubmitHandler::Initialize()
+{
+ // We submit all available parts by default.
+ for (cmCTest::Part p = cmCTest::PartStart; p != cmCTest::PartCount;
+ p = cmCTest::Part(p + 1)) {
+ this->SubmitPart[p] = true;
+ }
+ this->CDash = false;
+ this->HasWarnings = false;
+ this->HasErrors = false;
+ this->Superclass::Initialize();
+ this->HTTPProxy = "";
+ this->HTTPProxyType = 0;
+ this->HTTPProxyAuth = "";
+ this->FTPProxy = "";
+ this->FTPProxyType = 0;
+ this->LogFile = CM_NULLPTR;
+ this->Files.clear();
+}
+
+bool cmCTestSubmitHandler::SubmitUsingFTP(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url)
+{
+ CURL* curl;
+ CURLcode res;
+ FILE* ftpfile;
+ char error_buffer[1024];
+
+ /* In windows, this will init the winsock stuff */
+ ::curl_global_init(CURL_GLOBAL_ALL);
+
+ cmCTest::SetOfStrings::const_iterator file;
+ for (file = files.begin(); file != files.end(); ++file) {
+ /* get a curl handle */
+ curl = curl_easy_init();
+ if (curl) {
+ // Using proxy
+ if (this->FTPProxyType > 0) {
+ curl_easy_setopt(curl, CURLOPT_PROXY, this->FTPProxy.c_str());
+ switch (this->FTPProxyType) {
+ case 2:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
+ break;
+ case 3:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
+ break;
+ default:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ }
+ }
+
+ // enable uploading
+ ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
+
+ // if there is little to no activity for too long stop submitting
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME,
+ SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
+
+ ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
+
+ std::string local_file = *file;
+ if (!cmSystemTools::FileExists(local_file.c_str())) {
+ local_file = localprefix + "/" + *file;
+ }
+ std::string upload_as =
+ url + "/" + remoteprefix + cmSystemTools::GetFilenameName(*file);
+
+ if (!cmSystemTools::FileExists(local_file.c_str())) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Cannot find file: " << local_file << std::endl);
+ ::curl_easy_cleanup(curl);
+ ::curl_global_cleanup();
+ return false;
+ }
+ unsigned long filelen = cmSystemTools::FileLength(local_file);
+
+ ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
+ *this->LogFile << "\tUpload file: " << local_file << " to " << upload_as
+ << std::endl;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Upload file: " << local_file << " to "
+ << upload_as << std::endl,
+ this->Quiet);
+
+ ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+
+ // specify target
+ ::curl_easy_setopt(curl, CURLOPT_URL, upload_as.c_str());
+
+ // now specify which file to upload
+ ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
+
+ // and give the size of the upload (optional)
+ ::curl_easy_setopt(curl, CURLOPT_INFILESIZE, static_cast<long>(filelen));
+
+ // and give curl the buffer for errors
+ ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
+
+ // specify handler for output
+ ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
+ cmCTestSubmitHandlerWriteMemoryCallback);
+ ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
+ cmCTestSubmitHandlerCurlDebugCallback);
+
+ /* we pass our 'chunk' struct to the callback function */
+ cmCTestSubmitHandlerVectorOfChar chunk;
+ cmCTestSubmitHandlerVectorOfChar chunkDebug;
+ ::curl_easy_setopt(curl, CURLOPT_FILE, (void*)&chunk);
+ ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void*)&chunkDebug);
+
+ // Now run off and do what you've been told!
+ res = ::curl_easy_perform(curl);
+
+ if (!chunk.empty()) {
+ cmCTestOptionalLog(this->CTest, DEBUG, "CURL output: ["
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+ << "]" << std::endl,
+ this->Quiet);
+ }
+ if (!chunkDebug.empty()) {
+ cmCTestOptionalLog(
+ this->CTest, DEBUG, "CURL debug output: ["
+ << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
+ << std::endl,
+ this->Quiet);
+ }
+
+ fclose(ftpfile);
+ if (res) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " Error when uploading file: "
+ << local_file << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Error message was: " << error_buffer << std::endl);
+ *this->LogFile << " Error when uploading file: " << local_file
+ << std::endl
+ << " Error message was: " << error_buffer << std::endl
+ << " Curl output was: ";
+ // avoid dereference of empty vector
+ if (!chunk.empty()) {
+ *this->LogFile << cmCTestLogWrite(&*chunk.begin(), chunk.size());
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
+ << std::endl);
+ }
+ *this->LogFile << std::endl;
+ ::curl_easy_cleanup(curl);
+ ::curl_global_cleanup();
+ return false;
+ }
+ // always cleanup
+ ::curl_easy_cleanup(curl);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Uploaded: " + local_file << std::endl,
+ this->Quiet);
+ }
+ }
+ ::curl_global_cleanup();
+ return true;
+}
+
+// Uploading files is simpler
+bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url)
+{
+ CURL* curl;
+ CURLcode res;
+ FILE* ftpfile;
+ char error_buffer[1024];
+ struct curl_slist* headers =
+ ::curl_slist_append(CM_NULLPTR, "Content-Type: text/xml");
+
+ /* In windows, this will init the winsock stuff */
+ ::curl_global_init(CURL_GLOBAL_ALL);
+ std::string dropMethod(this->CTest->GetCTestConfiguration("DropMethod"));
+ std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
+ std::vector<std::string> args;
+ cmSystemTools::ExpandListArgument(curlopt, args);
+ bool verifyPeerOff = false;
+ bool verifyHostOff = false;
+ for (std::vector<std::string>::iterator i = args.begin(); i != args.end();
+ ++i) {
+ if (*i == "CURLOPT_SSL_VERIFYPEER_OFF") {
+ verifyPeerOff = true;
+ }
+ if (*i == "CURLOPT_SSL_VERIFYHOST_OFF") {
+ verifyHostOff = true;
+ }
+ }
+ std::string::size_type kk;
+ cmCTest::SetOfStrings::const_iterator file;
+ for (file = files.begin(); file != files.end(); ++file) {
+ /* get a curl handle */
+ curl = curl_easy_init();
+ if (curl) {
+ cmCurlSetCAInfo(curl);
+ if (verifyPeerOff) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Set CURLOPT_SSL_VERIFYPEER to off\n",
+ this->Quiet);
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
+ }
+ if (verifyHostOff) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Set CURLOPT_SSL_VERIFYHOST to off\n",
+ this->Quiet);
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
+ }
+
+ // Using proxy
+ if (this->HTTPProxyType > 0) {
+ curl_easy_setopt(curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
+ switch (this->HTTPProxyType) {
+ case 2:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
+ break;
+ case 3:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
+ break;
+ default:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ if (!this->HTTPProxyAuth.empty()) {
+ curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
+ this->HTTPProxyAuth.c_str());
+ }
+ }
+ }
+ if (this->CTest->ShouldUseHTTP10()) {
+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ }
+ // enable HTTP ERROR parsing
+ curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
+ /* enable uploading */
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
+
+ // if there is little to no activity for too long stop submitting
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME,
+ SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
+
+ /* HTTP PUT please */
+ ::curl_easy_setopt(curl, CURLOPT_PUT, 1);
+ ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+
+ // Be sure to set Content-Type to satisfy fussy modsecurity rules
+ ::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+
+ std::string local_file = *file;
+ if (!cmSystemTools::FileExists(local_file.c_str())) {
+ local_file = localprefix + "/" + *file;
+ }
+ std::string remote_file =
+ remoteprefix + cmSystemTools::GetFilenameName(*file);
+
+ *this->LogFile << "\tUpload file: " << local_file << " to "
+ << remote_file << std::endl;
+
+ std::string ofile = "";
+ for (kk = 0; kk < remote_file.size(); kk++) {
+ char c = remote_file[kk];
+ char hexCh[4] = { 0, 0, 0, 0 };
+ hexCh[0] = c;
+ switch (c) {
+ case '+':
+ case '?':
+ case '/':
+ case '\\':
+ case '&':
+ case ' ':
+ case '=':
+ case '%':
+ sprintf(hexCh, "%%%02X", (int)c);
+ ofile.append(hexCh);
+ break;
+ default:
+ ofile.append(hexCh);
+ }
+ }
+ std::string upload_as = url +
+ ((url.find('?') == std::string::npos) ? '?' : '&') + "FileName=" +
+ ofile;
+
+ upload_as += "&MD5=";
+
+ if (cmSystemTools::IsOn(this->GetOption("InternalTest"))) {
+ upload_as += "bad_md5sum";
+ } else {
+ char md5[33];
+ cmSystemTools::ComputeFileMD5(local_file, md5);
+ md5[32] = 0;
+ upload_as += md5;
+ }
+
+ if (!cmSystemTools::FileExists(local_file.c_str())) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Cannot find file: " << local_file << std::endl);
+ ::curl_easy_cleanup(curl);
+ ::curl_slist_free_all(headers);
+ ::curl_global_cleanup();
+ return false;
+ }
+ unsigned long filelen = cmSystemTools::FileLength(local_file);
+
+ ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Upload file: " << local_file << " to "
+ << upload_as << " Size: "
+ << filelen << std::endl,
+ this->Quiet);
+
+ // specify target
+ ::curl_easy_setopt(curl, CURLOPT_URL, upload_as.c_str());
+
+ // now specify which file to upload
+ ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
+
+ // and give the size of the upload (optional)
+ ::curl_easy_setopt(curl, CURLOPT_INFILESIZE, static_cast<long>(filelen));
+
+ // and give curl the buffer for errors
+ ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
+
+ // specify handler for output
+ ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
+ cmCTestSubmitHandlerWriteMemoryCallback);
+ ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
+ cmCTestSubmitHandlerCurlDebugCallback);
+
+ /* we pass our 'chunk' struct to the callback function */
+ cmCTestSubmitHandlerVectorOfChar chunk;
+ cmCTestSubmitHandlerVectorOfChar chunkDebug;
+ ::curl_easy_setopt(curl, CURLOPT_FILE, (void*)&chunk);
+ ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void*)&chunkDebug);
+
+ // Now run off and do what you've been told!
+ res = ::curl_easy_perform(curl);
+
+ if (cmSystemTools::IsOn(this->GetOption("InternalTest")) &&
+ cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
+ this->CTest->GetCDashVersion().c_str(),
+ "1.7")) {
+ // mock failure output for internal test case
+ std::string mock_output =
+ "<cdash version=\"1.7.0\">\n"
+ " <status>ERROR</status>\n"
+ " <message>Checksum failed for file.</message>\n"
+ "</cdash>\n";
+ chunk.clear();
+ chunk.assign(mock_output.begin(), mock_output.end());
+ }
+
+ if (!chunk.empty()) {
+ cmCTestOptionalLog(this->CTest, DEBUG, "CURL output: ["
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+ << "]" << std::endl,
+ this->Quiet);
+ this->ParseResponse(chunk);
+ }
+ if (!chunkDebug.empty()) {
+ cmCTestOptionalLog(
+ this->CTest, DEBUG, "CURL debug output: ["
+ << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
+ << std::endl,
+ this->Quiet);
+ }
+
+ // If curl failed for any reason, or checksum fails, wait and retry
+ //
+ if (res != CURLE_OK || this->HasErrors) {
+ std::string retryDelay = this->GetOption("RetryDelay") == CM_NULLPTR
+ ? ""
+ : this->GetOption("RetryDelay");
+ std::string retryCount = this->GetOption("RetryCount") == CM_NULLPTR
+ ? ""
+ : this->GetOption("RetryCount");
+
+ int delay = retryDelay == ""
+ ? atoi(this->CTest->GetCTestConfiguration("CTestSubmitRetryDelay")
+ .c_str())
+ : atoi(retryDelay.c_str());
+ int count = retryCount == ""
+ ? atoi(this->CTest->GetCTestConfiguration("CTestSubmitRetryCount")
+ .c_str())
+ : atoi(retryCount.c_str());
+
+ for (int i = 0; i < count; i++) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submit failed, waiting " << delay
+ << " seconds...\n",
+ this->Quiet);
+
+ double stop = cmSystemTools::GetTime() + delay;
+ while (cmSystemTools::GetTime() < stop) {
+ cmSystemTools::Delay(100);
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Retry submission: Attempt "
+ << (i + 1) << " of " << count << std::endl,
+ this->Quiet);
+
+ ::fclose(ftpfile);
+ ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
+ ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
+
+ chunk.clear();
+ chunkDebug.clear();
+ this->HasErrors = false;
+
+ res = ::curl_easy_perform(curl);
+
+ if (!chunk.empty()) {
+ cmCTestOptionalLog(
+ this->CTest, DEBUG, "CURL output: ["
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
+ << std::endl,
+ this->Quiet);
+ this->ParseResponse(chunk);
+ }
+
+ if (res == CURLE_OK && !this->HasErrors) {
+ break;
+ }
+ }
+ }
+
+ fclose(ftpfile);
+ if (res) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " Error when uploading file: "
+ << local_file << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Error message was: " << error_buffer << std::endl);
+ *this->LogFile << " Error when uploading file: " << local_file
+ << std::endl
+ << " Error message was: " << error_buffer
+ << std::endl;
+ // avoid deref of begin for zero size array
+ if (!chunk.empty()) {
+ *this->LogFile << " Curl output was: "
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+ << std::endl;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
+ << std::endl);
+ }
+ ::curl_easy_cleanup(curl);
+ ::curl_slist_free_all(headers);
+ ::curl_global_cleanup();
+ return false;
+ }
+ // always cleanup
+ ::curl_easy_cleanup(curl);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Uploaded: " + local_file << std::endl,
+ this->Quiet);
+ }
+ }
+ ::curl_slist_free_all(headers);
+ ::curl_global_cleanup();
+ return true;
+}
+
+void cmCTestSubmitHandler::ParseResponse(
+ cmCTestSubmitHandlerVectorOfChar chunk)
+{
+ std::string output = "";
+ output.append(chunk.begin(), chunk.end());
+
+ if (output.find("<cdash") != output.npos) {
+ ResponseParser parser;
+ parser.Parse(output.c_str());
+
+ if (parser.Status != ResponseParser::STATUS_OK) {
+ this->HasErrors = true;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Submission failed: " << parser.Message << std::endl);
+ return;
+ }
+ }
+ output = cmSystemTools::UpperCase(output);
+ if (output.find("WARNING") != std::string::npos) {
+ this->HasWarnings = true;
+ }
+ if (output.find("ERROR") != std::string::npos) {
+ this->HasErrors = true;
+ }
+
+ if (this->HasWarnings || this->HasErrors) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Server Response:\n"
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "\n");
+ }
+}
+
+bool cmCTestSubmitHandler::TriggerUsingHTTP(const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url)
+{
+ CURL* curl;
+ char error_buffer[1024];
+
+ /* In windows, this will init the winsock stuff */
+ ::curl_global_init(CURL_GLOBAL_ALL);
+
+ cmCTest::SetOfStrings::const_iterator file;
+ for (file = files.begin(); file != files.end(); ++file) {
+ /* get a curl handle */
+ curl = curl_easy_init();
+ if (curl) {
+ // Using proxy
+ if (this->HTTPProxyType > 0) {
+ curl_easy_setopt(curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
+ switch (this->HTTPProxyType) {
+ case 2:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
+ break;
+ case 3:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
+ break;
+ default:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ if (!this->HTTPProxyAuth.empty()) {
+ curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
+ this->HTTPProxyAuth.c_str());
+ }
+ }
+ }
+
+ ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+
+ // and give curl the buffer for errors
+ ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
+
+ // specify handler for output
+ ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
+ cmCTestSubmitHandlerWriteMemoryCallback);
+ ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
+ cmCTestSubmitHandlerCurlDebugCallback);
+
+ /* we pass our 'chunk' struct to the callback function */
+ cmCTestSubmitHandlerVectorOfChar chunk;
+ cmCTestSubmitHandlerVectorOfChar chunkDebug;
+ ::curl_easy_setopt(curl, CURLOPT_FILE, (void*)&chunk);
+ ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void*)&chunkDebug);
+
+ std::string rfile = remoteprefix + cmSystemTools::GetFilenameName(*file);
+ std::string ofile = "";
+ std::string::iterator kk;
+ for (kk = rfile.begin(); kk < rfile.end(); ++kk) {
+ char c = *kk;
+ char hexCh[4] = { 0, 0, 0, 0 };
+ hexCh[0] = c;
+ switch (c) {
+ case '+':
+ case '?':
+ case '/':
+ case '\\':
+ case '&':
+ case ' ':
+ case '=':
+ case '%':
+ sprintf(hexCh, "%%%02X", (int)c);
+ ofile.append(hexCh);
+ break;
+ default:
+ ofile.append(hexCh);
+ }
+ }
+ std::string turl = url +
+ ((url.find('?') == std::string::npos) ? '?' : '&') + "xmlfile=" +
+ ofile;
+ *this->LogFile << "Trigger url: " << turl << std::endl;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Trigger url: " << turl << std::endl, this->Quiet);
+ curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
+ curl_easy_setopt(curl, CURLOPT_URL, turl.c_str());
+ if (curl_easy_perform(curl)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Error when triggering: " << turl << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Error message was: " << error_buffer << std::endl);
+ *this->LogFile << "\tTriggering failed with error: " << error_buffer
+ << std::endl
+ << " Error message was: " << error_buffer
+ << std::endl;
+ if (!chunk.empty()) {
+ *this->LogFile << " Curl output was: "
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+ << std::endl;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
+ << std::endl);
+ }
+ ::curl_easy_cleanup(curl);
+ ::curl_global_cleanup();
+ return false;
+ }
+
+ if (!chunk.empty()) {
+ cmCTestOptionalLog(this->CTest, DEBUG, "CURL output: ["
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+ << "]" << std::endl,
+ this->Quiet);
+ }
+ if (!chunkDebug.empty()) {
+ cmCTestOptionalLog(
+ this->CTest, DEBUG, "CURL debug output: ["
+ << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
+ << std::endl,
+ this->Quiet);
+ }
+
+ // always cleanup
+ ::curl_easy_cleanup(curl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl,
+ this->Quiet);
+ }
+ }
+ ::curl_global_cleanup();
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Dart server triggered..." << std::endl, this->Quiet);
+ return true;
+}
+
+bool cmCTestSubmitHandler::SubmitUsingSCP(const std::string& scp_command,
+ const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url)
+{
+ if (scp_command.empty() || localprefix.empty() || files.empty() ||
+ remoteprefix.empty() || url.empty()) {
+ return 0;
+ }
+
+ std::vector<const char*> argv;
+ argv.push_back(scp_command.c_str()); // Scp command
+ argv.push_back(scp_command.c_str()); // Dummy string for file
+ argv.push_back(scp_command.c_str()); // Dummy string for remote url
+ argv.push_back(CM_NULLPTR);
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ // cmsysProcess_SetTimeout(cp, timeout);
+
+ int problems = 0;
+
+ cmCTest::SetOfStrings::const_iterator file;
+ for (file = files.begin(); file != files.end(); ++file) {
+ int retVal;
+
+ std::string lfname = localprefix;
+ cmSystemTools::ConvertToUnixSlashes(lfname);
+ lfname += "/" + *file;
+ lfname = cmSystemTools::ConvertToOutputPath(lfname.c_str());
+ argv[1] = lfname.c_str();
+ std::string rfname = url + "/" + remoteprefix + *file;
+ argv[2] = rfname.c_str();
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Execute \""
+ << argv[0] << "\" \"" << argv[1] << "\" \"" << argv[2]
+ << "\"" << std::endl,
+ this->Quiet);
+ *this->LogFile << "Execute \"" << argv[0] << "\" \"" << argv[1] << "\" \""
+ << argv[2] << "\"" << std::endl;
+
+ cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_Execute(cp);
+ char* data;
+ int length;
+
+ while (cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(data, length), this->Quiet);
+ }
+
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+
+ int result = cmsysProcess_GetState(cp);
+
+ if (result == cmsysProcess_State_Exited) {
+ retVal = cmsysProcess_GetExitValue(cp);
+ if (retVal != 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "\tSCP returned: " << retVal << std::endl,
+ this->Quiet);
+ *this->LogFile << "\tSCP returned: " << retVal << std::endl;
+ problems++;
+ }
+ } else if (result == cmsysProcess_State_Exception) {
+ retVal = cmsysProcess_GetExitException(cp);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "\tThere was an exception: " << retVal << std::endl);
+ *this->LogFile << "\tThere was an exception: " << retVal << std::endl;
+ problems++;
+ } else if (result == cmsysProcess_State_Expired) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was a timeout"
+ << std::endl);
+ *this->LogFile << "\tThere was a timeout" << std::endl;
+ problems++;
+ } else if (result == cmsysProcess_State_Error) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "\tError executing SCP: "
+ << cmsysProcess_GetErrorString(cp) << std::endl);
+ *this->LogFile << "\tError executing SCP: "
+ << cmsysProcess_GetErrorString(cp) << std::endl;
+ problems++;
+ }
+ }
+ cmsysProcess_Delete(cp);
+ return problems == 0;
+}
+
+bool cmCTestSubmitHandler::SubmitUsingCP(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& destination)
+{
+ if (localprefix.empty() || files.empty() || remoteprefix.empty() ||
+ destination.empty()) {
+ /* clang-format off */
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Missing arguments for submit via cp:\n"
+ << "\tlocalprefix: " << localprefix << "\n"
+ << "\tNumber of files: " << files.size() << "\n"
+ << "\tremoteprefix: " << remoteprefix << "\n"
+ << "\tdestination: " << destination << std::endl);
+ /* clang-format on */
+ return 0;
+ }
+
+ cmCTest::SetOfStrings::const_iterator file;
+ for (file = files.begin(); file != files.end(); ++file) {
+ std::string lfname = localprefix;
+ cmSystemTools::ConvertToUnixSlashes(lfname);
+ lfname += "/" + *file;
+ std::string rfname = destination + "/" + remoteprefix + *file;
+ cmSystemTools::CopyFileAlways(lfname, rfname);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Copy file: "
+ << lfname << " to " << rfname << std::endl,
+ this->Quiet);
+ }
+ std::string tagDoneFile = destination + "/" + remoteprefix + "DONE";
+ cmSystemTools::Touch(tagDoneFile, true);
+ return true;
+}
+
+#if defined(CTEST_USE_XMLRPC)
+bool cmCTestSubmitHandler::SubmitUsingXMLRPC(
+ const std::string& localprefix, const std::set<std::string>& files,
+ const std::string& remoteprefix, const std::string& url)
+{
+ xmlrpc_env env;
+ char ctestString[] = "CTest";
+ std::string ctestVersionString = cmVersion::GetCMakeVersion();
+ char* ctestVersion = const_cast<char*>(ctestVersionString.c_str());
+
+ std::string realURL = url + "/" + remoteprefix + "/Command/";
+
+ /* Start up our XML-RPC client library. */
+ xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, ctestString, ctestVersion);
+
+ /* Initialize our error-handling environment. */
+ xmlrpc_env_init(&env);
+
+ /* Call the famous server at UserLand. */
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Submitting to: "
+ << realURL << " (" << remoteprefix << ")" << std::endl,
+ this->Quiet);
+ cmCTest::SetOfStrings::const_iterator file;
+ for (file = files.begin(); file != files.end(); ++file) {
+ xmlrpc_value* result;
+
+ std::string local_file = *file;
+ if (!cmSystemTools::FileExists(local_file.c_str())) {
+ local_file = localprefix + "/" + *file;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submit file: " << local_file << std::endl,
+ this->Quiet);
+ struct stat st;
+ if (::stat(local_file.c_str(), &st)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Cannot find file: " << local_file << std::endl);
+ return false;
+ }
+
+ // off_t can be bigger than size_t. fread takes size_t.
+ // make sure the file is not too big.
+ if (static_cast<off_t>(static_cast<size_t>(st.st_size)) !=
+ static_cast<off_t>(st.st_size)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " File too big: " << local_file
+ << std::endl);
+ return false;
+ }
+ size_t fileSize = static_cast<size_t>(st.st_size);
+ FILE* fp = cmsys::SystemTools::Fopen(local_file.c_str(), "rb");
+ if (!fp) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Cannot open file: " << local_file << std::endl);
+ return false;
+ }
+
+ unsigned char* fileBuffer = new unsigned char[fileSize];
+ if (fread(fileBuffer, 1, fileSize, fp) != fileSize) {
+ delete[] fileBuffer;
+ fclose(fp);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Cannot read file: " << local_file << std::endl);
+ return false;
+ }
+ fclose(fp);
+
+ char remoteCommand[] = "Submit.put";
+ char* pRealURL = const_cast<char*>(realURL.c_str());
+ result = xmlrpc_client_call(&env, pRealURL, remoteCommand, "(6)",
+ fileBuffer, (xmlrpc_int32)fileSize);
+
+ delete[] fileBuffer;
+
+ if (env.fault_occurred) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " Submission problem: "
+ << env.fault_string << " (" << env.fault_code << ")"
+ << std::endl);
+ xmlrpc_env_clean(&env);
+ xmlrpc_client_cleanup();
+ return false;
+ }
+
+ /* Dispose of our result value. */
+ xmlrpc_DECREF(result);
+ }
+
+ /* Clean up our error-handling environment. */
+ xmlrpc_env_clean(&env);
+
+ /* Shutdown our XML-RPC client library. */
+ xmlrpc_client_cleanup();
+ return true;
+}
+#else
+bool cmCTestSubmitHandler::SubmitUsingXMLRPC(std::string const&,
+ std::set<std::string> const&,
+ std::string const&,
+ std::string const&)
+{
+ return false;
+}
+#endif
+
+void cmCTestSubmitHandler::ConstructCDashURL(std::string& dropMethod,
+ std::string& url)
+{
+ dropMethod = this->CTest->GetCTestConfiguration("DropMethod");
+ url = dropMethod;
+ url += "://";
+ if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) {
+ url += this->CTest->GetCTestConfiguration("DropSiteUser");
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetCTestConfiguration("DropSiteUser").c_str(), this->Quiet);
+ if (!this->CTest->GetCTestConfiguration("DropSitePassword").empty()) {
+ url += ":" + this->CTest->GetCTestConfiguration("DropSitePassword");
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, ":******", this->Quiet);
+ }
+ url += "@";
+ }
+ url += this->CTest->GetCTestConfiguration("DropSite") +
+ this->CTest->GetCTestConfiguration("DropLocation");
+}
+
+int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file,
+ std::string const& typeString)
+{
+ if (file.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Upload file not specified\n");
+ return -1;
+ }
+ if (!cmSystemTools::FileExists(file)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Upload file not found: '"
+ << file << "'\n");
+ return -1;
+ }
+ cmCTestCurl curl(this->CTest);
+ std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
+ std::vector<std::string> args;
+ cmSystemTools::ExpandListArgument(curlopt, args);
+ curl.SetCurlOptions(args);
+ curl.SetTimeOutSeconds(SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
+ std::string dropMethod;
+ std::string url;
+ this->ConstructCDashURL(dropMethod, url);
+ std::string::size_type pos = url.find("submit.php?");
+ url = url.substr(0, pos + 10);
+ if (!(dropMethod == "http" || dropMethod == "https")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Only http and https are supported for CDASH_UPLOAD\n");
+ return -1;
+ }
+ char md5sum[33];
+ md5sum[32] = 0;
+ cmSystemTools::ComputeFileMD5(file, md5sum);
+ // 1. request the buildid and check to see if the 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"));
+ cmake* cm = ch->GetCMake();
+ const char* subproject = cm->GetState()->GetGlobalProperty("SubProject");
+ // TODO: Encode values for a URL instead of trusting caller.
+ std::ostringstream str;
+ str << "project="
+ << curl.Escape(this->CTest->GetCTestConfiguration("ProjectName")) << "&";
+ if (subproject) {
+ str << "subproject=" << curl.Escape(subproject) << "&";
+ }
+ str << "stamp=" << curl.Escape(this->CTest->GetCurrentTag()) << "-"
+ << curl.Escape(this->CTest->GetTestModelString()) << "&"
+ << "model=" << curl.Escape(this->CTest->GetTestModelString()) << "&"
+ << "build="
+ << curl.Escape(this->CTest->GetCTestConfiguration("BuildName")) << "&"
+ << "site=" << curl.Escape(this->CTest->GetCTestConfiguration("Site"))
+ << "&"
+ << "track=" << curl.Escape(this->CTest->GetTestModelString()) << "&"
+ << "starttime=" << (int)cmSystemTools::GetTime() << "&"
+ << "endtime=" << (int)cmSystemTools::GetTime() << "&"
+ << "datafilesmd5[0]=" << md5sum << "&"
+ << "type=" << curl.Escape(typeString);
+ std::string fields = str.str();
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "fields: " << fields << "\nurl:" << url
+ << "\nfile: " << file << "\n",
+ this->Quiet);
+ std::string response;
+ if (!curl.HttpRequest(url, fields, response)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Error in HttpRequest\n"
+ << response);
+ return -1;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Request upload response: [" << response << "]\n",
+ this->Quiet);
+ Json::Value json;
+ Json::Reader reader;
+ if (!reader.parse(response, json)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "error parsing json string ["
+ << response << "]\n"
+ << reader.getFormattedErrorMessages() << "\n");
+ return -1;
+ }
+ if (json["status"].asInt() != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Bad status returned from CDash: " << json["status"].asInt());
+ return -1;
+ }
+ if (json["datafilesmd5"].isArray()) {
+ int datares = json["datafilesmd5"][0].asInt();
+ if (datares == 1) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "File already exists on CDash, skip upload " << file
+ << "\n",
+ this->Quiet);
+ return 0;
+ }
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "bad datafilesmd5 value in response " << response << "\n");
+ return -1;
+ }
+
+ std::string upload_as = cmSystemTools::GetFilenameName(file);
+ std::ostringstream fstr;
+ fstr << "type=" << curl.Escape(typeString) << "&"
+ << "md5=" << md5sum << "&"
+ << "filename=" << curl.Escape(upload_as) << "&"
+ << "buildid=" << json["buildid"].asString();
+ if (!curl.UploadFile(file, url, fstr.str(), response)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "error uploading to CDash. "
+ << file << " " << url << " " << fstr.str());
+ return -1;
+ }
+ if (!reader.parse(response, json)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "error parsing json string ["
+ << response << "]\n"
+ << reader.getFormattedErrorMessages() << "\n");
+ return -1;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Upload file response: [" << response << "]\n",
+ this->Quiet);
+ return 0;
+}
+
+int cmCTestSubmitHandler::ProcessHandler()
+{
+ const char* cdashUploadFile = this->GetOption("CDashUploadFile");
+ const char* cdashUploadType = this->GetOption("CDashUploadType");
+ if (cdashUploadFile && cdashUploadType) {
+ return this->HandleCDashUploadFile(cdashUploadFile, cdashUploadType);
+ }
+ std::string iscdash = this->CTest->GetCTestConfiguration("IsCDash");
+ // cdash does not need to trigger so just return true
+ if (!iscdash.empty()) {
+ this->CDash = true;
+ }
+
+ const std::string& buildDirectory =
+ this->CTest->GetCTestConfiguration("BuildDirectory");
+ if (buildDirectory.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find BuildDirectory key in the DartConfiguration.tcl"
+ << std::endl);
+ return -1;
+ }
+
+ if (getenv("HTTP_PROXY")) {
+ this->HTTPProxyType = 1;
+ this->HTTPProxy = getenv("HTTP_PROXY");
+ if (getenv("HTTP_PROXY_PORT")) {
+ this->HTTPProxy += ":";
+ this->HTTPProxy += getenv("HTTP_PROXY_PORT");
+ }
+ if (getenv("HTTP_PROXY_TYPE")) {
+ std::string type = getenv("HTTP_PROXY_TYPE");
+ // HTTP/SOCKS4/SOCKS5
+ if (type == "HTTP") {
+ this->HTTPProxyType = 1;
+ } else if (type == "SOCKS4") {
+ this->HTTPProxyType = 2;
+ } else if (type == "SOCKS5") {
+ this->HTTPProxyType = 3;
+ }
+ }
+ if (getenv("HTTP_PROXY_USER")) {
+ this->HTTPProxyAuth = getenv("HTTP_PROXY_USER");
+ }
+ if (getenv("HTTP_PROXY_PASSWD")) {
+ this->HTTPProxyAuth += ":";
+ this->HTTPProxyAuth += getenv("HTTP_PROXY_PASSWD");
+ }
+ }
+
+ if (getenv("FTP_PROXY")) {
+ this->FTPProxyType = 1;
+ this->FTPProxy = getenv("FTP_PROXY");
+ if (getenv("FTP_PROXY_PORT")) {
+ this->FTPProxy += ":";
+ this->FTPProxy += getenv("FTP_PROXY_PORT");
+ }
+ if (getenv("FTP_PROXY_TYPE")) {
+ std::string type = getenv("FTP_PROXY_TYPE");
+ // HTTP/SOCKS4/SOCKS5
+ if (type == "HTTP") {
+ this->FTPProxyType = 1;
+ } else if (type == "SOCKS4") {
+ this->FTPProxyType = 2;
+ } else if (type == "SOCKS5") {
+ this->FTPProxyType = 3;
+ }
+ }
+ }
+
+ if (!this->HTTPProxy.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Use HTTP Proxy: " << this->HTTPProxy << std::endl,
+ this->Quiet);
+ }
+ if (!this->FTPProxy.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Use FTP Proxy: " << this->FTPProxy << std::endl,
+ this->Quiet);
+ }
+ cmGeneratedFileStream ofs;
+ this->StartLogFile("Submit", ofs);
+
+ cmCTest::SetOfStrings files;
+ std::string prefix = this->GetSubmitResultsPrefix();
+
+ if (!this->Files.empty()) {
+ // Submit the explicitly selected files:
+ //
+ files.insert(this->Files.begin(), this->Files.end());
+ }
+
+ // Add to the list of files to submit from any selected, existing parts:
+ //
+
+ // TODO:
+ // Check if test is enabled
+
+ this->CTest->AddIfExists(cmCTest::PartUpdate, "Update.xml");
+ this->CTest->AddIfExists(cmCTest::PartConfigure, "Configure.xml");
+ this->CTest->AddIfExists(cmCTest::PartBuild, "Build.xml");
+ this->CTest->AddIfExists(cmCTest::PartTest, "Test.xml");
+ if (this->CTest->AddIfExists(cmCTest::PartCoverage, "Coverage.xml")) {
+ std::vector<std::string> gfiles;
+ std::string gpath =
+ buildDirectory + "/Testing/" + this->CTest->GetCurrentTag();
+ std::string::size_type glen = gpath.size() + 1;
+ gpath = gpath + "/CoverageLog*";
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Globbing for: " << gpath << std::endl, this->Quiet);
+ if (cmSystemTools::SimpleGlob(gpath, gfiles, 1)) {
+ size_t cc;
+ for (cc = 0; cc < gfiles.size(); cc++) {
+ gfiles[cc] = gfiles[cc].substr(glen);
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Glob file: " << gfiles[cc] << std::endl,
+ this->Quiet);
+ this->CTest->AddSubmitFile(cmCTest::PartCoverage, gfiles[cc].c_str());
+ }
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem globbing" << std::endl);
+ }
+ }
+ this->CTest->AddIfExists(cmCTest::PartMemCheck, "DynamicAnalysis.xml");
+ this->CTest->AddIfExists(cmCTest::PartMemCheck, "Purify.xml");
+ this->CTest->AddIfExists(cmCTest::PartNotes, "Notes.xml");
+ this->CTest->AddIfExists(cmCTest::PartUpload, "Upload.xml");
+
+ // Query parts for files to submit.
+ for (cmCTest::Part p = cmCTest::PartStart; p != cmCTest::PartCount;
+ p = cmCTest::Part(p + 1)) {
+ // Skip parts we are not submitting.
+ if (!this->SubmitPart[p]) {
+ continue;
+ }
+
+ // Submit files from this part.
+ std::vector<std::string> const& pfiles = this->CTest->GetSubmitFiles(p);
+ files.insert(pfiles.begin(), pfiles.end());
+ }
+
+ if (ofs) {
+ ofs << "Upload files:" << std::endl;
+ int cnt = 0;
+ cmCTest::SetOfStrings::iterator it;
+ for (it = files.begin(); it != files.end(); ++it) {
+ ofs << cnt << "\t" << *it << std::endl;
+ cnt++;
+ }
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "Submit files (using "
+ << this->CTest->GetCTestConfiguration("DropMethod")
+ << ")" << std::endl,
+ this->Quiet);
+ const char* specificTrack = this->CTest->GetSpecificTrack();
+ if (specificTrack) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Send to track: " << specificTrack << std::endl,
+ this->Quiet);
+ }
+ this->SetLogFile(&ofs);
+
+ std::string dropMethod(this->CTest->GetCTestConfiguration("DropMethod"));
+
+ if (dropMethod == "" || dropMethod == "ftp") {
+ ofs << "Using drop method: FTP" << std::endl;
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Using FTP submit method" << std::endl
+ << " Drop site: ftp://",
+ this->Quiet);
+ std::string url = "ftp://";
+ url += cmCTest::MakeURLSafe(
+ this->CTest->GetCTestConfiguration("DropSiteUser")) +
+ ":" + cmCTest::MakeURLSafe(
+ this->CTest->GetCTestConfiguration("DropSitePassword")) +
+ "@" + this->CTest->GetCTestConfiguration("DropSite") +
+ cmCTest::MakeURLSafe(this->CTest->GetCTestConfiguration("DropLocation"));
+ if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetCTestConfiguration("DropSiteUser").c_str(),
+ this->Quiet);
+ if (!this->CTest->GetCTestConfiguration("DropSitePassword").empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, ":******",
+ this->Quiet);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "@", this->Quiet);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetCTestConfiguration("DropSite")
+ << this->CTest->GetCTestConfiguration("DropLocation")
+ << std::endl,
+ this->Quiet);
+ if (!this->SubmitUsingFTP(buildDirectory + "/Testing/" +
+ this->CTest->GetCurrentTag(),
+ files, prefix, url)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Problems when submitting via FTP" << std::endl);
+ ofs << " Problems when submitting via FTP" << std::endl;
+ return -1;
+ }
+ if (!this->CDash) {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT, " Using HTTP trigger method"
+ << std::endl
+ << " Trigger site: "
+ << this->CTest->GetCTestConfiguration("TriggerSite") << std::endl,
+ this->Quiet);
+ if (!this->TriggerUsingHTTP(
+ files, prefix,
+ this->CTest->GetCTestConfiguration("TriggerSite"))) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Problems when triggering via HTTP" << std::endl);
+ ofs << " Problems when triggering via HTTP" << std::endl;
+ return -1;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submission successful" << std::endl, this->Quiet);
+ ofs << " Submission successful" << std::endl;
+ return 0;
+ }
+ } else if (dropMethod == "http" || dropMethod == "https") {
+ std::string url = dropMethod;
+ url += "://";
+ ofs << "Using drop method: " << dropMethod << std::endl;
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Using HTTP submit method" << std::endl
+ << " Drop site:" << url,
+ this->Quiet);
+ if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) {
+ url += this->CTest->GetCTestConfiguration("DropSiteUser");
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetCTestConfiguration("DropSiteUser").c_str(),
+ this->Quiet);
+ if (!this->CTest->GetCTestConfiguration("DropSitePassword").empty()) {
+ url += ":" + this->CTest->GetCTestConfiguration("DropSitePassword");
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, ":******",
+ this->Quiet);
+ }
+ url += "@";
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "@", this->Quiet);
+ }
+ url += this->CTest->GetCTestConfiguration("DropSite") +
+ this->CTest->GetCTestConfiguration("DropLocation");
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetCTestConfiguration("DropSite")
+ << this->CTest->GetCTestConfiguration("DropLocation")
+ << std::endl,
+ this->Quiet);
+ if (!this->SubmitUsingHTTP(buildDirectory + "/Testing/" +
+ this->CTest->GetCurrentTag(),
+ files, prefix, url)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Problems when submitting via HTTP" << std::endl);
+ ofs << " Problems when submitting via HTTP" << std::endl;
+ return -1;
+ }
+ if (!this->CDash) {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT, " Using HTTP trigger method"
+ << std::endl
+ << " Trigger site: "
+ << this->CTest->GetCTestConfiguration("TriggerSite") << std::endl,
+ this->Quiet);
+ if (!this->TriggerUsingHTTP(
+ files, prefix,
+ this->CTest->GetCTestConfiguration("TriggerSite"))) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Problems when triggering via HTTP" << std::endl);
+ ofs << " Problems when triggering via HTTP" << std::endl;
+ return -1;
+ }
+ }
+ if (this->HasErrors) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Errors occurred during "
+ "submission."
+ << std::endl);
+ ofs << " Errors occurred during submission. " << std::endl;
+ } else {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT, " Submission successful"
+ << (this->HasWarnings ? ", with warnings." : "") << std::endl,
+ this->Quiet);
+ ofs << " Submission successful"
+ << (this->HasWarnings ? ", with warnings." : "") << std::endl;
+ }
+
+ return 0;
+ } else if (dropMethod == "xmlrpc") {
+#if defined(CTEST_USE_XMLRPC)
+ ofs << "Using drop method: XML-RPC" << std::endl;
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Using XML-RPC submit method" << std::endl,
+ this->Quiet);
+ std::string url = this->CTest->GetCTestConfiguration("DropSite");
+ prefix = this->CTest->GetCTestConfiguration("DropLocation");
+ if (!this->SubmitUsingXMLRPC(buildDirectory + "/Testing/" +
+ this->CTest->GetCurrentTag(),
+ files, prefix, url)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Problems when submitting via XML-RPC" << std::endl);
+ ofs << " Problems when submitting via XML-RPC" << std::endl;
+ return -1;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submission successful" << std::endl, this->Quiet);
+ ofs << " Submission successful" << std::endl;
+ return 0;
+#else
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Submission method \"xmlrpc\" not compiled into CTest!"
+ << std::endl);
+ return -1;
+#endif
+ } else if (dropMethod == "scp") {
+ std::string url;
+ std::string oldWorkingDirectory;
+ if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) {
+ url += this->CTest->GetCTestConfiguration("DropSiteUser") + "@";
+ }
+ url += this->CTest->GetCTestConfiguration("DropSite") + ":" +
+ this->CTest->GetCTestConfiguration("DropLocation");
+
+ // change to the build directory so that we can uses a relative path
+ // on windows since scp dosn't support "c:" a drive in the path
+ oldWorkingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::ChangeDirectory(buildDirectory);
+
+ if (!this->SubmitUsingSCP(this->CTest->GetCTestConfiguration("ScpCommand"),
+ "Testing/" + this->CTest->GetCurrentTag(), files,
+ prefix, url)) {
+ cmSystemTools::ChangeDirectory(oldWorkingDirectory);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Problems when submitting via SCP" << std::endl);
+ ofs << " Problems when submitting via SCP" << std::endl;
+ return -1;
+ }
+ cmSystemTools::ChangeDirectory(oldWorkingDirectory);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submission successful" << std::endl, this->Quiet);
+ ofs << " Submission successful" << std::endl;
+ return 0;
+ } else if (dropMethod == "cp") {
+ std::string location = this->CTest->GetCTestConfiguration("DropLocation");
+
+ // change to the build directory so that we can uses a relative path
+ // on windows since scp dosn't support "c:" a drive in the path
+ std::string oldWorkingDirectory =
+ cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::ChangeDirectory(buildDirectory);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Change directory: " << buildDirectory << std::endl,
+ this->Quiet);
+
+ if (!this->SubmitUsingCP("Testing/" + this->CTest->GetCurrentTag(), files,
+ prefix, location)) {
+ cmSystemTools::ChangeDirectory(oldWorkingDirectory);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Problems when submitting via CP" << std::endl);
+ ofs << " Problems when submitting via cp" << std::endl;
+ return -1;
+ }
+ cmSystemTools::ChangeDirectory(oldWorkingDirectory);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submission successful" << std::endl, this->Quiet);
+ ofs << " Submission successful" << std::endl;
+ return 0;
+ }
+
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " Unknown submission method: \""
+ << dropMethod << "\"" << std::endl);
+ return -1;
+}
+
+std::string cmCTestSubmitHandler::GetSubmitResultsPrefix()
+{
+ std::string buildname =
+ cmCTest::SafeBuildIdField(this->CTest->GetCTestConfiguration("BuildName"));
+ std::string name = this->CTest->GetCTestConfiguration("Site") + "___" +
+ buildname + "___" + this->CTest->GetCurrentTag() + "-" +
+ this->CTest->GetTestModelString() + "___XML___";
+ return name;
+}
+
+void cmCTestSubmitHandler::SelectParts(std::set<cmCTest::Part> const& parts)
+{
+ // Check whether each part is selected.
+ for (cmCTest::Part p = cmCTest::PartStart; p != cmCTest::PartCount;
+ p = cmCTest::Part(p + 1)) {
+ this->SubmitPart[p] =
+ (std::set<cmCTest::Part>::const_iterator(parts.find(p)) != parts.end());
+ }
+}
+
+void cmCTestSubmitHandler::SelectFiles(cmCTest::SetOfStrings const& files)
+{
+ this->Files.insert(files.begin(), files.end());
+}
diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h
new file mode 100644
index 0000000..4cca6eb
--- /dev/null
+++ b/Source/CTest/cmCTestSubmitHandler.h
@@ -0,0 +1,100 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestSubmitHandler_h
+#define cmCTestSubmitHandler_h
+
+#include "cmCTestGenericHandler.h"
+
+/** \class cmCTestSubmitHandler
+ * \brief Helper class for CTest
+ *
+ * Submit testing results
+ *
+ */
+class cmCTestSubmitHandler : public cmCTestGenericHandler
+{
+public:
+ cmTypeMacro(cmCTestSubmitHandler, cmCTestGenericHandler);
+
+ cmCTestSubmitHandler();
+ ~cmCTestSubmitHandler() CM_OVERRIDE { this->LogFile = CM_NULLPTR; }
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() CM_OVERRIDE;
+
+ void Initialize() CM_OVERRIDE;
+
+ /** Specify a set of parts (by name) to submit. */
+ void SelectParts(std::set<cmCTest::Part> const& parts);
+
+ /** Specify a set of files to submit. */
+ void SelectFiles(cmCTest::SetOfStrings const& files);
+
+ // handle the cdash file upload protocol
+ int HandleCDashUploadFile(std::string const& file, std::string const& type);
+
+ void ConstructCDashURL(std::string& dropMethod, std::string& url);
+
+private:
+ void SetLogFile(std::ostream* ost) { this->LogFile = ost; }
+
+ /**
+ * Submit file using various ways
+ */
+ bool SubmitUsingFTP(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix, const std::string& url);
+ bool SubmitUsingHTTP(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url);
+ bool SubmitUsingSCP(const std::string& scp_command,
+ const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix, const std::string& url);
+
+ bool SubmitUsingCP(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix, const std::string& url);
+
+ bool TriggerUsingHTTP(const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url);
+
+ bool SubmitUsingXMLRPC(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url);
+
+ typedef std::vector<char> cmCTestSubmitHandlerVectorOfChar;
+
+ void ParseResponse(cmCTestSubmitHandlerVectorOfChar chunk);
+
+ std::string GetSubmitResultsPrefix();
+
+ class ResponseParser;
+ std::string HTTPProxy;
+ int HTTPProxyType;
+ std::string HTTPProxyAuth;
+ std::string FTPProxy;
+ int FTPProxyType;
+ std::ostream* LogFile;
+ bool SubmitPart[cmCTest::PartCount];
+ bool CDash;
+ bool HasWarnings;
+ bool HasErrors;
+ cmCTest::SetOfStrings Files;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx
new file mode 100644
index 0000000..1d064db
--- /dev/null
+++ b/Source/CTest/cmCTestTestCommand.cxx
@@ -0,0 +1,121 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestTestCommand.h"
+
+#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
+
+cmCTestTestCommand::cmCTestTestCommand()
+{
+ this->Arguments[ctt_START] = "START";
+ this->Arguments[ctt_END] = "END";
+ this->Arguments[ctt_STRIDE] = "STRIDE";
+ this->Arguments[ctt_EXCLUDE] = "EXCLUDE";
+ this->Arguments[ctt_INCLUDE] = "INCLUDE";
+ this->Arguments[ctt_EXCLUDE_LABEL] = "EXCLUDE_LABEL";
+ this->Arguments[ctt_INCLUDE_LABEL] = "INCLUDE_LABEL";
+ this->Arguments[ctt_PARALLEL_LEVEL] = "PARALLEL_LEVEL";
+ this->Arguments[ctt_SCHEDULE_RANDOM] = "SCHEDULE_RANDOM";
+ this->Arguments[ctt_STOP_TIME] = "STOP_TIME";
+ this->Arguments[ctt_TEST_LOAD] = "TEST_LOAD";
+ this->Arguments[ctt_LAST] = CM_NULLPTR;
+ this->Last = ctt_LAST;
+}
+
+cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
+{
+ const char* ctestTimeout =
+ this->Makefile->GetDefinition("CTEST_TEST_TIMEOUT");
+
+ double timeout = this->CTest->GetTimeOut();
+ if (ctestTimeout) {
+ timeout = atof(ctestTimeout);
+ } else {
+ if (timeout <= 0) {
+ // By default use timeout of 10 minutes
+ timeout = 600;
+ }
+ }
+ this->CTest->SetTimeOut(timeout);
+ cmCTestGenericHandler* handler = this->InitializeActualHandler();
+ if (this->Values[ctt_START] || this->Values[ctt_END] ||
+ this->Values[ctt_STRIDE]) {
+ std::ostringstream testsToRunString;
+ if (this->Values[ctt_START]) {
+ testsToRunString << this->Values[ctt_START];
+ }
+ testsToRunString << ",";
+ if (this->Values[ctt_END]) {
+ testsToRunString << this->Values[ctt_END];
+ }
+ testsToRunString << ",";
+ if (this->Values[ctt_STRIDE]) {
+ testsToRunString << this->Values[ctt_STRIDE];
+ }
+ handler->SetOption("TestsToRunInformation",
+ testsToRunString.str().c_str());
+ }
+ if (this->Values[ctt_EXCLUDE]) {
+ handler->SetOption("ExcludeRegularExpression", this->Values[ctt_EXCLUDE]);
+ }
+ if (this->Values[ctt_INCLUDE]) {
+ handler->SetOption("IncludeRegularExpression", this->Values[ctt_INCLUDE]);
+ }
+ if (this->Values[ctt_EXCLUDE_LABEL]) {
+ handler->SetOption("ExcludeLabelRegularExpression",
+ this->Values[ctt_EXCLUDE_LABEL]);
+ }
+ if (this->Values[ctt_INCLUDE_LABEL]) {
+ handler->SetOption("LabelRegularExpression",
+ this->Values[ctt_INCLUDE_LABEL]);
+ }
+ if (this->Values[ctt_PARALLEL_LEVEL]) {
+ handler->SetOption("ParallelLevel", this->Values[ctt_PARALLEL_LEVEL]);
+ }
+ if (this->Values[ctt_SCHEDULE_RANDOM]) {
+ handler->SetOption("ScheduleRandom", this->Values[ctt_SCHEDULE_RANDOM]);
+ }
+ if (this->Values[ctt_STOP_TIME]) {
+ this->CTest->SetStopTime(this->Values[ctt_STOP_TIME]);
+ }
+
+ // Test load is determined by: TEST_LOAD argument,
+ // or CTEST_TEST_LOAD script variable, or ctest --test-load
+ // command line argument... in that order.
+ unsigned long testLoad;
+ const char* ctestTestLoad = this->Makefile->GetDefinition("CTEST_TEST_LOAD");
+ if (this->Values[ctt_TEST_LOAD] && *this->Values[ctt_TEST_LOAD]) {
+ if (!cmSystemTools::StringToULong(this->Values[ctt_TEST_LOAD],
+ &testLoad)) {
+ testLoad = 0;
+ cmCTestLog(this->CTest, WARNING, "Invalid value for 'TEST_LOAD' : "
+ << this->Values[ctt_TEST_LOAD] << std::endl);
+ }
+ } else if (ctestTestLoad && *ctestTestLoad) {
+ if (!cmSystemTools::StringToULong(ctestTestLoad, &testLoad)) {
+ testLoad = 0;
+ cmCTestLog(this->CTest, WARNING, "Invalid value for 'CTEST_TEST_LOAD' : "
+ << ctestTestLoad << std::endl);
+ }
+ } else {
+ testLoad = this->CTest->GetTestLoad();
+ }
+ handler->SetTestLoad(testLoad);
+
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
+
+cmCTestGenericHandler* cmCTestTestCommand::InitializeActualHandler()
+{
+ return this->CTest->GetInitializedHandler("test");
+}
diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h
new file mode 100644
index 0000000..f652971
--- /dev/null
+++ b/Source/CTest/cmCTestTestCommand.h
@@ -0,0 +1,68 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestTestCommand_h
+#define cmCTestTestCommand_h
+
+#include "cmCTestHandlerCommand.h"
+
+/** \class cmCTestTest
+ * \brief Run a ctest script
+ *
+ * cmCTestTestCommand defineds the command to test the project.
+ */
+class cmCTestTestCommand : public cmCTestHandlerCommand
+{
+public:
+ cmCTestTestCommand();
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestTestCommand* ni = new cmCTestTestCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return ni;
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "ctest_test"; }
+
+ cmTypeMacro(cmCTestTestCommand, cmCTestHandlerCommand);
+
+protected:
+ virtual cmCTestGenericHandler* InitializeActualHandler();
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
+
+ enum
+ {
+ ctt_BUILD = ct_LAST,
+ ctt_RETURN_VALUE,
+ ctt_START,
+ ctt_END,
+ ctt_STRIDE,
+ ctt_EXCLUDE,
+ ctt_INCLUDE,
+ ctt_EXCLUDE_LABEL,
+ ctt_INCLUDE_LABEL,
+ ctt_PARALLEL_LEVEL,
+ ctt_SCHEDULE_RANDOM,
+ ctt_STOP_TIME,
+ ctt_TEST_LOAD,
+ ctt_LAST
+ };
+};
+
+#endif
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
new file mode 100644
index 0000000..cd250fb
--- /dev/null
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -0,0 +1,1991 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCTestTestHandler.h"
+
+#include "cmCTest.h"
+#include "cmCTestBatchTestHandler.h"
+#include "cmCTestMultiProcessHandler.h"
+#include "cmCTestRunTest.h"
+#include "cmCommand.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+#include "cm_utf8.h"
+#include "cmake.h"
+#include <cmsys/Base64.h>
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Process.h>
+#include <cmsys/RegularExpression.hxx>
+
+#include <float.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include <set>
+
+class cmCTestSubdirCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestSubdirCommand* c = new cmCTestSubdirCommand;
+ c->TestHandler = this->TestHandler;
+ return c;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "subdirs"; }
+
+ cmTypeMacro(cmCTestSubdirCommand, cmCommand);
+
+ cmCTestTestHandler* TestHandler;
+};
+
+bool cmCTestSubdirCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.empty()) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ std::vector<std::string>::const_iterator it;
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ for (it = args.begin(); it != args.end(); ++it) {
+ std::string fname;
+
+ if (cmSystemTools::FileIsFullPath(it->c_str())) {
+ fname = *it;
+ } else {
+ fname = cwd;
+ fname += "/";
+ fname += *it;
+ }
+
+ if (!cmSystemTools::FileIsDirectory(fname)) {
+ // No subdirectory? So what...
+ continue;
+ }
+ cmSystemTools::ChangeDirectory(fname);
+ const char* testFilename;
+ if (cmSystemTools::FileExists("CTestTestfile.cmake")) {
+ // does the CTestTestfile.cmake exist ?
+ testFilename = "CTestTestfile.cmake";
+ } else if (cmSystemTools::FileExists("DartTestfile.txt")) {
+ // does the DartTestfile.txt exist ?
+ testFilename = "DartTestfile.txt";
+ } else {
+ // No CTestTestfile? Who cares...
+ continue;
+ }
+ fname += "/";
+ fname += testFilename;
+ bool readit = this->Makefile->ReadDependentFile(fname.c_str());
+ cmSystemTools::ChangeDirectory(cwd);
+ if (!readit) {
+ std::string m = "Could not find include file: ";
+ m += fname;
+ this->SetError(m);
+ return false;
+ }
+ }
+ cmSystemTools::ChangeDirectory(cwd);
+ return true;
+}
+
+class cmCTestAddSubdirectoryCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestAddSubdirectoryCommand* c = new cmCTestAddSubdirectoryCommand;
+ c->TestHandler = this->TestHandler;
+ return c;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "add_subdirectory"; }
+
+ cmTypeMacro(cmCTestAddSubdirectoryCommand, cmCommand);
+
+ cmCTestTestHandler* TestHandler;
+};
+
+bool cmCTestAddSubdirectoryCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.empty()) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::ChangeDirectory(cwd);
+ std::string fname = cwd;
+ fname += "/";
+ fname += args[0];
+
+ if (!cmSystemTools::FileExists(fname.c_str())) {
+ // No subdirectory? So what...
+ return true;
+ }
+ cmSystemTools::ChangeDirectory(fname);
+ const char* testFilename;
+ if (cmSystemTools::FileExists("CTestTestfile.cmake")) {
+ // does the CTestTestfile.cmake exist ?
+ testFilename = "CTestTestfile.cmake";
+ } else if (cmSystemTools::FileExists("DartTestfile.txt")) {
+ // does the DartTestfile.txt exist ?
+ testFilename = "DartTestfile.txt";
+ } else {
+ // No CTestTestfile? Who cares...
+ cmSystemTools::ChangeDirectory(cwd);
+ return true;
+ }
+ fname += "/";
+ fname += testFilename;
+ bool readit = this->Makefile->ReadDependentFile(fname.c_str());
+ cmSystemTools::ChangeDirectory(cwd);
+ if (!readit) {
+ std::string m = "Could not find include file: ";
+ m += fname;
+ this->SetError(m);
+ return false;
+ }
+ return true;
+}
+
+class cmCTestAddTestCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestAddTestCommand* c = new cmCTestAddTestCommand;
+ c->TestHandler = this->TestHandler;
+ return c;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "add_test"; }
+
+ cmTypeMacro(cmCTestAddTestCommand, cmCommand);
+
+ cmCTestTestHandler* TestHandler;
+};
+
+bool cmCTestAddTestCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ return this->TestHandler->AddTest(args);
+}
+
+class cmCTestSetTestsPropertiesCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestSetTestsPropertiesCommand* c = new cmCTestSetTestsPropertiesCommand;
+ c->TestHandler = this->TestHandler;
+ return c;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "set_tests_properties"; }
+
+ cmTypeMacro(cmCTestSetTestsPropertiesCommand, cmCommand);
+
+ cmCTestTestHandler* TestHandler;
+};
+
+bool cmCTestSetTestsPropertiesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ return this->TestHandler->SetTestsProperties(args);
+}
+
+// get the next number in a string with numbers separated by ,
+// pos is the start of the search and pos2 is the end of the search
+// pos becomes pos2 after a call to GetNextNumber.
+// -1 is returned at the end of the list.
+inline int GetNextNumber(std::string const& in, int& val,
+ std::string::size_type& pos,
+ std::string::size_type& pos2)
+{
+ pos2 = in.find(',', pos);
+ if (pos2 != in.npos) {
+ if (pos2 - pos == 0) {
+ val = -1;
+ } else {
+ val = atoi(in.substr(pos, pos2 - pos).c_str());
+ }
+ pos = pos2 + 1;
+ return 1;
+ } else {
+ if (in.size() - pos == 0) {
+ val = -1;
+ } else {
+ val = atoi(in.substr(pos, in.size() - pos).c_str());
+ }
+ return 0;
+ }
+}
+
+// get the next number in a string with numbers separated by ,
+// pos is the start of the search and pos2 is the end of the search
+// pos becomes pos2 after a call to GetNextNumber.
+// -1 is returned at the end of the list.
+inline int GetNextRealNumber(std::string const& in, double& val,
+ std::string::size_type& pos,
+ std::string::size_type& pos2)
+{
+ pos2 = in.find(',', pos);
+ if (pos2 != in.npos) {
+ if (pos2 - pos == 0) {
+ val = -1;
+ } else {
+ val = atof(in.substr(pos, pos2 - pos).c_str());
+ }
+ pos = pos2 + 1;
+ return 1;
+ } else {
+ if (in.size() - pos == 0) {
+ val = -1;
+ } else {
+ val = atof(in.substr(pos, in.size() - pos).c_str());
+ }
+ return 0;
+ }
+}
+
+cmCTestTestHandler::cmCTestTestHandler()
+{
+ this->UseUnion = false;
+
+ this->UseIncludeLabelRegExpFlag = false;
+ this->UseExcludeLabelRegExpFlag = false;
+ this->UseIncludeRegExpFlag = false;
+ this->UseExcludeRegExpFlag = false;
+ this->UseExcludeRegExpFirst = false;
+
+ this->CustomMaximumPassedTestOutputSize = 1 * 1024;
+ this->CustomMaximumFailedTestOutputSize = 300 * 1024;
+
+ this->MemCheck = false;
+
+ this->LogFile = CM_NULLPTR;
+
+ // regex to detect <DartMeasurement>...</DartMeasurement>
+ this->DartStuff.compile("(<DartMeasurement.*/DartMeasurement[a-zA-Z]*>)");
+ // regex to detect each individual <DartMeasurement>...</DartMeasurement>
+ this->DartStuff1.compile(
+ "(<DartMeasurement[^<]*</DartMeasurement[a-zA-Z]*>)");
+}
+
+void cmCTestTestHandler::Initialize()
+{
+ this->Superclass::Initialize();
+
+ this->ElapsedTestingTime = -1;
+
+ this->TestResults.clear();
+
+ this->CustomTestsIgnore.clear();
+ this->StartTest = "";
+ this->EndTest = "";
+
+ this->CustomPreTest.clear();
+ this->CustomPostTest.clear();
+ this->CustomMaximumPassedTestOutputSize = 1 * 1024;
+ this->CustomMaximumFailedTestOutputSize = 300 * 1024;
+
+ this->TestsToRun.clear();
+
+ this->UseIncludeLabelRegExpFlag = false;
+ this->UseExcludeLabelRegExpFlag = false;
+ this->UseIncludeRegExpFlag = false;
+ this->UseExcludeRegExpFlag = false;
+ this->UseExcludeRegExpFirst = false;
+ this->IncludeLabelRegularExpression = "";
+ this->ExcludeLabelRegularExpression = "";
+ this->IncludeRegExp = "";
+ this->ExcludeRegExp = "";
+
+ TestsToRunString = "";
+ this->UseUnion = false;
+ this->TestList.clear();
+}
+
+void cmCTestTestHandler::PopulateCustomVectors(cmMakefile* mf)
+{
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_TEST",
+ this->CustomPreTest);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_POST_TEST",
+ this->CustomPostTest);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_TESTS_IGNORE",
+ this->CustomTestsIgnore);
+ this->CTest->PopulateCustomInteger(
+ mf, "CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE",
+ this->CustomMaximumPassedTestOutputSize);
+ this->CTest->PopulateCustomInteger(
+ mf, "CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE",
+ this->CustomMaximumFailedTestOutputSize);
+}
+
+int cmCTestTestHandler::PreProcessHandler()
+{
+ if (!this->ExecuteCommands(this->CustomPreTest)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem executing pre-test command(s)." << std::endl);
+ return 0;
+ }
+ return 1;
+}
+
+int cmCTestTestHandler::PostProcessHandler()
+{
+ if (!this->ExecuteCommands(this->CustomPostTest)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem executing post-test command(s)." << std::endl);
+ return 0;
+ }
+ return 1;
+}
+
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
+int cmCTestTestHandler::ProcessHandler()
+{
+ // Update internal data structure from generic one
+ this->SetTestsToRunInformation(this->GetOption("TestsToRunInformation"));
+ this->SetUseUnion(cmSystemTools::IsOn(this->GetOption("UseUnion")));
+ if (cmSystemTools::IsOn(this->GetOption("ScheduleRandom"))) {
+ this->CTest->SetScheduleType("Random");
+ }
+ if (this->GetOption("ParallelLevel")) {
+ this->CTest->SetParallelLevel(atoi(this->GetOption("ParallelLevel")));
+ }
+
+ const char* val;
+ val = this->GetOption("LabelRegularExpression");
+ if (val) {
+ this->UseIncludeLabelRegExpFlag = true;
+ this->IncludeLabelRegExp = val;
+ }
+ val = this->GetOption("ExcludeLabelRegularExpression");
+ if (val) {
+ this->UseExcludeLabelRegExpFlag = true;
+ this->ExcludeLabelRegExp = val;
+ }
+ val = this->GetOption("IncludeRegularExpression");
+ if (val) {
+ this->UseIncludeRegExp();
+ this->SetIncludeRegExp(val);
+ }
+ val = this->GetOption("ExcludeRegularExpression");
+ if (val) {
+ this->UseExcludeRegExp();
+ this->SetExcludeRegExp(val);
+ }
+ this->SetRerunFailed(cmSystemTools::IsOn(this->GetOption("RerunFailed")));
+
+ this->TestResults.clear();
+
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT, (this->MemCheck ? "Memory check" : "Test")
+ << " project " << cmSystemTools::GetCurrentWorkingDirectory()
+ << std::endl,
+ this->Quiet);
+ if (!this->PreProcessHandler()) {
+ return -1;
+ }
+
+ cmGeneratedFileStream mLogFile;
+ this->StartLogFile((this->MemCheck ? "DynamicAnalysis" : "Test"), mLogFile);
+ this->LogFile = &mLogFile;
+
+ std::vector<std::string> passed;
+ std::vector<std::string> failed;
+ int total;
+
+ // start the real time clock
+ double clock_start, clock_finish;
+ clock_start = cmSystemTools::GetTime();
+
+ this->ProcessDirectory(passed, failed);
+
+ clock_finish = cmSystemTools::GetTime();
+
+ total = int(passed.size()) + int(failed.size());
+
+ if (total == 0) {
+ if (!this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "No tests were found!!!"
+ << std::endl);
+ }
+ } else {
+ if (this->HandlerVerbose && !passed.empty() &&
+ (this->UseIncludeRegExpFlag || this->UseExcludeRegExpFlag)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
+ << "The following tests passed:" << std::endl,
+ this->Quiet);
+ for (std::vector<std::string>::iterator j = passed.begin();
+ j != passed.end(); ++j) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "\t" << *j << std::endl, this->Quiet);
+ }
+ }
+
+ float percent = float(passed.size()) * 100.0f / float(total);
+ if (!failed.empty() && percent > 99) {
+ percent = 99;
+ }
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl
+ << static_cast<int>(percent + .5f) << "% tests passed, "
+ << failed.size() << " tests failed out of " << total
+ << std::endl);
+ if (this->CTest->GetLabelSummary()) {
+ this->PrintLabelSummary();
+ }
+ char realBuf[1024];
+ sprintf(realBuf, "%6.2f sec", (double)(clock_finish - clock_start));
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "\nTotal Test time (real) = " << realBuf << "\n",
+ this->Quiet);
+
+ if (!failed.empty()) {
+ cmGeneratedFileStream ofs;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl
+ << "The following tests FAILED:" << std::endl);
+ this->StartLogFile("TestsFailed", ofs);
+
+ typedef std::set<cmCTestTestHandler::cmCTestTestResult,
+ cmCTestTestResultLess>
+ SetOfTests;
+ SetOfTests resultsSet(this->TestResults.begin(),
+ this->TestResults.end());
+
+ for (SetOfTests::iterator ftit = resultsSet.begin();
+ ftit != resultsSet.end(); ++ftit) {
+ if (ftit->Status != cmCTestTestHandler::COMPLETED) {
+ ofs << ftit->TestCount << ":" << ftit->Name << std::endl;
+ cmCTestLog(
+ this->CTest, HANDLER_OUTPUT, "\t"
+ << std::setw(3) << ftit->TestCount << " - " << ftit->Name << " ("
+ << this->GetTestStatus(ftit->Status) << ")" << std::endl);
+ }
+ }
+ }
+ }
+
+ if (this->CTest->GetProduceXML()) {
+ cmGeneratedFileStream xmlfile;
+ if (!this->StartResultingXML(
+ (this->MemCheck ? cmCTest::PartMemCheck : cmCTest::PartTest),
+ (this->MemCheck ? "DynamicAnalysis" : "Test"), xmlfile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create "
+ << (this->MemCheck ? "memory check" : "testing")
+ << " XML file" << std::endl);
+ this->LogFile = CM_NULLPTR;
+ return 1;
+ }
+ cmXMLWriter xml(xmlfile);
+ this->GenerateDartOutput(xml);
+ }
+
+ if (!this->PostProcessHandler()) {
+ this->LogFile = CM_NULLPTR;
+ return -1;
+ }
+
+ if (!failed.empty()) {
+ this->LogFile = CM_NULLPTR;
+ return -1;
+ }
+ this->LogFile = CM_NULLPTR;
+ return 0;
+}
+
+void cmCTestTestHandler::PrintLabelSummary()
+{
+ cmCTestTestHandler::ListOfTests::iterator it = this->TestList.begin();
+ std::map<std::string, double> labelTimes;
+ std::map<std::string, int> labelCounts;
+ std::set<std::string> labels;
+ // initialize maps
+ std::string::size_type maxlen = 0;
+ for (; it != this->TestList.end(); ++it) {
+ cmCTestTestProperties& p = *it;
+ if (!p.Labels.empty()) {
+ for (std::vector<std::string>::iterator l = p.Labels.begin();
+ l != p.Labels.end(); ++l) {
+ if ((*l).size() > maxlen) {
+ maxlen = (*l).size();
+ }
+ labels.insert(*l);
+ labelTimes[*l] = 0;
+ labelCounts[*l] = 0;
+ }
+ }
+ }
+ cmCTestTestHandler::TestResultsVector::iterator ri =
+ this->TestResults.begin();
+ // fill maps
+ for (; ri != this->TestResults.end(); ++ri) {
+ cmCTestTestResult& result = *ri;
+ cmCTestTestProperties& p = *result.Properties;
+ if (!p.Labels.empty()) {
+ for (std::vector<std::string>::iterator l = p.Labels.begin();
+ l != p.Labels.end(); ++l) {
+ labelTimes[*l] += result.ExecutionTime;
+ ++labelCounts[*l];
+ }
+ }
+ }
+ // now print times
+ if (!labels.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "\nLabel Time Summary:",
+ this->Quiet);
+ }
+ for (std::set<std::string>::const_iterator i = labels.begin();
+ i != labels.end(); ++i) {
+ std::string label = *i;
+ label.resize(maxlen + 3, ' ');
+
+ char buf[1024];
+ sprintf(buf, "%6.2f sec", labelTimes[*i]);
+
+ std::ostringstream labelCountStr;
+ labelCountStr << "(" << labelCounts[*i] << " test";
+ if (labelCounts[*i] > 1) {
+ labelCountStr << "s";
+ }
+ labelCountStr << ")";
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "\n"
+ << label << " = " << buf << " "
+ << labelCountStr.str(),
+ this->Quiet);
+ if (this->LogFile) {
+ *this->LogFile << "\n" << *i << " = " << buf << "\n";
+ }
+ }
+ if (!labels.empty()) {
+ if (this->LogFile) {
+ *this->LogFile << "\n";
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "\n", this->Quiet);
+ }
+}
+
+void cmCTestTestHandler::CheckLabelFilterInclude(cmCTestTestProperties& it)
+{
+ // if not using Labels to filter then return
+ if (!this->UseIncludeLabelRegExpFlag) {
+ return;
+ }
+ // if there are no labels and we are filtering by labels
+ // then exclude the test as it does not have the label
+ if (it.Labels.empty()) {
+ it.IsInBasedOnREOptions = false;
+ return;
+ }
+ // check to see if the label regular expression matches
+ bool found = false; // assume it does not match
+ // loop over all labels and look for match
+ for (std::vector<std::string>::iterator l = it.Labels.begin();
+ l != it.Labels.end(); ++l) {
+ if (this->IncludeLabelRegularExpression.find(*l)) {
+ found = true;
+ }
+ }
+ // if no match was found, exclude the test
+ if (!found) {
+ it.IsInBasedOnREOptions = false;
+ }
+}
+
+void cmCTestTestHandler::CheckLabelFilterExclude(cmCTestTestProperties& it)
+{
+ // if not using Labels to filter then return
+ if (!this->UseExcludeLabelRegExpFlag) {
+ return;
+ }
+ // if there are no labels and we are excluding by labels
+ // then do nothing as a no label can not be a match
+ if (it.Labels.empty()) {
+ return;
+ }
+ // check to see if the label regular expression matches
+ bool found = false; // assume it does not match
+ // loop over all labels and look for match
+ for (std::vector<std::string>::iterator l = it.Labels.begin();
+ l != it.Labels.end(); ++l) {
+ if (this->ExcludeLabelRegularExpression.find(*l)) {
+ found = true;
+ }
+ }
+ // if match was found, exclude the test
+ if (found) {
+ it.IsInBasedOnREOptions = false;
+ }
+}
+
+void cmCTestTestHandler::CheckLabelFilter(cmCTestTestProperties& it)
+{
+ this->CheckLabelFilterInclude(it);
+ this->CheckLabelFilterExclude(it);
+}
+
+void cmCTestTestHandler::ComputeTestList()
+{
+ this->TestList.clear(); // clear list of test
+ this->GetListOfTests();
+
+ if (this->RerunFailed) {
+ this->ComputeTestListForRerunFailed();
+ return;
+ }
+
+ cmCTestTestHandler::ListOfTests::size_type tmsize = this->TestList.size();
+ // how many tests are in based on RegExp?
+ int inREcnt = 0;
+ cmCTestTestHandler::ListOfTests::iterator it;
+ for (it = this->TestList.begin(); it != this->TestList.end(); it++) {
+ this->CheckLabelFilter(*it);
+ if (it->IsInBasedOnREOptions) {
+ inREcnt++;
+ }
+ }
+ // expand the test list based on the union flag
+ if (this->UseUnion) {
+ this->ExpandTestsToRunInformation((int)tmsize);
+ } else {
+ this->ExpandTestsToRunInformation(inREcnt);
+ }
+ // Now create a final list of tests to run
+ int cnt = 0;
+ inREcnt = 0;
+ std::string last_directory = "";
+ ListOfTests finalList;
+ for (it = this->TestList.begin(); it != this->TestList.end(); it++) {
+ cnt++;
+ if (it->IsInBasedOnREOptions) {
+ inREcnt++;
+ }
+
+ if (this->UseUnion) {
+ // if it is not in the list and not in the regexp then skip
+ if ((!this->TestsToRun.empty() &&
+ std::find(this->TestsToRun.begin(), this->TestsToRun.end(), cnt) ==
+ this->TestsToRun.end()) &&
+ !it->IsInBasedOnREOptions) {
+ continue;
+ }
+ } else {
+ // is this test in the list of tests to run? If not then skip it
+ if ((!this->TestsToRun.empty() &&
+ std::find(this->TestsToRun.begin(), this->TestsToRun.end(),
+ inREcnt) == this->TestsToRun.end()) ||
+ !it->IsInBasedOnREOptions) {
+ continue;
+ }
+ }
+ it->Index = cnt; // save the index into the test list for this test
+ finalList.push_back(*it);
+ }
+ // Save the total number of tests before exclusions
+ this->TotalNumberOfTests = this->TestList.size();
+ // Set the TestList to the final list of all test
+ this->TestList = finalList;
+
+ this->UpdateMaxTestNameWidth();
+}
+
+void cmCTestTestHandler::ComputeTestListForRerunFailed()
+{
+ this->ExpandTestsToRunInformationForRerunFailed();
+
+ cmCTestTestHandler::ListOfTests::iterator it;
+ ListOfTests finalList;
+ int cnt = 0;
+ for (it = this->TestList.begin(); it != this->TestList.end(); it++) {
+ cnt++;
+
+ // if this test is not in our list of tests to run, then skip it.
+ if ((!this->TestsToRun.empty() &&
+ std::find(this->TestsToRun.begin(), this->TestsToRun.end(), cnt) ==
+ this->TestsToRun.end())) {
+ continue;
+ }
+
+ it->Index = cnt;
+ finalList.push_back(*it);
+ }
+
+ // Save the total number of tests before exclusions
+ this->TotalNumberOfTests = this->TestList.size();
+
+ // Set the TestList to the list of failed tests to rerun
+ this->TestList = finalList;
+
+ this->UpdateMaxTestNameWidth();
+}
+
+void cmCTestTestHandler::UpdateMaxTestNameWidth()
+{
+ std::string::size_type max = this->CTest->GetMaxTestNameWidth();
+ for (cmCTestTestHandler::ListOfTests::iterator it = this->TestList.begin();
+ it != this->TestList.end(); it++) {
+ cmCTestTestProperties& p = *it;
+ if (max < p.Name.size()) {
+ max = p.Name.size();
+ }
+ }
+ if (static_cast<std::string::size_type>(
+ this->CTest->GetMaxTestNameWidth()) != max) {
+ this->CTest->SetMaxTestNameWidth(static_cast<int>(max));
+ }
+}
+
+bool cmCTestTestHandler::GetValue(const char* tag, int& value,
+ std::istream& fin)
+{
+ std::string line;
+ bool ret = true;
+ cmSystemTools::GetLineFromStream(fin, line);
+ if (line == tag) {
+ fin >> value;
+ ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "parse error: missing tag: "
+ << tag << " found [" << line << "]" << std::endl);
+ ret = false;
+ }
+ return ret;
+}
+
+bool cmCTestTestHandler::GetValue(const char* tag, double& value,
+ std::istream& fin)
+{
+ std::string line;
+ cmSystemTools::GetLineFromStream(fin, line);
+ bool ret = true;
+ if (line == tag) {
+ fin >> value;
+ ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "parse error: missing tag: "
+ << tag << " found [" << line << "]" << std::endl);
+ ret = false;
+ }
+ return ret;
+}
+
+bool cmCTestTestHandler::GetValue(const char* tag, bool& value,
+ std::istream& fin)
+{
+ std::string line;
+ cmSystemTools::GetLineFromStream(fin, line);
+ bool ret = true;
+ if (line == tag) {
+#ifdef __HAIKU__
+ int tmp = 0;
+ fin >> tmp;
+ value = false;
+ if (tmp) {
+ value = true;
+ }
+#else
+ fin >> value;
+#endif
+ ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "parse error: missing tag: "
+ << tag << " found [" << line << "]" << std::endl);
+ ret = false;
+ }
+ return ret;
+}
+
+bool cmCTestTestHandler::GetValue(const char* tag, size_t& value,
+ std::istream& fin)
+{
+ std::string line;
+ cmSystemTools::GetLineFromStream(fin, line);
+ bool ret = true;
+ if (line == tag) {
+ fin >> value;
+ ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "parse error: missing tag: "
+ << tag << " found [" << line << "]" << std::endl);
+ ret = false;
+ }
+ return ret;
+}
+
+bool cmCTestTestHandler::GetValue(const char* tag, std::string& value,
+ std::istream& fin)
+{
+ std::string line;
+ cmSystemTools::GetLineFromStream(fin, line);
+ bool ret = true;
+ if (line == tag) {
+ ret = cmSystemTools::GetLineFromStream(fin, value);
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "parse error: missing tag: "
+ << tag << " found [" << line << "]" << std::endl);
+ ret = false;
+ }
+ return ret;
+}
+
+void cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed,
+ std::vector<std::string>& failed)
+{
+ this->ComputeTestList();
+ this->StartTest = this->CTest->CurrentTime();
+ this->StartTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
+ double elapsed_time_start = cmSystemTools::GetTime();
+
+ cmCTestMultiProcessHandler* parallel = this->CTest->GetBatchJobs()
+ ? new cmCTestBatchTestHandler
+ : new cmCTestMultiProcessHandler;
+ parallel->SetCTest(this->CTest);
+ parallel->SetParallelLevel(this->CTest->GetParallelLevel());
+ parallel->SetTestHandler(this);
+ parallel->SetQuiet(this->Quiet);
+ if (this->TestLoad > 0) {
+ parallel->SetTestLoad(this->TestLoad);
+ } else {
+ parallel->SetTestLoad(this->CTest->GetTestLoad());
+ }
+
+ *this->LogFile
+ << "Start testing: " << this->CTest->CurrentTime() << std::endl
+ << "----------------------------------------------------------"
+ << std::endl;
+
+ cmCTestMultiProcessHandler::TestMap tests;
+ cmCTestMultiProcessHandler::PropertiesMap properties;
+
+ bool randomSchedule = this->CTest->GetScheduleType() == "Random";
+ if (randomSchedule) {
+ srand((unsigned)time(CM_NULLPTR));
+ }
+
+ for (ListOfTests::iterator it = this->TestList.begin();
+ it != this->TestList.end(); ++it) {
+ cmCTestTestProperties& p = *it;
+ cmCTestMultiProcessHandler::TestSet depends;
+
+ if (randomSchedule) {
+ p.Cost = static_cast<float>(rand());
+ }
+
+ if (p.Timeout == 0 && this->CTest->GetGlobalTimeout() != 0) {
+ p.Timeout = this->CTest->GetGlobalTimeout();
+ }
+
+ if (!p.Depends.empty()) {
+ for (std::vector<std::string>::iterator i = p.Depends.begin();
+ i != p.Depends.end(); ++i) {
+ for (ListOfTests::iterator it2 = this->TestList.begin();
+ it2 != this->TestList.end(); ++it2) {
+ if (it2->Name == *i) {
+ depends.insert(it2->Index);
+ break; // break out of test loop as name can only match 1
+ }
+ }
+ }
+ }
+ tests[it->Index] = depends;
+ properties[it->Index] = &*it;
+ }
+ parallel->SetTests(tests, properties);
+ parallel->SetPassFailVectors(&passed, &failed);
+ this->TestResults.clear();
+ parallel->SetTestResults(&this->TestResults);
+
+ if (this->CTest->ShouldPrintLabels()) {
+ parallel->PrintLabels();
+ } else if (this->CTest->GetShowOnly()) {
+ parallel->PrintTestList();
+ } else {
+ parallel->RunTests();
+ }
+ delete parallel;
+ this->EndTest = this->CTest->CurrentTime();
+ this->EndTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
+ this->ElapsedTestingTime = cmSystemTools::GetTime() - elapsed_time_start;
+ *this->LogFile << "End testing: " << this->CTest->CurrentTime() << std::endl;
+}
+
+void cmCTestTestHandler::GenerateTestCommand(std::vector<std::string>&, int)
+{
+}
+
+void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml)
+{
+ if (!this->CTest->GetProduceXML()) {
+ return;
+ }
+
+ this->CTest->StartXML(xml, this->AppendXML);
+ xml.StartElement("Testing");
+ xml.Element("StartDateTime", this->StartTest);
+ xml.Element("StartTestTime", this->StartTestTime);
+ xml.StartElement("TestList");
+ cmCTestTestHandler::TestResultsVector::size_type cc;
+ for (cc = 0; cc < this->TestResults.size(); cc++) {
+ cmCTestTestResult* result = &this->TestResults[cc];
+ std::string testPath = result->Path + "/" + result->Name;
+ xml.Element("Test", this->CTest->GetShortPathToFile(testPath.c_str()));
+ }
+ xml.EndElement(); // TestList
+ for (cc = 0; cc < this->TestResults.size(); cc++) {
+ cmCTestTestResult* result = &this->TestResults[cc];
+ this->WriteTestResultHeader(xml, result);
+ xml.StartElement("Results");
+ if (result->Status != cmCTestTestHandler::NOT_RUN) {
+ if (result->Status != cmCTestTestHandler::COMPLETED ||
+ result->ReturnValue) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Exit Code");
+ xml.Element("Value", this->GetTestStatus(result->Status));
+ xml.EndElement(); // NamedMeasurement
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Exit Value");
+ xml.Element("Value", result->ReturnValue);
+ xml.EndElement(); // NamedMeasurement
+ }
+ this->GenerateRegressionImages(xml, result->DartString);
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "numeric/double");
+ xml.Attribute("name", "Execution Time");
+ xml.Element("Value", result->ExecutionTime);
+ xml.EndElement(); // NamedMeasurement
+ if (!result->Reason.empty()) {
+ const char* reasonType = "Pass Reason";
+ if (result->Status != cmCTestTestHandler::COMPLETED &&
+ result->Status != cmCTestTestHandler::NOT_RUN) {
+ reasonType = "Fail Reason";
+ }
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", reasonType);
+ xml.Element("Value", result->Reason);
+ xml.EndElement(); // NamedMeasurement
+ }
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Completion Status");
+ xml.Element("Value", result->CompletionStatus);
+ xml.EndElement(); // NamedMeasurement
+ }
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Command Line");
+ xml.Element("Value", result->FullCommandLine);
+ xml.EndElement(); // NamedMeasurement
+ std::map<std::string, std::string>::iterator measureIt;
+ for (measureIt = result->Properties->Measurements.begin();
+ measureIt != result->Properties->Measurements.end(); ++measureIt) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", measureIt->first);
+ xml.Element("Value", measureIt->second);
+ xml.EndElement(); // NamedMeasurement
+ }
+ xml.StartElement("Measurement");
+ xml.StartElement("Value");
+ if (result->CompressOutput) {
+ xml.Attribute("encoding", "base64");
+ xml.Attribute("compression", "gzip");
+ }
+ xml.Content(result->Output);
+ xml.EndElement(); // Value
+ xml.EndElement(); // Measurement
+ xml.EndElement(); // Results
+
+ this->AttachFiles(xml, result);
+ this->WriteTestResultFooter(xml, result);
+ }
+
+ xml.Element("EndDateTime", this->EndTest);
+ xml.Element("EndTestTime", this->EndTestTime);
+ xml.Element("ElapsedMinutes",
+ static_cast<int>(this->ElapsedTestingTime / 6) / 10.0);
+ xml.EndElement(); // Testing
+ this->CTest->EndXML(xml);
+}
+
+void cmCTestTestHandler::WriteTestResultHeader(cmXMLWriter& xml,
+ cmCTestTestResult* result)
+{
+ xml.StartElement("Test");
+ if (result->Status == cmCTestTestHandler::COMPLETED) {
+ xml.Attribute("Status", "passed");
+ } else if (result->Status == cmCTestTestHandler::NOT_RUN) {
+ xml.Attribute("Status", "notrun");
+ } else {
+ xml.Attribute("Status", "failed");
+ }
+ std::string testPath = result->Path + "/" + result->Name;
+ xml.Element("Name", result->Name);
+ xml.Element("Path", this->CTest->GetShortPathToFile(result->Path.c_str()));
+ xml.Element("FullName", this->CTest->GetShortPathToFile(testPath.c_str()));
+ xml.Element("FullCommandLine", result->FullCommandLine);
+}
+
+void cmCTestTestHandler::WriteTestResultFooter(cmXMLWriter& xml,
+ cmCTestTestResult* result)
+{
+ if (!result->Properties->Labels.empty()) {
+ xml.StartElement("Labels");
+ std::vector<std::string> const& labels = result->Properties->Labels;
+ for (std::vector<std::string>::const_iterator li = labels.begin();
+ li != labels.end(); ++li) {
+ xml.Element("Label", *li);
+ }
+ xml.EndElement(); // Labels
+ }
+
+ xml.EndElement(); // Test
+}
+
+void cmCTestTestHandler::AttachFiles(cmXMLWriter& xml,
+ cmCTestTestResult* result)
+{
+ if (result->Status != cmCTestTestHandler::COMPLETED &&
+ !result->Properties->AttachOnFail.empty()) {
+ result->Properties->AttachedFiles.insert(
+ result->Properties->AttachedFiles.end(),
+ result->Properties->AttachOnFail.begin(),
+ result->Properties->AttachOnFail.end());
+ }
+ for (std::vector<std::string>::const_iterator file =
+ result->Properties->AttachedFiles.begin();
+ file != result->Properties->AttachedFiles.end(); ++file) {
+ const std::string& base64 = this->CTest->Base64GzipEncodeFile(*file);
+ std::string fname = cmSystemTools::GetFilenameName(*file);
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("name", "Attached File");
+ xml.Attribute("encoding", "base64");
+ xml.Attribute("compression", "tar/gzip");
+ xml.Attribute("filename", fname);
+ xml.Attribute("type", "file");
+ xml.Element("Value", base64);
+ xml.EndElement(); // NamedMeasurement
+ }
+}
+
+int cmCTestTestHandler::ExecuteCommands(std::vector<std::string>& vec)
+{
+ std::vector<std::string>::iterator it;
+ for (it = vec.begin(); it != vec.end(); ++it) {
+ int retVal = 0;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run command: " << *it << std::endl, this->Quiet);
+ if (!cmSystemTools::RunSingleCommand(it->c_str(), CM_NULLPTR, CM_NULLPTR,
+ &retVal, CM_NULLPTR,
+ cmSystemTools::OUTPUT_MERGE
+ /*this->Verbose*/) ||
+ retVal != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem running command: " << *it << std::endl);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+// Find the appropriate executable to run for a test
+std::string cmCTestTestHandler::FindTheExecutable(const char* exe)
+{
+ std::string resConfig;
+ std::vector<std::string> extraPaths;
+ std::vector<std::string> failedPaths;
+ if (strcmp(exe, "NOT_AVAILABLE") == 0) {
+ return exe;
+ }
+ return cmCTestTestHandler::FindExecutable(this->CTest, exe, resConfig,
+ extraPaths, failedPaths);
+}
+
+// add additional configurations to the search path
+void cmCTestTestHandler::AddConfigurations(
+ cmCTest* ctest, std::vector<std::string>& attempted,
+ std::vector<std::string>& attemptedConfigs, std::string filepath,
+ std::string& filename)
+{
+ std::string tempPath;
+
+ if (!filepath.empty() && filepath[filepath.size() - 1] != '/') {
+ filepath += "/";
+ }
+ tempPath = filepath + filename;
+ attempted.push_back(tempPath);
+ attemptedConfigs.push_back("");
+
+ if (!ctest->GetConfigType().empty()) {
+ tempPath = filepath;
+ tempPath += ctest->GetConfigType();
+ tempPath += "/";
+ tempPath += filename;
+ attempted.push_back(tempPath);
+ attemptedConfigs.push_back(ctest->GetConfigType());
+ // If the file is an OSX bundle then the configtype
+ // will be at the start of the path
+ tempPath = ctest->GetConfigType();
+ tempPath += "/";
+ tempPath += filepath;
+ tempPath += filename;
+ attempted.push_back(tempPath);
+ attemptedConfigs.push_back(ctest->GetConfigType());
+ } else {
+ // no config specified - try some options...
+ tempPath = filepath;
+ tempPath += "Release/";
+ tempPath += filename;
+ attempted.push_back(tempPath);
+ attemptedConfigs.push_back("Release");
+ tempPath = filepath;
+ tempPath += "Debug/";
+ tempPath += filename;
+ attempted.push_back(tempPath);
+ attemptedConfigs.push_back("Debug");
+ tempPath = filepath;
+ tempPath += "MinSizeRel/";
+ tempPath += filename;
+ attempted.push_back(tempPath);
+ attemptedConfigs.push_back("MinSizeRel");
+ tempPath = filepath;
+ tempPath += "RelWithDebInfo/";
+ tempPath += filename;
+ attempted.push_back(tempPath);
+ attemptedConfigs.push_back("RelWithDebInfo");
+ tempPath = filepath;
+ tempPath += "Deployment/";
+ tempPath += filename;
+ attempted.push_back(tempPath);
+ attemptedConfigs.push_back("Deployment");
+ tempPath = filepath;
+ tempPath += "Development/";
+ tempPath += filename;
+ attempted.push_back(tempPath);
+ attemptedConfigs.push_back("Deployment");
+ }
+}
+
+// Find the appropriate executable to run for a test
+std::string cmCTestTestHandler::FindExecutable(
+ cmCTest* ctest, const char* testCommand, std::string& resultingConfig,
+ std::vector<std::string>& extraPaths, std::vector<std::string>& failed)
+{
+ // now run the compiled test if we can find it
+ std::vector<std::string> attempted;
+ std::vector<std::string> attemptedConfigs;
+ std::string tempPath;
+ std::string filepath = cmSystemTools::GetFilenamePath(testCommand);
+ std::string filename = cmSystemTools::GetFilenameName(testCommand);
+
+ cmCTestTestHandler::AddConfigurations(ctest, attempted, attemptedConfigs,
+ filepath, filename);
+
+ // even if a fullpath was specified also try it relative to the current
+ // directory
+ if (!filepath.empty() && filepath[0] == '/') {
+ std::string localfilepath = filepath.substr(1, filepath.size() - 1);
+ cmCTestTestHandler::AddConfigurations(ctest, attempted, attemptedConfigs,
+ localfilepath, filename);
+ }
+
+ // if extraPaths are provided and we were not passed a full path, try them,
+ // try any extra paths
+ if (filepath.empty()) {
+ for (unsigned int i = 0; i < extraPaths.size(); ++i) {
+ std::string filepathExtra =
+ cmSystemTools::GetFilenamePath(extraPaths[i]);
+ std::string filenameExtra =
+ cmSystemTools::GetFilenameName(extraPaths[i]);
+ cmCTestTestHandler::AddConfigurations(ctest, attempted, attemptedConfigs,
+ filepathExtra, filenameExtra);
+ }
+ }
+
+ // store the final location in fullPath
+ std::string fullPath;
+
+ // now look in the paths we specified above
+ for (unsigned int ai = 0; ai < attempted.size() && fullPath.empty(); ++ai) {
+ // first check without exe extension
+ if (cmSystemTools::FileExists(attempted[ai].c_str()) &&
+ !cmSystemTools::FileIsDirectory(attempted[ai])) {
+ fullPath = cmSystemTools::CollapseFullPath(attempted[ai]);
+ resultingConfig = attemptedConfigs[ai];
+ }
+ // then try with the exe extension
+ else {
+ failed.push_back(attempted[ai]);
+ tempPath = attempted[ai];
+ tempPath += cmSystemTools::GetExecutableExtension();
+ if (cmSystemTools::FileExists(tempPath.c_str()) &&
+ !cmSystemTools::FileIsDirectory(tempPath)) {
+ fullPath = cmSystemTools::CollapseFullPath(tempPath);
+ resultingConfig = attemptedConfigs[ai];
+ } else {
+ failed.push_back(tempPath);
+ }
+ }
+ }
+
+ // if everything else failed, check the users path, but only if a full path
+ // wasn't specified
+ if (fullPath.empty() && filepath.empty()) {
+ std::string path = cmSystemTools::FindProgram(filename.c_str());
+ if (path != "") {
+ resultingConfig = "";
+ return path;
+ }
+ }
+ if (fullPath.empty()) {
+ cmCTestLog(ctest, HANDLER_OUTPUT, "Could not find executable "
+ << testCommand << "\n"
+ << "Looked in the following places:\n");
+ for (std::vector<std::string>::iterator i = failed.begin();
+ i != failed.end(); ++i) {
+ cmCTestLog(ctest, HANDLER_OUTPUT, *i << "\n");
+ }
+ }
+
+ return fullPath;
+}
+
+void cmCTestTestHandler::GetListOfTests()
+{
+ if (!this->IncludeLabelRegExp.empty()) {
+ this->IncludeLabelRegularExpression.compile(
+ this->IncludeLabelRegExp.c_str());
+ }
+ if (!this->ExcludeLabelRegExp.empty()) {
+ this->ExcludeLabelRegularExpression.compile(
+ this->ExcludeLabelRegExp.c_str());
+ }
+ if (!this->IncludeRegExp.empty()) {
+ this->IncludeTestsRegularExpression.compile(this->IncludeRegExp.c_str());
+ }
+ if (!this->ExcludeRegExp.empty()) {
+ this->ExcludeTestsRegularExpression.compile(this->ExcludeRegExp.c_str());
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Constructing a list of tests" << std::endl, this->Quiet);
+ cmake cm;
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator gg(&cm);
+ CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(&gg, cm.GetCurrentSnapshot()));
+ mf->AddDefinition("CTEST_CONFIGURATION_TYPE",
+ this->CTest->GetConfigType().c_str());
+
+ // Add handler for ADD_TEST
+ cmCTestAddTestCommand* newCom1 = new cmCTestAddTestCommand;
+ newCom1->TestHandler = this;
+ cm.GetState()->AddCommand(newCom1);
+
+ // Add handler for SUBDIRS
+ cmCTestSubdirCommand* newCom2 = new cmCTestSubdirCommand;
+ newCom2->TestHandler = this;
+ cm.GetState()->AddCommand(newCom2);
+
+ // Add handler for ADD_SUBDIRECTORY
+ cmCTestAddSubdirectoryCommand* newCom3 = new cmCTestAddSubdirectoryCommand;
+ newCom3->TestHandler = this;
+ cm.GetState()->AddCommand(newCom3);
+
+ // Add handler for SET_SOURCE_FILES_PROPERTIES
+ cmCTestSetTestsPropertiesCommand* newCom4 =
+ new cmCTestSetTestsPropertiesCommand;
+ newCom4->TestHandler = this;
+ cm.GetState()->AddCommand(newCom4);
+
+ const char* testFilename;
+ if (cmSystemTools::FileExists("CTestTestfile.cmake")) {
+ // does the CTestTestfile.cmake exist ?
+ testFilename = "CTestTestfile.cmake";
+ } else if (cmSystemTools::FileExists("DartTestfile.txt")) {
+ // does the DartTestfile.txt exist ?
+ testFilename = "DartTestfile.txt";
+ } else {
+ return;
+ }
+
+ if (!mf->ReadListFile(testFilename)) {
+ return;
+ }
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Done constructing a list of tests" << std::endl,
+ this->Quiet);
+}
+
+void cmCTestTestHandler::UseIncludeRegExp()
+{
+ this->UseIncludeRegExpFlag = true;
+}
+
+void cmCTestTestHandler::UseExcludeRegExp()
+{
+ this->UseExcludeRegExpFlag = true;
+ this->UseExcludeRegExpFirst = !this->UseIncludeRegExpFlag;
+}
+
+const char* cmCTestTestHandler::GetTestStatus(int status)
+{
+ static const char statuses[][100] = {
+ "Not Run", "Timeout", "SEGFAULT", "ILLEGAL", "INTERRUPT",
+ "NUMERICAL", "OTHER_FAULT", "Failed", "BAD_COMMAND", "Completed"
+ };
+
+ if (status < cmCTestTestHandler::NOT_RUN ||
+ status > cmCTestTestHandler::COMPLETED) {
+ return "No Status";
+ }
+ return statuses[status];
+}
+
+void cmCTestTestHandler::ExpandTestsToRunInformation(size_t numTests)
+{
+ if (this->TestsToRunString.empty()) {
+ return;
+ }
+
+ int start;
+ int end = -1;
+ double stride = -1;
+ std::string::size_type pos = 0;
+ std::string::size_type pos2;
+ // read start
+ if (GetNextNumber(this->TestsToRunString, start, pos, pos2)) {
+ // read end
+ if (GetNextNumber(this->TestsToRunString, end, pos, pos2)) {
+ // read stride
+ if (GetNextRealNumber(this->TestsToRunString, stride, pos, pos2)) {
+ int val = 0;
+ // now read specific numbers
+ while (GetNextNumber(this->TestsToRunString, val, pos, pos2)) {
+ this->TestsToRun.push_back(val);
+ }
+ this->TestsToRun.push_back(val);
+ }
+ }
+ }
+
+ // if start is not specified then we assume we start at 1
+ if (start == -1) {
+ start = 1;
+ }
+
+ // if end isnot specified then we assume we end with the last test
+ if (end == -1) {
+ end = static_cast<int>(numTests);
+ }
+
+ // if the stride wasn't specified then it defaults to 1
+ if (stride == -1) {
+ stride = 1;
+ }
+
+ // if we have a range then add it
+ if (end != -1 && start != -1 && stride > 0) {
+ int i = 0;
+ while (i * stride + start <= end) {
+ this->TestsToRun.push_back(static_cast<int>(i * stride + start));
+ ++i;
+ }
+ }
+
+ // sort the array
+ std::sort(this->TestsToRun.begin(), this->TestsToRun.end(),
+ std::less<int>());
+ // remove duplicates
+ std::vector<int>::iterator new_end =
+ std::unique(this->TestsToRun.begin(), this->TestsToRun.end());
+ this->TestsToRun.erase(new_end, this->TestsToRun.end());
+}
+
+void cmCTestTestHandler::ExpandTestsToRunInformationForRerunFailed()
+{
+
+ std::string dirName = this->CTest->GetBinaryDir() + "/Testing/Temporary";
+
+ cmsys::Directory directory;
+ if (directory.Load(dirName) == 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to read the contents of "
+ << dirName << std::endl);
+ return;
+ }
+
+ int numFiles =
+ static_cast<int>(cmsys::Directory::GetNumberOfFilesInDirectory(dirName));
+ std::string pattern = "LastTestsFailed";
+ std::string logName = "";
+
+ for (int i = 0; i < numFiles; ++i) {
+ std::string fileName = directory.GetFile(i);
+ // bcc crashes if we attempt a normal substring comparison,
+ // hence the following workaround
+ std::string fileNameSubstring = fileName.substr(0, pattern.length());
+ if (fileNameSubstring.compare(pattern) != 0) {
+ continue;
+ }
+ if (logName == "") {
+ logName = fileName;
+ } else {
+ // if multiple matching logs were found we use the most recently
+ // modified one.
+ int res;
+ cmSystemTools::FileTimeCompare(logName, fileName, &res);
+ if (res == -1) {
+ logName = fileName;
+ }
+ }
+ }
+
+ std::string lastTestsFailedLog =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/" + logName;
+
+ if (!cmSystemTools::FileExists(lastTestsFailedLog.c_str())) {
+ if (!this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, lastTestsFailedLog
+ << " does not exist!" << std::endl);
+ }
+ return;
+ }
+
+ // parse the list of tests to rerun from LastTestsFailed.log
+ cmsys::ifstream ifs(lastTestsFailedLog.c_str());
+ if (ifs) {
+ std::string line;
+ std::string::size_type pos;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ pos = line.find(':', 0);
+ if (pos == line.npos) {
+ continue;
+ }
+
+ int val = atoi(line.substr(0, pos).c_str());
+ this->TestsToRun.push_back(val);
+ }
+ ifs.close();
+ } else if (!this->CTest->GetShowOnly() &&
+ !this->CTest->ShouldPrintLabels()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem reading file: "
+ << lastTestsFailedLog
+ << " while generating list of previously failed tests."
+ << std::endl);
+ }
+}
+
+// Just for convenience
+#define SPACE_REGEX "[ \t\r\n]"
+void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml,
+ const std::string& dart)
+{
+ cmsys::RegularExpression twoattributes(
+ "<DartMeasurement" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>([^<]*)</DartMeasurement>");
+ cmsys::RegularExpression threeattributes(
+ "<DartMeasurement" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>([^<]*)</DartMeasurement>");
+ cmsys::RegularExpression fourattributes(
+ "<DartMeasurement" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>([^<]*)</DartMeasurement>");
+ cmsys::RegularExpression cdatastart(
+ "<DartMeasurement" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>" SPACE_REGEX "*<!\\[CDATA\\[");
+ cmsys::RegularExpression cdataend("]]>" SPACE_REGEX "*</DartMeasurement>");
+ cmsys::RegularExpression measurementfile(
+ "<DartMeasurementFile" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>([^<]*)</DartMeasurementFile>");
+
+ bool done = false;
+ std::string cxml = dart;
+ while (!done) {
+ if (twoattributes.find(cxml)) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(twoattributes.match(1).c_str(), twoattributes.match(2));
+ xml.Attribute(twoattributes.match(3).c_str(), twoattributes.match(4));
+ xml.Element("Value", twoattributes.match(5));
+ xml.EndElement();
+ cxml.erase(twoattributes.start(),
+ twoattributes.end() - twoattributes.start());
+ } else if (threeattributes.find(cxml)) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(threeattributes.match(1).c_str(),
+ threeattributes.match(2));
+ xml.Attribute(threeattributes.match(3).c_str(),
+ threeattributes.match(4));
+ xml.Attribute(threeattributes.match(5).c_str(),
+ threeattributes.match(6));
+ xml.Element("Value", twoattributes.match(7));
+ xml.EndElement();
+ cxml.erase(threeattributes.start(),
+ threeattributes.end() - threeattributes.start());
+ } else if (fourattributes.find(cxml)) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(fourattributes.match(1).c_str(), fourattributes.match(2));
+ xml.Attribute(fourattributes.match(3).c_str(), fourattributes.match(4));
+ xml.Attribute(fourattributes.match(5).c_str(), fourattributes.match(6));
+ xml.Attribute(fourattributes.match(7).c_str(), fourattributes.match(8));
+ xml.Element("Value", twoattributes.match(9));
+ xml.EndElement();
+ cxml.erase(fourattributes.start(),
+ fourattributes.end() - fourattributes.start());
+ } else if (cdatastart.find(cxml) && cdataend.find(cxml)) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(cdatastart.match(1).c_str(), cdatastart.match(2));
+ xml.Attribute(cdatastart.match(3).c_str(), cdatastart.match(4));
+ xml.StartElement("Value");
+ xml.CData(
+ cxml.substr(cdatastart.end(), cdataend.start() - cdatastart.end()));
+ xml.EndElement(); // Value
+ xml.EndElement(); // NamedMeasurement
+ cxml.erase(cdatastart.start(), cdataend.end() - cdatastart.start());
+ } else if (measurementfile.find(cxml)) {
+ const std::string& filename =
+ cmCTest::CleanString(measurementfile.match(5));
+ if (cmSystemTools::FileExists(filename.c_str())) {
+ long len = cmSystemTools::FileLength(filename);
+ if (len == 0) {
+ std::string k1 = measurementfile.match(1);
+ std::string v1 = measurementfile.match(2);
+ std::string k2 = measurementfile.match(3);
+ std::string v2 = measurementfile.match(4);
+ if (cmSystemTools::LowerCase(k1) == "type") {
+ v1 = "text/string";
+ }
+ if (cmSystemTools::LowerCase(k2) == "type") {
+ v2 = "text/string";
+ }
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(k1.c_str(), v1);
+ xml.Attribute(k2.c_str(), v2);
+ xml.Attribute("encoding", "none");
+ xml.Element("Value", "Image " + filename + " is empty");
+ xml.EndElement();
+ } else {
+ cmsys::ifstream ifs(filename.c_str(), std::ios::in
+#ifdef _WIN32
+ | std::ios::binary
+#endif
+ );
+ unsigned char* file_buffer = new unsigned char[len + 1];
+ ifs.read(reinterpret_cast<char*>(file_buffer), len);
+ unsigned char* encoded_buffer = new unsigned char[static_cast<int>(
+ static_cast<double>(len) * 1.5 + 5.0)];
+
+ size_t rlen =
+ cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1);
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(measurementfile.match(1).c_str(),
+ measurementfile.match(2));
+ xml.Attribute(measurementfile.match(3).c_str(),
+ measurementfile.match(4));
+ xml.Attribute("encoding", "base64");
+ std::ostringstream ostr;
+ for (size_t cc = 0; cc < rlen; cc++) {
+ ostr << encoded_buffer[cc];
+ if (cc % 60 == 0 && cc) {
+ ostr << std::endl;
+ }
+ }
+ xml.Element("Value", ostr.str());
+ xml.EndElement(); // NamedMeasurement
+ delete[] file_buffer;
+ delete[] encoded_buffer;
+ }
+ } else {
+ int idx = 4;
+ if (measurementfile.match(1) == "name") {
+ idx = 2;
+ }
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("name", measurementfile.match(idx));
+ xml.Attribute("text", "text/string");
+ xml.Element("Value", "File " + filename + " not found");
+ xml.EndElement();
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "File \""
+ << filename << "\" not found." << std::endl,
+ this->Quiet);
+ }
+ cxml.erase(measurementfile.start(),
+ measurementfile.end() - measurementfile.start());
+ } else {
+ done = true;
+ }
+ }
+}
+
+void cmCTestTestHandler::SetIncludeRegExp(const char* arg)
+{
+ this->IncludeRegExp = arg;
+}
+
+void cmCTestTestHandler::SetExcludeRegExp(const char* arg)
+{
+ this->ExcludeRegExp = arg;
+}
+
+void cmCTestTestHandler::SetTestsToRunInformation(const char* in)
+{
+ if (!in) {
+ return;
+ }
+ this->TestsToRunString = in;
+ // if the argument is a file, then read it and use the contents as the
+ // string
+ if (cmSystemTools::FileExists(in)) {
+ cmsys::ifstream fin(in);
+ unsigned long filelen = cmSystemTools::FileLength(in);
+ char* buff = new char[filelen + 1];
+ fin.getline(buff, filelen);
+ buff[fin.gcount()] = 0;
+ this->TestsToRunString = buff;
+ delete[] buff;
+ }
+}
+
+bool cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length)
+{
+ if (!length || length >= output.size() ||
+ output.find("CTEST_FULL_OUTPUT") != output.npos) {
+ return true;
+ }
+
+ // Truncate at given length but do not break in the middle of a multi-byte
+ // UTF-8 encoding.
+ char const* const begin = output.c_str();
+ char const* const end = begin + output.size();
+ char const* const truncate = begin + length;
+ char const* current = begin;
+ while (current < truncate) {
+ unsigned int ch;
+ if (const char* next = cm_utf8_decode_character(current, end, &ch)) {
+ if (next > truncate) {
+ break;
+ }
+ current = next;
+ } else // Bad byte will be handled by cmXMLWriter.
+ {
+ ++current;
+ }
+ }
+ output = output.substr(0, current - begin);
+
+ // Append truncation message.
+ std::ostringstream msg;
+ msg << "...\n"
+ "The rest of the test output was removed since it exceeds the "
+ "threshold "
+ "of "
+ << length << " bytes.\n";
+ output += msg.str();
+ return true;
+}
+
+bool cmCTestTestHandler::SetTestsProperties(
+ const std::vector<std::string>& args)
+{
+ std::vector<std::string>::const_iterator it;
+ std::vector<std::string> tests;
+ bool found = false;
+ for (it = args.begin(); it != args.end(); ++it) {
+ if (*it == "PROPERTIES") {
+ found = true;
+ break;
+ }
+ tests.push_back(*it);
+ }
+ if (!found) {
+ return false;
+ }
+ ++it; // skip PROPERTIES
+ for (; it != args.end(); ++it) {
+ std::string key = *it;
+ ++it;
+ if (it == args.end()) {
+ break;
+ }
+ std::string val = *it;
+ std::vector<std::string>::const_iterator tit;
+ for (tit = tests.begin(); tit != tests.end(); ++tit) {
+ cmCTestTestHandler::ListOfTests::iterator rtit;
+ for (rtit = this->TestList.begin(); rtit != this->TestList.end();
+ ++rtit) {
+ if (*tit == rtit->Name) {
+ if (key == "WILL_FAIL") {
+ rtit->WillFail = cmSystemTools::IsOn(val.c_str());
+ }
+ if (key == "ATTACHED_FILES") {
+ cmSystemTools::ExpandListArgument(val, rtit->AttachedFiles);
+ }
+ if (key == "ATTACHED_FILES_ON_FAIL") {
+ cmSystemTools::ExpandListArgument(val, rtit->AttachOnFail);
+ }
+ if (key == "RESOURCE_LOCK") {
+ std::vector<std::string> lval;
+ cmSystemTools::ExpandListArgument(val, lval);
+
+ rtit->LockedResources.insert(lval.begin(), lval.end());
+ }
+ if (key == "TIMEOUT") {
+ rtit->Timeout = atof(val.c_str());
+ rtit->ExplicitTimeout = true;
+ }
+ if (key == "COST") {
+ rtit->Cost = static_cast<float>(atof(val.c_str()));
+ }
+ if (key == "REQUIRED_FILES") {
+ cmSystemTools::ExpandListArgument(val, rtit->RequiredFiles);
+ }
+ if (key == "RUN_SERIAL") {
+ rtit->RunSerial = cmSystemTools::IsOn(val.c_str());
+ }
+ if (key == "FAIL_REGULAR_EXPRESSION") {
+ std::vector<std::string> lval;
+ cmSystemTools::ExpandListArgument(val, lval);
+ std::vector<std::string>::iterator crit;
+ for (crit = lval.begin(); crit != lval.end(); ++crit) {
+ rtit->ErrorRegularExpressions.push_back(
+ std::pair<cmsys::RegularExpression, std::string>(
+ cmsys::RegularExpression(crit->c_str()),
+ std::string(*crit)));
+ }
+ }
+ if (key == "PROCESSORS") {
+ rtit->Processors = atoi(val.c_str());
+ if (rtit->Processors < 1) {
+ rtit->Processors = 1;
+ }
+ }
+ if (key == "SKIP_RETURN_CODE") {
+ rtit->SkipReturnCode = atoi(val.c_str());
+ if (rtit->SkipReturnCode < 0 || rtit->SkipReturnCode > 255) {
+ rtit->SkipReturnCode = -1;
+ }
+ }
+ if (key == "DEPENDS") {
+ cmSystemTools::ExpandListArgument(val, rtit->Depends);
+ }
+ if (key == "ENVIRONMENT") {
+ cmSystemTools::ExpandListArgument(val, rtit->Environment);
+ }
+ if (key == "LABELS") {
+ cmSystemTools::ExpandListArgument(val, rtit->Labels);
+ }
+ if (key == "MEASUREMENT") {
+ size_t pos = val.find_first_of('=');
+ if (pos != val.npos) {
+ std::string mKey = val.substr(0, pos);
+ const char* mVal = val.c_str() + pos + 1;
+ rtit->Measurements[mKey] = mVal;
+ } else {
+ rtit->Measurements[val] = "1";
+ }
+ }
+ if (key == "PASS_REGULAR_EXPRESSION") {
+ std::vector<std::string> lval;
+ cmSystemTools::ExpandListArgument(val, lval);
+ std::vector<std::string>::iterator crit;
+ for (crit = lval.begin(); crit != lval.end(); ++crit) {
+ rtit->RequiredRegularExpressions.push_back(
+ std::pair<cmsys::RegularExpression, std::string>(
+ cmsys::RegularExpression(crit->c_str()),
+ std::string(*crit)));
+ }
+ }
+ if (key == "WORKING_DIRECTORY") {
+ rtit->Directory = val;
+ }
+ if (key == "TIMEOUT_AFTER_MATCH") {
+ std::vector<std::string> propArgs;
+ cmSystemTools::ExpandListArgument(val, propArgs);
+ if (propArgs.size() != 2) {
+ cmCTestLog(this->CTest, WARNING,
+ "TIMEOUT_AFTER_MATCH expects two arguments, found "
+ << propArgs.size() << std::endl);
+ } else {
+ rtit->AlternateTimeout = atof(propArgs[0].c_str());
+ std::vector<std::string> lval;
+ cmSystemTools::ExpandListArgument(propArgs[1], lval);
+ std::vector<std::string>::iterator crit;
+ for (crit = lval.begin(); crit != lval.end(); ++crit) {
+ rtit->TimeoutRegularExpressions.push_back(
+ std::pair<cmsys::RegularExpression, std::string>(
+ cmsys::RegularExpression(crit->c_str()),
+ std::string(*crit)));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args)
+{
+ const std::string& testname = args[0];
+ cmCTestOptionalLog(this->CTest, DEBUG, "Add test: " << args[0] << std::endl,
+ this->Quiet);
+
+ if (this->UseExcludeRegExpFlag && this->UseExcludeRegExpFirst &&
+ this->ExcludeTestsRegularExpression.find(testname.c_str())) {
+ return true;
+ }
+ if (this->MemCheck) {
+ std::vector<std::string>::iterator it;
+ bool found = false;
+ for (it = this->CustomTestsIgnore.begin();
+ it != this->CustomTestsIgnore.end(); ++it) {
+ if (*it == testname) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Ignore memcheck: " << *it << std::endl, this->Quiet);
+ return true;
+ }
+ } else {
+ std::vector<std::string>::iterator it;
+ bool found = false;
+ for (it = this->CustomTestsIgnore.begin();
+ it != this->CustomTestsIgnore.end(); ++it) {
+ if (*it == testname) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Ignore test: " << *it << std::endl, this->Quiet);
+ return true;
+ }
+ }
+
+ cmCTestTestProperties test;
+ test.Name = testname;
+ test.Args = args;
+ test.Directory = cmSystemTools::GetCurrentWorkingDirectory();
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Set test directory: " << test.Directory << std::endl,
+ this->Quiet);
+
+ test.IsInBasedOnREOptions = true;
+ test.WillFail = false;
+ test.RunSerial = false;
+ test.Timeout = 0;
+ test.ExplicitTimeout = false;
+ test.Cost = 0;
+ test.Processors = 1;
+ test.SkipReturnCode = -1;
+ test.PreviousRuns = 0;
+ if (this->UseIncludeRegExpFlag &&
+ !this->IncludeTestsRegularExpression.find(testname.c_str())) {
+ test.IsInBasedOnREOptions = false;
+ } else if (this->UseExcludeRegExpFlag && !this->UseExcludeRegExpFirst &&
+ this->ExcludeTestsRegularExpression.find(testname.c_str())) {
+ test.IsInBasedOnREOptions = false;
+ }
+ this->TestList.push_back(test);
+ return true;
+}
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
new file mode 100644
index 0000000..a085a82
--- /dev/null
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -0,0 +1,295 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCTestTestHandler_h
+#define cmCTestTestHandler_h
+
+#include "cmCTestGenericHandler.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+class cmMakefile;
+class cmXMLWriter;
+
+/** \class cmCTestTestHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestTestHandler : public cmCTestGenericHandler
+{
+ friend class cmCTestRunTest;
+ friend class cmCTestMultiProcessHandler;
+ friend class cmCTestBatchTestHandler;
+
+public:
+ cmTypeMacro(cmCTestTestHandler, cmCTestGenericHandler);
+
+ /**
+ * The main entry point for this class
+ */
+ int ProcessHandler() CM_OVERRIDE;
+
+ /**
+ * When both -R and -I are used should te resulting test list be the
+ * intersection or the union of the lists. By default it is the
+ * intersection.
+ */
+ void SetUseUnion(bool val) { this->UseUnion = val; }
+
+ /**
+ * Set whether or not CTest should only execute the tests that failed
+ * on the previous run. By default this is false.
+ */
+ void SetRerunFailed(bool val) { this->RerunFailed = val; }
+
+ /**
+ * This method is called when reading CTest custom file
+ */
+ void PopulateCustomVectors(cmMakefile* mf) CM_OVERRIDE;
+
+ ///! Control the use of the regular expresisons, call these methods to turn
+ /// them on
+ void UseIncludeRegExp();
+ void UseExcludeRegExp();
+ void SetIncludeRegExp(const char*);
+ void SetExcludeRegExp(const char*);
+
+ void SetMaxIndex(int n) { this->MaxIndex = n; }
+ int GetMaxIndex() { return this->MaxIndex; }
+
+ void SetTestOutputSizePassed(int n)
+ {
+ this->CustomMaximumPassedTestOutputSize = n;
+ }
+ void SetTestOutputSizeFailed(int n)
+ {
+ this->CustomMaximumFailedTestOutputSize = n;
+ }
+
+ ///! pass the -I argument down
+ void SetTestsToRunInformation(const char*);
+
+ cmCTestTestHandler();
+
+ /*
+ * Add the test to the list of tests to be executed
+ */
+ bool AddTest(const std::vector<std::string>& args);
+
+ /*
+ * Set tests properties
+ */
+ bool SetTestsProperties(const std::vector<std::string>& args);
+
+ void Initialize() CM_OVERRIDE;
+
+ // NOTE: This struct is Saved/Restored
+ // in cmCTestTestHandler, if you add to this class
+ // then you must add the new members to that code or
+ // ctest -j N will break for that feature
+ struct cmCTestTestProperties
+ {
+ std::string Name;
+ std::string Directory;
+ std::vector<std::string> Args;
+ std::vector<std::string> RequiredFiles;
+ std::vector<std::string> Depends;
+ std::vector<std::string> AttachedFiles;
+ std::vector<std::string> AttachOnFail;
+ std::vector<std::pair<cmsys::RegularExpression, std::string> >
+ ErrorRegularExpressions;
+ std::vector<std::pair<cmsys::RegularExpression, std::string> >
+ RequiredRegularExpressions;
+ std::vector<std::pair<cmsys::RegularExpression, std::string> >
+ TimeoutRegularExpressions;
+ std::map<std::string, std::string> Measurements;
+ bool IsInBasedOnREOptions;
+ bool WillFail;
+ float Cost;
+ int PreviousRuns;
+ bool RunSerial;
+ double Timeout;
+ bool ExplicitTimeout;
+ double AlternateTimeout;
+ int Index;
+ // Requested number of process slots
+ int Processors;
+ // return code of test which will mark test as "not run"
+ int SkipReturnCode;
+ std::vector<std::string> Environment;
+ std::vector<std::string> Labels;
+ std::set<std::string> LockedResources;
+ };
+
+ struct cmCTestTestResult
+ {
+ std::string Name;
+ std::string Path;
+ std::string Reason;
+ std::string FullCommandLine;
+ double ExecutionTime;
+ int ReturnValue;
+ int Status;
+ bool CompressOutput;
+ std::string CompletionStatus;
+ std::string Output;
+ std::string DartString;
+ int TestCount;
+ cmCTestTestProperties* Properties;
+ };
+
+ struct cmCTestTestResultLess
+ {
+ bool operator()(const cmCTestTestResult& lhs,
+ const cmCTestTestResult& rhs) const
+ {
+ return lhs.TestCount < rhs.TestCount;
+ }
+ };
+
+ // add configurations to a search path for an executable
+ static void AddConfigurations(cmCTest* ctest,
+ std::vector<std::string>& attempted,
+ std::vector<std::string>& attemptedConfigs,
+ std::string filepath, std::string& filename);
+
+ // full signature static method to find an executable
+ static std::string FindExecutable(cmCTest* ctest, const char* testCommand,
+ std::string& resultingConfig,
+ std::vector<std::string>& extraPaths,
+ std::vector<std::string>& failed);
+
+ typedef std::vector<cmCTestTestProperties> ListOfTests;
+
+protected:
+ // compute a final test list
+ virtual int PreProcessHandler();
+ virtual int PostProcessHandler();
+ virtual void GenerateTestCommand(std::vector<std::string>& args, int test);
+ int ExecuteCommands(std::vector<std::string>& vec);
+
+ void WriteTestResultHeader(cmXMLWriter& xml, cmCTestTestResult* result);
+ void WriteTestResultFooter(cmXMLWriter& xml, cmCTestTestResult* result);
+ // Write attached test files into the xml
+ void AttachFiles(cmXMLWriter& xml, cmCTestTestResult* result);
+
+ //! Clean test output to specified length
+ bool CleanTestOutput(std::string& output, size_t length);
+
+ double ElapsedTestingTime;
+
+ typedef std::vector<cmCTestTestResult> TestResultsVector;
+ TestResultsVector TestResults;
+
+ std::vector<std::string> CustomTestsIgnore;
+ std::string StartTest;
+ std::string EndTest;
+ unsigned int StartTestTime;
+ unsigned int EndTestTime;
+ bool MemCheck;
+ int CustomMaximumPassedTestOutputSize;
+ int CustomMaximumFailedTestOutputSize;
+ int MaxIndex;
+
+public:
+ enum
+ { // Program statuses
+ NOT_RUN = 0,
+ TIMEOUT,
+ SEGFAULT,
+ ILLEGAL,
+ INTERRUPT,
+ NUMERICAL,
+ OTHER_FAULT,
+ FAILED,
+ BAD_COMMAND,
+ COMPLETED
+ };
+
+private:
+ /**
+ * Generate the Dart compatible output
+ */
+ virtual void GenerateDartOutput(cmXMLWriter& xml);
+
+ void PrintLabelSummary();
+ /**
+ * Run the tests for a directory and any subdirectories
+ */
+ void ProcessDirectory(std::vector<std::string>& passed,
+ std::vector<std::string>& failed);
+
+ /**
+ * Get the list of tests in directory and subdirectories.
+ */
+ void GetListOfTests();
+ // compute the lists of tests that will actually run
+ // based on union regex and -I stuff
+ void ComputeTestList();
+
+ // compute the lists of tests that will actually run
+ // based on LastTestFailed.log
+ void ComputeTestListForRerunFailed();
+
+ void UpdateMaxTestNameWidth();
+
+ bool GetValue(const char* tag, std::string& value, std::istream& fin);
+ bool GetValue(const char* tag, int& value, std::istream& fin);
+ bool GetValue(const char* tag, size_t& value, std::istream& fin);
+ bool GetValue(const char* tag, bool& value, std::istream& fin);
+ bool GetValue(const char* tag, double& value, std::istream& fin);
+ /**
+ * Find the executable for a test
+ */
+ std::string FindTheExecutable(const char* exe);
+
+ const char* GetTestStatus(int status);
+ void ExpandTestsToRunInformation(size_t numPossibleTests);
+ void ExpandTestsToRunInformationForRerunFailed();
+
+ std::vector<std::string> CustomPreTest;
+ std::vector<std::string> CustomPostTest;
+
+ std::vector<int> TestsToRun;
+
+ bool UseIncludeLabelRegExpFlag;
+ bool UseExcludeLabelRegExpFlag;
+ bool UseIncludeRegExpFlag;
+ bool UseExcludeRegExpFlag;
+ bool UseExcludeRegExpFirst;
+ std::string IncludeLabelRegExp;
+ std::string ExcludeLabelRegExp;
+ std::string IncludeRegExp;
+ std::string ExcludeRegExp;
+ cmsys::RegularExpression IncludeLabelRegularExpression;
+ cmsys::RegularExpression ExcludeLabelRegularExpression;
+ cmsys::RegularExpression IncludeTestsRegularExpression;
+ cmsys::RegularExpression ExcludeTestsRegularExpression;
+
+ void GenerateRegressionImages(cmXMLWriter& xml, const std::string& dart);
+ cmsys::RegularExpression DartStuff1;
+ void CheckLabelFilter(cmCTestTestProperties& it);
+ void CheckLabelFilterExclude(cmCTestTestProperties& it);
+ void CheckLabelFilterInclude(cmCTestTestProperties& it);
+
+ std::string TestsToRunString;
+ bool UseUnion;
+ ListOfTests TestList;
+ size_t TotalNumberOfTests;
+ cmsys::RegularExpression DartStuff;
+
+ std::ostream* LogFile;
+
+ bool RerunFailed;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx
new file mode 100644
index 0000000..bc06da6
--- /dev/null
+++ b/Source/CTest/cmCTestUpdateCommand.cxx
@@ -0,0 +1,96 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestUpdateCommand.h"
+
+#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
+
+cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
+{
+ if (this->Values[ct_SOURCE]) {
+ this->CTest->SetCTestConfiguration(
+ "SourceDirectory",
+ cmSystemTools::CollapseFullPath(this->Values[ct_SOURCE]).c_str(),
+ this->Quiet);
+ } else {
+ this->CTest->SetCTestConfiguration(
+ "SourceDirectory",
+ cmSystemTools::CollapseFullPath(
+ this->Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY"))
+ .c_str(),
+ this->Quiet);
+ }
+ std::string source_dir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "UpdateCommand", "CTEST_UPDATE_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "UpdateOptions", "CTEST_UPDATE_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CVSCommand", "CTEST_CVS_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CVSUpdateOptions", "CTEST_CVS_UPDATE_OPTIONS",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "SVNCommand", "CTEST_SVN_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "SVNUpdateOptions", "CTEST_SVN_UPDATE_OPTIONS",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "SVNOptions", "CTEST_SVN_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "BZRCommand", "CTEST_BZR_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "BZRUpdateOptions", "CTEST_BZR_UPDATE_OPTIONS",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "GITCommand", "CTEST_GIT_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "GITUpdateOptions", "CTEST_GIT_UPDATE_OPTIONS",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "GITInitSubmodules", "CTEST_GIT_INIT_SUBMODULES",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "GITUpdateCustom", "CTEST_GIT_UPDATE_CUSTOM", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "UpdateVersionOnly", "CTEST_UPDATE_VERSION_ONLY",
+ 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);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "P4Command", "CTEST_P4_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "P4UpdateOptions", "CTEST_P4_UPDATE_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "P4Client", "CTEST_P4_CLIENT", this->Quiet);
+ 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 CM_NULLPTR;
+ }
+ handler->SetCommand(this);
+ if (source_dir.empty()) {
+ this->SetError("source directory not specified. Please use SOURCE tag");
+ return CM_NULLPTR;
+ }
+ handler->SetOption("SourceDirectory", source_dir.c_str());
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
diff --git a/Source/CTest/cmCTestUpdateCommand.h b/Source/CTest/cmCTestUpdateCommand.h
new file mode 100644
index 0000000..6b5bbab
--- /dev/null
+++ b/Source/CTest/cmCTestUpdateCommand.h
@@ -0,0 +1,49 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestUpdateCommand_h
+#define cmCTestUpdateCommand_h
+
+#include "cmCTestHandlerCommand.h"
+
+/** \class cmCTestUpdate
+ * \brief Run a ctest script
+ *
+ * cmCTestUpdateCommand defineds the command to updates the repository.
+ */
+class cmCTestUpdateCommand : public cmCTestHandlerCommand
+{
+public:
+ cmCTestUpdateCommand() {}
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestUpdateCommand* ni = new cmCTestUpdateCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return ni;
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "ctest_update"; }
+
+ cmTypeMacro(cmCTestUpdateCommand, cmCTestHandlerCommand);
+
+protected:
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx
new file mode 100644
index 0000000..ac7eb05
--- /dev/null
+++ b/Source/CTest/cmCTestUpdateHandler.cxx
@@ -0,0 +1,376 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCTestUpdateHandler.h"
+
+#include "cmCLocaleEnvironmentScope.h"
+#include "cmCTest.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmVersion.h"
+#include "cmXMLParser.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+#include "cmCTestBZR.h"
+#include "cmCTestCVS.h"
+#include "cmCTestGIT.h"
+#include "cmCTestHG.h"
+#include "cmCTestP4.h"
+#include "cmCTestSVN.h"
+#include "cmCTestVC.h"
+
+#include <cm_auto_ptr.hxx>
+
+//#include <cmsys/RegularExpression.hxx>
+#include <cmsys/Process.h>
+
+// used for sleep
+#ifdef _WIN32
+#include "windows.h"
+#endif
+
+#include <float.h>
+#include <math.h>
+#include <stdlib.h>
+
+static const char* cmCTestUpdateHandlerUpdateStrings[] = {
+ "Unknown", "CVS", "SVN", "BZR", "GIT", "HG", "P4"
+};
+
+static const char* cmCTestUpdateHandlerUpdateToString(int type)
+{
+ if (type < cmCTestUpdateHandler::e_UNKNOWN ||
+ type >= cmCTestUpdateHandler::e_LAST) {
+ return cmCTestUpdateHandlerUpdateStrings[cmCTestUpdateHandler::e_UNKNOWN];
+ }
+ return cmCTestUpdateHandlerUpdateStrings[type];
+}
+
+cmCTestUpdateHandler::cmCTestUpdateHandler()
+{
+}
+
+void cmCTestUpdateHandler::Initialize()
+{
+ this->Superclass::Initialize();
+ this->UpdateCommand = "";
+ this->UpdateType = e_CVS;
+}
+
+int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type)
+{
+ cmCTestOptionalLog(this->CTest, DEBUG, "Determine update type from command: "
+ << cmd << " and type: " << type << std::endl,
+ this->Quiet);
+ if (type && *type) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Type specified: " << type << std::endl, this->Quiet);
+ std::string stype = cmSystemTools::LowerCase(type);
+ if (stype.find("cvs") != std::string::npos) {
+ return cmCTestUpdateHandler::e_CVS;
+ }
+ if (stype.find("svn") != std::string::npos) {
+ return cmCTestUpdateHandler::e_SVN;
+ }
+ if (stype.find("bzr") != std::string::npos) {
+ return cmCTestUpdateHandler::e_BZR;
+ }
+ if (stype.find("git") != std::string::npos) {
+ return cmCTestUpdateHandler::e_GIT;
+ }
+ if (stype.find("hg") != std::string::npos) {
+ return cmCTestUpdateHandler::e_HG;
+ }
+ if (stype.find("p4") != std::string::npos) {
+ return cmCTestUpdateHandler::e_P4;
+ }
+ } else {
+ cmCTestOptionalLog(
+ this->CTest, DEBUG,
+ "Type not specified, check command: " << cmd << std::endl, this->Quiet);
+ std::string stype = cmSystemTools::LowerCase(cmd);
+ if (stype.find("cvs") != std::string::npos) {
+ return cmCTestUpdateHandler::e_CVS;
+ }
+ if (stype.find("svn") != std::string::npos) {
+ return cmCTestUpdateHandler::e_SVN;
+ }
+ if (stype.find("bzr") != std::string::npos) {
+ return cmCTestUpdateHandler::e_BZR;
+ }
+ if (stype.find("git") != std::string::npos) {
+ return cmCTestUpdateHandler::e_GIT;
+ }
+ if (stype.find("hg") != std::string::npos) {
+ return cmCTestUpdateHandler::e_HG;
+ }
+ if (stype.find("p4") != std::string::npos) {
+ return cmCTestUpdateHandler::e_P4;
+ }
+ }
+ return cmCTestUpdateHandler::e_UNKNOWN;
+}
+
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
+int cmCTestUpdateHandler::ProcessHandler()
+{
+ // Make sure VCS tool messages are in English so we can parse them.
+ cmCLocaleEnvironmentScope fixLocale;
+ static_cast<void>(fixLocale);
+
+ // Get source dir
+ const char* sourceDirectory = this->GetOption("SourceDirectory");
+ if (!sourceDirectory) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find SourceDirectory key in the DartConfiguration.tcl"
+ << std::endl);
+ return -1;
+ }
+
+ cmGeneratedFileStream ofs;
+ if (!this->CTest->GetShowOnly()) {
+ this->StartLogFile("Update", ofs);
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Updating the repository: " << sourceDirectory
+ << std::endl,
+ this->Quiet);
+
+ if (!this->SelectVCS()) {
+ return -1;
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Use "
+ << cmCTestUpdateHandlerUpdateToString(this->UpdateType)
+ << " repository type" << std::endl;
+ , this->Quiet);
+
+ // Create an object to interact with the VCS tool.
+ CM_AUTO_PTR<cmCTestVC> vc;
+ switch (this->UpdateType) {
+ case e_CVS:
+ vc.reset(new cmCTestCVS(this->CTest, ofs));
+ break;
+ case e_SVN:
+ vc.reset(new cmCTestSVN(this->CTest, ofs));
+ break;
+ case e_BZR:
+ vc.reset(new cmCTestBZR(this->CTest, ofs));
+ break;
+ case e_GIT:
+ vc.reset(new cmCTestGIT(this->CTest, ofs));
+ break;
+ case e_HG:
+ vc.reset(new cmCTestHG(this->CTest, ofs));
+ break;
+ case e_P4:
+ vc.reset(new cmCTestP4(this->CTest, ofs));
+ break;
+ default:
+ vc.reset(new cmCTestVC(this->CTest, ofs));
+ break;
+ }
+ vc->SetCommandLineTool(this->UpdateCommand);
+ vc->SetSourceDirectory(sourceDirectory);
+
+ // Cleanup the working tree.
+ vc->Cleanup();
+
+ //
+ // Now update repository and remember what files were updated
+ //
+ cmGeneratedFileStream os;
+ if (!this->StartResultingXML(cmCTest::PartUpdate, "Update", os)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open log file"
+ << std::endl);
+ return -1;
+ }
+ std::string start_time = this->CTest->CurrentTime();
+ unsigned int start_time_time =
+ static_cast<unsigned int>(cmSystemTools::GetTime());
+ double elapsed_time_start = cmSystemTools::GetTime();
+
+ bool updated = vc->Update();
+ std::string buildname =
+ cmCTest::SafeBuildIdField(this->CTest->GetCTestConfiguration("BuildName"));
+
+ cmXMLWriter xml(os);
+ xml.StartDocument();
+ xml.StartElement("Update");
+ xml.Attribute("mode", "Client");
+ xml.Attribute("Generator",
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
+ xml.Element("Site", this->CTest->GetCTestConfiguration("Site"));
+ xml.Element("BuildName", buildname);
+ xml.Element("BuildStamp", this->CTest->GetCurrentTag() + "-" +
+ this->CTest->GetTestModelString());
+ xml.Element("StartDateTime", start_time);
+ xml.Element("StartTime", start_time_time);
+ xml.Element("UpdateCommand", vc->GetUpdateCommandLine());
+ xml.Element("UpdateType",
+ cmCTestUpdateHandlerUpdateToString(this->UpdateType));
+
+ vc->WriteXML(xml);
+
+ int localModifications = 0;
+ int numUpdated = vc->GetPathCount(cmCTestVC::PathUpdated);
+ if (numUpdated) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Found " << numUpdated << " updated files\n",
+ this->Quiet);
+ }
+ if (int numModified = vc->GetPathCount(cmCTestVC::PathModified)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Found "
+ << numModified << " locally modified files\n",
+ this->Quiet);
+ localModifications += numModified;
+ }
+ if (int numConflicting = vc->GetPathCount(cmCTestVC::PathConflicting)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Found " << numConflicting << " conflicting files\n",
+ this->Quiet);
+ localModifications += numConflicting;
+ }
+
+ cmCTestOptionalLog(this->CTest, DEBUG, "End" << std::endl, this->Quiet);
+ std::string end_time = this->CTest->CurrentTime();
+ xml.Element("EndDateTime", end_time);
+ xml.Element("EndTime", static_cast<unsigned int>(cmSystemTools::GetTime()));
+ xml.Element(
+ "ElapsedMinutes",
+ static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start) / 6) /
+ 10.0);
+
+ xml.StartElement("UpdateReturnStatus");
+ if (localModifications) {
+ xml.Content("Update error: "
+ "There are modified or conflicting files in the repository");
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " There are modified or conflicting files in the repository"
+ << std::endl);
+ }
+ if (!updated) {
+ xml.Content("Update command failed:\n");
+ xml.Content(vc->GetUpdateCommandLine());
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Update command failed: "
+ << vc->GetUpdateCommandLine() << "\n");
+ }
+ xml.EndElement(); // UpdateReturnStatus
+ xml.EndElement(); // Update
+ xml.EndDocument();
+ return updated ? numUpdated : -1;
+}
+
+int cmCTestUpdateHandler::DetectVCS(const char* dir)
+{
+ std::string sourceDirectory = dir;
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Check directory: " << sourceDirectory << std::endl,
+ this->Quiet);
+ sourceDirectory += "/.svn";
+ if (cmSystemTools::FileExists(sourceDirectory.c_str())) {
+ return cmCTestUpdateHandler::e_SVN;
+ }
+ sourceDirectory = dir;
+ sourceDirectory += "/CVS";
+ if (cmSystemTools::FileExists(sourceDirectory.c_str())) {
+ return cmCTestUpdateHandler::e_CVS;
+ }
+ sourceDirectory = dir;
+ sourceDirectory += "/.bzr";
+ if (cmSystemTools::FileExists(sourceDirectory.c_str())) {
+ return cmCTestUpdateHandler::e_BZR;
+ }
+ sourceDirectory = dir;
+ sourceDirectory += "/.git";
+ if (cmSystemTools::FileExists(sourceDirectory.c_str())) {
+ return cmCTestUpdateHandler::e_GIT;
+ }
+ sourceDirectory = dir;
+ sourceDirectory += "/.hg";
+ if (cmSystemTools::FileExists(sourceDirectory.c_str())) {
+ return cmCTestUpdateHandler::e_HG;
+ }
+ sourceDirectory = dir;
+ sourceDirectory += "/.p4";
+ if (cmSystemTools::FileExists(sourceDirectory.c_str())) {
+ return cmCTestUpdateHandler::e_P4;
+ }
+ sourceDirectory = dir;
+ sourceDirectory += "/.p4config";
+ if (cmSystemTools::FileExists(sourceDirectory.c_str())) {
+ return cmCTestUpdateHandler::e_P4;
+ }
+ return cmCTestUpdateHandler::e_UNKNOWN;
+}
+
+bool cmCTestUpdateHandler::SelectVCS()
+{
+ // Get update command
+ this->UpdateCommand = this->CTest->GetCTestConfiguration("UpdateCommand");
+
+ // Detect the VCS managing the source tree.
+ this->UpdateType = this->DetectVCS(this->GetOption("SourceDirectory"));
+ if (this->UpdateType == e_UNKNOWN) {
+ // The source tree does not have a recognized VCS. Check the
+ // configuration value or command name.
+ this->UpdateType = this->DetermineType(
+ this->UpdateCommand.c_str(),
+ this->CTest->GetCTestConfiguration("UpdateType").c_str());
+ }
+
+ // If no update command was specified, lookup one for this VCS tool.
+ if (this->UpdateCommand.empty()) {
+ const char* key = CM_NULLPTR;
+ switch (this->UpdateType) {
+ case e_CVS:
+ key = "CVSCommand";
+ break;
+ case e_SVN:
+ key = "SVNCommand";
+ break;
+ case e_BZR:
+ key = "BZRCommand";
+ break;
+ case e_GIT:
+ key = "GITCommand";
+ break;
+ case e_HG:
+ key = "HGCommand";
+ break;
+ case e_P4:
+ key = "P4Command";
+ break;
+ default:
+ break;
+ }
+ if (key) {
+ this->UpdateCommand = this->CTest->GetCTestConfiguration(key);
+ }
+ if (this->UpdateCommand.empty()) {
+ std::ostringstream e;
+ e << "Cannot find UpdateCommand ";
+ if (key) {
+ e << "or " << key;
+ }
+ e << " configuration key.";
+ cmCTestLog(this->CTest, ERROR_MESSAGE, e.str() << std::endl);
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/Source/CTest/cmCTestUpdateHandler.h b/Source/CTest/cmCTestUpdateHandler.h
new file mode 100644
index 0000000..6733c8c
--- /dev/null
+++ b/Source/CTest/cmCTestUpdateHandler.h
@@ -0,0 +1,73 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCTestUpdateHandler_h
+#define cmCTestUpdateHandler_h
+
+#include "cmCTestGenericHandler.h"
+
+#include "cmListFileCache.h"
+
+/** \class cmCTestUpdateHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestUpdateHandler : public cmCTestGenericHandler
+{
+public:
+ cmTypeMacro(cmCTestUpdateHandler, cmCTestGenericHandler);
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() CM_OVERRIDE;
+
+ cmCTestUpdateHandler();
+
+ enum
+ {
+ e_UNKNOWN = 0,
+ e_CVS,
+ e_SVN,
+ e_BZR,
+ e_GIT,
+ e_HG,
+ e_P4,
+ e_LAST
+ };
+
+ /**
+ * Initialize handler
+ */
+ void Initialize() CM_OVERRIDE;
+
+private:
+ // Some structures needed for update
+ struct StringPair : public std::pair<std::string, std::string>
+ {
+ };
+ struct UpdateFiles : public std::vector<StringPair>
+ {
+ };
+
+ // Determine the type of version control
+ int DetermineType(const char* cmd, const char* type);
+
+ // The VCS command to update the working tree.
+ std::string UpdateCommand;
+ int UpdateType;
+
+ int DetectVCS(const char* dir);
+ bool SelectVCS();
+};
+
+#endif
diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx
new file mode 100644
index 0000000..7393d21
--- /dev/null
+++ b/Source/CTest/cmCTestUploadCommand.cxx
@@ -0,0 +1,64 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestUploadCommand.h"
+
+#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
+#include "cmCTestUploadHandler.h"
+
+cmCTestGenericHandler* cmCTestUploadCommand::InitializeHandler()
+{
+ cmCTestGenericHandler* handler =
+ this->CTest->GetInitializedHandler("upload");
+ if (!handler) {
+ this->SetError("internal CTest error. Cannot instantiate upload handler");
+ return CM_NULLPTR;
+ }
+ static_cast<cmCTestUploadHandler*>(handler)->SetFiles(this->Files);
+
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
+
+bool cmCTestUploadCommand::CheckArgumentKeyword(std::string const& arg)
+{
+ if (arg == "FILES") {
+ this->ArgumentDoing = ArgumentDoingFiles;
+ return true;
+ }
+ if (arg == "QUIET") {
+ this->ArgumentDoing = ArgumentDoingNone;
+ this->Quiet = true;
+ return true;
+ }
+ return false;
+}
+
+bool cmCTestUploadCommand::CheckArgumentValue(std::string const& arg)
+{
+ if (this->ArgumentDoing == ArgumentDoingFiles) {
+ if (cmSystemTools::FileExists(arg.c_str())) {
+ this->Files.insert(arg);
+ return true;
+ } else {
+ std::ostringstream e;
+ e << "File \"" << arg << "\" does not exist. Cannot submit "
+ << "a non-existent file.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ this->ArgumentDoing = ArgumentDoingError;
+ return false;
+ }
+ }
+
+ // Look for other arguments.
+ return this->Superclass::CheckArgumentValue(arg);
+}
diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h
new file mode 100644
index 0000000..923995d
--- /dev/null
+++ b/Source/CTest/cmCTestUploadCommand.h
@@ -0,0 +1,63 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestUploadCommand_h
+#define cmCTestUploadCommand_h
+
+#include "cmCTestHandlerCommand.h"
+
+#include "cmCTest.h"
+
+/** \class cmCTestUpload
+ * \brief Run a ctest script
+ *
+ * cmCTestUploadCommand defines the command to upload result files for
+ * the project.
+ */
+class cmCTestUploadCommand : public cmCTestHandlerCommand
+{
+public:
+ cmCTestUploadCommand() {}
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestUploadCommand* ni = new cmCTestUploadCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return ni;
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "ctest_upload"; }
+
+ cmTypeMacro(cmCTestUploadCommand, cmCTestHandlerCommand);
+
+protected:
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
+
+ bool CheckArgumentKeyword(std::string const& arg) CM_OVERRIDE;
+ bool CheckArgumentValue(std::string const& arg) CM_OVERRIDE;
+
+ enum
+ {
+ ArgumentDoingFiles = Superclass::ArgumentDoingLast1,
+ ArgumentDoingLast2
+ };
+
+ cmCTest::SetOfStrings Files;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestUploadHandler.cxx b/Source/CTest/cmCTestUploadHandler.cxx
new file mode 100644
index 0000000..6a3b830
--- /dev/null
+++ b/Source/CTest/cmCTestUploadHandler.cxx
@@ -0,0 +1,78 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestUploadHandler.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmVersion.h"
+#include "cmXMLWriter.h"
+
+cmCTestUploadHandler::cmCTestUploadHandler()
+{
+ this->Initialize();
+}
+
+void cmCTestUploadHandler::Initialize()
+{
+ this->Superclass::Initialize();
+ this->Files.clear();
+}
+
+void cmCTestUploadHandler::SetFiles(const cmCTest::SetOfStrings& files)
+{
+ this->Files = files;
+}
+
+int cmCTestUploadHandler::ProcessHandler()
+{
+ cmGeneratedFileStream ofs;
+ if (!this->CTest->OpenOutputFile(this->CTest->GetCurrentTag(), "Upload.xml",
+ ofs)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open Upload.xml file"
+ << std::endl);
+ return -1;
+ }
+ std::string buildname =
+ cmCTest::SafeBuildIdField(this->CTest->GetCTestConfiguration("BuildName"));
+ cmCTest::SetOfStrings::const_iterator it;
+
+ cmXMLWriter xml(ofs);
+ xml.StartDocument();
+ xml.ProcessingInstruction("xml-stylesheet",
+ "type=\"text/xsl\" "
+ "href=\"Dart/Source/Server/XSL/Build.xsl "
+ "<file:///Dart/Source/Server/XSL/Build.xsl> \"");
+ xml.StartElement("Site");
+ xml.Attribute("BuildName", buildname);
+ xml.Attribute("BuildStamp", this->CTest->GetCurrentTag() + "-" +
+ this->CTest->GetTestModelString());
+ xml.Attribute("Name", this->CTest->GetCTestConfiguration("Site"));
+ xml.Attribute("Generator",
+ std::string("ctest") + cmVersion::GetCMakeVersion());
+ this->CTest->AddSiteProperties(xml);
+ xml.StartElement("Upload");
+
+ for (it = this->Files.begin(); it != this->Files.end(); it++) {
+ cmCTestOptionalLog(this->CTest, OUTPUT,
+ "\tUpload file: " << *it << std::endl, this->Quiet);
+ xml.StartElement("File");
+ xml.Attribute("filename", *it);
+ xml.StartElement("Content");
+ xml.Attribute("encoding", "base64");
+ xml.Content(this->CTest->Base64EncodeFile(*it));
+ xml.EndElement(); // Content
+ xml.EndElement(); // File
+ }
+ xml.EndElement(); // Upload
+ xml.EndElement(); // Site
+ xml.EndDocument();
+ return 0;
+}
diff --git a/Source/CTest/cmCTestUploadHandler.h b/Source/CTest/cmCTestUploadHandler.h
new file mode 100644
index 0000000..8b824d6
--- /dev/null
+++ b/Source/CTest/cmCTestUploadHandler.h
@@ -0,0 +1,45 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestUploadHandler_h
+#define cmCTestUploadHandler_h
+
+#include "cmCTestGenericHandler.h"
+
+/** \class cmCTestUploadHandler
+ * \brief Helper class for CTest
+ *
+ * Submit arbitrary files
+ *
+ */
+class cmCTestUploadHandler : public cmCTestGenericHandler
+{
+public:
+ cmTypeMacro(cmCTestUploadHandler, cmCTestGenericHandler);
+
+ cmCTestUploadHandler();
+ ~cmCTestUploadHandler() CM_OVERRIDE {}
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() CM_OVERRIDE;
+
+ void Initialize() CM_OVERRIDE;
+
+ /** Specify a set of files to submit. */
+ void SetFiles(cmCTest::SetOfStrings const& files);
+
+private:
+ cmCTest::SetOfStrings Files;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx
new file mode 100644
index 0000000..3376588
--- /dev/null
+++ b/Source/CTest/cmCTestVC.cxx
@@ -0,0 +1,217 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTestVC.h"
+
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+
+#include <cmsys/Process.h>
+
+cmCTestVC::cmCTestVC(cmCTest* ct, std::ostream& log)
+ : CTest(ct)
+ , Log(log)
+{
+ this->PathCount[PathUpdated] = 0;
+ this->PathCount[PathModified] = 0;
+ this->PathCount[PathConflicting] = 0;
+ this->Unknown.Date = "Unknown";
+ this->Unknown.Author = "Unknown";
+ this->Unknown.Rev = "Unknown";
+}
+
+cmCTestVC::~cmCTestVC()
+{
+}
+
+void cmCTestVC::SetCommandLineTool(std::string const& tool)
+{
+ this->CommandLineTool = tool;
+}
+
+void cmCTestVC::SetSourceDirectory(std::string const& dir)
+{
+ this->SourceDirectory = dir;
+}
+
+bool cmCTestVC::InitialCheckout(const char* command)
+{
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " First perform the initial checkout: " << command << "\n");
+
+ // Make the parent directory in which to perform the checkout.
+ std::string parent = cmSystemTools::GetFilenamePath(this->SourceDirectory);
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Perform checkout in directory: " << parent << "\n");
+ if (!cmSystemTools::MakeDirectory(parent.c_str())) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create directory: " << parent << std::endl);
+ return false;
+ }
+
+ // Construct the initial checkout command line.
+ std::vector<std::string> args = cmSystemTools::ParseArguments(command);
+ std::vector<char const*> vc_co;
+ for (std::vector<std::string>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai) {
+ vc_co.push_back(ai->c_str());
+ }
+ vc_co.push_back(CM_NULLPTR);
+
+ // Run the initial checkout command and log its output.
+ this->Log << "--- Begin Initial Checkout ---\n";
+ OutputLogger out(this->Log, "co-out> ");
+ OutputLogger err(this->Log, "co-err> ");
+ bool result = this->RunChild(&vc_co[0], &out, &err, parent.c_str());
+ this->Log << "--- End Initial Checkout ---\n";
+ if (!result) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initial checkout failed!"
+ << std::endl);
+ }
+ return result;
+}
+
+bool cmCTestVC::RunChild(char const* const* cmd, OutputParser* out,
+ OutputParser* err, const char* workDir)
+{
+ this->Log << this->ComputeCommandLine(cmd) << "\n";
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, cmd);
+ workDir = workDir ? workDir : this->SourceDirectory.c_str();
+ cmsysProcess_SetWorkingDirectory(cp, workDir);
+ this->RunProcess(cp, out, err);
+ int result = cmsysProcess_GetExitValue(cp);
+ cmsysProcess_Delete(cp);
+ return result == 0;
+}
+
+std::string cmCTestVC::ComputeCommandLine(char const* const* cmd)
+{
+ std::ostringstream line;
+ const char* sep = "";
+ for (const char* const* arg = cmd; *arg; ++arg) {
+ line << sep << "\"" << *arg << "\"";
+ sep = " ";
+ }
+ return line.str();
+}
+
+bool cmCTestVC::RunUpdateCommand(char const* const* cmd, OutputParser* out,
+ OutputParser* err)
+{
+ // Report the command line.
+ this->UpdateCommandLine = this->ComputeCommandLine(cmd);
+ if (this->CTest->GetShowOnly()) {
+ this->Log << this->UpdateCommandLine << "\n";
+ return true;
+ }
+
+ // Run the command.
+ return this->RunChild(cmd, out, err);
+}
+
+std::string cmCTestVC::GetNightlyTime()
+{
+ // Get the nightly start time corresponding to the current dau.
+ struct tm* t = this->CTest->GetNightlyTime(
+ this->CTest->GetCTestConfiguration("NightlyStartTime"),
+ this->CTest->GetTomorrowTag());
+ char current_time[1024];
+ sprintf(current_time, "%04d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900,
+ t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+ return std::string(current_time);
+}
+
+void cmCTestVC::Cleanup()
+{
+ this->Log << "--- Begin Cleanup ---\n";
+ this->CleanupImpl();
+ this->Log << "--- End Cleanup ---\n";
+}
+
+void cmCTestVC::CleanupImpl()
+{
+ // We do no cleanup by default.
+}
+
+bool cmCTestVC::Update()
+{
+ bool result = true;
+ // if update version only is on then do not actually update,
+ // just note the current version and finish
+ if (!cmSystemTools::IsOn(
+ this->CTest->GetCTestConfiguration("UpdateVersionOnly").c_str())) {
+ this->NoteOldRevision();
+ this->Log << "--- Begin Update ---\n";
+ result = this->UpdateImpl();
+ this->Log << "--- End Update ---\n";
+ }
+ this->NoteNewRevision();
+ return result;
+}
+
+void cmCTestVC::NoteOldRevision()
+{
+ // We do nothing by default.
+}
+
+void cmCTestVC::NoteNewRevision()
+{
+ // We do nothing by default.
+}
+
+bool cmCTestVC::UpdateImpl()
+{
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "* Unknown VCS tool, not updating!" << std::endl);
+ return true;
+}
+
+bool cmCTestVC::WriteXML(cmXMLWriter& xml)
+{
+ this->Log << "--- Begin Revisions ---\n";
+ bool result = this->WriteXMLUpdates(xml);
+ this->Log << "--- End Revisions ---\n";
+ return result;
+}
+
+bool cmCTestVC::WriteXMLUpdates(cmXMLWriter&)
+{
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "* CTest cannot extract updates for this VCS tool.\n");
+ return true;
+}
+
+void cmCTestVC::WriteXMLEntry(cmXMLWriter& xml, std::string const& path,
+ std::string const& name, std::string const& full,
+ File const& f)
+{
+ static const char* desc[3] = { "Updated", "Modified", "Conflicting" };
+ Revision const& rev = f.Rev ? *f.Rev : this->Unknown;
+ std::string prior = f.PriorRev ? f.PriorRev->Rev : std::string("Unknown");
+ xml.StartElement(desc[f.Status]);
+ xml.Element("File", name);
+ xml.Element("Directory", path);
+ xml.Element("FullName", full);
+ xml.Element("CheckinDate", rev.Date);
+ xml.Element("Author", rev.Author);
+ xml.Element("Email", rev.EMail);
+ xml.Element("Committer", rev.Committer);
+ xml.Element("CommitterEmail", rev.CommitterEMail);
+ xml.Element("CommitDate", rev.CommitDate);
+ xml.Element("Log", rev.Log);
+ xml.Element("Revision", rev.Rev);
+ xml.Element("PriorRevision", prior);
+ xml.EndElement();
+ ++this->PathCount[f.Status];
+}
diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h
new file mode 100644
index 0000000..eb85a236
--- /dev/null
+++ b/Source/CTest/cmCTestVC.h
@@ -0,0 +1,155 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestVC_h
+#define cmCTestVC_h
+
+#include "cmProcessTools.h"
+
+class cmCTest;
+class cmXMLWriter;
+
+/** \class cmCTestVC
+ * \brief Base class for version control system handlers
+ *
+ */
+class cmCTestVC : public cmProcessTools
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestVC(cmCTest* ctest, std::ostream& log);
+
+ virtual ~cmCTestVC();
+
+ /** Command line tool to invoke. */
+ void SetCommandLineTool(std::string const& tool);
+
+ /** Top-level source directory. */
+ void SetSourceDirectory(std::string const& dir);
+
+ /** Get the date/time specification for the current nightly start time. */
+ std::string GetNightlyTime();
+
+ /** Prepare the work tree. */
+ bool InitialCheckout(const char* command);
+
+ /** Perform cleanup operations on the work tree. */
+ void Cleanup();
+
+ /** Update the working tree to the new revision. */
+ bool Update();
+
+ /** Get the command line used by the Update method. */
+ std::string const& GetUpdateCommandLine() const
+ {
+ return this->UpdateCommandLine;
+ }
+
+ /** Write Update.xml entries for the updates found. */
+ bool WriteXML(cmXMLWriter& xml);
+
+ /** Enumerate non-trivial working tree states during update. */
+ enum PathStatus
+ {
+ PathUpdated,
+ PathModified,
+ PathConflicting
+ };
+
+ /** Get the number of working tree paths in each state after update. */
+ int GetPathCount(PathStatus s) const { return this->PathCount[s]; }
+
+protected:
+ // Internal API to be implemented by subclasses.
+ virtual void CleanupImpl();
+ virtual void NoteOldRevision();
+ virtual bool UpdateImpl();
+ virtual void NoteNewRevision();
+ virtual bool WriteXMLUpdates(cmXMLWriter& xml);
+
+#if defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x510
+ // Sun CC 5.1 needs help to allow cmCTestSVN::Revision to see this
+public:
+#endif
+ /** Basic information about one revision of a tree or file. */
+ struct Revision
+ {
+ std::string Rev;
+ std::string Date;
+ std::string Author;
+ std::string EMail;
+ std::string Committer;
+ std::string CommitterEMail;
+ std::string CommitDate;
+ std::string Log;
+ };
+
+protected:
+ struct File;
+ friend struct File;
+
+ /** Represent change to one file. */
+ struct File
+ {
+ PathStatus Status;
+ Revision const* Rev;
+ Revision const* PriorRev;
+ File()
+ : Status(PathUpdated)
+ , Rev(CM_NULLPTR)
+ , PriorRev(CM_NULLPTR)
+ {
+ }
+ File(PathStatus status, Revision const* rev, Revision const* priorRev)
+ : Status(status)
+ , Rev(rev)
+ , PriorRev(priorRev)
+ {
+ }
+ };
+
+ /** Convert a list of arguments to a human-readable command line. */
+ static std::string ComputeCommandLine(char const* const* cmd);
+
+ /** Run a command line and send output to given parsers. */
+ bool RunChild(char const* const* cmd, OutputParser* out, OutputParser* err,
+ const char* workDir = CM_NULLPTR);
+
+ /** Run VC update command line and send output to given parsers. */
+ bool RunUpdateCommand(char const* const* cmd, OutputParser* out,
+ OutputParser* err = CM_NULLPTR);
+
+ /** Write xml element for one file. */
+ void WriteXMLEntry(cmXMLWriter& xml, std::string const& path,
+ std::string const& name, std::string const& full,
+ File const& f);
+
+ // Instance of cmCTest running the script.
+ cmCTest* CTest;
+
+ // A stream to which we write log information.
+ std::ostream& Log;
+
+ // Basic information about the working tree.
+ std::string CommandLineTool;
+ std::string SourceDirectory;
+
+ // Record update command info.
+ std::string UpdateCommandLine;
+
+ // Placeholder for unknown revisions.
+ Revision Unknown;
+
+ // Count paths reported with each PathStatus value.
+ int PathCount[3];
+};
+
+#endif
diff --git a/Source/CTest/cmParseBlanketJSCoverage.cxx b/Source/CTest/cmParseBlanketJSCoverage.cxx
new file mode 100644
index 0000000..fa539e4
--- /dev/null
+++ b/Source/CTest/cmParseBlanketJSCoverage.cxx
@@ -0,0 +1,148 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmParseBlanketJSCoverage.h"
+
+#include "cmSystemTools.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <stdio.h>
+#include <stdlib.h>
+
+class cmParseBlanketJSCoverage::JSONParser
+{
+public:
+ typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector
+ FileLinesType;
+ JSONParser(cmCTestCoverageHandlerContainer& cont)
+ : Coverage(cont)
+ {
+ }
+
+ virtual ~JSONParser() {}
+
+ std::string getValue(std::string line, int type)
+ {
+ size_t begIndex;
+ size_t endIndex;
+ endIndex = line.rfind(',');
+ begIndex = line.find_first_of(':');
+ if (type == 0) {
+ // A unique substring to remove the extra characters
+ // around the files name in the JSON (extra " and ,)
+ std::string foundFileName =
+ line.substr(begIndex + 3, endIndex - (begIndex + 4));
+ return foundFileName;
+ } else {
+ return line.substr(begIndex, line.npos);
+ }
+ }
+ bool ParseFile(std::string const& file)
+ {
+ FileLinesType localCoverageVector;
+ std::string filename;
+ bool foundFile = false;
+ bool inSource = false;
+ std::string covResult;
+ std::string line;
+
+ cmsys::ifstream in(file.c_str());
+ if (!in) {
+ return false;
+ }
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ if (line.find("filename") != line.npos) {
+ if (foundFile) {
+ /*
+ * Upon finding a second file name, generate a
+ * vector within the total coverage to capture the
+ * information in the local vector
+ */
+ FileLinesType& CoverageVector =
+ this->Coverage.TotalCoverage[filename];
+ CoverageVector = localCoverageVector;
+ localCoverageVector.clear();
+ }
+ foundFile = true;
+ inSource = false;
+ filename = getValue(line, 0);
+ } else if ((line.find("coverage") != line.npos) && foundFile &&
+ inSource) {
+ /*
+ * two types of "coverage" in the JSON structure
+ *
+ * The coverage result over the file or set of files
+ * and the coverage for each individual line
+ *
+ * FoundFile and foundSource ensure that
+ * only the value of the line coverage is captured
+ */
+ std::string result = getValue(line, 1);
+ result = result.substr(2, result.npos);
+ if (result == "\"\"") {
+ // Empty quotation marks indicate that the
+ // line is not executable
+ localCoverageVector.push_back(-1);
+ } else {
+ // Else, it contains the number of time executed
+ localCoverageVector.push_back(atoi(result.c_str()));
+ }
+ } else if (line.find("source") != line.npos) {
+ inSource = true;
+ }
+ }
+
+ // On exit, capture end of last file covered.
+ FileLinesType& CoverageVector = this->Coverage.TotalCoverage[filename];
+ CoverageVector = localCoverageVector;
+ localCoverageVector.clear();
+ return true;
+ }
+
+private:
+ cmCTestCoverageHandlerContainer& Coverage;
+};
+
+cmParseBlanketJSCoverage::cmParseBlanketJSCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParseBlanketJSCoverage::LoadCoverageData(std::vector<std::string> files)
+{
+ size_t i = 0;
+ std::string path;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found " << files.size() << " Files" << std::endl,
+ this->Coverage.Quiet);
+ for (i = 0; i < files.size(); i++) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading JSON File " << files[i] << std::endl,
+ this->Coverage.Quiet);
+
+ if (!this->ReadJSONFile(files[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmParseBlanketJSCoverage::ReadJSONFile(std::string const& file)
+{
+ cmParseBlanketJSCoverage::JSONParser parser(this->Coverage);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Parsing " << file << std::endl, this->Coverage.Quiet);
+ parser.ParseFile(file);
+ return true;
+}
diff --git a/Source/CTest/cmParseBlanketJSCoverage.h b/Source/CTest/cmParseBlanketJSCoverage.h
new file mode 100644
index 0000000..a4f6670
--- /dev/null
+++ b/Source/CTest/cmParseBlanketJSCoverage.h
@@ -0,0 +1,45 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmParseBlanketJSCoverage_h
+#define cmParseBlanketJSCoverage_h
+
+#include "cmCTestCoverageHandler.h"
+
+/** \class cmParseBlanketJSCoverage
+ * \brief Parse BlanketJS coverage information
+ *
+ * This class is used to parse BlanketJS(Pascal) coverage information
+ * generated by the Blanket.js library when used in conjunction with the
+ * test runner mocha.js, which is used to write out the JSON format.
+ *
+ * Blanket.js:
+ * http://blanketjs.org/
+ *
+ * Mocha.js
+ * http://visionmedia.github.io/mocha/
+ */
+class cmParseBlanketJSCoverage
+{
+public:
+ cmParseBlanketJSCoverage(cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest);
+ bool LoadCoverageData(std::vector<std::string> files);
+ // Read the JSON output
+ bool ReadJSONFile(std::string const& file);
+
+protected:
+ class JSONParser;
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
+#endif
diff --git a/Source/CTest/cmParseCacheCoverage.cxx b/Source/CTest/cmParseCacheCoverage.cxx
new file mode 100644
index 0000000..0916da2
--- /dev/null
+++ b/Source/CTest/cmParseCacheCoverage.cxx
@@ -0,0 +1,196 @@
+#include "cmParseCacheCoverage.h"
+
+#include "cmSystemTools.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <stdio.h>
+#include <stdlib.h>
+
+cmParseCacheCoverage::cmParseCacheCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : cmParseMumpsCoverage(cont, ctest)
+{
+}
+
+bool cmParseCacheCoverage::LoadCoverageData(const char* d)
+{
+ // load all the .mcov files in the specified directory
+ cmsys::Directory dir;
+ if (!dir.Load(d)) {
+ return false;
+ }
+ size_t numf;
+ unsigned int i;
+ numf = dir.GetNumberOfFiles();
+ for (i = 0; i < numf; i++) {
+ std::string file = dir.GetFile(i);
+ if (file != "." && file != ".." && !cmSystemTools::FileIsDirectory(file)) {
+ std::string path = d;
+ path += "/";
+ path += file;
+ if (cmSystemTools::GetFilenameLastExtension(path) == ".cmcov") {
+ if (!this->ReadCMCovFile(path.c_str())) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+// not currently used, but leave it in case we want it in the future
+void cmParseCacheCoverage::RemoveUnCoveredFiles()
+{
+ // loop over the coverage data computed and remove all files
+ // that only have -1 or 0 for the lines.
+ cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator ci =
+ this->Coverage.TotalCoverage.begin();
+ while (ci != this->Coverage.TotalCoverage.end()) {
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& v = ci->second;
+ bool nothing = true;
+ for (cmCTestCoverageHandlerContainer::SingleFileCoverageVector::iterator
+ i = v.begin();
+ i != v.end(); ++i) {
+ if (*i > 0) {
+ nothing = false;
+ break;
+ }
+ }
+ if (nothing) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "No coverage found in: " << ci->first << std::endl,
+ this->Coverage.Quiet);
+ this->Coverage.TotalCoverage.erase(ci++);
+ } else {
+ ++ci;
+ }
+ }
+}
+
+bool cmParseCacheCoverage::SplitString(std::vector<std::string>& args,
+ std::string const& line)
+{
+ std::string::size_type pos1 = 0;
+ std::string::size_type pos2 = line.find(',', 0);
+ if (pos2 == std::string::npos) {
+ return false;
+ }
+ std::string arg;
+ while (pos2 != std::string::npos) {
+ arg = line.substr(pos1, pos2 - pos1);
+ args.push_back(arg);
+ pos1 = pos2 + 1;
+ pos2 = line.find(',', pos1);
+ }
+ arg = line.substr(pos1);
+ args.push_back(arg);
+ return true;
+}
+
+bool cmParseCacheCoverage::ReadCMCovFile(const char* file)
+{
+ cmsys::ifstream in(file);
+ if (!in) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Can not open : " << file << "\n");
+ return false;
+ }
+ std::string line;
+ std::vector<std::string> separateLine;
+ if (!cmSystemTools::GetLineFromStream(in, line)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Empty file : "
+ << file << " referenced in this line of cmcov data:\n"
+ "["
+ << line << "]\n");
+ return false;
+ }
+ separateLine.clear();
+ this->SplitString(separateLine, line);
+ if (separateLine.size() != 4 || separateLine[0] != "Routine" ||
+ separateLine[1] != "Line" || separateLine[2] != "RtnLine" ||
+ separateLine[3] != "Code") {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Bad first line of cmcov file : " << file << " line:\n"
+ "["
+ << line << "]\n");
+ }
+ std::string routine;
+ std::string filepath;
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ // clear out line argument vector
+ separateLine.clear();
+ // parse the comma separated line
+ this->SplitString(separateLine, line);
+ // might have more because code could have a quoted , in it
+ // but we only care about the first 3 args anyway
+ if (separateLine.size() < 4) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Bad line of cmcov file expected at least 4 found: "
+ << separateLine.size() << " " << file << " line:\n"
+ "["
+ << line << "]\n");
+ for (std::string::size_type i = 0; i < separateLine.size(); ++i) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "" << separateLine[1] << " ");
+ }
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "\n");
+ return false;
+ }
+ // if we do not have a routine yet, then it should be
+ // the first argument in the vector
+ if (routine.empty()) {
+ routine = separateLine[0];
+ // Find the full path to the file
+ if (!this->FindMumpsFile(routine, filepath)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Could not find mumps file for routine: " << routine
+ << "\n");
+ filepath = "";
+ continue; // move to next line
+ }
+ }
+ // if we have a routine name, check for end of routine
+ else {
+ // Totals in arg 0 marks the end of a routine
+ if (separateLine[0].substr(0, 6) == "Totals") {
+ routine = ""; // at the end of this routine
+ filepath = "";
+ continue; // move to next line
+ }
+ }
+ // if the file path was not found for the routine
+ // move to next line. We should have already warned
+ // after the call to FindMumpsFile that we did not find
+ // it, so don't report again to cut down on output
+ if (filepath.empty()) {
+ continue;
+ }
+ // now we are ready to set the coverage from the line of data
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector =
+ this->Coverage.TotalCoverage[filepath];
+ std::string::size_type linenumber = atoi(separateLine[1].c_str()) - 1;
+ int count = atoi(separateLine[2].c_str());
+ if (linenumber > coverageVector.size()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Parse error line is greater than number of lines in file: "
+ << linenumber << " " << filepath << "\n");
+ continue; // skip setting count to avoid crash
+ }
+ // now add to count for linenumber
+ // for some reason the cache coverage adds extra lines to the
+ // end of the file in some cases. Since they do not exist, we will
+ // mark them as non executable
+ while (linenumber >= coverageVector.size()) {
+ coverageVector.push_back(-1);
+ }
+ // Accounts for lines that were previously marked
+ // as non-executable code (-1). if the parser comes back with
+ // a non-zero count, increase the count by 1 to push the line
+ // into the executable code set in addition to the count found.
+ if (coverageVector[linenumber] == -1 && count > 0) {
+ coverageVector[linenumber] += count + 1;
+ } else {
+ coverageVector[linenumber] += count;
+ }
+ }
+ return true;
+}
diff --git a/Source/CTest/cmParseCacheCoverage.h b/Source/CTest/cmParseCacheCoverage.h
new file mode 100644
index 0000000..65b1d10
--- /dev/null
+++ b/Source/CTest/cmParseCacheCoverage.h
@@ -0,0 +1,40 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmParseCacheCoverage_h
+#define cmParseCacheCoverage_h
+
+#include "cmParseMumpsCoverage.h"
+
+/** \class cmParseCacheCoverage
+ * \brief Parse Cache coverage information
+ *
+ * This class is used to parse Cache coverage information for
+ * mumps.
+ */
+class cmParseCacheCoverage : public cmParseMumpsCoverage
+{
+public:
+ cmParseCacheCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+
+protected:
+ // implement virtual from parent
+ bool LoadCoverageData(const char* dir) CM_OVERRIDE;
+ // remove files with no coverage
+ void RemoveUnCoveredFiles();
+ // Read a single mcov file
+ bool ReadCMCovFile(const char* f);
+ // split a string based on ,
+ bool SplitString(std::vector<std::string>& args, std::string const& line);
+};
+
+#endif
diff --git a/Source/CTest/cmParseCoberturaCoverage.cxx b/Source/CTest/cmParseCoberturaCoverage.cxx
new file mode 100644
index 0000000..1a3fe3c
--- /dev/null
+++ b/Source/CTest/cmParseCoberturaCoverage.cxx
@@ -0,0 +1,166 @@
+#include "cmParseCoberturaCoverage.h"
+
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+
+class cmParseCoberturaCoverage::XMLParser : public cmXMLParser
+{
+public:
+ XMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
+ : CTest(ctest)
+ , Coverage(cont)
+ {
+ this->InSources = false;
+ this->InSource = false;
+ this->SkipThisClass = false;
+ this->FilePaths.push_back(this->Coverage.SourceDir);
+ this->FilePaths.push_back(this->Coverage.BinaryDir);
+ this->CurFileName = "";
+ }
+
+ ~XMLParser() CM_OVERRIDE {}
+
+protected:
+ void EndElement(const std::string& name) CM_OVERRIDE
+ {
+ if (name == "source") {
+ this->InSource = false;
+ } else if (name == "sources") {
+ this->InSources = false;
+ } else if (name == "class") {
+ this->SkipThisClass = false;
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) CM_OVERRIDE
+ {
+ std::string tmp;
+ tmp.insert(0, data, length);
+ if (this->InSources && this->InSource) {
+ this->FilePaths.push_back(tmp);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Adding Source: " << tmp << std::endl,
+ this->Coverage.Quiet);
+ }
+ }
+
+ void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
+ {
+ std::string FoundSource;
+ std::string finalpath = "";
+ if (name == "source") {
+ this->InSource = true;
+ } else if (name == "sources") {
+ this->InSources = true;
+ } else if (name == "class") {
+ int tagCount = 0;
+ while (true) {
+ if (strcmp(atts[tagCount], "filename") == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading file: " << atts[tagCount + 1]
+ << std::endl,
+ this->Coverage.Quiet);
+ std::string filename = atts[tagCount + 1];
+ this->CurFileName = "";
+
+ // Check if this is an absolute path that falls within our
+ // source or binary directories.
+ for (size_t i = 0; i < FilePaths.size(); i++) {
+ if (filename.find(FilePaths[i]) == 0) {
+ this->CurFileName = filename;
+ break;
+ }
+ }
+
+ if (this->CurFileName == "") {
+ // Check if this is a path that is relative to our source or
+ // binary directories.
+ for (size_t i = 0; i < FilePaths.size(); i++) {
+ finalpath = FilePaths[i] + "/" + filename;
+ if (cmSystemTools::FileExists(finalpath.c_str())) {
+ this->CurFileName = finalpath;
+ break;
+ }
+ }
+ }
+
+ cmsys::ifstream fin(this->CurFileName.c_str());
+ if (this->CurFileName == "" || !fin) {
+ this->CurFileName =
+ this->Coverage.BinaryDir + "/" + atts[tagCount + 1];
+ fin.open(this->CurFileName.c_str());
+ if (!fin) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Skipping system file " << filename
+ << std::endl,
+ this->Coverage.Quiet);
+
+ this->SkipThisClass = true;
+ break;
+ }
+ }
+ std::string line;
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->CurFileName];
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ curFileLines.push_back(-1);
+ }
+
+ break;
+ }
+ ++tagCount;
+ }
+ } else if (name == "line") {
+ int tagCount = 0;
+ int curNumber = -1;
+ int curHits = -1;
+ while (true) {
+ if (this->SkipThisClass) {
+ break;
+ }
+ if (strcmp(atts[tagCount], "hits") == 0) {
+ curHits = atoi(atts[tagCount + 1]);
+ } else if (strcmp(atts[tagCount], "number") == 0) {
+ curNumber = atoi(atts[tagCount + 1]);
+ }
+
+ if (curHits > -1 && curNumber > 0) {
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->CurFileName];
+ {
+ curFileLines[curNumber - 1] = curHits;
+ }
+ break;
+ }
+ ++tagCount;
+ }
+ }
+ }
+
+private:
+ bool InSources;
+ bool InSource;
+ bool SkipThisClass;
+ std::vector<std::string> FilePaths;
+ typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector
+ FileLinesType;
+ cmCTest* CTest;
+ cmCTestCoverageHandlerContainer& Coverage;
+ std::string CurFileName;
+};
+
+cmParseCoberturaCoverage::cmParseCoberturaCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParseCoberturaCoverage::ReadCoverageXML(const char* xmlFile)
+{
+ cmParseCoberturaCoverage::XMLParser parser(this->CTest, this->Coverage);
+ parser.ParseFile(xmlFile);
+ return true;
+}
diff --git a/Source/CTest/cmParseCoberturaCoverage.h b/Source/CTest/cmParseCoberturaCoverage.h
new file mode 100644
index 0000000..4fa6d10
--- /dev/null
+++ b/Source/CTest/cmParseCoberturaCoverage.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmParseCoberturaCoverage_h
+#define cmParseCoberturaCoverage_h
+
+#include "cmCTestCoverageHandler.h"
+
+/** \class cmParsePythonCoverage
+ * \brief Parse coverage.py Python coverage information
+ *
+ * This class is used to parse the output of the coverage.py tool that
+ * is currently maintained by Ned Batchelder. That tool has a command
+ * that produces xml output in the format typically output by the common
+ * Java-based Cobertura coverage application. This helper class parses
+ * that XML file to fill the coverage-handler container.
+ */
+class cmParseCoberturaCoverage
+{
+public:
+ //! Create the coverage parser by passing in the coverage handler
+ //! container and the cmCTest object
+ cmParseCoberturaCoverage(cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest);
+
+ bool inSources;
+ bool inSource;
+ std::vector<std::string> filepaths;
+ //! Read the XML produced by running `coverage xml`
+ bool ReadCoverageXML(const char* xmlFile);
+
+private:
+ class XMLParser;
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+ std::string CurFileName;
+};
+
+#endif
diff --git a/Source/CTest/cmParseDelphiCoverage.cxx b/Source/CTest/cmParseDelphiCoverage.cxx
new file mode 100644
index 0000000..9d86ce9
--- /dev/null
+++ b/Source/CTest/cmParseDelphiCoverage.cxx
@@ -0,0 +1,225 @@
+#include "cmParseDelphiCoverage.h"
+
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <stdio.h>
+#include <stdlib.h>
+
+class cmParseDelphiCoverage::HTMLParser
+{
+public:
+ typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector
+ FileLinesType;
+ HTMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
+ : CTest(ctest)
+ , Coverage(cont)
+ {
+ }
+
+ virtual ~HTMLParser() {}
+
+ bool initializeDelphiFile(
+ std::string const& filename,
+ cmParseDelphiCoverage::HTMLParser::FileLinesType& coverageVector)
+ {
+ std::string line;
+ size_t comPos;
+ size_t semiPos;
+ bool blockComFlag = false;
+ bool lineComFlag = false;
+ std::vector<std::string> beginSet;
+ cmsys::ifstream in(filename.c_str());
+ if (!in) {
+ return false;
+ }
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ lineComFlag = false;
+ // Unique cases found in lines.
+ size_t beginPos = line.find("begin");
+
+ // Check that the begin is the first non-space string on the line
+ if ((beginPos == line.find_first_not_of(' ')) && beginPos != line.npos) {
+ beginSet.push_back("begin");
+ coverageVector.push_back(-1);
+ continue;
+ } else if (line.find('{') != line.npos) {
+ blockComFlag = true;
+ } else if (line.find('}') != line.npos) {
+ blockComFlag = false;
+ coverageVector.push_back(-1);
+ continue;
+ } else if ((line.find("end;") != line.npos) && !beginSet.empty()) {
+ beginSet.pop_back();
+ coverageVector.push_back(-1);
+ continue;
+ }
+
+ // This checks for comments after lines of code, finding the
+ // comment symbol after the ending semicolon.
+ comPos = line.find("//");
+ if (comPos != line.npos) {
+ semiPos = line.find(';');
+ if (comPos < semiPos) {
+ lineComFlag = true;
+ }
+ }
+ // Based up what was found, add a line to the coverageVector
+ if (!beginSet.empty() && line != "" && !blockComFlag && !lineComFlag) {
+ coverageVector.push_back(0);
+ } else {
+ coverageVector.push_back(-1);
+ }
+ }
+ return true;
+ }
+ bool ParseFile(const char* file)
+ {
+ std::string line = file;
+ std::string lineresult;
+ std::string lastroutine;
+ std::string filename;
+ std::string filelineoffset;
+ size_t afterLineNum = 0;
+ size_t lastoffset = 0;
+ size_t endcovpos = 0;
+ size_t endnamepos = 0;
+ size_t pos = 0;
+
+ /*
+ * This first 'while' section goes through the found HTML
+ * file name and attempts to capture the source file name
+ * which is set as part of the HTML file name: the name of
+ * the file is found in parenthesis '()'
+ *
+ * See test HTML file name: UTCovTest(UTCovTest.pas).html.
+ *
+ * Find the text inside each pair of parenthesis and check
+ * to see if it ends in '.pas'. If it can't be found,
+ * exit the function.
+ */
+ while (true) {
+ lastoffset = line.find('(', pos);
+ if (lastoffset == line.npos) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, endnamepos
+ << "File not found " << lastoffset << std::endl,
+ this->Coverage.Quiet);
+ return false;
+ }
+ endnamepos = line.find(')', lastoffset);
+ filename = line.substr(lastoffset + 1, (endnamepos - 1) - lastoffset);
+ if (filename.find(".pas") != filename.npos) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Coverage found for file: " << filename
+ << std::endl,
+ this->Coverage.Quiet);
+ break;
+ }
+ pos = lastoffset + 1;
+ }
+ /*
+ * Glob through the source directory for the
+ * file found above
+ */
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOff();
+ std::string glob = Coverage.SourceDir + "*/" + filename;
+ gl.FindFiles(glob);
+ std::vector<std::string> const& files = gl.GetFiles();
+ if (files.empty()) {
+ /*
+ * If that doesn't find any matching files
+ * return a failure.
+ */
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Unable to find file matching" << glob << std::endl,
+ this->Coverage.Quiet);
+ return false;
+ }
+ FileLinesType& coverageVector = this->Coverage.TotalCoverage[files[0]];
+
+ /*
+ * Initialize the file to have all code between 'begin' and
+ * 'end' tags marked as executable
+ */
+
+ this->initializeDelphiFile(files[0], coverageVector);
+
+ cmsys::ifstream in(file);
+ if (!in) {
+ return false;
+ }
+
+ /*
+ * Now read the HTML file, looking for the lines that have an
+ * "inline" in it. Then parse out the "class" value of that
+ * line to determine if the line is executed or not.
+ *
+ * Sample HTML line:
+ *
+ * <tr class="covered"><td>47</td><td><pre style="display:inline;">
+ * &nbsp;CheckEquals(1,2-1);</pre></td></tr>
+ *
+ */
+
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ if (line.find("inline") == line.npos) {
+ continue;
+ }
+
+ lastoffset = line.find("class=");
+ endcovpos = line.find('>', lastoffset);
+ lineresult = line.substr(lastoffset + 7, (endcovpos - 8) - lastoffset);
+
+ if (lineresult == "covered") {
+ afterLineNum = line.find('<', endcovpos + 5);
+ filelineoffset =
+ line.substr(endcovpos + 5, afterLineNum - (endcovpos + 5));
+ coverageVector[atoi(filelineoffset.c_str()) - 1] = 1;
+ }
+ }
+ return true;
+ }
+
+private:
+ cmCTest* CTest;
+ cmCTestCoverageHandlerContainer& Coverage;
+};
+
+cmParseDelphiCoverage::cmParseDelphiCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParseDelphiCoverage::LoadCoverageData(
+ std::vector<std::string> const& files)
+{
+ size_t i;
+ std::string path;
+ size_t numf = files.size();
+ for (i = 0; i < numf; i++) {
+ path = files[i];
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading HTML File " << path << std::endl,
+ this->Coverage.Quiet);
+ if (cmSystemTools::GetFilenameLastExtension(path) == ".html") {
+ if (!this->ReadDelphiHTML(path.c_str())) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool cmParseDelphiCoverage::ReadDelphiHTML(const char* file)
+{
+ cmParseDelphiCoverage::HTMLParser parser(this->CTest, this->Coverage);
+ parser.ParseFile(file);
+ return true;
+}
diff --git a/Source/CTest/cmParseDelphiCoverage.h b/Source/CTest/cmParseDelphiCoverage.h
new file mode 100644
index 0000000..c1c495c
--- /dev/null
+++ b/Source/CTest/cmParseDelphiCoverage.h
@@ -0,0 +1,41 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmParseDelphiCoverage_h
+#define cmParseDelphiCoverage_h
+
+#include "cmCTestCoverageHandler.h"
+
+/** \class cmParseDelphiCoverage
+ * \brief Parse Delphi coverage information
+ *
+ * This class is used to parse Delphi(Pascal) coverage information
+ * generated by the Delphi-Code-Coverage tool
+ *
+ * https://code.google.com/p/delphi-code-coverage/
+ */
+
+class cmParseDelphiCoverage
+{
+public:
+ cmParseDelphiCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+ bool LoadCoverageData(std::vector<std::string> const& files);
+ bool ReadDelphiHTML(const char* file);
+ // Read a single HTML file from output
+ bool ReadHTMLFile(const char* f);
+
+protected:
+ class HTMLParser;
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
+#endif
diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx
new file mode 100644
index 0000000..33ad839
--- /dev/null
+++ b/Source/CTest/cmParseGTMCoverage.cxx
@@ -0,0 +1,240 @@
+#include "cmParseGTMCoverage.h"
+
+#include "cmSystemTools.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <stdio.h>
+#include <stdlib.h>
+
+cmParseGTMCoverage::cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest)
+ : cmParseMumpsCoverage(cont, ctest)
+{
+}
+
+bool cmParseGTMCoverage::LoadCoverageData(const char* d)
+{
+ // load all the .mcov files in the specified directory
+ cmsys::Directory dir;
+ if (!dir.Load(d)) {
+ return false;
+ }
+ size_t numf;
+ unsigned int i;
+ numf = dir.GetNumberOfFiles();
+ for (i = 0; i < numf; i++) {
+ std::string file = dir.GetFile(i);
+ if (file != "." && file != ".." && !cmSystemTools::FileIsDirectory(file)) {
+ std::string path = d;
+ path += "/";
+ path += file;
+ if (cmSystemTools::GetFilenameLastExtension(path) == ".mcov") {
+ if (!this->ReadMCovFile(path.c_str())) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool cmParseGTMCoverage::ReadMCovFile(const char* file)
+{
+ cmsys::ifstream in(file);
+ if (!in) {
+ return false;
+ }
+ std::string line;
+ std::string lastfunction;
+ std::string lastroutine;
+ std::string lastpath;
+ int lastoffset = 0;
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ // only look at lines that have coverage data
+ if (line.find("^ZZCOVERAGE") == line.npos) {
+ continue;
+ }
+ std::string filepath;
+ std::string function;
+ std::string routine;
+ int linenumber = 0;
+ int count = 0;
+ this->ParseMCOVLine(line, routine, function, linenumber, count);
+ // skip this one
+ if (routine == "RSEL") {
+ continue;
+ }
+ // no need to search the file if we just did it
+ if (function == lastfunction && lastroutine == routine) {
+ if (!lastpath.empty()) {
+ this->Coverage.TotalCoverage[lastpath][lastoffset + linenumber] +=
+ count;
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Can not find mumps file : "
+ << lastroutine
+ << " referenced in this line of mcov data:\n"
+ "["
+ << line << "]\n");
+ }
+ continue;
+ }
+ // Find the full path to the file
+ bool found = this->FindMumpsFile(routine, filepath);
+ if (found) {
+ int lineoffset = 0;
+ if (this->FindFunctionInMumpsFile(filepath, function, lineoffset)) {
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector&
+ coverageVector = this->Coverage.TotalCoverage[filepath];
+ // This section accounts for lines that were previously marked
+ // as non-executable code (-1), if the parser comes back with
+ // a non-zero count, increase the count by 1 to push the line
+ // into the executable code set in addtion to the count found.
+ if (coverageVector[lineoffset + linenumber] == -1 && count > 0) {
+ coverageVector[lineoffset + linenumber] += count + 1;
+ } else {
+ coverageVector[lineoffset + linenumber] += count;
+ }
+ lastoffset = lineoffset;
+ }
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Can not find mumps file : "
+ << routine << " referenced in this line of mcov data:\n"
+ "["
+ << line << "]\n");
+ }
+ lastfunction = function;
+ lastroutine = routine;
+ lastpath = filepath;
+ }
+ return true;
+}
+
+bool cmParseGTMCoverage::FindFunctionInMumpsFile(std::string const& filepath,
+ std::string const& function,
+ int& lineoffset)
+{
+ cmsys::ifstream in(filepath.c_str());
+ if (!in) {
+ return false;
+ }
+ std::string line;
+ int linenum = 0;
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ std::string::size_type pos = line.find(function);
+ if (pos == 0) {
+ char nextchar = line[function.size()];
+ if (nextchar == ' ' || nextchar == '(' || nextchar == '\t') {
+ lineoffset = linenum;
+ return true;
+ }
+ }
+ if (pos == 1) {
+ char prevchar = line[0];
+ char nextchar = line[function.size() + 1];
+ if (prevchar == '%' && (nextchar == ' ' || nextchar == '(')) {
+ lineoffset = linenum;
+ return true;
+ }
+ }
+ linenum++; // move to next line count
+ }
+ lineoffset = 0;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Could not find entry point : "
+ << function << " in " << filepath << "\n");
+ return false;
+}
+
+bool cmParseGTMCoverage::ParseMCOVLine(std::string const& line,
+ std::string& routine,
+ std::string& function, int& linenumber,
+ int& count)
+{
+ // this method parses lines from the .mcov file
+ // each line has ^COVERAGE(...) in it, and there
+ // are several varients of coverage lines:
+ //
+ // ^COVERAGE("DIC11","PR1",0)="2:0:0:0"
+ // ( file , entry, line ) = "number_executed:timing_info"
+ // ^COVERAGE("%RSEL","SRC")="1:0:0:0"
+ // ( file , entry ) = "number_executed:timing_info"
+ // ^COVERAGE("%RSEL","init",8,"FOR_LOOP",1)=1
+ // ( file , entry, line, IGNORE ) =number_executed
+ std::vector<std::string> args;
+ std::string::size_type pos = line.find('(', 0);
+ // if no ( is found, then return line has no coverage
+ if (pos == std::string::npos) {
+ return false;
+ }
+ std::string arg;
+ bool done = false;
+ // separate out all of the comma separated arguments found
+ // in the COVERAGE(...) line
+ while (line[pos] && !done) {
+ // save the char we are looking at
+ char cur = line[pos];
+ // , or ) means end of argument
+ if (cur == ',' || cur == ')') {
+ // save the argument into the argument vector
+ args.push_back(arg);
+ // start on a new argument
+ arg = "";
+ // if we are at the end of the ), then finish while loop
+ if (cur == ')') {
+ done = true;
+ }
+ } else {
+ // all chars except ", (, and % get stored in the arg string
+ if (cur != '\"' && cur != '(' && cur != '%') {
+ arg.append(1, line[pos]);
+ }
+ }
+ // move to next char
+ pos++;
+ }
+ // now parse the right hand side of the =
+ pos = line.find('=');
+ // no = found, this is an error
+ if (pos == line.npos) {
+ return false;
+ }
+ pos++; // move past =
+
+ // if the next positing is not a ", then this is a
+ // COVERAGE(..)=count line and turn the rest of the string
+ // past the = into an integer and set it to count
+ if (line[pos] != '\"') {
+ count = atoi(line.substr(pos).c_str());
+ } else {
+ // this means line[pos] is a ", and we have a
+ // COVERAGE(...)="1:0:0:0" type of line
+ pos++; // move past "
+ // find the first : past the "
+ std::string::size_type pos2 = line.find(':', pos);
+ // turn the string between the " and the first : into an integer
+ // and set it to count
+ count = atoi(line.substr(pos, pos2 - pos).c_str());
+ }
+ // less then two arguments is an error
+ if (args.size() < 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Error parsing mcov line: ["
+ << line << "]\n");
+ return false;
+ }
+ routine = args[0]; // the routine is the first argument
+ function = args[1]; // the function in the routine is the second
+ // in the two argument only format
+ // ^COVERAGE("%RSEL","SRC"), the line offset is 0
+ if (args.size() == 2) {
+ // To avoid double counting of line 0 of each entry point,
+ // Don't count the lines that do not give an explicit line
+ // number.
+ routine = "";
+ function = "";
+ } else {
+ // this is the format for this line
+ // ^COVERAGE("%RSEL","SRC",count)
+ linenumber = atoi(args[2].c_str());
+ }
+ return true;
+}
diff --git a/Source/CTest/cmParseGTMCoverage.h b/Source/CTest/cmParseGTMCoverage.h
new file mode 100644
index 0000000..4188689
--- /dev/null
+++ b/Source/CTest/cmParseGTMCoverage.h
@@ -0,0 +1,44 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmParseGTMCoverage_h
+#define cmParseGTMCoverage_h
+
+#include "cmParseMumpsCoverage.h"
+
+/** \class cmParseGTMCoverage
+ * \brief Parse GTM coverage information
+ *
+ * This class is used to parse GTM coverage information for
+ * mumps.
+ */
+class cmParseGTMCoverage : public cmParseMumpsCoverage
+{
+public:
+ cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+
+protected:
+ // implement virtual from parent
+ bool LoadCoverageData(const char* dir) CM_OVERRIDE;
+ // Read a single mcov file
+ bool ReadMCovFile(const char* f);
+ // find out what line in a mumps file (filepath) the given entry point
+ // or function is. lineoffset is set by this method.
+ bool FindFunctionInMumpsFile(std::string const& filepath,
+ std::string const& function, int& lineoffset);
+ // parse a line from a .mcov file, and fill in the
+ // routine, function, linenumber and coverage count
+ bool ParseMCOVLine(std::string const& line, std::string& routine,
+ std::string& function, int& linenumber, int& count);
+};
+
+#endif
diff --git a/Source/CTest/cmParseJacocoCoverage.cxx b/Source/CTest/cmParseJacocoCoverage.cxx
new file mode 100644
index 0000000..9325812
--- /dev/null
+++ b/Source/CTest/cmParseJacocoCoverage.cxx
@@ -0,0 +1,179 @@
+#include "cmParseJacocoCoverage.h"
+
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <stdio.h>
+#include <stdlib.h>
+
+class cmParseJacocoCoverage::XMLParser : public cmXMLParser
+{
+public:
+ XMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
+ : CTest(ctest)
+ , Coverage(cont)
+ {
+ this->FilePath = "";
+ this->PackagePath = "";
+ this->PackageName = "";
+ }
+
+ ~XMLParser() CM_OVERRIDE {}
+
+protected:
+ void EndElement(const std::string&) CM_OVERRIDE {}
+
+ void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
+ {
+ if (name == "package") {
+ this->PackageName = atts[1];
+ this->PackagePath = "";
+ } else if (name == "sourcefile") {
+ std::string fileName = atts[1];
+
+ if (this->PackagePath == "") {
+ if (!this->FindPackagePath(fileName)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find file: "
+ << this->PackageName << "/" << fileName << std::endl);
+ this->Coverage.Error++;
+ return;
+ }
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading file: " << fileName << std::endl,
+ this->Coverage.Quiet);
+
+ this->FilePath = this->PackagePath + "/" + fileName;
+ cmsys::ifstream fin(this->FilePath.c_str());
+ if (!fin) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Jacoco Coverage: Error opening " << this->FilePath
+ << std::endl);
+ }
+ std::string line;
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->FilePath];
+ if (fin) {
+ curFileLines.push_back(-1);
+ }
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ curFileLines.push_back(-1);
+ }
+ } else if (name == "line") {
+ int tagCount = 0;
+ int nr = -1;
+ int ci = -1;
+ while (true) {
+ if (strcmp(atts[tagCount], "ci") == 0) {
+ ci = atoi(atts[tagCount + 1]);
+ } else if (strcmp(atts[tagCount], "nr") == 0) {
+ nr = atoi(atts[tagCount + 1]);
+ }
+ if (ci > -1 && nr > 0) {
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->FilePath];
+ if (!curFileLines.empty()) {
+ curFileLines[nr - 1] = ci;
+ }
+ break;
+ }
+ ++tagCount;
+ }
+ }
+ }
+
+ virtual bool FindPackagePath(std::string const& fileName)
+ {
+ // Search for the source file in the source directory.
+ if (this->PackagePathFound(fileName, this->Coverage.SourceDir)) {
+ return true;
+ }
+
+ // If not found there, check the binary directory.
+ if (this->PackagePathFound(fileName, this->Coverage.BinaryDir)) {
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool PackagePathFound(std::string const& fileName,
+ std::string const& baseDir)
+ {
+ // Search for the file in the baseDir and its subdirectories.
+ std::string packageGlob = baseDir;
+ packageGlob += "/";
+ packageGlob += fileName;
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOn();
+ gl.FindFiles(packageGlob);
+ std::vector<std::string> const& files = gl.GetFiles();
+ if (files.empty()) {
+ return false;
+ }
+
+ // Check if any of the locations found match our package.
+ for (std::vector<std::string>::const_iterator fi = files.begin();
+ fi != files.end(); ++fi) {
+ std::string dir = cmsys::SystemTools::GetParentDirectory(*fi);
+ if (cmsys::SystemTools::StringEndsWith(dir, this->PackageName.c_str())) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found package directory for " << fileName << ": "
+ << dir << std::endl,
+ this->Coverage.Quiet);
+ this->PackagePath = dir;
+ return true;
+ }
+ }
+ return false;
+ }
+
+private:
+ std::string FilePath;
+ std::string PackagePath;
+ std::string PackageName;
+ typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector
+ FileLinesType;
+ cmCTest* CTest;
+ cmCTestCoverageHandlerContainer& Coverage;
+};
+
+cmParseJacocoCoverage::cmParseJacocoCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParseJacocoCoverage::LoadCoverageData(
+ std::vector<std::string> const& files)
+{
+ // load all the jacoco.xml files in the source directory
+ cmsys::Directory dir;
+ size_t i;
+ std::string path;
+ size_t numf = files.size();
+ for (i = 0; i < numf; i++) {
+ path = files[i];
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading XML File " << path << std::endl,
+ this->Coverage.Quiet);
+ if (cmSystemTools::GetFilenameLastExtension(path) == ".xml") {
+ if (!this->ReadJacocoXML(path.c_str())) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool cmParseJacocoCoverage::ReadJacocoXML(const char* file)
+{
+ cmParseJacocoCoverage::XMLParser parser(this->CTest, this->Coverage);
+ parser.ParseFile(file);
+ return true;
+}
diff --git a/Source/CTest/cmParseJacocoCoverage.h b/Source/CTest/cmParseJacocoCoverage.h
new file mode 100644
index 0000000..bcd472e
--- /dev/null
+++ b/Source/CTest/cmParseJacocoCoverage.h
@@ -0,0 +1,55 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmParseJacocoCoverage_h
+#define cmParseJacocoCoverage_h
+
+#include "cmCTestCoverageHandler.h"
+
+/** \class cmParseJacocoCoverage
+ * \brief Parse JaCoCO coverage information
+ *
+ * This class is used to parse coverage information for
+ * java using the JaCoCo tool:
+ *
+ * http://www.eclemma.org/jacoco/trunk/index.html
+ */
+class cmParseJacocoCoverage
+{
+public:
+ cmParseJacocoCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+ bool LoadCoverageData(std::vector<std::string> const& files);
+
+ std::string PackageName;
+ std::string FileName;
+ std::string ModuleName;
+ std::string CurFileName;
+
+private:
+ // implement virtual from parent
+ // remove files with no coverage
+ void RemoveUnCoveredFiles();
+ // Read a single mcov file
+ bool ReadJacocoXML(const char* f);
+ // split a string based on ,
+ bool SplitString(std::vector<std::string>& args, std::string const& line);
+ bool FindJavaFile(std::string const& routine, std::string& filepath);
+ void InitializeJavaFile(std::string& file);
+ bool LoadSource(std::string d);
+
+ class XMLParser;
+ std::map<std::string, std::string> RoutineToDirectory;
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
+
+#endif
diff --git a/Source/CTest/cmParseMumpsCoverage.cxx b/Source/CTest/cmParseMumpsCoverage.cxx
new file mode 100644
index 0000000..d786d79
--- /dev/null
+++ b/Source/CTest/cmParseMumpsCoverage.cxx
@@ -0,0 +1,144 @@
+#include "cmParseGTMCoverage.h"
+
+#include "cmSystemTools.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <stdio.h>
+#include <stdlib.h>
+
+cmParseMumpsCoverage::cmParseMumpsCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+cmParseMumpsCoverage::~cmParseMumpsCoverage()
+{
+}
+
+bool cmParseMumpsCoverage::ReadCoverageFile(const char* file)
+{
+ // Read the gtm_coverage.mcov file, that has two lines of data:
+ // packages:/full/path/to/Vista/Packages
+ // coverage_dir:/full/path/to/dir/with/*.mcov
+ cmsys::ifstream in(file);
+ if (!in) {
+ return false;
+ }
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ std::string::size_type pos = line.find(':', 0);
+ std::string packages;
+ if (pos != std::string::npos) {
+ std::string type = line.substr(0, pos);
+ std::string path = line.substr(pos + 1);
+ if (type == "packages") {
+ this->LoadPackages(path.c_str());
+ } else if (type == "coverage_dir") {
+ this->LoadCoverageData(path.c_str());
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Parse Error in Mumps coverage file :\n"
+ << file << "\ntype: [" << type << "]\npath:[" << path
+ << "]\n"
+ "input line: ["
+ << line << "]\n");
+ }
+ }
+ }
+ return true;
+}
+
+void cmParseMumpsCoverage::InitializeMumpsFile(std::string& file)
+{
+ // initialize the coverage information for a given mumps file
+ cmsys::ifstream in(file.c_str());
+ if (!in) {
+ return;
+ }
+ std::string line;
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector =
+ this->Coverage.TotalCoverage[file];
+ if (!cmSystemTools::GetLineFromStream(in, line)) {
+ return;
+ }
+ // first line of a .m file can never be run
+ coverageVector.push_back(-1);
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ // putting in a 0 for a line means it is executable code
+ // putting in a -1 for a line means it is not executable code
+ int val = -1; // assume line is not executable
+ bool found = false;
+ std::string::size_type i = 0;
+ // (1) Search for the first whitespace or semicolon character on a line.
+ // This will skip over labels if the line starts with one, or will simply
+ // be the first character on the line for non-label lines.
+ for (; i < line.size(); ++i) {
+ if (line[i] == ' ' || line[i] == '\t' || line[i] == ';') {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ // (2) If the first character found above is whitespace or a period
+ // then continue the search for the first following non-whitespace
+ // character.
+ if (line[i] == ' ' || line[i] == '\t') {
+ while (i < line.size() &&
+ (line[i] == ' ' || line[i] == '\t' || line[i] == '.')) {
+ i++;
+ }
+ }
+ // (3) If the character found is not a semicolon then the line counts for
+ // coverage.
+ if (i < line.size() && line[i] != ';') {
+ val = 0;
+ }
+ }
+ coverageVector.push_back(val);
+ }
+}
+
+bool cmParseMumpsCoverage::LoadPackages(const char* d)
+{
+ cmsys::Glob glob;
+ glob.RecurseOn();
+ std::string pat = d;
+ pat += "/*.m";
+ glob.FindFiles(pat);
+ std::vector<std::string>& files = glob.GetFiles();
+ std::vector<std::string>::iterator fileIt;
+ for (fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
+ std::string name = cmSystemTools::GetFilenameName(*fileIt);
+ this->RoutineToDirectory[name.substr(0, name.size() - 2)] = *fileIt;
+ // initialze each file, this is left out until CDash is fixed
+ // to handle large numbers of files
+ this->InitializeMumpsFile(*fileIt);
+ }
+ return true;
+}
+
+bool cmParseMumpsCoverage::FindMumpsFile(std::string const& routine,
+ std::string& filepath)
+{
+ std::map<std::string, std::string>::iterator i =
+ this->RoutineToDirectory.find(routine);
+ if (i != this->RoutineToDirectory.end()) {
+ filepath = i->second;
+ return true;
+ } else {
+ // try some alternate names
+ const char* tryname[] = { "GUX", "GTM", "ONT", CM_NULLPTR };
+ for (int k = 0; tryname[k] != CM_NULLPTR; k++) {
+ std::string routine2 = routine + tryname[k];
+ i = this->RoutineToDirectory.find(routine2);
+ if (i != this->RoutineToDirectory.end()) {
+ filepath = i->second;
+ return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/Source/CTest/cmParseMumpsCoverage.h b/Source/CTest/cmParseMumpsCoverage.h
new file mode 100644
index 0000000..3761ba6
--- /dev/null
+++ b/Source/CTest/cmParseMumpsCoverage.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmParseMumpsCoverage_h
+#define cmParseMumpsCoverage_h
+
+#include "cmCTestCoverageHandler.h"
+
+/** \class cmParseMumpsCoverage
+ * \brief Parse Mumps coverage information
+ *
+ * This class is used as the base class for Mumps coverage
+ * parsing.
+ */
+class cmParseMumpsCoverage
+{
+public:
+ cmParseMumpsCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+ virtual ~cmParseMumpsCoverage();
+ // This is the toplevel coverage file locating the coverage files
+ // and the mumps source code package tree.
+ bool ReadCoverageFile(const char* file);
+
+protected:
+ // sub classes will use this to
+ // load all coverage files found in the given directory
+ virtual bool LoadCoverageData(const char* d) = 0;
+ // search the package directory for mumps files and fill
+ // in the RoutineToDirectory map
+ bool LoadPackages(const char* dir);
+ // initialize the coverage information for a single mumps file
+ void InitializeMumpsFile(std::string& file);
+ // Find mumps file for routine
+ bool FindMumpsFile(std::string const& routine, std::string& filepath);
+
+protected:
+ std::map<std::string, std::string> RoutineToDirectory;
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
+
+#endif
diff --git a/Source/CTest/cmParsePHPCoverage.cxx b/Source/CTest/cmParsePHPCoverage.cxx
new file mode 100644
index 0000000..5ec2718
--- /dev/null
+++ b/Source/CTest/cmParsePHPCoverage.cxx
@@ -0,0 +1,216 @@
+#include "cmParsePHPCoverage.h"
+
+#include "cmSystemTools.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+
+/*
+ To setup coverage for php.
+
+ - edit php.ini to add auto prepend and append php files from phpunit
+ auto_prepend_file =
+ auto_append_file =
+ - run the tests
+ - run this program on all the files in c:/tmp
+
+*/
+
+cmParsePHPCoverage::cmParsePHPCoverage(cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParsePHPCoverage::ReadUntil(std::istream& in, char until)
+{
+ char c = 0;
+ while (in.get(c) && c != until) {
+ }
+ return c == until;
+}
+bool cmParsePHPCoverage::ReadCoverageArray(std::istream& in,
+ std::string const& fileName)
+{
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector =
+ this->Coverage.TotalCoverage[fileName];
+
+ char c;
+ char buf[4];
+ in.read(buf, 3);
+ buf[3] = 0;
+ if (strcmp(buf, ";a:") != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read start of coverage array, found : " << buf
+ << "\n");
+ return false;
+ }
+ int size = 0;
+ if (!this->ReadInt(in, size)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read size ");
+ return false;
+ }
+ if (!in.get(c) && c == '{') {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read open {\n");
+ return false;
+ }
+ for (int i = 0; i < size; i++) {
+ this->ReadUntil(in, ':');
+ int line = 0;
+ this->ReadInt(in, line);
+ // ok xdebug may have a bug here
+ // it seems to be 1 based but often times
+ // seems to have a 0'th line.
+ line--;
+ if (line < 0) {
+ line = 0;
+ }
+ this->ReadUntil(in, ':');
+ int value = 0;
+ this->ReadInt(in, value);
+ // make sure the vector is the right size and is
+ // initialized with -1 for each line
+ while (coverageVector.size() <= static_cast<size_t>(line)) {
+ coverageVector.push_back(-1);
+ }
+ // if value is less than 0, set it to zero
+ // TODO figure out the difference between
+ // -1 and -2 in xdebug coverage?? For now
+ // assume less than 0 is just not covered
+ // CDash expects -1 for non executable code (like comments)
+ // and 0 for uncovered code, and a positive value
+ // for number of times a line was executed
+ if (value < 0) {
+ value = 0;
+ }
+ // if unset then set it to value
+ if (coverageVector[line] == -1) {
+ coverageVector[line] = value;
+ }
+ // otherwise increment by value
+ else {
+ coverageVector[line] += value;
+ }
+ }
+ return true;
+}
+
+bool cmParsePHPCoverage::ReadInt(std::istream& in, int& v)
+{
+ std::string s;
+ char c = 0;
+ while (in.get(c) && c != ':' && c != ';') {
+ s += c;
+ }
+ v = atoi(s.c_str());
+ return true;
+}
+
+bool cmParsePHPCoverage::ReadArraySize(std::istream& in, int& size)
+{
+ char c = 0;
+ in.get(c);
+ if (c != 'a') {
+ return false;
+ }
+ if (in.get(c) && c == ':') {
+ if (this->ReadInt(in, size)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmParsePHPCoverage::ReadFileInformation(std::istream& in)
+{
+ char buf[4];
+ in.read(buf, 2);
+ buf[2] = 0;
+ if (strcmp(buf, "s:") != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read start of file info found: [" << buf << "]\n");
+ return false;
+ }
+ char c;
+ int size = 0;
+ if (this->ReadInt(in, size)) {
+ size++; // add one for null termination
+ char* s = new char[size + 1];
+ // read open quote
+ if (in.get(c) && c != '"') {
+ delete[] s;
+ return false;
+ }
+ // read the string data
+ in.read(s, size - 1);
+ s[size - 1] = 0;
+ std::string fileName = s;
+ delete[] s;
+ // read close quote
+ if (in.get(c) && c != '"') {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read close quote\n"
+ << "read [" << c << "]\n");
+ return false;
+ }
+ if (!this->ReadCoverageArray(in, fileName)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read coverage array for file: " << fileName
+ << "\n");
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool cmParsePHPCoverage::ReadPHPData(const char* file)
+{
+ cmsys::ifstream in(file);
+ if (!in) {
+ return false;
+ }
+ int size = 0;
+ this->ReadArraySize(in, size);
+ char c = 0;
+ in.get(c);
+ if (c != '{') {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read open array\n");
+ return false;
+ }
+ for (int i = 0; i < size; i++) {
+ if (!this->ReadFileInformation(in)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Failed to read file #" << i
+ << "\n");
+ return false;
+ }
+ in.get(c);
+ if (c != '}') {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read close array\n");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmParsePHPCoverage::ReadPHPCoverageDirectory(const char* d)
+{
+ cmsys::Directory dir;
+ if (!dir.Load(d)) {
+ return false;
+ }
+ size_t numf;
+ unsigned int i;
+ numf = dir.GetNumberOfFiles();
+ for (i = 0; i < numf; i++) {
+ std::string file = dir.GetFile(i);
+ if (file != "." && file != ".." && !cmSystemTools::FileIsDirectory(file)) {
+ std::string path = d;
+ path += "/";
+ path += file;
+ if (!this->ReadPHPData(path.c_str())) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
diff --git a/Source/CTest/cmParsePHPCoverage.h b/Source/CTest/cmParsePHPCoverage.h
new file mode 100644
index 0000000..72f9129
--- /dev/null
+++ b/Source/CTest/cmParsePHPCoverage.h
@@ -0,0 +1,43 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmParsePHPCoverage_h
+#define cmParsePHPCoverage_h
+
+#include "cmCTestCoverageHandler.h"
+
+/** \class cmParsePHPCoverage
+ * \brief Parse xdebug PHP coverage information
+ *
+ * This class is used to parse php coverage information produced
+ * by xdebug. The data is stored as a php dump of the array
+ * return by xdebug coverage. It is an array of arrays.
+ */
+class cmParsePHPCoverage
+{
+public:
+ cmParsePHPCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+ bool ReadPHPCoverageDirectory(const char* dir);
+ void PrintCoverage();
+
+private:
+ bool ReadPHPData(const char* file);
+ bool ReadArraySize(std::istream& in, int& size);
+ bool ReadFileInformation(std::istream& in);
+ bool ReadInt(std::istream& in, int& v);
+ bool ReadCoverageArray(std::istream& in, std::string const&);
+ bool ReadUntil(std::istream& in, char until);
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
+
+#endif
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
new file mode 100644
index 0000000..92fe642
--- /dev/null
+++ b/Source/CTest/cmProcess.cxx
@@ -0,0 +1,241 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include <cmProcess.h>
+
+#include <cmSystemTools.h>
+
+cmProcess::cmProcess()
+{
+ this->Process = CM_NULLPTR;
+ this->Timeout = 0;
+ this->TotalTime = 0;
+ this->ExitValue = 0;
+ this->Id = 0;
+ this->StartTime = 0;
+}
+
+cmProcess::~cmProcess()
+{
+ cmsysProcess_Delete(this->Process);
+}
+void cmProcess::SetCommand(const char* command)
+{
+ this->Command = command;
+}
+
+void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
+{
+ this->Arguments = args;
+}
+
+bool cmProcess::StartProcess()
+{
+ if (this->Command.empty()) {
+ return false;
+ }
+ this->StartTime = cmSystemTools::GetTime();
+ this->ProcessArgs.clear();
+ // put the command as arg0
+ this->ProcessArgs.push_back(this->Command.c_str());
+ // now put the command arguments in
+ for (std::vector<std::string>::iterator i = this->Arguments.begin();
+ i != this->Arguments.end(); ++i) {
+ this->ProcessArgs.push_back(i->c_str());
+ }
+ this->ProcessArgs.push_back(CM_NULLPTR); // null terminate the list
+ this->Process = cmsysProcess_New();
+ cmsysProcess_SetCommand(this->Process, &*this->ProcessArgs.begin());
+ if (!this->WorkingDirectory.empty()) {
+ cmsysProcess_SetWorkingDirectory(this->Process,
+ this->WorkingDirectory.c_str());
+ }
+ cmsysProcess_SetTimeout(this->Process, this->Timeout);
+ cmsysProcess_SetOption(this->Process, cmsysProcess_Option_MergeOutput, 1);
+ cmsysProcess_Execute(this->Process);
+ return (cmsysProcess_GetState(this->Process) ==
+ cmsysProcess_State_Executing);
+}
+
+bool cmProcess::Buffer::GetLine(std::string& line)
+{
+ // Scan for the next newline.
+ 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;
+ size_type length = this->Last - this->First;
+ while (length && text[length - 1] == '\r') {
+ length--;
+ }
+ line.assign(text, length);
+
+ // Start a new range for the next line.
+ ++this->Last;
+ this->First = Last;
+
+ // Return the line extracted.
+ return true;
+ }
+ }
+
+ // Available data have been exhausted without a newline.
+ if (this->First != 0) {
+ // Move the partial line to the beginning of the buffer.
+ this->erase(this->begin(), this->begin() + this->First);
+ this->First = 0;
+ this->Last = this->size();
+ }
+ return false;
+}
+
+bool cmProcess::Buffer::GetLast(std::string& line)
+{
+ // Return the partial last line, if any.
+ if (!this->empty()) {
+ line.assign(&*this->begin(), this->size());
+ this->First = this->Last = 0;
+ this->clear();
+ return true;
+ }
+ return false;
+}
+
+int cmProcess::GetNextOutputLine(std::string& line, double timeout)
+{
+ for (;;) {
+ // Look for lines already buffered.
+ if (this->Output.GetLine(line)) {
+ return cmsysProcess_Pipe_STDOUT;
+ }
+
+ // Check for more data from the process.
+ char* data;
+ int length;
+ int p = cmsysProcess_WaitForData(this->Process, &data, &length, &timeout);
+ if (p == cmsysProcess_Pipe_Timeout) {
+ return cmsysProcess_Pipe_Timeout;
+ } else if (p == cmsysProcess_Pipe_STDOUT) {
+ this->Output.insert(this->Output.end(), data, data + length);
+ } else // p == cmsysProcess_Pipe_None
+ {
+ // The process will provide no more data.
+ break;
+ }
+ }
+
+ // Look for partial last lines.
+ if (this->Output.GetLast(line)) {
+ return cmsysProcess_Pipe_STDOUT;
+ }
+
+ // No more data. Wait for process exit.
+ if (!cmsysProcess_WaitForExit(this->Process, &timeout)) {
+ return cmsysProcess_Pipe_Timeout;
+ }
+
+ // Record exit information.
+ this->ExitValue = cmsysProcess_GetExitValue(this->Process);
+ this->TotalTime = cmSystemTools::GetTime() - this->StartTime;
+ // Because of a processor clock scew the runtime may become slightly
+ // negative. If someone changed the system clock while the process was
+ // running this may be even more. Make sure not to report a negative
+ // duration here.
+ if (this->TotalTime <= 0.0) {
+ this->TotalTime = 0.0;
+ }
+ // std::cerr << "Time to run: " << this->TotalTime << "\n";
+ return cmsysProcess_Pipe_None;
+}
+
+// return the process status
+int cmProcess::GetProcessStatus()
+{
+ if (!this->Process) {
+ return cmsysProcess_State_Exited;
+ }
+ return cmsysProcess_GetState(this->Process);
+}
+
+int cmProcess::ReportStatus()
+{
+ int result = 1;
+ switch (cmsysProcess_GetState(this->Process)) {
+ case cmsysProcess_State_Starting: {
+ std::cerr << "cmProcess: Never started " << this->Command
+ << " process.\n";
+ } break;
+ case cmsysProcess_State_Error: {
+ std::cerr << "cmProcess: Error executing " << this->Command
+ << " process: " << cmsysProcess_GetErrorString(this->Process)
+ << "\n";
+ } break;
+ case cmsysProcess_State_Exception: {
+ std::cerr << "cmProcess: " << this->Command
+ << " process exited with an exception: ";
+ switch (cmsysProcess_GetExitException(this->Process)) {
+ case cmsysProcess_Exception_None: {
+ std::cerr << "None";
+ } break;
+ case cmsysProcess_Exception_Fault: {
+ std::cerr << "Segmentation fault";
+ } break;
+ case cmsysProcess_Exception_Illegal: {
+ std::cerr << "Illegal instruction";
+ } break;
+ case cmsysProcess_Exception_Interrupt: {
+ std::cerr << "Interrupted by user";
+ } break;
+ case cmsysProcess_Exception_Numerical: {
+ std::cerr << "Numerical exception";
+ } break;
+ case cmsysProcess_Exception_Other: {
+ std::cerr << "Unknown";
+ } break;
+ }
+ std::cerr << "\n";
+ } break;
+ case cmsysProcess_State_Executing: {
+ std::cerr << "cmProcess: Never terminated " << this->Command
+ << " process.\n";
+ } break;
+ case cmsysProcess_State_Exited: {
+ result = cmsysProcess_GetExitValue(this->Process);
+ std::cerr << "cmProcess: " << this->Command
+ << " process exited with code " << result << "\n";
+ } break;
+ case cmsysProcess_State_Expired: {
+ std::cerr << "cmProcess: killed " << this->Command
+ << " process due to timeout.\n";
+ } break;
+ case cmsysProcess_State_Killed: {
+ std::cerr << "cmProcess: killed " << this->Command << " process.\n";
+ } break;
+ }
+ return result;
+}
+
+void cmProcess::ChangeTimeout(double t)
+{
+ this->Timeout = t;
+ cmsysProcess_SetTimeout(this->Process, this->Timeout);
+}
+
+void cmProcess::ResetStartTime()
+{
+ cmsysProcess_ResetStartTime(this->Process);
+}
+
+int cmProcess::GetExitException()
+{
+ return cmsysProcess_GetExitException(this->Process);
+}
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
new file mode 100644
index 0000000..d5e2721
--- /dev/null
+++ b/Source/CTest/cmProcess.h
@@ -0,0 +1,86 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmProcess_h
+#define cmProcess_h
+
+#include "cmStandardIncludes.h"
+
+#include <cmsys/Process.h>
+
+/** \class cmProcess
+ * \brief run a process with c++
+ *
+ * cmProcess wraps the kwsys process stuff in a c++ class.
+ */
+class cmProcess
+{
+public:
+ cmProcess();
+ ~cmProcess();
+ const char* GetCommand() { return this->Command.c_str(); }
+ void SetCommand(const char* command);
+ void SetCommandArguments(std::vector<std::string> const& arg);
+ void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; }
+ void SetTimeout(double t) { this->Timeout = t; }
+ void ChangeTimeout(double t);
+ void ResetStartTime();
+ // Return true if the process starts
+ bool StartProcess();
+
+ // return the process status
+ int GetProcessStatus();
+ // Report the status of the program
+ int ReportStatus();
+ int GetId() { return this->Id; }
+ void SetId(int id) { this->Id = id; }
+ int GetExitValue() { return this->ExitValue; }
+ double GetTotalTime() { return this->TotalTime; }
+ int GetExitException();
+ /**
+ * Read one line of output but block for no more than timeout.
+ * Returns:
+ * cmsysProcess_Pipe_None = Process terminated and all output read
+ * cmsysProcess_Pipe_STDOUT = Line came from stdout or stderr
+ * cmsysProcess_Pipe_Timeout = Timeout expired while waiting
+ */
+ int GetNextOutputLine(std::string& line, double timeout);
+
+private:
+ double Timeout;
+ double StartTime;
+ double TotalTime;
+ cmsysProcess* Process;
+ class Buffer : public std::vector<char>
+ {
+ // Half-open index range of partial line already scanned.
+ size_type First;
+ size_type Last;
+
+ public:
+ Buffer()
+ : First(0)
+ , Last(0)
+ {
+ }
+ bool GetLine(std::string& line);
+ bool GetLast(std::string& line);
+ };
+ Buffer Output;
+ std::string Command;
+ std::string WorkingDirectory;
+ std::vector<std::string> Arguments;
+ std::vector<const char*> ProcessArgs;
+ int Id;
+ int ExitValue;
+};
+
+#endif
diff --git a/Source/Checks/cm_c11_thread_local.c b/Source/Checks/cm_c11_thread_local.c
new file mode 100644
index 0000000..bdf91aa
--- /dev/null
+++ b/Source/Checks/cm_c11_thread_local.c
@@ -0,0 +1,5 @@
+_Thread_local int i = 42;
+int main(void)
+{
+ return 0;
+}
diff --git a/Source/Checks/cm_c11_thread_local.cmake b/Source/Checks/cm_c11_thread_local.cmake
new file mode 100644
index 0000000..6b8d10b
--- /dev/null
+++ b/Source/Checks/cm_c11_thread_local.cmake
@@ -0,0 +1,33 @@
+set(CMake_C11_THREAD_LOCAL_BROKEN 0)
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_C11_STANDARD_COMPILE_OPTION)
+ if(NOT DEFINED CMake_C11_THREAD_LOCAL_WORKS)
+ message(STATUS "Checking if compiler supports C11 _Thread_local")
+ try_compile(CMake_C11_THREAD_LOCAL_WORKS
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_LIST_DIR}/cm_c11_thread_local.c
+ CMAKE_FLAGS -DCMAKE_C_STANDARD=11
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if(CMake_C11_THREAD_LOCAL_WORKS AND "${OUTPUT}" MATCHES "error: expected '=', ',', ';', 'asm' or '__attribute__' before 'int'")
+ set_property(CACHE CMake_C11_THREAD_LOCAL_WORKS PROPERTY VALUE 0)
+ endif()
+ if(CMake_C11_THREAD_LOCAL_WORKS)
+ message(STATUS "Checking if compiler supports C11 _Thread_local - yes")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if compiler supports C11 _Thread_local passed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ else()
+ message(STATUS "Checking if compiler supports C11 _Thread_local - no")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if compiler supports C11 _Thread_local failed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ endif()
+ endif()
+ if(NOT CMake_C11_THREAD_LOCAL_WORKS)
+ set(CMake_C11_THREAD_LOCAL_BROKEN 1)
+ endif()
+endif()
diff --git a/Source/Checks/cm_cxx14_cstdio.cmake b/Source/Checks/cm_cxx14_cstdio.cmake
new file mode 100644
index 0000000..73f7e2e
--- /dev/null
+++ b/Source/Checks/cm_cxx14_cstdio.cmake
@@ -0,0 +1,33 @@
+set(CMake_CXX14_CSTDIO_BROKEN 0)
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND CMAKE_CXX14_STANDARD_COMPILE_OPTION)
+ if(NOT DEFINED CMake_CXX14_CSTDIO_WORKS)
+ message(STATUS "Checking if compiler supports C++14 cstdio")
+ try_compile(CMake_CXX14_CSTDIO_WORKS
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_LIST_DIR}/cm_cxx14_cstdio.cpp
+ CMAKE_FLAGS -DCMAKE_CXX_STANDARD=14
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if(CMake_CXX14_CSTDIO_WORKS AND "${OUTPUT}" MATCHES "error: no member named.*gets.*in the global namespace")
+ set_property(CACHE CMake_CXX14_CSTDIO_WORKS PROPERTY VALUE 0)
+ endif()
+ if(CMake_CXX14_CSTDIO_WORKS)
+ message(STATUS "Checking if compiler supports C++14 cstdio - yes")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if compiler supports C++14 cstdio passed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ else()
+ message(STATUS "Checking if compiler supports C++14 cstdio - no")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if compiler supports C++14 cstdio failed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ endif()
+ endif()
+ if(NOT CMake_CXX14_CSTDIO_WORKS)
+ set(CMake_CXX14_CSTDIO_BROKEN 1)
+ endif()
+endif()
diff --git a/Source/Checks/cm_cxx14_cstdio.cpp b/Source/Checks/cm_cxx14_cstdio.cpp
new file mode 100644
index 0000000..f5806a9
--- /dev/null
+++ b/Source/Checks/cm_cxx14_cstdio.cpp
@@ -0,0 +1,5 @@
+#include <cstdio>
+int main()
+{
+ return 0;
+}
diff --git a/Source/Checks/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake
new file mode 100644
index 0000000..6fde7b6
--- /dev/null
+++ b/Source/Checks/cm_cxx_features.cmake
@@ -0,0 +1,39 @@
+
+function(cm_check_cxx_feature name)
+ string(TOUPPER ${name} FEATURE)
+ if(NOT DEFINED CMake_HAVE_CXX_${FEATURE})
+ message(STATUS "Checking if compiler supports C++ ${name}")
+ try_compile(CMake_HAVE_CXX_${FEATURE}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_LIST_DIR}/cm_cxx_${name}.cxx
+ CMAKE_FLAGS -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}
+ OUTPUT_VARIABLE OUTPUT
+ )
+ # If using the feature causes warnings, treat it as broken/unavailable.
+ if(OUTPUT MATCHES "warning")
+ set(CMake_HAVE_CXX_${FEATURE} OFF CACHE INTERNAL "TRY_COMPILE" FORCE)
+ endif()
+ if(CMake_HAVE_CXX_${FEATURE})
+ message(STATUS "Checking if compiler supports C++ ${name} - yes")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if compiler supports C++ ${name} passed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ else()
+ message(STATUS "Checking if compiler supports C++ ${name} - no")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if compiler supports C++ ${name} failed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ endif()
+ endif()
+endfunction()
+
+if(CMAKE_CXX_STANDARD)
+ cm_check_cxx_feature(nullptr)
+ cm_check_cxx_feature(override)
+ cm_check_cxx_feature(unordered_map)
+ cm_check_cxx_feature(unordered_set)
+endif()
diff --git a/Source/Checks/cm_cxx_nullptr.cxx b/Source/Checks/cm_cxx_nullptr.cxx
new file mode 100644
index 0000000..500684a
--- /dev/null
+++ b/Source/Checks/cm_cxx_nullptr.cxx
@@ -0,0 +1,14 @@
+int test(int)
+{
+ return -1;
+}
+
+int test(int*)
+{
+ return 0;
+}
+
+int main()
+{
+ return test(nullptr);
+}
diff --git a/Source/Checks/cm_cxx_override.cxx b/Source/Checks/cm_cxx_override.cxx
new file mode 100644
index 0000000..5a33fbb
--- /dev/null
+++ b/Source/Checks/cm_cxx_override.cxx
@@ -0,0 +1,24 @@
+struct Foo
+{
+ Foo() {}
+ virtual ~Foo() {}
+ virtual int test() const = 0;
+};
+
+struct Bar : Foo
+{
+ Bar() {}
+ ~Bar() override {}
+ int test() const override { return 0; }
+};
+
+int test(Foo const& foo)
+{
+ return foo.test();
+}
+
+int main()
+{
+ Bar const bar;
+ return test(bar);
+}
diff --git a/Source/Checks/cm_cxx_unordered_map.cxx b/Source/Checks/cm_cxx_unordered_map.cxx
new file mode 100644
index 0000000..be3de25
--- /dev/null
+++ b/Source/Checks/cm_cxx_unordered_map.cxx
@@ -0,0 +1,7 @@
+#include <unordered_map>
+int main()
+{
+ std::unordered_map<int, int> map;
+ map[0] = 0;
+ return 0;
+}
diff --git a/Source/Checks/cm_cxx_unordered_set.cxx b/Source/Checks/cm_cxx_unordered_set.cxx
new file mode 100644
index 0000000..de4bb77
--- /dev/null
+++ b/Source/Checks/cm_cxx_unordered_set.cxx
@@ -0,0 +1,7 @@
+#include <unordered_set>
+int main()
+{
+ std::unordered_set<int> set;
+ set.insert(0);
+ return 0;
+}
diff --git a/Source/CursesDialog/.NoDartCoverage b/Source/CursesDialog/.NoDartCoverage
new file mode 100644
index 0000000..3c99729
--- /dev/null
+++ b/Source/CursesDialog/.NoDartCoverage
@@ -0,0 +1 @@
+# do not do coverage in this directory
diff --git a/Source/CursesDialog/CMakeLists.txt b/Source/CursesDialog/CMakeLists.txt
new file mode 100644
index 0000000..55599b6
--- /dev/null
+++ b/Source/CursesDialog/CMakeLists.txt
@@ -0,0 +1,51 @@
+#=============================================================================
+# CMake - Cross Platform Makefile Generator
+# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+set( CURSES_SRCS
+ CursesDialog/cmCursesOptionsWidget
+ CursesDialog/cmCursesBoolWidget
+ CursesDialog/cmCursesCacheEntryComposite
+ CursesDialog/cmCursesDummyWidget
+ CursesDialog/cmCursesFilePathWidget
+ CursesDialog/cmCursesForm
+ CursesDialog/cmCursesLabelWidget
+ CursesDialog/cmCursesLongMessageForm
+ CursesDialog/cmCursesMainForm
+ CursesDialog/cmCursesPathWidget
+ CursesDialog/cmCursesStringWidget
+ CursesDialog/cmCursesWidget
+ CursesDialog/ccmake
+ )
+
+if( NOT CMAKE_USE_SYSTEM_FORM )
+ include_directories(${CMake_SOURCE_DIR}/Source/CursesDialog/form
+ ${CMake_BINARY_DIR}/Source/CursesDialog/form)
+endif()
+include_directories(${CURSES_INCLUDE_PATH})
+
+
+add_executable(ccmake ${CURSES_SRCS} )
+target_link_libraries(ccmake CMakeLib)
+if(CMAKE_USE_SYSTEM_FORM)
+ target_link_libraries(ccmake
+ ${CURSES_FORM_LIBRARY}
+ ${CURSES_LIBRARY}
+ )
+ if(CURSES_EXTRA_LIBRARY)
+ target_link_libraries(ccmake ${CURSES_EXTRA_LIBRARY})
+ endif()
+else()
+ target_link_libraries(ccmake cmForm)
+endif()
+
+CMake_OPTIONAL_COMPONENT(ccmake)
+install(TARGETS ccmake DESTINATION ${CMAKE_BIN_DIR} ${COMPONENT})
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
new file mode 100644
index 0000000..606c954
--- /dev/null
+++ b/Source/CursesDialog/ccmake.cxx
@@ -0,0 +1,185 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCursesStandardIncludes.h"
+
+#include "../cmDocumentation.h"
+#include "../cmSystemTools.h"
+#include "../cmake.h"
+
+#include <signal.h>
+#include <sys/ioctl.h>
+
+#include "cmCursesMainForm.h"
+#include <cmsys/Encoding.hxx>
+
+#include <form.h>
+
+static const char* cmDocumentationName[][2] = {
+ { CM_NULLPTR, " ccmake - Curses Interface for CMake." },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+static const char* cmDocumentationUsage[][2] = {
+ { CM_NULLPTR, " ccmake <path-to-source>\n"
+ " ccmake <path-to-existing-build>" },
+ { CM_NULLPTR,
+ "Specify a source directory to (re-)generate a build system for "
+ "it in the current working directory. Specify an existing build "
+ "directory to re-generate its build system." },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+static const char* cmDocumentationUsageNote[][2] = {
+ { CM_NULLPTR, "Run 'ccmake --help' for more information." },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+static const char* cmDocumentationOptions[]
+ [2] = { CMAKE_STANDARD_OPTIONS_TABLE,
+ { CM_NULLPTR, CM_NULLPTR } };
+
+cmCursesForm* cmCursesForm::CurrentForm = CM_NULLPTR;
+
+extern "C" {
+
+void onsig(int)
+{
+ if (cmCursesForm::CurrentForm) {
+ endwin();
+ initscr(); /* Initialization */
+ noecho(); /* Echo off */
+ cbreak(); /* nl- or cr not needed */
+ keypad(stdscr, TRUE); /* Use key symbols as
+ KEY_DOWN*/
+ refresh();
+ int x, y;
+ getmaxyx(stdscr, y, x);
+ cmCursesForm::CurrentForm->Render(1, 1, x, y);
+ cmCursesForm::CurrentForm->UpdateStatusBar();
+ }
+ signal(SIGWINCH, onsig);
+}
+}
+
+void CMakeMessageHandler(const char* message, const char* title, bool&,
+ void* clientData)
+{
+ cmCursesForm* self = static_cast<cmCursesForm*>(clientData);
+ self->AddError(message, title);
+}
+
+int main(int argc, char const* const* argv)
+{
+ cmsys::Encoding::CommandLineArguments encoding_args =
+ cmsys::Encoding::CommandLineArguments::Main(argc, argv);
+ argc = encoding_args.argc();
+ argv = encoding_args.argv();
+
+ cmSystemTools::FindCMakeResources(argv[0]);
+ cmDocumentation doc;
+ doc.addCMakeStandardDocSections();
+ if (doc.CheckOptions(argc, argv)) {
+ cmake hcm;
+ hcm.SetHomeDirectory("");
+ hcm.SetHomeOutputDirectory("");
+ hcm.AddCMakePaths();
+ std::vector<cmDocumentationEntry> generators;
+ hcm.GetGeneratorDocumentation(generators);
+ doc.SetName("ccmake");
+ doc.SetSection("Name", cmDocumentationName);
+ doc.SetSection("Usage", cmDocumentationUsage);
+ if (argc == 1) {
+ doc.AppendSection("Usage", cmDocumentationUsageNote);
+ }
+ doc.SetSection("Generators", generators);
+ doc.PrependSection("Options", cmDocumentationOptions);
+ return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
+ }
+
+ bool debug = false;
+ unsigned int i;
+ int j;
+ std::vector<std::string> args;
+ for (j = 0; j < argc; ++j) {
+ if (strcmp(argv[j], "-debug") == 0) {
+ debug = true;
+ } else {
+ args.push_back(argv[j]);
+ }
+ }
+
+ std::string cacheDir = cmSystemTools::GetCurrentWorkingDirectory();
+ for (i = 1; i < args.size(); ++i) {
+ std::string arg = args[i];
+ if (arg.find("-B", 0) == 0) {
+ cacheDir = arg.substr(2);
+ }
+ }
+
+ cmSystemTools::DisableRunCommandOutput();
+
+ if (debug) {
+ cmCursesForm::DebugStart();
+ }
+
+ initscr(); /* Initialization */
+ noecho(); /* Echo off */
+ cbreak(); /* nl- or cr not needed */
+ keypad(stdscr, TRUE); /* Use key symbols as
+ KEY_DOWN*/
+
+ signal(SIGWINCH, onsig);
+
+ int x, y;
+ getmaxyx(stdscr, y, x);
+ if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) {
+ endwin();
+ std::cerr << "Window is too small. A size of at least "
+ << cmCursesMainForm::MIN_WIDTH << " x "
+ << cmCursesMainForm::MIN_HEIGHT << " is required to run ccmake."
+ << std::endl;
+ return 1;
+ }
+
+ cmCursesMainForm* myform;
+
+ myform = new cmCursesMainForm(args, x);
+ if (myform->LoadCache(cacheDir.c_str())) {
+ curses_clear();
+ touchwin(stdscr);
+ endwin();
+ delete myform;
+ std::cerr << "Error running cmake::LoadCache(). Aborting.\n";
+ return 1;
+ }
+
+ cmSystemTools::SetMessageCallback(CMakeMessageHandler, myform);
+
+ cmCursesForm::CurrentForm = myform;
+
+ myform->InitializeUI();
+ if (myform->Configure(1) == 0) {
+ myform->Render(1, 1, x, y);
+ myform->HandleInput();
+ }
+
+ // Need to clean-up better
+ curses_clear();
+ touchwin(stdscr);
+ endwin();
+ delete cmCursesForm::CurrentForm;
+ cmCursesForm::CurrentForm = CM_NULLPTR;
+
+ std::cout << std::endl << std::endl;
+
+ return 0;
+}
diff --git a/Source/CursesDialog/cmCursesBoolWidget.cxx b/Source/CursesDialog/cmCursesBoolWidget.cxx
new file mode 100644
index 0000000..9bcf050
--- /dev/null
+++ b/Source/CursesDialog/cmCursesBoolWidget.cxx
@@ -0,0 +1,58 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCursesBoolWidget.h"
+
+#include "cmCursesMainForm.h"
+
+cmCursesBoolWidget::cmCursesBoolWidget(int width, int height, int left,
+ int top)
+ : cmCursesWidget(width, height, left, top)
+{
+ this->Type = cmState::BOOL;
+ set_field_fore(this->Field, A_NORMAL);
+ set_field_back(this->Field, A_STANDOUT);
+ field_opts_off(this->Field, O_STATIC);
+ this->SetValueAsBool(false);
+}
+
+bool cmCursesBoolWidget::HandleInput(int& key, cmCursesMainForm*, WINDOW* w)
+{
+
+ // 10 == enter
+ if (key == 10 || key == KEY_ENTER) {
+ if (this->GetValueAsBool()) {
+ this->SetValueAsBool(false);
+ } else {
+ this->SetValueAsBool(true);
+ }
+
+ touchwin(w);
+ wrefresh(w);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void cmCursesBoolWidget::SetValueAsBool(bool value)
+{
+ if (value) {
+ this->SetValue("ON");
+ } else {
+ this->SetValue("OFF");
+ }
+}
+
+bool cmCursesBoolWidget::GetValueAsBool()
+{
+ return this->Value == "ON";
+}
diff --git a/Source/CursesDialog/cmCursesBoolWidget.h b/Source/CursesDialog/cmCursesBoolWidget.h
new file mode 100644
index 0000000..d2899ee
--- /dev/null
+++ b/Source/CursesDialog/cmCursesBoolWidget.h
@@ -0,0 +1,40 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCursesBoolWidget_h
+#define cmCursesBoolWidget_h
+
+#include "cmCursesWidget.h"
+
+class cmCursesMainForm;
+
+class cmCursesBoolWidget : public cmCursesWidget
+{
+public:
+ cmCursesBoolWidget(int width, int height, int left, int top);
+
+ // Description:
+ // Handle user input. Called by the container of this widget
+ // when this widget has focus. Returns true if the input was
+ // handled.
+ bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) CM_OVERRIDE;
+
+ // Description:
+ // Set/Get the value (on/off).
+ void SetValueAsBool(bool value);
+ bool GetValueAsBool();
+
+protected:
+ cmCursesBoolWidget(const cmCursesBoolWidget& from);
+ void operator=(const cmCursesBoolWidget&);
+};
+
+#endif // cmCursesBoolWidget_h
diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
new file mode 100644
index 0000000..ea12756
--- /dev/null
+++ b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
@@ -0,0 +1,116 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCursesCacheEntryComposite.h"
+
+#include "../cmState.h"
+#include "../cmSystemTools.h"
+#include "../cmake.h"
+#include "cmCursesBoolWidget.h"
+#include "cmCursesDummyWidget.h"
+#include "cmCursesFilePathWidget.h"
+#include "cmCursesLabelWidget.h"
+#include "cmCursesOptionsWidget.h"
+#include "cmCursesPathWidget.h"
+#include "cmCursesStringWidget.h"
+
+#include <assert.h>
+
+cmCursesCacheEntryComposite::cmCursesCacheEntryComposite(
+ const std::string& key, int labelwidth, int entrywidth)
+ : Key(key)
+ , LabelWidth(labelwidth)
+ , EntryWidth(entrywidth)
+{
+ this->Label = new cmCursesLabelWidget(this->LabelWidth, 1, 1, 1, key);
+ this->IsNewLabel = new cmCursesLabelWidget(1, 1, 1, 1, " ");
+ this->Entry = CM_NULLPTR;
+ this->Entry = new cmCursesStringWidget(this->EntryWidth, 1, 1, 1);
+}
+
+cmCursesCacheEntryComposite::cmCursesCacheEntryComposite(
+ const std::string& key, cmake* cm, bool isNew, int labelwidth,
+ int entrywidth)
+ : Key(key)
+ , LabelWidth(labelwidth)
+ , EntryWidth(entrywidth)
+{
+ this->Label = new cmCursesLabelWidget(this->LabelWidth, 1, 1, 1, key);
+ if (isNew) {
+ this->IsNewLabel = new cmCursesLabelWidget(1, 1, 1, 1, "*");
+ } else {
+ this->IsNewLabel = new cmCursesLabelWidget(1, 1, 1, 1, " ");
+ }
+
+ this->Entry = CM_NULLPTR;
+ const char* value = cm->GetState()->GetCacheEntryValue(key);
+ assert(value);
+ switch (cm->GetState()->GetCacheEntryType(key)) {
+ case cmState::BOOL:
+ this->Entry = new cmCursesBoolWidget(this->EntryWidth, 1, 1, 1);
+ if (cmSystemTools::IsOn(value)) {
+ static_cast<cmCursesBoolWidget*>(this->Entry)->SetValueAsBool(true);
+ } else {
+ static_cast<cmCursesBoolWidget*>(this->Entry)->SetValueAsBool(false);
+ }
+ break;
+ case cmState::PATH:
+ this->Entry = new cmCursesPathWidget(this->EntryWidth, 1, 1, 1);
+ static_cast<cmCursesPathWidget*>(this->Entry)->SetString(value);
+ break;
+ case cmState::FILEPATH:
+ this->Entry = new cmCursesFilePathWidget(this->EntryWidth, 1, 1, 1);
+ static_cast<cmCursesFilePathWidget*>(this->Entry)->SetString(value);
+ break;
+ case cmState::STRING: {
+ const char* stringsProp =
+ cm->GetState()->GetCacheEntryProperty(key, "STRINGS");
+ if (stringsProp) {
+ cmCursesOptionsWidget* ow =
+ new cmCursesOptionsWidget(this->EntryWidth, 1, 1, 1);
+ this->Entry = ow;
+ std::vector<std::string> options;
+ cmSystemTools::ExpandListArgument(stringsProp, options);
+ for (std::vector<std::string>::iterator si = options.begin();
+ si != options.end(); ++si) {
+ ow->AddOption(*si);
+ }
+ ow->SetOption(value);
+ } else {
+ this->Entry = new cmCursesStringWidget(this->EntryWidth, 1, 1, 1);
+ static_cast<cmCursesStringWidget*>(this->Entry)->SetString(value);
+ }
+ break;
+ }
+ case cmState::UNINITIALIZED:
+ cmSystemTools::Error("Found an undefined variable: ", key.c_str());
+ break;
+ default:
+ // TODO : put warning message here
+ break;
+ }
+}
+
+cmCursesCacheEntryComposite::~cmCursesCacheEntryComposite()
+{
+ delete this->Label;
+ delete this->IsNewLabel;
+ delete this->Entry;
+}
+
+const char* cmCursesCacheEntryComposite::GetValue()
+{
+ if (this->Label) {
+ return this->Label->GetValue();
+ } else {
+ return CM_NULLPTR;
+ }
+}
diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.h b/Source/CursesDialog/cmCursesCacheEntryComposite.h
new file mode 100644
index 0000000..8ed3902
--- /dev/null
+++ b/Source/CursesDialog/cmCursesCacheEntryComposite.h
@@ -0,0 +1,41 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCursesCacheEntryComposite_h
+#define cmCursesCacheEntryComposite_h
+
+#include "cmCursesLabelWidget.h"
+
+class cmCursesCacheEntryComposite
+{
+public:
+ cmCursesCacheEntryComposite(const std::string& key, int labelwidth,
+ int entrywidth);
+ cmCursesCacheEntryComposite(const std::string& key, cmake* cm, bool isNew,
+ int labelwidth, int entrywidth);
+ ~cmCursesCacheEntryComposite();
+ const char* GetValue();
+
+ friend class cmCursesMainForm;
+
+protected:
+ cmCursesCacheEntryComposite(const cmCursesCacheEntryComposite& from);
+ void operator=(const cmCursesCacheEntryComposite&);
+
+ cmCursesLabelWidget* Label;
+ cmCursesLabelWidget* IsNewLabel;
+ cmCursesWidget* Entry;
+ std::string Key;
+ int LabelWidth;
+ int EntryWidth;
+};
+
+#endif // cmCursesCacheEntryComposite_h
diff --git a/Source/CursesDialog/cmCursesDummyWidget.cxx b/Source/CursesDialog/cmCursesDummyWidget.cxx
new file mode 100644
index 0000000..3cd36af
--- /dev/null
+++ b/Source/CursesDialog/cmCursesDummyWidget.cxx
@@ -0,0 +1,24 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCursesDummyWidget.h"
+
+cmCursesDummyWidget::cmCursesDummyWidget(int width, int height, int left,
+ int top)
+ : cmCursesWidget(width, height, left, top)
+{
+ this->Type = cmState::INTERNAL;
+}
+
+bool cmCursesDummyWidget::HandleInput(int&, cmCursesMainForm*, WINDOW*)
+{
+ return false;
+}
diff --git a/Source/CursesDialog/cmCursesDummyWidget.h b/Source/CursesDialog/cmCursesDummyWidget.h
new file mode 100644
index 0000000..e6ca91e
--- /dev/null
+++ b/Source/CursesDialog/cmCursesDummyWidget.h
@@ -0,0 +1,35 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCursesDummyWidget_h
+#define cmCursesDummyWidget_h
+
+#include "cmCursesWidget.h"
+
+class cmCursesMainForm;
+
+class cmCursesDummyWidget : public cmCursesWidget
+{
+public:
+ cmCursesDummyWidget(int width, int height, int left, int top);
+
+ // Description:
+ // Handle user input. Called by the container of this widget
+ // when this widget has focus. Returns true if the input was
+ // handled.
+ bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) CM_OVERRIDE;
+
+protected:
+ cmCursesDummyWidget(const cmCursesDummyWidget& from);
+ void operator=(const cmCursesDummyWidget&);
+};
+
+#endif // cmCursesDummyWidget_h
diff --git a/Source/CursesDialog/cmCursesFilePathWidget.cxx b/Source/CursesDialog/cmCursesFilePathWidget.cxx
new file mode 100644
index 0000000..28a74a9
--- /dev/null
+++ b/Source/CursesDialog/cmCursesFilePathWidget.cxx
@@ -0,0 +1,19 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCursesFilePathWidget.h"
+
+cmCursesFilePathWidget::cmCursesFilePathWidget(int width, int height, int left,
+ int top)
+ : cmCursesPathWidget(width, height, left, top)
+{
+ this->Type = cmState::FILEPATH;
+}
diff --git a/Source/CursesDialog/cmCursesFilePathWidget.h b/Source/CursesDialog/cmCursesFilePathWidget.h
new file mode 100644
index 0000000..72adc77
--- /dev/null
+++ b/Source/CursesDialog/cmCursesFilePathWidget.h
@@ -0,0 +1,27 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCursesFilePathWidget_h
+#define cmCursesFilePathWidget_h
+
+#include "cmCursesPathWidget.h"
+
+class cmCursesFilePathWidget : public cmCursesPathWidget
+{
+public:
+ cmCursesFilePathWidget(int width, int height, int left, int top);
+
+protected:
+ cmCursesFilePathWidget(const cmCursesFilePathWidget& from);
+ void operator=(const cmCursesFilePathWidget&);
+};
+
+#endif // cmCursesFilePathWidget_h
diff --git a/Source/CursesDialog/cmCursesForm.cxx b/Source/CursesDialog/cmCursesForm.cxx
new file mode 100644
index 0000000..b3320c9
--- /dev/null
+++ b/Source/CursesDialog/cmCursesForm.cxx
@@ -0,0 +1,54 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCursesForm.h"
+
+cmsys::ofstream cmCursesForm::DebugFile;
+bool cmCursesForm::Debug = false;
+
+cmCursesForm::cmCursesForm()
+{
+ this->Form = CM_NULLPTR;
+}
+
+cmCursesForm::~cmCursesForm()
+{
+ if (this->Form) {
+ unpost_form(this->Form);
+ free_form(this->Form);
+ this->Form = CM_NULLPTR;
+ }
+}
+
+void cmCursesForm::DebugStart()
+{
+ cmCursesForm::Debug = true;
+ cmCursesForm::DebugFile.open("ccmakelog.txt");
+}
+
+void cmCursesForm::DebugEnd()
+{
+ if (!cmCursesForm::Debug) {
+ return;
+ }
+
+ cmCursesForm::Debug = false;
+ cmCursesForm::DebugFile.close();
+}
+
+void cmCursesForm::LogMessage(const char* msg)
+{
+ if (!cmCursesForm::Debug) {
+ return;
+ }
+
+ cmCursesForm::DebugFile << msg << std::endl;
+}
diff --git a/Source/CursesDialog/cmCursesForm.h b/Source/CursesDialog/cmCursesForm.h
new file mode 100644
index 0000000..c0192fc
--- /dev/null
+++ b/Source/CursesDialog/cmCursesForm.h
@@ -0,0 +1,71 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCursesForm_h
+#define cmCursesForm_h
+
+#include "cmCursesStandardIncludes.h"
+
+#include <cmsys/FStream.hxx>
+
+class cmCursesForm
+{
+public:
+ cmCursesForm();
+ virtual ~cmCursesForm();
+
+ // Description:
+ // Handle user input.
+ virtual void HandleInput() = 0;
+
+ // Description:
+ // Display form.
+ virtual void Render(int left, int top, int width, int height) = 0;
+
+ // Description:
+ // This method should normally called only by the form.
+ // The only exception is during a resize.
+ virtual void UpdateStatusBar() = 0;
+
+ // Description:
+ // During a CMake run, an error handle should add errors
+ // to be displayed afterwards.
+ virtual void AddError(const char*, const char*) {}
+
+ // Description:
+ // Turn debugging on. This will create ccmakelog.txt.
+ static void DebugStart();
+
+ // Description:
+ // Turn debugging off. This will close ccmakelog.txt.
+ static void DebugEnd();
+
+ // Description:
+ // Write a debugging message.
+ static void LogMessage(const char* msg);
+
+ // Description:
+ // Return the FORM. Should be only used by low-level methods.
+ FORM* GetForm() { return this->Form; }
+
+ static cmCursesForm* CurrentForm;
+
+protected:
+ static cmsys::ofstream DebugFile;
+ static bool Debug;
+
+ cmCursesForm(const cmCursesForm& form);
+ void operator=(const cmCursesForm&);
+
+ FORM* Form;
+};
+
+#endif // cmCursesForm_h
diff --git a/Source/CursesDialog/cmCursesLabelWidget.cxx b/Source/CursesDialog/cmCursesLabelWidget.cxx
new file mode 100644
index 0000000..e9da71e
--- /dev/null
+++ b/Source/CursesDialog/cmCursesLabelWidget.cxx
@@ -0,0 +1,32 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCursesLabelWidget.h"
+
+cmCursesLabelWidget::cmCursesLabelWidget(int width, int height, int left,
+ int top, const std::string& name)
+ : cmCursesWidget(width, height, left, top)
+{
+ field_opts_off(this->Field, O_EDIT);
+ field_opts_off(this->Field, O_ACTIVE);
+ field_opts_off(this->Field, O_STATIC);
+ this->SetValue(name);
+}
+
+cmCursesLabelWidget::~cmCursesLabelWidget()
+{
+}
+
+bool cmCursesLabelWidget::HandleInput(int&, cmCursesMainForm*, WINDOW*)
+{
+ // Static text. No input is handled here.
+ return false;
+}
diff --git a/Source/CursesDialog/cmCursesLabelWidget.h b/Source/CursesDialog/cmCursesLabelWidget.h
new file mode 100644
index 0000000..ff645af
--- /dev/null
+++ b/Source/CursesDialog/cmCursesLabelWidget.h
@@ -0,0 +1,37 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCursesLabelWidget_h
+#define cmCursesLabelWidget_h
+
+#include "cmCursesWidget.h"
+
+class cmCursesMainForm;
+
+class cmCursesLabelWidget : public cmCursesWidget
+{
+public:
+ cmCursesLabelWidget(int width, int height, int left, int top,
+ const std::string& name);
+ ~cmCursesLabelWidget() CM_OVERRIDE;
+
+ // Description:
+ // Handle user input. Called by the container of this widget
+ // when this widget has focus. Returns true if the input was
+ // handled
+ bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) CM_OVERRIDE;
+
+protected:
+ cmCursesLabelWidget(const cmCursesLabelWidget& from);
+ void operator=(const cmCursesLabelWidget&);
+};
+
+#endif // cmCursesLabelWidget_h
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx
new file mode 100644
index 0000000..48cc42c
--- /dev/null
+++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx
@@ -0,0 +1,182 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCursesLongMessageForm.h"
+
+#include "../cmSystemTools.h"
+#include "../cmVersion.h"
+#include "../cmake.h"
+#include "cmCursesMainForm.h"
+
+inline int ctrl(int z)
+{
+ return (z & 037);
+}
+
+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);
+ // Add one blank line after each message
+ this->Messages += "\n\n";
+ }
+ this->Title = title;
+ this->Fields[0] = CM_NULLPTR;
+ this->Fields[1] = CM_NULLPTR;
+}
+
+cmCursesLongMessageForm::~cmCursesLongMessageForm()
+{
+ if (this->Fields[0]) {
+ free_field(this->Fields[0]);
+ }
+}
+
+void cmCursesLongMessageForm::UpdateStatusBar()
+{
+ int x, y;
+ getmaxyx(stdscr, y, x);
+
+ char bar[cmCursesMainForm::MAX_WIDTH];
+ size_t size = strlen(this->Title.c_str());
+ if (size >= cmCursesMainForm::MAX_WIDTH) {
+ size = cmCursesMainForm::MAX_WIDTH - 1;
+ }
+ strncpy(bar, this->Title.c_str(), size);
+ for (size_t i = size - 1; i < cmCursesMainForm::MAX_WIDTH; i++) {
+ bar[i] = ' ';
+ }
+ int width;
+ if (x < cmCursesMainForm::MAX_WIDTH) {
+ width = x;
+ } else {
+ width = cmCursesMainForm::MAX_WIDTH - 1;
+ }
+
+ bar[width] = '\0';
+
+ char version[cmCursesMainForm::MAX_WIDTH];
+ char vertmp[128];
+ sprintf(vertmp, "CMake Version %s", cmVersion::GetCMakeVersion());
+ size_t sideSpace = (width - strlen(vertmp));
+ for (size_t i = 0; i < sideSpace; i++) {
+ version[i] = ' ';
+ }
+ sprintf(version + sideSpace, "%s", vertmp);
+ version[width] = '\0';
+
+ char fmt_s[] = "%s";
+ curses_move(y - 4, 0);
+ attron(A_STANDOUT);
+ printw(fmt_s, bar);
+ attroff(A_STANDOUT);
+ curses_move(y - 3, 0);
+ printw(fmt_s, version);
+ pos_form_cursor(this->Form);
+}
+
+void cmCursesLongMessageForm::PrintKeys()
+{
+ int x, y;
+ getmaxyx(stdscr, y, x);
+ if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) {
+ return;
+ }
+ char firstLine[512];
+ sprintf(firstLine, "Press [e] to exit help");
+
+ char fmt_s[] = "%s";
+ curses_move(y - 2, 0);
+ printw(fmt_s, firstLine);
+ pos_form_cursor(this->Form);
+}
+
+void cmCursesLongMessageForm::Render(int, int, int, int)
+{
+ int x, y;
+ getmaxyx(stdscr, y, x);
+
+ if (this->Form) {
+ unpost_form(this->Form);
+ free_form(this->Form);
+ this->Form = CM_NULLPTR;
+ }
+
+ const char* msg = this->Messages.c_str();
+
+ curses_clear();
+
+ if (this->Fields[0]) {
+ free_field(this->Fields[0]);
+ this->Fields[0] = CM_NULLPTR;
+ }
+
+ this->Fields[0] = new_field(y - 6, x - 2, 1, 1, 0, 0);
+
+ field_opts_off(this->Fields[0], O_STATIC);
+
+ this->Form = new_form(this->Fields);
+ post_form(this->Form);
+
+ int i = 0;
+ form_driver(this->Form, REQ_BEG_FIELD);
+ while (msg[i] != '\0' && i < 60000) {
+ if (msg[i] == '\n' && msg[i + 1] != '\0') {
+ form_driver(this->Form, REQ_NEW_LINE);
+ } else {
+ form_driver(this->Form, msg[i]);
+ }
+ i++;
+ }
+ form_driver(this->Form, REQ_BEG_FIELD);
+
+ this->UpdateStatusBar();
+ this->PrintKeys();
+ touchwin(stdscr);
+ refresh();
+}
+
+void cmCursesLongMessageForm::HandleInput()
+{
+ if (!this->Form) {
+ return;
+ }
+
+ char debugMessage[128];
+
+ for (;;) {
+ int key = getch();
+
+ sprintf(debugMessage, "Message widget handling input, key: %d", key);
+ cmCursesForm::LogMessage(debugMessage);
+
+ // quit
+ if (key == 'o' || key == 'e') {
+ break;
+ } else if (key == KEY_DOWN || key == ctrl('n')) {
+ form_driver(this->Form, REQ_SCR_FLINE);
+ } else if (key == KEY_UP || key == ctrl('p')) {
+ form_driver(this->Form, REQ_SCR_BLINE);
+ } else if (key == KEY_NPAGE || key == ctrl('d')) {
+ form_driver(this->Form, REQ_SCR_FPAGE);
+ } else if (key == KEY_PPAGE || key == ctrl('u')) {
+ form_driver(this->Form, REQ_SCR_BPAGE);
+ }
+
+ this->UpdateStatusBar();
+ this->PrintKeys();
+ touchwin(stdscr);
+ wrefresh(stdscr);
+ }
+}
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.h b/Source/CursesDialog/cmCursesLongMessageForm.h
new file mode 100644
index 0000000..a12ed2f
--- /dev/null
+++ b/Source/CursesDialog/cmCursesLongMessageForm.h
@@ -0,0 +1,57 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCursesLongMessageForm_h
+#define cmCursesLongMessageForm_h
+
+#include "cmCursesStandardIncludes.h"
+
+#include "cmCursesForm.h"
+
+class cmCursesCacheEntryComposite;
+
+class cmCursesLongMessageForm : public cmCursesForm
+{
+public:
+ cmCursesLongMessageForm(std::vector<std::string> const& messages,
+ const char* title);
+ ~cmCursesLongMessageForm() CM_OVERRIDE;
+
+ // Description:
+ // Handle user input.
+ void HandleInput() CM_OVERRIDE;
+
+ // Description:
+ // Display form. Use a window of size width x height, starting
+ // at top, left.
+ void Render(int left, int top, int width, int height) CM_OVERRIDE;
+
+ // Description:
+ // This method should normally called only by the form.
+ // The only exception is during a resize.
+ void PrintKeys();
+
+ // Description:
+ // This method should normally called only by the form.
+ // The only exception is during a resize.
+ void UpdateStatusBar() CM_OVERRIDE;
+
+protected:
+ cmCursesLongMessageForm(const cmCursesLongMessageForm& from);
+ void operator=(const cmCursesLongMessageForm&);
+
+ std::string Messages;
+ std::string Title;
+
+ FIELD* Fields[2];
+};
+
+#endif // cmCursesLongMessageForm_h
diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx
new file mode 100644
index 0000000..9ae38d6
--- /dev/null
+++ b/Source/CursesDialog/cmCursesMainForm.cxx
@@ -0,0 +1,1154 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCursesMainForm.h"
+
+#include "../cmSystemTools.h"
+#include "../cmVersion.h"
+#include "../cmake.h"
+#include "cmAlgorithms.h"
+#include "cmCursesBoolWidget.h"
+#include "cmCursesCacheEntryComposite.h"
+#include "cmCursesDummyWidget.h"
+#include "cmCursesFilePathWidget.h"
+#include "cmCursesLabelWidget.h"
+#include "cmCursesLongMessageForm.h"
+#include "cmCursesPathWidget.h"
+#include "cmCursesStringWidget.h"
+#include "cmState.h"
+
+inline int ctrl(int z)
+{
+ return (z & 037);
+}
+
+cmCursesMainForm::cmCursesMainForm(std::vector<std::string> const& args,
+ int initWidth)
+ : Args(args)
+ , InitialWidth(initWidth)
+{
+ this->NumberOfPages = 0;
+ this->Fields = CM_NULLPTR;
+ this->Entries = CM_NULLPTR;
+ this->AdvancedMode = false;
+ this->NumberOfVisibleEntries = 0;
+ this->OkToGenerate = false;
+ this->HelpMessage.push_back(
+ "Welcome to ccmake, curses based user interface for CMake.");
+ this->HelpMessage.push_back("");
+ this->HelpMessage.push_back(s_ConstHelpMessage);
+ this->CMakeInstance = new cmake;
+ this->CMakeInstance->SetCMakeEditCommand(
+ cmSystemTools::GetCMakeCursesCommand());
+
+ // create the arguments for the cmake object
+ std::string whereCMake = cmSystemTools::GetProgramPath(this->Args[0]);
+ whereCMake += "/cmake";
+ this->Args[0] = whereCMake;
+ this->CMakeInstance->SetArgs(this->Args);
+ this->SearchString = "";
+ this->OldSearchString = "";
+ this->SearchMode = false;
+}
+
+cmCursesMainForm::~cmCursesMainForm()
+{
+ if (this->Form) {
+ unpost_form(this->Form);
+ free_form(this->Form);
+ this->Form = CM_NULLPTR;
+ }
+ delete[] this->Fields;
+
+ // Clean-up composites
+ if (this->Entries) {
+ cmDeleteAll(*this->Entries);
+ }
+ delete this->Entries;
+ if (this->CMakeInstance) {
+ delete this->CMakeInstance;
+ this->CMakeInstance = CM_NULLPTR;
+ }
+}
+
+// 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;
+}
+
+// Create new cmCursesCacheEntryComposite entries from the cache
+void cmCursesMainForm::InitializeUI()
+{
+ // Create a vector of cmCursesCacheEntryComposite's
+ // which contain labels, entries and new entry markers
+ std::vector<cmCursesCacheEntryComposite*>* newEntries =
+ new std::vector<cmCursesCacheEntryComposite*>;
+ std::vector<std::string> cacheKeys =
+ this->CMakeInstance->GetState()->GetCacheEntryKeys();
+ newEntries->reserve(cacheKeys.size());
+
+ // Count non-internal and non-static entries
+ int count = 0;
+
+ for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
+ it != cacheKeys.end(); ++it) {
+ cmState::CacheEntryType t =
+ this->CMakeInstance->GetState()->GetCacheEntryType(*it);
+ if (t != cmState::INTERNAL && t != cmState::STATIC &&
+ t != cmState::UNINITIALIZED) {
+ ++count;
+ }
+ }
+
+ int entrywidth = this->InitialWidth - 35;
+
+ cmCursesCacheEntryComposite* comp;
+ if (count == 0) {
+ // If cache is empty, display a label saying so and a
+ // dummy entry widget (does not respond to input)
+ comp = new cmCursesCacheEntryComposite("EMPTY CACHE", 30, 30);
+ comp->Entry = new cmCursesDummyWidget(1, 1, 1, 1);
+ newEntries->push_back(comp);
+ } else {
+ // 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;
+ cmState::CacheEntryType t =
+ this->CMakeInstance->GetState()->GetCacheEntryType(*it);
+ if (t == cmState::INTERNAL || t == cmState::STATIC ||
+ t == cmState::UNINITIALIZED) {
+ continue;
+ }
+
+ if (!this->LookForCacheEntry(key)) {
+ newEntries->push_back(new cmCursesCacheEntryComposite(
+ key, this->CMakeInstance, true, 30, entrywidth));
+ this->OkToGenerate = false;
+ }
+ }
+
+ // then add entries which are old
+ for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
+ it != cacheKeys.end(); ++it) {
+ std::string key = *it;
+ cmState::CacheEntryType t =
+ this->CMakeInstance->GetState()->GetCacheEntryType(*it);
+ if (t == cmState::INTERNAL || t == cmState::STATIC ||
+ t == cmState::UNINITIALIZED) {
+ continue;
+ }
+
+ if (this->LookForCacheEntry(key)) {
+ newEntries->push_back(new cmCursesCacheEntryComposite(
+ key, this->CMakeInstance, false, 30, entrywidth));
+ }
+ }
+ }
+
+ // Clean old entries
+ if (this->Entries) {
+ cmDeleteAll(*this->Entries);
+ }
+ delete this->Entries;
+ this->Entries = newEntries;
+
+ // Compute fields from composites
+ this->RePost();
+}
+
+void cmCursesMainForm::RePost()
+{
+ // Create the fields to be passed to the form.
+ if (this->Form) {
+ unpost_form(this->Form);
+ free_form(this->Form);
+ this->Form = CM_NULLPTR;
+ }
+ delete[] this->Fields;
+ if (this->AdvancedMode) {
+ this->NumberOfVisibleEntries = this->Entries->size();
+ } 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) {
+ const char* existingValue =
+ this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+ bool advanced =
+ this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
+ (*it)->GetValue(), "ADVANCED");
+ if (!existingValue || (!this->AdvancedMode && advanced)) {
+ continue;
+ }
+ this->NumberOfVisibleEntries++;
+ }
+ }
+ // there is always one even if it is the dummy one
+ if (this->NumberOfVisibleEntries == 0) {
+ this->NumberOfVisibleEntries = 1;
+ }
+ // Assign the fields: 3 for each entry: label, new entry marker
+ // ('*' or ' ') and entry widget
+ this->Fields = new FIELD*[3 * this->NumberOfVisibleEntries + 1];
+ size_t cc;
+ for (cc = 0; cc < 3 * this->NumberOfVisibleEntries + 1; cc++) {
+ this->Fields[cc] = CM_NULLPTR;
+ }
+
+ // Assign fields
+ int j = 0;
+ std::vector<cmCursesCacheEntryComposite*>::iterator it;
+ for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+ const char* existingValue =
+ this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+ bool advanced =
+ this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
+ (*it)->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;
+ 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;
+ this->NumberOfVisibleEntries = 1;
+ }
+ // Has to be null terminated.
+ this->Fields[3 * this->NumberOfVisibleEntries] = CM_NULLPTR;
+}
+
+void cmCursesMainForm::Render(int left, int top, int width, int height)
+{
+
+ if (this->Form) {
+ FIELD* currentField = current_field(this->Form);
+ cmCursesWidget* cw =
+ reinterpret_cast<cmCursesWidget*>(field_userptr(currentField));
+ // If in edit mode, get out of it
+ if (cw->GetType() == cmState::STRING || cw->GetType() == cmState::PATH ||
+ cw->GetType() == cmState::FILEPATH) {
+ cmCursesStringWidget* sw = static_cast<cmCursesStringWidget*>(cw);
+ sw->SetInEdit(false);
+ }
+ // Delete the previous form
+ unpost_form(this->Form);
+ free_form(this->Form);
+ this->Form = CM_NULLPTR;
+ }
+
+ // Wrong window size
+ if (width < cmCursesMainForm::MIN_WIDTH || width < this->InitialWidth ||
+ height < cmCursesMainForm::MIN_HEIGHT) {
+ return;
+ }
+
+ // Leave room for toolbar
+ height -= 7;
+
+ if (this->AdvancedMode) {
+ this->NumberOfVisibleEntries = this->Entries->size();
+ } 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) {
+ const char* existingValue =
+ this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+ bool advanced =
+ this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
+ (*it)->GetValue(), "ADVANCED");
+ if (!existingValue || (!this->AdvancedMode && advanced)) {
+ continue;
+ }
+ this->NumberOfVisibleEntries++;
+ }
+ }
+
+ // Re-adjust the fields according to their place
+ this->NumberOfPages = 1;
+ if (height > 0) {
+ bool isNewPage;
+ int i = 0;
+ std::vector<cmCursesCacheEntryComposite*>::iterator it;
+ for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+ const char* existingValue =
+ this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+ bool advanced =
+ this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
+ (*it)->GetValue(), "ADVANCED");
+ if (!existingValue || (!this->AdvancedMode && advanced)) {
+ continue;
+ }
+ int row = (i % height) + 1;
+ int page = (i / height) + 1;
+ isNewPage = (page > 1) && (row == 1);
+
+ 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);
+ i++;
+ }
+ }
+
+ // Post the form
+ this->Form = new_form(this->Fields);
+ post_form(this->Form);
+ // Update toolbar
+ this->UpdateStatusBar();
+ this->PrintKeys();
+
+ touchwin(stdscr);
+ refresh();
+}
+
+void cmCursesMainForm::PrintKeys(int process /* = 0 */)
+{
+ int x, y;
+ getmaxyx(stdscr, y, x);
+ if (x < cmCursesMainForm::MIN_WIDTH || x < this->InitialWidth ||
+ y < cmCursesMainForm::MIN_HEIGHT) {
+ return;
+ }
+
+ // Give the current widget (if it exists), a chance to print keys
+ cmCursesWidget* cw = CM_NULLPTR;
+ if (this->Form) {
+ FIELD* currentField = current_field(this->Form);
+ cw = reinterpret_cast<cmCursesWidget*>(field_userptr(currentField));
+ }
+
+ if (cw) {
+ cw->PrintKeys();
+ }
+
+ // {
+ // }
+ // else
+ // {
+ char firstLine[512] = "";
+ char secondLine[512] = "";
+ char thirdLine[512] = "";
+ if (process) {
+ const char* clearLine =
+ " ";
+ strcpy(firstLine, clearLine);
+ strcpy(secondLine, clearLine);
+ strcpy(thirdLine, clearLine);
+ } else {
+ if (this->OkToGenerate) {
+ sprintf(firstLine,
+ "Press [c] to configure Press [g] to generate and exit");
+ } else {
+ sprintf(firstLine,
+ "Press [c] to configure ");
+ }
+ {
+ const char* toggleKeyInstruction =
+ "Press [t] to toggle advanced mode (Currently %s)";
+ sprintf(thirdLine, toggleKeyInstruction,
+ this->AdvancedMode ? "On" : "Off");
+ }
+ sprintf(secondLine, "Press [h] for help "
+ "Press [q] to quit without generating");
+ }
+
+ curses_move(y - 4, 0);
+ char fmt_s[] = "%s";
+ char fmt[512] = "Press [enter] to edit option";
+ if (process) {
+ strcpy(fmt, " ");
+ }
+ printw(fmt_s, fmt);
+ curses_move(y - 3, 0);
+ printw(fmt_s, firstLine);
+ curses_move(y - 2, 0);
+ printw(fmt_s, secondLine);
+ curses_move(y - 1, 0);
+ printw(fmt_s, thirdLine);
+
+ if (cw) {
+ sprintf(firstLine, "Page %d of %d", cw->GetPage(), this->NumberOfPages);
+ curses_move(0, 65 - static_cast<unsigned int>(strlen(firstLine)) - 1);
+ printw(fmt_s, firstLine);
+ }
+ // }
+
+ pos_form_cursor(this->Form);
+}
+
+// Print the key of the current entry and the CMake version
+// on the status bar. Designed for a width of 80 chars.
+void cmCursesMainForm::UpdateStatusBar(const char* message)
+{
+ int x, y;
+ getmaxyx(stdscr, y, x);
+ // If window size is too small, display error and return
+ if (x < cmCursesMainForm::MIN_WIDTH || x < this->InitialWidth ||
+ y < cmCursesMainForm::MIN_HEIGHT) {
+ curses_clear();
+ curses_move(0, 0);
+ char fmt[] = "Window is too small. A size of at least %dx%d is required.";
+ printw(fmt, (cmCursesMainForm::MIN_WIDTH < this->InitialWidth
+ ? this->InitialWidth
+ : cmCursesMainForm::MIN_WIDTH),
+ cmCursesMainForm::MIN_HEIGHT);
+ touchwin(stdscr);
+ wrefresh(stdscr);
+ return;
+ }
+
+ // Get the key of the current entry
+ FIELD* cur = current_field(this->Form);
+ int findex = field_index(cur);
+ cmCursesWidget* lbl = CM_NULLPTR;
+ if (findex >= 0) {
+ lbl = reinterpret_cast<cmCursesWidget*>(
+ field_userptr(this->Fields[findex - 2]));
+ }
+ char help[128] = "";
+ const char* curField = "";
+ if (lbl) {
+ curField = lbl->GetValue();
+
+ // Get the help string of the current entry
+ // and add it to the help string
+ const char* existingValue =
+ this->CMakeInstance->GetState()->GetCacheEntryValue(curField);
+ if (existingValue) {
+ const char* hs = this->CMakeInstance->GetState()->GetCacheEntryProperty(
+ curField, "HELPSTRING");
+ if (hs) {
+ strncpy(help, hs, 127);
+ help[127] = '\0';
+ } else {
+ help[0] = 0;
+ }
+ } else {
+ sprintf(help, " ");
+ }
+ }
+
+ // Join the key, help string and pad with spaces
+ // (or truncate) as necessary
+ char bar[cmCursesMainForm::MAX_WIDTH];
+ size_t i, curFieldLen = strlen(curField);
+ size_t helpLen = strlen(help);
+
+ size_t width;
+ if (x < cmCursesMainForm::MAX_WIDTH) {
+ width = x;
+ } else {
+ width = cmCursesMainForm::MAX_WIDTH;
+ }
+
+ if (message) {
+ curField = message;
+ curFieldLen = strlen(message);
+ if (curFieldLen < width) {
+ strcpy(bar, curField);
+ for (i = curFieldLen; i < width; ++i) {
+ bar[i] = ' ';
+ }
+ } else {
+ strncpy(bar, curField, width);
+ }
+ } else {
+ if (curFieldLen >= width) {
+ strncpy(bar, curField, width);
+ } else {
+ strcpy(bar, curField);
+ bar[curFieldLen] = ':';
+ bar[curFieldLen + 1] = ' ';
+ if (curFieldLen + helpLen + 2 >= width) {
+ strncpy(bar + curFieldLen + 2, help, width - curFieldLen - 2);
+ } else {
+ strcpy(bar + curFieldLen + 2, help);
+ for (i = curFieldLen + helpLen + 2; i < width; ++i) {
+ bar[i] = ' ';
+ }
+ }
+ }
+ }
+
+ bar[width] = '\0';
+
+ // Display CMake version info on the next line
+ // We want to display this on the right
+ char version[cmCursesMainForm::MAX_WIDTH];
+ char vertmp[128];
+ sprintf(vertmp, "CMake Version %s", cmVersion::GetCMakeVersion());
+ size_t sideSpace = (width - strlen(vertmp));
+ for (i = 0; i < sideSpace; i++) {
+ version[i] = ' ';
+ }
+ sprintf(version + sideSpace, "%s", vertmp);
+ version[width] = '\0';
+
+ // Now print both lines
+ char fmt_s[] = "%s";
+ curses_move(y - 5, 0);
+ attron(A_STANDOUT);
+ printw(fmt_s, bar);
+ attroff(A_STANDOUT);
+ curses_move(y - 4, 0);
+ printw(fmt_s, version);
+ pos_form_cursor(this->Form);
+}
+
+void cmCursesMainForm::UpdateProgress(const char* msg, float prog, void* vp)
+{
+ cmCursesMainForm* cm = static_cast<cmCursesMainForm*>(vp);
+ if (!cm) {
+ return;
+ }
+ char tmp[1024];
+ const char* cmsg = tmp;
+ if (prog >= 0) {
+ sprintf(tmp, "%s %i%%", msg, (int)(100 * prog));
+ } else {
+ cmsg = msg;
+ }
+ cm->UpdateStatusBar(cmsg);
+ cm->PrintKeys(1);
+ curses_move(1, 1);
+ touchwin(stdscr);
+ refresh();
+}
+
+int cmCursesMainForm::Configure(int noconfigure)
+{
+ int xi, yi;
+ getmaxyx(stdscr, yi, xi);
+
+ curses_move(1, 1);
+ this->UpdateStatusBar("Configuring, please wait...");
+ this->PrintKeys(1);
+ touchwin(stdscr);
+ refresh();
+ this->CMakeInstance->SetProgressCallback(cmCursesMainForm::UpdateProgress,
+ this);
+
+ // always save the current gui values to disk
+ this->FillCacheManagerFromUI();
+ this->CMakeInstance->SaveCache(
+ this->CMakeInstance->GetHomeOutputDirectory());
+ this->LoadCache(CM_NULLPTR);
+
+ // Get rid of previous errors
+ this->Errors = std::vector<std::string>();
+
+ // run the generate process
+ this->OkToGenerate = true;
+ int retVal;
+ if (noconfigure) {
+ retVal = this->CMakeInstance->DoPreConfigureChecks();
+ this->OkToGenerate = false;
+ if (retVal > 0) {
+ retVal = 0;
+ }
+ } else {
+ retVal = this->CMakeInstance->Configure();
+ }
+ this->CMakeInstance->SetProgressCallback(CM_NULLPTR, CM_NULLPTR);
+
+ keypad(stdscr, TRUE); /* Use key symbols as
+ KEY_DOWN*/
+
+ if (retVal != 0 || !this->Errors.empty()) {
+ // see if there was an error
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ this->OkToGenerate = false;
+ }
+ int xx, yy;
+ getmaxyx(stdscr, yy, xx);
+ cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
+ this->Errors, cmSystemTools::GetErrorOccuredFlag()
+ ? "Errors occurred during the last pass."
+ : "CMake produced the following output.");
+ // reset error condition
+ cmSystemTools::ResetErrorOccuredFlag();
+ CurrentForm = msgs;
+ msgs->Render(1, 1, xx, yy);
+ msgs->HandleInput();
+ // If they typed the wrong source directory, we report
+ // an error and exit
+ if (retVal == -2) {
+ return retVal;
+ }
+ CurrentForm = this;
+ this->Render(1, 1, xx, yy);
+ }
+
+ this->InitializeUI();
+ this->Render(1, 1, xi, yi);
+
+ return 0;
+}
+
+int cmCursesMainForm::Generate()
+{
+ int xi, yi;
+ getmaxyx(stdscr, yi, xi);
+
+ curses_move(1, 1);
+ this->UpdateStatusBar("Generating, please wait...");
+ this->PrintKeys(1);
+ touchwin(stdscr);
+ refresh();
+ this->CMakeInstance->SetProgressCallback(cmCursesMainForm::UpdateProgress,
+ this);
+
+ // Get rid of previous errors
+ this->Errors = std::vector<std::string>();
+
+ // run the generate process
+ int retVal = this->CMakeInstance->Generate();
+
+ this->CMakeInstance->SetProgressCallback(CM_NULLPTR, CM_NULLPTR);
+ keypad(stdscr, TRUE); /* Use key symbols as
+ KEY_DOWN*/
+
+ if (retVal != 0 || !this->Errors.empty()) {
+ // see if there was an error
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ this->OkToGenerate = false;
+ }
+ // reset error condition
+ cmSystemTools::ResetErrorOccuredFlag();
+ int xx, yy;
+ getmaxyx(stdscr, yy, xx);
+ const char* title = "Messages during last pass.";
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ title = "Errors occurred during the last pass.";
+ }
+ cmCursesLongMessageForm* msgs =
+ new cmCursesLongMessageForm(this->Errors, title);
+ CurrentForm = msgs;
+ msgs->Render(1, 1, xx, yy);
+ msgs->HandleInput();
+ // If they typed the wrong source directory, we report
+ // an error and exit
+ if (retVal == -2) {
+ return retVal;
+ }
+ CurrentForm = this;
+ this->Render(1, 1, xx, yy);
+ }
+
+ this->InitializeUI();
+ this->Render(1, 1, xi, yi);
+
+ return 0;
+}
+
+void cmCursesMainForm::AddError(const char* message, const char*)
+{
+ this->Errors.push_back(message);
+}
+
+void cmCursesMainForm::RemoveEntry(const char* value)
+{
+ if (!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;
+ }
+ }
+}
+
+// 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;
+ const char* existingValue =
+ this->CMakeInstance->GetState()->GetCacheEntryValue(cacheKey);
+ if (existingValue) {
+ std::string oldValue = existingValue;
+ std::string newValue = (*this->Entries)[i]->Entry->GetValue();
+ std::string fixedOldValue;
+ std::string fixedNewValue;
+ cmState::CacheEntryType t =
+ this->CMakeInstance->GetState()->GetCacheEntryType(cacheKey);
+ this->FixValue(t, oldValue, fixedOldValue);
+ this->FixValue(t, newValue, fixedNewValue);
+
+ if (!(fixedOldValue == fixedNewValue)) {
+ // The user has changed the value. Mark it as modified.
+ this->CMakeInstance->GetState()->SetCacheEntryBoolProperty(
+ cacheKey, "MODIFIED", true);
+ this->CMakeInstance->GetState()->SetCacheEntryValue(cacheKey,
+ fixedNewValue);
+ }
+ }
+ }
+}
+
+void cmCursesMainForm::FixValue(cmState::CacheEntryType type,
+ const std::string& in, std::string& out) const
+{
+ out = in.substr(0, in.find_last_not_of(' ') + 1);
+ if (type == cmState::PATH || type == cmState::FILEPATH) {
+ cmSystemTools::ConvertToUnixSlashes(out);
+ }
+ if (type == cmState::BOOL) {
+ if (cmSystemTools::IsOff(out.c_str())) {
+ out = "OFF";
+ } else {
+ out = "ON";
+ }
+ }
+}
+
+#include <unistd.h>
+
+void cmCursesMainForm::HandleInput()
+{
+ int x = 0, y = 0;
+
+ if (!this->Form) {
+ return;
+ }
+
+ FIELD* currentField;
+ cmCursesWidget* currentWidget;
+
+ char debugMessage[128];
+
+ for (;;) {
+ this->UpdateStatusBar();
+ this->PrintKeys();
+ if (this->SearchMode) {
+ std::string searchstr = "Search: " + this->SearchString;
+ this->UpdateStatusBar(searchstr.c_str());
+ this->PrintKeys(1);
+ curses_move(y - 5, static_cast<unsigned int>(searchstr.size()));
+ // curses_move(1,1);
+ touchwin(stdscr);
+ refresh();
+ }
+ int key = getch();
+
+ getmaxyx(stdscr, y, x);
+ // If window too small, handle 'q' only
+ if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) {
+ // quit
+ if (key == 'q') {
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ currentField = current_field(this->Form);
+ currentWidget =
+ reinterpret_cast<cmCursesWidget*>(field_userptr(currentField));
+
+ bool widgetHandled = false;
+
+ if (this->SearchMode) {
+ if (key == 10 || key == KEY_ENTER) {
+ this->SearchMode = false;
+ if (!this->SearchString.empty()) {
+ this->JumpToCacheEntry(this->SearchString.c_str());
+ this->OldSearchString = this->SearchString;
+ }
+ this->SearchString = "";
+ }
+ /*
+ else if ( key == KEY_ESCAPE )
+ {
+ this->SearchMode = false;
+ }
+ */
+ else if ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z') ||
+ (key >= '0' && key <= '9') || (key == '_')) {
+ if (this->SearchString.size() <
+ static_cast<std::string::size_type>(x - 10)) {
+ this->SearchString += static_cast<char>(key);
+ }
+ } else if (key == ctrl('h') || key == KEY_BACKSPACE || key == KEY_DC) {
+ if (!this->SearchString.empty()) {
+ this->SearchString.resize(this->SearchString.size() - 1);
+ }
+ }
+ } else if (currentWidget && !this->SearchMode) {
+ // Ask the current widget if it wants to handle input
+ widgetHandled = currentWidget->HandleInput(key, this, stdscr);
+ if (widgetHandled) {
+ this->OkToGenerate = false;
+ this->UpdateStatusBar();
+ this->PrintKeys();
+ }
+ }
+ if ((!currentWidget || !widgetHandled) && !this->SearchMode) {
+ // If the current widget does not want to handle input,
+ // we handle it.
+ sprintf(debugMessage, "Main form handling input, key: %d", key);
+ cmCursesForm::LogMessage(debugMessage);
+ // quit
+ if (key == 'q') {
+ break;
+ }
+ // if not end of page, next field otherwise next page
+ // each entry consists of fields: label, isnew, value
+ // therefore, the label field for the prev. entry is index-5
+ // and the label field for the next entry is index+1
+ // (index always corresponds to the value field)
+ else if (key == KEY_DOWN || key == ctrl('n')) {
+ FIELD* cur = current_field(this->Form);
+ size_t findex = field_index(cur);
+ if (findex == 3 * this->NumberOfVisibleEntries - 1) {
+ continue;
+ }
+ if (new_page(this->Fields[findex + 1])) {
+ form_driver(this->Form, REQ_NEXT_PAGE);
+ } else {
+ form_driver(this->Form, REQ_NEXT_FIELD);
+ }
+ }
+ // if not beginning of page, previous field, otherwise previous page
+ // each entry consists of fields: label, isnew, value
+ // therefore, the label field for the prev. entry is index-5
+ // and the label field for the next entry is index+1
+ // (index always corresponds to the value field)
+ else if (key == KEY_UP || key == ctrl('p')) {
+ FIELD* cur = current_field(this->Form);
+ int findex = field_index(cur);
+ if (findex == 2) {
+ continue;
+ }
+ if (new_page(this->Fields[findex - 2])) {
+ form_driver(this->Form, REQ_PREV_PAGE);
+ set_current_field(this->Form, this->Fields[findex - 3]);
+ } else {
+ form_driver(this->Form, REQ_PREV_FIELD);
+ }
+ }
+ // pg down
+ else if (key == KEY_NPAGE || key == ctrl('d')) {
+ form_driver(this->Form, REQ_NEXT_PAGE);
+ }
+ // pg up
+ else if (key == KEY_PPAGE || key == ctrl('u')) {
+ form_driver(this->Form, REQ_PREV_PAGE);
+ }
+ // configure
+ else if (key == 'c') {
+ this->Configure();
+ }
+ // display help
+ else if (key == 'h') {
+ getmaxyx(stdscr, y, x);
+
+ FIELD* cur = current_field(this->Form);
+ int findex = field_index(cur);
+ cmCursesWidget* lbl = reinterpret_cast<cmCursesWidget*>(
+ field_userptr(this->Fields[findex - 2]));
+ const char* curField = lbl->GetValue();
+ const char* helpString = CM_NULLPTR;
+
+ const char* existingValue =
+ this->CMakeInstance->GetState()->GetCacheEntryValue(curField);
+ if (existingValue) {
+ helpString = this->CMakeInstance->GetState()->GetCacheEntryProperty(
+ curField, "HELPSTRING");
+ }
+ if (helpString) {
+ char* message = new char
+ [strlen(curField) + strlen(helpString) +
+ strlen(
+ "Current option is: \n Help string for this option is: \n") +
+ 10];
+ sprintf(
+ message,
+ "Current option is: %s\nHelp string for this option is: %s\n",
+ curField, helpString);
+ this->HelpMessage[1] = message;
+ delete[] message;
+ } else {
+ this->HelpMessage[1] = "";
+ }
+
+ cmCursesLongMessageForm* msgs =
+ new cmCursesLongMessageForm(this->HelpMessage, "Help.");
+ CurrentForm = msgs;
+ msgs->Render(1, 1, x, y);
+ msgs->HandleInput();
+ CurrentForm = this;
+ this->Render(1, 1, x, y);
+ set_current_field(this->Form, cur);
+ }
+ // display last errors
+ else if (key == 'l') {
+ getmaxyx(stdscr, y, x);
+ cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
+ this->Errors, "Errors occurred during the last pass.");
+ CurrentForm = msgs;
+ msgs->Render(1, 1, x, y);
+ msgs->HandleInput();
+ CurrentForm = this;
+ this->Render(1, 1, x, y);
+ } else if (key == '/') {
+ this->SearchMode = true;
+ this->UpdateStatusBar("Search");
+ this->PrintKeys(1);
+ touchwin(stdscr);
+ refresh();
+ } else if (key == 'n') {
+ if (!this->OldSearchString.empty()) {
+ this->JumpToCacheEntry(this->OldSearchString.c_str());
+ }
+ }
+ // switch advanced on/off
+ else if (key == 't') {
+ if (this->AdvancedMode) {
+ this->AdvancedMode = false;
+ } else {
+ this->AdvancedMode = true;
+ }
+ getmaxyx(stdscr, y, x);
+ this->RePost();
+ this->Render(1, 1, x, y);
+ }
+ // generate and exit
+ else if (key == 'g') {
+ if (this->OkToGenerate) {
+ this->Generate();
+ break;
+ }
+ }
+ // delete cache entry
+ else if (key == 'd' && this->NumberOfVisibleEntries) {
+ this->OkToGenerate = false;
+ FIELD* cur = current_field(this->Form);
+ size_t findex = field_index(cur);
+
+ // make the next or prev. current field after deletion
+ // each entry consists of fields: label, isnew, value
+ // therefore, the label field for the prev. entry is findex-5
+ // and the label field for the next entry is findex+1
+ // (findex always corresponds to the value field)
+ FIELD* nextCur;
+ if (findex == 2) {
+ nextCur = CM_NULLPTR;
+ } else if (findex == 3 * this->NumberOfVisibleEntries - 1) {
+ nextCur = this->Fields[findex - 5];
+ } else {
+ nextCur = this->Fields[findex + 1];
+ }
+
+ // Get the label widget
+ // each entry consists of fields: label, isnew, value
+ // therefore, the label field for the is findex-2
+ // (findex always corresponds to the value field)
+ cmCursesWidget* lbl = reinterpret_cast<cmCursesWidget*>(
+ field_userptr(this->Fields[findex - 2]));
+ if (lbl) {
+ this->CMakeInstance->GetState()->RemoveCacheEntry(lbl->GetValue());
+
+ std::string nextVal;
+ if (nextCur) {
+ nextVal =
+ (reinterpret_cast<cmCursesWidget*>(field_userptr(nextCur))
+ ->GetValue());
+ }
+
+ getmaxyx(stdscr, y, x);
+ this->RemoveEntry(lbl->GetValue());
+ this->RePost();
+ this->Render(1, 1, x, y);
+
+ if (nextCur) {
+ // make the next or prev. current field after deletion
+ nextCur = CM_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);
+ }
+ }
+ }
+ }
+ }
+
+ touchwin(stdscr);
+ wrefresh(stdscr);
+ }
+}
+
+int cmCursesMainForm::LoadCache(const char*)
+
+{
+ int r = this->CMakeInstance->LoadCache();
+ if (r < 0) {
+ return r;
+ }
+ this->CMakeInstance->SetCacheArgs(this->Args);
+ this->CMakeInstance->PreLoadCMakeFiles();
+ return r;
+}
+
+void cmCursesMainForm::JumpToCacheEntry(const char* astr)
+{
+ std::string str;
+ if (astr) {
+ str = cmSystemTools::LowerCase(astr);
+ }
+
+ if (str.empty()) {
+ return;
+ }
+ FIELD* cur = current_field(this->Form);
+ int start_index = field_index(cur);
+ int findex = start_index;
+ for (;;) {
+ if (!str.empty()) {
+ cmCursesWidget* lbl = CM_NULLPTR;
+ if (findex >= 0) {
+ lbl = reinterpret_cast<cmCursesWidget*>(
+ field_userptr(this->Fields[findex - 2]));
+ }
+ if (lbl) {
+ const char* curField = lbl->GetValue();
+ if (curField) {
+ std::string cfld = cmSystemTools::LowerCase(curField);
+ if (cfld.find(str) != cfld.npos && findex != start_index) {
+ break;
+ }
+ }
+ }
+ }
+ if (size_t(findex) >= 3 * this->NumberOfVisibleEntries - 1) {
+ set_current_field(this->Form, this->Fields[2]);
+ } else if (new_page(this->Fields[findex + 1])) {
+ form_driver(this->Form, REQ_NEXT_PAGE);
+ } else {
+ form_driver(this->Form, REQ_NEXT_FIELD);
+ }
+ /*
+ char buffer[1024];
+ sprintf(buffer, "Line: %d != %d / %d\n", findex, idx,
+ this->NumberOfVisibleEntries);
+ touchwin(stdscr);
+ refresh();
+ this->UpdateStatusBar( buffer );
+ usleep(100000);
+ */
+ cur = current_field(this->Form);
+ findex = field_index(cur);
+ if (findex == start_index) {
+ break;
+ }
+ }
+}
+
+const char* cmCursesMainForm::s_ConstHelpMessage =
+ "CMake is used to configure and generate build files for software projects. "
+ "The basic steps for configuring a project with ccmake are as follows:\n\n"
+ "1. Run ccmake in the directory where you want the object and executable "
+ "files to be placed (build directory). If the source directory is not the "
+ "same as this build directory, you have to specify it as an argument on the "
+ "command line.\n\n"
+ "2. When ccmake is run, it will read the configuration files and display "
+ "the current build options. "
+ "If you have run CMake before and have updated the configuration files "
+ "since then, any new entries will be displayed on top and will be marked "
+ "with a *. "
+ "On the other hand, the first time you run ccmake, all build options will "
+ "be new and will be marked as such. "
+ "At this point, you can modify any options (see keys below) you want to "
+ "change. "
+ "When you are satisfied with your changes, press 'c' to have CMake process "
+ "the configuration files. "
+ "Please note that changing some options may cause new ones to appear. These "
+ "will be shown on top and will be marked with *. "
+ "Repeat this procedure until you are satisfied with all the options and "
+ "there are no new entries. "
+ "At this point, a new command will appear: G)enerate and Exit. You can now "
+ "hit 'g' to have CMake generate all the build files (i.e. makefiles or "
+ "project files) and exit. "
+ "At any point during the process, you can exit ccmake with 'q'. However, "
+ "this will not generate/change any build files.\n\n"
+ "ccmake KEYS:\n\n"
+ "Navigation: "
+ "You can use the arrow keys and page up, down to navigate the options. "
+ "Alternatively, you can use the following keys: \n"
+ " C-n : next option\n"
+ " C-p : previous options\n"
+ " C-d : down one page\n"
+ " C-u : up one page\n\n"
+ "Editing options: "
+ "To change an option press enter or return. If the current options is a "
+ "boolean, this will toggle it's value. "
+ "Otherwise, ccmake will enter edit mode. In this mode you can edit an "
+ "option using arrow keys and backspace. Alternatively, you can use the "
+ "following keys:\n"
+ " C-b : back one character\n"
+ " C-f : forward one character\n"
+ " C-a : go to the beginning of the field\n"
+ " C-e : go to the end of the field\n"
+ " C-d : delete previous character\n"
+ " C-k : kill the rest of the field\n"
+ " Esc : Restore field (discard last changes)\n"
+ " Enter : Leave edit mode\n"
+ "You can also delete an option by pressing 'd'\n\n"
+ "Commands:\n"
+ " q : quit ccmake without generating build files\n"
+ " h : help, shows this screen\n"
+ " c : process the configuration files with the current options\n"
+ " g : generate build files and exit, only available when there are no "
+ "new options and no errors have been detected during last configuration.\n"
+ " l : shows last errors\n"
+ " t : toggles advanced mode. In normal mode, only the most important "
+ "options are shown. In advanced mode, all options are shown. We recommend "
+ "using normal mode unless you are an expert.\n"
+ " / : search for a variable name.\n";
diff --git a/Source/CursesDialog/cmCursesMainForm.h b/Source/CursesDialog/cmCursesMainForm.h
new file mode 100644
index 0000000..d17ee33
--- /dev/null
+++ b/Source/CursesDialog/cmCursesMainForm.h
@@ -0,0 +1,166 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCursesMainForm_h
+#define cmCursesMainForm_h
+
+#include "cmCursesStandardIncludes.h"
+
+#include "../cmState.h"
+#include "cmCursesForm.h"
+
+class cmCursesCacheEntryComposite;
+class cmCursesWidget;
+class cmake;
+
+/** \class cmCursesMainForm
+ * \brief The main page of ccmake
+ *
+ * cmCursesMainForm is the main page of ccmake.
+ */
+class cmCursesMainForm : public cmCursesForm
+{
+public:
+ cmCursesMainForm(std::vector<std::string> const& args, int initwidth);
+ ~cmCursesMainForm() CM_OVERRIDE;
+
+ /**
+ * Set the widgets which represent the cache entries.
+ */
+ void InitializeUI();
+
+ /**
+ * Handle user input.
+ */
+ void HandleInput() CM_OVERRIDE;
+
+ /**
+ * Display form. Use a window of size width x height, starting
+ * at top, left.
+ */
+ void Render(int left, int top, int width, int height) CM_OVERRIDE;
+
+ /**
+ * Returns true if an entry with the given key is in the
+ * list of current composites.
+ */
+ bool LookForCacheEntry(const std::string& key);
+
+ enum
+ {
+ MIN_WIDTH = 65,
+ MIN_HEIGHT = 6,
+ IDEAL_WIDTH = 80,
+ MAX_WIDTH = 512
+ };
+
+ /**
+ * This method should normally be called only by the form. The only
+ * exception is during a resize. The optional argument specifies the
+ * string to be displayed in the status bar.
+ */
+ void UpdateStatusBar() CM_OVERRIDE { this->UpdateStatusBar(CM_NULLPTR); }
+ virtual void UpdateStatusBar(const char* message);
+
+ /**
+ * Display current commands and their keys on the toolbar. This
+ * method should normally called only by the form. The only
+ * exception is during a resize. If the optional argument process is
+ * specified and is either 1 (configure) or 2 (generate), then keys
+ * will be displayed accordingly.
+ */
+ void PrintKeys(int process = 0);
+
+ /**
+ * During a CMake run, an error handle should add errors
+ * to be displayed afterwards.
+ */
+ void AddError(const char* message, const char* title) CM_OVERRIDE;
+
+ /**
+ * Used to do a configure. If argument is specified, it does only the check
+ * and not configure.
+ */
+ int Configure(int noconfigure = 0);
+
+ /**
+ * Used to generate
+ */
+ int Generate();
+
+ /**
+ * Used by main program
+ */
+ int LoadCache(const char* dir);
+
+ /**
+ * Progress callback
+ */
+ static void UpdateProgressOld(const char* msg, float prog, void*);
+ static void UpdateProgress(const char* msg, float prog, void*);
+
+protected:
+ cmCursesMainForm(const cmCursesMainForm& from);
+ void operator=(const cmCursesMainForm&);
+
+ // Copy the cache values from the user interface to the actual
+ // cache.
+ void FillCacheManagerFromUI();
+ // Fix formatting of values to a consistent form.
+ void FixValue(cmState::CacheEntryType type, const std::string& in,
+ std::string& out) const;
+ // Re-post the existing fields. Used to toggle between
+ // normal and advanced modes. Render() should be called
+ // afterwards.
+ void RePost();
+ // Remove an entry from the interface and the cache.
+ void RemoveEntry(const char* value);
+
+ // Jump to the cache entry whose name matches the string.
+ void JumpToCacheEntry(const char* str);
+
+ // Copies of cache entries stored in the user interface
+ std::vector<cmCursesCacheEntryComposite*>* Entries;
+ // Errors produced during last run of cmake
+ std::vector<std::string> Errors;
+ // Command line argumens to be passed to cmake each time
+ // it is run
+ std::vector<std::string> Args;
+ // Message displayed when user presses 'h'
+ // It is: Welcome + info about current entry + common help
+ std::vector<std::string> HelpMessage;
+
+ // Common help
+ static const char* s_ConstHelpMessage;
+
+ // Fields displayed. Includes labels, new entry markers, entries
+ FIELD** Fields;
+ // Where is source of current project
+ std::string WhereSource;
+ // Where is cmake executable
+ std::string WhereCMake;
+ // Number of entries shown (depends on mode -normal or advanced-)
+ size_t NumberOfVisibleEntries;
+ bool AdvancedMode;
+ // Did the iteration converge (no new entries) ?
+ bool OkToGenerate;
+ // Number of pages displayed
+ int NumberOfPages;
+
+ int InitialWidth;
+ cmake* CMakeInstance;
+
+ std::string SearchString;
+ std::string OldSearchString;
+ bool SearchMode;
+};
+
+#endif // cmCursesMainForm_h
diff --git a/Source/CursesDialog/cmCursesOptionsWidget.cxx b/Source/CursesDialog/cmCursesOptionsWidget.cxx
new file mode 100644
index 0000000..1a3a8c2
--- /dev/null
+++ b/Source/CursesDialog/cmCursesOptionsWidget.cxx
@@ -0,0 +1,93 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCursesOptionsWidget.h"
+
+#include "cmCursesMainForm.h"
+
+inline int ctrl(int z)
+{
+ return (z & 037);
+}
+
+cmCursesOptionsWidget::cmCursesOptionsWidget(int width, int height, int left,
+ int top)
+ : cmCursesWidget(width, height, left, top)
+{
+ this->Type = cmState::BOOL; // this is a bit of a hack
+ // there is no option type, and string type causes ccmake to cast
+ // the widget into a string widget at some point. BOOL is safe for
+ // now.
+ set_field_fore(this->Field, A_NORMAL);
+ set_field_back(this->Field, A_STANDOUT);
+ field_opts_off(this->Field, O_STATIC);
+}
+
+bool cmCursesOptionsWidget::HandleInput(int& key, cmCursesMainForm*, WINDOW* w)
+{
+
+ // 10 == enter
+ if (key == 10 || key == KEY_ENTER) {
+ this->NextOption();
+ touchwin(w);
+ wrefresh(w);
+ return true;
+ } else if (key == KEY_LEFT || key == ctrl('b')) {
+ touchwin(w);
+ wrefresh(w);
+ this->PreviousOption();
+ return true;
+ } else if (key == KEY_RIGHT || key == ctrl('f')) {
+ this->NextOption();
+ touchwin(w);
+ wrefresh(w);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void cmCursesOptionsWidget::AddOption(std::string const& option)
+{
+ this->Options.push_back(option);
+}
+
+void cmCursesOptionsWidget::NextOption()
+{
+ this->CurrentOption++;
+ if (this->CurrentOption > this->Options.size() - 1) {
+ this->CurrentOption = 0;
+ }
+ this->SetValue(this->Options[this->CurrentOption]);
+}
+void cmCursesOptionsWidget::PreviousOption()
+{
+ if (this->CurrentOption == 0) {
+ this->CurrentOption = this->Options.size() - 1;
+ } else {
+ this->CurrentOption--;
+ }
+ this->SetValue(this->Options[this->CurrentOption]);
+}
+
+void cmCursesOptionsWidget::SetOption(const std::string& value)
+{
+ this->CurrentOption = 0; // default to 0 index
+ this->SetValue(value);
+ int index = 0;
+ for (std::vector<std::string>::iterator i = this->Options.begin();
+ i != this->Options.end(); ++i) {
+ if (*i == value) {
+ this->CurrentOption = index;
+ }
+ index++;
+ }
+}
diff --git a/Source/CursesDialog/cmCursesOptionsWidget.h b/Source/CursesDialog/cmCursesOptionsWidget.h
new file mode 100644
index 0000000..f88b6bc
--- /dev/null
+++ b/Source/CursesDialog/cmCursesOptionsWidget.h
@@ -0,0 +1,41 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCursesOptionsWidget_h
+#define cmCursesOptionsWidget_h
+
+#include "cmCursesWidget.h"
+
+class cmCursesMainForm;
+
+class cmCursesOptionsWidget : public cmCursesWidget
+{
+public:
+ cmCursesOptionsWidget(int width, int height, int left, int top);
+
+ // Description:
+ // Handle user input. Called by the container of this widget
+ // when this widget has focus. Returns true if the input was
+ // handled.
+ bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) CM_OVERRIDE;
+ void SetOption(const std::string&);
+ void AddOption(std::string const&);
+ void NextOption();
+ void PreviousOption();
+
+protected:
+ cmCursesOptionsWidget(const cmCursesOptionsWidget& from);
+ void operator=(const cmCursesOptionsWidget&);
+ std::vector<std::string> Options;
+ std::vector<std::string>::size_type CurrentOption;
+};
+
+#endif // cmCursesOptionsWidget_h
diff --git a/Source/CursesDialog/cmCursesPathWidget.cxx b/Source/CursesDialog/cmCursesPathWidget.cxx
new file mode 100644
index 0000000..33fffd1
--- /dev/null
+++ b/Source/CursesDialog/cmCursesPathWidget.cxx
@@ -0,0 +1,86 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCursesPathWidget.h"
+
+#include "cmCursesMainForm.h"
+#include "cmSystemTools.h"
+
+cmCursesPathWidget::cmCursesPathWidget(int width, int height, int left,
+ int top)
+ : cmCursesStringWidget(width, height, left, top)
+{
+ this->Type = cmState::PATH;
+ this->Cycle = false;
+ this->CurrentIndex = 0;
+}
+
+void cmCursesPathWidget::OnType(int& key, cmCursesMainForm* fm, WINDOW* w)
+{
+ this->Cycle = false;
+ this->CurrentIndex = 0;
+ this->LastGlob = "";
+ this->cmCursesStringWidget::OnType(key, fm, w);
+}
+
+void cmCursesPathWidget::OnTab(cmCursesMainForm* fm, WINDOW* w)
+{
+ if (!this->GetString()) {
+ return;
+ }
+ FORM* form = fm->GetForm();
+ form_driver(form, REQ_NEXT_FIELD);
+ form_driver(form, REQ_PREV_FIELD);
+ std::string cstr = this->GetString();
+ cstr = cstr.substr(0, cstr.find_last_not_of(" \t\n\r") + 1);
+ if (this->LastString != cstr) {
+ this->Cycle = false;
+ this->CurrentIndex = 0;
+ this->LastGlob = "";
+ }
+ std::string glob;
+ if (this->Cycle) {
+ glob = this->LastGlob;
+ } else {
+ glob = cstr + "*";
+ }
+ std::vector<std::string> dirs;
+
+ cmSystemTools::SimpleGlob(glob, dirs,
+ (this->Type == cmState::PATH ? -1 : 0));
+ if (this->CurrentIndex < dirs.size()) {
+ cstr = dirs[this->CurrentIndex];
+ }
+ if (cstr[cstr.size() - 1] == '*') {
+ cstr = cstr.substr(0, cstr.size() - 1);
+ }
+
+ if (cmSystemTools::FileIsDirectory(cstr)) {
+ cstr += "/";
+ }
+
+ this->SetString(cstr);
+ touchwin(w);
+ wrefresh(w);
+ form_driver(form, REQ_END_FIELD);
+ this->LastGlob = glob;
+ this->LastString = cstr;
+ this->Cycle = true;
+ this->CurrentIndex++;
+ if (this->CurrentIndex >= dirs.size()) {
+ this->CurrentIndex = 0;
+ }
+}
+
+void cmCursesPathWidget::OnReturn(cmCursesMainForm* fm, WINDOW* w)
+{
+ this->cmCursesStringWidget::OnReturn(fm, w);
+}
diff --git a/Source/CursesDialog/cmCursesPathWidget.h b/Source/CursesDialog/cmCursesPathWidget.h
new file mode 100644
index 0000000..cd26df6
--- /dev/null
+++ b/Source/CursesDialog/cmCursesPathWidget.h
@@ -0,0 +1,40 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCursesPathWidget_h
+#define cmCursesPathWidget_h
+
+#include "cmCursesStringWidget.h"
+
+class cmCursesPathWidget : public cmCursesStringWidget
+{
+public:
+ cmCursesPathWidget(int width, int height, int left, int top);
+
+ /**
+ * This method is called when different keys are pressed. The
+ * subclass can have a special implementation handler for this.
+ */
+ void OnTab(cmCursesMainForm* fm, WINDOW* w) CM_OVERRIDE;
+ void OnReturn(cmCursesMainForm* fm, WINDOW* w) CM_OVERRIDE;
+ void OnType(int& key, cmCursesMainForm* fm, WINDOW* w) CM_OVERRIDE;
+
+protected:
+ cmCursesPathWidget(const cmCursesPathWidget& from);
+ void operator=(const cmCursesPathWidget&);
+
+ std::string LastString;
+ std::string LastGlob;
+ bool Cycle;
+ std::string::size_type CurrentIndex;
+};
+
+#endif // cmCursesPathWidget_h
diff --git a/Source/CursesDialog/cmCursesStandardIncludes.h b/Source/CursesDialog/cmCursesStandardIncludes.h
new file mode 100644
index 0000000..7b44df9
--- /dev/null
+++ b/Source/CursesDialog/cmCursesStandardIncludes.h
@@ -0,0 +1,45 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCursesStandardIncludes_h
+#define cmCursesStandardIncludes_h
+
+#include "../cmStandardIncludes.h"
+
+#if defined(__sun__) && defined(__GNUC__)
+#define _MSE_INT_H
+#endif
+
+#if defined(__hpux)
+#define _BOOL_DEFINED
+#include <sys/time.h>
+#endif
+
+#include <form.h>
+
+// on some machines move erase and clear conflict with stl
+// so remove them from the namespace
+inline void curses_move(unsigned int x, unsigned int y)
+{
+ move(x, y);
+}
+
+inline void curses_clear()
+{
+ erase();
+ clearok(stdscr, TRUE);
+}
+
+#undef move
+#undef erase
+#undef clear
+
+#endif // cmCursesStandardIncludes_h
diff --git a/Source/CursesDialog/cmCursesStringWidget.cxx b/Source/CursesDialog/cmCursesStringWidget.cxx
new file mode 100644
index 0000000..6eb5310
--- /dev/null
+++ b/Source/CursesDialog/cmCursesStringWidget.cxx
@@ -0,0 +1,205 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCursesStringWidget.h"
+
+#include "cmCursesMainForm.h"
+
+inline int ctrl(int z)
+{
+ return (z & 037);
+}
+
+cmCursesStringWidget::cmCursesStringWidget(int width, int height, int left,
+ int top)
+ : cmCursesWidget(width, height, left, top)
+{
+ this->InEdit = false;
+ this->Type = cmState::STRING;
+ set_field_fore(this->Field, A_NORMAL);
+ set_field_back(this->Field, A_STANDOUT);
+ field_opts_off(this->Field, O_STATIC);
+}
+
+void cmCursesStringWidget::OnTab(cmCursesMainForm*, WINDOW*)
+{
+ // FORM* form = fm->GetForm();
+}
+
+void cmCursesStringWidget::OnReturn(cmCursesMainForm* fm, WINDOW*)
+{
+ FORM* form = fm->GetForm();
+ if (this->InEdit) {
+ cmCursesForm::LogMessage("String widget leaving edit.");
+ this->InEdit = false;
+ fm->PrintKeys();
+ delete[] this->OriginalString;
+ // trick to force forms to update the field buffer
+ form_driver(form, REQ_NEXT_FIELD);
+ form_driver(form, REQ_PREV_FIELD);
+ this->Done = true;
+ } else {
+ cmCursesForm::LogMessage("String widget entering edit.");
+ this->InEdit = true;
+ fm->PrintKeys();
+ char* buf = field_buffer(this->Field, 0);
+ this->OriginalString = new char[strlen(buf) + 1];
+ strcpy(this->OriginalString, buf);
+ }
+}
+
+void cmCursesStringWidget::OnType(int& key, cmCursesMainForm* fm, WINDOW*)
+{
+ form_driver(fm->GetForm(), key);
+}
+
+bool cmCursesStringWidget::HandleInput(int& key, cmCursesMainForm* fm,
+ WINDOW* w)
+{
+ int x, y;
+
+ FORM* form = fm->GetForm();
+ // 10 == enter
+ if (!this->InEdit && (key != 10 && key != KEY_ENTER)) {
+ return false;
+ }
+
+ this->OriginalString = CM_NULLPTR;
+ this->Done = false;
+
+ char debugMessage[128];
+
+ // <Enter> is used to change edit mode (like <Esc> in vi).
+ while (!this->Done) {
+ sprintf(debugMessage, "String widget handling input, key: %d", key);
+ cmCursesForm::LogMessage(debugMessage);
+
+ fm->PrintKeys();
+
+ getmaxyx(stdscr, y, x);
+ // If window too small, handle 'q' only
+ if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) {
+ // quit
+ if (key == 'q') {
+ return false;
+ } else {
+ key = getch();
+ continue;
+ }
+ }
+
+ // If resize occurred during edit, move out of edit mode
+ if (!this->InEdit && (key != 10 && key != KEY_ENTER)) {
+ return false;
+ }
+ // 10 == enter
+ if (key == 10 || key == KEY_ENTER) {
+ this->OnReturn(fm, w);
+ } else if (key == KEY_DOWN || key == ctrl('n') || key == KEY_UP ||
+ key == ctrl('p') || key == KEY_NPAGE || key == ctrl('d') ||
+ key == KEY_PPAGE || key == ctrl('u')) {
+ this->InEdit = false;
+ delete[] this->OriginalString;
+ // trick to force forms to update the field buffer
+ form_driver(form, REQ_NEXT_FIELD);
+ form_driver(form, REQ_PREV_FIELD);
+ return false;
+ }
+ // esc
+ else if (key == 27) {
+ if (this->InEdit) {
+ this->InEdit = false;
+ fm->PrintKeys();
+ this->SetString(this->OriginalString);
+ delete[] this->OriginalString;
+ touchwin(w);
+ wrefresh(w);
+ return true;
+ }
+ } else if (key == 9) {
+ this->OnTab(fm, w);
+ } else if (key == KEY_LEFT || key == ctrl('b')) {
+ form_driver(form, REQ_PREV_CHAR);
+ } else if (key == KEY_RIGHT || key == ctrl('f')) {
+ form_driver(form, REQ_NEXT_CHAR);
+ } else if (key == ctrl('k')) {
+ form_driver(form, REQ_CLR_EOL);
+ } else if (key == ctrl('a') || key == KEY_HOME) {
+ form_driver(form, REQ_BEG_FIELD);
+ } else if (key == ctrl('e') || key == KEY_END) {
+ form_driver(form, REQ_END_FIELD);
+ } else if (key == 127 || key == KEY_BACKSPACE) {
+ FIELD* cur = current_field(form);
+ form_driver(form, REQ_DEL_PREV);
+ if (current_field(form) != cur) {
+ set_current_field(form, cur);
+ }
+ } else if (key == ctrl('d') || key == KEY_DC) {
+ form_driver(form, REQ_DEL_CHAR);
+ } else {
+ this->OnType(key, fm, w);
+ }
+ if (!this->Done) {
+ touchwin(w);
+ wrefresh(w);
+
+ key = getch();
+ }
+ }
+ return true;
+}
+
+void cmCursesStringWidget::SetString(const std::string& value)
+{
+ this->SetValue(value);
+}
+
+const char* cmCursesStringWidget::GetString()
+{
+ return this->GetValue();
+}
+
+const char* cmCursesStringWidget::GetValue()
+{
+ return field_buffer(this->Field, 0);
+}
+
+bool cmCursesStringWidget::PrintKeys()
+{
+ int x, y;
+ getmaxyx(stdscr, y, x);
+ if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) {
+ return false;
+ }
+ if (this->InEdit) {
+ char fmt_s[] = "%s";
+ char firstLine[512];
+ // Clean the toolbar
+ for (int i = 0; i < 512; i++) {
+ firstLine[i] = ' ';
+ }
+ firstLine[511] = '\0';
+ curses_move(y - 4, 0);
+ printw(fmt_s, firstLine);
+ curses_move(y - 3, 0);
+ printw(fmt_s, firstLine);
+ curses_move(y - 2, 0);
+ printw(fmt_s, firstLine);
+ curses_move(y - 1, 0);
+ printw(fmt_s, firstLine);
+
+ curses_move(y - 3, 0);
+ printw(fmt_s, "Editing option, press [enter] to leave edit.");
+ return true;
+ } else {
+ return false;
+ }
+}
diff --git a/Source/CursesDialog/cmCursesStringWidget.h b/Source/CursesDialog/cmCursesStringWidget.h
new file mode 100644
index 0000000..c8ca482
--- /dev/null
+++ b/Source/CursesDialog/cmCursesStringWidget.h
@@ -0,0 +1,76 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCursesStringWidget_h
+#define cmCursesStringWidget_h
+
+#include "cmCursesWidget.h"
+
+class cmCursesMainForm;
+
+/** \class cmCursesStringWidget
+ * \brief A simple entry widget.
+ *
+ * cmCursesStringWdiget is a simple text entry widget.
+ */
+
+class cmCursesStringWidget : public cmCursesWidget
+{
+public:
+ cmCursesStringWidget(int width, int height, int left, int top);
+
+ /**
+ * Handle user input. Called by the container of this widget
+ * when this widget has focus. Returns true if the input was
+ * handled.
+ */
+ bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) CM_OVERRIDE;
+
+ /**
+ * Set/Get the string.
+ */
+ void SetString(const std::string& value);
+ const char* GetString();
+ const char* GetValue() CM_OVERRIDE;
+
+ /**
+ * Set/Get InEdit flag. Can be used to tell the widget to leave
+ * edit mode (in case of a resize for example).
+ */
+ void SetInEdit(bool inedit) { this->InEdit = inedit; }
+ bool GetInEdit() { return this->InEdit; }
+
+ /**
+ * This method is called when different keys are pressed. The
+ * subclass can have a special implementation handler for this.
+ */
+ virtual void OnTab(cmCursesMainForm* fm, WINDOW* w);
+ virtual void OnReturn(cmCursesMainForm* fm, WINDOW* w);
+ virtual void OnType(int& key, cmCursesMainForm* fm, WINDOW* w);
+
+ /**
+ * If there are any, print the widget specific commands
+ * in the toolbar and return true. Otherwise, return false
+ * and the parent widget will print.
+ */
+ bool PrintKeys() CM_OVERRIDE;
+
+protected:
+ cmCursesStringWidget(const cmCursesStringWidget& from);
+ void operator=(const cmCursesStringWidget&);
+
+ // true if the widget is in edit mode
+ bool InEdit;
+ char* OriginalString;
+ bool Done;
+};
+
+#endif // cmCursesStringWidget_h
diff --git a/Source/CursesDialog/cmCursesWidget.cxx b/Source/CursesDialog/cmCursesWidget.cxx
new file mode 100644
index 0000000..49f2795
--- /dev/null
+++ b/Source/CursesDialog/cmCursesWidget.cxx
@@ -0,0 +1,53 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCursesWidget.h"
+
+cmCursesWidget::cmCursesWidget(int width, int height, int left, int top)
+{
+ this->Field = new_field(height, width, top, left, 0, 0);
+ set_field_userptr(this->Field, reinterpret_cast<char*>(this));
+ field_opts_off(this->Field, O_AUTOSKIP);
+ this->Page = 0;
+}
+
+cmCursesWidget::~cmCursesWidget()
+{
+ if (this->Field) {
+ free_field(this->Field);
+ this->Field = CM_NULLPTR;
+ }
+}
+
+void cmCursesWidget::Move(int x, int y, bool isNewPage)
+{
+ if (!this->Field) {
+ return;
+ }
+
+ move_field(this->Field, y, x);
+ if (isNewPage) {
+ set_new_page(this->Field, TRUE);
+ } else {
+ set_new_page(this->Field, FALSE);
+ }
+}
+
+void cmCursesWidget::SetValue(const std::string& value)
+{
+ this->Value = value;
+ set_field_buffer(this->Field, 0, const_cast<char*>(value.c_str()));
+}
+
+const char* cmCursesWidget::GetValue()
+{
+ return this->Value.c_str();
+}
diff --git a/Source/CursesDialog/cmCursesWidget.h b/Source/CursesDialog/cmCursesWidget.h
new file mode 100644
index 0000000..2ac5bb8
--- /dev/null
+++ b/Source/CursesDialog/cmCursesWidget.h
@@ -0,0 +1,78 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCursesWidget_h
+#define cmCursesWidget_h
+
+#include "cmCursesStandardIncludes.h"
+
+#include "../cmState.h"
+
+class cmCursesMainForm;
+
+class cmCursesWidget
+{
+public:
+ cmCursesWidget(int width, int height, int left, int top);
+ virtual ~cmCursesWidget();
+
+ /**
+ * Handle user input. Called by the container of this widget
+ * when this widget has focus. Returns true if the input was
+ * handled
+ */
+ virtual bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) = 0;
+
+ /**
+ * Change the position of the widget. Set isNewPage to true
+ * if this widget marks the beginning of a new page.
+ */
+ virtual void Move(int x, int y, bool isNewPage);
+
+ /**
+ * Set/Get the value (setting the value also changes the contents
+ * of the field buffer).
+ */
+ virtual void SetValue(const std::string& value);
+ virtual const char* GetValue();
+
+ /**
+ * Get the type of the widget (STRING, PATH etc...)
+ */
+ cmState::CacheEntryType GetType() { return this->Type; }
+
+ /**
+ * If there are any, print the widget specific commands
+ * in the toolbar and return true. Otherwise, return false
+ * and the parent widget will print.
+ */
+ virtual bool PrintKeys() { return false; }
+
+ /**
+ * Set/Get the page this widget is in.
+ */
+ void SetPage(int page) { this->Page = page; }
+ int GetPage() { return this->Page; }
+
+ friend class cmCursesMainForm;
+
+protected:
+ cmCursesWidget(const cmCursesWidget& from);
+ void operator=(const cmCursesWidget&);
+
+ cmState::CacheEntryType Type;
+ std::string Value;
+ FIELD* Field;
+ // The page in the main form this widget is in
+ int Page;
+};
+
+#endif // cmCursesWidget_h
diff --git a/Source/CursesDialog/form/.NoDartCoverage b/Source/CursesDialog/form/.NoDartCoverage
new file mode 100644
index 0000000..3c99729
--- /dev/null
+++ b/Source/CursesDialog/form/.NoDartCoverage
@@ -0,0 +1 @@
+# do not do coverage in this directory
diff --git a/Source/CursesDialog/form/CMakeLists.txt b/Source/CursesDialog/form/CMakeLists.txt
new file mode 100644
index 0000000..4e07fa0
--- /dev/null
+++ b/Source/CursesDialog/form/CMakeLists.txt
@@ -0,0 +1,66 @@
+#=============================================================================
+# CMake - Cross Platform Makefile Generator
+# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+project(CMAKE_FORM)
+
+include_regular_expression("^.*$")
+include_directories(${CURSES_INCLUDE_PATH} "${CMAKE_CURRENT_BINARY_DIR}")
+
+configure_file(cmFormConfigure.h.in "${CMAKE_CURRENT_BINARY_DIR}/cmFormConfigure.h")
+
+set( FORM_SRCS
+ fld_arg.c
+ fld_attr.c
+ fld_current.c
+ fld_def.c
+ fld_dup.c
+ fld_ftchoice.c
+ fld_ftlink.c
+ fld_info.c
+ fld_just.c
+ fld_link.c
+ fld_max.c
+ fld_move.c
+ fld_newftyp.c
+ fld_opts.c
+ fld_pad.c
+ fld_page.c
+ fld_stat.c
+ fld_type.c
+ fld_user.c
+ frm_cursor.c
+ frm_data.c
+ frm_def.c
+ frm_driver.c
+ frm_hook.c
+ frm_opts.c
+ frm_page.c
+ frm_post.c
+ frm_req_name.c
+ frm_scale.c
+ frm_sub.c
+ frm_user.c
+ frm_win.c
+ fty_alnum.c
+ fty_alpha.c
+ fty_enum.c
+ fty_int.c
+ fty_ipv4.c
+ fty_num.c
+ fty_regex.c
+ )
+
+include_directories(${CMAKE_FORM_SOURCE_DIR})
+add_library(cmForm ${FORM_SRCS} )
+target_link_libraries(cmForm ${CURSES_LIBRARY})
+if(CURSES_EXTRA_LIBRARY)
+ target_link_libraries(cmForm ${CURSES_EXTRA_LIBRARY})
+endif()
diff --git a/Source/CursesDialog/form/READ.ME b/Source/CursesDialog/form/READ.ME
new file mode 100644
index 0000000..dd91693
--- /dev/null
+++ b/Source/CursesDialog/form/READ.ME
@@ -0,0 +1,15 @@
+This is a clone of the form library that is available with typical
+System V curses implementations (ETI).
+
+It is modelled after the documentation that comes for this library with
+a 386 based SVR4 implementation (ESIX).
+
+The development environment was and is an ELF based Linux system.
+
+For things that still need doing, see the TO-DO file in the top-level
+directory.
+
+Juergen Pfeifer
+
+eMail: juergen.pfeifer@gmx.net
+
diff --git a/Source/CursesDialog/form/cmFormConfigure.h.in b/Source/CursesDialog/form/cmFormConfigure.h.in
new file mode 100644
index 0000000..a43169d
--- /dev/null
+++ b/Source/CursesDialog/form/cmFormConfigure.h.in
@@ -0,0 +1,21 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef CMFORMCONFIGURE_H
+#define CMFORMCONFIGURE_H
+
+#cmakedefine CURSES_HAVE_CURSES_H
+#cmakedefine CURSES_HAVE_NCURSES_H
+#cmakedefine CURSES_HAVE_NCURSES_NCURSES_H
+#cmakedefine CURSES_HAVE_NCURSES_CURSES_H
+
+#endif
diff --git a/Source/CursesDialog/form/eti.h b/Source/CursesDialog/form/eti.h
new file mode 100644
index 0000000..cc1c830
--- /dev/null
+++ b/Source/CursesDialog/form/eti.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#ifndef _ETI_ERRNO_H_
+#define _ETI_ERRNO_H_
+
+#define E_OK (0)
+#define E_SYSTEM_ERROR (-1)
+#define E_BAD_ARGUMENT (-2)
+#define E_POSTED (-3)
+#define E_CONNECTED (-4)
+#define E_BAD_STATE (-5)
+#define E_NO_ROOM (-6)
+#define E_NOT_POSTED (-7)
+#define E_UNKNOWN_COMMAND (-8)
+#define E_NO_MATCH (-9)
+#define E_NOT_SELECTABLE (-10)
+#define E_NOT_CONNECTED (-11)
+#define E_REQUEST_DENIED (-12)
+#define E_INVALID_FIELD (-13)
+#define E_CURRENT (-14)
+
+#endif
diff --git a/Source/CursesDialog/form/fld_arg.c b/Source/CursesDialog/form/fld_arg.c
new file mode 100644
index 0000000..91ad79f
--- /dev/null
+++ b/Source/CursesDialog/form/fld_arg.c
@@ -0,0 +1,91 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_fieldtype_arg(
+| FIELDTYPE *typ,
+| void * (* const make_arg)(va_list *),
+| void * (* const copy_arg)(const void *),
+| void (* const free_arg)(void *) )
+|
+| Description : Connects to the type additional arguments necessary
+| for a set_field_type call. The various function pointer
+| arguments are:
+| make_arg : allocates a structure for the field
+| specific parameters.
+| copy_arg : duplicate the structure created by
+| make_arg
+| free_arg : Release the memory allocated by make_arg
+| or copy_arg
+|
+| At least make_arg must be non-NULL.
+| You may pass NULL for copy_arg and free_arg if your
+| make_arg function doesn't allocate memory and your
+| arg fits into the storage for a (void*).
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid argument
++--------------------------------------------------------------------------*/
+int set_fieldtype_arg(FIELDTYPE * typ,
+ void * (* const make_arg)(va_list *),
+ void * (* const copy_arg)(const void *),
+ void (* const free_arg)(void *))
+{
+ if ( !typ || !make_arg )
+ RETURN(E_BAD_ARGUMENT);
+
+ typ->status |= _HAS_ARGS;
+ typ->makearg = make_arg;
+ typ->copyarg = copy_arg;
+ typ->freearg = free_arg;
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : void *field_arg(const FIELD *field)
+|
+| Description : Retrieve pointer to the fields argument structure.
+|
+| Return Values : Pointer to structure or NULL if none is defined.
++--------------------------------------------------------------------------*/
+void *field_arg(const FIELD * field)
+{
+ return Normalize_Field(field)->arg;
+}
+
+/* fld_arg.c ends here */
diff --git a/Source/CursesDialog/form/fld_attr.c b/Source/CursesDialog/form/fld_attr.c
new file mode 100644
index 0000000..35ea903
--- /dev/null
+++ b/Source/CursesDialog/form/fld_attr.c
@@ -0,0 +1,110 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+MODULE_ID("$Id$")
+
+/*----------------------------------------------------------------------------
+ Field-Attribute manipulation routines
+ --------------------------------------------------------------------------*/
+/* "Template" macro to generate a function to set a fields attribute */
+#define GEN_FIELD_ATTR_SET_FCT( name ) \
+int set_field_ ## name (FIELD * field, chtype attr)\
+{\
+ int res = E_BAD_ARGUMENT;\
+ if ( attr==A_NORMAL || ((attr & A_ATTRIBUTES)==attr) )\
+ {\
+ Normalize_Field( field );\
+ if ((field -> name) != attr)\
+ {\
+ field -> name = attr;\
+ res = _nc_Synchronize_Attributes( field );\
+ }\
+ else\
+ res = E_OK;\
+ }\
+ RETURN(res);\
+}
+
+/* "Template" macro to generate a function to get a fields attribute */
+#define GEN_FIELD_ATTR_GET_FCT( name ) \
+chtype field_ ## name (const FIELD * field)\
+{\
+ return ( A_ATTRIBUTES & (Normalize_Field( field ) -> name) );\
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_fore(FIELD *field, chtype attr)
+|
+| Description : Sets the foreground of the field used to display the
+| field contents.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid attributes
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+GEN_FIELD_ATTR_SET_FCT( fore )
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : chtype field_fore(const FIELD *)
+|
+| Description : Retrieve fields foreground attribute
+|
+| Return Values : The foreground attribute
++--------------------------------------------------------------------------*/
+GEN_FIELD_ATTR_GET_FCT( fore )
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_back(FIELD *field, chtype attr)
+|
+| Description : Sets the background of the field used to display the
+| fields extend.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid attributes
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+GEN_FIELD_ATTR_SET_FCT( back )
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : chtype field_back(const
+|
+| Description : Retrieve fields background attribute
+|
+| Return Values : The background attribute
++--------------------------------------------------------------------------*/
+GEN_FIELD_ATTR_GET_FCT( back )
+
+/* fld_attr.c ends here */
diff --git a/Source/CursesDialog/form/fld_current.c b/Source/CursesDialog/form/fld_current.c
new file mode 100644
index 0000000..d4b1254
--- /dev/null
+++ b/Source/CursesDialog/form/fld_current.c
@@ -0,0 +1,124 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_current_field(FORM * form,FIELD * field)
+|
+| Description : Set the current field of the form to the specified one.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid form or field pointer
+| E_REQUEST_DENIED - field not selectable
+| E_BAD_STATE - called from a hook routine
+| E_INVALID_FIELD - current field can't be left
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int set_current_field(FORM * form, FIELD * field)
+{
+ int err = E_OK;
+
+ if ( !form || !field )
+ RETURN(E_BAD_ARGUMENT);
+
+ if ( (form != field->form) || Field_Is_Not_Selectable(field) )
+ RETURN(E_REQUEST_DENIED);
+
+ if (!(form->status & _POSTED))
+ {
+ form->current = field;
+ form->curpage = field->page;
+ }
+ else
+ {
+ if (form->status & _IN_DRIVER)
+ err = E_BAD_STATE;
+ else
+ {
+ if (form->current != field)
+ {
+ if (!_nc_Internal_Validation(form))
+ err = E_INVALID_FIELD;
+ else
+ {
+ Call_Hook(form,fieldterm);
+ if (field->page != form->curpage)
+ {
+ Call_Hook(form,formterm);
+ err = _nc_Set_Form_Page(form,field->page,field);
+ Call_Hook(form,forminit);
+ }
+ else
+ {
+ err = _nc_Set_Current_Field(form,field);
+ }
+ Call_Hook(form,fieldinit);
+ _nc_Refresh_Current_Field(form);
+ }
+ }
+ }
+ }
+ RETURN(err);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELD *current_field(const FORM * form)
+|
+| Description : Return the current field.
+|
+| Return Values : Pointer to the current field.
++--------------------------------------------------------------------------*/
+FIELD *current_field(const FORM * form)
+{
+ return Normalize_Form(form)->current;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_index(const FIELD * field)
+|
+| Description : Return the index of the field in the field-array of
+| the form.
+|
+| Return Values : >= 0 : field index
+| -1 : fieldpointer invalid or field not connected
++--------------------------------------------------------------------------*/
+int field_index(const FIELD * field)
+{
+ return ( (field && field->form) ? field->index : -1 );
+}
+
+/* fld_current.c ends here */
diff --git a/Source/CursesDialog/form/fld_def.c b/Source/CursesDialog/form/fld_def.c
new file mode 100644
index 0000000..00da3b4
--- /dev/null
+++ b/Source/CursesDialog/form/fld_def.c
@@ -0,0 +1,346 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/* this can't be readonly */
+static FIELD default_field = {
+ 0, /* status */
+ 0, /* rows */
+ 0, /* cols */
+ 0, /* frow */
+ 0, /* fcol */
+ 0, /* drows */
+ 0, /* dcols */
+ 0, /* maxgrow*/
+ 0, /* nrow */
+ 0, /* nbuf */
+ NO_JUSTIFICATION, /* just */
+ 0, /* page */
+ 0, /* index */
+ (int)' ', /* pad */
+ A_NORMAL, /* fore */
+ A_NORMAL, /* back */
+ ALL_FIELD_OPTS, /* opts */
+ (FIELD *)0, /* snext */
+ (FIELD *)0, /* sprev */
+ (FIELD *)0, /* link */
+ (FORM *)0, /* form */
+ (FIELDTYPE *)0, /* type */
+ (char *)0, /* arg */
+ (char *)0, /* buf */
+ (char *)0 /* usrptr */
+};
+
+FIELD *_nc_Default_Field = &default_field;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : TypeArgument *_nc_Make_Argument(
+| const FIELDTYPE *typ,
+| va_list *ap,
+| int *err )
+|
+| Description : Create an argument structure for the specified type.
+| Use the type-dependent argument list to construct
+| it.
+|
+| Return Values : Pointer to argument structure. Maybe NULL.
+| In case of an error in *err an errorcounter is increased.
++--------------------------------------------------------------------------*/
+TypeArgument*
+_nc_Make_Argument(const FIELDTYPE *typ, va_list *ap, int *err)
+{
+ TypeArgument *res = (TypeArgument *)0;
+ TypeArgument *p;
+
+ if (typ && (typ->status & _HAS_ARGS))
+ {
+ assert(err && ap);
+ if (typ->status & _LINKED_TYPE)
+ {
+ p = (TypeArgument *)malloc(sizeof(TypeArgument));
+ if (p)
+ {
+ p->left = _nc_Make_Argument(typ->left ,ap,err);
+ p->right = _nc_Make_Argument(typ->right,ap,err);
+ return p;
+ }
+ else
+ *err += 1;
+ } else
+ {
+ assert(typ->makearg != 0);
+ if ( !(res=(TypeArgument *)typ->makearg(ap)) )
+ *err += 1;
+ }
+ }
+ return res;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : TypeArgument *_nc_Copy_Argument(const FIELDTYPE *typ,
+| const TypeArgument *argp,
+| int *err )
+|
+| Description : Create a copy of an argument structure for the specified
+| type.
+|
+| Return Values : Pointer to argument structure. Maybe NULL.
+| In case of an error in *err an errorcounter is increased.
++--------------------------------------------------------------------------*/
+TypeArgument*
+_nc_Copy_Argument(const FIELDTYPE *typ,
+ const TypeArgument *argp, int *err)
+{
+ TypeArgument *res = (TypeArgument *)0;
+ TypeArgument *p;
+
+ if ( typ && (typ->status & _HAS_ARGS) )
+ {
+ assert(err && argp);
+ if (typ->status & _LINKED_TYPE)
+ {
+ p = (TypeArgument *)malloc(sizeof(TypeArgument));
+ if (p)
+ {
+ p->left = _nc_Copy_Argument(typ,argp->left ,err);
+ p->right = _nc_Copy_Argument(typ,argp->right,err);
+ return p;
+ }
+ *err += 1;
+ }
+ else
+ {
+ if (typ->copyarg)
+ {
+ if (!(res = (TypeArgument *)(typ->copyarg((const void *)argp))))
+ *err += 1;
+ }
+ else
+ res = (TypeArgument *)argp;
+ }
+ }
+ return res;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : void _nc_Free_Argument(const FIELDTYPE *typ,
+| TypeArgument * argp )
+|
+| Description : Release memory associated with the argument structure
+| for the given fieldtype.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+void
+_nc_Free_Argument(const FIELDTYPE * typ, TypeArgument * argp)
+{
+ if (!typ || !(typ->status & _HAS_ARGS))
+ return;
+
+ if (typ->status & _LINKED_TYPE)
+ {
+ assert(argp != 0);
+ _nc_Free_Argument(typ->left ,argp->left );
+ _nc_Free_Argument(typ->right,argp->right);
+ free(argp);
+ }
+ else
+ {
+ if (typ->freearg)
+ typ->freearg((void *)argp);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : bool _nc_Copy_Type( FIELD *dst, FIELD const *src )
+|
+| Description : Copy argument structure of field src to field dst
+|
+| Return Values : TRUE - copy worked
+| FALSE - error occurred
++--------------------------------------------------------------------------*/
+bool
+_nc_Copy_Type(FIELD *dst, FIELD const *src)
+{
+ int err = 0;
+
+ assert(dst && src);
+
+ dst->type = src->type;
+ dst->arg = (void *)_nc_Copy_Argument(src->type,(TypeArgument *)(src->arg),&err);
+
+ if (err)
+ {
+ _nc_Free_Argument(dst->type,(TypeArgument *)(dst->arg));
+ dst->type = (FIELDTYPE *)0;
+ dst->arg = (void *)0;
+ return FALSE;
+ }
+ else
+ {
+ if (dst->type)
+ dst->type->ref++;
+ return TRUE;
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : void _nc_Free_Type( FIELD *field )
+|
+| Description : Release Argument structure for this field
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+void
+_nc_Free_Type(FIELD *field)
+{
+ assert(field != 0);
+ if (field->type)
+ field->type->ref--;
+ _nc_Free_Argument(field->type,(TypeArgument *)(field->arg));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELD *new_field( int rows, int cols,
+| int frow, int fcol,
+| int nrow, int nbuf )
+|
+| Description : Create a new field with this many 'rows' and 'cols',
+| starting at 'frow/fcol' in the subwindow of the form.
+| Allocate 'nrow' off-screen rows and 'nbuf' additional
+| buffers. If an error occurs, errno is set to
+|
+| E_BAD_ARGUMENT - invalid argument
+| E_SYSTEM_ERROR - system error
+|
+| Return Values : Pointer to the new field or NULL if failure.
++--------------------------------------------------------------------------*/
+FIELD *new_field(int rows, int cols, int frow, int fcol, int nrow, int nbuf)
+{
+ FIELD *New_Field = (FIELD *)0;
+ int err = E_BAD_ARGUMENT;
+
+ if (rows>0 &&
+ cols>0 &&
+ frow>=0 &&
+ fcol>=0 &&
+ nrow>=0 &&
+ nbuf>=0 &&
+ ((err = E_SYSTEM_ERROR) != 0) && /* trick: this resets the default error */
+ (New_Field=(FIELD *)malloc(sizeof(FIELD))) )
+ {
+ *New_Field = default_field;
+ New_Field->rows = rows;
+ New_Field->cols = cols;
+ New_Field->drows = rows + nrow;
+ New_Field->dcols = cols;
+ New_Field->frow = frow;
+ New_Field->fcol = fcol;
+ New_Field->nrow = nrow;
+ New_Field->nbuf = nbuf;
+ New_Field->link = New_Field;
+
+ if (_nc_Copy_Type(New_Field,&default_field))
+ {
+ size_t len;
+
+ len = Total_Buffer_Size(New_Field);
+ if ((New_Field->buf = (char *)malloc(len)))
+ {
+ /* Prefill buffers with blanks and insert terminating zeroes
+ between buffers */
+ int i;
+
+ memset(New_Field->buf,' ',len);
+ for(i=0;i<=New_Field->nbuf;i++)
+ {
+ New_Field->buf[(New_Field->drows*New_Field->cols+1)*(i+1)-1]
+ = '\0';
+ }
+ return New_Field;
+ }
+ }
+ }
+
+ if (New_Field)
+ free_field(New_Field);
+
+ SET_ERROR( err );
+ return (FIELD *)0;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int free_field( FIELD *field )
+|
+| Description : Frees the storage allocated for the field.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer
+| E_CONNECTED - field is connected
++--------------------------------------------------------------------------*/
+int free_field(FIELD * field)
+{
+ if (!field)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (field->form)
+ RETURN(E_CONNECTED);
+
+ if (field == field->link)
+ {
+ if (field->buf)
+ free(field->buf);
+ }
+ else
+ {
+ FIELD *f;
+
+ for(f=field;f->link != field;f = f->link)
+ {}
+ f->link = field->link;
+ }
+ _nc_Free_Type(field);
+ free(field);
+ RETURN(E_OK);
+}
+
+/* fld_def.c ends here */
diff --git a/Source/CursesDialog/form/fld_dup.c b/Source/CursesDialog/form/fld_dup.c
new file mode 100644
index 0000000..1c5301d
--- /dev/null
+++ b/Source/CursesDialog/form/fld_dup.c
@@ -0,0 +1,97 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELD *dup_field(FIELD *field, int frow, int fcol)
+|
+| Description : Duplicates the field at the specified position. All
+| field attributes and the buffers are copied.
+| If an error occurs, errno is set to
+|
+| E_BAD_ARGUMENT - invalid argument
+| E_SYSTEM_ERROR - system error
+|
+| Return Values : Pointer to the new field or NULL if failure
++--------------------------------------------------------------------------*/
+FIELD *dup_field(FIELD * field, int frow, int fcol)
+{
+ FIELD *New_Field = (FIELD *)0;
+ int err = E_BAD_ARGUMENT;
+
+ if (field && (frow>=0) && (fcol>=0) &&
+ ((err=E_SYSTEM_ERROR) != 0) && /* trick : this resets the default error */
+ (New_Field=(FIELD *)malloc(sizeof(FIELD))) )
+ {
+ *New_Field = *_nc_Default_Field;
+ New_Field->frow = frow;
+ New_Field->fcol = fcol;
+ New_Field->link = New_Field;
+ New_Field->rows = field->rows;
+ New_Field->cols = field->cols;
+ New_Field->nrow = field->nrow;
+ New_Field->drows = field->drows;
+ New_Field->dcols = field->dcols;
+ New_Field->maxgrow = field->maxgrow;
+ New_Field->nbuf = field->nbuf;
+ New_Field->just = field->just;
+ New_Field->fore = field->fore;
+ New_Field->back = field->back;
+ New_Field->pad = field->pad;
+ New_Field->opts = field->opts;
+ New_Field->usrptr = field->usrptr;
+
+ if (_nc_Copy_Type(New_Field,field))
+ {
+ size_t len;
+
+ len = Total_Buffer_Size(New_Field);
+ if ( (New_Field->buf=(char *)malloc(len)) )
+ {
+ memcpy(New_Field->buf,field->buf,len);
+ return New_Field;
+ }
+ }
+ }
+
+ if (New_Field)
+ free_field(New_Field);
+
+ SET_ERROR(err);
+ return (FIELD *)0;
+}
+
+/* fld_dup.c ends here */
diff --git a/Source/CursesDialog/form/fld_ftchoice.c b/Source/CursesDialog/form/fld_ftchoice.c
new file mode 100644
index 0000000..bb37073
--- /dev/null
+++ b/Source/CursesDialog/form/fld_ftchoice.c
@@ -0,0 +1,62 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_fieldtype_choice(
+| FIELDTYPE *typ,
+| bool (* const next_choice)(FIELD *,const void *),
+| bool (* const prev_choice)(FIELD *,const void *))
+|
+| Description : Define implementation of enumeration requests.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid arguments
++--------------------------------------------------------------------------*/
+int set_fieldtype_choice(FIELDTYPE * typ,
+ bool (* const next_choice) (FIELD *,const void *),
+ bool (* const prev_choice) (FIELD *,const void *))
+{
+ if ( !typ || !next_choice || !prev_choice )
+ RETURN(E_BAD_ARGUMENT);
+
+ typ->status |= _HAS_CHOICE;
+ typ->next = next_choice;
+ typ->prev = prev_choice;
+ RETURN(E_OK);
+}
+
+/* fld_ftchoice.c ends here */
diff --git a/Source/CursesDialog/form/fld_ftlink.c b/Source/CursesDialog/form/fld_ftlink.c
new file mode 100644
index 0000000..e98a4ca
--- /dev/null
+++ b/Source/CursesDialog/form/fld_ftlink.c
@@ -0,0 +1,83 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELDTYPE *link_fieldtype(
+| FIELDTYPE *type1,
+| FIELDTYPE *type2)
+|
+| Description : Create a new fieldtype built from the two given types.
+| They are connected by an logical 'OR'.
+| If an error occurs, errno is set to
+| E_BAD_ARGUMENT - invalid arguments
+| E_SYSTEM_ERROR - system error (no memory)
+|
+| Return Values : Fieldtype pointer or NULL if error occurred.
++--------------------------------------------------------------------------*/
+FIELDTYPE *link_fieldtype(FIELDTYPE * type1, FIELDTYPE * type2)
+{
+ FIELDTYPE *nftyp = (FIELDTYPE *)0;
+
+ if ( type1 && type2 )
+ {
+ nftyp = (FIELDTYPE *)malloc(sizeof(FIELDTYPE));
+ if (nftyp)
+ {
+ *nftyp = *_nc_Default_FieldType;
+ nftyp->status |= _LINKED_TYPE;
+ if ((type1->status & _HAS_ARGS) || (type2->status & _HAS_ARGS) )
+ nftyp->status |= _HAS_ARGS;
+ if ((type1->status & _HAS_CHOICE) || (type2->status & _HAS_CHOICE) )
+ nftyp->status |= _HAS_CHOICE;
+ nftyp->left = type1;
+ nftyp->right = type2;
+ type1->ref++;
+ type2->ref++;
+ }
+ else
+ {
+ SET_ERROR( E_SYSTEM_ERROR );
+ }
+ }
+ else
+ {
+ SET_ERROR( E_BAD_ARGUMENT );
+ }
+ return nftyp;
+}
+
+/* fld_ftlink.c ends here */
diff --git a/Source/CursesDialog/form/fld_info.c b/Source/CursesDialog/form/fld_info.c
new file mode 100644
index 0000000..1ba92c8
--- /dev/null
+++ b/Source/CursesDialog/form/fld_info.c
@@ -0,0 +1,91 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_info(const FIELD *field,
+| int *rows, int *cols,
+| int *frow, int *fcol,
+| int *nrow, int *nbuf)
+|
+| Description : Retrieve infos about the fields creation parameters.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer
++--------------------------------------------------------------------------*/
+int field_info(const FIELD *field,
+ int *rows, int *cols,
+ int *frow, int *fcol,
+ int *nrow, int *nbuf)
+{
+ if (!field)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (rows) *rows = field->rows;
+ if (cols) *cols = field->cols;
+ if (frow) *frow = field->frow;
+ if (fcol) *fcol = field->fcol;
+ if (nrow) *nrow = field->nrow;
+ if (nbuf) *nbuf = field->nbuf;
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int dynamic_field_info(const FIELD *field,
+| int *drows, int *dcols,
+| int *maxgrow)
+|
+| Description : Retrieve information about a dynamic fields current
+| dynamic parameters.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid argument
++--------------------------------------------------------------------------*/
+int dynamic_field_info(const FIELD *field,
+ int *drows, int *dcols, int *maxgrow)
+{
+ if (!field)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (drows) *drows = field->drows;
+ if (dcols) *dcols = field->dcols;
+ if (maxgrow) *maxgrow = field->maxgrow;
+
+ RETURN(E_OK);
+}
+
+/* fld_info.c ends here */
diff --git a/Source/CursesDialog/form/fld_just.c b/Source/CursesDialog/form/fld_just.c
new file mode 100644
index 0000000..7015654
--- /dev/null
+++ b/Source/CursesDialog/form/fld_just.c
@@ -0,0 +1,81 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_just(FIELD *field, int just)
+|
+| Description : Set the fields type of justification.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - one of the arguments was incorrect
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int set_field_just(FIELD * field, int just)
+{
+ int res = E_BAD_ARGUMENT;
+
+ if ((just==NO_JUSTIFICATION) ||
+ (just==JUSTIFY_LEFT) ||
+ (just==JUSTIFY_CENTER) ||
+ (just==JUSTIFY_RIGHT) )
+ {
+ Normalize_Field( field );
+ if (field->just != just)
+ {
+ field->just = just;
+ res = _nc_Synchronize_Attributes( field );
+ }
+ else
+ res = E_OK;
+ }
+ RETURN(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_just( const FIELD *field )
+|
+| Description : Retrieve the fields type of justification
+|
+| Return Values : The justification type.
++--------------------------------------------------------------------------*/
+int field_just(const FIELD * field)
+{
+ return Normalize_Field( field )->just;
+}
+
+/* fld_just.c ends here */
diff --git a/Source/CursesDialog/form/fld_link.c b/Source/CursesDialog/form/fld_link.c
new file mode 100644
index 0000000..164f51b
--- /dev/null
+++ b/Source/CursesDialog/form/fld_link.c
@@ -0,0 +1,90 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELD *link_field(FIELD *field, int frow, int fcol)
+|
+| Description : Duplicates the field at the specified position. The
+| new field shares its buffers with the original one,
+| the attributes are independent.
+| If an error occurs, errno is set to
+|
+| E_BAD_ARGUMENT - invalid argument
+| E_SYSTEM_ERROR - system error
+|
+| Return Values : Pointer to the new field or NULL if failure
++--------------------------------------------------------------------------*/
+FIELD *link_field(FIELD * field, int frow, int fcol)
+{
+ FIELD *New_Field = (FIELD *)0;
+ int err = E_BAD_ARGUMENT;
+
+ if (field && (frow>=0) && (fcol>=0) &&
+ ((err=E_SYSTEM_ERROR) != 0) && /* trick: this resets the default error */
+ (New_Field = (FIELD *)malloc(sizeof(FIELD))) )
+ {
+ *New_Field = *_nc_Default_Field;
+ New_Field->frow = frow;
+ New_Field->fcol = fcol;
+ New_Field->link = field->link;
+ field->link = New_Field;
+ New_Field->buf = field->buf;
+ New_Field->rows = field->rows;
+ New_Field->cols = field->cols;
+ New_Field->nrow = field->nrow;
+ New_Field->nbuf = field->nbuf;
+ New_Field->drows = field->drows;
+ New_Field->dcols = field->dcols;
+ New_Field->maxgrow= field->maxgrow;
+ New_Field->just = field->just;
+ New_Field->fore = field->fore;
+ New_Field->back = field->back;
+ New_Field->pad = field->pad;
+ New_Field->opts = field->opts;
+ New_Field->usrptr = field->usrptr;
+ if (_nc_Copy_Type(New_Field,field))
+ return New_Field;
+ }
+
+ if (New_Field)
+ free_field(New_Field);
+
+ SET_ERROR( err );
+ return (FIELD *)0;
+}
+
+/* fld_link.c ends here */
diff --git a/Source/CursesDialog/form/fld_max.c b/Source/CursesDialog/form/fld_max.c
new file mode 100644
index 0000000..cca8dc5
--- /dev/null
+++ b/Source/CursesDialog/form/fld_max.c
@@ -0,0 +1,74 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_max_field(FIELD *field, int maxgrow)
+|
+| Description : Set the maximum growth for a dynamic field. If maxgrow=0
+| the field may grow to any possible size.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid argument
++--------------------------------------------------------------------------*/
+int set_max_field(FIELD *field, int maxgrow)
+{
+ if (!field || (maxgrow<0))
+ RETURN(E_BAD_ARGUMENT);
+ else
+ {
+ bool single_line_field = Single_Line_Field(field);
+
+ if (maxgrow>0)
+ {
+ if (( single_line_field && (maxgrow < field->dcols)) ||
+ (!single_line_field && (maxgrow < field->drows)))
+ RETURN(E_BAD_ARGUMENT);
+ }
+ field->maxgrow = maxgrow;
+ field->status &= ~_MAY_GROW;
+ if (!(field->opts & O_STATIC))
+ {
+ if ((maxgrow==0) ||
+ ( single_line_field && (field->dcols < maxgrow)) ||
+ (!single_line_field && (field->drows < maxgrow)))
+ field->status |= _MAY_GROW;
+ }
+ }
+ RETURN(E_OK);
+}
+
+/* fld_max.c ends here */
diff --git a/Source/CursesDialog/form/fld_move.c b/Source/CursesDialog/form/fld_move.c
new file mode 100644
index 0000000..2293477
--- /dev/null
+++ b/Source/CursesDialog/form/fld_move.c
@@ -0,0 +1,62 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int move_field(FIELD *field,int frow, int fcol)
+|
+| Description : Moves the disconnected field to the new location in
+| the forms subwindow.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid argument passed
+| E_CONNECTED - field is connected
++--------------------------------------------------------------------------*/
+int move_field(FIELD *field, int frow, int fcol)
+{
+ if ( !field || (frow<0) || (fcol<0) )
+ RETURN(E_BAD_ARGUMENT);
+
+ if (field->form)
+ RETURN(E_CONNECTED);
+
+ field->frow = frow;
+ field->fcol = fcol;
+ RETURN(E_OK);
+}
+
+/* fld_move.c ends here */
+
diff --git a/Source/CursesDialog/form/fld_newftyp.c b/Source/CursesDialog/form/fld_newftyp.c
new file mode 100644
index 0000000..b839f19
--- /dev/null
+++ b/Source/CursesDialog/form/fld_newftyp.c
@@ -0,0 +1,125 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+static FIELDTYPE const default_fieldtype = {
+ 0, /* status */
+ 0L, /* reference count */
+ (FIELDTYPE *)0, /* pointer to left operand */
+ (FIELDTYPE *)0, /* pointer to right operand */
+ NULL, /* makearg function */
+ NULL, /* copyarg function */
+ NULL, /* freearg function */
+ NULL, /* field validation function */
+ NULL, /* Character check function */
+ NULL, /* enumerate next function */
+ NULL /* enumerate previous function */
+};
+
+const FIELDTYPE* _nc_Default_FieldType = &default_fieldtype;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELDTYPE *new_fieldtype(
+| bool (* const field_check)(FIELD *,const void *),
+| bool (* const char_check) (int, const void *) )
+|
+| Description : Create a new fieldtype. The application programmer must
+| write a field_check and a char_check function and give
+| them as input to this call.
+| If an error occurs, errno is set to
+| E_BAD_ARGUMENT - invalid arguments
+| E_SYSTEM_ERROR - system error (no memory)
+|
+| Return Values : Fieldtype pointer or NULL if error occurred
++--------------------------------------------------------------------------*/
+FIELDTYPE *new_fieldtype(
+ bool (* const field_check)(FIELD *,const void *),
+ bool (* const char_check) (int,const void *) )
+{
+ FIELDTYPE *nftyp = (FIELDTYPE *)0;
+
+ if ( (field_check) || (char_check) )
+ {
+ nftyp = (FIELDTYPE *)malloc(sizeof(FIELDTYPE));
+ if (nftyp)
+ {
+ *nftyp = default_fieldtype;
+ nftyp->fcheck = field_check;
+ nftyp->ccheck = char_check;
+ }
+ else
+ {
+ SET_ERROR( E_SYSTEM_ERROR );
+ }
+ }
+ else
+ {
+ SET_ERROR( E_BAD_ARGUMENT );
+ }
+ return nftyp;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int free_fieldtype(FIELDTYPE *typ)
+|
+| Description : Release the memory associated with this fieldtype.
+|
+| Return Values : E_OK - success
+| E_CONNECTED - there are fields referencing the type
+| E_BAD_ARGUMENT - invalid fieldtype pointer
++--------------------------------------------------------------------------*/
+int free_fieldtype(FIELDTYPE *typ)
+{
+ if (!typ)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (typ->ref!=0)
+ RETURN(E_CONNECTED);
+
+ if (typ->status & _RESIDENT)
+ RETURN(E_CONNECTED);
+
+ if (typ->status & _LINKED_TYPE)
+ {
+ if (typ->left ) typ->left->ref--;
+ if (typ->right) typ->right->ref--;
+ }
+ free(typ);
+ RETURN(E_OK);
+}
+
+/* fld_newftyp.c ends here */
diff --git a/Source/CursesDialog/form/fld_opts.c b/Source/CursesDialog/form/fld_opts.c
new file mode 100644
index 0000000..234634b
--- /dev/null
+++ b/Source/CursesDialog/form/fld_opts.c
@@ -0,0 +1,124 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*----------------------------------------------------------------------------
+ Field-Options manipulation routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_opts(FIELD *field, Field_Options opts)
+|
+| Description : Turns on the named options for this field and turns
+| off all the remaining options.
+|
+| Return Values : E_OK - success
+| E_CURRENT - the field is the current field
+| E_BAD_ARGUMENT - invalid options
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int set_field_opts(FIELD * field, Field_Options opts)
+{
+ int res = E_BAD_ARGUMENT;
+ opts &= ALL_FIELD_OPTS;
+ if (!(opts & ~ALL_FIELD_OPTS))
+ res = _nc_Synchronize_Options( Normalize_Field(field), opts );
+ RETURN(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : Field_Options field_opts(const FIELD *field)
+|
+| Description : Retrieve the fields options.
+|
+| Return Values : The options.
++--------------------------------------------------------------------------*/
+Field_Options field_opts(const FIELD * field)
+{
+ return ALL_FIELD_OPTS & Normalize_Field( field )->opts;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_opts_on(FIELD *field, Field_Options opts)
+|
+| Description : Turns on the named options for this field and all the
+| remaining options are unchanged.
+|
+| Return Values : E_OK - success
+| E_CURRENT - the field is the current field
+| E_BAD_ARGUMENT - invalid options
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int field_opts_on(FIELD * field, Field_Options opts)
+{
+ int res = E_BAD_ARGUMENT;
+
+ opts &= ALL_FIELD_OPTS;
+ if (!(opts & ~ALL_FIELD_OPTS))
+ {
+ Normalize_Field( field );
+ res = _nc_Synchronize_Options( field, field->opts | opts );
+ }
+ RETURN(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_opts_off(FIELD *field, Field_Options opts)
+|
+| Description : Turns off the named options for this field and all the
+| remaining options are unchanged.
+|
+| Return Values : E_OK - success
+| E_CURRENT - the field is the current field
+| E_BAD_ARGUMENT - invalid options
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int field_opts_off(FIELD * field, Field_Options opts)
+{
+ int res = E_BAD_ARGUMENT;
+
+ opts &= ALL_FIELD_OPTS;
+ if (!(opts & ~ALL_FIELD_OPTS))
+ {
+ Normalize_Field( field );
+ res = _nc_Synchronize_Options( field, field->opts & ~opts );
+ }
+ RETURN(res);
+}
+
+/* fld_opts.c ends here */
diff --git a/Source/CursesDialog/form/fld_pad.c b/Source/CursesDialog/form/fld_pad.c
new file mode 100644
index 0000000..4598340
--- /dev/null
+++ b/Source/CursesDialog/form/fld_pad.c
@@ -0,0 +1,78 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_pad(FIELD *field, int ch)
+|
+| Description : Set the pad character used to fill the field. This must
+| be a printable character.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer or pad character
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int set_field_pad(FIELD * field, int ch)
+{
+ int res = E_BAD_ARGUMENT;
+
+ Normalize_Field( field );
+ if (isprint((unsigned char)ch))
+ {
+ if (field->pad != ch)
+ {
+ field->pad = ch;
+ res = _nc_Synchronize_Attributes( field );
+ }
+ else
+ res = E_OK;
+ }
+ RETURN(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_pad(const FIELD *field)
+|
+| Description : Retrieve the fields pad character.
+|
+| Return Values : The pad character.
++--------------------------------------------------------------------------*/
+int field_pad(const FIELD * field)
+{
+ return Normalize_Field( field )->pad;
+}
+
+/* fld_pad.c ends here */
diff --git a/Source/CursesDialog/form/fld_page.c b/Source/CursesDialog/form/fld_page.c
new file mode 100644
index 0000000..408e712
--- /dev/null
+++ b/Source/CursesDialog/form/fld_page.c
@@ -0,0 +1,76 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_new_page(FIELD *field, bool new_page_flag)
+|
+| Description : Marks the field as the beginning of a new page of
+| the form.
+|
+| Return Values : E_OK - success
+| E_CONNECTED - field is connected
++--------------------------------------------------------------------------*/
+int set_new_page(FIELD * field, bool new_page_flag)
+{
+ Normalize_Field(field);
+ if (field->form)
+ RETURN(E_CONNECTED);
+
+ if (new_page_flag)
+ field->status |= _NEWPAGE;
+ else
+ field->status &= ~_NEWPAGE;
+
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : bool new_page(const FIELD *field)
+|
+| Description : Retrieve the info whether or not the field starts a
+| new page on the form.
+|
+| Return Values : TRUE - field starts a new page
+| FALSE - field doesn't start a new page
++--------------------------------------------------------------------------*/
+bool new_page(const FIELD * field)
+{
+ return (Normalize_Field(field)->status & _NEWPAGE) ? TRUE : FALSE;
+}
+
+/* fld_page.c ends here */
diff --git a/Source/CursesDialog/form/fld_stat.c b/Source/CursesDialog/form/fld_stat.c
new file mode 100644
index 0000000..ee6831b
--- /dev/null
+++ b/Source/CursesDialog/form/fld_stat.c
@@ -0,0 +1,73 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_status(FIELD *field, bool status)
+|
+| Description : Set or clear the 'changed' indication flag for that
+| fields primary buffer.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+int set_field_status(FIELD * field, bool status)
+{
+ Normalize_Field( field );
+
+ if (status)
+ field->status |= _CHANGED;
+ else
+ field->status &= ~_CHANGED;
+
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : bool field_status(const FIELD *field)
+|
+| Description : Retrieve the value of the 'changed' indication flag
+| for that fields primary buffer.
+|
+| Return Values : TRUE - buffer has been changed
+| FALSE - buffer has not been changed
++--------------------------------------------------------------------------*/
+bool field_status(const FIELD * field)
+{
+ return ((Normalize_Field(field)->status & _CHANGED) ? TRUE : FALSE);
+}
+
+/* fld_stat.c ends here */
diff --git a/Source/CursesDialog/form/fld_type.c b/Source/CursesDialog/form/fld_type.c
new file mode 100644
index 0000000..6c9def2
--- /dev/null
+++ b/Source/CursesDialog/form/fld_type.c
@@ -0,0 +1,51 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELDTYPE *field_type(const FIELD *field)
+|
+| Description : Retrieve the associated fieldtype for this field.
+|
+| Return Values : Pointer to fieldtype of NULL if none is defined.
++--------------------------------------------------------------------------*/
+FIELDTYPE *field_type(const FIELD * field)
+{
+ return Normalize_Field(field)->type;
+}
+
+/* fld_type.c ends here */
diff --git a/Source/CursesDialog/form/fld_user.c b/Source/CursesDialog/form/fld_user.c
new file mode 100644
index 0000000..3287b5b
--- /dev/null
+++ b/Source/CursesDialog/form/fld_user.c
@@ -0,0 +1,67 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_userptr(FIELD *field, void *usrptr)
+|
+| Description : Set the pointer that is reserved in any field to store
+| application relevant information
+|
+| Return Values : E_OK - on success
++--------------------------------------------------------------------------*/
+int set_field_userptr(FIELD * field, void *usrptr)
+{
+ Normalize_Field( field )->usrptr = usrptr;
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : void *field_userptr(const FIELD *field)
+|
+| Description : Return the pointer that is reserved in any field to
+| store application relevant information.
+|
+| Return Values : Value of pointer. If no such pointer has been set,
+| NULL is returned
++--------------------------------------------------------------------------*/
+void *field_userptr(const FIELD *field)
+{
+ return Normalize_Field( field )->usrptr;
+}
+
+/* fld_user.c ends here */
diff --git a/Source/CursesDialog/form/form.h b/Source/CursesDialog/form/form.h
new file mode 100644
index 0000000..1219cb5
--- /dev/null
+++ b/Source/CursesDialog/form/form.h
@@ -0,0 +1,411 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#ifndef FORM_H
+#define FORM_H
+
+#if defined(__sun__) && defined(__GNUC__)
+ #define _MSE_INT_H
+#endif
+
+#include <cmFormConfigure.h>
+
+/* figure out which curses.h to include */
+# if defined(CURSES_HAVE_NCURSES_H)
+# include <ncurses.h>
+# elif defined(CURSES_HAVE_NCURSES_NCURSES_H)
+# include <ncurses/ncurses.h>
+# elif defined(CURSES_HAVE_NCURSES_CURSES_H)
+# include <ncurses/curses.h>
+# else
+# if defined(__hpux)
+# if defined(_XOPEN_SOURCE_EXTENDED)
+# define HAVE__XOPEN_SOURCE_EXTENDED
+# else
+# define _XOPEN_SOURCE_EXTENDED
+# endif
+# endif
+# include <curses.h>
+# if defined(__hpux) && !defined(HAVE__XOPEN_SOURCE_EXTENDED)
+# undef _XOPEN_SOURCE_EXTENDED
+# endif
+# endif
+
+#include <eti.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+typedef int Form_Options;
+typedef int Field_Options;
+
+ /**********
+ * _PAGE *
+ **********/
+
+typedef struct {
+ short pmin; /* index of first field on page */
+ short pmax; /* index of last field on page */
+ short smin; /* index of top leftmost field on page */
+ short smax; /* index of bottom rightmost field on page */
+} _PAGE;
+
+ /**********
+ * FIELD *
+ **********/
+
+typedef struct fieldnode {
+ unsigned short status; /* flags */
+ short rows; /* size in rows */
+ short cols; /* size in cols */
+ short frow; /* first row */
+ short fcol; /* first col */
+ int drows; /* dynamic rows */
+ int dcols; /* dynamic cols */
+ int maxgrow; /* maximum field growth */
+ int nrow; /* offscreen rows */
+ short nbuf; /* additional buffers */
+ short just; /* justification */
+ short page; /* page on form */
+ short index; /* into form -> field */
+ int pad; /* pad character */
+ chtype fore; /* foreground attribute */
+ chtype back; /* background attribute */
+ Field_Options opts; /* options */
+ struct fieldnode * snext; /* sorted order pointer */
+ struct fieldnode * sprev; /* sorted order pointer */
+ struct fieldnode * link; /* linked field chain */
+ struct formnode * form; /* containing form */
+ struct typenode * type; /* field type */
+ void * arg; /* argument for type */
+ char * buf; /* field buffers */
+ void * usrptr; /* user pointer */
+} FIELD;
+
+ /**************
+ * FIELDTYPE *
+ **************/
+
+typedef struct typenode {
+ unsigned short status; /* flags */
+ long ref; /* reference count */
+ struct typenode * left; /* ptr to operand for | */
+ struct typenode * right; /* ptr to operand for | */
+
+ void* (*makearg)(va_list *); /* make fieldtype arg */
+ void* (*copyarg)(const void *); /* copy fieldtype arg */
+ void (*freearg)(void *); /* free fieldtype arg */
+
+ bool (*fcheck)(FIELD *,const void *); /* field validation */
+ bool (*ccheck)(int,const void *); /* character validation */
+
+ bool (*next)(FIELD *,const void *); /* enumerate next value */
+ bool (*prev)(FIELD *,const void *); /* enumerate prev value */
+
+} FIELDTYPE;
+
+ /*********
+ * FORM *
+ *********/
+
+typedef struct formnode {
+ unsigned short status; /* flags */
+ short rows; /* size in rows */
+ short cols; /* size in cols */
+ int currow; /* current row in field window*/
+ int curcol; /* current col in field window*/
+ int toprow; /* in scrollable field window */
+ int begincol; /* in horiz. scrollable field */
+ short maxfield; /* number of fields */
+ short maxpage; /* number of pages */
+ short curpage; /* index into page */
+ Form_Options opts; /* options */
+ WINDOW * win; /* window */
+ WINDOW * sub; /* subwindow */
+ WINDOW * w; /* window for current field */
+ FIELD ** field; /* field [maxfield] */
+ FIELD * current; /* current field */
+ _PAGE * page; /* page [maxpage] */
+ void * usrptr; /* user pointer */
+
+ void (*forminit)(struct formnode *);
+ void (*formterm)(struct formnode *);
+ void (*fieldinit)(struct formnode *);
+ void (*fieldterm)(struct formnode *);
+
+} FORM;
+
+typedef void (*Form_Hook)(FORM *);
+
+ /***************************
+ * miscellaneous #defines *
+ ***************************/
+
+/* field justification */
+#define NO_JUSTIFICATION (0)
+#define JUSTIFY_LEFT (1)
+#define JUSTIFY_CENTER (2)
+#define JUSTIFY_RIGHT (3)
+
+/* field options */
+#define O_VISIBLE (0x0001)
+#define O_ACTIVE (0x0002)
+#define O_PUBLIC (0x0004)
+#define O_EDIT (0x0008)
+#define O_WRAP (0x0010)
+#define O_BLANK (0x0020)
+#define O_AUTOSKIP (0x0040)
+#define O_NULLOK (0x0080)
+#define O_PASSOK (0x0100)
+#define O_STATIC (0x0200)
+
+/* form options */
+#define O_NL_OVERLOAD (0x0001)
+#define O_BS_OVERLOAD (0x0002)
+
+/* form driver commands */
+#define REQ_NEXT_PAGE (KEY_MAX + 1) /* move to next page */
+#define REQ_PREV_PAGE (KEY_MAX + 2) /* move to previous page */
+#define REQ_FIRST_PAGE (KEY_MAX + 3) /* move to first page */
+#define REQ_LAST_PAGE (KEY_MAX + 4) /* move to last page */
+
+#define REQ_NEXT_FIELD (KEY_MAX + 5) /* move to next field */
+#define REQ_PREV_FIELD (KEY_MAX + 6) /* move to previous field */
+#define REQ_FIRST_FIELD (KEY_MAX + 7) /* move to first field */
+#define REQ_LAST_FIELD (KEY_MAX + 8) /* move to last field */
+#define REQ_SNEXT_FIELD (KEY_MAX + 9) /* move to sorted next field */
+#define REQ_SPREV_FIELD (KEY_MAX + 10) /* move to sorted prev field */
+#define REQ_SFIRST_FIELD (KEY_MAX + 11) /* move to sorted first field */
+#define REQ_SLAST_FIELD (KEY_MAX + 12) /* move to sorted last field */
+#define REQ_LEFT_FIELD (KEY_MAX + 13) /* move to left to field */
+#define REQ_RIGHT_FIELD (KEY_MAX + 14) /* move to right to field */
+#define REQ_UP_FIELD (KEY_MAX + 15) /* move to up to field */
+#define REQ_DOWN_FIELD (KEY_MAX + 16) /* move to down to field */
+
+#define REQ_NEXT_CHAR (KEY_MAX + 17) /* move to next char in field */
+#define REQ_PREV_CHAR (KEY_MAX + 18) /* move to prev char in field */
+#define REQ_NEXT_LINE (KEY_MAX + 19) /* move to next line in field */
+#define REQ_PREV_LINE (KEY_MAX + 20) /* move to prev line in field */
+#define REQ_NEXT_WORD (KEY_MAX + 21) /* move to next word in field */
+#define REQ_PREV_WORD (KEY_MAX + 22) /* move to prev word in field */
+#define REQ_BEG_FIELD (KEY_MAX + 23) /* move to first char in field */
+#define REQ_END_FIELD (KEY_MAX + 24) /* move after last char in fld */
+#define REQ_BEG_LINE (KEY_MAX + 25) /* move to beginning of line */
+#define REQ_END_LINE (KEY_MAX + 26) /* move after last char in line */
+#define REQ_LEFT_CHAR (KEY_MAX + 27) /* move left in field */
+#define REQ_RIGHT_CHAR (KEY_MAX + 28) /* move right in field */
+#define REQ_UP_CHAR (KEY_MAX + 29) /* move up in field */
+#define REQ_DOWN_CHAR (KEY_MAX + 30) /* move down in field */
+
+#define REQ_NEW_LINE (KEY_MAX + 31) /* insert/overlay new line */
+#define REQ_INS_CHAR (KEY_MAX + 32) /* insert blank char at cursor */
+#define REQ_INS_LINE (KEY_MAX + 33) /* insert blank line at cursor */
+#define REQ_DEL_CHAR (KEY_MAX + 34) /* delete char at cursor */
+#define REQ_DEL_PREV (KEY_MAX + 35) /* delete char before cursor */
+#define REQ_DEL_LINE (KEY_MAX + 36) /* delete line at cursor */
+#define REQ_DEL_WORD (KEY_MAX + 37) /* delete line at cursor */
+#define REQ_CLR_EOL (KEY_MAX + 38) /* clear to end of line */
+#define REQ_CLR_EOF (KEY_MAX + 39) /* clear to end of field */
+#define REQ_CLR_FIELD (KEY_MAX + 40) /* clear entire field */
+#define REQ_OVL_MODE (KEY_MAX + 41) /* begin overlay mode */
+#define REQ_INS_MODE (KEY_MAX + 42) /* begin insert mode */
+#define REQ_SCR_FLINE (KEY_MAX + 43) /* scroll field forward a line */
+#define REQ_SCR_BLINE (KEY_MAX + 44) /* scroll field backward a line */
+#define REQ_SCR_FPAGE (KEY_MAX + 45) /* scroll field forward a page */
+#define REQ_SCR_BPAGE (KEY_MAX + 46) /* scroll field backward a page */
+#define REQ_SCR_FHPAGE (KEY_MAX + 47) /* scroll field forward half page */
+#define REQ_SCR_BHPAGE (KEY_MAX + 48) /* scroll field backward half page */
+#define REQ_SCR_FCHAR (KEY_MAX + 49) /* horizontal scroll char */
+#define REQ_SCR_BCHAR (KEY_MAX + 50) /* horizontal scroll char */
+#define REQ_SCR_HFLINE (KEY_MAX + 51) /* horizontal scroll line */
+#define REQ_SCR_HBLINE (KEY_MAX + 52) /* horizontal scroll line */
+#define REQ_SCR_HFHALF (KEY_MAX + 53) /* horizontal scroll half line */
+#define REQ_SCR_HBHALF (KEY_MAX + 54) /* horizontal scroll half line */
+
+#define REQ_VALIDATION (KEY_MAX + 55) /* validate field */
+#define REQ_NEXT_CHOICE (KEY_MAX + 56) /* display next field choice */
+#define REQ_PREV_CHOICE (KEY_MAX + 57) /* display prev field choice */
+
+#define MIN_FORM_COMMAND (KEY_MAX + 1) /* used by form_driver */
+#define MAX_FORM_COMMAND (KEY_MAX + 57) /* used by form_driver */
+
+#if defined(MAX_COMMAND)
+# if (MAX_FORM_COMMAND > MAX_COMMAND)
+# error Something is wrong -- MAX_FORM_COMMAND is greater than MAX_COMMAND
+# elif (MAX_COMMAND != (KEY_MAX + 128))
+# error Something is wrong -- MAX_COMMAND is already inconsistently defined.
+# endif
+#else
+# define MAX_COMMAND (KEY_MAX + 128)
+#endif
+
+ /*************************
+ * standard field types *
+ *************************/
+extern FIELDTYPE *TYPE_ALPHA,
+ *TYPE_ALNUM,
+ *TYPE_ENUM,
+ *TYPE_INTEGER,
+ *TYPE_NUMERIC,
+ *TYPE_REGEXP;
+
+ /************************************
+ * built-in additional field types *
+ * They are not defined in SVr4 *
+ ************************************/
+extern FIELDTYPE *TYPE_IPV4; /* Internet IP Version 4 address */
+
+ /***********************
+ * Default objects *
+ ***********************/
+extern FORM *_nc_Default_Form;
+extern FIELD *_nc_Default_Field;
+
+
+ /***********************
+ * FIELDTYPE routines *
+ ***********************/
+extern FIELDTYPE
+ *new_fieldtype(
+ bool (* const field_check)(FIELD *,const void *),
+ bool (* const char_check)(int,const void *)),
+ *link_fieldtype(FIELDTYPE *,FIELDTYPE *);
+
+extern int free_fieldtype(FIELDTYPE *),
+ set_fieldtype_choice (FIELDTYPE *,
+ bool (* const next_choice)(FIELD *,const void *),
+ bool (* const prev_choice)(FIELD *,const void *));
+
+ /*******************
+ * FIELD routines *
+ *******************/
+extern FIELD *new_field(int,int,int,int,int,int),
+ *dup_field(FIELD *,int,int),
+ *link_field(FIELD *,int,int);
+
+extern int free_field(FIELD *),
+ field_info(const FIELD *,int *,int *,int *,int *,int *,int *),
+ dynamic_field_info(const FIELD *,int *,int *,int *),
+ set_max_field( FIELD *,int),
+ move_field(FIELD *,int,int),
+ set_field_type(FIELD *,FIELDTYPE *,...),
+ set_new_page(FIELD *,bool),
+ set_field_just(FIELD *,int),
+ field_just(const FIELD *),
+ set_field_fore(FIELD *,chtype),
+ set_field_back(FIELD *,chtype),
+ set_field_pad(FIELD *,int),
+ field_pad(const FIELD *),
+ set_field_buffer(FIELD *,int,const char *),
+ set_field_status(FIELD *,bool),
+ set_field_userptr(FIELD *, void *),
+ set_field_opts(FIELD *,Field_Options),
+ field_opts_on(FIELD *,Field_Options),
+ field_opts_off(FIELD *,Field_Options);
+
+extern chtype field_fore(const FIELD *),
+ field_back(const FIELD *);
+
+extern bool new_page(const FIELD *),
+ field_status(const FIELD *);
+
+extern void *field_arg(const FIELD *);
+
+extern void *field_userptr(const FIELD *);
+
+extern FIELDTYPE
+ *field_type(const FIELD *);
+
+extern char* field_buffer(const FIELD *,int);
+
+extern Field_Options
+ field_opts(const FIELD *);
+
+ /******************
+ * FORM routines *
+ ******************/
+extern FORM *new_form(FIELD **);
+
+extern FIELD **form_fields(const FORM *),
+ *current_field(const FORM *);
+
+extern WINDOW *form_win(const FORM *),
+ *form_sub(const FORM *);
+
+extern Form_Hook
+ form_init(const FORM *),
+ form_term(const FORM *),
+ field_init(const FORM *),
+ field_term(const FORM *);
+
+extern int free_form(FORM *),
+ set_form_fields(FORM *,FIELD **),
+ field_count(const FORM *),
+ set_form_win(FORM *,WINDOW *),
+ set_form_sub(FORM *,WINDOW *),
+ set_current_field(FORM *,FIELD *),
+ field_index(const FIELD *),
+ set_form_page(FORM *,int),
+ form_page(const FORM *),
+ scale_form(const FORM *,int *,int *),
+ set_form_init(FORM *,Form_Hook),
+ set_form_term(FORM *,Form_Hook),
+ set_field_init(FORM *,Form_Hook),
+ set_field_term(FORM *,Form_Hook),
+ post_form(FORM *),
+ unpost_form(FORM *),
+ pos_form_cursor(FORM *),
+ form_driver(FORM *,int),
+ set_form_userptr(FORM *,void *),
+ set_form_opts(FORM *,Form_Options),
+ form_opts_on(FORM *,Form_Options),
+ form_opts_off(FORM *,Form_Options),
+ form_request_by_name(const char *);
+
+extern const char
+ *form_request_name(int);
+
+extern void *form_userptr(const FORM *);
+
+extern Form_Options
+ form_opts(const FORM *);
+
+extern bool data_ahead(const FORM *),
+ data_behind(const FORM *);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* FORM_H */
diff --git a/Source/CursesDialog/form/form.priv.h b/Source/CursesDialog/form/form.priv.h
new file mode 100644
index 0000000..6e00af6
--- /dev/null
+++ b/Source/CursesDialog/form/form.priv.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "mf_common.h"
+#include "form.h"
+
+/* form status values */
+#define _OVLMODE (0x04) /* Form is in overlay mode */
+#define _WINDOW_MODIFIED (0x10) /* Current field window has been modified */
+#define _FCHECK_REQUIRED (0x20) /* Current field needs validation */
+
+/* field status values */
+#define _CHANGED (0x01) /* Field has been changed */
+#define _NEWTOP (0x02) /* Vertical scrolling occurred */
+#define _NEWPAGE (0x04) /* field begins new page of form */
+#define _MAY_GROW (0x08) /* dynamic field may still grow */
+
+/* fieldtype status values */
+#define _LINKED_TYPE (0x01) /* Type is a linked type */
+#define _HAS_ARGS (0x02) /* Type has arguments */
+#define _HAS_CHOICE (0x04) /* Type has choice methods */
+#define _RESIDENT (0x08) /* Type is builtin */
+
+/* This are the field options required to be a selectable field in field
+ navigation requests */
+#define O_SELECTABLE (O_ACTIVE | O_VISIBLE)
+
+/* If form is NULL replace form argument by default-form */
+#define Normalize_Form(form) ((form)=(form)?(form):_nc_Default_Form)
+
+/* If field is NULL replace field argument by default-field */
+#define Normalize_Field(field) ((field)=(field)?(field):_nc_Default_Field)
+
+/* Retrieve forms window */
+#define Get_Form_Window(form) \
+ ((form)->sub?(form)->sub:((form)->win?(form)->win:stdscr))
+
+/* Calculate the size for a single buffer for this field */
+#define Buffer_Length(field) ((field)->drows * (field)->dcols)
+
+/* Calculate the total size of all buffers for this field */
+#define Total_Buffer_Size(field) \
+ ( (Buffer_Length(field) + 1) * (1+(field)->nbuf) )
+
+/* Logic to determine whether or not a field is single lined */
+#define Single_Line_Field(field) \
+ (((field)->rows + (field)->nrow) == 1)
+
+/* Logic to determine whether or not a field is selectable */
+#define Field_Is_Selectable(f) (((f)->opts & O_SELECTABLE)==O_SELECTABLE)
+#define Field_Is_Not_Selectable(f) (((f)->opts & O_SELECTABLE)!=O_SELECTABLE)
+
+typedef struct typearg {
+ struct typearg *left;
+ struct typearg *right;
+} TypeArgument;
+
+/* This is a dummy request code (normally invalid) to be used internally
+ with the form_driver() routine to position to the first active field
+ on the form
+*/
+#define FIRST_ACTIVE_MAGIC (-291056)
+
+#define ALL_FORM_OPTS ( \
+ O_NL_OVERLOAD |\
+ O_BS_OVERLOAD )
+
+#define ALL_FIELD_OPTS ( \
+ O_VISIBLE |\
+ O_ACTIVE |\
+ O_PUBLIC |\
+ O_EDIT |\
+ O_WRAP |\
+ O_BLANK |\
+ O_AUTOSKIP|\
+ O_NULLOK |\
+ O_PASSOK |\
+ O_STATIC )
+
+
+#define C_BLANK ' '
+#define is_blank(c) ((c)==C_BLANK)
+
+extern const FIELDTYPE* _nc_Default_FieldType;
+
+extern TypeArgument* _nc_Make_Argument(const FIELDTYPE*,va_list*,int*);
+extern TypeArgument *_nc_Copy_Argument(const FIELDTYPE*,const TypeArgument*, int*);
+extern void _nc_Free_Argument(const FIELDTYPE*,TypeArgument*);
+extern bool _nc_Copy_Type(FIELD*, FIELD const *);
+extern void _nc_Free_Type(FIELD *);
+
+extern int _nc_Synchronize_Attributes(FIELD*);
+extern int _nc_Synchronize_Options(FIELD*,Field_Options);
+extern int _nc_Set_Form_Page(FORM*,int,FIELD*);
+extern int _nc_Refresh_Current_Field(FORM*);
+extern FIELD* _nc_First_Active_Field(FORM*);
+extern bool _nc_Internal_Validation(FORM*);
+extern int _nc_Set_Current_Field(FORM*,FIELD*);
+extern int _nc_Position_Form_Cursor(FORM*);
diff --git a/Source/CursesDialog/form/frm_cursor.c b/Source/CursesDialog/form/frm_cursor.c
new file mode 100644
index 0000000..6c311fe
--- /dev/null
+++ b/Source/CursesDialog/form/frm_cursor.c
@@ -0,0 +1,66 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int pos_form_cursor(FORM * form)
+|
+| Description : Moves the form window cursor to the location required
+| by the form driver to resume form processing. This may
+| be needed after the application calls a curses library
+| I/O routine that modifies the cursor position.
+|
+| Return Values : E_OK - Success
+| E_SYSTEM_ERROR - System error.
+| E_BAD_ARGUMENT - Invalid form pointer
+| E_NOT_POSTED - Form is not posted
++--------------------------------------------------------------------------*/
+int pos_form_cursor(FORM * form)
+{
+ int res;
+
+ if (!form)
+ res = E_BAD_ARGUMENT;
+ else
+ {
+ if (!(form->status & _POSTED))
+ res = E_NOT_POSTED;
+ else
+ res = _nc_Position_Form_Cursor(form);
+ }
+ RETURN(res);
+}
+
+/* frm_cursor.c ends here */
diff --git a/Source/CursesDialog/form/frm_data.c b/Source/CursesDialog/form/frm_data.c
new file mode 100644
index 0000000..fb62ab8
--- /dev/null
+++ b/Source/CursesDialog/form/frm_data.c
@@ -0,0 +1,183 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+extern int winnstr(WINDOW *, char *, int);
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : bool data_behind(const FORM *form)
+|
+| Description : Check for off-screen data behind. This is nearly trivial
+| becose the begin of a field is fixed.
+|
+| Return Values : TRUE - there are off-screen data behind
+| FALSE - there are no off-screen data behind
++--------------------------------------------------------------------------*/
+bool data_behind(const FORM *form)
+{
+ bool result = FALSE;
+
+ if (form && (form->status & _POSTED) && form->current)
+ {
+ FIELD *field;
+
+ field = form->current;
+ if (!Single_Line_Field(field))
+ {
+ result = (form->toprow==0) ? FALSE : TRUE;
+ }
+ else
+ {
+ result = (form->begincol==0) ? FALSE : TRUE;
+ }
+ }
+ return(result);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static char * After_Last_Non_Pad_Position(
+| char *buffer,
+| int len,
+| int pad)
+|
+| Description : Find the last position in the buffer that doesn't
+| contain a padding character.
+|
+| Return Values : The pointer to this position
++--------------------------------------------------------------------------*/
+INLINE
+static char * After_Last_Non_Pad_Position(char *buffer, int len, int pad)
+{
+ char *end = buffer + len;
+
+ assert(buffer && len>=0);
+ while ( (buffer < end) && (*(end-1)==pad) )
+ end--;
+
+ return end;
+}
+
+#define SMALL_BUFFER_SIZE (80)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : bool data_ahead(const FORM *form)
+|
+| Description : Check for off-screen data ahead. This is more difficult
+| because a dynamic field has a variable end.
+|
+| Return Values : TRUE - there are off-screen data ahead
+| FALSE - there are no off-screen data ahead
++--------------------------------------------------------------------------*/
+bool data_ahead(const FORM *form)
+{
+ bool result = FALSE;
+
+ if (form && (form->status & _POSTED) && form->current)
+ {
+ static char buffer[SMALL_BUFFER_SIZE + 1];
+ FIELD *field;
+ bool large_buffer;
+ bool cursor_moved = FALSE;
+ char *bp;
+ char *found_content;
+ int pos;
+
+ field = form->current;
+ assert(form->w != 0);
+
+ large_buffer = (field->cols > SMALL_BUFFER_SIZE);
+ if (large_buffer)
+ bp = (char *)malloc((size_t)(field->cols) + 1);
+ else
+ bp = buffer;
+
+ assert(bp != 0);
+
+ if (Single_Line_Field(field))
+ {
+ int check_len;
+
+ pos = form->begincol + field->cols;
+ while (pos < field->dcols)
+ {
+ check_len = field->dcols - pos;
+ if ( check_len >= field->cols )
+ check_len = field->cols;
+ cursor_moved = TRUE;
+ wmove(form->w,0,pos);
+ winnstr(form->w,bp,check_len);
+ found_content =
+ After_Last_Non_Pad_Position(bp,check_len,field->pad);
+ if (found_content==bp)
+ pos += field->cols;
+ else
+ {
+ result = TRUE;
+ break;
+ }
+ }
+ }
+ else
+ {
+ pos = form->toprow + field->rows;
+ while (pos < field->drows)
+ {
+ cursor_moved = TRUE;
+ wmove(form->w,pos,0);
+ pos++;
+ winnstr(form->w,bp,field->cols);
+ found_content =
+ After_Last_Non_Pad_Position(bp,field->cols,field->pad);
+ if (found_content!=bp)
+ {
+ result = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (large_buffer)
+ free(bp);
+
+ if (cursor_moved)
+ wmove(form->w,form->currow,form->curcol);
+ }
+ return(result);
+}
+
+/* frm_data.c ends here */
diff --git a/Source/CursesDialog/form/frm_def.c b/Source/CursesDialog/form/frm_def.c
new file mode 100644
index 0000000..645b3ba
--- /dev/null
+++ b/Source/CursesDialog/form/frm_def.c
@@ -0,0 +1,376 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/* this can't be readonly */
+static FORM default_form = {
+ 0, /* status */
+ 0, /* rows */
+ 0, /* cols */
+ 0, /* currow */
+ 0, /* curcol */
+ 0, /* toprow */
+ 0, /* begincol */
+ -1, /* maxfield */
+ -1, /* maxpage */
+ -1, /* curpage */
+ ALL_FORM_OPTS, /* opts */
+ (WINDOW *)0, /* win */
+ (WINDOW *)0, /* sub */
+ (WINDOW *)0, /* w */
+ (FIELD **)0, /* field */
+ (FIELD *)0, /* current */
+ (_PAGE *)0, /* page */
+ (char *)0, /* usrptr */
+ NULL, /* forminit */
+ NULL, /* formterm */
+ NULL, /* fieldinit */
+ NULL /* fieldterm */
+};
+
+FORM *_nc_Default_Form = &default_form;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Insert_Field_By_Position(
+| FIELD *new_field,
+| FIELD *head )
+|
+| Description : Insert new_field into sorted fieldlist with head "head"
+| and return new head of sorted fieldlist. Sorting
+| criteria is (row,column). This is a circular list.
+|
+| Return Values : New head of sorted fieldlist
++--------------------------------------------------------------------------*/
+static FIELD *Insert_Field_By_Position(FIELD *newfield, FIELD *head)
+{
+ FIELD *current, *newhead;
+
+ assert(newfield != 0);
+
+ if (!head)
+ { /* empty list is trivial */
+ newhead = newfield->snext = newfield->sprev = newfield;
+ }
+ else
+ {
+ newhead = current = head;
+ while((current->frow < newfield->frow) ||
+ ((current->frow==newfield->frow) &&
+ (current->fcol < newfield->fcol)) )
+ {
+ current = current->snext;
+ if (current==head)
+ { /* We cycled through. Reset head to indicate that */
+ head = (FIELD *)0;
+ break;
+ }
+ }
+ /* we leave the loop with current pointing to the field after newfield*/
+ newfield->snext = current;
+ newfield->sprev = current->sprev;
+ newfield->snext->sprev = newfield;
+ newfield->sprev->snext = newfield;
+ if (current==head)
+ newhead = newfield;
+ }
+ return(newhead);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Disconnect_Fields(FORM *form)
+|
+| Description : Break association between form and array of fields.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Disconnect_Fields( FORM * form )
+{
+ if (form->field)
+ {
+ FIELD **fields;
+
+ for(fields=form->field;*fields;fields++)
+ {
+ if (form == (*fields)->form)
+ (*fields)->form = (FORM *)0;
+ }
+
+ form->rows = form->cols = 0;
+ form->maxfield = form->maxpage = -1;
+ form->field = (FIELD **)0;
+ if (form->page)
+ free(form->page);
+ form->page = (_PAGE *)0;
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Connect_Fields(FORM *form, FIELD **fields)
+|
+| Description : Set association between form and array of fields.
+|
+| Return Values : E_OK - no error
+| E_CONNECTED - a field is already connected
+| E_BAD_ARGUMENT - Invalid form pointer or field array
+| E_SYSTEM_ERROR - not enough memory
++--------------------------------------------------------------------------*/
+static int Connect_Fields(FORM * form, FIELD ** fields)
+{
+ int field_cnt, j;
+ int page_nr;
+ int maximum_row_in_field, maximum_col_in_field;
+ _PAGE *pg;
+
+ assert(form != 0);
+
+ form->field = fields;
+ form->maxfield = 0;
+ form->maxpage = 0;
+
+ if (!fields)
+ RETURN(E_OK);
+
+ page_nr = 0;
+ /* store formpointer in fields and count pages */
+ for(field_cnt=0;fields[field_cnt];field_cnt++)
+ {
+ if (fields[field_cnt]->form)
+ RETURN(E_CONNECTED);
+ if ( field_cnt==0 ||
+ (fields[field_cnt]->status & _NEWPAGE))
+ page_nr++;
+ fields[field_cnt]->form = form;
+ }
+ if (field_cnt==0)
+ RETURN(E_BAD_ARGUMENT);
+
+ /* allocate page structures */
+ if ( (pg = (_PAGE *)malloc(page_nr * sizeof(_PAGE))) != (_PAGE *)0 )
+ {
+ form->page = pg;
+ }
+ else
+ RETURN(E_SYSTEM_ERROR);
+
+ /* Cycle through fields and calculate page boundaries as well as
+ size of the form */
+ for(j=0;j<field_cnt;j++)
+ {
+ if (j==0)
+ pg->pmin = j;
+ else
+ {
+ if (fields[j]->status & _NEWPAGE)
+ {
+ pg->pmax = j-1;
+ pg++;
+ pg->pmin = j;
+ }
+ }
+
+ maximum_row_in_field = fields[j]->frow + fields[j]->rows;
+ maximum_col_in_field = fields[j]->fcol + fields[j]->cols;
+
+ if (form->rows < maximum_row_in_field)
+ form->rows = maximum_row_in_field;
+ if (form->cols < maximum_col_in_field)
+ form->cols = maximum_col_in_field;
+ }
+
+ pg->pmax = field_cnt-1;
+ form->maxfield = field_cnt;
+ form->maxpage = page_nr;
+
+ /* Sort fields on form pages */
+ for(page_nr = 0;page_nr < form->maxpage; page_nr++)
+ {
+ FIELD *fld = (FIELD *)0;
+ for(j = form->page[page_nr].pmin;j <= form->page[page_nr].pmax;j++)
+ {
+ fields[j]->index = j;
+ fields[j]->page = page_nr;
+ fld = Insert_Field_By_Position(fields[j],fld);
+ }
+ form->page[page_nr].smin = fld->index;
+ form->page[page_nr].smax = fld->sprev->index;
+ }
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Associate_Fields(FORM *form, FIELD **fields)
+|
+| Description : Set association between form and array of fields.
+| If there are fields, position to first active field.
+|
+| Return Values : E_OK - success
+| any other - error occurred
++--------------------------------------------------------------------------*/
+INLINE static int Associate_Fields(FORM *form, FIELD **fields)
+{
+ int res = Connect_Fields(form,fields);
+ if (res == E_OK)
+ {
+ if (form->maxpage>0)
+ {
+ form->curpage = 0;
+ form_driver(form,FIRST_ACTIVE_MAGIC);
+ }
+ else
+ {
+ form->curpage = -1;
+ form->current = (FIELD *)0;
+ }
+ }
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FORM *new_form( FIELD **fields )
+|
+| Description : Create new form with given array of fields.
+|
+| Return Values : Pointer to form. NULL if error occurred.
++--------------------------------------------------------------------------*/
+FORM *new_form(FIELD ** fields)
+{
+ int err = E_SYSTEM_ERROR;
+
+ FORM *form = (FORM *)malloc(sizeof(FORM));
+
+ if (form)
+ {
+ *form = *_nc_Default_Form;
+ if ((err=Associate_Fields(form,fields))!=E_OK)
+ {
+ free_form(form);
+ form = (FORM *)0;
+ }
+ }
+
+ if (!form)
+ SET_ERROR(err);
+
+ return(form);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int free_form( FORM *form )
+|
+| Description : Release internal memory associated with form.
+|
+| Return Values : E_OK - no error
+| E_BAD_ARGUMENT - invalid form pointer
+| E_POSTED - form is posted
++--------------------------------------------------------------------------*/
+int free_form(FORM * form)
+{
+ if ( !form )
+ RETURN(E_BAD_ARGUMENT);
+
+ if ( form->status & _POSTED)
+ RETURN(E_POSTED);
+
+ Disconnect_Fields( form );
+ if (form->page)
+ free(form->page);
+ free(form);
+
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_fields( FORM *form, FIELD **fields )
+|
+| Description : Set a new association of an array of fields to a form
+|
+| Return Values : E_OK - no error
+| E_BAD_ARGUMENT - invalid form pointer
+| E_POSTED - form is posted
++--------------------------------------------------------------------------*/
+int set_form_fields(FORM * form, FIELD ** fields)
+{
+ FIELD **old;
+ int res;
+
+ if ( !form )
+ RETURN(E_BAD_ARGUMENT);
+
+ if ( form->status & _POSTED )
+ RETURN(E_POSTED);
+
+ old = form->field;
+ Disconnect_Fields( form );
+
+ if( (res = Associate_Fields( form, fields )) != E_OK )
+ Connect_Fields( form, old );
+
+ RETURN(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELD **form_fields( const FORM *form )
+|
+| Description : Retrieve array of fields
+|
+| Return Values : Pointer to field array
++--------------------------------------------------------------------------*/
+FIELD **form_fields(const FORM * form)
+{
+ return (Normalize_Form( form )->field);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_count( const FORM *form )
+|
+| Description : Retrieve number of fields
+|
+| Return Values : Number of fields, -1 if none are defined
++--------------------------------------------------------------------------*/
+int field_count(const FORM * form)
+{
+ return (Normalize_Form( form )->maxfield);
+}
+
+/* frm_def.c ends here */
diff --git a/Source/CursesDialog/form/frm_driver.c b/Source/CursesDialog/form/frm_driver.c
new file mode 100644
index 0000000..e4e72aa
--- /dev/null
+++ b/Source/CursesDialog/form/frm_driver.c
@@ -0,0 +1,3883 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+
+/* AIX seems to define this */
+#undef lines
+#undef columns
+
+MODULE_ID("$Id$")
+
+/* These declarations are missing from curses.h on some platforms. */
+extern int winnstr(WINDOW *, char *, int);
+#if defined(__DECCXX_VER) || (defined(__GNUC__) && defined(__osf__))
+extern int waddnstr(WINDOW *,const char *const,int);
+extern void wbkgdset(WINDOW *,chtype);
+#ifndef untouchwin
+extern int untouchwin(WINDOW *);
+#endif
+extern void wcursyncup(WINDOW *);
+extern int copywin(const WINDOW*,WINDOW*,int,int,int,int,int,int,int);
+extern bool is_linetouched(WINDOW *,int);
+extern void wsyncup(WINDOW *);
+extern WINDOW *derwin(WINDOW *,int,int,int,int);
+extern int winsnstr(WINDOW *, const char *,int);
+extern int winsdelln(WINDOW *,int);
+#endif
+
+/*----------------------------------------------------------------------------
+ This is the core module of the form library. It contains the majority
+ of the driver routines as well as the form_driver function.
+
+ Essentially this module is nearly the whole library. This is because
+ all the functions in this module depends on some others in the module,
+ so it makes no sense to split them into separate files because they
+ will always be linked together. The only acceptable concern is turnaround
+ time for this module, but now we have all Pentiums or Riscs, so what!
+
+ The driver routines are grouped into nine generic categories:
+
+ a) Page Navigation ( all functions prefixed by PN_ )
+ The current page of the form is left and some new page is
+ entered.
+ b) Inter-Field Navigation ( all functions prefixed by FN_ )
+ The current field of the form is left and some new field is
+ entered.
+ c) Intra-Field Navigation ( all functions prefixed by IFN_ )
+ The current position in the current field is changed.
+ d) Vertical Scrolling ( all functions prefixed by VSC_ )
+ Esseantially this is a specialization of Intra-Field navigation.
+ It has to check for a multi-line field.
+ e) Horizontal Scrolling ( all functions prefixed by HSC_ )
+ Esseantially this is a specialization of Intra-Field navigation.
+ It has to check for a single-line field.
+ f) Field Editing ( all functions prefixed by FE_ )
+ The content of the current field is changed
+ g) Edit Mode requests ( all functions prefixed by EM_ )
+ Switching between insert and overlay mode
+ h) Field-Validation requests ( all functions prefixed by FV_ )
+ Perform verifications of the field.
+ i) Choice requests ( all functions prefixed by CR_ )
+ Requests to enumerate possible field values
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Some remarks on the placements of assert() macros :
+ I use them only on "strategic" places, i.e. top level entries where
+ I want to make sure that things are set correctly. Throughout subordinate
+ routines I omit them mostly.
+ --------------------------------------------------------------------------*/
+
+/*
+Some options that may effect compatibility in behavior to SVr4 forms,
+but they are here to allow a more intuitive and user friendly behaviour of
+our form implementation. This doesn't affect the API, so we feel it is
+uncritical.
+
+The initial implementation tries to stay very close with the behaviour
+of the original SVr4 implementation, although in some areas it is quite
+clear that this isn't the most appropriate way. As far as possible this
+sources will allow you to build a forms lib that behaves quite similar
+to SVr4, but now and in the future we will give you better options.
+Perhaps at some time we will make this configurable at runtime.
+*/
+
+/* Implement a more user-friendly previous/next word behaviour */
+#define FRIENDLY_PREV_NEXT_WORD (1)
+/* Fix the wrong behaviour for forms with all fields inactive */
+#define FIX_FORM_INACTIVE_BUG (1)
+/* Allow dynamic field growth also when navigating past the end */
+#define GROW_IF_NAVIGATE (1)
+
+/*----------------------------------------------------------------------------
+ Forward references to some internally used static functions
+ --------------------------------------------------------------------------*/
+static int Inter_Field_Navigation ( int (* const fct) (FORM *), FORM * form );
+static int FN_Next_Field (FORM * form);
+static int FN_Previous_Field (FORM * form);
+static int FE_New_Line(FORM *);
+static int FE_Delete_Previous(FORM *);
+
+/*----------------------------------------------------------------------------
+ Macro Definitions.
+
+ Some Remarks on that: I use the convention to use UPPERCASE for constants
+ defined by Macros. If I provide a macro as a kind of inline routine to
+ provide some logic, I use my Upper_Lower case style.
+ --------------------------------------------------------------------------*/
+
+/* Calculate the position of a single row in a field buffer */
+#define Position_Of_Row_In_Buffer(field,row) ((row)*(field)->dcols)
+
+/* Calculate start address for the fields buffer# N */
+#define Address_Of_Nth_Buffer(field,N) \
+ ((field)->buf + (N)*(1+Buffer_Length(field)))
+
+/* Calculate the start address of the row in the fields specified buffer# N */
+#define Address_Of_Row_In_Nth_Buffer(field,N,row) \
+ (Address_Of_Nth_Buffer(field,N) + Position_Of_Row_In_Buffer(field,row))
+
+/* Calculate the start address of the row in the fields primary buffer */
+#define Address_Of_Row_In_Buffer(field,row) \
+ Address_Of_Row_In_Nth_Buffer(field,0,row)
+
+/* Calculate the start address of the row in the forms current field
+ buffer# N */
+#define Address_Of_Current_Row_In_Nth_Buffer(form,N) \
+ Address_Of_Row_In_Nth_Buffer((form)->current,N,(form)->currow)
+
+/* Calculate the start address of the row in the forms current field
+ primary buffer */
+#define Address_Of_Current_Row_In_Buffer(form) \
+ Address_Of_Current_Row_In_Nth_Buffer(form,0)
+
+/* Calculate the address of the cursor in the forms current field
+ primary buffer */
+#define Address_Of_Current_Position_In_Nth_Buffer(form,N) \
+ (Address_Of_Current_Row_In_Nth_Buffer(form,N) + (form)->curcol)
+
+/* Calculate the address of the cursor in the forms current field
+ buffer# N */
+#define Address_Of_Current_Position_In_Buffer(form) \
+ Address_Of_Current_Position_In_Nth_Buffer(form,0)
+
+/* Logic to decide whether or not a field is actually a field with
+ vertical or horizontal scrolling */
+#define Is_Scroll_Field(field) \
+ (((field)->drows > (field)->rows) || \
+ ((field)->dcols > (field)->cols))
+
+/* Logic to decide whether or not a field needs to have an individual window
+ instead of a derived window because it contains invisible parts.
+ This is true for non-public fields and for scrollable fields. */
+#define Has_Invisible_Parts(field) \
+ (!((field)->opts & O_PUBLIC) || \
+ Is_Scroll_Field(field))
+
+/* Logic to decide whether or not a field needs justification */
+#define Justification_Allowed(field) \
+ (((field)->just != NO_JUSTIFICATION) && \
+ (Single_Line_Field(field)) && \
+ (((field)->dcols == (field)->cols) && \
+ ((field)->opts & O_STATIC)) )
+
+/* Logic to determine whether or not a dynamic field may still grow */
+#define Growable(field) ((field)->status & _MAY_GROW)
+
+/* Macro to set the attributes for a fields window */
+#define Set_Field_Window_Attributes(field,win) \
+( wbkgdset((win),(chtype)((field)->pad | (field)->back)), \
+ wattrset((win),(field)->fore) )
+
+/* Logic to decide whether or not a field really appears on the form */
+#define Field_Really_Appears(field) \
+ ((field->form) &&\
+ (field->form->status & _POSTED) &&\
+ (field->opts & O_VISIBLE) &&\
+ (field->page == field->form->curpage))
+
+/* Logic to determine whether or not we are on the first position in the
+ current field */
+#define First_Position_In_Current_Field(form) \
+ (((form)->currow==0) && ((form)->curcol==0))
+
+
+#define Minimum(a,b) (((a)<=(b)) ? (a) : (b))
+#define Maximum(a,b) (((a)>=(b)) ? (a) : (b))
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static char *Get_Start_Of_Data(char * buf, int blen)
+|
+| Description : Return pointer to first non-blank position in buffer.
+| If buffer is empty return pointer to buffer itself.
+|
+| Return Values : Pointer to first non-blank position in buffer
++--------------------------------------------------------------------------*/
+INLINE static char *Get_Start_Of_Data(char * buf, int blen)
+{
+ char *p = buf;
+ char *end = &buf[blen];
+
+ assert(buf && blen>=0);
+ while( (p < end) && is_blank(*p) )
+ p++;
+ return( (p==end) ? buf : p );
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static char *After_End_Of_Data(char * buf, int blen)
+|
+| Description : Return pointer after last non-blank position in buffer.
+| If buffer is empty, return pointer to buffer itself.
+|
+| Return Values : Pointer to position after last non-blank position in
+| buffer.
++--------------------------------------------------------------------------*/
+INLINE static char *After_End_Of_Data(char * buf,int blen)
+{
+ char *p = &buf[blen];
+
+ assert(buf && blen>=0);
+ while( (p>buf) && is_blank(p[-1]) )
+ p--;
+ return( p );
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static char *Get_First_Whitespace_Character(
+| char * buf, int blen)
+|
+| Description : Position to the first whitespace character.
+|
+| Return Values : Pointer to first whitespace character in buffer.
++--------------------------------------------------------------------------*/
+INLINE static char *Get_First_Whitespace_Character(char * buf, int blen)
+{
+ char *p = buf;
+ char *end = &p[blen];
+
+ assert(buf && blen>=0);
+ while( (p < end) && !is_blank(*p))
+ p++;
+ return( (p==end) ? buf : p );
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static char *After_Last_Whitespace_Character(
+| char * buf, int blen)
+|
+| Description : Get the position after the last whitespace character.
+|
+| Return Values : Pointer to position after last whitespace character in
+| buffer.
++--------------------------------------------------------------------------*/
+INLINE static char *After_Last_Whitespace_Character(char * buf, int blen)
+{
+ char *p = &buf[blen];
+
+ assert(buf && blen>=0);
+ while( (p>buf) && !is_blank(p[-1]) )
+ p--;
+ return( p );
+}
+
+/* Set this to 1 to use the div_t version. This is a good idea if your
+ compiler has an intrinsic div() support. Unfortunately GNU-C has it
+ not yet.
+ N.B.: This only works if form->curcol follows immediately form->currow
+ and both are of type int.
+*/
+#define USE_DIV_T (0)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Adjust_Cursor_Position(
+| FORM * form, const char * pos)
+|
+| Description : Set current row and column of the form to values
+| corresponding to the buffer position.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+INLINE static void Adjust_Cursor_Position(FORM * form, const char * pos)
+{
+ FIELD *field;
+ int idx;
+
+ field = form->current;
+ assert( pos >= field->buf && field->dcols > 0);
+ idx = (int)( pos - field->buf );
+#if USE_DIV_T
+ *((div_t *)&(form->currow)) = div(idx,field->dcols);
+#else
+ form->currow = idx / field->dcols;
+ form->curcol = idx - field->cols * form->currow;
+#endif
+ if ( field->drows < form->currow )
+ form->currow = 0;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Buffer_To_Window(
+| const FIELD * field,
+| WINDOW * win)
+|
+| Description : Copy the buffer to the window. If its a multiline
+| field, the buffer is split to the lines of the
+| window without any editing.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Buffer_To_Window(const FIELD * field, WINDOW * win)
+{
+ int width, height;
+ int len;
+ int row;
+ char *pBuffer;
+
+ assert(win && field);
+
+ getmaxyx(win, height, width);
+
+ for(row=0, pBuffer=field->buf;
+ row < height;
+ row++, pBuffer += width )
+ {
+ if ((len = (int)( After_End_Of_Data( pBuffer, width ) - pBuffer )) > 0)
+ {
+ wmove( win, row, 0 );
+ waddnstr( win, pBuffer, len );
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Window_To_Buffer(
+| WINDOW * win,
+| FIELD * field)
+|
+| Description : Copy the content of the window into the buffer.
+| The multiple lines of a window are simply
+| concatenated into the buffer. Pad characters in
+| the window will be replaced by blanks in the buffer.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Window_To_Buffer(WINDOW * win, FIELD * field)
+{
+ int pad;
+ int len = 0;
+ char *p;
+ int row, height, width;
+
+ assert(win && field && field->buf );
+
+ pad = field->pad;
+ p = field->buf;
+ getmaxyx(win, height, width);
+
+ for(row=0; (row < height) && (row < field->drows); row++ )
+ {
+ wmove( win, row, 0 );
+ len += winnstr( win, p+len, field->dcols );
+ }
+ p[len] = '\0';
+
+ /* replace visual padding character by blanks in buffer */
+ if (pad != C_BLANK)
+ {
+ int i;
+ for(i=0; i<len; i++, p++)
+ {
+ if (*p==pad)
+ *p = C_BLANK;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Synchronize_Buffer(FORM * form)
+|
+| Description : If there was a change, copy the content of the
+| window into the buffer, so the buffer is synchronized
+| with the windows content. We have to indicate that the
+| buffer needs validation due to the change.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+INLINE static void Synchronize_Buffer(FORM * form)
+{
+ if (form->status & _WINDOW_MODIFIED)
+ {
+ form->status &= ~_WINDOW_MODIFIED;
+ form->status |= _FCHECK_REQUIRED;
+ Window_To_Buffer(form->w,form->current);
+ wmove(form->w,form->currow,form->curcol);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Field_Grown( FIELD *field, int amount)
+|
+| Description : This function is called for growable dynamic fields
+| only. It has to increase the buffers and to allocate
+| a new window for this field.
+| This function has the side effect to set a new
+| field-buffer pointer, the dcols and drows values
+| as well as a new current Window for the field.
+|
+| Return Values : TRUE - field successfully increased
+| FALSE - there was some error
++--------------------------------------------------------------------------*/
+static bool Field_Grown(FIELD * field, int amount)
+{
+ bool result = FALSE;
+
+ if (field && Growable(field))
+ {
+ bool single_line_field = Single_Line_Field(field);
+ int old_buflen = Buffer_Length(field);
+ int new_buflen;
+ int old_dcols = field->dcols;
+ int old_drows = field->drows;
+ char *oldbuf = field->buf;
+ char *newbuf;
+
+ int growth;
+ FORM *form = field->form;
+ bool need_visual_update = ((form != (FORM *)0) &&
+ (form->status & _POSTED) &&
+ (form->current==field));
+
+ if (need_visual_update)
+ Synchronize_Buffer(form);
+
+ if (single_line_field)
+ {
+ growth = field->cols * amount;
+ if (field->maxgrow)
+ growth = Minimum(field->maxgrow - field->dcols,growth);
+ field->dcols += growth;
+ if (field->dcols == field->maxgrow)
+ field->status &= ~_MAY_GROW;
+ }
+ else
+ {
+ growth = (field->rows + field->nrow) * amount;
+ if (field->maxgrow)
+ growth = Minimum(field->maxgrow - field->drows,growth);
+ field->drows += growth;
+ if (field->drows == field->maxgrow)
+ field->status &= ~_MAY_GROW;
+ }
+ /* drows, dcols changed, so we get really the new buffer length */
+ new_buflen = Buffer_Length(field);
+ newbuf=(char *)malloc((size_t)Total_Buffer_Size(field));
+ if (!newbuf)
+ { /* restore to previous state */
+ field->dcols = old_dcols;
+ field->drows = old_drows;
+ if (( single_line_field && (field->dcols!=field->maxgrow)) ||
+ (!single_line_field && (field->drows!=field->maxgrow)))
+ field->status |= _MAY_GROW;
+ return FALSE;
+ }
+ else
+ { /* Copy all the buffers. This is the reason why we can't
+ just use realloc().
+ */
+ int i;
+ char *old_bp;
+ char *new_bp;
+
+ field->buf = newbuf;
+ for(i=0;i<=field->nbuf;i++)
+ {
+ new_bp = Address_Of_Nth_Buffer(field,i);
+ old_bp = oldbuf + i*(1+old_buflen);
+ memcpy(new_bp,old_bp,(size_t)old_buflen);
+ if (new_buflen > old_buflen)
+ memset(new_bp + old_buflen,C_BLANK,
+ (size_t)(new_buflen - old_buflen));
+ *(new_bp + new_buflen) = '\0';
+ }
+
+ if (need_visual_update)
+ {
+ WINDOW *new_window = newpad(field->drows,field->dcols);
+ if (!new_window)
+ { /* restore old state */
+ field->dcols = old_dcols;
+ field->drows = old_drows;
+ field->buf = oldbuf;
+ if (( single_line_field &&
+ (field->dcols!=field->maxgrow)) ||
+ (!single_line_field &&
+ (field->drows!=field->maxgrow)))
+ field->status |= _MAY_GROW;
+ free( newbuf );
+ return FALSE;
+ }
+ assert(form!=(FORM *)0);
+ delwin(form->w);
+ form->w = new_window;
+ Set_Field_Window_Attributes(field,form->w);
+ werase(form->w);
+ Buffer_To_Window(field,form->w);
+ untouchwin(form->w);
+ wmove(form->w,form->currow,form->curcol);
+ }
+
+ free(oldbuf);
+ /* reflect changes in linked fields */
+ if (field != field->link)
+ {
+ FIELD *linked_field;
+ for(linked_field = field->link;
+ linked_field!= field;
+ linked_field = linked_field->link)
+ {
+ linked_field->buf = field->buf;
+ linked_field->drows = field->drows;
+ linked_field->dcols = field->dcols;
+ }
+ }
+ result = TRUE;
+ }
+ }
+ return(result);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int _nc_Position_Form_Cursor(FORM * form)
+|
+| Description : Position the cursor in the window for the current
+| field to be in sync. with the currow and curcol
+| values.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid form pointer
+| E_SYSTEM_ERROR - form has no current field or
+| field-window
++--------------------------------------------------------------------------*/
+int
+_nc_Position_Form_Cursor(FORM * form)
+{
+ FIELD *field;
+ WINDOW *formwin;
+
+ if (!form)
+ return(E_BAD_ARGUMENT);
+
+ if (!form->w || !form->current)
+ return(E_SYSTEM_ERROR);
+
+ field = form->current;
+ formwin = Get_Form_Window(form);
+
+ wmove( form->w, form->currow, form->curcol );
+ if ( Has_Invisible_Parts(field) )
+ {
+ /* in this case fieldwin isn't derived from formwin, so we have
+ to move the cursor in formwin by hand... */
+ wmove(formwin,
+ field->frow + form->currow - form->toprow,
+ field->fcol + form->curcol - form->begincol);
+ wcursyncup(formwin);
+ }
+ else
+ wcursyncup(form->w);
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int _nc_Refresh_Current_Field(FORM * form)
+|
+| Description : Propagate the changes in the fields window to the
+| window of the form.
+|
+| Return Values : E_OK - on success
+| E_BAD_ARGUMENT - invalid form pointer
+| E_SYSTEM_ERROR - general error
++--------------------------------------------------------------------------*/
+int
+_nc_Refresh_Current_Field(FORM * form)
+{
+ WINDOW *formwin;
+ FIELD *field;
+
+ if (!form)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (!form->w || !form->current)
+ RETURN(E_SYSTEM_ERROR);
+
+ field = form->current;
+ formwin = Get_Form_Window(form);
+
+ if (field->opts & O_PUBLIC)
+ {
+ if (Is_Scroll_Field(field))
+ {
+ /* Again, in this case the fieldwin isn't derived from formwin,
+ so we have to perform a copy operation. */
+ if (Single_Line_Field(field))
+ { /* horizontal scrolling */
+ if (form->curcol < form->begincol)
+ form->begincol = form->curcol;
+ else
+ {
+ if (form->curcol >= (form->begincol + field->cols))
+ form->begincol = form->curcol - field->cols + 1;
+ }
+ copywin(form->w,
+ formwin,
+ 0,
+ form->begincol,
+ field->frow,
+ field->fcol,
+ field->frow,
+ field->cols + field->fcol - 1,
+ 0);
+ }
+ else
+ { /* A multiline, i.e. vertical scrolling field */
+ int row_after_bottom,first_modified_row,first_unmodified_row;
+
+ if (field->drows > field->rows)
+ {
+ row_after_bottom = form->toprow + field->rows;
+ if (form->currow < form->toprow)
+ {
+ form->toprow = form->currow;
+ field->status |= _NEWTOP;
+ }
+ if (form->currow >= row_after_bottom)
+ {
+ form->toprow = form->currow - field->rows + 1;
+ field->status |= _NEWTOP;
+ }
+ if (field->status & _NEWTOP)
+ { /* means we have to copy whole range */
+ first_modified_row = form->toprow;
+ first_unmodified_row = first_modified_row + field->rows;
+ field->status &= ~_NEWTOP;
+ }
+ else
+ { /* we try to optimize : finding the range of touched
+ lines */
+ first_modified_row = form->toprow;
+ while(first_modified_row < row_after_bottom)
+ {
+ if (is_linetouched(form->w,first_modified_row))
+ break;
+ first_modified_row++;
+ }
+ first_unmodified_row = first_modified_row;
+ while(first_unmodified_row < row_after_bottom)
+ {
+ if (!is_linetouched(form->w,first_unmodified_row))
+ break;
+ first_unmodified_row++;
+ }
+ }
+ }
+ else
+ {
+ first_modified_row = form->toprow;
+ first_unmodified_row = first_modified_row + field->rows;
+ }
+ if (first_unmodified_row != first_modified_row)
+ copywin(form->w,
+ formwin,
+ first_modified_row,
+ 0,
+ field->frow + first_modified_row - form->toprow,
+ field->fcol,
+ field->frow + first_unmodified_row - form->toprow - 1,
+ field->cols + field->fcol - 1,
+ 0);
+ }
+ wsyncup(formwin);
+ }
+ else
+ { /* if the field-window is simply a derived window, i.e. contains
+ no invisible parts, the whole thing is trivial
+ */
+ wsyncup(form->w);
+ }
+ }
+ untouchwin(form->w);
+ return _nc_Position_Form_Cursor(form);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Perform_Justification(
+| FIELD * field,
+| WINDOW * win)
+|
+| Description : Output field with requested justification
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Perform_Justification(FIELD * field, WINDOW * win)
+{
+ char *bp;
+ int len;
+ int col = 0;
+
+ bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
+ len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field)) - bp);
+
+ if (len>0)
+ {
+ assert(win && (field->drows == 1) && (field->dcols == field->cols));
+
+ switch(field->just)
+ {
+ case JUSTIFY_LEFT:
+ break;
+ case JUSTIFY_CENTER:
+ col = (field->cols - len)/2;
+ break;
+ case JUSTIFY_RIGHT:
+ col = field->cols - len;
+ break;
+ default:
+ break;
+ }
+
+ wmove(win,0,col);
+ waddnstr(win,bp,len);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Undo_Justification(
+| FIELD * field,
+| WINDOW * win)
+|
+| Description : Display field without any justification, i.e.
+| left justified
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Undo_Justification(FIELD * field, WINDOW * win)
+{
+ char *bp;
+ int len;
+
+ bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
+ len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field))-bp);
+
+ if (len>0)
+ {
+ assert(win != 0);
+ wmove(win,0,0);
+ waddnstr(win,bp,len);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Char(
+| FIELDTYPE * typ,
+| int ch,
+| TypeArgument *argp)
+|
+| Description : Perform a single character check for character ch
+| according to the fieldtype instance.
+|
+| Return Values : TRUE - Character is valid
+| FALSE - Character is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Char(FIELDTYPE * typ, int ch, TypeArgument *argp)
+{
+ if (typ)
+ {
+ if (typ->status & _LINKED_TYPE)
+ {
+ assert(argp != 0);
+ return(
+ Check_Char(typ->left ,ch,argp->left ) ||
+ Check_Char(typ->right,ch,argp->right) );
+ }
+ else
+ {
+ if (typ->ccheck)
+ return typ->ccheck(ch,(void *)argp);
+ }
+ }
+ return (isprint((unsigned char)ch) ? TRUE : FALSE);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Display_Or_Erase_Field(
+| FIELD * field,
+| bool bEraseFlag)
+|
+| Description : Create a subwindow for the field and display the
+| buffer contents (apply justification if required)
+| or simply erase the field.
+|
+| Return Values : E_OK - on success
+| E_SYSTEM_ERROR - some error (typical no memory)
++--------------------------------------------------------------------------*/
+static int Display_Or_Erase_Field(FIELD * field, bool bEraseFlag)
+{
+ WINDOW *win;
+ WINDOW *fwin;
+
+ if (!field)
+ return E_SYSTEM_ERROR;
+
+ fwin = Get_Form_Window(field->form);
+ win = derwin(fwin,
+ field->rows,field->cols,field->frow,field->fcol);
+
+ if (!win)
+ return E_SYSTEM_ERROR;
+ else
+ {
+ if (field->opts & O_VISIBLE)
+ Set_Field_Window_Attributes(field,win);
+ else
+ {
+#if defined(__LSB_VERSION__)
+ /* getattrs() would be handy, but it is not part of LSB 4.0 */
+ attr_t fwinAttrs;
+ short fwinPair;
+ wattr_get(fwin, &fwinAttrs, &fwinPair, 0);
+ wattr_set(win, fwinAttrs, fwinPair, 0);
+#else
+ wattrset(win,getattrs(fwin));
+#endif
+ }
+ werase(win);
+ }
+
+ if (!bEraseFlag)
+ {
+ if (field->opts & O_PUBLIC)
+ {
+ if (Justification_Allowed(field))
+ Perform_Justification(field,win);
+ else
+ Buffer_To_Window(field,win);
+ }
+ field->status &= ~_NEWTOP;
+ }
+ wsyncup(win);
+ delwin(win);
+ return E_OK;
+}
+
+/* Macros to preset the bEraseFlag */
+#define Display_Field(field) Display_Or_Erase_Field(field,FALSE)
+#define Erase_Field(field) Display_Or_Erase_Field(field,TRUE)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Synchronize_Field(FIELD * field)
+|
+| Description : Synchronize the windows content with the value in
+| the buffer.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer
+| E_SYSTEM_ERROR - some severe basic error
++--------------------------------------------------------------------------*/
+static int Synchronize_Field(FIELD * field)
+{
+ FORM *form;
+ int res = E_OK;
+
+ if (!field)
+ return(E_BAD_ARGUMENT);
+
+ if (((form=field->form) != (FORM *)0)
+ && Field_Really_Appears(field))
+ {
+ if (field == form->current)
+ {
+ form->currow = form->curcol = form->toprow = form->begincol = 0;
+ werase(form->w);
+
+ if ( (field->opts & O_PUBLIC) && Justification_Allowed(field) )
+ Undo_Justification( field, form->w );
+ else
+ Buffer_To_Window( field, form->w );
+
+ field->status |= _NEWTOP;
+ res = _nc_Refresh_Current_Field( form );
+ }
+ else
+ res = Display_Field( field );
+ }
+ field->status |= _CHANGED;
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Synchronize_Linked_Fields(FIELD * field)
+|
+| Description : Propagate the Synchronize_Field function to all linked
+| fields. The first error that occurs in the sequence
+| of updates is the returnvalue.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer
+| E_SYSTEM_ERROR - some severe basic error
++--------------------------------------------------------------------------*/
+static int Synchronize_Linked_Fields(FIELD * field)
+{
+ FIELD *linked_field;
+ int res = E_OK;
+ int syncres;
+
+ if (!field)
+ return(E_BAD_ARGUMENT);
+
+ if (!field->link)
+ return(E_SYSTEM_ERROR);
+
+ for(linked_field = field->link;
+ linked_field!= field;
+ linked_field = linked_field->link )
+ {
+ if (((syncres=Synchronize_Field(linked_field)) != E_OK) &&
+ (res==E_OK))
+ res = syncres;
+ }
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int _nc_Synchronize_Attributes(FIELD * field)
+|
+| Description : If a fields visual attributes have changed, this
+| routine is called to propagate those changes to the
+| screen.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer
+| E_SYSTEM_ERROR - some severe basic error
++--------------------------------------------------------------------------*/
+int _nc_Synchronize_Attributes(FIELD * field)
+{
+ FORM *form;
+ int res = E_OK;
+ WINDOW *formwin;
+
+ if (!field)
+ return(E_BAD_ARGUMENT);
+
+ if (((form=field->form) != (FORM *)0)
+ && Field_Really_Appears(field))
+ {
+ if (form->current==field)
+ {
+ Synchronize_Buffer(form);
+ Set_Field_Window_Attributes(field,form->w);
+ werase(form->w);
+ if (field->opts & O_PUBLIC)
+ {
+ if (Justification_Allowed(field))
+ Undo_Justification(field,form->w);
+ else
+ Buffer_To_Window(field,form->w);
+ }
+ else
+ {
+ formwin = Get_Form_Window(form);
+ copywin(form->w,formwin,
+ 0,0,
+ field->frow,field->fcol,
+ field->rows-1,field->cols-1,0);
+ wsyncup(formwin);
+ Buffer_To_Window(field,form->w);
+ field->status |= _NEWTOP; /* fake refresh to paint all */
+ _nc_Refresh_Current_Field(form);
+ }
+ }
+ else
+ {
+ res = Display_Field(field);
+ }
+ }
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int _nc_Synchronize_Options(FIELD * field,
+| Field_Options newopts)
+|
+| Description : If a fields options have changed, this routine is
+| called to propagate these changes to the screen and
+| to really change the behaviour of the field.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer
+| E_SYSTEM_ERROR - some severe basic error
++--------------------------------------------------------------------------*/
+int
+_nc_Synchronize_Options(FIELD *field, Field_Options newopts)
+{
+ Field_Options oldopts;
+ Field_Options changed_opts;
+ FORM *form;
+ int res = E_OK;
+
+ if (!field)
+ return(E_BAD_ARGUMENT);
+
+ oldopts = field->opts;
+ changed_opts = oldopts ^ newopts;
+ field->opts = newopts;
+ form = field->form;
+
+ if (form)
+ {
+ if (form->current == field)
+ {
+ field->opts = oldopts;
+ return(E_CURRENT);
+ }
+
+ if (form->status & _POSTED)
+ {
+ if (form->curpage == field->page)
+ {
+ if (changed_opts & O_VISIBLE)
+ {
+ if (newopts & O_VISIBLE)
+ res = Display_Field(field);
+ else
+ res = Erase_Field(field);
+ }
+ else
+ {
+ if ((changed_opts & O_PUBLIC) &&
+ (newopts & O_VISIBLE))
+ res = Display_Field(field);
+ }
+ }
+ }
+ }
+
+ if (changed_opts & O_STATIC)
+ {
+ bool single_line_field = Single_Line_Field(field);
+ int res2 = E_OK;
+
+ if (newopts & O_STATIC)
+ { /* the field becomes now static */
+ field->status &= ~_MAY_GROW;
+ /* if actually we have no hidden columns, justification may
+ occur again */
+ if (single_line_field &&
+ (field->cols == field->dcols) &&
+ (field->just != NO_JUSTIFICATION) &&
+ Field_Really_Appears(field))
+ {
+ res2 = Display_Field(field);
+ }
+ }
+ else
+ { /* field is no longer static */
+ if ((field->maxgrow==0) ||
+ ( single_line_field && (field->dcols < field->maxgrow)) ||
+ (!single_line_field && (field->drows < field->maxgrow)))
+ {
+ field->status |= _MAY_GROW;
+ /* a field with justification now changes its behaviour,
+ so we must redisplay it */
+ if (single_line_field &&
+ (field->just != NO_JUSTIFICATION) &&
+ Field_Really_Appears(field))
+ {
+ res2 = Display_Field(field);
+ }
+ }
+ }
+ if (res2 != E_OK)
+ res = res2;
+ }
+
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int _nc_Set_Current_Field(FORM * form,
+| FIELD * newfield)
+|
+| Description : Make the newfield the new current field.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid form or field pointer
+| E_SYSTEM_ERROR - some severe basic error
++--------------------------------------------------------------------------*/
+int
+_nc_Set_Current_Field(FORM *form, FIELD *newfield)
+{
+ FIELD *field;
+ WINDOW *new_window;
+
+ if (!form || !newfield || !form->current || (newfield->form!=form))
+ return(E_BAD_ARGUMENT);
+
+ if ( (form->status & _IN_DRIVER) )
+ return(E_BAD_STATE);
+
+ if (!(form->field))
+ return(E_NOT_CONNECTED);
+
+ field = form->current;
+
+ if ((field!=newfield) ||
+ !(form->status & _POSTED))
+ {
+ if ((form->w) &&
+ (field->opts & O_VISIBLE) &&
+ (field->form->curpage == field->page))
+ {
+ _nc_Refresh_Current_Field(form);
+ if (field->opts & O_PUBLIC)
+ {
+ if (field->drows > field->rows)
+ {
+ if (form->toprow==0)
+ field->status &= ~_NEWTOP;
+ else
+ field->status |= _NEWTOP;
+ }
+ else
+ {
+ if (Justification_Allowed(field))
+ {
+ Window_To_Buffer(form->w,field);
+ werase(form->w);
+ Perform_Justification(field,form->w);
+ wsyncup(form->w);
+ }
+ }
+ }
+ delwin(form->w);
+ }
+
+ field = newfield;
+
+ if (Has_Invisible_Parts(field))
+ new_window = newpad(field->drows,field->dcols);
+ else
+ new_window = derwin(Get_Form_Window(form),
+ field->rows,field->cols,field->frow,field->fcol);
+
+ if (!new_window)
+ return(E_SYSTEM_ERROR);
+
+ form->current = field;
+ form->w = new_window;
+ form->status &= ~_WINDOW_MODIFIED;
+ Set_Field_Window_Attributes(field,form->w);
+
+ if (Has_Invisible_Parts(field))
+ {
+ werase(form->w);
+ Buffer_To_Window(field,form->w);
+ }
+ else
+ {
+ if (Justification_Allowed(field))
+ {
+ werase(form->w);
+ Undo_Justification(field,form->w);
+ wsyncup(form->w);
+ }
+ }
+
+ untouchwin(form->w);
+ }
+
+ form->currow = form->curcol = form->toprow = form->begincol = 0;
+ return(E_OK);
+}
+
+/*----------------------------------------------------------------------------
+ Intra-Field Navigation routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Next_Character(FORM * form)
+|
+| Description : Move to the next character in the field. In a multiline
+| field this wraps at the end of the line.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - at the rightmost position
++--------------------------------------------------------------------------*/
+static int IFN_Next_Character(FORM * form)
+{
+ FIELD *field = form->current;
+
+ if ((++(form->curcol))==field->dcols)
+ {
+ if ((++(form->currow))==field->drows)
+ {
+#if GROW_IF_NAVIGATE
+ if (!Single_Line_Field(field) && Field_Grown(field,1)) {
+ form->curcol = 0;
+ return(E_OK);
+ }
+#endif
+ form->currow--;
+#if GROW_IF_NAVIGATE
+ if (Single_Line_Field(field) && Field_Grown(field,1))
+ return(E_OK);
+#endif
+ form->curcol--;
+ return(E_REQUEST_DENIED);
+ }
+ form->curcol = 0;
+ }
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Previous_Character(FORM * form)
+|
+| Description : Move to the previous character in the field. In a
+| multiline field this wraps and the beginning of the
+| line.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - at the leftmost position
++--------------------------------------------------------------------------*/
+static int IFN_Previous_Character(FORM * form)
+{
+ if ((--(form->curcol))<0)
+ {
+ if ((--(form->currow))<0)
+ {
+ form->currow++;
+ form->curcol++;
+ return(E_REQUEST_DENIED);
+ }
+ form->curcol = form->current->dcols - 1;
+ }
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Next_Line(FORM * form)
+|
+| Description : Move to the beginning of the next line in the field
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - at the last line
++--------------------------------------------------------------------------*/
+static int IFN_Next_Line(FORM * form)
+{
+ FIELD *field = form->current;
+
+ if ((++(form->currow))==field->drows)
+ {
+#if GROW_IF_NAVIGATE
+ if (!Single_Line_Field(field) && Field_Grown(field,1))
+ return(E_OK);
+#endif
+ form->currow--;
+ return(E_REQUEST_DENIED);
+ }
+ form->curcol = 0;
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Previous_Line(FORM * form)
+|
+| Description : Move to the beginning of the previous line in the field
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - at the first line
++--------------------------------------------------------------------------*/
+static int IFN_Previous_Line(FORM * form)
+{
+ if ( (--(form->currow)) < 0 )
+ {
+ form->currow++;
+ return(E_REQUEST_DENIED);
+ }
+ form->curcol = 0;
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Next_Word(FORM * form)
+|
+| Description : Move to the beginning of the next word in the field.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - there is no next word
++--------------------------------------------------------------------------*/
+static int IFN_Next_Word(FORM * form)
+{
+ FIELD *field = form->current;
+ char *bp = Address_Of_Current_Position_In_Buffer(form);
+ char *s;
+ char *t;
+
+ /* We really need access to the data, so we have to synchronize */
+ Synchronize_Buffer(form);
+
+ /* Go to the first whitespace after the current position (including
+ current position). This is then the startpoint to look for the
+ next non-blank data */
+ s = Get_First_Whitespace_Character(bp,Buffer_Length(field) -
+ (int)(bp - field->buf));
+
+ /* Find the start of the next word */
+ t = Get_Start_Of_Data(s,Buffer_Length(field) -
+ (int)(s - field->buf));
+#if !FRIENDLY_PREV_NEXT_WORD
+ if (s==t)
+ return(E_REQUEST_DENIED);
+ else
+#endif
+ {
+ Adjust_Cursor_Position(form,t);
+ return(E_OK);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Previous_Word(FORM * form)
+|
+| Description : Move to the beginning of the previous word in the field.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - there is no previous word
++--------------------------------------------------------------------------*/
+static int IFN_Previous_Word(FORM * form)
+{
+ FIELD *field = form->current;
+ char *bp = Address_Of_Current_Position_In_Buffer(form);
+ char *s;
+ char *t;
+ bool again = FALSE;
+
+ /* We really need access to the data, so we have to synchronize */
+ Synchronize_Buffer(form);
+
+ s = After_End_Of_Data(field->buf,(int)(bp-field->buf));
+ /* s points now right after the last non-blank in the buffer before bp.
+ If bp was in a word, s equals bp. In this case we must find the last
+ whitespace in the buffer before bp and repeat the game to really find
+ the previous word! */
+ if (s==bp)
+ again = TRUE;
+
+ /* And next call now goes backward to look for the last whitespace
+ before that, pointing right after this, so it points to the begin
+ of the previous word.
+ */
+ t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
+#if !FRIENDLY_PREV_NEXT_WORD
+ if (s==t)
+ return(E_REQUEST_DENIED);
+#endif
+ if (again)
+ { /* and do it again, replacing bp by t */
+ s = After_End_Of_Data(field->buf,(int)(t - field->buf));
+ t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
+#if !FRIENDLY_PREV_NEXT_WORD
+ if (s==t)
+ return(E_REQUEST_DENIED);
+#endif
+ }
+ Adjust_Cursor_Position(form,t);
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Beginning_Of_Field(FORM * form)
+|
+| Description : Place the cursor at the first non-pad character in
+| the field.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int IFN_Beginning_Of_Field(FORM * form)
+{
+ FIELD *field = form->current;
+
+ Synchronize_Buffer(form);
+ Adjust_Cursor_Position(form,
+ Get_Start_Of_Data(field->buf,Buffer_Length(field)));
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_End_Of_Field(FORM * form)
+|
+| Description : Place the cursor after the last non-pad character in
+| the field. If the field occupies the last position in
+| the buffer, the cursos is positioned on the last
+| character.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int IFN_End_Of_Field(FORM * form)
+{
+ FIELD *field = form->current;
+ char *pos;
+
+ Synchronize_Buffer(form);
+ pos = After_End_Of_Data(field->buf,Buffer_Length(field));
+ if (pos==(field->buf + Buffer_Length(field)))
+ pos--;
+ Adjust_Cursor_Position(form,pos);
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Beginning_Of_Line(FORM * form)
+|
+| Description : Place the cursor on the first non-pad character in
+| the current line of the field.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int IFN_Beginning_Of_Line(FORM * form)
+{
+ FIELD *field = form->current;
+
+ Synchronize_Buffer(form);
+ Adjust_Cursor_Position(form,
+ Get_Start_Of_Data(Address_Of_Current_Row_In_Buffer(form),
+ field->dcols));
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_End_Of_Line(FORM * form)
+|
+| Description : Place the cursor after the last non-pad character in the
+| current line of the field. If the field occupies the
+| last column in the line, the cursor is positioned on the
+| last character of the line.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int IFN_End_Of_Line(FORM * form)
+{
+ FIELD *field = form->current;
+ char *pos;
+ char *bp;
+
+ Synchronize_Buffer(form);
+ bp = Address_Of_Current_Row_In_Buffer(form);
+ pos = After_End_Of_Data(bp,field->dcols);
+ if (pos == (bp + field->dcols))
+ pos--;
+ Adjust_Cursor_Position(form,pos);
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Left_Character(FORM * form)
+|
+| Description : Move one character to the left in the current line.
+| This doesn't cycle.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - already in first column
++--------------------------------------------------------------------------*/
+static int IFN_Left_Character(FORM * form)
+{
+ if ( (--(form->curcol)) < 0 )
+ {
+ form->curcol++;
+ return(E_REQUEST_DENIED);
+ }
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Right_Character(FORM * form)
+|
+| Description : Move one character to the right in the current line.
+| This doesn't cycle.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - already in last column
++--------------------------------------------------------------------------*/
+static int IFN_Right_Character(FORM * form)
+{
+ if ( (++(form->curcol)) == form->current->dcols )
+ {
+#if GROW_IF_NAVIGATE
+ FIELD *field = form->current;
+ if (Single_Line_Field(field) && Field_Grown(field,1))
+ return(E_OK);
+#endif
+ --(form->curcol);
+ return(E_REQUEST_DENIED);
+ }
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Up_Character(FORM * form)
+|
+| Description : Move one line up. This doesn't cycle through the lines
+| of the field.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - already in last column
++--------------------------------------------------------------------------*/
+static int IFN_Up_Character(FORM * form)
+{
+ if ( (--(form->currow)) < 0 )
+ {
+ form->currow++;
+ return(E_REQUEST_DENIED);
+ }
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Down_Character(FORM * form)
+|
+| Description : Move one line down. This doesn't cycle through the
+| lines of the field.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - already in last column
++--------------------------------------------------------------------------*/
+static int IFN_Down_Character(FORM * form)
+{
+ FIELD *field = form->current;
+
+ if ( (++(form->currow)) == field->drows )
+ {
+#if GROW_IF_NAVIGATE
+ if (!Single_Line_Field(field) && Field_Grown(field,1))
+ return(E_OK);
+#endif
+ --(form->currow);
+ return(E_REQUEST_DENIED);
+ }
+ return(E_OK);
+}
+/*----------------------------------------------------------------------------
+ END of Intra-Field Navigation routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Vertical scrolling helper routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Generic(FORM *form, int lines)
+|
+| Description : Scroll multi-line field forward (lines>0) or
+| backward (lines<0) this many lines.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - can't scroll
++--------------------------------------------------------------------------*/
+static int VSC_Generic(FORM *form, int lines)
+{
+ FIELD *field = form->current;
+ int res = E_REQUEST_DENIED;
+ int rows_to_go = (lines > 0 ? lines : -lines);
+
+ if (lines > 0)
+ {
+ if ( (rows_to_go + form->toprow) > (field->drows - field->rows) )
+ rows_to_go = (field->drows - field->rows - form->toprow);
+
+ if (rows_to_go > 0)
+ {
+ form->currow += rows_to_go;
+ form->toprow += rows_to_go;
+ res = E_OK;
+ }
+ }
+ else
+ {
+ if (rows_to_go > form->toprow)
+ rows_to_go = form->toprow;
+
+ if (rows_to_go > 0)
+ {
+ form->currow -= rows_to_go;
+ form->toprow -= rows_to_go;
+ res = E_OK;
+ }
+ }
+ return(res);
+}
+/*----------------------------------------------------------------------------
+ End of Vertical scrolling helper routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Vertical scrolling routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Vertical_Scrolling(
+| int (* const fct) (FORM *),
+| FORM * form)
+|
+| Description : Performs the generic vertical scrolling routines.
+| This has to check for a multi-line field and to set
+| the _NEWTOP flag if scrolling really occurred.
+|
+| Return Values : Propagated error code from low-level driver calls
++--------------------------------------------------------------------------*/
+static int Vertical_Scrolling(int (* const fct) (FORM *), FORM * form)
+{
+ int res = E_REQUEST_DENIED;
+
+ if (!Single_Line_Field(form->current))
+ {
+ res = fct(form);
+ if (res == E_OK)
+ form->current->status |= _NEWTOP;
+ }
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Scroll_Line_Forward(FORM * form)
+|
+| Description : Scroll multi-line field forward a line
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data ahead
++--------------------------------------------------------------------------*/
+static int VSC_Scroll_Line_Forward(FORM * form)
+{
+ return VSC_Generic(form,1);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Scroll_Line_Backward(FORM * form)
+|
+| Description : Scroll multi-line field backward a line
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data behind
++--------------------------------------------------------------------------*/
+static int VSC_Scroll_Line_Backward(FORM * form)
+{
+ return VSC_Generic(form,-1);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Scroll_Page_Forward(FORM * form)
+|
+| Description : Scroll a multi-line field forward a page
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data ahead
++--------------------------------------------------------------------------*/
+static int VSC_Scroll_Page_Forward(FORM * form)
+{
+ return VSC_Generic(form,form->current->rows);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Scroll_Half_Page_Forward(FORM * form)
+|
+| Description : Scroll a multi-line field forward half a page
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data ahead
++--------------------------------------------------------------------------*/
+static int VSC_Scroll_Half_Page_Forward(FORM * form)
+{
+ return VSC_Generic(form,(form->current->rows + 1)/2);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Scroll_Page_Backward(FORM * form)
+|
+| Description : Scroll a multi-line field backward a page
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data behind
++--------------------------------------------------------------------------*/
+static int VSC_Scroll_Page_Backward(FORM * form)
+{
+ return VSC_Generic(form, -(form->current->rows));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Scroll_Half_Page_Backward(FORM * form)
+|
+| Description : Scroll a multi-line field backward half a page
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data behind
++--------------------------------------------------------------------------*/
+static int VSC_Scroll_Half_Page_Backward(FORM * form)
+{
+ return VSC_Generic(form, -((form->current->rows + 1)/2));
+}
+/*----------------------------------------------------------------------------
+ End of Vertical scrolling routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Horizontal scrolling helper routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Generic(FORM *form, int columns)
+|
+| Description : Scroll single-line field forward (columns>0) or
+| backward (columns<0) this many columns.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - can't scroll
++--------------------------------------------------------------------------*/
+static int HSC_Generic(FORM *form, int columns)
+{
+ FIELD *field = form->current;
+ int res = E_REQUEST_DENIED;
+ int cols_to_go = (columns > 0 ? columns : -columns);
+
+ if (columns > 0)
+ {
+ if ((cols_to_go + form->begincol) > (field->dcols - field->cols))
+ cols_to_go = field->dcols - field->cols - form->begincol;
+
+ if (cols_to_go > 0)
+ {
+ form->curcol += cols_to_go;
+ form->begincol += cols_to_go;
+ res = E_OK;
+ }
+ }
+ else
+ {
+ if ( cols_to_go > form->begincol )
+ cols_to_go = form->begincol;
+
+ if (cols_to_go > 0)
+ {
+ form->curcol -= cols_to_go;
+ form->begincol -= cols_to_go;
+ res = E_OK;
+ }
+ }
+ return(res);
+}
+/*----------------------------------------------------------------------------
+ End of Horizontal scrolling helper routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Horizontal scrolling routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Horizontal_Scrolling(
+| int (* const fct) (FORM *),
+| FORM * form)
+|
+| Description : Performs the generic horizontal scrolling routines.
+| This has to check for a single-line field.
+|
+| Return Values : Propagated error code from low-level driver calls
++--------------------------------------------------------------------------*/
+static int Horizontal_Scrolling(int (* const fct) (FORM *), FORM * form)
+{
+ if (Single_Line_Field(form->current))
+ return fct(form);
+ else
+ return(E_REQUEST_DENIED);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Scroll_Char_Forward(FORM * form)
+|
+| Description : Scroll single-line field forward a character
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data ahead
++--------------------------------------------------------------------------*/
+static int HSC_Scroll_Char_Forward(FORM *form)
+{
+ return HSC_Generic(form,1);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Scroll_Char_Backward(FORM * form)
+|
+| Description : Scroll single-line field backward a character
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data behind
++--------------------------------------------------------------------------*/
+static int HSC_Scroll_Char_Backward(FORM *form)
+{
+ return HSC_Generic(form,-1);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Horizontal_Line_Forward(FORM* form)
+|
+| Description : Scroll single-line field forward a line
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data ahead
++--------------------------------------------------------------------------*/
+static int HSC_Horizontal_Line_Forward(FORM * form)
+{
+ return HSC_Generic(form,form->current->cols);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Horizontal_Half_Line_Forward(FORM* form)
+|
+| Description : Scroll single-line field forward half a line
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data ahead
++--------------------------------------------------------------------------*/
+static int HSC_Horizontal_Half_Line_Forward(FORM * form)
+{
+ return HSC_Generic(form,(form->current->cols + 1)/2);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Horizontal_Line_Backward(FORM* form)
+|
+| Description : Scroll single-line field backward a line
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data behind
++--------------------------------------------------------------------------*/
+static int HSC_Horizontal_Line_Backward(FORM * form)
+{
+ return HSC_Generic(form,-(form->current->cols));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Horizontal_Half_Line_Backward(FORM* form)
+|
+| Description : Scroll single-line field backward half a line
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data behind
++--------------------------------------------------------------------------*/
+static int HSC_Horizontal_Half_Line_Backward(FORM * form)
+{
+ return HSC_Generic(form,-((form->current->cols + 1)/2));
+}
+
+/*----------------------------------------------------------------------------
+ End of Horizontal scrolling routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Helper routines for Field Editing
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Is_There_Room_For_A_Line(FORM * form)
+|
+| Description : Check whether or not there is enough room in the
+| buffer to enter a whole line.
+|
+| Return Values : TRUE - there is enough space
+| FALSE - there is not enough space
++--------------------------------------------------------------------------*/
+INLINE static bool Is_There_Room_For_A_Line(FORM * form)
+{
+ FIELD *field = form->current;
+ char *begin_of_last_line, *s;
+
+ Synchronize_Buffer(form);
+ begin_of_last_line = Address_Of_Row_In_Buffer(field,(field->drows-1));
+ s = After_End_Of_Data(begin_of_last_line,field->dcols);
+ return ((s==begin_of_last_line) ? TRUE : FALSE);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
+|
+| Description : Checks whether or not there is room for a new character
+| in the current line.
+|
+| Return Values : TRUE - there is room
+| FALSE - there is not enough room (line full)
++--------------------------------------------------------------------------*/
+INLINE static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
+{
+ int last_char_in_line;
+
+ wmove(form->w,form->currow,form->current->dcols-1);
+ last_char_in_line = (int)(winch(form->w) & A_CHARTEXT);
+ wmove(form->w,form->currow,form->curcol);
+ return (((last_char_in_line == form->current->pad) ||
+ is_blank(last_char_in_line)) ? TRUE : FALSE);
+}
+
+#define There_Is_No_Room_For_A_Char_In_Line(f) \
+ !Is_There_Room_For_A_Char_In_Line(f)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Insert_String(
+| FORM * form,
+| int row,
+| char *txt,
+| int len )
+|
+| Description : Insert the 'len' characters beginning at pointer 'txt'
+| into the 'row' of the 'form'. The insertion occurs
+| on the beginning of the row, all other characters are
+| moved to the right. After the text a pad character will
+| be inserted to separate the text from the rest. If
+| necessary the insertion moves characters on the next
+| line to make place for the requested insertion string.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED -
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+static int Insert_String(FORM *form, int row, char *txt, int len)
+{
+ FIELD *field = form->current;
+ char *bp = Address_Of_Row_In_Buffer(field,row);
+ int datalen = (int)(After_End_Of_Data(bp,field->dcols) - bp);
+ int freelen = field->dcols - datalen;
+ int requiredlen = len+1;
+ char *split;
+ int result = E_REQUEST_DENIED;
+ char *Space;
+
+ Space = (char*)malloc(2*sizeof(char));
+ strcpy(Space, " ");
+
+ if (freelen >= requiredlen)
+ {
+ wmove(form->w,row,0);
+ winsnstr(form->w,txt,len);
+ wmove(form->w,row,len);
+ winsnstr(form->w,Space,1);
+ free(Space);
+ return E_OK;
+ }
+ else
+ { /* we have to move characters on the next line. If we are on the
+ last line this may work, if the field is growable */
+ if ((row == (field->drows - 1)) && Growable(field))
+ {
+ if (!Field_Grown(field,1))
+ {
+ free(Space);
+ return(E_SYSTEM_ERROR);
+ }
+ /* !!!Side-Effect : might be changed due to growth!!! */
+ bp = Address_Of_Row_In_Buffer(field,row);
+ }
+
+ if (row < (field->drows - 1))
+ {
+ split = After_Last_Whitespace_Character(bp,
+ (int)(Get_Start_Of_Data(bp + field->dcols - requiredlen ,
+ requiredlen) - bp));
+ /* split points now to the first character of the portion of the
+ line that must be moved to the next line */
+ datalen = (int)(split-bp); /* + freelen has to stay on this line */
+ freelen = field->dcols - (datalen + freelen); /* for the next line */
+
+ if ((result=Insert_String(form,row+1,split,freelen))==E_OK)
+ {
+ wmove(form->w,row,datalen);
+ wclrtoeol(form->w);
+ wmove(form->w,row,0);
+ winsnstr(form->w,txt,len);
+ wmove(form->w,row,len);
+ winsnstr(form->w,Space,1);
+ free(Space);
+ return E_OK;
+ }
+ }
+ free(Space);
+ return(result);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Wrapping_Not_Necessary_Or_Wrapping_Ok(
+| FORM * form)
+|
+| Description : If a character has been entered into a field, it may
+| be that wrapping has to occur. This routine checks
+| whether or not wrapping is required and if so, performs
+| the wrapping.
+|
+| Return Values : E_OK - no wrapping required or wrapping
+| was successful
+| E_REQUEST_DENIED -
+| E_SYSTEM_ERROR - some system error
++--------------------------------------------------------------------------*/
+static int Wrapping_Not_Necessary_Or_Wrapping_Ok(FORM * form)
+{
+ FIELD *field = form->current;
+ int result = E_REQUEST_DENIED;
+ bool Last_Row = ((field->drows - 1) == form->currow);
+
+ if ( (field->opts & O_WRAP) && /* wrapping wanted */
+ (!Single_Line_Field(field)) && /* must be multi-line */
+ (There_Is_No_Room_For_A_Char_In_Line(form)) && /* line is full */
+ (!Last_Row || Growable(field)) ) /* there are more lines*/
+ {
+ char *bp;
+ char *split;
+ int chars_to_be_wrapped;
+ int chars_to_remain_on_line;
+ if (Last_Row)
+ { /* the above logic already ensures, that in this case the field
+ is growable */
+ if (!Field_Grown(field,1))
+ return E_SYSTEM_ERROR;
+ }
+ bp = Address_Of_Current_Row_In_Buffer(form);
+ Window_To_Buffer(form->w,field);
+ split = After_Last_Whitespace_Character(bp,field->dcols);
+ /* split points to the first character of the sequence to be brought
+ on the next line */
+ chars_to_remain_on_line = (int)(split - bp);
+ chars_to_be_wrapped = field->dcols - chars_to_remain_on_line;
+ if (chars_to_remain_on_line > 0)
+ {
+ if ((result=Insert_String(form,form->currow+1,split,
+ chars_to_be_wrapped)) == E_OK)
+ {
+ wmove(form->w,form->currow,chars_to_remain_on_line);
+ wclrtoeol(form->w);
+ if (form->curcol >= chars_to_remain_on_line)
+ {
+ form->currow++;
+ form->curcol -= chars_to_remain_on_line;
+ }
+ return E_OK;
+ }
+ }
+ else
+ return E_OK;
+ if (result!=E_OK)
+ {
+ wmove(form->w,form->currow,form->curcol);
+ wdelch(form->w);
+ Window_To_Buffer(form->w,field);
+ result = E_REQUEST_DENIED;
+ }
+ }
+ else
+ result = E_OK; /* wrapping was not necessary */
+ return(result);
+}
+
+/*----------------------------------------------------------------------------
+ Field Editing routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Field_Editing(
+| int (* const fct) (FORM *),
+| FORM * form)
+|
+| Description : Generic routine for field editing requests. The driver
+| routines are only called for editable fields, the
+| _WINDOW_MODIFIED flag is set if editing occurred.
+| This is somewhat special due to the overload semantics
+| of the NEW_LINE and DEL_PREV requests.
+|
+| Return Values : Error code from low level drivers.
++--------------------------------------------------------------------------*/
+static int Field_Editing(int (* const fct) (FORM *), FORM * form)
+{
+ int res = E_REQUEST_DENIED;
+
+ /* We have to deal here with the specific case of the overloaded
+ behaviour of New_Line and Delete_Previous requests.
+ They may end up in navigational requests if we are on the first
+ character in a field. But navigation is also allowed on non-
+ editable fields.
+ */
+ if ((fct==FE_Delete_Previous) &&
+ (form->opts & O_BS_OVERLOAD) &&
+ First_Position_In_Current_Field(form) )
+ {
+ res = Inter_Field_Navigation(FN_Previous_Field,form);
+ }
+ else
+ {
+ if (fct==FE_New_Line)
+ {
+ if ((form->opts & O_NL_OVERLOAD) &&
+ First_Position_In_Current_Field(form))
+ {
+ res = Inter_Field_Navigation(FN_Next_Field,form);
+ }
+ else
+ /* FE_New_Line deals itself with the _WINDOW_MODIFIED flag */
+ res = fct(form);
+ }
+ else
+ {
+ /* From now on, everything must be editable */
+ if (form->current->opts & O_EDIT)
+ {
+ res = fct(form);
+ if (res==E_OK)
+ form->status |= _WINDOW_MODIFIED;
+ }
+ }
+ }
+ return res;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_New_Line(FORM * form)
+|
+| Description : Perform a new line request. This is rather complex
+| compared to other routines in this code due to the
+| rather difficult to understand description in the
+| manuals.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - new line not allowed
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+static int FE_New_Line(FORM * form)
+{
+ FIELD *field = form->current;
+ char *bp, *t;
+ bool Last_Row = ((field->drows - 1)==form->currow);
+
+ if (form->status & _OVLMODE)
+ {
+ if (Last_Row &&
+ (!(Growable(field) && !Single_Line_Field(field))))
+ {
+ if (!(form->opts & O_NL_OVERLOAD))
+ return(E_REQUEST_DENIED);
+ wclrtoeol(form->w);
+ /* we have to set this here, although it is also
+ handled in the generic routine. The reason is,
+ that FN_Next_Field may fail, but the form is
+ definitively changed */
+ form->status |= _WINDOW_MODIFIED;
+ return Inter_Field_Navigation(FN_Next_Field,form);
+ }
+ else
+ {
+ if (Last_Row && !Field_Grown(field,1))
+ { /* N.B.: due to the logic in the 'if', LastRow==TRUE
+ means here that the field is growable and not
+ a single-line field */
+ return(E_SYSTEM_ERROR);
+ }
+ wclrtoeol(form->w);
+ form->currow++;
+ form->curcol = 0;
+ form->status |= _WINDOW_MODIFIED;
+ return(E_OK);
+ }
+ }
+ else
+ { /* Insert Mode */
+ if (Last_Row &&
+ !(Growable(field) && !Single_Line_Field(field)))
+ {
+ if (!(form->opts & O_NL_OVERLOAD))
+ return(E_REQUEST_DENIED);
+ return Inter_Field_Navigation(FN_Next_Field,form);
+ }
+ else
+ {
+ bool May_Do_It = !Last_Row && Is_There_Room_For_A_Line(form);
+
+ if (!(May_Do_It || Growable(field)))
+ return(E_REQUEST_DENIED);
+ if (!May_Do_It && !Field_Grown(field,1))
+ return(E_SYSTEM_ERROR);
+
+ bp= Address_Of_Current_Position_In_Buffer(form);
+ t = After_End_Of_Data(bp,field->dcols - form->curcol);
+ wclrtoeol(form->w);
+ form->currow++;
+ form->curcol=0;
+ wmove(form->w,form->currow,form->curcol);
+ winsertln(form->w);
+ waddnstr(form->w,bp,(int)(t-bp));
+ form->status |= _WINDOW_MODIFIED;
+ return E_OK;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Insert_Character(FORM * form)
+|
+| Description : Insert blank character at the cursor position
+|
+| Return Values : E_OK
+| E_REQUEST_DENIED
++--------------------------------------------------------------------------*/
+static int FE_Insert_Character(FORM * form)
+{
+ FIELD *field = form->current;
+ int result = E_REQUEST_DENIED;
+
+ if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
+ {
+ bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
+
+ if (There_Is_Room ||
+ ((Single_Line_Field(field) && Growable(field))))
+ {
+ if (!There_Is_Room && !Field_Grown(field,1))
+ result = E_SYSTEM_ERROR;
+ else
+ {
+ winsch(form->w,(chtype)C_BLANK);
+ result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form);
+ }
+ }
+ }
+ return result;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Insert_Line(FORM * form)
+|
+| Description : Insert a blank line at the cursor position
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - line can not be inserted
++--------------------------------------------------------------------------*/
+static int FE_Insert_Line(FORM * form)
+{
+ FIELD *field = form->current;
+ int result = E_REQUEST_DENIED;
+
+ if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
+ {
+ bool Maybe_Done = (form->currow!=(field->drows-1)) &&
+ Is_There_Room_For_A_Line(form);
+
+ if (!Single_Line_Field(field) &&
+ (Maybe_Done || Growable(field)))
+ {
+ if (!Maybe_Done && !Field_Grown(field,1))
+ result = E_SYSTEM_ERROR;
+ else
+ {
+ form->curcol = 0;
+ winsertln(form->w);
+ result = E_OK;
+ }
+ }
+ }
+ return result;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Delete_Character(FORM * form)
+|
+| Description : Delete character at the cursor position
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int FE_Delete_Character(FORM * form)
+{
+ wdelch(form->w);
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Delete_Previous(FORM * form)
+|
+| Description : Delete character before cursor. Again this is a rather
+| difficult piece compared to others due to the overloading
+| semantics of backspace.
+| N.B.: The case of overloaded BS on first field position
+| is already handled in the generic routine.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - Character can't be deleted
++--------------------------------------------------------------------------*/
+static int FE_Delete_Previous(FORM * form)
+{
+ FIELD *field = form->current;
+
+ if (First_Position_In_Current_Field(form))
+ return E_REQUEST_DENIED;
+
+ if ( (--(form->curcol))<0 )
+ {
+ char *this_line, *prev_line, *prev_end, *this_end;
+
+ form->curcol++;
+ if (form->status & _OVLMODE)
+ return E_REQUEST_DENIED;
+
+ prev_line = Address_Of_Row_In_Buffer(field,(form->currow-1));
+ this_line = Address_Of_Row_In_Buffer(field,(form->currow));
+ Synchronize_Buffer(form);
+ prev_end = After_End_Of_Data(prev_line,field->dcols);
+ this_end = After_End_Of_Data(this_line,field->dcols);
+ if ((int)(this_end-this_line) >
+ (field->cols-(int)(prev_end-prev_line)))
+ return E_REQUEST_DENIED;
+ wdeleteln(form->w);
+ Adjust_Cursor_Position(form,prev_end);
+ wmove(form->w,form->currow,form->curcol);
+ waddnstr(form->w,this_line,(int)(this_end-this_line));
+ }
+ else
+ {
+ wmove(form->w,form->currow,form->curcol);
+ wdelch(form->w);
+ }
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Delete_Line(FORM * form)
+|
+| Description : Delete line at cursor position.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int FE_Delete_Line(FORM * form)
+{
+ form->curcol = 0;
+ wdeleteln(form->w);
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Delete_Word(FORM * form)
+|
+| Description : Delete word at cursor position
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - failure
++--------------------------------------------------------------------------*/
+static int FE_Delete_Word(FORM * form)
+{
+ FIELD *field = form->current;
+ char *bp = Address_Of_Current_Row_In_Buffer(form);
+ char *ep = bp + field->dcols;
+ char *cp = bp + form->curcol;
+ char *s;
+
+ Synchronize_Buffer(form);
+ if (is_blank(*cp))
+ return E_REQUEST_DENIED; /* not in word */
+
+ /* move cursor to begin of word and erase to end of screen-line */
+ Adjust_Cursor_Position(form,
+ After_Last_Whitespace_Character(bp,form->curcol));
+ wmove(form->w,form->currow,form->curcol);
+ wclrtoeol(form->w);
+
+ /* skip over word in buffer */
+ s = Get_First_Whitespace_Character(cp,(int)(ep-cp));
+ /* to begin of next word */
+ s = Get_Start_Of_Data(s,(int)(ep - s));
+ if ( (s!=cp) && !is_blank(*s))
+ {
+ /* copy remaining line to window */
+ waddnstr(form->w,s,(int)(s - After_End_Of_Data(s,(int)(ep - s))));
+ }
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Clear_To_End_Of_Line(FORM * form)
+|
+| Description : Clear to end of current line.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int FE_Clear_To_End_Of_Line(FORM * form)
+{
+ wclrtoeol(form->w);
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Clear_To_End_Of_Form(FORM * form)
+|
+| Description : Clear to end of form.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int FE_Clear_To_End_Of_Form(FORM * form)
+{
+ wclrtobot(form->w);
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Clear_Field(FORM * form)
+|
+| Description : Clear entire field.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int FE_Clear_Field(FORM * form)
+{
+ form->currow = form->curcol = 0;
+ werase(form->w);
+ return E_OK;
+}
+/*----------------------------------------------------------------------------
+ END of Field Editing routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Edit Mode routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int EM_Overlay_Mode(FORM * form)
+|
+| Description : Switch to overlay mode.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int EM_Overlay_Mode(FORM * form)
+{
+ form->status |= _OVLMODE;
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int EM_Insert_Mode(FORM * form)
+|
+| Description : Switch to insert mode
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int EM_Insert_Mode(FORM * form)
+{
+ form->status &= ~_OVLMODE;
+ return E_OK;
+}
+
+/*----------------------------------------------------------------------------
+ END of Edit Mode routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Helper routines for Choice Requests
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Next_Choice(
+| FIELDTYPE * typ,
+| FIELD * field,
+| TypeArgument *argp)
+|
+| Description : Get the next field choice. For linked types this is
+| done recursively.
+|
+| Return Values : TRUE - next choice successfully retrieved
+| FALSE - couldn't retrieve next choice
++--------------------------------------------------------------------------*/
+static bool Next_Choice(FIELDTYPE * typ, FIELD *field, TypeArgument *argp)
+{
+ if (!typ || !(typ->status & _HAS_CHOICE))
+ return FALSE;
+
+ if (typ->status & _LINKED_TYPE)
+ {
+ assert(argp != 0);
+ return(
+ Next_Choice(typ->left ,field,argp->left) ||
+ Next_Choice(typ->right,field,argp->right) );
+ }
+ else
+ {
+ assert(typ->next != 0);
+ return typ->next(field,(void *)argp);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Previous_Choice(
+| FIELDTYPE * typ,
+| FIELD * field,
+| TypeArgument *argp)
+|
+| Description : Get the previous field choice. For linked types this
+| is done recursively.
+|
+| Return Values : TRUE - previous choice successfully retrieved
+| FALSE - couldn't retrieve previous choice
++--------------------------------------------------------------------------*/
+static bool Previous_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
+{
+ if (!typ || !(typ->status & _HAS_CHOICE))
+ return FALSE;
+
+ if (typ->status & _LINKED_TYPE)
+ {
+ assert(argp != 0);
+ return(
+ Previous_Choice(typ->left ,field,argp->left) ||
+ Previous_Choice(typ->right,field,argp->right));
+ }
+ else
+ {
+ assert(typ->prev != 0);
+ return typ->prev(field,(void *)argp);
+ }
+}
+/*----------------------------------------------------------------------------
+ End of Helper routines for Choice Requests
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Routines for Choice Requests
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int CR_Next_Choice(FORM * form)
+|
+| Description : Get the next field choice.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - next choice couldn't be retrieved
++--------------------------------------------------------------------------*/
+static int CR_Next_Choice(FORM * form)
+{
+ FIELD *field = form->current;
+ Synchronize_Buffer(form);
+ return ((Next_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
+ E_OK : E_REQUEST_DENIED);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int CR_Previous_Choice(FORM * form)
+|
+| Description : Get the previous field choice.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - prev. choice couldn't be retrieved
++--------------------------------------------------------------------------*/
+static int CR_Previous_Choice(FORM * form)
+{
+ FIELD *field = form->current;
+ Synchronize_Buffer(form);
+ return ((Previous_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
+ E_OK : E_REQUEST_DENIED);
+}
+/*----------------------------------------------------------------------------
+ End of Routines for Choice Requests
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Helper routines for Field Validations.
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Field(
+| FIELDTYPE * typ,
+| FIELD * field,
+| TypeArgument * argp)
+|
+| Description : Check the field according to its fieldtype and its
+| actual arguments. For linked fieldtypes this is done
+| recursively.
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid.
++--------------------------------------------------------------------------*/
+static bool Check_Field(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
+{
+ if (typ)
+ {
+ if (field->opts & O_NULLOK)
+ {
+ char *bp = field->buf;
+ assert(bp != 0);
+ while(is_blank(*bp))
+ { bp++; }
+ if (*bp == '\0')
+ return TRUE;
+ }
+
+ if (typ->status & _LINKED_TYPE)
+ {
+ assert(argp != 0);
+ return(
+ Check_Field(typ->left ,field,argp->left ) ||
+ Check_Field(typ->right,field,argp->right) );
+ }
+ else
+ {
+ if (typ->fcheck)
+ return typ->fcheck(field,(void *)argp);
+ }
+ }
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : bool _nc_Internal_Validation(FORM * form )
+|
+| Description : Validate the current field of the form.
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+bool
+_nc_Internal_Validation(FORM *form)
+{
+ FIELD *field;
+
+ field = form->current;
+
+ Synchronize_Buffer(form);
+ if ((form->status & _FCHECK_REQUIRED) ||
+ (!(field->opts & O_PASSOK)))
+ {
+ if (!Check_Field(field->type,field,(TypeArgument *)(field->arg)))
+ return FALSE;
+ form->status &= ~_FCHECK_REQUIRED;
+ field->status |= _CHANGED;
+ Synchronize_Linked_Fields(field);
+ }
+ return TRUE;
+}
+/*----------------------------------------------------------------------------
+ End of Helper routines for Field Validations.
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Routines for Field Validation.
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FV_Validation(FORM * form)
+|
+| Description : Validate the current field of the form.
+|
+| Return Values : E_OK - field valid
+| E_INVALID_FIELD - field not valid
++--------------------------------------------------------------------------*/
+static int FV_Validation(FORM * form)
+{
+ if (_nc_Internal_Validation(form))
+ return E_OK;
+ else
+ return E_INVALID_FIELD;
+}
+/*----------------------------------------------------------------------------
+ End of routines for Field Validation.
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Helper routines for Inter-Field Navigation
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Next_Field_On_Page(FIELD * field)
+|
+| Description : Get the next field after the given field on the current
+| page. The order of fields is the one defined by the
+| fields array. Only visible and active fields are
+| counted.
+|
+| Return Values : Pointer to the next field.
++--------------------------------------------------------------------------*/
+INLINE static FIELD *Next_Field_On_Page(FIELD * field)
+{
+ FORM *form = field->form;
+ FIELD **field_on_page = &form->field[field->index];
+ FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
+ FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
+
+ do
+ {
+ field_on_page =
+ (field_on_page==last_on_page) ? first_on_page : field_on_page + 1;
+ if (Field_Is_Selectable(*field_on_page))
+ break;
+ } while(field!=(*field_on_page));
+ return(*field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELD* _nc_First_Active_Field(FORM * form)
+|
+| Description : Get the first active field on the current page,
+| if there are such. If there are none, get the first
+| visible field on the page. If there are also none,
+| we return the first field on page and hope the best.
+|
+| Return Values : Pointer to calculated field.
++--------------------------------------------------------------------------*/
+FIELD*
+_nc_First_Active_Field(FORM * form)
+{
+ FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
+ FIELD *proposed = Next_Field_On_Page(*last_on_page);
+
+ if (proposed == *last_on_page)
+ { /* there might be the special situation, where there is no
+ active and visible field on the current page. We then select
+ the first visible field on this readonly page
+ */
+ if (Field_Is_Not_Selectable(proposed))
+ {
+ FIELD **field = &form->field[proposed->index];
+ FIELD **first = &form->field[form->page[form->curpage].pmin];
+
+ do
+ {
+ field = (field==last_on_page) ? first : field + 1;
+ if (((*field)->opts & O_VISIBLE))
+ break;
+ } while(proposed!=(*field));
+
+ proposed = *field;
+
+ if ((proposed == *last_on_page) && !(proposed->opts&O_VISIBLE))
+ { /* This means, there is also no visible field on the page.
+ So we propose the first one and hope the very best...
+ Some very clever user has designed a readonly and invisible
+ page on this form.
+ */
+ proposed = *first;
+ }
+ }
+ }
+ return(proposed);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Previous_Field_On_Page(FIELD * field)
+|
+| Description : Get the previous field before the given field on the
+| current page. The order of fields is the one defined by
+| the fields array. Only visible and active fields are
+| counted.
+|
+| Return Values : Pointer to the previous field.
++--------------------------------------------------------------------------*/
+INLINE static FIELD *Previous_Field_On_Page(FIELD * field)
+{
+ FORM *form = field->form;
+ FIELD **field_on_page = &form->field[field->index];
+ FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
+ FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
+
+ do
+ {
+ field_on_page =
+ (field_on_page==first_on_page) ? last_on_page : field_on_page - 1;
+ if (Field_Is_Selectable(*field_on_page))
+ break;
+ } while(field!=(*field_on_page));
+
+ return (*field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Sorted_Next_Field(FIELD * field)
+|
+| Description : Get the next field after the given field on the current
+| page. The order of fields is the one defined by the
+| (row,column) geometry, rows are major.
+|
+| Return Values : Pointer to the next field.
++--------------------------------------------------------------------------*/
+INLINE static FIELD *Sorted_Next_Field(FIELD * field)
+{
+ FIELD *field_on_page = field;
+
+ do
+ {
+ field_on_page = field_on_page->snext;
+ if (Field_Is_Selectable(field_on_page))
+ break;
+ } while(field_on_page!=field);
+
+ return (field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Sorted_Previous_Field(FIELD * field)
+|
+| Description : Get the previous field before the given field on the
+| current page. The order of fields is the one defined
+| by the (row,column) geometry, rows are major.
+|
+| Return Values : Pointer to the previous field.
++--------------------------------------------------------------------------*/
+INLINE static FIELD *Sorted_Previous_Field(FIELD * field)
+{
+ FIELD *field_on_page = field;
+
+ do
+ {
+ field_on_page = field_on_page->sprev;
+ if (Field_Is_Selectable(field_on_page))
+ break;
+ } while(field_on_page!=field);
+
+ return (field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Left_Neighbour_Field(FIELD * field)
+|
+| Description : Get the left neighbour of the field on the same line
+| and the same page. Cycles through the line.
+|
+| Return Values : Pointer to left neighbour field.
++--------------------------------------------------------------------------*/
+INLINE static FIELD *Left_Neighbour_Field(FIELD * field)
+{
+ FIELD *field_on_page = field;
+
+ /* For a field that has really a left neighbour, the while clause
+ immediately fails and the loop is left, positioned at the right
+ neighbour. Otherwise we cycle backwards through the sorted fieldlist
+ until we enter the same line (from the right end).
+ */
+ do
+ {
+ field_on_page = Sorted_Previous_Field(field_on_page);
+ } while(field_on_page->frow != field->frow);
+
+ return (field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Right_Neighbour_Field(FIELD * field)
+|
+| Description : Get the right neighbour of the field on the same line
+| and the same page.
+|
+| Return Values : Pointer to right neighbour field.
++--------------------------------------------------------------------------*/
+INLINE static FIELD *Right_Neighbour_Field(FIELD * field)
+{
+ FIELD *field_on_page = field;
+
+ /* See the comments on Left_Neighbour_Field to understand how it works */
+ do
+ {
+ field_on_page = Sorted_Next_Field(field_on_page);
+ } while(field_on_page->frow != field->frow);
+
+ return (field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Upper_Neighbour_Field(FIELD * field)
+|
+| Description : Because of the row-major nature of sorting the fields,
+| its more difficult to define whats the upper neighbour
+| field really means. We define that it must be on a
+| 'previous' line (cyclic order!) and is the rightmost
+| field laying on the left side of the given field. If
+| this set is empty, we take the first field on the line.
+|
+| Return Values : Pointer to the upper neighbour field.
++--------------------------------------------------------------------------*/
+static FIELD *Upper_Neighbour_Field(FIELD * field)
+{
+ FIELD *field_on_page = field;
+ int frow = field->frow;
+ int fcol = field->fcol;
+
+ /* Walk back to the 'previous' line. The second term in the while clause
+ just guarantees that we stop if we cycled through the line because
+ there might be no 'previous' line if the page has just one line.
+ */
+ do
+ {
+ field_on_page = Sorted_Previous_Field(field_on_page);
+ } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
+
+ if (field_on_page->frow!=frow)
+ { /* We really found a 'previous' line. We are positioned at the
+ rightmost field on this line */
+ frow = field_on_page->frow;
+
+ /* We walk to the left as long as we are really right of the
+ field. */
+ while(field_on_page->frow==frow && field_on_page->fcol>fcol)
+ field_on_page = Sorted_Previous_Field(field_on_page);
+
+ /* If we wrapped, just go to the right which is the first field on
+ the row */
+ if (field_on_page->frow!=frow)
+ field_on_page = Sorted_Next_Field(field_on_page);
+ }
+
+ return (field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Down_Neighbour_Field(FIELD * field)
+|
+| Description : Because of the row-major nature of sorting the fields,
+| its more difficult to define whats the down neighbour
+| field really means. We define that it must be on a
+| 'next' line (cyclic order!) and is the leftmost
+| field laying on the right side of the given field. If
+| this set is empty, we take the last field on the line.
+|
+| Return Values : Pointer to the upper neighbour field.
++--------------------------------------------------------------------------*/
+static FIELD *Down_Neighbour_Field(FIELD * field)
+{
+ FIELD *field_on_page = field;
+ int frow = field->frow;
+ int fcol = field->fcol;
+
+ /* Walk forward to the 'next' line. The second term in the while clause
+ just guarantees that we stop if we cycled through the line because
+ there might be no 'next' line if the page has just one line.
+ */
+ do
+ {
+ field_on_page = Sorted_Next_Field(field_on_page);
+ } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
+
+ if (field_on_page->frow!=frow)
+ { /* We really found a 'next' line. We are positioned at the rightmost
+ field on this line */
+ frow = field_on_page->frow;
+
+ /* We walk to the right as long as we are really left of the
+ field. */
+ while(field_on_page->frow==frow && field_on_page->fcol<fcol)
+ field_on_page = Sorted_Next_Field(field_on_page);
+
+ /* If we wrapped, just go to the left which is the last field on
+ the row */
+ if (field_on_page->frow!=frow)
+ field_on_page = Sorted_Previous_Field(field_on_page);
+ }
+
+ return(field_on_page);
+}
+
+/*----------------------------------------------------------------------------
+ Inter-Field Navigation routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Inter_Field_Navigation(
+| int (* const fct) (FORM *),
+| FORM * form)
+|
+| Description : Generic behaviour for changing the current field, the
+| field is left and a new field is entered. So the field
+| must be validated and the field init/term hooks must
+| be called.
+|
+| Return Values : E_OK - success
+| E_INVALID_FIELD - field is invalid
+| some other - error from subordinate call
++--------------------------------------------------------------------------*/
+static int Inter_Field_Navigation(int (* const fct) (FORM *),FORM *form)
+{
+ int res;
+
+ if (!_nc_Internal_Validation(form))
+ res = E_INVALID_FIELD;
+ else
+ {
+ Call_Hook(form,fieldterm);
+ res = fct(form);
+ Call_Hook(form,fieldinit);
+ }
+ return res;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Next_Field(FORM * form)
+|
+| Description : Move to the next field on the current page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Next_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Next_Field_On_Page(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Previous_Field(FORM * form)
+|
+| Description : Move to the previous field on the current page of the
+| form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Previous_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Previous_Field_On_Page(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_First_Field(FORM * form)
+|
+| Description : Move to the first field on the current page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_First_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Next_Field_On_Page(form->field[form->page[form->curpage].pmax]));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Last_Field(FORM * form)
+|
+| Description : Move to the last field on the current page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Last_Field(FORM * form)
+{
+ return
+ _nc_Set_Current_Field(form,
+ Previous_Field_On_Page(form->field[form->page[form->curpage].pmin]));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Sorted_Next_Field(FORM * form)
+|
+| Description : Move to the sorted next field on the current page
+| of the form.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Sorted_Next_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Sorted_Next_Field(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Sorted_Previous_Field(FORM * form)
+|
+| Description : Move to the sorted previous field on the current page
+| of the form.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Sorted_Previous_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Sorted_Previous_Field(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Sorted_First_Field(FORM * form)
+|
+| Description : Move to the sorted first field on the current page
+| of the form.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Sorted_First_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Sorted_Next_Field(form->field[form->page[form->curpage].smax]));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Sorted_Last_Field(FORM * form)
+|
+| Description : Move to the sorted last field on the current page
+| of the form.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Sorted_Last_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Sorted_Previous_Field(form->field[form->page[form->curpage].smin]));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Left_Field(FORM * form)
+|
+| Description : Get the field on the left of the current field on the
+| same line and the same page. Cycles through the line.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Left_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Left_Neighbour_Field(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Right_Field(FORM * form)
+|
+| Description : Get the field on the right of the current field on the
+| same line and the same page. Cycles through the line.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Right_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Right_Neighbour_Field(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Up_Field(FORM * form)
+|
+| Description : Get the upper neighbour of the current field. This
+| cycles through the page. See the comments of the
+| Upper_Neighbour_Field function to understand how
+| 'upper' is defined.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Up_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Upper_Neighbour_Field(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Down_Field(FORM * form)
+|
+| Description : Get the down neighbour of the current field. This
+| cycles through the page. See the comments of the
+| Down_Neighbour_Field function to understand how
+| 'down' is defined.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Down_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Down_Neighbour_Field(form->current));
+}
+/*----------------------------------------------------------------------------
+ END of Field Navigation routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Helper routines for Page Navigation
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int _nc_Set_Form_Page(FORM * form,
+| int page,
+| FIELD * field)
+|
+| Description : Make the given page nr. the current page and make
+| the given field the current field on the page. If
+| for the field NULL is given, make the first field on
+| the page the current field. The routine acts only
+| if the requested page is not the current page.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+int
+_nc_Set_Form_Page(FORM * form, int page, FIELD * field)
+{
+ int res = E_OK;
+
+ if ((form->curpage!=page))
+ {
+ FIELD *last_field, *field_on_page;
+
+ werase(Get_Form_Window(form));
+ form->curpage = page;
+ last_field = field_on_page = form->field[form->page[page].smin];
+ do
+ {
+ if (field_on_page->opts & O_VISIBLE)
+ if ((res=Display_Field(field_on_page))!=E_OK)
+ return(res);
+ field_on_page = field_on_page->snext;
+ } while(field_on_page != last_field);
+
+ if (field)
+ res = _nc_Set_Current_Field(form,field);
+ else
+ /* N.B.: we don't encapsulate this by Inter_Field_Navigation(),
+ because this is already executed in a page navigation
+ context that contains field navigation
+ */
+ res = FN_First_Field(form);
+ }
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Next_Page_Number(const FORM * form)
+|
+| Description : Calculate the page number following the current page
+| number. This cycles if the highest page number is
+| reached.
+|
+| Return Values : The next page number
++--------------------------------------------------------------------------*/
+INLINE static int Next_Page_Number(const FORM * form)
+{
+ return (form->curpage + 1) % form->maxpage;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Previous_Page_Number(const FORM * form)
+|
+| Description : Calculate the page number before the current page
+| number. This cycles if the first page number is
+| reached.
+|
+| Return Values : The previous page number
++--------------------------------------------------------------------------*/
+INLINE static int Previous_Page_Number(const FORM * form)
+{
+ return (form->curpage!=0 ? form->curpage - 1 : form->maxpage - 1);
+}
+
+/*----------------------------------------------------------------------------
+ Page Navigation routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Page_Navigation(
+| int (* const fct) (FORM *),
+| FORM * form)
+|
+| Description : Generic behaviour for changing a page. This means
+| that the field is left and a new field is entered.
+| So the field must be validated and the field init/term
+| hooks must be called. Because also the page is changed,
+| the forms init/term hooks must be called also.
+|
+| Return Values : E_OK - success
+| E_INVALID_FIELD - field is invalid
+| some other - error from subordinate call
++--------------------------------------------------------------------------*/
+static int Page_Navigation(int (* const fct) (FORM *), FORM * form)
+{
+ int res;
+
+ if (!_nc_Internal_Validation(form))
+ res = E_INVALID_FIELD;
+ else
+ {
+ Call_Hook(form,fieldterm);
+ Call_Hook(form,formterm);
+ res = fct(form);
+ Call_Hook(form,forminit);
+ Call_Hook(form,fieldinit);
+ }
+ return res;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int PN_Next_Page(FORM * form)
+|
+| Description : Move to the next page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int PN_Next_Page(FORM * form)
+{
+ return _nc_Set_Form_Page(form,Next_Page_Number(form),(FIELD *)0);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int PN_Previous_Page(FORM * form)
+|
+| Description : Move to the previous page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int PN_Previous_Page(FORM * form)
+{
+ return _nc_Set_Form_Page(form,Previous_Page_Number(form),(FIELD *)0);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int PN_First_Page(FORM * form)
+|
+| Description : Move to the first page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int PN_First_Page(FORM * form)
+{
+ return _nc_Set_Form_Page(form,0,(FIELD *)0);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int PN_Last_Page(FORM * form)
+|
+| Description : Move to the last page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int PN_Last_Page(FORM * form)
+{
+ return _nc_Set_Form_Page(form,form->maxpage-1,(FIELD *)0);
+}
+/*----------------------------------------------------------------------------
+ END of Field Navigation routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Helper routines for the core form driver.
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Data_Entry(FORM * form,int c)
+|
+| Description : Enter character c into at the current position of the
+| current field of the form.
+|
+| Return Values : E_OK -
+| E_REQUEST_DENIED -
+| E_SYSTEM_ERROR -
++--------------------------------------------------------------------------*/
+static int Data_Entry(FORM * form, int c)
+{
+ FIELD *field = form->current;
+ int result = E_REQUEST_DENIED;
+
+ if ( (field->opts & O_EDIT)
+#if FIX_FORM_INACTIVE_BUG
+ && (field->opts & O_ACTIVE)
+#endif
+ )
+ {
+ if ( (field->opts & O_BLANK) &&
+ First_Position_In_Current_Field(form) &&
+ !(form->status & _FCHECK_REQUIRED) &&
+ !(form->status & _WINDOW_MODIFIED) )
+ werase(form->w);
+
+ if (form->status & _OVLMODE)
+ {
+ waddch(form->w,(chtype)c);
+ }
+ else /* no _OVLMODE */
+ {
+ bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
+
+ if (!(There_Is_Room ||
+ ((Single_Line_Field(field) && Growable(field)))))
+ return E_REQUEST_DENIED;
+
+ if (!There_Is_Room && !Field_Grown(field,1))
+ return E_SYSTEM_ERROR;
+
+ winsch(form->w,(chtype)c);
+ }
+
+ if ((result=Wrapping_Not_Necessary_Or_Wrapping_Ok(form))==E_OK)
+ {
+ bool End_Of_Field= (((field->drows-1)==form->currow) &&
+ ((field->dcols-1)==form->curcol));
+ form->status |= _WINDOW_MODIFIED;
+ if (End_Of_Field && !Growable(field) && (field->opts & O_AUTOSKIP))
+ result = Inter_Field_Navigation(FN_Next_Field,form);
+ else
+ {
+ if (End_Of_Field && Growable(field) && !Field_Grown(field,1))
+ result = E_SYSTEM_ERROR;
+ else
+ {
+ IFN_Next_Character(form);
+ result = E_OK;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/* Structure to describe the binding of a request code to a function.
+ The member keycode codes the request value as well as the generic
+ routine to use for the request. The code for the generic routine
+ is coded in the upper 16 Bits while the request code is coded in
+ the lower 16 bits.
+
+ In terms of C++ you might think of a request as a class with a
+ virtual method "perform". The different types of request are
+ derived from this base class and overload (or not) the base class
+ implementation of perform.
+*/
+typedef struct {
+ int keycode; /* must be at least 32 bit: hi:mode, lo: key */
+ int (*cmd)(FORM *); /* low level driver routine for this key */
+} Binding_Info;
+
+/* You may see this is the class-id of the request type class */
+#define ID_PN (0x00000000) /* Page navigation */
+#define ID_FN (0x00010000) /* Inter-Field navigation */
+#define ID_IFN (0x00020000) /* Intra-Field navigation */
+#define ID_VSC (0x00030000) /* Vertical Scrolling */
+#define ID_HSC (0x00040000) /* Horizontal Scrolling */
+#define ID_FE (0x00050000) /* Field Editing */
+#define ID_EM (0x00060000) /* Edit Mode */
+#define ID_FV (0x00070000) /* Field Validation */
+#define ID_CH (0x00080000) /* Choice */
+#define ID_Mask (0xffff0000)
+#define Key_Mask (0x0000ffff)
+#define ID_Shft (16)
+
+/* This array holds all the Binding Infos */
+static const Binding_Info bindings[MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1] =
+{
+ { REQ_NEXT_PAGE |ID_PN ,PN_Next_Page},
+ { REQ_PREV_PAGE |ID_PN ,PN_Previous_Page},
+ { REQ_FIRST_PAGE |ID_PN ,PN_First_Page},
+ { REQ_LAST_PAGE |ID_PN ,PN_Last_Page},
+
+ { REQ_NEXT_FIELD |ID_FN ,FN_Next_Field},
+ { REQ_PREV_FIELD |ID_FN ,FN_Previous_Field},
+ { REQ_FIRST_FIELD |ID_FN ,FN_First_Field},
+ { REQ_LAST_FIELD |ID_FN ,FN_Last_Field},
+ { REQ_SNEXT_FIELD |ID_FN ,FN_Sorted_Next_Field},
+ { REQ_SPREV_FIELD |ID_FN ,FN_Sorted_Previous_Field},
+ { REQ_SFIRST_FIELD |ID_FN ,FN_Sorted_First_Field},
+ { REQ_SLAST_FIELD |ID_FN ,FN_Sorted_Last_Field},
+ { REQ_LEFT_FIELD |ID_FN ,FN_Left_Field},
+ { REQ_RIGHT_FIELD |ID_FN ,FN_Right_Field},
+ { REQ_UP_FIELD |ID_FN ,FN_Up_Field},
+ { REQ_DOWN_FIELD |ID_FN ,FN_Down_Field},
+
+ { REQ_NEXT_CHAR |ID_IFN ,IFN_Next_Character},
+ { REQ_PREV_CHAR |ID_IFN ,IFN_Previous_Character},
+ { REQ_NEXT_LINE |ID_IFN ,IFN_Next_Line},
+ { REQ_PREV_LINE |ID_IFN ,IFN_Previous_Line},
+ { REQ_NEXT_WORD |ID_IFN ,IFN_Next_Word},
+ { REQ_PREV_WORD |ID_IFN ,IFN_Previous_Word},
+ { REQ_BEG_FIELD |ID_IFN ,IFN_Beginning_Of_Field},
+ { REQ_END_FIELD |ID_IFN ,IFN_End_Of_Field},
+ { REQ_BEG_LINE |ID_IFN ,IFN_Beginning_Of_Line},
+ { REQ_END_LINE |ID_IFN ,IFN_End_Of_Line},
+ { REQ_LEFT_CHAR |ID_IFN ,IFN_Left_Character},
+ { REQ_RIGHT_CHAR |ID_IFN ,IFN_Right_Character},
+ { REQ_UP_CHAR |ID_IFN ,IFN_Up_Character},
+ { REQ_DOWN_CHAR |ID_IFN ,IFN_Down_Character},
+
+ { REQ_NEW_LINE |ID_FE ,FE_New_Line},
+ { REQ_INS_CHAR |ID_FE ,FE_Insert_Character},
+ { REQ_INS_LINE |ID_FE ,FE_Insert_Line},
+ { REQ_DEL_CHAR |ID_FE ,FE_Delete_Character},
+ { REQ_DEL_PREV |ID_FE ,FE_Delete_Previous},
+ { REQ_DEL_LINE |ID_FE ,FE_Delete_Line},
+ { REQ_DEL_WORD |ID_FE ,FE_Delete_Word},
+ { REQ_CLR_EOL |ID_FE ,FE_Clear_To_End_Of_Line},
+ { REQ_CLR_EOF |ID_FE ,FE_Clear_To_End_Of_Form},
+ { REQ_CLR_FIELD |ID_FE ,FE_Clear_Field},
+
+ { REQ_OVL_MODE |ID_EM ,EM_Overlay_Mode},
+ { REQ_INS_MODE |ID_EM ,EM_Insert_Mode},
+
+ { REQ_SCR_FLINE |ID_VSC ,VSC_Scroll_Line_Forward},
+ { REQ_SCR_BLINE |ID_VSC ,VSC_Scroll_Line_Backward},
+ { REQ_SCR_FPAGE |ID_VSC ,VSC_Scroll_Page_Forward},
+ { REQ_SCR_BPAGE |ID_VSC ,VSC_Scroll_Page_Backward},
+ { REQ_SCR_FHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Forward},
+ { REQ_SCR_BHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Backward},
+
+ { REQ_SCR_FCHAR |ID_HSC ,HSC_Scroll_Char_Forward},
+ { REQ_SCR_BCHAR |ID_HSC ,HSC_Scroll_Char_Backward},
+ { REQ_SCR_HFLINE |ID_HSC ,HSC_Horizontal_Line_Forward},
+ { REQ_SCR_HBLINE |ID_HSC ,HSC_Horizontal_Line_Backward},
+ { REQ_SCR_HFHALF |ID_HSC ,HSC_Horizontal_Half_Line_Forward},
+ { REQ_SCR_HBHALF |ID_HSC ,HSC_Horizontal_Half_Line_Backward},
+
+ { REQ_VALIDATION |ID_FV ,FV_Validation},
+
+ { REQ_NEXT_CHOICE |ID_CH ,CR_Next_Choice},
+ { REQ_PREV_CHOICE |ID_CH ,CR_Previous_Choice}
+};
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int form_driver(FORM * form,int c)
+|
+| Description : This is the workhorse of the forms system. It checks
+| to determine whether the character c is a request or
+| data. If it is a request, the form driver executes
+| the request and returns the result. If it is data
+| (printable character), it enters the data into the
+| current position in the current field. If it is not
+| recognized, the form driver assumes it is an application
+| defined command and returns E_UNKNOWN_COMMAND.
+| Application defined command should be defined relative
+| to MAX_FORM_COMMAND, the maximum value of a request.
+|
+| Return Values : E_OK - success
+| E_SYSTEM_ERROR - system error
+| E_BAD_ARGUMENT - an argument is incorrect
+| E_NOT_POSTED - form is not posted
+| E_INVALID_FIELD - field contents are invalid
+| E_BAD_STATE - called from inside a hook routine
+| E_REQUEST_DENIED - request failed
+| E_UNKNOWN_COMMAND - command not known
++--------------------------------------------------------------------------*/
+int form_driver(FORM * form, int c)
+{
+ const Binding_Info* BI = (Binding_Info *)0;
+ int res = E_UNKNOWN_COMMAND;
+
+ if (!form)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (!(form->field))
+ RETURN(E_NOT_CONNECTED);
+
+ assert(form->page != 0);
+
+ if (c==FIRST_ACTIVE_MAGIC)
+ {
+ form->current = _nc_First_Active_Field(form);
+ return E_OK;
+ }
+
+ assert(form->current &&
+ form->current->buf &&
+ (form->current->form == form)
+ );
+
+ if ( form->status & _IN_DRIVER )
+ RETURN(E_BAD_STATE);
+
+ if ( !( form->status & _POSTED ) )
+ RETURN(E_NOT_POSTED);
+
+ if ((c>=MIN_FORM_COMMAND && c<=MAX_FORM_COMMAND) &&
+ ((bindings[c-MIN_FORM_COMMAND].keycode & Key_Mask) == c))
+ BI = &(bindings[c-MIN_FORM_COMMAND]);
+
+ if (BI)
+ {
+ typedef int (*Generic_Method)(int (* const)(FORM *),FORM *);
+ static const Generic_Method Generic_Methods[] =
+ {
+ Page_Navigation, /* overloaded to call field&form hooks */
+ Inter_Field_Navigation, /* overloaded to call field hooks */
+ NULL, /* Intra-Field is generic */
+ Vertical_Scrolling, /* Overloaded to check multi-line */
+ Horizontal_Scrolling, /* Overloaded to check single-line */
+ Field_Editing, /* Overloaded to mark modification */
+ NULL, /* Edit Mode is generic */
+ NULL, /* Field Validation is generic */
+ NULL /* Choice Request is generic */
+ };
+ size_t nMethods = (sizeof(Generic_Methods)/sizeof(Generic_Methods[0]));
+ size_t method = ((BI->keycode & ID_Mask) >> ID_Shft) & 0xffff;
+
+ if ( (method >= nMethods) || !(BI->cmd) )
+ res = E_SYSTEM_ERROR;
+ else
+ {
+ Generic_Method fct = Generic_Methods[method];
+ if (fct)
+ res = fct(BI->cmd,form);
+ else
+ res = (BI->cmd)(form);
+ }
+ }
+ else
+ {
+ if (!(c & (~(int)MAX_REGULAR_CHARACTER)) &&
+ isprint((unsigned char)c) &&
+ Check_Char(form->current->type,c,
+ (TypeArgument *)(form->current->arg)))
+ res = Data_Entry(form,c);
+ }
+ _nc_Refresh_Current_Field(form);
+ RETURN(res);
+}
+
+/*----------------------------------------------------------------------------
+ Field-Buffer manipulation routines.
+ The effects of setting a buffer is tightly coupled to the core of the form
+ driver logic. This is especially true in the case of growable fields.
+ So I don't separate this into an own module.
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_buffer(FIELD *field,
+| int buffer, char *value)
+|
+| Description : Set the given buffer of the field to the given value.
+| Buffer 0 stores the displayed content of the field.
+| For dynamic fields this may grow the fieldbuffers if
+| the length of the value exceeds the current buffer
+| length. For buffer 0 only printable values are allowed.
+| For static fields, the value needs not to be zero ter-
+| minated. It is copied up to the length of the buffer.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid argument
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int set_field_buffer(FIELD * field, int buffer, const char * value)
+{
+ char *s, *p;
+ int res = E_OK;
+ unsigned int len;
+
+ if ( !field || !value || ((buffer < 0)||(buffer > field->nbuf)) )
+ RETURN(E_BAD_ARGUMENT);
+
+ len = Buffer_Length(field);
+
+ if (buffer==0)
+ {
+ const char *v;
+ unsigned int i = 0;
+
+ for(v=value; *v && (i<len); v++,i++)
+ {
+ if (!isprint((unsigned char)*v))
+ RETURN(E_BAD_ARGUMENT);
+ }
+ }
+
+ if (Growable(field))
+ {
+ /* for a growable field we must assume zero terminated strings, because
+ somehow we have to detect the length of what should be copied.
+ */
+ unsigned int vlen = strlen(value);
+ if (vlen > len)
+ {
+ if (!Field_Grown(field,
+ (int)(1 + (vlen-len)/((field->rows+field->nrow)*field->cols))))
+ RETURN(E_SYSTEM_ERROR);
+
+ /* in this case we also have to check, whether or not the remaining
+ characters in value are also printable for buffer 0. */
+ if (buffer==0)
+ {
+ unsigned int i;
+
+ for(i=len; i<vlen; i++)
+ if (!isprint((int)(value[i])))
+ RETURN(E_BAD_ARGUMENT);
+ }
+ len = vlen;
+ }
+ }
+
+ p = Address_Of_Nth_Buffer(field,buffer);
+
+#if HAVE_MEMCCPY
+ s = memccpy(p,value,0,len);
+#else
+ for(s=(char *)value; *s && (s < (value+len)); s++)
+ p[s-value] = *s;
+ if (s < (value+len))
+ {
+ int off = s-value;
+ p[off] = *s++;
+ s = p + (s-value);
+ }
+ else
+ s=(char *)0;
+#endif
+
+ if (s)
+ { /* this means, value was null terminated and not greater than the
+ buffer. We have to pad with blanks. Please note that due to memccpy
+ logic s points after the terminating null. */
+ s--; /* now we point to the terminator. */
+ assert(len >= (unsigned int)(s-p));
+ if (len > (unsigned int)(s-p))
+ memset(s,C_BLANK,len-(unsigned int)(s-p));
+ }
+
+ if (buffer==0)
+ {
+ int syncres;
+ if (((syncres=Synchronize_Field( field ))!=E_OK) &&
+ (res==E_OK))
+ res = syncres;
+ if (((syncres=Synchronize_Linked_Fields(field ))!=E_OK) &&
+ (res==E_OK))
+ res = syncres;
+ }
+ RETURN(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : char *field_buffer(const FIELD *field,int buffer)
+|
+| Description : Return the address of the buffer for the field.
+|
+| Return Values : Pointer to buffer or NULL if arguments were invalid.
++--------------------------------------------------------------------------*/
+char *field_buffer(const FIELD * field, int buffer)
+{
+ if (field && (buffer >= 0) && (buffer <= field->nbuf))
+ return Address_Of_Nth_Buffer(field,buffer);
+ else
+ return (char *)0;
+}
+
+/* frm_driver.c ends here */
diff --git a/Source/CursesDialog/form/frm_hook.c b/Source/CursesDialog/form/frm_hook.c
new file mode 100644
index 0000000..eb654c4
--- /dev/null
+++ b/Source/CursesDialog/form/frm_hook.c
@@ -0,0 +1,140 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/* "Template" macro to generate function to set application specific hook */
+#define GEN_HOOK_SET_FUNCTION( typ, name ) \
+int set_ ## typ ## _ ## name (FORM *form, Form_Hook func)\
+{\
+ (Normalize_Form( form ) -> typ ## name) = func ;\
+ RETURN(E_OK);\
+}
+
+/* "Template" macro to generate function to get application specific hook */
+#define GEN_HOOK_GET_FUNCTION( typ, name ) \
+Form_Hook typ ## _ ## name ( const FORM *form )\
+{\
+ return ( Normalize_Form( form ) -> typ ## name );\
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_init(FORM *form, Form_Hook f)
+|
+| Description : Assigns an application defined initialization function
+| to be called when the form is posted and just after
+| the current field changes.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+GEN_HOOK_SET_FUNCTION(field,init)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : Form_Hook field_init(const FORM *form)
+|
+| Description : Retrieve field initialization routine address.
+|
+| Return Values : The address or NULL if no hook defined.
++--------------------------------------------------------------------------*/
+GEN_HOOK_GET_FUNCTION(field,init)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_term(FORM *form, Form_Hook f)
+|
+| Description : Assigns an application defined finalization function
+| to be called when the form is unposted and just before
+| the current field changes.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+GEN_HOOK_SET_FUNCTION(field,term)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : Form_Hook field_term(const FORM *form)
+|
+| Description : Retrieve field finalization routine address.
+|
+| Return Values : The address or NULL if no hook defined.
++--------------------------------------------------------------------------*/
+GEN_HOOK_GET_FUNCTION(field,term)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_init(FORM *form, Form_Hook f)
+|
+| Description : Assigns an application defined initialization function
+| to be called when the form is posted and just after
+| a page change.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+GEN_HOOK_SET_FUNCTION(form,init)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : Form_Hook form_init(const FORM *form)
+|
+| Description : Retrieve form initialization routine address.
+|
+| Return Values : The address or NULL if no hook defined.
++--------------------------------------------------------------------------*/
+GEN_HOOK_GET_FUNCTION(form,init)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_term(FORM *form, Form_Hook f)
+|
+| Description : Assigns an application defined finalization function
+| to be called when the form is unposted and just before
+| a page change.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+GEN_HOOK_SET_FUNCTION(form,term)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : Form_Hook form_term(const FORM *form)
+|
+| Description : Retrieve form finalization routine address.
+|
+| Return Values : The address or NULL if no hook defined.
++--------------------------------------------------------------------------*/
+GEN_HOOK_GET_FUNCTION(form,term)
+
+/* frm_hook.c ends here */
diff --git a/Source/CursesDialog/form/frm_opts.c b/Source/CursesDialog/form/frm_opts.c
new file mode 100644
index 0000000..7bbeaa1
--- /dev/null
+++ b/Source/CursesDialog/form/frm_opts.c
@@ -0,0 +1,116 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_opts(FORM *form, Form_Options opts)
+|
+| Description : Turns on the named options and turns off all the
+| remaining options for that form.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid options
++--------------------------------------------------------------------------*/
+int set_form_opts(FORM * form, Form_Options opts)
+{
+ opts &= ALL_FORM_OPTS;
+ if (opts & ~ALL_FORM_OPTS)
+ RETURN(E_BAD_ARGUMENT);
+ else
+ {
+ Normalize_Form( form )->opts = opts;
+ RETURN(E_OK);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : Form_Options form_opts(const FORM *)
+|
+| Description : Retrieves the current form options.
+|
+| Return Values : The option flags.
++--------------------------------------------------------------------------*/
+Form_Options form_opts(const FORM * form)
+{
+ return (Normalize_Form(form)->opts & ALL_FORM_OPTS);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int form_opts_on(FORM *form, Form_Options opts)
+|
+| Description : Turns on the named options; no other options are
+| changed.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid options
++--------------------------------------------------------------------------*/
+int form_opts_on(FORM * form, Form_Options opts)
+{
+ opts &= ALL_FORM_OPTS;
+ if (opts & ~ALL_FORM_OPTS)
+ RETURN(E_BAD_ARGUMENT);
+ else
+ {
+ Normalize_Form( form )->opts |= opts;
+ RETURN(E_OK);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int form_opts_off(FORM *form, Form_Options opts)
+|
+| Description : Turns off the named options; no other options are
+| changed.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid options
++--------------------------------------------------------------------------*/
+int form_opts_off(FORM * form, Form_Options opts)
+{
+ opts &= ALL_FORM_OPTS;
+ if (opts & ~ALL_FORM_OPTS)
+ RETURN(E_BAD_ARGUMENT);
+ else
+ {
+ Normalize_Form(form)->opts &= ~opts;
+ RETURN(E_OK);
+ }
+}
+
+/* frm_opts.c ends here */
diff --git a/Source/CursesDialog/form/frm_page.c b/Source/CursesDialog/form/frm_page.c
new file mode 100644
index 0000000..842cbce
--- /dev/null
+++ b/Source/CursesDialog/form/frm_page.c
@@ -0,0 +1,100 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_page(FORM * form,int page)
+|
+| Description : Set the page number of the form.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid form pointer or page number
+| E_BAD_STATE - called from a hook routine
+| E_INVALID_FIELD - current field can't be left
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int set_form_page(FORM * form, int page)
+{
+ int err = E_OK;
+
+ if ( !form || (page<0) || (page>=form->maxpage) )
+ RETURN(E_BAD_ARGUMENT);
+
+ if (!(form->status & _POSTED))
+ {
+ form->curpage = page;
+ form->current = _nc_First_Active_Field(form);
+ }
+ else
+ {
+ if (form->status & _IN_DRIVER)
+ err = E_BAD_STATE;
+ else
+ {
+ if (form->curpage != page)
+ {
+ if (!_nc_Internal_Validation(form))
+ err = E_INVALID_FIELD;
+ else
+ {
+ Call_Hook(form,fieldterm);
+ Call_Hook(form,formterm);
+ err = _nc_Set_Form_Page(form,page,(FIELD *)0);
+ Call_Hook(form,forminit);
+ Call_Hook(form,fieldinit);
+ _nc_Refresh_Current_Field(form);
+ }
+ }
+ }
+ }
+ RETURN(err);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int form_page(const FORM * form)
+|
+| Description : Return the current page of the form.
+|
+| Return Values : >= 0 : current page number
+| -1 : invalid form pointer
++--------------------------------------------------------------------------*/
+int form_page(const FORM * form)
+{
+ return Normalize_Form(form)->curpage;
+}
+
+/* frm_page.c ends here */
diff --git a/Source/CursesDialog/form/frm_post.c b/Source/CursesDialog/form/frm_post.c
new file mode 100644
index 0000000..924fe6a
--- /dev/null
+++ b/Source/CursesDialog/form/frm_post.c
@@ -0,0 +1,119 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int post_form(FORM * form)
+|
+| Description : Writes the form into its associated subwindow.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid form pointer
+| E_POSTED - form already posted
+| E_NOT_CONNECTED - no fields connected to form
+| E_NO_ROOM - form doesn't fit into subwindow
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int post_form(FORM * form)
+{
+ WINDOW *formwin;
+ int err;
+ int page;
+ int height, width;
+
+ if (!form)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (form->status & _POSTED)
+ RETURN(E_POSTED);
+
+ if (!(form->field))
+ RETURN(E_NOT_CONNECTED);
+
+ formwin = Get_Form_Window(form);
+ getmaxyx(formwin, height, width);
+ if ((form->cols > width) || (form->rows > height))
+ RETURN(E_NO_ROOM);
+
+ /* reset form->curpage to an invald value. This forces Set_Form_Page
+ to do the page initialization which is required by post_form.
+ */
+ page = form->curpage;
+ form->curpage = -1;
+ if ((err = _nc_Set_Form_Page(form,page,form->current))!=E_OK)
+ RETURN(err);
+
+ form->status |= _POSTED;
+
+ Call_Hook(form,forminit);
+ Call_Hook(form,fieldinit);
+
+ _nc_Refresh_Current_Field(form);
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int unpost_form(FORM * form)
+|
+| Description : Erase form from its associated subwindow.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid form pointer
+| E_NOT_POSTED - form isn't posted
+| E_BAD_STATE - called from a hook routine
++--------------------------------------------------------------------------*/
+int unpost_form(FORM * form)
+{
+ if (!form)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (!(form->status & _POSTED))
+ RETURN(E_NOT_POSTED);
+
+ if (form->status & _IN_DRIVER)
+ RETURN(E_BAD_STATE);
+
+ Call_Hook(form,fieldterm);
+ Call_Hook(form,formterm);
+
+ werase(Get_Form_Window(form));
+ delwin(form->w);
+ form->w = (WINDOW *)0;
+ form->status &= ~_POSTED;
+ RETURN(E_OK);
+}
+
+/* frm_post.c ends here */
diff --git a/Source/CursesDialog/form/frm_req_name.c b/Source/CursesDialog/form/frm_req_name.c
new file mode 100644
index 0000000..6fb9183
--- /dev/null
+++ b/Source/CursesDialog/form/frm_req_name.c
@@ -0,0 +1,163 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+/***************************************************************************
+* Module form_request_name *
+* Routines to handle external names of menu requests *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+static const char *request_names[ MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1 ] = {
+ "NEXT_PAGE" ,
+ "PREV_PAGE" ,
+ "FIRST_PAGE" ,
+ "LAST_PAGE" ,
+
+ "NEXT_FIELD" ,
+ "PREV_FIELD" ,
+ "FIRST_FIELD" ,
+ "LAST_FIELD" ,
+ "SNEXT_FIELD" ,
+ "SPREV_FIELD" ,
+ "SFIRST_FIELD" ,
+ "SLAST_FIELD" ,
+ "LEFT_FIELD" ,
+ "RIGHT_FIELD" ,
+ "UP_FIELD" ,
+ "DOWN_FIELD" ,
+
+ "NEXT_CHAR" ,
+ "PREV_CHAR" ,
+ "NEXT_LINE" ,
+ "PREV_LINE" ,
+ "NEXT_WORD" ,
+ "PREV_WORD" ,
+ "BEG_FIELD" ,
+ "END_FIELD" ,
+ "BEG_LINE" ,
+ "END_LINE" ,
+ "LEFT_CHAR" ,
+ "RIGHT_CHAR" ,
+ "UP_CHAR" ,
+ "DOWN_CHAR" ,
+
+ "NEW_LINE" ,
+ "INS_CHAR" ,
+ "INS_LINE" ,
+ "DEL_CHAR" ,
+ "DEL_PREV" ,
+ "DEL_LINE" ,
+ "DEL_WORD" ,
+ "CLR_EOL" ,
+ "CLR_EOF" ,
+ "CLR_FIELD" ,
+ "OVL_MODE" ,
+ "INS_MODE" ,
+ "SCR_FLINE" ,
+ "SCR_BLINE" ,
+ "SCR_FPAGE" ,
+ "SCR_BPAGE" ,
+ "SCR_FHPAGE" ,
+ "SCR_BHPAGE" ,
+ "SCR_FCHAR" ,
+ "SCR_BCHAR" ,
+ "SCR_HFLINE" ,
+ "SCR_HBLINE" ,
+ "SCR_HFHALF" ,
+ "SCR_HBHALF" ,
+
+ "VALIDATION" ,
+ "NEXT_CHOICE" ,
+ "PREV_CHOICE"
+};
+#define A_SIZE (sizeof(request_names)/sizeof(request_names[0]))
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : const char * form_request_name (int request);
+|
+| Description : Get the external name of a form request.
+|
+| Return Values : Pointer to name - on success
+| NULL - on invalid request code
++--------------------------------------------------------------------------*/
+const char *form_request_name( int request )
+{
+ if ( (request < MIN_FORM_COMMAND) || (request > MAX_FORM_COMMAND) )
+ {
+ SET_ERROR (E_BAD_ARGUMENT);
+ return (const char *)0;
+ }
+ else
+ return request_names[ request - MIN_FORM_COMMAND ];
+}
+
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int form_request_by_name (const char *str);
+|
+| Description : Search for a request with this name.
+|
+| Return Values : Request Id - on success
+| E_NO_MATCH - request not found
++--------------------------------------------------------------------------*/
+int form_request_by_name( const char *str )
+{
+ /* because the table is so small, it doesn't really hurt
+ to run sequentially through it.
+ */
+ unsigned int i = 0;
+ char buf[16];
+
+ if (str)
+ {
+ strncpy(buf,str,sizeof(buf));
+ while( (i<sizeof(buf)) && (buf[i] != '\0') )
+ {
+ buf[i] = toupper((int)(buf[i]));
+ i++;
+ }
+
+ for (i=0; i < A_SIZE; i++)
+ {
+ if (strncmp(request_names[i],buf,sizeof(buf))==0)
+ return MIN_FORM_COMMAND + i;
+ }
+ }
+ RETURN(E_NO_MATCH);
+}
+
+/* frm_req_name.c ends here */
diff --git a/Source/CursesDialog/form/frm_scale.c b/Source/CursesDialog/form/frm_scale.c
new file mode 100644
index 0000000..028e9e2
--- /dev/null
+++ b/Source/CursesDialog/form/frm_scale.c
@@ -0,0 +1,63 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int scale_form( const FORM *form, int *rows, int *cols )
+|
+| Description : Retrieve size of form
+|
+| Return Values : E_OK - no error
+| E_BAD_ARGUMENT - invalid form pointer
+| E_NOT_CONNECTED - no fields connected to form
++--------------------------------------------------------------------------*/
+int scale_form(const FORM * form, int * rows, int * cols)
+{
+ if ( !form )
+ RETURN(E_BAD_ARGUMENT);
+
+ if ( !(form->field) )
+ RETURN(E_NOT_CONNECTED);
+
+ if (rows)
+ *rows = form->rows;
+ if (cols)
+ *cols = form->cols;
+
+ RETURN(E_OK);
+}
+
+/* frm_scale.c ends here */
diff --git a/Source/CursesDialog/form/frm_sub.c b/Source/CursesDialog/form/frm_sub.c
new file mode 100644
index 0000000..62dc613
--- /dev/null
+++ b/Source/CursesDialog/form/frm_sub.c
@@ -0,0 +1,69 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_sub(FORM *form, WINDOW *win)
+|
+| Description : Set the subwindow of the form to win.
+|
+| Return Values : E_OK - success
+| E_POSTED - form is posted
++--------------------------------------------------------------------------*/
+int set_form_sub(FORM * form, WINDOW * win)
+{
+ if (form && (form->status & _POSTED))
+ RETURN(E_POSTED);
+
+ Normalize_Form( form )->sub = win;
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : WINDOW *form_sub(const FORM *)
+|
+| Description : Retrieve the window of the form.
+|
+| Return Values : The pointer to the Subwindow.
++--------------------------------------------------------------------------*/
+WINDOW *form_sub(const FORM * form)
+{
+ const FORM* f = Normalize_Form( form );
+ return Get_Form_Window(f);
+}
+
+/* frm_sub.c ends here */
diff --git a/Source/CursesDialog/form/frm_user.c b/Source/CursesDialog/form/frm_user.c
new file mode 100644
index 0000000..f38bbbb
--- /dev/null
+++ b/Source/CursesDialog/form/frm_user.c
@@ -0,0 +1,67 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_userptr(FORM *form, void *usrptr)
+|
+| Description : Set the pointer that is reserved in any form to store
+| application relevant information
+|
+| Return Values : E_OK - on success
++--------------------------------------------------------------------------*/
+int set_form_userptr(FORM * form, void *usrptr)
+{
+ Normalize_Form(form)->usrptr = usrptr;
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : void *form_userptr(const FORM *form)
+|
+| Description : Return the pointer that is reserved in any form to
+| store application relevant information.
+|
+| Return Values : Value of pointer. If no such pointer has been set,
+| NULL is returned
++--------------------------------------------------------------------------*/
+void *form_userptr(const FORM * form)
+{
+ return Normalize_Form(form)->usrptr;
+}
+
+/* frm_user.c ends here */
diff --git a/Source/CursesDialog/form/frm_win.c b/Source/CursesDialog/form/frm_win.c
new file mode 100644
index 0000000..82d716f
--- /dev/null
+++ b/Source/CursesDialog/form/frm_win.c
@@ -0,0 +1,70 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_win(FORM *form,WINDOW *win)
+|
+| Description : Set the window of the form to win.
+|
+| Return Values : E_OK - success
+| E_POSTED - form is posted
++--------------------------------------------------------------------------*/
+int set_form_win(FORM * form, WINDOW * win)
+{
+ if (form && (form->status & _POSTED))
+ RETURN(E_POSTED);
+
+ Normalize_Form( form )->win = win;
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : WINDOW *form_win(const FORM *)
+|
+| Description : Retrieve the window of the form.
+|
+| Return Values : The pointer to the Window or stdscr if there is none.
++--------------------------------------------------------------------------*/
+WINDOW *form_win(const FORM * form)
+{
+ const FORM* f = Normalize_Form( form );
+ return (f->win ? f->win : stdscr);
+}
+
+/* frm_win.c ends here */
+
diff --git a/Source/CursesDialog/form/fty_alnum.c b/Source/CursesDialog/form/fty_alnum.c
new file mode 100644
index 0000000..6f3cfd4
--- /dev/null
+++ b/Source/CursesDialog/form/fty_alnum.c
@@ -0,0 +1,138 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+typedef struct {
+ int width;
+} alnumARG;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Make_AlphaNumeric_Type(va_list *ap)
+|
+| Description : Allocate structure for alphanumeric type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error
++--------------------------------------------------------------------------*/
+static void *Make_AlphaNumeric_Type(va_list * ap)
+{
+ alnumARG *argp = (alnumARG *)malloc(sizeof(alnumARG));
+
+ if (argp)
+ argp->width = va_arg(*ap,int);
+
+ return ((void *)argp);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Copy_AlphaNumericType(const void *argp)
+|
+| Description : Copy structure for alphanumeric type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error.
++--------------------------------------------------------------------------*/
+static void *Copy_AlphaNumeric_Type(const void *argp)
+{
+ const alnumARG *ap = (const alnumARG *)argp;
+ alnumARG *result = (alnumARG *)malloc(sizeof(alnumARG));
+
+ if (result)
+ *result = *ap;
+
+ return ((void *)result);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Free_AlphaNumeric_Type(void *argp)
+|
+| Description : Free structure for alphanumeric type argument.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Free_AlphaNumeric_Type(void * argp)
+{
+ if (argp)
+ free(argp);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_AlphaNumeric_Field(
+| FIELD *field,
+| const void *argp)
+|
+| Description : Validate buffer content to be a valid alphanumeric value
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_AlphaNumeric_Field(FIELD * field, const void * argp)
+{
+ int width = ((const alnumARG *)argp)->width;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+ int l = -1;
+ unsigned char *s;
+
+ while(*bp && *bp==' ')
+ bp++;
+ if (*bp)
+ {
+ s = bp;
+ while(*bp && isalnum(*bp))
+ bp++;
+ l = (int)(bp-s);
+ while(*bp && *bp==' ')
+ bp++;
+ }
+ return ((*bp || (l < width)) ? FALSE : TRUE);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_AlphaNumeric_Character(
+| int c,
+| const void *argp )
+|
+| Description : Check a character for the alphanumeric type.
+|
+| Return Values : TRUE - character is valid
+| FALSE - character is invalid
++--------------------------------------------------------------------------*/
+static bool Check_AlphaNumeric_Character(int c, const void * argp)
+{
+ argp=0; /* Silence unused parameter warning. */
+ return (isalnum(c) ? TRUE : FALSE);
+}
+
+static FIELDTYPE typeALNUM = {
+ _HAS_ARGS | _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ Make_AlphaNumeric_Type,
+ Copy_AlphaNumeric_Type,
+ Free_AlphaNumeric_Type,
+ Check_AlphaNumeric_Field,
+ Check_AlphaNumeric_Character,
+ NULL,
+ NULL
+};
+
+FIELDTYPE* TYPE_ALNUM = &typeALNUM;
+
+/* fty_alnum.c ends here */
diff --git a/Source/CursesDialog/form/fty_alpha.c b/Source/CursesDialog/form/fty_alpha.c
new file mode 100644
index 0000000..e4e9ceb
--- /dev/null
+++ b/Source/CursesDialog/form/fty_alpha.c
@@ -0,0 +1,139 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+typedef struct {
+ int width;
+} alphaARG;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Make_Alpha_Type(va_list *ap)
+|
+| Description : Allocate structure for alpha type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error
++--------------------------------------------------------------------------*/
+static void *Make_Alpha_Type(va_list * ap)
+{
+ alphaARG *argp = (alphaARG *)malloc(sizeof(alphaARG));
+ if (argp)
+ {
+ argp->width = va_arg(*ap,int);
+ }
+ return ((void *)argp);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Copy_Alpha_Type(const void * argp)
+|
+| Description : Copy structure for alpha type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error.
++--------------------------------------------------------------------------*/
+static void *Copy_Alpha_Type(const void * argp)
+{
+ const alphaARG *ap = (const alphaARG *)argp;
+ alphaARG *result = (alphaARG *)malloc(sizeof(alphaARG));
+
+ if (result)
+ {
+ *result = *ap;
+ }
+ return ((void *)result);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Free_Alpha_Type( void * argp )
+|
+| Description : Free structure for alpha type argument.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Free_Alpha_Type(void * argp)
+{
+ if (argp)
+ free(argp);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Alpha_Field(
+| FIELD * field,
+| const void * argp)
+|
+| Description : Validate buffer content to be a valid alpha value
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Alpha_Field(FIELD * field, const void * argp)
+{
+ int width = ((const alphaARG *)argp)->width;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+ int l = -1;
+ unsigned char *s;
+
+ while(*bp && *bp==' ')
+ bp++;
+ if (*bp)
+ {
+ s = bp;
+ while(*bp && isalpha(*bp))
+ bp++;
+ l = (int)(bp-s);
+ while(*bp && *bp==' ')
+ bp++;
+ }
+ return ((*bp || (l < width)) ? FALSE : TRUE);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Alpha_Character(
+| int c,
+| const void * argp)
+|
+| Description : Check a character for the alpha type.
+|
+| Return Values : TRUE - character is valid
+| FALSE - character is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Alpha_Character(int c, const void * argp)
+{
+ argp=0; /* Silence unused parameter warning. */
+ return (isalpha(c) ? TRUE : FALSE);
+}
+
+static FIELDTYPE typeALPHA = {
+ _HAS_ARGS | _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ Make_Alpha_Type,
+ Copy_Alpha_Type,
+ Free_Alpha_Type,
+ Check_Alpha_Field,
+ Check_Alpha_Character,
+ NULL,
+ NULL
+};
+
+FIELDTYPE* TYPE_ALPHA = &typeALPHA;
+
+/* fty_alpha.c ends here */
diff --git a/Source/CursesDialog/form/fty_enum.c b/Source/CursesDialog/form/fty_enum.c
new file mode 100644
index 0000000..59058a9
--- /dev/null
+++ b/Source/CursesDialog/form/fty_enum.c
@@ -0,0 +1,295 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+typedef struct {
+ char **kwds;
+ int count;
+ bool checkcase;
+ bool checkunique;
+} enumARG;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Make_Enum_Type( va_list * ap )
+|
+| Description : Allocate structure for enumeration type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error
++--------------------------------------------------------------------------*/
+static void *Make_Enum_Type(va_list * ap)
+{
+ enumARG *argp = (enumARG *)malloc(sizeof(enumARG));
+
+ if (argp)
+ {
+ int cnt = 0;
+ char **kp = (char **)0;
+ int ccase, cunique;
+
+ argp->kwds = va_arg(*ap,char **);
+ ccase = va_arg(*ap,int);
+ cunique = va_arg(*ap,int);
+ argp->checkcase = ccase ? TRUE : FALSE;
+ argp->checkunique = cunique ? TRUE : FALSE;
+
+ kp = argp->kwds;
+ while( kp && (*kp++) ) cnt++;
+ argp->count = cnt;
+ }
+ return (void *)argp;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Copy_Enum_Type( const void * argp )
+|
+| Description : Copy structure for enumeration type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error.
++--------------------------------------------------------------------------*/
+static void *Copy_Enum_Type(const void * argp)
+{
+ enumARG *result = (enumARG *)0;
+
+ if (argp)
+ {
+ const enumARG *ap = (const enumARG *)argp;
+
+ result = (enumARG *)malloc(sizeof(enumARG));
+ if (result)
+ *result = *ap;
+ }
+ return (void *)result;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Free_Enum_Type( void * argp )
+|
+| Description : Free structure for enumeration type argument.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Free_Enum_Type(void * argp)
+{
+ if (argp)
+ free(argp);
+}
+
+#define SKIP_SPACE(x) while(((*(x))!='\0') && (is_blank(*(x)))) (x)++
+#define NOMATCH 0
+#define PARTIAL 1
+#define EXACT 2
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Compare(const unsigned char * s,
+| const unsigned char * buf,
+| bool ccase )
+|
+| Description : Check whether or not the text in 'buf' matches the
+| text in 's', at least partial.
+|
+| Return Values : NOMATCH - buffer doesn't match
+| PARTIAL - buffer matches partially
+| EXACT - buffer matches exactly
++--------------------------------------------------------------------------*/
+static int Compare(const unsigned char *s, const unsigned char *buf,
+ bool ccase)
+{
+ SKIP_SPACE(buf); /* Skip leading spaces in both texts */
+ SKIP_SPACE(s);
+
+ if (*buf=='\0')
+ {
+ return (((*s)!='\0') ? NOMATCH : EXACT);
+ }
+ else
+ {
+ if (ccase)
+ {
+ while(*s++ == *buf)
+ {
+ if (*buf++=='\0') return EXACT;
+ }
+ }
+ else
+ {
+ while(toupper(*s++)==toupper(*buf))
+ {
+ if (*buf++=='\0') return EXACT;
+ }
+ }
+ }
+ /* At this location buf points to the first character where it no longer
+ matches with s. So if only blanks are following, we have a partial
+ match otherwise there is no match */
+ SKIP_SPACE(buf);
+ if (*buf)
+ return NOMATCH;
+
+ /* If it happens that the reference buffer is at its end, the partial
+ match is actually an exact match. */
+ return ((s[-1]!='\0') ? PARTIAL : EXACT);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Enum_Field(
+| FIELD * field,
+| const void * argp)
+|
+| Description : Validate buffer content to be a valid enumeration value
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Enum_Field(FIELD * field, const void * argp)
+{
+ char **kwds = ((const enumARG *)argp)->kwds;
+ bool ccase = ((const enumARG *)argp)->checkcase;
+ bool unique = ((const enumARG *)argp)->checkunique;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+ char *s, *t, *p;
+ int res;
+
+ while( kwds && (s=(*kwds++)) )
+ {
+ if ((res=Compare((unsigned char *)s,bp,ccase))!=NOMATCH)
+ {
+ p=t=s; /* t is at least a partial match */
+ if ((unique && res!=EXACT))
+ {
+ while( kwds && (p = *kwds++) )
+ {
+ if ((res=Compare((unsigned char *)p,bp,ccase))!=NOMATCH)
+ {
+ if (res==EXACT)
+ {
+ t = p;
+ break;
+ }
+ else
+ t = (char *)0;
+ }
+ }
+ }
+ if (t)
+ {
+ set_field_buffer(field,0,t);
+ return TRUE;
+ }
+ if (!p)
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static const char *dummy[] = { (char *)0 };
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Next_Enum(FIELD * field,
+| const void * argp)
+|
+| Description : Check for the next enumeration value
+|
+| Return Values : TRUE - next value found and loaded
+| FALSE - no next value loaded
++--------------------------------------------------------------------------*/
+static bool Next_Enum(FIELD * field, const void * argp)
+{
+ const enumARG *args = (const enumARG *)argp;
+ char **kwds = args->kwds;
+ bool ccase = args->checkcase;
+ int cnt = args->count;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+
+ if (kwds) {
+ while(cnt--)
+ {
+ if (Compare((unsigned char *)(*kwds++),bp,ccase)==EXACT)
+ break;
+ }
+ if (cnt<=0)
+ kwds = args->kwds;
+ if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT))
+ {
+ set_field_buffer(field,0,*kwds);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Previous_Enum(
+| FIELD * field,
+| const void * argp)
+|
+| Description : Check for the previous enumeration value
+|
+| Return Values : TRUE - previous value found and loaded
+| FALSE - no previous value loaded
++--------------------------------------------------------------------------*/
+static bool Previous_Enum(FIELD * field, const void * argp)
+{
+ const enumARG *args = (const enumARG *)argp;
+ int cnt = args->count;
+ char **kwds = &args->kwds[cnt-1];
+ bool ccase = args->checkcase;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+
+ if (kwds) {
+ while(cnt--)
+ {
+ if (Compare((unsigned char *)(*kwds--),bp,ccase)==EXACT)
+ break;
+ }
+
+ if (cnt<=0)
+ kwds = &args->kwds[args->count-1];
+
+ if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT))
+ {
+ set_field_buffer(field,0,*kwds);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+static FIELDTYPE typeENUM = {
+ _HAS_ARGS | _HAS_CHOICE | _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ Make_Enum_Type,
+ Copy_Enum_Type,
+ Free_Enum_Type,
+ Check_Enum_Field,
+ NULL,
+ Next_Enum,
+ Previous_Enum
+};
+
+FIELDTYPE* TYPE_ENUM = &typeENUM;
+
+/* fty_enum.c ends here */
diff --git a/Source/CursesDialog/form/fty_int.c b/Source/CursesDialog/form/fty_int.c
new file mode 100644
index 0000000..7107fcc
--- /dev/null
+++ b/Source/CursesDialog/form/fty_int.c
@@ -0,0 +1,161 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+typedef struct {
+ int precision;
+ long low;
+ long high;
+} integerARG;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Make_Integer_Type( va_list * ap )
+|
+| Description : Allocate structure for integer type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error
++--------------------------------------------------------------------------*/
+static void *Make_Integer_Type(va_list * ap)
+{
+ integerARG *argp = (integerARG *)malloc(sizeof(integerARG));
+
+ if (argp)
+ {
+ argp->precision = va_arg(*ap,int);
+ argp->low = va_arg(*ap,long);
+ argp->high = va_arg(*ap,long);
+ }
+ return (void *)argp;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Copy_Integer_Type(const void * argp)
+|
+| Description : Copy structure for integer type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error.
++--------------------------------------------------------------------------*/
+static void *Copy_Integer_Type(const void * argp)
+{
+ const integerARG *ap = (const integerARG *)argp;
+ integerARG *result = (integerARG *)0;
+
+ if (argp)
+ {
+ result = (integerARG *)malloc(sizeof(integerARG));
+ if (result)
+ *result = *ap;
+ }
+ return (void *)result;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Free_Integer_Type(void * argp)
+|
+| Description : Free structure for integer type argument.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Free_Integer_Type(void * argp)
+{
+ if (argp)
+ free(argp);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Integer_Field(
+| FIELD * field,
+| const void * argp)
+|
+| Description : Validate buffer content to be a valid integer value
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Integer_Field(FIELD * field, const void * argp)
+{
+ const integerARG *argi = (const integerARG *)argp;
+ long low = argi->low;
+ long high = argi->high;
+ int prec = argi->precision;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+ char *s = (char *)bp;
+ long val;
+ char buf[100];
+
+ while( *bp && *bp==' ') bp++;
+ if (*bp)
+ {
+ if (*bp=='-') bp++;
+ while (*bp)
+ {
+ if (!isdigit(*bp)) break;
+ bp++;
+ }
+ while(*bp && *bp==' ') bp++;
+ if (*bp=='\0')
+ {
+ val = atol(s);
+ if (low<high)
+ {
+ if (val<low || val>high) return FALSE;
+ }
+ sprintf(buf,"%.*ld",(prec>0?prec:0),val);
+ set_field_buffer(field,0,buf);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Integer_Character(
+| int c,
+| const void * argp)
+|
+| Description : Check a character for the integer type.
+|
+| Return Values : TRUE - character is valid
+| FALSE - character is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Integer_Character(int c, const void * argp)
+{
+ argp=0; /* Silence unused parameter warning. */
+ return ((isdigit(c) || (c=='-')) ? TRUE : FALSE);
+}
+
+static FIELDTYPE typeINTEGER = {
+ _HAS_ARGS | _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ Make_Integer_Type,
+ Copy_Integer_Type,
+ Free_Integer_Type,
+ Check_Integer_Field,
+ Check_Integer_Character,
+ NULL,
+ NULL
+};
+
+FIELDTYPE* TYPE_INTEGER = &typeINTEGER;
+
+/* fty_int.c ends here */
diff --git a/Source/CursesDialog/form/fty_ipv4.c b/Source/CursesDialog/form/fty_ipv4.c
new file mode 100644
index 0000000..c855af6
--- /dev/null
+++ b/Source/CursesDialog/form/fty_ipv4.c
@@ -0,0 +1,84 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Per Foreby, perf@efd.lth.se *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_IPV4_Field(
+| FIELD * field,
+| const void * argp)
+|
+| Description : Validate buffer content to be a valid IP number (Ver. 4)
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_IPV4_Field(FIELD * field, const void * argp)
+{
+ char *bp = field_buffer(field,0);
+ int num = 0, len;
+ unsigned int d1=256, d2=256, d3=256, d4=256;
+
+ argp=0; /* Silence unused parameter warning. */
+
+ if(isdigit((int)(*bp))) /* Must start with digit */
+ {
+ num = sscanf(bp, "%u.%u.%u.%u%n", &d1, &d2, &d3, &d4, &len);
+ if (num == 4)
+ {
+ bp += len; /* Make bp point to what sscanf() left */
+ while (*bp && isspace((int)(*bp)))
+ bp++; /* Allow trailing whitespace */
+ }
+ }
+ return ((num != 4 || *bp || d1 > 255 || d2 > 255
+ || d3 > 255 || d4 > 255) ? FALSE : TRUE);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_IPV4_Character(
+| int c,
+| const void *argp )
+|
+| Description : Check a character for unsigned type or period.
+|
+| Return Values : TRUE - character is valid
+| FALSE - character is invalid
++--------------------------------------------------------------------------*/
+static bool Check_IPV4_Character(int c, const void * argp)
+{
+ argp=0; /* Silence unused parameter warning. */
+ return ((isdigit(c) || (c=='.')) ? TRUE : FALSE);
+}
+
+static FIELDTYPE typeIPV4 = {
+ _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ NULL,
+ NULL,
+ NULL,
+ Check_IPV4_Field,
+ Check_IPV4_Character,
+ NULL,
+ NULL
+};
+
+FIELDTYPE* TYPE_IPV4 = &typeIPV4;
+
+/* fty_ipv4.c ends here */
diff --git a/Source/CursesDialog/form/fty_num.c b/Source/CursesDialog/form/fty_num.c
new file mode 100644
index 0000000..7809599
--- /dev/null
+++ b/Source/CursesDialog/form/fty_num.c
@@ -0,0 +1,192 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+typedef struct {
+ int precision;
+ double low;
+ double high;
+ struct lconv* L;
+} numericARG;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Make_Numeric_Type(va_list * ap)
+|
+| Description : Allocate structure for numeric type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error
++--------------------------------------------------------------------------*/
+static void *Make_Numeric_Type(va_list * ap)
+{
+ numericARG *argn = (numericARG *)malloc(sizeof(numericARG));
+
+ if (argn)
+ {
+ argn->precision = va_arg(*ap,int);
+ argn->low = va_arg(*ap,double);
+ argn->high = va_arg(*ap,double);
+#if HAVE_LOCALE_H
+ argn->L = localeconv();
+#else
+ argn->L = NULL;
+#endif
+ }
+ return (void *)argn;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Copy_Numeric_Type(const void * argp)
+|
+| Description : Copy structure for numeric type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error.
++--------------------------------------------------------------------------*/
+static void *Copy_Numeric_Type(const void * argp)
+{
+ const numericARG *ap = (const numericARG *)argp;
+ numericARG *result = (numericARG *)0;
+
+ if (argp)
+ {
+ result = (numericARG *)malloc(sizeof(numericARG));
+ if (result)
+ *result = *ap;
+ }
+ return (void *)result;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Free_Numeric_Type(void * argp)
+|
+| Description : Free structure for numeric type argument.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Free_Numeric_Type(void * argp)
+{
+ if (argp)
+ free(argp);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Numeric_Field(FIELD * field,
+| const void * argp)
+|
+| Description : Validate buffer content to be a valid numeric value
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Numeric_Field(FIELD * field, const void * argp)
+{
+ const numericARG *argn = (const numericARG *)argp;
+ double low = argn->low;
+ double high = argn->high;
+ int prec = argn->precision;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+ char *s = (char *)bp;
+ double val = 0.0;
+ char buf[64];
+
+ while(*bp && *bp==' ') bp++;
+ if (*bp)
+ {
+ if (*bp=='-' || *bp=='+')
+ bp++;
+ while(*bp)
+ {
+ if (!isdigit(*bp)) break;
+ bp++;
+ }
+ if (*bp==(
+#if HAVE_LOCALE_H
+ (L && L->decimal_point) ? *(L->decimal_point) :
+#endif
+ '.'))
+ {
+ bp++;
+ while(*bp)
+ {
+ if (!isdigit(*bp)) break;
+ bp++;
+ }
+ }
+ while(*bp && *bp==' ') bp++;
+ if (*bp=='\0')
+ {
+ val = atof(s);
+ if (low<high)
+ {
+ if (val<low || val>high) return FALSE;
+ }
+ sprintf(buf,"%.*f",(prec>0?prec:0),val);
+ set_field_buffer(field,0,buf);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Numeric_Character(
+| int c,
+| const void * argp)
+|
+| Description : Check a character for the numeric type.
+|
+| Return Values : TRUE - character is valid
+| FALSE - character is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Numeric_Character(int c, const void * argp)
+{
+ argp=0; /* Silence unused parameter warning. */
+ return (isdigit(c) ||
+ c == '+' ||
+ c == '-' ||
+ c == (
+#if HAVE_LOCALE_H
+ (L && L->decimal_point) ? *(L->decimal_point) :
+#endif
+ '.')
+ ) ? TRUE : FALSE;
+}
+
+static FIELDTYPE typeNUMERIC = {
+ _HAS_ARGS | _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ Make_Numeric_Type,
+ Copy_Numeric_Type,
+ Free_Numeric_Type,
+ Check_Numeric_Field,
+ Check_Numeric_Character,
+ NULL,
+ NULL
+};
+
+FIELDTYPE* TYPE_NUMERIC = &typeNUMERIC;
+
+/* fty_num.c ends here */
diff --git a/Source/CursesDialog/form/fty_regex.c b/Source/CursesDialog/form/fty_regex.c
new file mode 100644
index 0000000..f90e0c1
--- /dev/null
+++ b/Source/CursesDialog/form/fty_regex.c
@@ -0,0 +1,264 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+#if HAVE_REGEX_H_FUNCS /* We prefer POSIX regex */
+#include <regex.h>
+
+typedef struct
+{
+ regex_t *pRegExp;
+ unsigned long *refCount;
+} RegExp_Arg;
+
+#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
+#undef RETURN
+static int reg_errno;
+
+static char *RegEx_Init(char *instring)
+{
+ reg_errno = 0;
+ return instring;
+}
+
+static char *RegEx_Error(int code)
+{
+ reg_errno = code;
+ return 0;
+}
+
+#define INIT char *sp = RegEx_Init(instring);
+#define GETC() (*sp++)
+#define PEEKC() (*sp)
+#define UNGETC(c) (--sp)
+#define RETURN(c) return(c)
+#define ERROR(c) return RegEx_Error(c)
+
+#if HAVE_REGEXP_H_FUNCS
+#include <regexp.h>
+#else
+#include <regexpr.h>
+#endif
+
+typedef struct
+{
+ char *compiled_expression;
+ unsigned long *refCount;
+} RegExp_Arg;
+
+/* Maximum Length we allow for a compiled regular expression */
+#define MAX_RX_LEN (2048)
+#define RX_INCREMENT (256)
+
+#endif
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Make_RegularExpression_Type(va_list * ap)
+|
+| Description : Allocate structure for regex type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error
++--------------------------------------------------------------------------*/
+static void *Make_RegularExpression_Type(va_list * ap)
+{
+#if HAVE_REGEX_H_FUNCS
+ char *rx = va_arg(*ap,char *);
+ RegExp_Arg *preg;
+
+ preg = (RegExp_Arg*)malloc(sizeof(RegExp_Arg));
+ if (preg)
+ {
+ if (((preg->pRegExp = (regex_t*)malloc(sizeof(regex_t))) != (regex_t*)0)
+ && !regcomp(preg->pRegExp,rx,
+ (REG_EXTENDED | REG_NOSUB | REG_NEWLINE) ))
+ {
+ preg->refCount = (unsigned long *)malloc(sizeof(unsigned long));
+ *(preg->refCount) = 1;
+ }
+ else
+ {
+ if (preg->pRegExp)
+ free(preg->pRegExp);
+ free(preg);
+ preg = (RegExp_Arg*)0;
+ }
+ }
+ return((void *)preg);
+#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
+ char *rx = va_arg(*ap,char *);
+ RegExp_Arg *pArg;
+
+ pArg = (RegExp_Arg *)malloc(sizeof(RegExp_Arg));
+
+ if (pArg)
+ {
+ int blen = RX_INCREMENT;
+ pArg->compiled_expression = NULL;
+ pArg->refCount = (unsigned long *)malloc(sizeof(unsigned long));
+ *(pArg->refCount) = 1;
+
+ do {
+ char *buf = (char *)malloc(blen);
+ if (buf)
+ {
+#if HAVE_REGEXP_H_FUNCS
+ char *last_pos = compile (rx, buf, &buf[blen], '\0');
+#else /* HAVE_REGEXPR_H_FUNCS */
+ char *last_pos = compile (rx, buf, &buf[blen]);
+#endif
+ if (reg_errno)
+ {
+ free(buf);
+ if (reg_errno==50)
+ blen += RX_INCREMENT;
+ else
+ {
+ free(pArg);
+ pArg = NULL;
+ break;
+ }
+ }
+ else
+ {
+ pArg->compiled_expression = buf;
+ break;
+ }
+ }
+ } while( blen <= MAX_RX_LEN );
+ }
+ if (pArg && !pArg->compiled_expression)
+ {
+ free(pArg);
+ pArg = NULL;
+ }
+ return (void *)pArg;
+#else
+ ap=0; /* Silence unused parameter warning. */
+ return 0;
+#endif
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Copy_RegularExpression_Type(
+| const void * argp)
+|
+| Description : Copy structure for regex type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error.
++--------------------------------------------------------------------------*/
+static void *Copy_RegularExpression_Type(const void * argp)
+{
+#if (HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS)
+ const RegExp_Arg *ap = (const RegExp_Arg *)argp;
+ const RegExp_Arg *result = (const RegExp_Arg *)0;
+
+ if (ap)
+ {
+ *(ap->refCount) += 1;
+ result = ap;
+ }
+ return (void *)result;
+#else
+ argp=0; /* Silence unused parameter warning. */
+ return 0;
+#endif
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Free_RegularExpression_Type(void * argp)
+|
+| Description : Free structure for regex type argument.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Free_RegularExpression_Type(void * argp)
+{
+#if HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
+ RegExp_Arg *ap = (RegExp_Arg *)argp;
+ if (ap)
+ {
+ if (--(*(ap->refCount)) == 0)
+ {
+#if HAVE_REGEX_H_FUNCS
+ if (ap->pRegExp)
+ {
+ free(ap->refCount);
+ regfree(ap->pRegExp);
+ }
+#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
+ if (ap->compiled_expression)
+ {
+ free(ap->refCount);
+ free(ap->compiled_expression);
+ }
+#endif
+ free(ap);
+ }
+ }
+#else
+ argp=0; /* Silence unused parameter warning. */
+#endif
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_RegularExpression_Field(
+| FIELD * field,
+| const void * argp)
+|
+| Description : Validate buffer content to be a valid regular expression
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_RegularExpression_Field(FIELD * field, const void * argp)
+{
+ bool match = FALSE;
+#if HAVE_REGEX_H_FUNCS
+ const RegExp_Arg *ap = (const RegExp_Arg*)argp;
+ if (ap && ap->pRegExp)
+ match = (regexec(ap->pRegExp,field_buffer(field,0),0,NULL,0) ? FALSE:TRUE);
+#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
+ RegExp_Arg *ap = (RegExp_Arg *)argp;
+ if (ap && ap->compiled_expression)
+ match = (step(field_buffer(field,0),ap->compiled_expression) ? TRUE:FALSE);
+#else
+ argp=0; /* Silence unused parameter warning. */
+ field=0; /* Silence unused parameter warning. */
+#endif
+ return match;
+}
+
+static FIELDTYPE typeREGEXP = {
+ _HAS_ARGS | _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ Make_RegularExpression_Type,
+ Copy_RegularExpression_Type,
+ Free_RegularExpression_Type,
+ Check_RegularExpression_Field,
+ NULL,
+ NULL,
+ NULL
+};
+
+FIELDTYPE* TYPE_REGEXP = &typeREGEXP;
+
+/* fty_regex.c ends here */
diff --git a/Source/CursesDialog/form/llib-lform b/Source/CursesDialog/form/llib-lform
new file mode 100644
index 0000000..ac2ba43
--- /dev/null
+++ b/Source/CursesDialog/form/llib-lform
@@ -0,0 +1,694 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Thomas E. Dickey <dickey@clark.net> 1996,1997 *
+ ****************************************************************************/
+/* LINTLIBRARY */
+
+/* ./fld_arg.c */
+
+#include "form.priv.h"
+
+#undef set_fieldtype_arg
+int set_fieldtype_arg(
+ FIELDTYPE *typ,
+ void *(*const make_arg)(
+ va_list *p1),
+ void *(*const copy_arg)(
+ const void *p1),
+ void (*const free_arg)(
+ void *p1))
+ { return(*(int *)0); }
+
+#undef field_arg
+void *field_arg(
+ const FIELD *field)
+ { return(*(void **)0); }
+
+/* ./fld_attr.c */
+
+#undef set_field_fore
+int set_field_fore(
+ FIELD *field,
+ chtype attr)
+ { return(*(int *)0); }
+
+#undef field_fore
+chtype field_fore(
+ const FIELD *field)
+ { return(*(chtype *)0); }
+
+#undef set_field_back
+int set_field_back(
+ FIELD *field,
+ chtype attr)
+ { return(*(int *)0); }
+
+#undef field_back
+chtype field_back(
+ const FIELD *field)
+ { return(*(chtype *)0); }
+
+/* ./fld_current.c */
+
+#undef set_current_field
+int set_current_field(
+ FORM *form,
+ FIELD *field)
+ { return(*(int *)0); }
+
+#undef current_field
+FIELD *current_field(
+ const FORM *form)
+ { return(*(FIELD **)0); }
+
+#undef field_index
+int field_index(
+ const FIELD *field)
+ { return(*(int *)0); }
+
+/* ./fld_def.c */
+
+#undef _nc_Default_Field
+FIELD *_nc_Default_Field;
+
+#undef _nc_Make_Argument
+TypeArgument *_nc_Make_Argument(
+ const FIELDTYPE *typ,
+ va_list *ap,
+ int *err)
+ { return(*(TypeArgument **)0); }
+
+#undef _nc_Copy_Argument
+TypeArgument *_nc_Copy_Argument(
+ const FIELDTYPE *typ,
+ const TypeArgument *argp,
+ int *err)
+ { return(*(TypeArgument **)0); }
+
+#undef _nc_Free_Argument
+void _nc_Free_Argument(
+ const FIELDTYPE *typ,
+ TypeArgument *argp)
+ { /* void */ }
+
+#undef _nc_Copy_Type
+bool _nc_Copy_Type(
+ FIELD *dst,
+ FIELD const *src)
+ { return(*(bool *)0); }
+
+#undef _nc_Free_Type
+void _nc_Free_Type(
+ FIELD *field)
+ { /* void */ }
+
+#undef new_field
+FIELD *new_field(
+ int rows,
+ int cols,
+ int frow,
+ int fcol,
+ int nrow,
+ int nbuf)
+ { return(*(FIELD **)0); }
+
+#undef free_field
+int free_field(
+ FIELD *field)
+ { return(*(int *)0); }
+
+/* ./fld_dup.c */
+
+#undef dup_field
+FIELD *dup_field(
+ FIELD *field,
+ int frow,
+ int fcol)
+ { return(*(FIELD **)0); }
+
+/* ./fld_ftchoice.c */
+
+#undef set_fieldtype_choice
+int set_fieldtype_choice(
+ FIELDTYPE *typ,
+ bool (*const next_choice)(
+ FIELD *p1,
+ const void *p2),
+ bool (*const prev_choice)(
+ FIELD *p1,
+ const void *p2))
+ { return(*(int *)0); }
+
+/* ./fld_ftlink.c */
+
+#undef link_fieldtype
+FIELDTYPE *link_fieldtype(
+ FIELDTYPE *type1,
+ FIELDTYPE *type2)
+ { return(*(FIELDTYPE **)0); }
+
+/* ./fld_info.c */
+
+#undef field_info
+int field_info(
+ const FIELD *field,
+ int *rows,
+ int *cols,
+ int *frow,
+ int *fcol,
+ int *nrow,
+ int *nbuf)
+ { return(*(int *)0); }
+
+#undef dynamic_field_info
+int dynamic_field_info(
+ const FIELD *field,
+ int *drows,
+ int *dcols,
+ int *maxgrow)
+ { return(*(int *)0); }
+
+/* ./fld_just.c */
+
+#undef set_field_just
+int set_field_just(
+ FIELD *field,
+ int just)
+ { return(*(int *)0); }
+
+#undef field_just
+int field_just(
+ const FIELD *field)
+ { return(*(int *)0); }
+
+/* ./fld_link.c */
+
+#undef link_field
+FIELD *link_field(
+ FIELD *field,
+ int frow,
+ int fcol)
+ { return(*(FIELD **)0); }
+
+/* ./fld_max.c */
+
+#undef set_max_field
+int set_max_field(
+ FIELD *field,
+ int maxgrow)
+ { return(*(int *)0); }
+
+/* ./fld_move.c */
+
+#undef move_field
+int move_field(
+ FIELD *field,
+ int frow,
+ int fcol)
+ { return(*(int *)0); }
+
+/* ./fld_newftyp.c */
+
+#undef _nc_Default_FieldType
+const FIELDTYPE *_nc_Default_FieldType = {0};
+
+#undef new_fieldtype
+FIELDTYPE *new_fieldtype(
+ bool (*const field_check)(
+ FIELD *p1,
+ const void *p2),
+ bool (*const char_check)(
+ int p1,
+ const void *p2))
+ { return(*(FIELDTYPE **)0); }
+
+#undef free_fieldtype
+int free_fieldtype(
+ FIELDTYPE *typ)
+ { return(*(int *)0); }
+
+/* ./fld_opts.c */
+
+#undef set_field_opts
+int set_field_opts(
+ FIELD *field,
+ Field_Options opts)
+ { return(*(int *)0); }
+
+#undef field_opts
+Field_Options field_opts(
+ const FIELD *field)
+ { return(*(Field_Options *)0); }
+
+#undef field_opts_on
+int field_opts_on(
+ FIELD *field,
+ Field_Options opts)
+ { return(*(int *)0); }
+
+#undef field_opts_off
+int field_opts_off(
+ FIELD *field,
+ Field_Options opts)
+ { return(*(int *)0); }
+
+/* ./fld_pad.c */
+
+#undef set_field_pad
+int set_field_pad(
+ FIELD *field,
+ int ch)
+ { return(*(int *)0); }
+
+#undef field_pad
+int field_pad(
+ const FIELD *field)
+ { return(*(int *)0); }
+
+/* ./fld_page.c */
+
+#undef set_new_page
+int set_new_page(
+ FIELD *field,
+ bool new_page_flag)
+ { return(*(int *)0); }
+
+#undef new_page
+bool new_page(
+ const FIELD *field)
+ { return(*(bool *)0); }
+
+/* ./fld_stat.c */
+
+#undef set_field_status
+int set_field_status(
+ FIELD *field,
+ bool status)
+ { return(*(int *)0); }
+
+#undef field_status
+bool field_status(
+ const FIELD *field)
+ { return(*(bool *)0); }
+
+/* ./fld_type.c */
+
+#undef set_field_type
+int set_field_type(
+ FIELD *field,
+ FIELDTYPE *type,
+ ...)
+ { return(*(int *)0); }
+
+#undef field_type
+FIELDTYPE *field_type(
+ const FIELD *field)
+ { return(*(FIELDTYPE **)0); }
+
+/* ./fld_user.c */
+
+#undef set_field_userptr
+int set_field_userptr(
+ FIELD *field,
+ void *usrptr)
+ { return(*(int *)0); }
+
+#undef field_userptr
+void *field_userptr(
+ const FIELD *field)
+ { return(*(void **)0); }
+
+/* ./frm_cursor.c */
+
+#undef pos_form_cursor
+int pos_form_cursor(
+ FORM *form)
+ { return(*(int *)0); }
+
+/* ./frm_data.c */
+
+#undef data_behind
+bool data_behind(
+ const FORM *form)
+ { return(*(bool *)0); }
+
+#undef data_ahead
+bool data_ahead(
+ const FORM *form)
+ { return(*(bool *)0); }
+
+/* ./frm_def.c */
+
+#undef _nc_Default_Form
+FORM *_nc_Default_Form;
+
+#undef new_form
+FORM *new_form(
+ FIELD **fields)
+ { return(*(FORM **)0); }
+
+#undef free_form
+int free_form(
+ FORM *form)
+ { return(*(int *)0); }
+
+#undef set_form_fields
+int set_form_fields(
+ FORM *form,
+ FIELD **fields)
+ { return(*(int *)0); }
+
+#undef form_fields
+FIELD **form_fields(
+ const FORM *form)
+ { return(*(FIELD ***)0); }
+
+#undef field_count
+int field_count(
+ const FORM *form)
+ { return(*(int *)0); }
+
+/* ./frm_driver.c */
+
+#undef _nc_Position_Form_Cursor
+int _nc_Position_Form_Cursor(
+ FORM *form)
+ { return(*(int *)0); }
+
+#undef _nc_Refresh_Current_Field
+int _nc_Refresh_Current_Field(
+ FORM *form)
+ { return(*(int *)0); }
+
+#undef _nc_Synchronize_Attributes
+int _nc_Synchronize_Attributes(
+ FIELD *field)
+ { return(*(int *)0); }
+
+#undef _nc_Synchronize_Options
+int _nc_Synchronize_Options(
+ FIELD *field,
+ Field_Options newopts)
+ { return(*(int *)0); }
+
+#undef _nc_Set_Current_Field
+int _nc_Set_Current_Field(
+ FORM *form,
+ FIELD *newfield)
+ { return(*(int *)0); }
+
+#undef _nc_Internal_Validation
+bool _nc_Internal_Validation(
+ FORM *form)
+ { return(*(bool *)0); }
+
+#undef _nc_First_Active_Field
+FIELD *_nc_First_Active_Field(
+ FORM *form)
+ { return(*(FIELD **)0); }
+
+#undef _nc_Set_Form_Page
+int _nc_Set_Form_Page(
+ FORM *form,
+ int page,
+ FIELD *field)
+ { return(*(int *)0); }
+
+typedef struct {
+ int keycode;
+ int (*cmd)(FORM *);
+} Binding_Info;
+
+#undef form_driver
+int form_driver(
+ FORM *form,
+ int c)
+ { return(*(int *)0); }
+
+#undef set_field_buffer
+int set_field_buffer(
+ FIELD *field,
+ int buffer,
+ const char *value)
+ { return(*(int *)0); }
+
+#undef field_buffer
+char *field_buffer(
+ const FIELD *field,
+ int buffer)
+ { return(*(char **)0); }
+
+/* ./frm_hook.c */
+
+#undef set_field_init
+int set_field_init(
+ FORM *form,
+ Form_Hook func)
+ { return(*(int *)0); }
+
+#undef field_init
+Form_Hook field_init(
+ const FORM *form)
+ { return(*(Form_Hook *)0); }
+
+#undef set_field_term
+int set_field_term(
+ FORM *form,
+ Form_Hook func)
+ { return(*(int *)0); }
+
+#undef field_term
+Form_Hook field_term(
+ const FORM *form)
+ { return(*(Form_Hook *)0); }
+
+#undef set_form_init
+int set_form_init(
+ FORM *form,
+ Form_Hook func)
+ { return(*(int *)0); }
+
+#undef form_init
+Form_Hook form_init(
+ const FORM *form)
+ { return(*(Form_Hook *)0); }
+
+#undef set_form_term
+int set_form_term(
+ FORM *form,
+ Form_Hook func)
+ { return(*(int *)0); }
+
+#undef form_term
+Form_Hook form_term(
+ const FORM *form)
+ { return(*(Form_Hook *)0); }
+
+/* ./frm_opts.c */
+
+#undef set_form_opts
+int set_form_opts(
+ FORM *form,
+ Form_Options opts)
+ { return(*(int *)0); }
+
+#undef form_opts
+Form_Options form_opts(
+ const FORM *form)
+ { return(*(Form_Options *)0); }
+
+#undef form_opts_on
+int form_opts_on(
+ FORM *form,
+ Form_Options opts)
+ { return(*(int *)0); }
+
+#undef form_opts_off
+int form_opts_off(
+ FORM *form,
+ Form_Options opts)
+ { return(*(int *)0); }
+
+/* ./frm_page.c */
+
+#undef set_form_page
+int set_form_page(
+ FORM *form,
+ int page)
+ { return(*(int *)0); }
+
+#undef form_page
+int form_page(
+ const FORM *form)
+ { return(*(int *)0); }
+
+/* ./frm_post.c */
+
+#undef post_form
+int post_form(
+ FORM *form)
+ { return(*(int *)0); }
+
+#undef unpost_form
+int unpost_form(
+ FORM *form)
+ { return(*(int *)0); }
+
+/* ./frm_req_name.c */
+
+#undef form_request_name
+const char *form_request_name(
+ int request)
+ { return(*(const char **)0); }
+
+#undef form_request_by_name
+int form_request_by_name(
+ const char *str)
+ { return(*(int *)0); }
+
+/* ./frm_scale.c */
+
+#undef scale_form
+int scale_form(
+ const FORM *form,
+ int *rows,
+ int *cols)
+ { return(*(int *)0); }
+
+/* ./frm_sub.c */
+
+#undef set_form_sub
+int set_form_sub(
+ FORM *form,
+ WINDOW *win)
+ { return(*(int *)0); }
+
+#undef form_sub
+WINDOW *form_sub(
+ const FORM *form)
+ { return(*(WINDOW **)0); }
+
+/* ./frm_user.c */
+
+#undef set_form_userptr
+int set_form_userptr(
+ FORM *form,
+ void *usrptr)
+ { return(*(int *)0); }
+
+#undef form_userptr
+void *form_userptr(
+ const FORM *form)
+ { return(*(void **)0); }
+
+/* ./frm_win.c */
+
+#undef set_form_win
+int set_form_win(
+ FORM *form,
+ WINDOW *win)
+ { return(*(int *)0); }
+
+#undef form_win
+WINDOW *form_win(
+ const FORM *form)
+ { return(*(WINDOW **)0); }
+
+/* ./fty_alnum.c */
+
+typedef struct {
+ int width;
+} alnumARG;
+
+#undef TYPE_ALNUM
+FIELDTYPE *TYPE_ALNUM;
+
+/* ./fty_alpha.c */
+
+typedef struct {
+ int width;
+} alphaARG;
+
+#undef TYPE_ALPHA
+FIELDTYPE *TYPE_ALPHA;
+
+/* ./fty_enum.c */
+
+typedef struct {
+ char **kwds;
+ int count;
+ bool checkcase;
+ bool checkunique;
+} enumARG;
+
+#undef TYPE_ENUM
+FIELDTYPE *TYPE_ENUM;
+
+/* ./fty_int.c */
+
+typedef struct {
+ int precision;
+ long low;
+ long high;
+} integerARG;
+
+#undef TYPE_INTEGER
+FIELDTYPE *TYPE_INTEGER;
+
+/* ./fty_ipv4.c */
+#undef TYPE_IPV4
+FIELDTYPE *TYPE_IPV4;
+
+/* ./fty_num.c */
+
+#include <locale.h>
+
+typedef struct {
+ int precision;
+ double low;
+ double high;
+ struct lconv* L;
+} numericARG;
+
+#undef TYPE_NUMERIC
+FIELDTYPE *TYPE_NUMERIC;
+
+/* ./fty_regex.c */
+
+#include <regex.h>
+
+typedef struct
+{
+ regex_t *pRegExp;
+ unsigned long *refCount;
+} RegExp_Arg;
+
+#undef TYPE_REGEXP
+FIELDTYPE *TYPE_REGEXP;
diff --git a/Source/CursesDialog/form/mf_common.h b/Source/CursesDialog/form/mf_common.h
new file mode 100644
index 0000000..6b1e8fe
--- /dev/null
+++ b/Source/CursesDialog/form/mf_common.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+ * Copyright (c) 1998,2000 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+/* Common internal header for menu and form library */
+
+#if HAVE_CONFIG_H
+# include <ncurses_cfg.h>
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#if DECL_ERRNO
+extern int errno;
+#endif
+
+/* in case of debug version we ignore the suppression of assertions */
+#ifdef TRACE
+# ifdef NDEBUG
+# undef NDEBUG
+# endif
+#endif
+
+#include <nc_alloc.h>
+
+#if USE_RCS_IDS
+#define MODULE_ID(id) static const char Ident[] = id;
+#else
+#define MODULE_ID(id) /*nothing*/
+#endif
+
+
+/* Maximum regular 8-bit character code */
+#define MAX_REGULAR_CHARACTER (0xff)
+
+#define SET_ERROR(code) (errno=(code))
+#define GET_ERROR() (errno)
+#define RETURN(code) return( SET_ERROR(code) )
+
+/* The few common values in the status fields for menus and forms */
+#define _POSTED (0x01) /* menu or form is posted */
+#define _IN_DRIVER (0x02) /* menu or form is processing hook routine */
+
+/* Call object hook */
+#define Call_Hook( object, handler ) \
+ if ( (object) && ((object)->handler) )\
+ {\
+ (object)->status |= _IN_DRIVER;\
+ (object)->handler(object);\
+ (object)->status &= ~_IN_DRIVER;\
+ }
+
+#define INLINE
+
+#ifndef TRACE
+# if CC_HAS_INLINE_FUNCS
+# undef INLINE
+# define INLINE inline
+# endif
+#endif
diff --git a/Source/CursesDialog/form/nc_alloc.h b/Source/CursesDialog/form/nc_alloc.h
new file mode 100644
index 0000000..f49ea93
--- /dev/null
+++ b/Source/CursesDialog/form/nc_alloc.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * 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 AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Thomas E. Dickey <dickey@clark.net> 1996,1997 *
+ ****************************************************************************/
+/* $Id$ */
+
+#ifndef NC_ALLOC_included
+#define NC_ALLOC_included 1
+
+#if HAVE_LIBDMALLOC
+#include <dmalloc.h> /* Gray Watson's library */
+#else
+#undef HAVE_LIBDMALLOC
+#define HAVE_LIBDMALLOC 0
+#endif
+
+#if HAVE_LIBDBMALLOC
+#include <dbmalloc.h> /* Conor Cahill's library */
+#else
+#undef HAVE_LIBDBMALLOC
+#define HAVE_LIBDBMALLOC 0
+#endif
+
+#ifndef NO_LEAKS
+#define NO_LEAKS 0
+#endif
+
+#if HAVE_LIBDBMALLOC || HAVE_LIBDMALLOC || NO_LEAKS
+#define HAVE_NC_FREEALL 1
+struct termtype;
+extern void _nc_free_and_exit(int) GCC_NORETURN;
+extern void _nc_free_tparm(void);
+extern void _nc_leaks_dump_entry(void);
+#define ExitProgram(code) _nc_free_and_exit(code)
+#endif
+
+#ifndef HAVE_NC_FREEALL
+#define HAVE_NC_FREEALL 0
+#endif
+
+#ifndef ExitProgram
+#define ExitProgram(code) return code
+#endif
+
+/* doalloc.c */
+extern void *_nc_doalloc(void *, size_t);
+#if !HAVE_STRDUP
+/* #define strdup _nc_strdup */
+extern char *_nc_strdup(const char *);
+#endif
+
+#define typeMalloc(type,elts) (type *)malloc((elts)*sizeof(type))
+#define typeCalloc(type,elts) (type *)calloc((elts),sizeof(type))
+#define typeRealloc(type,elts,ptr) (type *)_nc_doalloc(ptr, (elts)*sizeof(type))
+
+#endif /* NC_ALLOC_included */
diff --git a/Source/Modules/FindJsonCpp.cmake b/Source/Modules/FindJsonCpp.cmake
new file mode 100644
index 0000000..014d3bd
--- /dev/null
+++ b/Source/Modules/FindJsonCpp.cmake
@@ -0,0 +1,117 @@
+#[=======================================================================[.rst:
+FindJsonCpp
+-----------
+
+Find JsonCpp includes and library.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+An :ref:`imported target <Imported targets>` named
+``JsonCpp::JsonCpp`` is provided if JsonCpp has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``JsonCpp_FOUND``
+ True if JsonCpp was found, false otherwise.
+``JsonCpp_INCLUDE_DIRS``
+ Include directories needed to include JsonCpp headers.
+``JsonCpp_LIBRARIES``
+ Libraries needed to link to JsonCpp.
+``JsonCpp_VERSION_STRING``
+ The version of JsonCpp found.
+ May not be set for JsonCpp versions prior to 1.0.
+``JsonCpp_VERSION_MAJOR``
+ The major version of JsonCpp.
+``JsonCpp_VERSION_MINOR``
+ The minor version of JsonCpp.
+``JsonCpp_VERSION_PATCH``
+ The patch version of JsonCpp.
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+This module uses the following cache variables:
+
+``JsonCpp_LIBRARY``
+ The location of the JsonCpp library file.
+``JsonCpp_INCLUDE_DIR``
+ The location of the JsonCpp include directory containing ``json/json.h``.
+
+The cache variables should not be used by project code.
+They may be set by end users to point at JsonCpp components.
+#]=======================================================================]
+
+#=============================================================================
+# Copyright 2014-2015 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+#-----------------------------------------------------------------------------
+find_library(JsonCpp_LIBRARY
+ NAMES jsoncpp
+ )
+mark_as_advanced(JsonCpp_LIBRARY)
+
+find_path(JsonCpp_INCLUDE_DIR
+ NAMES json/json.h
+ PATH_SUFFIXES jsoncpp
+ )
+mark_as_advanced(JsonCpp_INCLUDE_DIR)
+
+#-----------------------------------------------------------------------------
+# Extract version number if possible.
+set(_JsonCpp_H_REGEX "^#[ \t]*define[ \t]+JSONCPP_VERSION_STRING[ \t]+\"(([0-9]+)\\.([0-9]+)\\.([0-9]+)[^\"]*)\".*$")
+if(JsonCpp_INCLUDE_DIR AND EXISTS "${JsonCpp_INCLUDE_DIR}/json/version.h")
+ file(STRINGS "${JsonCpp_INCLUDE_DIR}/json/version.h" _JsonCpp_H REGEX "${_JsonCpp_H_REGEX}")
+else()
+ set(_JsonCpp_H "")
+endif()
+if(_JsonCpp_H MATCHES "${_JsonCpp_H_REGEX}")
+ set(JsonCpp_VERSION_STRING "${CMAKE_MATCH_1}")
+ set(JsonCpp_VERSION_MAJOR "${CMAKE_MATCH_2}")
+ set(JsonCpp_VERSION_MINOR "${CMAKE_MATCH_3}")
+ set(JsonCpp_VERSION_PATCH "${CMAKE_MATCH_4}")
+else()
+ set(JsonCpp_VERSION_STRING "")
+ set(JsonCpp_VERSION_MAJOR "")
+ set(JsonCpp_VERSION_MINOR "")
+ set(JsonCpp_VERSION_PATCH "")
+endif()
+unset(_JsonCpp_H_REGEX)
+unset(_JsonCpp_H)
+
+#-----------------------------------------------------------------------------
+include(${CMAKE_CURRENT_LIST_DIR}/../../Modules/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(JsonCpp
+ FOUND_VAR JsonCpp_FOUND
+ REQUIRED_VARS JsonCpp_LIBRARY JsonCpp_INCLUDE_DIR
+ VERSION_VAR JsonCpp_VERSION_STRING
+ )
+set(JSONCPP_FOUND ${JsonCpp_FOUND})
+
+#-----------------------------------------------------------------------------
+# Provide documented result variables and targets.
+if(JsonCpp_FOUND)
+ set(JsonCpp_INCLUDE_DIRS ${JsonCpp_INCLUDE_DIR})
+ set(JsonCpp_LIBRARIES ${JsonCpp_LIBRARY})
+ if(NOT TARGET JsonCpp::JsonCpp)
+ add_library(JsonCpp::JsonCpp UNKNOWN IMPORTED)
+ set_target_properties(JsonCpp::JsonCpp PROPERTIES
+ IMPORTED_LOCATION "${JsonCpp_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${JsonCpp_INCLUDE_DIRS}"
+ IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
+ )
+ endif()
+endif()
diff --git a/Source/QtDialog/AddCacheEntry.cxx b/Source/QtDialog/AddCacheEntry.cxx
new file mode 100644
index 0000000..dc7a4b0
--- /dev/null
+++ b/Source/QtDialog/AddCacheEntry.cxx
@@ -0,0 +1,108 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "AddCacheEntry.h"
+
+#include <QCompleter>
+#include <QMetaProperty>
+
+static const int NumTypes = 4;
+static const int DefaultTypeIndex = 0;
+static const QByteArray TypeStrings[NumTypes] = { "BOOL", "PATH", "FILEPATH",
+ "STRING" };
+static const QCMakeProperty::PropertyType Types[NumTypes] = {
+ QCMakeProperty::BOOL, QCMakeProperty::PATH, QCMakeProperty::FILEPATH,
+ QCMakeProperty::STRING
+};
+
+AddCacheEntry::AddCacheEntry(QWidget* p, const QStringList& varNames,
+ const QStringList& varTypes)
+ : QWidget(p)
+ , VarNames(varNames)
+ , VarTypes(varTypes)
+{
+ this->setupUi(this);
+ for (int i = 0; i < NumTypes; i++) {
+ this->Type->addItem(TypeStrings[i]);
+ }
+ QWidget* cb = new QCheckBox();
+ QWidget* path = new QCMakePathEditor();
+ QWidget* filepath = new QCMakeFilePathEditor();
+ QWidget* string = new QLineEdit();
+ this->StackedWidget->addWidget(cb);
+ this->StackedWidget->addWidget(path);
+ this->StackedWidget->addWidget(filepath);
+ this->StackedWidget->addWidget(string);
+ this->setTabOrder(this->Name, this->Type);
+ this->setTabOrder(this->Type, cb);
+ this->setTabOrder(cb, path);
+ this->setTabOrder(path, filepath);
+ this->setTabOrder(filepath, string);
+ this->setTabOrder(string, this->Description);
+ QCompleter* completer = new QCompleter(this->VarNames, this);
+ this->Name->setCompleter(completer);
+ connect(completer, SIGNAL(activated(const QString&)), this,
+ SLOT(onCompletionActivated(const QString&)));
+}
+
+QString AddCacheEntry::name() const
+{
+ return this->Name->text();
+}
+
+QVariant AddCacheEntry::value() const
+{
+ QWidget* w = this->StackedWidget->currentWidget();
+ if (qobject_cast<QLineEdit*>(w)) {
+ return static_cast<QLineEdit*>(w)->text();
+ } else if (qobject_cast<QCheckBox*>(w)) {
+ return static_cast<QCheckBox*>(w)->isChecked();
+ }
+ return QVariant();
+}
+
+QString AddCacheEntry::description() const
+{
+ return this->Description->text();
+}
+
+QCMakeProperty::PropertyType AddCacheEntry::type() const
+{
+ int idx = this->Type->currentIndex();
+ if (idx >= 0 && idx < NumTypes) {
+ return Types[idx];
+ }
+ return Types[DefaultTypeIndex];
+}
+
+QString AddCacheEntry::typeString() const
+{
+ int idx = this->Type->currentIndex();
+ if (idx >= 0 && idx < NumTypes) {
+ return TypeStrings[idx];
+ }
+ return TypeStrings[DefaultTypeIndex];
+}
+
+void AddCacheEntry::onCompletionActivated(const QString& text)
+{
+ int idx = this->VarNames.indexOf(text);
+ if (idx != -1) {
+ QString vartype = this->VarTypes[idx];
+ for (int i = 0; i < NumTypes; i++) {
+ if (TypeStrings[i] == vartype) {
+ this->Type->setCurrentIndex(i);
+ break;
+ }
+ }
+ }
+}
diff --git a/Source/QtDialog/AddCacheEntry.h b/Source/QtDialog/AddCacheEntry.h
new file mode 100644
index 0000000..05469af
--- /dev/null
+++ b/Source/QtDialog/AddCacheEntry.h
@@ -0,0 +1,45 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef AddCacheEntry_h
+#define AddCacheEntry_h
+
+#include "QCMake.h"
+
+#include <QCheckBox>
+#include <QStringList>
+#include <QWidget>
+
+#include "ui_AddCacheEntry.h"
+
+class AddCacheEntry : public QWidget, public Ui::AddCacheEntry
+{
+ Q_OBJECT
+public:
+ AddCacheEntry(QWidget* p, const QStringList& varNames,
+ const QStringList& varTypes);
+
+ QString name() const;
+ QVariant value() const;
+ QString description() const;
+ QCMakeProperty::PropertyType type() const;
+ QString typeString() const;
+
+private slots:
+ void onCompletionActivated(const QString& text);
+
+private:
+ const QStringList& VarNames;
+ const QStringList& VarTypes;
+};
+
+#endif
diff --git a/Source/QtDialog/AddCacheEntry.ui b/Source/QtDialog/AddCacheEntry.ui
new file mode 100644
index 0000000..a815874
--- /dev/null
+++ b/Source/QtDialog/AddCacheEntry.ui
@@ -0,0 +1,97 @@
+<ui version="4.0" >
+ <class>AddCacheEntry</class>
+ <widget class="QWidget" name="AddCacheEntry" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>380</width>
+ <height>158</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="Name" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Type:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="Type" >
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>Value:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QStackedWidget" name="StackedWidget" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Description:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLineEdit" name="Description" />
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QCMakePathEditor</class>
+ <extends>QLineEdit</extends>
+ <header>QCMakeWidgets.h</header>
+ </customwidget>
+ <customwidget>
+ <class>QCMakeFilePathEditor</class>
+ <extends>QLineEdit</extends>
+ <header>QCMakeWidgets.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>Type</sender>
+ <signal>currentIndexChanged(int)</signal>
+ <receiver>StackedWidget</receiver>
+ <slot>setCurrentIndex(int)</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>229</x>
+ <y>34</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>287</x>
+ <y>65</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Source/QtDialog/CMake.desktop b/Source/QtDialog/CMake.desktop
new file mode 100644
index 0000000..842091f
--- /dev/null
+++ b/Source/QtDialog/CMake.desktop
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Version=1.0
+Name=CMake
+Comment=Cross-platform buildsystem
+Exec=cmake-gui %f
+Icon=CMakeSetup
+Terminal=false
+X-MultipleArgs=false
+Type=Application
+Categories=Development;
+StartupNotify=true
+MimeType=application/x-cmakecache;
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
new file mode 100644
index 0000000..80c0dc0
--- /dev/null
+++ b/Source/QtDialog/CMakeLists.txt
@@ -0,0 +1,241 @@
+#=============================================================================
+# CMake - Cross Platform Makefile Generator
+# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+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)
+ include_directories(${Qt5Widgets_INCLUDE_DIRS})
+ add_definitions(${Qt5Widgets_DEFINITONS})
+ macro(qt4_wrap_ui)
+ qt5_wrap_ui(${ARGN})
+ endmacro()
+ macro(qt4_wrap_cpp)
+ qt5_wrap_cpp(${ARGN})
+ endmacro()
+ macro(qt4_add_resources)
+ qt5_add_resources(${ARGN})
+ endmacro()
+ set(CMake_QT_LIBRARIES ${Qt5Widgets_LIBRARIES})
+ set(QT_QTMAIN_LIBRARY ${Qt5Core_QTMAIN_LIBRARIES})
+
+ # Remove this when the minimum version of Qt is 4.6.
+ add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0)
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
+
+ if(CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES)
+ list(APPEND CMake_QT_LIBRARIES ${CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES})
+ set_property(SOURCE CMakeSetup.cxx
+ PROPERTY COMPILE_DEFINITIONS USE_QXcbIntegrationPlugin)
+ endif()
+
+ # We need to install platform plugin and add qt.conf for Qt5 on Mac and Windows.
+ # FIXME: This should be part of Qt5 CMake scripts, but unfortunatelly
+ # Qt5 support is missing there.
+ if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
+ macro(install_qt5_plugin _qt_plugin_name _qt_plugins_var)
+ get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION)
+ if(EXISTS "${_qt_plugin_path}")
+ get_filename_component(_qt_plugin_file "${_qt_plugin_path}" NAME)
+ get_filename_component(_qt_plugin_type "${_qt_plugin_path}" PATH)
+ get_filename_component(_qt_plugin_type "${_qt_plugin_type}" NAME)
+ if(APPLE)
+ set(_qt_plugin_dir "PlugIns")
+ elseif(WIN32)
+ set(_qt_plugin_dir "plugins")
+ endif()
+ set(_qt_plugin_dest "${_qt_plugin_dir}/${_qt_plugin_type}")
+ install(FILES "${_qt_plugin_path}"
+ DESTINATION "${_qt_plugin_dest}"
+ ${COMPONENT})
+ set(${_qt_plugins_var}
+ "${${_qt_plugins_var}};\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${_qt_plugin_dest}/${_qt_plugin_file}")
+ else()
+ message(FATAL_ERROR "QT plugin ${_qt_plugin_name} not found")
+ endif()
+ endmacro()
+ if(APPLE)
+ install_qt5_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS)
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
+ "[Paths]\nPlugins = ${_qt_plugin_dir}\n")
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/Resources"
+ ${COMPONENT})
+ elseif(WIN32)
+ install_qt5_plugin("Qt5::QWindowsIntegrationPlugin" QT_PLUGINS)
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
+ "[Paths]\nPlugins = ../${_qt_plugin_dir}\n")
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
+ DESTINATION bin
+ ${COMPONENT})
+ endif()
+ endif()
+
+ if(TARGET Qt5::Core)
+ get_property(_Qt5_Core_LOCATION TARGET Qt5::Core PROPERTY LOCATION)
+ get_filename_component(Qt_BIN_DIR "${_Qt5_Core_LOCATION}" PATH)
+ if(APPLE)
+ get_filename_component(Qt_BIN_DIR "${Qt_BIN_DIR}" PATH)
+ endif()
+ endif()
+else()
+ set(QT_MIN_VERSION "4.4.0")
+ find_package(Qt4 REQUIRED)
+ if(NOT QT4_FOUND)
+ message(SEND_ERROR "Failed to find Qt 4.4 or greater.")
+ return()
+ endif()
+
+ include(${QT_USE_FILE})
+
+ set(CMake_QT_LIBRARIES ${QT_LIBRARIES})
+
+endif()
+
+set(SRCS
+ AddCacheEntry.cxx
+ AddCacheEntry.h
+ CMakeSetup.cxx
+ CMakeSetupDialog.cxx
+ CMakeSetupDialog.h
+ FirstConfigure.cxx
+ FirstConfigure.h
+ QCMake.cxx
+ QCMake.h
+ QCMakeCacheView.cxx
+ QCMakeCacheView.h
+ QCMakeWidgets.cxx
+ QCMakeWidgets.h
+ RegexExplorer.cxx
+ RegexExplorer.h
+ WarningMessagesDialog.cxx
+ WarningMessagesDialog.h
+ )
+QT4_WRAP_UI(UI_SRCS
+ CMakeSetupDialog.ui
+ Compilers.ui
+ CrossCompiler.ui
+ AddCacheEntry.ui
+ RegexExplorer.ui
+ WarningMessagesDialog.ui
+ )
+QT4_WRAP_CPP(MOC_SRCS
+ AddCacheEntry.h
+ Compilers.h
+ CMakeSetupDialog.h
+ FirstConfigure.h
+ QCMake.h
+ QCMakeCacheView.h
+ QCMakeWidgets.h
+ RegexExplorer.h
+ WarningMessagesDialog.h
+ )
+QT4_ADD_RESOURCES(RC_SRCS CMakeSetup.qrc)
+
+set(SRCS ${SRCS} ${UI_SRCS} ${MOC_SRCS} ${RC_SRCS})
+if(WIN32)
+ set(SRCS ${SRCS} CMakeSetup.rc)
+endif()
+if(APPLE)
+ set(SRCS ${SRCS} CMakeSetup.icns)
+ set(MACOSX_BUNDLE_ICON_FILE CMakeSetup.icns)
+ set_source_files_properties(CMakeSetup.icns PROPERTIES
+ MACOSX_PACKAGE_LOCATION Resources)
+endif()
+
+if(USE_LGPL)
+ install(FILES ${CMake_SOURCE_DIR}/Licenses/LGPLv${USE_LGPL}.txt
+ DESTINATION ${CMAKE_DATA_DIR}/Licenses
+ ${COMPONENT})
+ set_property(SOURCE CMakeSetupDialog.cxx
+ PROPERTY COMPILE_DEFINITIONS USE_LGPL="${USE_LGPL}")
+endif()
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(cmake-gui WIN32 MACOSX_BUNDLE ${SRCS} ${MANIFEST_FILE})
+target_link_libraries(cmake-gui CMakeLib ${QT_QTMAIN_LIBRARY} ${CMake_QT_LIBRARIES})
+
+if(APPLE)
+ file(STRINGS "${CMake_SOURCE_DIR}/Copyright.txt" copyright_line
+ LIMIT_COUNT 1 REGEX "^Copyright 2000-20[0-9][0-9] Kitware")
+
+ set_target_properties(cmake-gui PROPERTIES
+ OUTPUT_NAME CMake
+ MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in"
+ MACOSX_BUNDLE_SHORT_VERSION_STRING "${CMAKE_BUNDLE_VERSION}"
+ # TBD: MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_BUNDLE_VERSION}"
+ MACOSX_BUNDLE_COPYRIGHT "${copyright_line}"
+ MACOSX_BUNDLE_GUI_IDENTIFIER "org.cmake.cmake"
+ )
+
+ # Create a symlink in the build tree to provide a "cmake-gui" next
+ # to the "cmake" executable that refers to the application bundle.
+ add_custom_command(TARGET cmake-gui POST_BUILD
+ COMMAND ln -sf CMake.app/Contents/MacOS/CMake
+ $<TARGET_FILE_DIR:cmake>/cmake-gui
+ )
+endif()
+set(CMAKE_INSTALL_DESTINATION_ARGS
+ BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}" ${COMPONENT})
+
+install(TARGETS cmake-gui
+ RUNTIME DESTINATION bin ${COMPONENT}
+ ${CMAKE_INSTALL_DESTINATION_ARGS})
+
+if(UNIX AND NOT APPLE)
+ foreach (size IN ITEMS 32 128)
+ install(
+ FILES "${CMAKE_CURRENT_SOURCE_DIR}/CMakeSetup${size}.png"
+ DESTINATION "${CMAKE_XDGDATA_DIR}/icons/hicolor/${size}x${size}/apps"
+ ${COMPONENT}
+ RENAME "CMakeSetup.png")
+ endforeach ()
+
+ # install a desktop file so CMake appears in the application start menu
+ # with an icon
+ install(FILES CMake.desktop
+ DESTINATION "${CMAKE_XDGDATA_DIR}/applications"
+ ${COMPONENT})
+ install(FILES cmakecache.xml
+ DESTINATION "${CMAKE_XDGDATA_DIR}/mime/packages"
+ ${COMPONENT})
+endif()
+
+if(APPLE)
+ install(CODE "
+ execute_process(COMMAND ln -s \"../MacOS/CMake\" cmake-gui
+ WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/bin)
+ " ${COMPONENT})
+endif()
+
+if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
+ # install rules for including 3rd party libs such as Qt
+ # if a system Qt is used (e.g. installed in /usr/lib/), it will not be included in the installation
+ set(fixup_exe "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/bin/cmake-gui${CMAKE_EXECUTABLE_SUFFIX}")
+ if(APPLE)
+ set(fixup_exe "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/MacOS/CMake")
+ endif()
+ install(CODE "
+ include(\"${CMake_SOURCE_DIR}/Modules/BundleUtilities.cmake\")
+ set(BU_CHMOD_BUNDLE_ITEMS ON)
+ fixup_bundle(\"${fixup_exe}\" \"${QT_PLUGINS}\" \"${Qt_BIN_DIR};${QT_LIBRARY_DIR};${QT_BINARY_DIR}\")
+ " ${COMPONENT})
+endif()
+
+set(CMAKE_PACKAGE_QTGUI TRUE)
+configure_file("${QtDialog_SOURCE_DIR}/QtDialogCPack.cmake.in"
+ "${QtDialog_BINARY_DIR}/QtDialogCPack.cmake" @ONLY)
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
new file mode 100644
index 0000000..ff3a7b2
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup.cxx
@@ -0,0 +1,257 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "QCMake.h" // include to disable MS warnings
+
+#include "CMakeSetupDialog.h"
+#include "cmAlgorithms.h"
+#include "cmDocumentation.h"
+#include "cmVersion.h"
+#include "cmake.h"
+#include <QApplication>
+#include <QDir>
+#include <QLocale>
+#include <QString>
+#include <QtPlugin>
+#include <QTextCodec>
+#include <QTranslator>
+#include <cmsys/CommandLineArguments.hxx>
+#include <cmsys/Encoding.hxx>
+#include <cmsys/SystemTools.hxx>
+
+static const char* cmDocumentationName[][2] = { { 0,
+ " cmake-gui - CMake GUI." },
+ { 0, 0 } };
+
+static const char* cmDocumentationUsage[][2] = {
+ { 0, " cmake-gui [options]\n"
+ " cmake-gui [options] <path-to-source>\n"
+ " cmake-gui [options] <path-to-existing-build>" },
+ { 0, 0 }
+};
+
+static const char* cmDocumentationOptions[][2] = { { 0, 0 } };
+
+#if defined(Q_OS_MAC)
+static int cmOSXInstall(std::string dir);
+static void cmAddPluginPath();
+#endif
+
+#if defined(USE_QXcbIntegrationPlugin)
+Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
+#endif
+
+int main(int argc, char** argv)
+{
+ cmsys::Encoding::CommandLineArguments encoding_args =
+ cmsys::Encoding::CommandLineArguments::Main(argc, argv);
+ int argc2 = encoding_args.argc();
+ char const* const* argv2 = encoding_args.argv();
+
+ cmSystemTools::FindCMakeResources(argv2[0]);
+ // check docs first so that X is not need to get docs
+ // do docs, if args were given
+ cmDocumentation doc;
+ doc.addCMakeStandardDocSections();
+ if (argc2 > 1 && doc.CheckOptions(argc2, argv2)) {
+ // Construct and print requested documentation.
+ cmake hcm;
+ hcm.SetHomeDirectory("");
+ hcm.SetHomeOutputDirectory("");
+ hcm.AddCMakePaths();
+
+ std::vector<cmDocumentationEntry> generators;
+ hcm.GetGeneratorDocumentation(generators);
+ doc.SetName("cmake");
+ doc.SetSection("Name", cmDocumentationName);
+ doc.SetSection("Usage", cmDocumentationUsage);
+ doc.AppendSection("Generators", generators);
+ doc.PrependSection("Options", cmDocumentationOptions);
+
+ return (doc.PrintRequestedDocumentation(std::cout) ? 0 : 1);
+ }
+
+#if defined(Q_OS_MAC)
+ if (argc2 == 2 && strcmp(argv2[1], "--install") == 0) {
+ return cmOSXInstall("/usr/local/bin");
+ }
+ if (argc2 == 2 && cmHasLiteralPrefix(argv2[1], "--install=")) {
+ return cmOSXInstall(argv2[1] + 10);
+ }
+#endif
+
+// When we are on OSX and we are launching cmake-gui from a symlink, the
+// application will fail to launch as it can't find the qt.conf file which
+// tells it what the name of the plugin folder is. We need to add this path
+// BEFORE the application is constructed as that is what triggers the
+// searching for the platform plugins
+#if defined(Q_OS_MAC)
+ cmAddPluginPath();
+#endif
+
+ QApplication app(argc, argv);
+
+ setlocale(LC_NUMERIC, "C");
+
+#if defined(CMAKE_ENCODING_UTF8)
+ QTextCodec* utf8_codec = QTextCodec::codecForName("UTF-8");
+ QTextCodec::setCodecForLocale(utf8_codec);
+#endif
+
+ // clean out standard Qt paths for plugins, which we don't use anyway
+ // when creating Mac bundles, it potentially causes problems
+ foreach (QString p, QApplication::libraryPaths()) {
+ QApplication::removeLibraryPath(p);
+ }
+
+ // tell the cmake library where cmake is
+ QDir cmExecDir(QApplication::applicationDirPath());
+#if defined(Q_OS_MAC)
+ cmExecDir.cd("../../../");
+#endif
+
+ // pick up translation files if they exists in the data directory
+ QDir translationsDir = cmExecDir;
+ translationsDir.cd(QString::fromLocal8Bit(".." CMAKE_DATA_DIR));
+ translationsDir.cd("i18n");
+ QTranslator translator;
+ QString transfile = QString("cmake_%1").arg(QLocale::system().name());
+ translator.load(transfile, translationsDir.path());
+ app.installTranslator(&translator);
+
+ // app setup
+ app.setApplicationName("CMakeSetup");
+ app.setOrganizationName("Kitware");
+ QIcon appIcon;
+ appIcon.addFile(":/Icons/CMakeSetup32.png");
+ appIcon.addFile(":/Icons/CMakeSetup128.png");
+ app.setWindowIcon(appIcon);
+
+ CMakeSetupDialog dialog;
+ dialog.show();
+
+ cmsys::CommandLineArguments arg;
+ arg.Initialize(argc2, argv2);
+ std::string binaryDirectory;
+ std::string sourceDirectory;
+ typedef cmsys::CommandLineArguments argT;
+ arg.AddArgument("-B", argT::CONCAT_ARGUMENT, &binaryDirectory,
+ "Binary Directory");
+ arg.AddArgument("-H", argT::CONCAT_ARGUMENT, &sourceDirectory,
+ "Source Directory");
+ // do not complain about unknown options
+ arg.StoreUnusedArguments(true);
+ arg.Parse();
+ if (!sourceDirectory.empty() && !binaryDirectory.empty()) {
+ dialog.setSourceDirectory(QString::fromLocal8Bit(sourceDirectory.c_str()));
+ dialog.setBinaryDirectory(QString::fromLocal8Bit(binaryDirectory.c_str()));
+ } else {
+ QStringList args = app.arguments();
+ if (args.count() == 2) {
+ std::string filePath =
+ cmSystemTools::CollapseFullPath(args[1].toLocal8Bit().data());
+
+ // check if argument is a directory containing CMakeCache.txt
+ std::string buildFilePath =
+ cmSystemTools::CollapseFullPath("CMakeCache.txt", filePath.c_str());
+
+ // check if argument is a CMakeCache.txt file
+ if (cmSystemTools::GetFilenameName(filePath) == "CMakeCache.txt" &&
+ cmSystemTools::FileExists(filePath.c_str())) {
+ buildFilePath = filePath;
+ }
+
+ // check if argument is a directory containing CMakeLists.txt
+ std::string srcFilePath =
+ cmSystemTools::CollapseFullPath("CMakeLists.txt", filePath.c_str());
+
+ if (cmSystemTools::FileExists(buildFilePath.c_str())) {
+ dialog.setBinaryDirectory(QString::fromLocal8Bit(
+ cmSystemTools::GetFilenamePath(buildFilePath).c_str()));
+ } else if (cmSystemTools::FileExists(srcFilePath.c_str())) {
+ dialog.setSourceDirectory(QString::fromLocal8Bit(filePath.c_str()));
+ dialog.setBinaryDirectory(QString::fromLocal8Bit(
+ cmSystemTools::CollapseFullPath(".").c_str()));
+ }
+ }
+ }
+
+ return app.exec();
+}
+
+#if defined(Q_OS_MAC)
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+static bool cmOSXInstall(std::string const& dir, std::string const& tool)
+{
+ if (tool.empty()) {
+ return true;
+ }
+ std::string link = dir + cmSystemTools::GetFilenameName(tool);
+ struct stat st;
+ if (lstat(link.c_str(), &st) == 0 && S_ISLNK(st.st_mode)) {
+ char buf[4096];
+ ssize_t s = readlink(link.c_str(), buf, sizeof(buf) - 1);
+ if (s >= 0 && std::string(buf, s) == tool) {
+ std::cerr << "Exists: '" << link << "' -> '" << tool << "'\n";
+ return true;
+ }
+ }
+ cmSystemTools::MakeDirectory(dir);
+ if (symlink(tool.c_str(), link.c_str()) == 0) {
+ std::cerr << "Linked: '" << link << "' -> '" << tool << "'\n";
+ return true;
+ } else {
+ int err = errno;
+ std::cerr << "Failed: '" << link << "' -> '" << tool
+ << "': " << strerror(err) << "\n";
+ return false;
+ }
+}
+static int cmOSXInstall(std::string dir)
+{
+ if (!cmHasLiteralSuffix(dir, "/")) {
+ dir += "/";
+ }
+ return (cmOSXInstall(dir, cmSystemTools::GetCMakeCommand()) &&
+ cmOSXInstall(dir, cmSystemTools::GetCTestCommand()) &&
+ cmOSXInstall(dir, cmSystemTools::GetCPackCommand()) &&
+ cmOSXInstall(dir, cmSystemTools::GetCMakeGUICommand()) &&
+ cmOSXInstall(dir, cmSystemTools::GetCMakeCursesCommand()))
+ ? 0
+ : 1;
+}
+
+// Locate the PlugIns directory and add it to the QApplication library paths.
+// We need to resolve all symlinks so we have a known relative path between
+// MacOS/CMake and the PlugIns directory.
+//
+// Note we are using cmSystemTools since Qt can't provide the path to the
+// executable before the QApplication is created, and that is when plugin
+// searching occurs.
+static void cmAddPluginPath()
+{
+ std::string const& path = cmSystemTools::GetCMakeGUICommand();
+ if (path.empty()) {
+ return;
+ }
+ std::string const& realPath = cmSystemTools::GetRealPath(path);
+ QFileInfo appPath(QString::fromLocal8Bit(realPath.c_str()));
+ QDir pluginDir = appPath.dir();
+ bool const foundPluginDir = pluginDir.cd("../PlugIns");
+ if (foundPluginDir) {
+ QApplication::addLibraryPath(pluginDir.path());
+ }
+}
+
+#endif
diff --git a/Source/QtDialog/CMakeSetup.icns b/Source/QtDialog/CMakeSetup.icns
new file mode 100644
index 0000000..4a50c04
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup.icns
Binary files differ
diff --git a/Source/QtDialog/CMakeSetup.ico b/Source/QtDialog/CMakeSetup.ico
new file mode 100644
index 0000000..e13bb15
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup.ico
Binary files differ
diff --git a/Source/QtDialog/CMakeSetup.qrc b/Source/QtDialog/CMakeSetup.qrc
new file mode 100644
index 0000000..eaac192
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/Icons" >
+ <file>CMakeSetup128.png</file>
+ <file>CMakeSetup32.png</file>
+ <file>Delete16.png</file>
+ <file>Plus16.png</file>
+ </qresource>
+</RCC>
diff --git a/Source/QtDialog/CMakeSetup.rc b/Source/QtDialog/CMakeSetup.rc
new file mode 100644
index 0000000..fcc887d
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup.rc
@@ -0,0 +1 @@
+IDI_ICON1 ICON DISCARDABLE "CMakeSetup.ico"
diff --git a/Source/QtDialog/CMakeSetup128.png b/Source/QtDialog/CMakeSetup128.png
new file mode 100644
index 0000000..12f1d9a
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup128.png
Binary files differ
diff --git a/Source/QtDialog/CMakeSetup32.png b/Source/QtDialog/CMakeSetup32.png
new file mode 100644
index 0000000..7bbcee4
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup32.png
Binary files differ
diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx
new file mode 100644
index 0000000..fda3e58
--- /dev/null
+++ b/Source/QtDialog/CMakeSetupDialog.cxx
@@ -0,0 +1,1303 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "CMakeSetupDialog.h"
+
+#include <QCloseEvent>
+#include <QCoreApplication>
+#include <QDialogButtonBox>
+#include <QDragEnterEvent>
+#include <QFileDialog>
+#include <QInputDialog>
+#include <QKeySequence>
+#include <QMenu>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QMimeData>
+#include <QProgressBar>
+#include <QSettings>
+#include <QShortcut>
+#include <QStatusBar>
+#include <QToolButton>
+#include <QUrl>
+
+#include "AddCacheEntry.h"
+#include "FirstConfigure.h"
+#include "QCMake.h"
+#include "QCMakeCacheView.h"
+#include "RegexExplorer.h"
+#include "WarningMessagesDialog.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+QCMakeThread::QCMakeThread(QObject* p)
+ : QThread(p)
+ , CMakeInstance(NULL)
+{
+}
+
+QCMake* QCMakeThread::cmakeInstance() const
+{
+ return this->CMakeInstance;
+}
+
+void QCMakeThread::run()
+{
+ this->CMakeInstance = new QCMake;
+ // emit that this cmake thread is ready for use
+ emit this->cmakeInitialized();
+ this->exec();
+ delete this->CMakeInstance;
+ this->CMakeInstance = NULL;
+}
+
+CMakeSetupDialog::CMakeSetupDialog()
+ : ExitAfterGenerate(true)
+ , CacheModified(false)
+ , ConfigureNeeded(true)
+ , CurrentState(Interrupting)
+{
+ QString title = QString(tr("CMake %1"));
+ title = title.arg(cmVersion::GetCMakeVersion());
+ this->setWindowTitle(title);
+
+ // create the GUI
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+ restoreGeometry(settings.value("geometry").toByteArray());
+ restoreState(settings.value("windowState").toByteArray());
+
+ this->AddVariableNames =
+ settings.value("AddVariableNames", QStringList("CMAKE_INSTALL_PREFIX"))
+ .toStringList();
+ this->AddVariableTypes =
+ settings.value("AddVariableTypes", QStringList("PATH")).toStringList();
+
+ QWidget* cont = new QWidget(this);
+ this->setupUi(cont);
+ this->Splitter->setStretchFactor(0, 3);
+ this->Splitter->setStretchFactor(1, 1);
+ this->setCentralWidget(cont);
+ this->ProgressBar->reset();
+ this->RemoveEntry->setEnabled(false);
+ this->AddEntry->setEnabled(false);
+
+ QByteArray p = settings.value("SplitterSizes").toByteArray();
+ this->Splitter->restoreState(p);
+
+ bool groupView = settings.value("GroupView", false).toBool();
+ this->setGroupedView(groupView);
+ this->groupedCheck->setCheckState(groupView ? Qt::Checked : Qt::Unchecked);
+
+ bool advancedView = settings.value("AdvancedView", false).toBool();
+ this->setAdvancedView(advancedView);
+ this->advancedCheck->setCheckState(advancedView ? Qt::Checked
+ : Qt::Unchecked);
+
+ QMenu* FileMenu = this->menuBar()->addMenu(tr("&File"));
+ this->ReloadCacheAction = FileMenu->addAction(tr("&Reload Cache"));
+ QObject::connect(this->ReloadCacheAction, SIGNAL(triggered(bool)), this,
+ SLOT(doReloadCache()));
+ this->DeleteCacheAction = FileMenu->addAction(tr("&Delete Cache"));
+ QObject::connect(this->DeleteCacheAction, SIGNAL(triggered(bool)), this,
+ SLOT(doDeleteCache()));
+ this->ExitAction = FileMenu->addAction(tr("E&xit"));
+ this->ExitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
+ QObject::connect(this->ExitAction, SIGNAL(triggered(bool)), this,
+ SLOT(close()));
+
+ QMenu* ToolsMenu = this->menuBar()->addMenu(tr("&Tools"));
+ this->ConfigureAction = ToolsMenu->addAction(tr("&Configure"));
+ // prevent merging with Preferences menu item on Mac OS X
+ this->ConfigureAction->setMenuRole(QAction::NoRole);
+ QObject::connect(this->ConfigureAction, SIGNAL(triggered(bool)), this,
+ SLOT(doConfigure()));
+ this->GenerateAction = ToolsMenu->addAction(tr("&Generate"));
+ QObject::connect(this->GenerateAction, SIGNAL(triggered(bool)), this,
+ SLOT(doGenerate()));
+ QAction* showChangesAction = ToolsMenu->addAction(tr("&Show My Changes"));
+ QObject::connect(showChangesAction, SIGNAL(triggered(bool)), this,
+ SLOT(showUserChanges()));
+#if defined(Q_WS_MAC) || defined(Q_OS_MAC)
+ this->InstallForCommandLineAction =
+ ToolsMenu->addAction(tr("&How to Install For Command Line Use"));
+ QObject::connect(this->InstallForCommandLineAction, SIGNAL(triggered(bool)),
+ this, SLOT(doInstallForCommandLine()));
+#endif
+ ToolsMenu->addSeparator();
+ ToolsMenu->addAction(tr("Regular Expression Explorer..."), this,
+ SLOT(doRegexExplorerDialog()));
+ ToolsMenu->addSeparator();
+ ToolsMenu->addAction(tr("&Find in Output..."), this,
+ SLOT(doOutputFindDialog()), QKeySequence::Find);
+ ToolsMenu->addAction(tr("Find Next"), this, SLOT(doOutputFindNext()),
+ QKeySequence::FindNext);
+ ToolsMenu->addAction(tr("Find Previous"), this, SLOT(doOutputFindPrev()),
+ QKeySequence::FindPrevious);
+ ToolsMenu->addAction(tr("Goto Next Error"), this, SLOT(doOutputErrorNext()),
+ QKeySequence(Qt::Key_F8)); // in Visual Studio
+ new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Period), this,
+ SLOT(doOutputErrorNext())); // in Eclipse
+
+ QMenu* OptionsMenu = this->menuBar()->addMenu(tr("&Options"));
+ OptionsMenu->addAction(tr("Warning Messages..."), this,
+ SLOT(doWarningMessagesDialog()));
+ this->WarnUninitializedAction =
+ OptionsMenu->addAction(tr("&Warn Uninitialized (--warn-uninitialized)"));
+ this->WarnUninitializedAction->setCheckable(true);
+ this->WarnUnusedAction =
+ OptionsMenu->addAction(tr("&Warn Unused (--warn-unused-vars)"));
+ this->WarnUnusedAction->setCheckable(true);
+
+ QAction* debugAction = OptionsMenu->addAction(tr("&Debug Output"));
+ debugAction->setCheckable(true);
+ QObject::connect(debugAction, SIGNAL(toggled(bool)), this,
+ SLOT(setDebugOutput(bool)));
+
+ OptionsMenu->addSeparator();
+ QAction* expandAction =
+ OptionsMenu->addAction(tr("&Expand Grouped Entries"));
+ QObject::connect(expandAction, SIGNAL(triggered(bool)), this->CacheValues,
+ SLOT(expandAll()));
+ QAction* collapseAction =
+ OptionsMenu->addAction(tr("&Collapse Grouped Entries"));
+ QObject::connect(collapseAction, SIGNAL(triggered(bool)), this->CacheValues,
+ SLOT(collapseAll()));
+
+ QMenu* HelpMenu = this->menuBar()->addMenu(tr("&Help"));
+ QAction* a = HelpMenu->addAction(tr("About"));
+ QObject::connect(a, SIGNAL(triggered(bool)), this, SLOT(doAbout()));
+ a = HelpMenu->addAction(tr("Help"));
+ QObject::connect(a, SIGNAL(triggered(bool)), this, SLOT(doHelp()));
+
+ this->setAcceptDrops(true);
+
+ // get the saved binary directories
+ QStringList buildPaths = this->loadBuildPaths();
+ this->BinaryDirectory->addItems(buildPaths);
+
+ this->BinaryDirectory->setCompleter(new QCMakeFileCompleter(this, true));
+ this->SourceDirectory->setCompleter(new QCMakeFileCompleter(this, true));
+
+ // fixed pitch font in output window
+ QFont outputFont("Courier");
+ this->Output->setFont(outputFont);
+ this->ErrorFormat.setForeground(QBrush(Qt::red));
+
+ this->Output->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(this->Output, SIGNAL(customContextMenuRequested(const QPoint&)),
+ this, SLOT(doOutputContextMenu(const QPoint&)));
+
+ // start the cmake worker thread
+ this->CMakeThread = new QCMakeThread(this);
+ QObject::connect(this->CMakeThread, SIGNAL(cmakeInitialized()), this,
+ SLOT(initialize()), Qt::QueuedConnection);
+ this->CMakeThread->start();
+
+ this->enterState(ReadyConfigure);
+
+ ProgressOffset = 0.0;
+ ProgressFactor = 1.0;
+}
+
+void CMakeSetupDialog::initialize()
+{
+ // now the cmake worker thread is running, lets make our connections to it
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ SIGNAL(propertiesChanged(const QCMakePropertyList&)),
+ this->CacheValues->cacheModel(),
+ SLOT(setProperties(const QCMakePropertyList&)));
+
+ QObject::connect(this->ConfigureButton, SIGNAL(clicked(bool)), this,
+ SLOT(doConfigure()));
+
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ SIGNAL(configureDone(int)), this, SLOT(exitLoop(int)));
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ SIGNAL(generateDone(int)), this, SLOT(exitLoop(int)));
+
+ QObject::connect(this->GenerateButton, SIGNAL(clicked(bool)), this,
+ SLOT(doGenerate()));
+
+ QObject::connect(this->BrowseSourceDirectoryButton, SIGNAL(clicked(bool)),
+ this, SLOT(doSourceBrowse()));
+ QObject::connect(this->BrowseBinaryDirectoryButton, SIGNAL(clicked(bool)),
+ this, SLOT(doBinaryBrowse()));
+
+ QObject::connect(this->BinaryDirectory, SIGNAL(editTextChanged(QString)),
+ this, SLOT(onBinaryDirectoryChanged(QString)));
+ QObject::connect(this->SourceDirectory, SIGNAL(textChanged(QString)), this,
+ SLOT(onSourceDirectoryChanged(QString)));
+
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ SIGNAL(sourceDirChanged(QString)), this,
+ SLOT(updateSourceDirectory(QString)));
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ SIGNAL(binaryDirChanged(QString)), this,
+ SLOT(updateBinaryDirectory(QString)));
+
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ SIGNAL(progressChanged(QString, float)), this,
+ SLOT(showProgress(QString, float)));
+
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ SIGNAL(errorMessage(QString)), this, SLOT(error(QString)));
+
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ SIGNAL(outputMessage(QString)), this,
+ SLOT(message(QString)));
+
+ QObject::connect(this->groupedCheck, SIGNAL(toggled(bool)), this,
+ SLOT(setGroupedView(bool)));
+ QObject::connect(this->advancedCheck, SIGNAL(toggled(bool)), this,
+ SLOT(setAdvancedView(bool)));
+ QObject::connect(this->Search, SIGNAL(textChanged(QString)), this,
+ SLOT(setSearchFilter(QString)));
+
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ SIGNAL(generatorChanged(QString)), this,
+ SLOT(updateGeneratorLabel(QString)));
+ this->updateGeneratorLabel(QString());
+
+ QObject::connect(this->CacheValues->cacheModel(),
+ SIGNAL(dataChanged(QModelIndex, QModelIndex)), this,
+ SLOT(setCacheModified()));
+
+ QObject::connect(this->CacheValues->selectionModel(),
+ SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
+ this, SLOT(selectionChanged()));
+ QObject::connect(this->RemoveEntry, SIGNAL(clicked(bool)), this,
+ SLOT(removeSelectedCacheEntries()));
+ QObject::connect(this->AddEntry, SIGNAL(clicked(bool)), this,
+ SLOT(addCacheEntry()));
+
+ QObject::connect(this->WarnUninitializedAction, SIGNAL(triggered(bool)),
+ this->CMakeThread->cmakeInstance(),
+ SLOT(setWarnUninitializedMode(bool)));
+ QObject::connect(this->WarnUnusedAction, SIGNAL(triggered(bool)),
+ this->CMakeThread->cmakeInstance(),
+ SLOT(setWarnUnusedMode(bool)));
+
+ if (!this->SourceDirectory->text().isEmpty() ||
+ !this->BinaryDirectory->lineEdit()->text().isEmpty()) {
+ this->onSourceDirectoryChanged(this->SourceDirectory->text());
+ this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
+ } else {
+ this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
+ }
+}
+
+CMakeSetupDialog::~CMakeSetupDialog()
+{
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+ settings.setValue("windowState", QVariant(saveState()));
+ settings.setValue("geometry", QVariant(saveGeometry()));
+ settings.setValue("SplitterSizes", this->Splitter->saveState());
+
+ // wait for thread to stop
+ this->CMakeThread->quit();
+ this->CMakeThread->wait();
+}
+
+bool CMakeSetupDialog::prepareConfigure()
+{
+ // make sure build directory exists
+ QString bindir = this->CMakeThread->cmakeInstance()->binaryDirectory();
+ QDir dir(bindir);
+ if (!dir.exists()) {
+ QString msg = tr("Build directory does not exist, "
+ "should I create it?\n\n"
+ "Directory: ");
+ msg += bindir;
+ QString title = tr("Create Directory");
+ QMessageBox::StandardButton btn;
+ btn = QMessageBox::information(this, title, msg,
+ QMessageBox::Yes | QMessageBox::No);
+ if (btn == QMessageBox::No) {
+ return false;
+ }
+ if (!dir.mkpath(".")) {
+ QMessageBox::information(
+ this, tr("Create Directory Failed"),
+ QString(tr("Failed to create directory %1")).arg(dir.path()),
+ QMessageBox::Ok);
+
+ return false;
+ }
+ }
+
+ // if no generator, prompt for it and other setup stuff
+ if (this->CMakeThread->cmakeInstance()->generator().isEmpty()) {
+ if (!this->setupFirstConfigure()) {
+ return false;
+ }
+ }
+
+ // remember path
+ this->addBinaryPath(dir.absolutePath());
+
+ return true;
+}
+
+void CMakeSetupDialog::exitLoop(int err)
+{
+ this->LocalLoop.exit(err);
+}
+
+void CMakeSetupDialog::doConfigure()
+{
+ if (this->CurrentState == Configuring) {
+ // stop configure
+ doInterrupt();
+ return;
+ }
+
+ if (!prepareConfigure()) {
+ return;
+ }
+
+ this->enterState(Configuring);
+
+ bool ret = doConfigureInternal();
+
+ if (ret) {
+ this->ConfigureNeeded = false;
+ }
+
+ if (ret && !this->CacheValues->cacheModel()->newPropertyCount()) {
+ this->enterState(ReadyGenerate);
+ } else {
+ this->enterState(ReadyConfigure);
+ this->CacheValues->scrollToTop();
+ }
+ this->ProgressBar->reset();
+}
+
+bool CMakeSetupDialog::doConfigureInternal()
+{
+ this->Output->clear();
+ this->CacheValues->selectionModel()->clear();
+
+ QMetaObject::invokeMethod(
+ this->CMakeThread->cmakeInstance(), "setProperties", Qt::QueuedConnection,
+ Q_ARG(QCMakePropertyList, this->CacheValues->cacheModel()->properties()));
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "configure",
+ Qt::QueuedConnection);
+
+ int err = this->LocalLoop.exec();
+
+ if (err != 0) {
+ QMessageBox::critical(
+ this, tr("Error"),
+ tr("Error in configuration process, project files may be invalid"),
+ QMessageBox::Ok);
+ }
+
+ return 0 == err;
+}
+
+void CMakeSetupDialog::doInstallForCommandLine()
+{
+ QString title = tr("How to Install For Command Line Use");
+ QString msg = tr("One may add CMake to the PATH:\n"
+ "\n"
+ " PATH=\"%1\":\"$PATH\"\n"
+ "\n"
+ "Or, to install symlinks to '/usr/local/bin', run:\n"
+ "\n"
+ " sudo \"%2\" --install\n"
+ "\n"
+ "Or, to install symlinks to another directory, run:\n"
+ "\n"
+ " sudo \"%3\" --install=/path/to/bin\n");
+ msg = msg.arg(
+ cmSystemTools::GetFilenamePath(cmSystemTools::GetCMakeCommand()).c_str());
+ msg = msg.arg(cmSystemTools::GetCMakeGUICommand().c_str());
+ msg = msg.arg(cmSystemTools::GetCMakeGUICommand().c_str());
+
+ QDialog dialog;
+ dialog.setWindowTitle(title);
+ QVBoxLayout* l = new QVBoxLayout(&dialog);
+ QLabel* lab = new QLabel(&dialog);
+ l->addWidget(lab);
+ lab->setText(msg);
+ lab->setWordWrap(false);
+ lab->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ QDialogButtonBox* btns =
+ new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog);
+ QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ l->addWidget(btns);
+ dialog.exec();
+}
+
+bool CMakeSetupDialog::doGenerateInternal()
+{
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "generate",
+ Qt::QueuedConnection);
+
+ int err = this->LocalLoop.exec();
+
+ if (err != 0) {
+ QMessageBox::critical(
+ this, tr("Error"),
+ tr("Error in generation process, project files may be invalid"),
+ QMessageBox::Ok);
+ }
+
+ return 0 == err;
+}
+
+void CMakeSetupDialog::doGenerate()
+{
+ if (this->CurrentState == Generating) {
+ // stop generate
+ doInterrupt();
+ return;
+ }
+
+ // see if we need to configure
+ // we'll need to configure if:
+ // the configure step hasn't been done yet
+ // generate was the last step done
+ if (this->ConfigureNeeded) {
+ if (!prepareConfigure()) {
+ return;
+ }
+ }
+
+ this->enterState(Generating);
+
+ bool config_passed = true;
+ if (this->ConfigureNeeded) {
+ this->CacheValues->cacheModel()->setShowNewProperties(false);
+ this->ProgressFactor = 0.5;
+ config_passed = doConfigureInternal();
+ this->ProgressOffset = 0.5;
+ }
+
+ if (config_passed) {
+ doGenerateInternal();
+ }
+
+ this->ProgressOffset = 0.0;
+ this->ProgressFactor = 1.0;
+ this->CacheValues->cacheModel()->setShowNewProperties(true);
+
+ this->enterState(ReadyConfigure);
+ this->ProgressBar->reset();
+
+ this->ConfigureNeeded = true;
+}
+
+void CMakeSetupDialog::closeEvent(QCloseEvent* e)
+{
+ // prompt for close if there are unsaved changes, and we're not busy
+ if (this->CacheModified) {
+ QString msg = tr("You have changed options but not rebuilt, "
+ "are you sure you want to exit?");
+ QString title = tr("Confirm Exit");
+ QMessageBox::StandardButton btn;
+ btn = QMessageBox::critical(this, title, msg,
+ QMessageBox::Yes | QMessageBox::No);
+ if (btn == QMessageBox::No) {
+ e->ignore();
+ }
+ }
+
+ // don't close if we're busy, unless the user really wants to
+ if (this->CurrentState == Configuring) {
+ QString msg =
+ tr("You are in the middle of a Configure.\n"
+ "If you Exit now the configure information will be lost.\n"
+ "Are you sure you want to Exit?");
+ QString title = tr("Confirm Exit");
+ QMessageBox::StandardButton btn;
+ btn = QMessageBox::critical(this, title, msg,
+ QMessageBox::Yes | QMessageBox::No);
+ if (btn == QMessageBox::No) {
+ e->ignore();
+ } else {
+ this->doInterrupt();
+ }
+ }
+
+ // let the generate finish
+ if (this->CurrentState == Generating) {
+ e->ignore();
+ }
+}
+
+void CMakeSetupDialog::doHelp()
+{
+ QString msg = tr(
+ "CMake is used to configure and generate build files for "
+ "software projects. The basic steps for configuring a project are as "
+ "follows:\r\n\r\n1. Select the source directory for the project. This "
+ "should "
+ "contain the CMakeLists.txt files for the project.\r\n\r\n2. Select the "
+ "build "
+ "directory for the project. This is the directory where the project "
+ "will be "
+ "built. It can be the same or a different directory than the source "
+ "directory. For easy clean up, a separate build directory is "
+ "recommended. "
+ "CMake will create the directory if it does not exist.\r\n\r\n3. Once the "
+ "source and binary directories are selected, it is time to press the "
+ "Configure button. This will cause CMake to read all of the input files "
+ "and "
+ "discover all the variables used by the project. The first time a "
+ "variable "
+ "is displayed it will be in Red. Users should inspect red variables "
+ "making "
+ "sure the values are correct. For some projects the Configure process "
+ "can "
+ "be iterative, so continue to press the Configure button until there are "
+ "no "
+ "longer red entries.\r\n\r\n4. Once there are no longer red entries, you "
+ "should click the Generate button. This will write the build files to "
+ "the build "
+ "directory.");
+
+ QDialog dialog;
+ QFontMetrics met(this->font());
+ int msgWidth = met.width(msg);
+ dialog.setMinimumSize(msgWidth / 15, 20);
+ dialog.setWindowTitle(tr("Help"));
+ QVBoxLayout* l = new QVBoxLayout(&dialog);
+ QLabel* lab = new QLabel(&dialog);
+ lab->setText(msg);
+ lab->setWordWrap(true);
+ QDialogButtonBox* btns =
+ new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog);
+ QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ l->addWidget(lab);
+ l->addWidget(btns);
+ dialog.exec();
+}
+
+void CMakeSetupDialog::doInterrupt()
+{
+ this->enterState(Interrupting);
+ this->CMakeThread->cmakeInstance()->interrupt();
+}
+
+void CMakeSetupDialog::doSourceBrowse()
+{
+ QString dir = QFileDialog::getExistingDirectory(
+ this, tr("Enter Path to Source"), this->SourceDirectory->text(),
+ QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
+ if (!dir.isEmpty()) {
+ this->setSourceDirectory(dir);
+ }
+}
+
+void CMakeSetupDialog::updateSourceDirectory(const QString& dir)
+{
+ if (this->SourceDirectory->text() != dir) {
+ this->SourceDirectory->blockSignals(true);
+ this->SourceDirectory->setText(dir);
+ this->SourceDirectory->blockSignals(false);
+ }
+}
+
+void CMakeSetupDialog::updateBinaryDirectory(const QString& dir)
+{
+ if (this->BinaryDirectory->currentText() != dir) {
+ this->BinaryDirectory->blockSignals(true);
+ this->BinaryDirectory->setEditText(dir);
+ this->BinaryDirectory->blockSignals(false);
+ }
+}
+
+void CMakeSetupDialog::doBinaryBrowse()
+{
+ QString dir = QFileDialog::getExistingDirectory(
+ this, tr("Enter Path to Build"), this->BinaryDirectory->currentText(),
+ QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
+ if (!dir.isEmpty() && dir != this->BinaryDirectory->currentText()) {
+ this->setBinaryDirectory(dir);
+ }
+}
+
+void CMakeSetupDialog::setBinaryDirectory(const QString& dir)
+{
+ this->BinaryDirectory->setEditText(dir);
+}
+
+void CMakeSetupDialog::onSourceDirectoryChanged(const QString& dir)
+{
+ this->Output->clear();
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
+ "setSourceDirectory", Qt::QueuedConnection,
+ Q_ARG(QString, dir));
+}
+
+void CMakeSetupDialog::onBinaryDirectoryChanged(const QString& dir)
+{
+ QString title = QString(tr("CMake %1 - %2"));
+ title = title.arg(cmVersion::GetCMakeVersion());
+ title = title.arg(dir);
+ this->setWindowTitle(title);
+
+ this->CacheModified = false;
+ this->CacheValues->cacheModel()->clear();
+ qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())
+ ->clearChanges();
+ this->Output->clear();
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
+ "setBinaryDirectory", Qt::QueuedConnection,
+ Q_ARG(QString, dir));
+}
+
+void CMakeSetupDialog::setSourceDirectory(const QString& dir)
+{
+ this->SourceDirectory->setText(dir);
+}
+
+void CMakeSetupDialog::showProgress(const QString& /*msg*/, float percent)
+{
+ percent = (percent * ProgressFactor) + ProgressOffset;
+ this->ProgressBar->setValue(qRound(percent * 100));
+}
+
+void CMakeSetupDialog::error(const QString& msg)
+{
+ this->Output->setCurrentCharFormat(this->ErrorFormat);
+ // QTextEdit will terminate the msg with a ParagraphSeparator, but it also
+ // replaces
+ // all newlines with ParagraphSeparators. By replacing the newlines by
+ // ourself, one
+ // error msg will be one paragraph.
+ QString paragraph(msg);
+ paragraph.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ this->Output->append(paragraph);
+}
+
+void CMakeSetupDialog::message(const QString& msg)
+{
+ this->Output->setCurrentCharFormat(this->MessageFormat);
+ this->Output->append(msg);
+}
+
+void CMakeSetupDialog::setEnabledState(bool enabled)
+{
+ // disable parts of the GUI during configure/generate
+ this->CacheValues->cacheModel()->setEditEnabled(enabled);
+ this->SourceDirectory->setEnabled(enabled);
+ this->BrowseSourceDirectoryButton->setEnabled(enabled);
+ this->BinaryDirectory->setEnabled(enabled);
+ this->BrowseBinaryDirectoryButton->setEnabled(enabled);
+ this->ReloadCacheAction->setEnabled(enabled);
+ this->DeleteCacheAction->setEnabled(enabled);
+ this->ExitAction->setEnabled(enabled);
+ this->ConfigureAction->setEnabled(enabled);
+ this->AddEntry->setEnabled(enabled);
+ this->RemoveEntry->setEnabled(false); // let selection re-enable it
+}
+
+bool CMakeSetupDialog::setupFirstConfigure()
+{
+ FirstConfigure dialog;
+
+ // initialize dialog and restore saved settings
+
+ // add generators
+ dialog.setGenerators(
+ this->CMakeThread->cmakeInstance()->availableGenerators());
+
+ // restore from settings
+ dialog.loadFromSettings();
+
+ if (dialog.exec() == QDialog::Accepted) {
+ dialog.saveToSettings();
+ this->CMakeThread->cmakeInstance()->setGenerator(dialog.getGenerator());
+ this->CMakeThread->cmakeInstance()->setToolset(dialog.getToolset());
+
+ QCMakeCacheModel* m = this->CacheValues->cacheModel();
+
+ if (dialog.compilerSetup()) {
+ QString fortranCompiler = dialog.getFortranCompiler();
+ if (!fortranCompiler.isEmpty()) {
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
+ "Fortran compiler.", fortranCompiler, false);
+ }
+ QString cxxCompiler = dialog.getCXXCompiler();
+ if (!cxxCompiler.isEmpty()) {
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
+ "CXX compiler.", cxxCompiler, false);
+ }
+
+ QString cCompiler = dialog.getCCompiler();
+ if (!cCompiler.isEmpty()) {
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
+ "C compiler.", cCompiler, false);
+ }
+ } else if (dialog.crossCompilerSetup()) {
+ QString fortranCompiler = dialog.getFortranCompiler();
+ if (!fortranCompiler.isEmpty()) {
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
+ "Fortran compiler.", fortranCompiler, false);
+ }
+
+ QString mode = dialog.getCrossIncludeMode();
+ m->insertProperty(QCMakeProperty::STRING,
+ "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE",
+ tr("CMake Find Include Mode"), mode, false);
+ mode = dialog.getCrossLibraryMode();
+ m->insertProperty(QCMakeProperty::STRING,
+ "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY",
+ tr("CMake Find Library Mode"), mode, false);
+ mode = dialog.getCrossProgramMode();
+ m->insertProperty(QCMakeProperty::STRING,
+ "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM",
+ tr("CMake Find Program Mode"), mode, false);
+
+ QString rootPath = dialog.getCrossRoot();
+ m->insertProperty(QCMakeProperty::PATH, "CMAKE_FIND_ROOT_PATH",
+ tr("CMake Find Root Path"), rootPath, false);
+
+ QString systemName = dialog.getSystemName();
+ m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_NAME",
+ tr("CMake System Name"), systemName, false);
+ QString systemVersion = dialog.getSystemVersion();
+ m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_VERSION",
+ tr("CMake System Version"), systemVersion, false);
+ QString cxxCompiler = dialog.getCXXCompiler();
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
+ tr("CXX compiler."), cxxCompiler, false);
+ QString cCompiler = dialog.getCCompiler();
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
+ tr("C compiler."), cCompiler, false);
+ } else if (dialog.crossCompilerToolChainFile()) {
+ QString toolchainFile = dialog.getCrossCompilerToolChainFile();
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_TOOLCHAIN_FILE",
+ tr("Cross Compile ToolChain File"), toolchainFile,
+ false);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void CMakeSetupDialog::updateGeneratorLabel(const QString& gen)
+{
+ QString str = tr("Current Generator: ");
+ if (gen.isEmpty()) {
+ str += tr("None");
+ } else {
+ str += gen;
+ }
+ this->Generator->setText(str);
+}
+
+void CMakeSetupDialog::doReloadCache()
+{
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "reloadCache",
+ Qt::QueuedConnection);
+}
+
+void CMakeSetupDialog::doDeleteCache()
+{
+ QString title = tr("Delete Cache");
+ QString msg = tr("Are you sure you want to delete the cache?");
+ QMessageBox::StandardButton btn;
+ btn = QMessageBox::information(this, title, msg,
+ QMessageBox::Yes | QMessageBox::No);
+ if (btn == QMessageBox::No) {
+ return;
+ }
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "deleteCache",
+ Qt::QueuedConnection);
+}
+
+void CMakeSetupDialog::doAbout()
+{
+ QString msg = tr(
+ "CMake %1 (cmake.org).\n"
+ "CMake suite maintained and supported by Kitware (kitware.com/cmake).\n"
+ "Distributed under terms of the BSD 3-Clause License.\n"
+ "\n"
+ "CMake GUI maintained by csimsoft,\n"
+ "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"
+ "Qt is licensed under terms of the GNU LGPLv" USE_LGPL ", available at:\n"
+ " \"%3\""
+#endif
+ );
+ msg = msg.arg(cmVersion::GetCMakeVersion());
+ msg = msg.arg(qVersion());
+#ifdef USE_LGPL
+ std::string lgpl =
+ cmSystemTools::GetCMakeRoot() + "/Licenses/LGPLv" USE_LGPL ".txt";
+ msg = msg.arg(lgpl.c_str());
+#endif
+
+ QDialog dialog;
+ dialog.setWindowTitle(tr("About"));
+ QVBoxLayout* l = new QVBoxLayout(&dialog);
+ QLabel* lab = new QLabel(&dialog);
+ l->addWidget(lab);
+ lab->setText(msg);
+ lab->setWordWrap(true);
+ QDialogButtonBox* btns =
+ new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog);
+ QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ l->addWidget(btns);
+ dialog.exec();
+}
+
+void CMakeSetupDialog::setExitAfterGenerate(bool b)
+{
+ this->ExitAfterGenerate = b;
+}
+
+void CMakeSetupDialog::addBinaryPath(const QString& path)
+{
+ QString cleanpath = QDir::cleanPath(path);
+
+ // update UI
+ this->BinaryDirectory->blockSignals(true);
+ int idx = this->BinaryDirectory->findText(cleanpath);
+ if (idx != -1) {
+ this->BinaryDirectory->removeItem(idx);
+ }
+ this->BinaryDirectory->insertItem(0, cleanpath);
+ this->BinaryDirectory->setCurrentIndex(0);
+ this->BinaryDirectory->blockSignals(false);
+
+ // save to registry
+ QStringList buildPaths = this->loadBuildPaths();
+ buildPaths.removeAll(cleanpath);
+ buildPaths.prepend(cleanpath);
+ this->saveBuildPaths(buildPaths);
+}
+
+void CMakeSetupDialog::dragEnterEvent(QDragEnterEvent* e)
+{
+ if (!(this->CurrentState == ReadyConfigure ||
+ this->CurrentState == ReadyGenerate)) {
+ e->ignore();
+ return;
+ }
+
+ const QMimeData* dat = e->mimeData();
+ QList<QUrl> urls = dat->urls();
+ QString file = urls.count() ? urls[0].toLocalFile() : QString();
+ if (!file.isEmpty() &&
+ (file.endsWith("CMakeCache.txt", Qt::CaseInsensitive) ||
+ file.endsWith("CMakeLists.txt", Qt::CaseInsensitive))) {
+ e->accept();
+ } else {
+ e->ignore();
+ }
+}
+
+void CMakeSetupDialog::dropEvent(QDropEvent* e)
+{
+ if (!(this->CurrentState == ReadyConfigure ||
+ this->CurrentState == ReadyGenerate)) {
+ return;
+ }
+
+ const QMimeData* dat = e->mimeData();
+ QList<QUrl> urls = dat->urls();
+ QString file = urls.count() ? urls[0].toLocalFile() : QString();
+ if (file.endsWith("CMakeCache.txt", Qt::CaseInsensitive)) {
+ QFileInfo info(file);
+ if (this->CMakeThread->cmakeInstance()->binaryDirectory() !=
+ info.absolutePath()) {
+ this->setBinaryDirectory(info.absolutePath());
+ }
+ } else if (file.endsWith("CMakeLists.txt", Qt::CaseInsensitive)) {
+ QFileInfo info(file);
+ if (this->CMakeThread->cmakeInstance()->binaryDirectory() !=
+ info.absolutePath()) {
+ this->setSourceDirectory(info.absolutePath());
+ this->setBinaryDirectory(info.absolutePath());
+ }
+ }
+}
+
+QStringList CMakeSetupDialog::loadBuildPaths()
+{
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+
+ QStringList buildPaths;
+ for (int i = 0; i < 10; i++) {
+ QString p = settings.value(QString("WhereBuild%1").arg(i)).toString();
+ if (!p.isEmpty()) {
+ buildPaths.append(p);
+ }
+ }
+ return buildPaths;
+}
+
+void CMakeSetupDialog::saveBuildPaths(const QStringList& paths)
+{
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+
+ int num = paths.count();
+ if (num > 10) {
+ num = 10;
+ }
+
+ for (int i = 0; i < num; i++) {
+ settings.setValue(QString("WhereBuild%1").arg(i), paths[i]);
+ }
+}
+
+void CMakeSetupDialog::setCacheModified()
+{
+ this->CacheModified = true;
+ this->ConfigureNeeded = true;
+ this->enterState(ReadyConfigure);
+}
+
+void CMakeSetupDialog::removeSelectedCacheEntries()
+{
+ QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
+ QList<QPersistentModelIndex> pidxs;
+ foreach (QModelIndex i, idxs) {
+ pidxs.append(i);
+ }
+ foreach (QPersistentModelIndex pi, pidxs) {
+ this->CacheValues->model()->removeRow(pi.row(), pi.parent());
+ }
+}
+
+void CMakeSetupDialog::selectionChanged()
+{
+ QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
+ if (idxs.count() && (this->CurrentState == ReadyConfigure ||
+ this->CurrentState == ReadyGenerate)) {
+ this->RemoveEntry->setEnabled(true);
+ } else {
+ this->RemoveEntry->setEnabled(false);
+ }
+}
+
+void CMakeSetupDialog::enterState(CMakeSetupDialog::State s)
+{
+ if (s == this->CurrentState) {
+ return;
+ }
+
+ this->CurrentState = s;
+
+ if (s == Interrupting) {
+ this->ConfigureButton->setEnabled(false);
+ this->GenerateButton->setEnabled(false);
+ } else if (s == Configuring) {
+ this->setEnabledState(false);
+ this->GenerateButton->setEnabled(false);
+ this->GenerateAction->setEnabled(false);
+ this->ConfigureButton->setText(tr("&Stop"));
+ } else if (s == Generating) {
+ this->CacheModified = false;
+ this->setEnabledState(false);
+ this->ConfigureButton->setEnabled(false);
+ this->GenerateAction->setEnabled(false);
+ this->GenerateButton->setText(tr("&Stop"));
+ } else if (s == ReadyConfigure) {
+ this->setEnabledState(true);
+ this->GenerateButton->setEnabled(true);
+ this->GenerateAction->setEnabled(true);
+ this->ConfigureButton->setEnabled(true);
+ this->ConfigureButton->setText(tr("&Configure"));
+ this->GenerateButton->setText(tr("&Generate"));
+ } else if (s == ReadyGenerate) {
+ this->setEnabledState(true);
+ this->GenerateButton->setEnabled(true);
+ this->GenerateAction->setEnabled(true);
+ this->ConfigureButton->setEnabled(true);
+ this->ConfigureButton->setText(tr("&Configure"));
+ this->GenerateButton->setText(tr("&Generate"));
+ }
+}
+
+void CMakeSetupDialog::addCacheEntry()
+{
+ QDialog dialog(this);
+ dialog.resize(400, 200);
+ dialog.setWindowTitle(tr("Add Cache Entry"));
+ QVBoxLayout* l = new QVBoxLayout(&dialog);
+ AddCacheEntry* w =
+ new AddCacheEntry(&dialog, this->AddVariableNames, this->AddVariableTypes);
+ QDialogButtonBox* btns = new QDialogButtonBox(
+ QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);
+ QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(reject()));
+ l->addWidget(w);
+ l->addStretch();
+ l->addWidget(btns);
+ if (QDialog::Accepted == dialog.exec()) {
+ QCMakeCacheModel* m = this->CacheValues->cacheModel();
+ m->insertProperty(w->type(), w->name(), w->description(), w->value(),
+ false);
+
+ // only add variable names to the completion which are new
+ if (!this->AddVariableNames.contains(w->name())) {
+ this->AddVariableNames << w->name();
+ this->AddVariableTypes << w->typeString();
+ // limit to at most 100 completion items
+ if (this->AddVariableNames.size() > 100) {
+ this->AddVariableNames.removeFirst();
+ this->AddVariableTypes.removeFirst();
+ }
+ // make sure CMAKE_INSTALL_PREFIX is always there
+ if (!this->AddVariableNames.contains("CMAKE_INSTALL_PREFIX")) {
+ this->AddVariableNames << "CMAKE_INSTALL_PREFIX";
+ this->AddVariableTypes << "PATH";
+ }
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+ settings.setValue("AddVariableNames", this->AddVariableNames);
+ settings.setValue("AddVariableTypes", this->AddVariableTypes);
+ }
+ }
+}
+
+void CMakeSetupDialog::startSearch()
+{
+ this->Search->setFocus(Qt::OtherFocusReason);
+ this->Search->selectAll();
+}
+
+void CMakeSetupDialog::setDebugOutput(bool flag)
+{
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
+ "setDebugOutput", Qt::QueuedConnection,
+ Q_ARG(bool, flag));
+}
+
+void CMakeSetupDialog::setGroupedView(bool v)
+{
+ this->CacheValues->cacheModel()->setViewType(v ? QCMakeCacheModel::GroupView
+ : QCMakeCacheModel::FlatView);
+ this->CacheValues->setRootIsDecorated(v);
+
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+ settings.setValue("GroupView", v);
+}
+
+void CMakeSetupDialog::setAdvancedView(bool v)
+{
+ this->CacheValues->setShowAdvanced(v);
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+ settings.setValue("AdvancedView", v);
+}
+
+void CMakeSetupDialog::showUserChanges()
+{
+ QSet<QCMakeProperty> changes =
+ qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())
+ ->changes();
+
+ QDialog dialog(this);
+ dialog.setWindowTitle(tr("My Changes"));
+ dialog.resize(600, 400);
+ QVBoxLayout* l = new QVBoxLayout(&dialog);
+ QTextEdit* textedit = new QTextEdit(&dialog);
+ textedit->setReadOnly(true);
+ l->addWidget(textedit);
+ QDialogButtonBox* btns =
+ new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog);
+ QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(accept()));
+ l->addWidget(btns);
+
+ QString command;
+ QString cache;
+
+ foreach (QCMakeProperty prop, changes) {
+ QString type;
+ switch (prop.Type) {
+ case QCMakeProperty::BOOL:
+ type = "BOOL";
+ break;
+ case QCMakeProperty::PATH:
+ type = "PATH";
+ break;
+ case QCMakeProperty::FILEPATH:
+ type = "FILEPATH";
+ break;
+ case QCMakeProperty::STRING:
+ type = "STRING";
+ break;
+ }
+ QString value;
+ if (prop.Type == QCMakeProperty::BOOL) {
+ value = prop.Value.toBool() ? "1" : "0";
+ } else {
+ value = prop.Value.toString();
+ }
+
+ QString line("%1:%2=");
+ line = line.arg(prop.Key);
+ line = line.arg(type);
+
+ command += QString("-D%1\"%2\" ").arg(line).arg(value);
+ cache += QString("%1%2\n").arg(line).arg(value);
+ }
+
+ textedit->append(tr("Commandline options:"));
+ textedit->append(command);
+ textedit->append("\n");
+ textedit->append(tr("Cache file:"));
+ textedit->append(cache);
+
+ dialog.exec();
+}
+
+void CMakeSetupDialog::setSearchFilter(const QString& str)
+{
+ this->CacheValues->selectionModel()->clear();
+ this->CacheValues->setSearchFilter(str);
+}
+
+void CMakeSetupDialog::doOutputContextMenu(const QPoint& pt)
+{
+ QMenu* menu = this->Output->createStandardContextMenu();
+
+ menu->addSeparator();
+ menu->addAction(tr("Find..."), this, SLOT(doOutputFindDialog()),
+ QKeySequence::Find);
+ menu->addAction(tr("Find Next"), this, SLOT(doOutputFindNext()),
+ QKeySequence::FindNext);
+ menu->addAction(tr("Find Previous"), this, SLOT(doOutputFindPrev()),
+ QKeySequence::FindPrevious);
+ menu->addSeparator();
+ menu->addAction(tr("Goto Next Error"), this, SLOT(doOutputErrorNext()),
+ QKeySequence(Qt::Key_F8));
+
+ menu->exec(this->Output->mapToGlobal(pt));
+ delete menu;
+}
+
+void CMakeSetupDialog::doOutputFindDialog()
+{
+ QStringList strings(this->FindHistory);
+
+ QString selection = this->Output->textCursor().selectedText();
+ if (!selection.isEmpty() && !selection.contains(QChar::ParagraphSeparator) &&
+ !selection.contains(QChar::LineSeparator)) {
+ strings.push_front(selection);
+ }
+
+ bool ok;
+ QString search = QInputDialog::getItem(this, tr("Find in Output"),
+ tr("Find:"), strings, 0, true, &ok);
+ if (ok && !search.isEmpty()) {
+ if (!this->FindHistory.contains(search)) {
+ this->FindHistory.push_front(search);
+ }
+ doOutputFindNext();
+ }
+}
+
+void CMakeSetupDialog::doRegexExplorerDialog()
+{
+ RegexExplorer dialog(this);
+ dialog.exec();
+}
+
+void CMakeSetupDialog::doOutputFindPrev()
+{
+ doOutputFindNext(false);
+}
+
+void CMakeSetupDialog::doOutputFindNext(bool directionForward)
+{
+ if (this->FindHistory.isEmpty()) {
+ doOutputFindDialog(); // will re-call this function again
+ return;
+ }
+
+ QString search = this->FindHistory.front();
+
+ QTextCursor textCursor = this->Output->textCursor();
+ QTextDocument* document = this->Output->document();
+ QTextDocument::FindFlags flags;
+ if (!directionForward) {
+ flags |= QTextDocument::FindBackward;
+ }
+
+ textCursor = document->find(search, textCursor, flags);
+
+ if (textCursor.isNull()) {
+ // first search found nothing, wrap around and search again
+ textCursor = this->Output->textCursor();
+ textCursor.movePosition(directionForward ? QTextCursor::Start
+ : QTextCursor::End);
+ textCursor = document->find(search, textCursor, flags);
+ }
+
+ if (textCursor.hasSelection()) {
+ this->Output->setTextCursor(textCursor);
+ }
+}
+
+void CMakeSetupDialog::doOutputErrorNext()
+{
+ QTextCursor textCursor = this->Output->textCursor();
+ bool atEnd = false;
+
+ // move cursor out of current error-block
+ if (textCursor.blockCharFormat() == this->ErrorFormat) {
+ atEnd = !textCursor.movePosition(QTextCursor::NextBlock);
+ }
+
+ // move cursor to next error-block
+ while (textCursor.blockCharFormat() != this->ErrorFormat && !atEnd) {
+ atEnd = !textCursor.movePosition(QTextCursor::NextBlock);
+ }
+
+ if (atEnd) {
+ // first search found nothing, wrap around and search again
+ atEnd = !textCursor.movePosition(QTextCursor::Start);
+
+ // move cursor to next error-block
+ while (textCursor.blockCharFormat() != this->ErrorFormat && !atEnd) {
+ atEnd = !textCursor.movePosition(QTextCursor::NextBlock);
+ }
+ }
+
+ if (!atEnd) {
+ textCursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+
+ QTextCharFormat selectionFormat;
+ selectionFormat.setBackground(Qt::yellow);
+ QTextEdit::ExtraSelection extraSelection = { textCursor, selectionFormat };
+ this->Output->setExtraSelections(QList<QTextEdit::ExtraSelection>()
+ << extraSelection);
+
+ // make the whole error-block visible
+ this->Output->setTextCursor(textCursor);
+
+ // remove the selection to see the extraSelection
+ textCursor.setPosition(textCursor.anchor());
+ this->Output->setTextCursor(textCursor);
+ }
+}
+
+void CMakeSetupDialog::doWarningMessagesDialog()
+{
+ WarningMessagesDialog dialog(this, this->CMakeThread->cmakeInstance());
+ dialog.exec();
+}
diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h
new file mode 100644
index 0000000..2a4ea7a
--- /dev/null
+++ b/Source/QtDialog/CMakeSetupDialog.h
@@ -0,0 +1,148 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef CMakeSetupDialog_h
+#define CMakeSetupDialog_h
+
+#include "QCMake.h"
+
+#include "ui_CMakeSetupDialog.h"
+#include <QEventLoop>
+#include <QMainWindow>
+#include <QThread>
+
+class QCMakeThread;
+class CMakeCacheModel;
+class QProgressBar;
+class QToolButton;
+
+/// Qt user interface for CMake
+class CMakeSetupDialog : public QMainWindow, public Ui::CMakeSetupDialog
+{
+ Q_OBJECT
+public:
+ CMakeSetupDialog();
+ ~CMakeSetupDialog();
+
+public slots:
+ void setBinaryDirectory(const QString& dir);
+ void setSourceDirectory(const QString& dir);
+
+protected slots:
+ void initialize();
+ void doConfigure();
+ void doGenerate();
+ void doInstallForCommandLine();
+ void doHelp();
+ void doAbout();
+ void doInterrupt();
+ void error(const QString& message);
+ void message(const QString& message);
+
+ void doSourceBrowse();
+ void doBinaryBrowse();
+ void doReloadCache();
+ void doDeleteCache();
+ void updateSourceDirectory(const QString& dir);
+ void updateBinaryDirectory(const QString& dir);
+ void showProgress(const QString& msg, float percent);
+ void setEnabledState(bool);
+ bool setupFirstConfigure();
+ void updateGeneratorLabel(const QString& gen);
+ void setExitAfterGenerate(bool);
+ void addBinaryPath(const QString&);
+ QStringList loadBuildPaths();
+ void saveBuildPaths(const QStringList&);
+ void onBinaryDirectoryChanged(const QString& dir);
+ void onSourceDirectoryChanged(const QString& dir);
+ void setCacheModified();
+ void removeSelectedCacheEntries();
+ void selectionChanged();
+ void addCacheEntry();
+ void startSearch();
+ void setDebugOutput(bool);
+ void setAdvancedView(bool);
+ void setGroupedView(bool);
+ void showUserChanges();
+ void setSearchFilter(const QString& str);
+ bool prepareConfigure();
+ bool doConfigureInternal();
+ bool doGenerateInternal();
+ void exitLoop(int);
+ void doOutputContextMenu(const QPoint&);
+ void doOutputFindDialog();
+ void doOutputFindNext(bool directionForward = true);
+ void doOutputFindPrev();
+ void doOutputErrorNext();
+ void doRegexExplorerDialog();
+ /// display the modal warning messages dialog window
+ void doWarningMessagesDialog();
+
+protected:
+ enum State
+ {
+ Interrupting,
+ ReadyConfigure,
+ ReadyGenerate,
+ Configuring,
+ Generating
+ };
+ void enterState(State s);
+
+ void closeEvent(QCloseEvent*);
+ void dragEnterEvent(QDragEnterEvent*);
+ void dropEvent(QDropEvent*);
+
+ QCMakeThread* CMakeThread;
+ bool ExitAfterGenerate;
+ bool CacheModified;
+ bool ConfigureNeeded;
+ QAction* ReloadCacheAction;
+ QAction* DeleteCacheAction;
+ QAction* ExitAction;
+ QAction* ConfigureAction;
+ QAction* GenerateAction;
+ QAction* WarnUninitializedAction;
+ QAction* WarnUnusedAction;
+ QAction* InstallForCommandLineAction;
+ State CurrentState;
+
+ QTextCharFormat ErrorFormat;
+ QTextCharFormat MessageFormat;
+
+ QStringList AddVariableNames;
+ QStringList AddVariableTypes;
+ QStringList FindHistory;
+
+ QEventLoop LocalLoop;
+
+ float ProgressOffset;
+ float ProgressFactor;
+};
+
+// QCMake instance on a thread
+class QCMakeThread : public QThread
+{
+ Q_OBJECT
+public:
+ QCMakeThread(QObject* p);
+ QCMake* cmakeInstance() const;
+
+signals:
+ void cmakeInitialized();
+
+protected:
+ virtual void run();
+ QCMake* CMakeInstance;
+};
+
+#endif // CMakeSetupDialog_h
diff --git a/Source/QtDialog/CMakeSetupDialog.ui b/Source/QtDialog/CMakeSetupDialog.ui
new file mode 100644
index 0000000..b04bd93
--- /dev/null
+++ b/Source/QtDialog/CMakeSetupDialog.ui
@@ -0,0 +1,313 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CMakeSetupDialog</class>
+ <widget class="QWidget" name="CMakeSetupDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>707</width>
+ <height>582</height>
+ </rect>
+ </property>
+ <layout class="QGridLayout">
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item row="0" column="0">
+ <layout class="QGridLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Where is the source code:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="SourceDirectory"/>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="BrowseSourceDirectoryButton">
+ <property name="text">
+ <string>Browse &amp;Source...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Where to build the binaries:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="BinaryDirectory">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Ignored" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="BrowseBinaryDirectoryButton">
+ <property name="text">
+ <string>Browse &amp;Build...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QSplitter" name="Splitter">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <widget class="QFrame" name="frame">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>S&amp;earch:</string>
+ </property>
+ <property name="buddy">
+ <cstring>Search</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="Search">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Minimum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>12</width>
+ <height>23</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="groupedCheck">
+ <property name="text">
+ <string>Grouped</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="advancedCheck">
+ <property name="text">
+ <string>Advanced</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="AddEntry">
+ <property name="toolTip">
+ <string>Add New Entry</string>
+ </property>
+ <property name="text">
+ <string>&amp;Add Entry</string>
+ </property>
+ <property name="icon">
+ <iconset resource="CMakeSetup.qrc">
+ <normaloff>:/Icons/Plus16.png</normaloff>:/Icons/Plus16.png</iconset>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="RemoveEntry">
+ <property name="toolTip">
+ <string>Remove Selected Entries</string>
+ </property>
+ <property name="text">
+ <string>&amp;Remove Entry</string>
+ </property>
+ <property name="icon">
+ <iconset resource="CMakeSetup.qrc">
+ <normaloff>:/Icons/Delete16.png</normaloff>:/Icons/Delete16.png</iconset>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCMakeCacheView" name="CacheValues">
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::ExtendedSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Press Configure to update and display new values in red, then press Generate to generate selected build files.</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="ConfigureButton">
+ <property name="text">
+ <string>&amp;Configure</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="GenerateButton">
+ <property name="text">
+ <string>&amp;Generate</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="Generator">
+ <property name="text">
+ <string>Current Generator:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>121</width>
+ <height>27</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QProgressBar" name="ProgressBar">
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>0</number>
+ </property>
+ <property name="textVisible">
+ <bool>false</bool>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="textDirection">
+ <enum>QProgressBar::BottomToTop</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QTextEdit" name="Output">
+ <property name="lineWrapMode">
+ <enum>QTextEdit::NoWrap</enum>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QCMakeCacheView</class>
+ <extends>QTreeView</extends>
+ <header>QCMakeCacheView.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="CMakeSetup.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Source/QtDialog/Compilers.h b/Source/QtDialog/Compilers.h
new file mode 100644
index 0000000..bdb1962
--- /dev/null
+++ b/Source/QtDialog/Compilers.h
@@ -0,0 +1,21 @@
+
+
+#ifndef COMPILERS_HPP
+#define COMPILERS_HPP
+
+#include <QWidget>
+
+#include <ui_Compilers.h>
+
+class Compilers : public QWidget, public Ui::Compilers
+{
+ Q_OBJECT
+public:
+ Compilers(QWidget* p = NULL)
+ : QWidget(p)
+ {
+ this->setupUi(this);
+ }
+};
+
+#endif
diff --git a/Source/QtDialog/Compilers.ui b/Source/QtDialog/Compilers.ui
new file mode 100644
index 0000000..41f70ac
--- /dev/null
+++ b/Source/QtDialog/Compilers.ui
@@ -0,0 +1,87 @@
+<ui version="4.0" >
+ <class>Compilers</class>
+ <widget class="QWidget" name="Compilers" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>506</width>
+ <height>115</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="leftMargin" >
+ <number>0</number>
+ </property>
+ <property name="topMargin" >
+ <number>0</number>
+ </property>
+ <property name="rightMargin" >
+ <number>0</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>0</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QGroupBox" name="groupBox_4" >
+ <property name="title" >
+ <string>Compilers</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="leftMargin" >
+ <number>4</number>
+ </property>
+ <property name="topMargin" >
+ <number>4</number>
+ </property>
+ <property name="rightMargin" >
+ <number>4</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_16" >
+ <property name="text" >
+ <string>C</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QCMakeFilePathEditor" name="CCompiler" />
+ </item>
+ <item row="0" column="2" >
+ <widget class="QLabel" name="label_17" >
+ <property name="text" >
+ <string>C++</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3" >
+ <widget class="QCMakeFilePathEditor" name="CXXCompiler" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_18" >
+ <property name="text" >
+ <string>Fortran</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QCMakeFilePathEditor" name="FortranCompiler" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QCMakeFilePathEditor</class>
+ <extends>QLineEdit</extends>
+ <header>QCMakeWidgets.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Source/QtDialog/CrossCompiler.ui b/Source/QtDialog/CrossCompiler.ui
new file mode 100644
index 0000000..1fb1ebf
--- /dev/null
+++ b/Source/QtDialog/CrossCompiler.ui
@@ -0,0 +1,213 @@
+<ui version="4.0" >
+ <class>CrossCompiler</class>
+ <widget class="QWidget" name="CrossCompiler" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>433</width>
+ <height>319</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>CrossCompiler</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Target System</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_6" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Operating System</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="systemName" />
+ </item>
+ <item row="0" column="2" colspan="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_10" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Version</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="systemVersion" />
+ </item>
+ <item row="1" column="2" >
+ <widget class="QLabel" name="label_11" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Processor</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3" >
+ <widget class="QLineEdit" name="systemProcessor" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Find Program/Library/Include</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_9" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Target Root</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QCMakePathEditor" name="crossFindRoot" />
+ </item>
+ <item row="0" column="2" >
+ <widget class="QLabel" name="label_12" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Program Mode</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3" >
+ <widget class="QComboBox" name="crossProgramMode" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_13" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Library Mode</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="crossLibraryMode" />
+ </item>
+ <item row="1" column="2" >
+ <widget class="QLabel" name="label_14" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Include Mode</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3" >
+ <widget class="QComboBox" name="crossIncludeMode" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="Compilers" native="1" name="CrossCompilers" >
+ <property name="focusPolicy" >
+ <enum>Qt::TabFocus</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QCMakePathEditor</class>
+ <extends>QLineEdit</extends>
+ <header>QCMakeWidgets.h</header>
+ </customwidget>
+ <customwidget>
+ <class>Compilers</class>
+ <extends>QWidget</extends>
+ <header>Compilers.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <tabstops>
+ <tabstop>systemVersion</tabstop>
+ <tabstop>systemProcessor</tabstop>
+ <tabstop>CrossCompilers</tabstop>
+ <tabstop>crossFindRoot</tabstop>
+ <tabstop>crossProgramMode</tabstop>
+ <tabstop>crossLibraryMode</tabstop>
+ <tabstop>crossIncludeMode</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Source/QtDialog/Delete16.png b/Source/QtDialog/Delete16.png
new file mode 100644
index 0000000..16989fee
--- /dev/null
+++ b/Source/QtDialog/Delete16.png
Binary files differ
diff --git a/Source/QtDialog/FirstConfigure.cxx b/Source/QtDialog/FirstConfigure.cxx
new file mode 100644
index 0000000..ca5e3b5
--- /dev/null
+++ b/Source/QtDialog/FirstConfigure.cxx
@@ -0,0 +1,574 @@
+
+#include "FirstConfigure.h"
+
+#include "Compilers.h"
+
+#include <QComboBox>
+#include <QRadioButton>
+#include <QSettings>
+#include <QVBoxLayout>
+
+StartCompilerSetup::StartCompilerSetup(QWidget* p)
+ : QWizardPage(p)
+{
+ QVBoxLayout* l = new QVBoxLayout(this);
+ l->addWidget(new QLabel(tr("Specify the generator for this project")));
+ this->GeneratorOptions = new QComboBox(this);
+ l->addWidget(this->GeneratorOptions);
+
+ // Add the ability to specify toolset (-T parameter)
+ ToolsetFrame = CreateToolsetWidgets();
+ l->addWidget(ToolsetFrame);
+
+ l->addSpacing(6);
+
+ this->CompilerSetupOptions[0] =
+ new QRadioButton(tr("Use default native compilers"), this);
+ this->CompilerSetupOptions[1] =
+ new QRadioButton(tr("Specify native compilers"), this);
+ this->CompilerSetupOptions[2] =
+ new QRadioButton(tr("Specify toolchain file for cross-compiling"), this);
+ this->CompilerSetupOptions[3] =
+ new QRadioButton(tr("Specify options for cross-compiling"), this);
+ l->addWidget(this->CompilerSetupOptions[0]);
+ l->addWidget(this->CompilerSetupOptions[1]);
+ l->addWidget(this->CompilerSetupOptions[2]);
+ l->addWidget(this->CompilerSetupOptions[3]);
+
+ this->CompilerSetupOptions[0]->setChecked(true);
+
+ QObject::connect(this->CompilerSetupOptions[0], SIGNAL(toggled(bool)), this,
+ SLOT(onSelectionChanged(bool)));
+ QObject::connect(this->CompilerSetupOptions[1], SIGNAL(toggled(bool)), this,
+ SLOT(onSelectionChanged(bool)));
+ QObject::connect(this->CompilerSetupOptions[2], SIGNAL(toggled(bool)), this,
+ SLOT(onSelectionChanged(bool)));
+ QObject::connect(this->CompilerSetupOptions[3], SIGNAL(toggled(bool)), this,
+ SLOT(onSelectionChanged(bool)));
+ QObject::connect(GeneratorOptions,
+ SIGNAL(currentIndexChanged(QString const&)), this,
+ SLOT(onGeneratorChanged(QString const&)));
+}
+
+QFrame* StartCompilerSetup::CreateToolsetWidgets()
+{
+ QFrame* frame = new QFrame(this);
+ QVBoxLayout* l = new QVBoxLayout(frame);
+ l->setContentsMargins(0, 0, 0, 0);
+
+ ToolsetLabel = new QLabel(tr("Optional toolset to use (-T parameter)"));
+ l->addWidget(ToolsetLabel);
+
+ Toolset = new QLineEdit(frame);
+ l->addWidget(Toolset);
+
+ return frame;
+}
+
+StartCompilerSetup::~StartCompilerSetup()
+{
+}
+
+void StartCompilerSetup::setGenerators(
+ std::vector<cmake::GeneratorInfo> const& gens)
+{
+ this->GeneratorOptions->clear();
+
+ 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()));
+
+ if (it->supportsToolset) {
+ this->GeneratorsSupportingToolset.append(
+ QString::fromLocal8Bit(it->name.c_str()));
+ }
+ }
+
+ this->GeneratorOptions->addItems(generator_list);
+}
+
+void StartCompilerSetup::setCurrentGenerator(const QString& gen)
+{
+ int idx = this->GeneratorOptions->findText(gen);
+ if (idx != -1) {
+ this->GeneratorOptions->setCurrentIndex(idx);
+ }
+}
+
+QString StartCompilerSetup::getGenerator() const
+{
+ return this->GeneratorOptions->currentText();
+};
+
+QString StartCompilerSetup::getToolset() const
+{
+ return this->Toolset->text();
+};
+
+bool StartCompilerSetup::defaultSetup() const
+{
+ return this->CompilerSetupOptions[0]->isChecked();
+}
+
+bool StartCompilerSetup::compilerSetup() const
+{
+ return this->CompilerSetupOptions[1]->isChecked();
+}
+
+bool StartCompilerSetup::crossCompilerToolChainFile() const
+{
+ return this->CompilerSetupOptions[2]->isChecked();
+}
+
+bool StartCompilerSetup::crossCompilerSetup() const
+{
+ return this->CompilerSetupOptions[3]->isChecked();
+}
+
+void StartCompilerSetup::onSelectionChanged(bool on)
+{
+ if (on)
+ selectionChanged();
+}
+
+void StartCompilerSetup::onGeneratorChanged(QString const& name)
+{
+ if (GeneratorsSupportingToolset.contains(name)) {
+ ToolsetFrame->show();
+ } else {
+ ToolsetFrame->hide();
+ }
+}
+
+int StartCompilerSetup::nextId() const
+{
+ if (compilerSetup())
+ return NativeSetup;
+ if (crossCompilerSetup())
+ return CrossSetup;
+ if (crossCompilerToolChainFile())
+ return ToolchainSetup;
+ return -1;
+}
+
+NativeCompilerSetup::NativeCompilerSetup(QWidget* p)
+ : QWizardPage(p)
+{
+ QVBoxLayout* l = new QVBoxLayout(this);
+ QWidget* c = new QWidget(this);
+ l->addWidget(c);
+ this->setupUi(c);
+}
+
+NativeCompilerSetup::~NativeCompilerSetup()
+{
+}
+
+QString NativeCompilerSetup::getCCompiler() const
+{
+ return this->CCompiler->text();
+}
+
+void NativeCompilerSetup::setCCompiler(const QString& s)
+{
+ this->CCompiler->setText(s);
+}
+
+QString NativeCompilerSetup::getCXXCompiler() const
+{
+ return this->CXXCompiler->text();
+}
+
+void NativeCompilerSetup::setCXXCompiler(const QString& s)
+{
+ this->CXXCompiler->setText(s);
+}
+
+QString NativeCompilerSetup::getFortranCompiler() const
+{
+ return this->FortranCompiler->text();
+}
+
+void NativeCompilerSetup::setFortranCompiler(const QString& s)
+{
+ this->FortranCompiler->setText(s);
+}
+
+CrossCompilerSetup::CrossCompilerSetup(QWidget* p)
+ : QWizardPage(p)
+{
+ this->setupUi(this);
+ QWidget::setTabOrder(systemName, systemVersion);
+ QWidget::setTabOrder(systemVersion, systemProcessor);
+ QWidget::setTabOrder(systemProcessor, CrossCompilers->CCompiler);
+ QWidget::setTabOrder(CrossCompilers->CCompiler, CrossCompilers->CXXCompiler);
+ QWidget::setTabOrder(CrossCompilers->CXXCompiler,
+ CrossCompilers->FortranCompiler);
+ QWidget::setTabOrder(CrossCompilers->FortranCompiler, crossFindRoot);
+ QWidget::setTabOrder(crossFindRoot, crossProgramMode);
+ QWidget::setTabOrder(crossProgramMode, crossLibraryMode);
+ QWidget::setTabOrder(crossLibraryMode, crossIncludeMode);
+
+ // fill in combo boxes
+ QStringList modes;
+ modes << tr("Search in Target Root, then native system");
+ modes << tr("Search only in Target Root");
+ modes << tr("Search only in native system");
+ crossProgramMode->addItems(modes);
+ crossLibraryMode->addItems(modes);
+ crossIncludeMode->addItems(modes);
+ crossProgramMode->setCurrentIndex(2);
+ crossLibraryMode->setCurrentIndex(1);
+ crossIncludeMode->setCurrentIndex(1);
+
+ this->registerField("systemName*", this->systemName);
+}
+
+CrossCompilerSetup::~CrossCompilerSetup()
+{
+}
+
+QString CrossCompilerSetup::getCCompiler() const
+{
+ return this->CrossCompilers->CCompiler->text();
+}
+
+void CrossCompilerSetup::setCCompiler(const QString& s)
+{
+ this->CrossCompilers->CCompiler->setText(s);
+}
+
+QString CrossCompilerSetup::getCXXCompiler() const
+{
+ return this->CrossCompilers->CXXCompiler->text();
+}
+
+void CrossCompilerSetup::setCXXCompiler(const QString& s)
+{
+ this->CrossCompilers->CXXCompiler->setText(s);
+}
+
+QString CrossCompilerSetup::getFortranCompiler() const
+{
+ return this->CrossCompilers->FortranCompiler->text();
+}
+
+void CrossCompilerSetup::setFortranCompiler(const QString& s)
+{
+ this->CrossCompilers->FortranCompiler->setText(s);
+}
+
+QString CrossCompilerSetup::getSystem() const
+{
+ return this->systemName->text();
+}
+
+void CrossCompilerSetup::setSystem(const QString& t)
+{
+ this->systemName->setText(t);
+}
+
+QString CrossCompilerSetup::getVersion() const
+{
+ return this->systemVersion->text();
+}
+
+void CrossCompilerSetup::setVersion(const QString& t)
+{
+ this->systemVersion->setText(t);
+}
+
+QString CrossCompilerSetup::getProcessor() const
+{
+ return this->systemProcessor->text();
+}
+
+void CrossCompilerSetup::setProcessor(const QString& t)
+{
+ this->systemProcessor->setText(t);
+}
+
+QString CrossCompilerSetup::getFindRoot() const
+{
+ return this->crossFindRoot->text();
+}
+
+void CrossCompilerSetup::setFindRoot(const QString& t)
+{
+ return this->crossFindRoot->setText(t);
+}
+
+int CrossCompilerSetup::getProgramMode() const
+{
+ return this->crossProgramMode->currentIndex();
+}
+
+int CrossCompilerSetup::getLibraryMode() const
+{
+ return this->crossLibraryMode->currentIndex();
+}
+
+int CrossCompilerSetup::getIncludeMode() const
+{
+ return this->crossIncludeMode->currentIndex();
+}
+
+void CrossCompilerSetup::setProgramMode(int m)
+{
+ this->crossProgramMode->setCurrentIndex(m);
+}
+
+void CrossCompilerSetup::setLibraryMode(int m)
+{
+ this->crossLibraryMode->setCurrentIndex(m);
+}
+
+void CrossCompilerSetup::setIncludeMode(int m)
+{
+ this->crossIncludeMode->setCurrentIndex(m);
+}
+
+ToolchainCompilerSetup::ToolchainCompilerSetup(QWidget* p)
+ : QWizardPage(p)
+{
+ QVBoxLayout* l = new QVBoxLayout(this);
+ l->addWidget(new QLabel(tr("Specify the Toolchain file")));
+ this->ToolchainFile = new QCMakeFilePathEditor(this);
+ l->addWidget(this->ToolchainFile);
+}
+
+ToolchainCompilerSetup::~ToolchainCompilerSetup()
+{
+}
+
+QString ToolchainCompilerSetup::toolchainFile() const
+{
+ return this->ToolchainFile->text();
+}
+
+void ToolchainCompilerSetup::setToolchainFile(const QString& t)
+{
+ this->ToolchainFile->setText(t);
+}
+
+FirstConfigure::FirstConfigure()
+{
+ // this->setOption(QWizard::HaveFinishButtonOnEarlyPages, true);
+ this->mStartCompilerSetupPage = new StartCompilerSetup(this);
+ this->setPage(Start, this->mStartCompilerSetupPage);
+ QObject::connect(this->mStartCompilerSetupPage, SIGNAL(selectionChanged()),
+ this, SLOT(restart()));
+
+ this->mNativeCompilerSetupPage = new NativeCompilerSetup(this);
+ this->setPage(NativeSetup, this->mNativeCompilerSetupPage);
+
+ this->mCrossCompilerSetupPage = new CrossCompilerSetup(this);
+ this->setPage(CrossSetup, this->mCrossCompilerSetupPage);
+
+ this->mToolchainCompilerSetupPage = new ToolchainCompilerSetup(this);
+ this->setPage(ToolchainSetup, this->mToolchainCompilerSetupPage);
+}
+
+FirstConfigure::~FirstConfigure()
+{
+}
+
+void FirstConfigure::setGenerators(
+ std::vector<cmake::GeneratorInfo> const& gens)
+{
+ this->mStartCompilerSetupPage->setGenerators(gens);
+}
+
+QString FirstConfigure::getGenerator() const
+{
+ return this->mStartCompilerSetupPage->getGenerator();
+}
+
+QString FirstConfigure::getToolset() const
+{
+ return this->mStartCompilerSetupPage->getToolset();
+}
+
+void FirstConfigure::loadFromSettings()
+{
+ QSettings settings;
+ // restore generator
+ settings.beginGroup("Settings/StartPath");
+ QString lastGen = settings.value("LastGenerator").toString();
+ this->mStartCompilerSetupPage->setCurrentGenerator(lastGen);
+ settings.endGroup();
+
+ // restore compiler setup
+ settings.beginGroup("Settings/Compiler");
+ this->mNativeCompilerSetupPage->setCCompiler(
+ settings.value("CCompiler").toString());
+ this->mNativeCompilerSetupPage->setCXXCompiler(
+ settings.value("CXXCompiler").toString());
+ this->mNativeCompilerSetupPage->setFortranCompiler(
+ settings.value("FortranCompiler").toString());
+ settings.endGroup();
+
+ // restore cross compiler setup
+ settings.beginGroup("Settings/CrossCompiler");
+ this->mCrossCompilerSetupPage->setCCompiler(
+ settings.value("CCompiler").toString());
+ this->mCrossCompilerSetupPage->setCXXCompiler(
+ settings.value("CXXCompiler").toString());
+ this->mCrossCompilerSetupPage->setFortranCompiler(
+ settings.value("FortranCompiler").toString());
+ this->mToolchainCompilerSetupPage->setToolchainFile(
+ settings.value("ToolChainFile").toString());
+ this->mCrossCompilerSetupPage->setSystem(
+ settings.value("SystemName").toString());
+ this->mCrossCompilerSetupPage->setVersion(
+ settings.value("SystemVersion").toString());
+ this->mCrossCompilerSetupPage->setProcessor(
+ settings.value("SystemProcessor").toString());
+ this->mCrossCompilerSetupPage->setFindRoot(
+ settings.value("FindRoot").toString());
+ this->mCrossCompilerSetupPage->setProgramMode(
+ settings.value("ProgramMode", 0).toInt());
+ this->mCrossCompilerSetupPage->setLibraryMode(
+ settings.value("LibraryMode", 0).toInt());
+ this->mCrossCompilerSetupPage->setIncludeMode(
+ settings.value("IncludeMode", 0).toInt());
+ settings.endGroup();
+}
+
+void FirstConfigure::saveToSettings()
+{
+ QSettings settings;
+
+ // save generator
+ settings.beginGroup("Settings/StartPath");
+ QString lastGen = this->mStartCompilerSetupPage->getGenerator();
+ settings.setValue("LastGenerator", lastGen);
+ settings.endGroup();
+
+ // save compiler setup
+ settings.beginGroup("Settings/Compiler");
+ settings.setValue("CCompiler",
+ this->mNativeCompilerSetupPage->getCCompiler());
+ settings.setValue("CXXCompiler",
+ this->mNativeCompilerSetupPage->getCXXCompiler());
+ settings.setValue("FortranCompiler",
+ this->mNativeCompilerSetupPage->getFortranCompiler());
+ settings.endGroup();
+
+ // save cross compiler setup
+ settings.beginGroup("Settings/CrossCompiler");
+ settings.setValue("CCompiler",
+ this->mCrossCompilerSetupPage->getCCompiler());
+ settings.setValue("CXXCompiler",
+ this->mCrossCompilerSetupPage->getCXXCompiler());
+ settings.setValue("FortranCompiler",
+ this->mCrossCompilerSetupPage->getFortranCompiler());
+ settings.setValue("ToolChainFile", this->getCrossCompilerToolChainFile());
+ settings.setValue("SystemName", this->mCrossCompilerSetupPage->getSystem());
+ settings.setValue("SystemVersion",
+ this->mCrossCompilerSetupPage->getVersion());
+ settings.setValue("SystemProcessor",
+ this->mCrossCompilerSetupPage->getProcessor());
+ settings.setValue("FindRoot", this->mCrossCompilerSetupPage->getFindRoot());
+ settings.setValue("ProgramMode",
+ this->mCrossCompilerSetupPage->getProgramMode());
+ settings.setValue("LibraryMode",
+ this->mCrossCompilerSetupPage->getLibraryMode());
+ settings.setValue("IncludeMode",
+ this->mCrossCompilerSetupPage->getIncludeMode());
+ settings.endGroup();
+}
+
+bool FirstConfigure::defaultSetup() const
+{
+ return this->mStartCompilerSetupPage->defaultSetup();
+}
+
+bool FirstConfigure::compilerSetup() const
+{
+ return this->mStartCompilerSetupPage->compilerSetup();
+}
+
+bool FirstConfigure::crossCompilerSetup() const
+{
+ return this->mStartCompilerSetupPage->crossCompilerSetup();
+}
+
+bool FirstConfigure::crossCompilerToolChainFile() const
+{
+ return this->mStartCompilerSetupPage->crossCompilerToolChainFile();
+}
+
+QString FirstConfigure::getCrossCompilerToolChainFile() const
+{
+ return this->mToolchainCompilerSetupPage->toolchainFile();
+}
+
+QString FirstConfigure::getSystemName() const
+{
+ return this->mCrossCompilerSetupPage->getSystem();
+}
+
+QString FirstConfigure::getCCompiler() const
+{
+ if (this->compilerSetup()) {
+ return this->mNativeCompilerSetupPage->getCCompiler();
+ } else if (this->crossCompilerSetup()) {
+ return this->mCrossCompilerSetupPage->getCCompiler();
+ }
+ return QString();
+}
+
+QString FirstConfigure::getCXXCompiler() const
+{
+ if (this->compilerSetup()) {
+ return this->mNativeCompilerSetupPage->getCXXCompiler();
+ } else if (this->crossCompilerSetup()) {
+ return this->mCrossCompilerSetupPage->getCXXCompiler();
+ }
+ return QString();
+}
+
+QString FirstConfigure::getFortranCompiler() const
+{
+ if (this->compilerSetup()) {
+ return this->mNativeCompilerSetupPage->getFortranCompiler();
+ } else if (this->crossCompilerSetup()) {
+ return this->mCrossCompilerSetupPage->getFortranCompiler();
+ }
+ return QString();
+}
+
+QString FirstConfigure::getSystemVersion() const
+{
+ return this->mCrossCompilerSetupPage->getVersion();
+}
+
+QString FirstConfigure::getSystemProcessor() const
+{
+ return this->mCrossCompilerSetupPage->getProcessor();
+}
+
+QString FirstConfigure::getCrossRoot() const
+{
+ return this->mCrossCompilerSetupPage->getFindRoot();
+}
+
+const QString CrossModes[] = { "BOTH", "ONLY", "NEVER" };
+
+QString FirstConfigure::getCrossProgramMode() const
+{
+ return CrossModes[this->mCrossCompilerSetupPage->getProgramMode()];
+}
+
+QString FirstConfigure::getCrossLibraryMode() const
+{
+ return CrossModes[this->mCrossCompilerSetupPage->getLibraryMode()];
+}
+
+QString FirstConfigure::getCrossIncludeMode() const
+{
+ return CrossModes[this->mCrossCompilerSetupPage->getIncludeMode()];
+}
diff --git a/Source/QtDialog/FirstConfigure.h b/Source/QtDialog/FirstConfigure.h
new file mode 100644
index 0000000..c467ddb
--- /dev/null
+++ b/Source/QtDialog/FirstConfigure.h
@@ -0,0 +1,189 @@
+
+#ifndef FirstConfigure_h
+#define FirstConfigure_h
+
+#include <QWizard>
+#include <QWizardPage>
+
+#include "cmake.h"
+
+#include "ui_Compilers.h"
+#include "ui_CrossCompiler.h"
+
+class QRadioButton;
+class QComboBox;
+
+//! the wizard pages we'll use for the first configure of a build
+enum FirstConfigurePages
+{
+ Start,
+ NativeSetup,
+ ToolchainSetup,
+ CrossSetup,
+ Done
+};
+
+//! the first page that gives basic options for what compilers setup to choose
+//! from
+class StartCompilerSetup : public QWizardPage
+{
+ Q_OBJECT
+public:
+ StartCompilerSetup(QWidget* p);
+ ~StartCompilerSetup();
+ void setGenerators(std::vector<cmake::GeneratorInfo> const& gens);
+ void setCurrentGenerator(const QString& gen);
+ QString getGenerator() const;
+ QString getToolset() const;
+
+ bool defaultSetup() const;
+ bool compilerSetup() const;
+ bool crossCompilerSetup() const;
+ bool crossCompilerToolChainFile() const;
+
+ int nextId() const;
+
+signals:
+ void selectionChanged();
+
+protected slots:
+ void onSelectionChanged(bool);
+ void onGeneratorChanged(QString const& name);
+
+protected:
+ QComboBox* GeneratorOptions;
+ QRadioButton* CompilerSetupOptions[4];
+ QFrame* ToolsetFrame;
+ QLineEdit* Toolset;
+ QLabel* ToolsetLabel;
+ QStringList GeneratorsSupportingToolset;
+
+private:
+ QFrame* CreateToolsetWidgets();
+};
+
+//! the page that gives basic options for native compilers
+class NativeCompilerSetup : public QWizardPage, protected Ui::Compilers
+{
+ Q_OBJECT
+public:
+ NativeCompilerSetup(QWidget* p);
+ ~NativeCompilerSetup();
+
+ QString getCCompiler() const;
+ void setCCompiler(const QString&);
+
+ QString getCXXCompiler() const;
+ void setCXXCompiler(const QString&);
+
+ QString getFortranCompiler() const;
+ void setFortranCompiler(const QString&);
+
+ int nextId() const { return -1; }
+};
+
+//! the page that gives options for cross compilers
+class CrossCompilerSetup : public QWizardPage, protected Ui::CrossCompiler
+{
+ Q_OBJECT
+public:
+ CrossCompilerSetup(QWidget* p);
+ ~CrossCompilerSetup();
+
+ QString getSystem() const;
+ void setSystem(const QString&);
+
+ QString getVersion() const;
+ void setVersion(const QString&);
+
+ QString getProcessor() const;
+ void setProcessor(const QString&);
+
+ QString getCCompiler() const;
+ void setCCompiler(const QString&);
+
+ QString getCXXCompiler() const;
+ void setCXXCompiler(const QString&);
+
+ QString getFortranCompiler() const;
+ void setFortranCompiler(const QString&);
+
+ QString getFindRoot() const;
+ void setFindRoot(const QString&);
+
+ enum CrossMode
+ {
+ BOTH,
+ ONLY,
+ NEVER
+ };
+
+ int getProgramMode() const;
+ void setProgramMode(int);
+ int getLibraryMode() const;
+ void setLibraryMode(int);
+ int getIncludeMode() const;
+ void setIncludeMode(int);
+
+ int nextId() const { return -1; }
+};
+
+//! the page that gives options for a toolchain file
+class ToolchainCompilerSetup : public QWizardPage
+{
+ Q_OBJECT
+public:
+ ToolchainCompilerSetup(QWidget* p);
+ ~ToolchainCompilerSetup();
+
+ QString toolchainFile() const;
+ void setToolchainFile(const QString&);
+
+ int nextId() const { return -1; }
+
+protected:
+ QCMakeFilePathEditor* ToolchainFile;
+};
+
+//! the wizard with the pages
+class FirstConfigure : public QWizard
+{
+ Q_OBJECT
+public:
+ FirstConfigure();
+ ~FirstConfigure();
+
+ void setGenerators(std::vector<cmake::GeneratorInfo> const& gens);
+ QString getGenerator() const;
+ QString getToolset() const;
+
+ bool defaultSetup() const;
+ bool compilerSetup() const;
+ bool crossCompilerSetup() const;
+ bool crossCompilerToolChainFile() const;
+
+ QString getCCompiler() const;
+ QString getCXXCompiler() const;
+ QString getFortranCompiler() const;
+
+ QString getSystemName() const;
+ QString getSystemVersion() const;
+ QString getSystemProcessor() const;
+ QString getCrossRoot() const;
+ QString getCrossProgramMode() const;
+ QString getCrossLibraryMode() const;
+ QString getCrossIncludeMode() const;
+
+ QString getCrossCompilerToolChainFile() const;
+
+ void loadFromSettings();
+ void saveToSettings();
+
+protected:
+ StartCompilerSetup* mStartCompilerSetupPage;
+ NativeCompilerSetup* mNativeCompilerSetupPage;
+ CrossCompilerSetup* mCrossCompilerSetupPage;
+ ToolchainCompilerSetup* mToolchainCompilerSetupPage;
+};
+
+#endif // FirstConfigure_h
diff --git a/Source/QtDialog/Info.plist.in b/Source/QtDialog/Info.plist.in
new file mode 100644
index 0000000..00a27c3
--- /dev/null
+++ b/Source/QtDialog/Info.plist.in
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+ <key>LSApplicationCategoryType</key>
+ <string>public.app-category.developer-tools</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+ <key>NSHighResolutionCapable</key>
+ <true/>
+</dict>
+</plist>
diff --git a/Source/QtDialog/Plus16.png b/Source/QtDialog/Plus16.png
new file mode 100644
index 0000000..552f6f0
--- /dev/null
+++ b/Source/QtDialog/Plus16.png
Binary files differ
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
new file mode 100644
index 0000000..c84e153
--- /dev/null
+++ b/Source/QtDialog/QCMake.cxx
@@ -0,0 +1,462 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "QCMake.h"
+
+#include <QCoreApplication>
+#include <QDir>
+
+#include "cmExternalMakefileProjectGenerator.h"
+#include "cmState.h"
+#include "cmSystemTools.h"
+
+#ifdef Q_OS_WIN
+#include "qt_windows.h" // For SetErrorMode
+#endif
+
+QCMake::QCMake(QObject* p)
+ : QObject(p)
+{
+ this->WarnUninitializedMode = false;
+ this->WarnUnusedMode = false;
+ qRegisterMetaType<QCMakeProperty>();
+ qRegisterMetaType<QCMakePropertyList>();
+
+ cmSystemTools::DisableRunCommandOutput();
+ cmSystemTools::SetRunCommandHideConsole(true);
+ cmSystemTools::SetMessageCallback(QCMake::messageCallback, this);
+ cmSystemTools::SetStdoutCallback(QCMake::stdoutCallback, this);
+ cmSystemTools::SetStderrCallback(QCMake::stderrCallback, this);
+
+ this->CMakeInstance = new cmake;
+ this->CMakeInstance->SetCMakeEditCommand(
+ cmSystemTools::GetCMakeGUICommand());
+ this->CMakeInstance->SetProgressCallback(QCMake::progressCallback, this);
+
+ cmSystemTools::SetInterruptCallback(QCMake::interruptCallback, this);
+
+ std::vector<cmake::GeneratorInfo> generators;
+ this->CMakeInstance->GetRegisteredGenerators(generators);
+
+ std::vector<cmake::GeneratorInfo>::const_iterator it;
+ for (it = generators.begin(); it != generators.end(); ++it) {
+ // Skip the generator "KDevelop3", since there is also
+ // "KDevelop3 - Unix Makefiles", which is the full and official name.
+ // The short name is actually only still there since this was the name
+ // in CMake 2.4, to keep "command line argument compatibility", but
+ // this is not necessary in the GUI.
+ if (it->name == "KDevelop3") {
+ continue;
+ }
+
+ this->AvailableGenerators.push_back(*it);
+ }
+}
+
+QCMake::~QCMake()
+{
+ delete this->CMakeInstance;
+ // cmDynamicLoader::FlushCache();
+}
+
+void QCMake::loadCache(const QString& dir)
+{
+ this->setBinaryDirectory(dir);
+}
+
+void QCMake::setSourceDirectory(const QString& _dir)
+{
+ QString dir = QString::fromLocal8Bit(
+ cmSystemTools::GetActualCaseForPath(_dir.toLocal8Bit().data()).c_str());
+ if (this->SourceDirectory != dir) {
+ this->SourceDirectory = QDir::fromNativeSeparators(dir);
+ emit this->sourceDirChanged(this->SourceDirectory);
+ }
+}
+
+void QCMake::setBinaryDirectory(const QString& _dir)
+{
+ QString dir = QString::fromLocal8Bit(
+ cmSystemTools::GetActualCaseForPath(_dir.toLocal8Bit().data()).c_str());
+ if (this->BinaryDirectory != dir) {
+ this->BinaryDirectory = QDir::fromNativeSeparators(dir);
+ emit this->binaryDirChanged(this->BinaryDirectory);
+ cmState* state = this->CMakeInstance->GetState();
+ this->setGenerator(QString());
+ this->setToolset(QString());
+ if (!this->CMakeInstance->LoadCache(
+ this->BinaryDirectory.toLocal8Bit().data())) {
+ QDir testDir(this->BinaryDirectory);
+ if (testDir.exists("CMakeCache.txt")) {
+ cmSystemTools::Error(
+ "There is a CMakeCache.txt file for the current binary "
+ "tree but cmake does not have permission to read it. "
+ "Please check the permissions of the directory you are trying to "
+ "run CMake on.");
+ }
+ }
+
+ QCMakePropertyList props = this->properties();
+ emit this->propertiesChanged(props);
+ const char* homeDir = state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
+ if (homeDir) {
+ setSourceDirectory(QString::fromLocal8Bit(homeDir));
+ }
+ const char* gen = state->GetCacheEntryValue("CMAKE_GENERATOR");
+ if (gen) {
+ const char* extraGen =
+ state->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
+ std::string curGen =
+ cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
+ gen, extraGen ? extraGen : "");
+ this->setGenerator(QString::fromLocal8Bit(curGen.c_str()));
+ }
+
+ const char* toolset = state->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET");
+ if (toolset) {
+ this->setToolset(QString::fromLocal8Bit(toolset));
+ }
+ }
+}
+
+void QCMake::setGenerator(const QString& gen)
+{
+ if (this->Generator != gen) {
+ this->Generator = gen;
+ emit this->generatorChanged(this->Generator);
+ }
+}
+
+void QCMake::setToolset(const QString& toolset)
+{
+ if (this->Toolset != toolset) {
+ this->Toolset = toolset;
+ emit this->toolsetChanged(this->Toolset);
+ }
+}
+
+void QCMake::configure()
+{
+#ifdef Q_OS_WIN
+ UINT lastErrorMode = SetErrorMode(0);
+#endif
+
+ this->CMakeInstance->SetHomeDirectory(
+ this->SourceDirectory.toLocal8Bit().data());
+ this->CMakeInstance->SetHomeOutputDirectory(
+ this->BinaryDirectory.toLocal8Bit().data());
+ this->CMakeInstance->SetGlobalGenerator(
+ this->CMakeInstance->CreateGlobalGenerator(
+ this->Generator.toLocal8Bit().data()));
+ this->CMakeInstance->SetGeneratorPlatform("");
+ this->CMakeInstance->SetGeneratorToolset(this->Toolset.toLocal8Bit().data());
+ this->CMakeInstance->LoadCache();
+ this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode);
+ this->CMakeInstance->SetWarnUnused(this->WarnUnusedMode);
+ this->CMakeInstance->PreLoadCMakeFiles();
+
+ InterruptFlag = 0;
+ cmSystemTools::ResetErrorOccuredFlag();
+
+ int err = this->CMakeInstance->Configure();
+
+#ifdef Q_OS_WIN
+ SetErrorMode(lastErrorMode);
+#endif
+
+ emit this->propertiesChanged(this->properties());
+ emit this->configureDone(err);
+}
+
+void QCMake::generate()
+{
+#ifdef Q_OS_WIN
+ UINT lastErrorMode = SetErrorMode(0);
+#endif
+
+ InterruptFlag = 0;
+ cmSystemTools::ResetErrorOccuredFlag();
+
+ int err = this->CMakeInstance->Generate();
+
+#ifdef Q_OS_WIN
+ SetErrorMode(lastErrorMode);
+#endif
+
+ emit this->generateDone(err);
+}
+
+void QCMake::setProperties(const QCMakePropertyList& newProps)
+{
+ QCMakePropertyList props = newProps;
+
+ QStringList toremove;
+
+ // 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) {
+ cmState::CacheEntryType t = state->GetCacheEntryType(*it);
+ if (t == cmState::INTERNAL || t == cmState::STATIC) {
+ continue;
+ }
+
+ QCMakeProperty prop;
+ prop.Key = QString::fromLocal8Bit(it->c_str());
+ int idx = props.indexOf(prop);
+ if (idx == -1) {
+ toremove.append(QString::fromLocal8Bit(it->c_str()));
+ } else {
+ prop = props[idx];
+ if (prop.Value.type() == QVariant::Bool) {
+ state->SetCacheEntryValue(*it, prop.Value.toBool() ? "ON" : "OFF");
+ } else {
+ state->SetCacheEntryValue(*it,
+ prop.Value.toString().toLocal8Bit().data());
+ }
+ props.removeAt(idx);
+ }
+ }
+
+ // remove some properites
+ foreach (QString s, toremove) {
+ this->CMakeInstance->UnwatchUnusedCli(s.toLocal8Bit().data());
+
+ state->RemoveCacheEntry(s.toLocal8Bit().data());
+ }
+
+ // add some new properites
+ foreach (QCMakeProperty s, props) {
+ this->CMakeInstance->WatchUnusedCli(s.Key.toLocal8Bit().data());
+
+ if (s.Type == QCMakeProperty::BOOL) {
+ this->CMakeInstance->AddCacheEntry(
+ s.Key.toLocal8Bit().data(), s.Value.toBool() ? "ON" : "OFF",
+ s.Help.toLocal8Bit().data(), cmState::BOOL);
+ } else if (s.Type == QCMakeProperty::STRING) {
+ this->CMakeInstance->AddCacheEntry(
+ s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(),
+ s.Help.toLocal8Bit().data(), cmState::STRING);
+ } else if (s.Type == QCMakeProperty::PATH) {
+ this->CMakeInstance->AddCacheEntry(
+ s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(),
+ s.Help.toLocal8Bit().data(), cmState::PATH);
+ } else if (s.Type == QCMakeProperty::FILEPATH) {
+ this->CMakeInstance->AddCacheEntry(
+ s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(),
+ s.Help.toLocal8Bit().data(), cmState::FILEPATH);
+ }
+ }
+
+ this->CMakeInstance->SaveCache(this->BinaryDirectory.toLocal8Bit().data());
+}
+
+QCMakePropertyList QCMake::properties() const
+{
+ QCMakePropertyList ret;
+
+ 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) {
+ cmState::CacheEntryType t = state->GetCacheEntryType(*i);
+ if (t == cmState::INTERNAL || t == cmState::STATIC ||
+ t == cmState::UNINITIALIZED) {
+ continue;
+ }
+
+ const char* cachedValue = state->GetCacheEntryValue(*i);
+
+ QCMakeProperty prop;
+ prop.Key = QString::fromLocal8Bit(i->c_str());
+ prop.Help =
+ QString::fromLocal8Bit(state->GetCacheEntryProperty(*i, "HELPSTRING"));
+ prop.Value = QString::fromLocal8Bit(cachedValue);
+ prop.Advanced = state->GetCacheEntryPropertyAsBool(*i, "ADVANCED");
+ if (t == cmState::BOOL) {
+ prop.Type = QCMakeProperty::BOOL;
+ prop.Value = cmSystemTools::IsOn(cachedValue);
+ } else if (t == cmState::PATH) {
+ prop.Type = QCMakeProperty::PATH;
+ } else if (t == cmState::FILEPATH) {
+ prop.Type = QCMakeProperty::FILEPATH;
+ } else if (t == cmState::STRING) {
+ prop.Type = QCMakeProperty::STRING;
+ const char* stringsProperty =
+ state->GetCacheEntryProperty(*i, "STRINGS");
+ if (stringsProperty) {
+ prop.Strings = QString::fromLocal8Bit(stringsProperty).split(";");
+ }
+ }
+
+ ret.append(prop);
+ }
+
+ return ret;
+}
+
+void QCMake::interrupt()
+{
+ this->InterruptFlag.ref();
+}
+
+bool QCMake::interruptCallback(void* cd)
+{
+ QCMake* self = reinterpret_cast<QCMake*>(cd);
+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
+ return self->InterruptFlag;
+#else
+ return self->InterruptFlag.load();
+#endif
+}
+
+void QCMake::progressCallback(const char* msg, float percent, void* cd)
+{
+ QCMake* self = reinterpret_cast<QCMake*>(cd);
+ if (percent >= 0) {
+ emit self->progressChanged(QString::fromLocal8Bit(msg), percent);
+ } else {
+ emit self->outputMessage(QString::fromLocal8Bit(msg));
+ }
+ QCoreApplication::processEvents();
+}
+
+void QCMake::messageCallback(const char* msg, const char* /*title*/,
+ bool& /*stop*/, void* cd)
+{
+ QCMake* self = reinterpret_cast<QCMake*>(cd);
+ emit self->errorMessage(QString::fromLocal8Bit(msg));
+ QCoreApplication::processEvents();
+}
+
+void QCMake::stdoutCallback(const char* msg, size_t len, void* cd)
+{
+ QCMake* self = reinterpret_cast<QCMake*>(cd);
+ emit self->outputMessage(QString::fromLocal8Bit(msg, int(len)));
+ QCoreApplication::processEvents();
+}
+
+void QCMake::stderrCallback(const char* msg, size_t len, void* cd)
+{
+ QCMake* self = reinterpret_cast<QCMake*>(cd);
+ emit self->outputMessage(QString::fromLocal8Bit(msg, int(len)));
+ QCoreApplication::processEvents();
+}
+
+QString QCMake::binaryDirectory() const
+{
+ return this->BinaryDirectory;
+}
+
+QString QCMake::sourceDirectory() const
+{
+ return this->SourceDirectory;
+}
+
+QString QCMake::generator() const
+{
+ return this->Generator;
+}
+
+std::vector<cmake::GeneratorInfo> const& QCMake::availableGenerators() const
+{
+ return AvailableGenerators;
+}
+
+void QCMake::deleteCache()
+{
+ // delete cache
+ this->CMakeInstance->DeleteCache(this->BinaryDirectory.toLocal8Bit().data());
+ // reload to make our cache empty
+ this->CMakeInstance->LoadCache(this->BinaryDirectory.toLocal8Bit().data());
+ // emit no generator and no properties
+ this->setGenerator(QString());
+ this->setToolset(QString());
+ QCMakePropertyList props = this->properties();
+ emit this->propertiesChanged(props);
+}
+
+void QCMake::reloadCache()
+{
+ // emit that the cache was cleaned out
+ QCMakePropertyList props;
+ emit this->propertiesChanged(props);
+ // reload
+ this->CMakeInstance->LoadCache(this->BinaryDirectory.toLocal8Bit().data());
+ // emit new cache properties
+ props = this->properties();
+ emit this->propertiesChanged(props);
+}
+
+void QCMake::setDebugOutput(bool flag)
+{
+ if (flag != this->CMakeInstance->GetDebugOutput()) {
+ this->CMakeInstance->SetDebugOutputOn(flag);
+ emit this->debugOutputChanged(flag);
+ }
+}
+
+bool QCMake::getDebugOutput() const
+{
+ return this->CMakeInstance->GetDebugOutput();
+}
+
+bool QCMake::getSuppressDevWarnings()
+{
+ return this->CMakeInstance->GetSuppressDevWarnings();
+}
+
+void QCMake::setSuppressDevWarnings(bool value)
+{
+ this->CMakeInstance->SetSuppressDevWarnings(value);
+}
+
+bool QCMake::getSuppressDeprecatedWarnings()
+{
+ return this->CMakeInstance->GetSuppressDeprecatedWarnings();
+}
+
+void QCMake::setSuppressDeprecatedWarnings(bool value)
+{
+ this->CMakeInstance->SetSuppressDeprecatedWarnings(value);
+}
+
+bool QCMake::getDevWarningsAsErrors()
+{
+ return this->CMakeInstance->GetDevWarningsAsErrors();
+}
+
+void QCMake::setDevWarningsAsErrors(bool value)
+{
+ this->CMakeInstance->SetDevWarningsAsErrors(value);
+}
+
+bool QCMake::getDeprecatedWarningsAsErrors()
+{
+ return this->CMakeInstance->GetDeprecatedWarningsAsErrors();
+}
+
+void QCMake::setDeprecatedWarningsAsErrors(bool value)
+{
+ this->CMakeInstance->SetDeprecatedWarningsAsErrors(value);
+}
+
+void QCMake::setWarnUninitializedMode(bool value)
+{
+ this->WarnUninitializedMode = value;
+}
+
+void QCMake::setWarnUnusedMode(bool value)
+{
+ this->WarnUnusedMode = value;
+}
diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h
new file mode 100644
index 0000000..a818c6b
--- /dev/null
+++ b/Source/QtDialog/QCMake.h
@@ -0,0 +1,184 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef QCMake_h
+#define QCMake_h
+
+#include "cmake.h"
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4127)
+#pragma warning(disable : 4512)
+#endif
+
+#include <vector>
+
+#include <QAtomicInt>
+#include <QList>
+#include <QMetaType>
+#include <QObject>
+#include <QString>
+#include <QStringList>
+#include <QVariant>
+
+/// struct to represent cmake properties in Qt
+/// Value is of type String or Bool
+struct QCMakeProperty
+{
+ enum PropertyType
+ {
+ BOOL,
+ PATH,
+ FILEPATH,
+ STRING
+ };
+ QString Key;
+ QVariant Value;
+ QStringList Strings;
+ QString Help;
+ PropertyType Type;
+ bool Advanced;
+ bool operator==(const QCMakeProperty& other) const
+ {
+ return this->Key == other.Key;
+ }
+ bool operator<(const QCMakeProperty& other) const
+ {
+ return this->Key < other.Key;
+ }
+};
+
+// list of properties
+typedef QList<QCMakeProperty> QCMakePropertyList;
+
+// allow QVariant to be a property or list of properties
+Q_DECLARE_METATYPE(QCMakeProperty)
+Q_DECLARE_METATYPE(QCMakePropertyList)
+
+/// Qt API for CMake library.
+/// Wrapper like class allows for easier integration with
+/// Qt features such as, signal/slot connections, multi-threading, etc..
+class QCMake : public QObject
+{
+ Q_OBJECT
+public:
+ QCMake(QObject* p = 0);
+ ~QCMake();
+public slots:
+ /// load the cache file in a directory
+ void loadCache(const QString& dir);
+ /// set the source directory containing the source
+ void setSourceDirectory(const QString& dir);
+ /// set the binary directory to build in
+ void setBinaryDirectory(const QString& dir);
+ /// set the desired generator to use
+ void setGenerator(const QString& generator);
+ /// set the desired generator to use
+ void setToolset(const QString& toolset);
+ /// do the configure step
+ void configure();
+ /// generate the files
+ void generate();
+ /// set the property values
+ void setProperties(const QCMakePropertyList&);
+ /// interrupt the configure or generate process (if connecting, make a direct
+ /// connection)
+ void interrupt();
+ /// delete the cache in binary directory
+ void deleteCache();
+ /// reload the cache in binary directory
+ void reloadCache();
+ /// set whether to do debug output
+ void setDebugOutput(bool);
+ /// get whether to do suppress dev warnings
+ bool getSuppressDevWarnings();
+ /// set whether to do suppress dev warnings
+ void setSuppressDevWarnings(bool value);
+ /// get whether to do suppress deprecated warnings
+ bool getSuppressDeprecatedWarnings();
+ /// set whether to do suppress deprecated warnings
+ void setSuppressDeprecatedWarnings(bool value);
+ /// get whether to treat developer (author) warnings as errors
+ bool getDevWarningsAsErrors();
+ /// set whether to treat developer (author) warnings as errors
+ void setDevWarningsAsErrors(bool value);
+ /// get whether to treat deprecated warnings as errors
+ bool getDeprecatedWarningsAsErrors();
+ /// set whether to treat deprecated warnings as errors
+ void setDeprecatedWarningsAsErrors(bool value);
+ /// set whether to run cmake with warnings about uninitialized variables
+ void setWarnUninitializedMode(bool value);
+ /// set whether to run cmake with warnings about unused variables
+ void setWarnUnusedMode(bool value);
+
+public:
+ /// get the list of cache properties
+ QCMakePropertyList properties() const;
+ /// get the current binary directory
+ QString binaryDirectory() const;
+ /// get the current source directory
+ QString sourceDirectory() const;
+ /// get the current generator
+ QString generator() const;
+ /// get the available generators
+ std::vector<cmake::GeneratorInfo> const& availableGenerators() const;
+ /// get whether to do debug output
+ bool getDebugOutput() const;
+
+signals:
+ /// signal when properties change (during read from disk or configure
+ /// process)
+ void propertiesChanged(const QCMakePropertyList& vars);
+ /// signal when the generator changes
+ void generatorChanged(const QString& gen);
+ /// signal when the source directory changes (binary directory already
+ /// containing a CMakeCache.txt file)
+ void sourceDirChanged(const QString& dir);
+ /// signal when the binary directory changes
+ void binaryDirChanged(const QString& dir);
+ /// signal for progress events
+ void progressChanged(const QString& msg, float percent);
+ /// signal when configure is done
+ void configureDone(int error);
+ /// signal when generate is done
+ void generateDone(int error);
+ /// signal when there is an output message
+ void outputMessage(const QString& msg);
+ /// signal when there is an error message
+ void errorMessage(const QString& msg);
+ /// signal when debug output changes
+ void debugOutputChanged(bool);
+ /// signal when the toolset changes
+ void toolsetChanged(const QString& toolset);
+
+protected:
+ cmake* CMakeInstance;
+
+ static bool interruptCallback(void*);
+ static void progressCallback(const char* msg, float percent, void* cd);
+ static void messageCallback(const char* msg, const char* title, bool&,
+ void* cd);
+ static void stdoutCallback(const char* msg, size_t len, void* cd);
+ static void stderrCallback(const char* msg, size_t len, void* cd);
+ bool WarnUninitializedMode;
+ bool WarnUnusedMode;
+ bool WarnUnusedAllMode;
+ QString SourceDirectory;
+ QString BinaryDirectory;
+ QString Generator;
+ QString Toolset;
+ std::vector<cmake::GeneratorInfo> AvailableGenerators;
+ QString CMakeExecutable;
+ QAtomicInt InterruptFlag;
+};
+
+#endif // QCMake_h
diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx
new file mode 100644
index 0000000..cc1f4aa
--- /dev/null
+++ b/Source/QtDialog/QCMakeCacheView.cxx
@@ -0,0 +1,687 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "QCMakeCacheView.h"
+
+#include <QApplication>
+#include <QEvent>
+#include <QHBoxLayout>
+#include <QHeaderView>
+#include <QKeyEvent>
+#include <QMetaProperty>
+#include <QSortFilterProxyModel>
+#include <QStyle>
+
+#include "QCMakeWidgets.h"
+
+// filter for searches
+class QCMakeSearchFilter : public QSortFilterProxyModel
+{
+public:
+ QCMakeSearchFilter(QObject* o)
+ : QSortFilterProxyModel(o)
+ {
+ }
+
+protected:
+ bool filterAcceptsRow(int row, const QModelIndex& p) const
+ {
+ QStringList strs;
+ const QAbstractItemModel* m = this->sourceModel();
+ QModelIndex idx = m->index(row, 0, p);
+
+ // if there are no children, get strings for column 0 and 1
+ if (!m->hasChildren(idx)) {
+ strs.append(m->data(idx).toString());
+ idx = m->index(row, 1, p);
+ strs.append(m->data(idx).toString());
+ } else {
+ // get strings for children entries to compare with
+ // instead of comparing with the parent
+ int num = m->rowCount(idx);
+ for (int i = 0; i < num; i++) {
+ QModelIndex tmpidx = m->index(i, 0, idx);
+ strs.append(m->data(tmpidx).toString());
+ tmpidx = m->index(i, 1, idx);
+ strs.append(m->data(tmpidx).toString());
+ }
+ }
+
+ // check all strings for a match
+ foreach (QString str, strs) {
+ if (str.contains(this->filterRegExp())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+};
+
+// filter for searches
+class QCMakeAdvancedFilter : public QSortFilterProxyModel
+{
+public:
+ QCMakeAdvancedFilter(QObject* o)
+ : QSortFilterProxyModel(o)
+ , ShowAdvanced(false)
+ {
+ }
+
+ void setShowAdvanced(bool f)
+ {
+ this->ShowAdvanced = f;
+ this->invalidate();
+ }
+ bool showAdvanced() const { return this->ShowAdvanced; }
+
+protected:
+ bool ShowAdvanced;
+
+ bool filterAcceptsRow(int row, const QModelIndex& p) const
+ {
+ const QAbstractItemModel* m = this->sourceModel();
+ QModelIndex idx = m->index(row, 0, p);
+
+ // if there are no children
+ if (!m->hasChildren(idx)) {
+ bool adv = m->data(idx, QCMakeCacheModel::AdvancedRole).toBool();
+ if (!adv || (adv && this->ShowAdvanced)) {
+ return true;
+ }
+ return false;
+ }
+
+ // check children
+ int num = m->rowCount(idx);
+ for (int i = 0; i < num; i++) {
+ bool accept = this->filterAcceptsRow(i, idx);
+ if (accept) {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+QCMakeCacheView::QCMakeCacheView(QWidget* p)
+ : QTreeView(p)
+{
+ // hook up our model and search/filter proxies
+ this->CacheModel = new QCMakeCacheModel(this);
+ this->AdvancedFilter = new QCMakeAdvancedFilter(this);
+ this->AdvancedFilter->setSourceModel(this->CacheModel);
+ this->AdvancedFilter->setDynamicSortFilter(true);
+ this->SearchFilter = new QCMakeSearchFilter(this);
+ this->SearchFilter->setSourceModel(this->AdvancedFilter);
+ this->SearchFilter->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ this->SearchFilter->setDynamicSortFilter(true);
+ this->setModel(this->SearchFilter);
+
+ // our delegate for creating our editors
+ QCMakeCacheModelDelegate* delegate = new QCMakeCacheModelDelegate(this);
+ this->setItemDelegate(delegate);
+
+ this->setUniformRowHeights(true);
+
+ this->setEditTriggers(QAbstractItemView::AllEditTriggers);
+
+ // tab, backtab doesn't step through items
+ this->setTabKeyNavigation(false);
+
+ this->setRootIsDecorated(false);
+}
+
+bool QCMakeCacheView::event(QEvent* e)
+{
+ if (e->type() == QEvent::Show) {
+ this->header()->setDefaultSectionSize(this->viewport()->width() / 2);
+ }
+ return QTreeView::event(e);
+}
+
+QCMakeCacheModel* QCMakeCacheView::cacheModel() const
+{
+ return this->CacheModel;
+}
+
+QModelIndex QCMakeCacheView::moveCursor(CursorAction act,
+ Qt::KeyboardModifiers mod)
+{
+ // want home/end to go to begin/end of rows, not columns
+ if (act == MoveHome) {
+ return this->model()->index(0, 1);
+ } else if (act == MoveEnd) {
+ return this->model()->index(this->model()->rowCount() - 1, 1);
+ }
+ return QTreeView::moveCursor(act, mod);
+}
+
+void QCMakeCacheView::setShowAdvanced(bool s)
+{
+#if QT_VERSION >= 040300
+ // new 4.3 API that needs to be called. what about an older Qt?
+ this->SearchFilter->invalidate();
+#endif
+
+ this->AdvancedFilter->setShowAdvanced(s);
+}
+
+bool QCMakeCacheView::showAdvanced() const
+{
+ return this->AdvancedFilter->showAdvanced();
+}
+
+void QCMakeCacheView::setSearchFilter(const QString& s)
+{
+ this->SearchFilter->setFilterFixedString(s);
+}
+
+QCMakeCacheModel::QCMakeCacheModel(QObject* p)
+ : QStandardItemModel(p)
+ , EditEnabled(true)
+ , NewPropertyCount(0)
+ , View(FlatView)
+{
+ this->ShowNewProperties = true;
+ QStringList labels;
+ labels << tr("Name") << tr("Value");
+ this->setHorizontalHeaderLabels(labels);
+}
+
+QCMakeCacheModel::~QCMakeCacheModel()
+{
+}
+
+static uint qHash(const QCMakeProperty& p)
+{
+ return qHash(p.Key);
+}
+
+void QCMakeCacheModel::setShowNewProperties(bool f)
+{
+ this->ShowNewProperties = f;
+}
+
+void QCMakeCacheModel::clear()
+{
+ this->QStandardItemModel::clear();
+ this->NewPropertyCount = 0;
+
+ QStringList labels;
+ labels << tr("Name") << tr("Value");
+ this->setHorizontalHeaderLabels(labels);
+}
+
+void QCMakeCacheModel::setProperties(const QCMakePropertyList& props)
+{
+ QSet<QCMakeProperty> newProps, newProps2;
+
+ if (this->ShowNewProperties) {
+ newProps = props.toSet();
+ newProps2 = newProps;
+ QSet<QCMakeProperty> oldProps = this->properties().toSet();
+ oldProps.intersect(newProps);
+ newProps.subtract(oldProps);
+ newProps2.subtract(newProps);
+ } else {
+ newProps2 = props.toSet();
+ }
+
+ bool b = this->blockSignals(true);
+
+ this->clear();
+ this->NewPropertyCount = newProps.size();
+
+ if (View == FlatView) {
+ QCMakePropertyList newP = newProps.toList();
+ QCMakePropertyList newP2 = newProps2.toList();
+ qSort(newP);
+ qSort(newP2);
+ int row_count = 0;
+ foreach (QCMakeProperty p, newP) {
+ this->insertRow(row_count);
+ this->setPropertyData(this->index(row_count, 0), p, true);
+ row_count++;
+ }
+ foreach (QCMakeProperty p, newP2) {
+ this->insertRow(row_count);
+ this->setPropertyData(this->index(row_count, 0), p, false);
+ row_count++;
+ }
+ } else if (this->View == GroupView) {
+ QMap<QString, QCMakePropertyList> newPropsTree;
+ this->breakProperties(newProps, newPropsTree);
+ QMap<QString, QCMakePropertyList> newPropsTree2;
+ this->breakProperties(newProps2, newPropsTree2);
+
+ QStandardItem* root = this->invisibleRootItem();
+
+ foreach (QString key, newPropsTree.keys()) {
+ QCMakePropertyList props2 = newPropsTree[key];
+
+ QList<QStandardItem*> parentItems;
+ parentItems.append(
+ new QStandardItem(key.isEmpty() ? tr("Ungrouped Entries") : key));
+ parentItems.append(new QStandardItem());
+ parentItems[0]->setData(QBrush(QColor(255, 100, 100)),
+ Qt::BackgroundColorRole);
+ parentItems[1]->setData(QBrush(QColor(255, 100, 100)),
+ Qt::BackgroundColorRole);
+ parentItems[0]->setData(1, GroupRole);
+ parentItems[1]->setData(1, GroupRole);
+ root->appendRow(parentItems);
+
+ int num = props2.size();
+ for (int i = 0; i < num; i++) {
+ QCMakeProperty prop = props2[i];
+ QList<QStandardItem*> items;
+ items.append(new QStandardItem());
+ items.append(new QStandardItem());
+ parentItems[0]->appendRow(items);
+ this->setPropertyData(this->indexFromItem(items[0]), prop, true);
+ }
+ }
+
+ foreach (QString key, newPropsTree2.keys()) {
+ QCMakePropertyList props2 = newPropsTree2[key];
+
+ QStandardItem* parentItem =
+ new QStandardItem(key.isEmpty() ? tr("Ungrouped Entries") : key);
+ root->appendRow(parentItem);
+ parentItem->setData(1, GroupRole);
+
+ int num = props2.size();
+ for (int i = 0; i < num; i++) {
+ QCMakeProperty prop = props2[i];
+ QList<QStandardItem*> items;
+ items.append(new QStandardItem());
+ items.append(new QStandardItem());
+ parentItem->appendRow(items);
+ this->setPropertyData(this->indexFromItem(items[0]), prop, false);
+ }
+ }
+ }
+
+ this->blockSignals(b);
+ this->reset();
+}
+
+QCMakeCacheModel::ViewType QCMakeCacheModel::viewType() const
+{
+ return this->View;
+}
+
+void QCMakeCacheModel::setViewType(QCMakeCacheModel::ViewType t)
+{
+ this->View = t;
+
+ QCMakePropertyList props = this->properties();
+ QCMakePropertyList oldProps;
+ int numNew = this->NewPropertyCount;
+ int numTotal = props.count();
+ for (int i = numNew; i < numTotal; i++) {
+ oldProps.append(props[i]);
+ }
+
+ bool b = this->blockSignals(true);
+ this->clear();
+ this->setProperties(oldProps);
+ this->setProperties(props);
+ this->blockSignals(b);
+ this->reset();
+}
+
+void QCMakeCacheModel::setPropertyData(const QModelIndex& idx1,
+ const QCMakeProperty& prop, bool isNew)
+{
+ QModelIndex idx2 = idx1.sibling(idx1.row(), 1);
+
+ this->setData(idx1, prop.Key, Qt::DisplayRole);
+ this->setData(idx1, prop.Help, QCMakeCacheModel::HelpRole);
+ this->setData(idx1, prop.Type, QCMakeCacheModel::TypeRole);
+ this->setData(idx1, prop.Advanced, QCMakeCacheModel::AdvancedRole);
+
+ if (prop.Type == QCMakeProperty::BOOL) {
+ int check = prop.Value.toBool() ? Qt::Checked : Qt::Unchecked;
+ this->setData(idx2, check, Qt::CheckStateRole);
+ } else {
+ this->setData(idx2, prop.Value, Qt::DisplayRole);
+ }
+ this->setData(idx2, prop.Help, QCMakeCacheModel::HelpRole);
+
+ if (!prop.Strings.isEmpty()) {
+ this->setData(idx1, prop.Strings, QCMakeCacheModel::StringsRole);
+ }
+
+ if (isNew) {
+ this->setData(idx1, QBrush(QColor(255, 100, 100)),
+ Qt::BackgroundColorRole);
+ this->setData(idx2, QBrush(QColor(255, 100, 100)),
+ Qt::BackgroundColorRole);
+ }
+}
+
+void QCMakeCacheModel::getPropertyData(const QModelIndex& idx1,
+ QCMakeProperty& prop) const
+{
+ QModelIndex idx2 = idx1.sibling(idx1.row(), 1);
+
+ prop.Key = this->data(idx1, Qt::DisplayRole).toString();
+ prop.Help = this->data(idx1, HelpRole).toString();
+ prop.Type = static_cast<QCMakeProperty::PropertyType>(
+ this->data(idx1, TypeRole).toInt());
+ prop.Advanced = this->data(idx1, AdvancedRole).toBool();
+ prop.Strings =
+ this->data(idx1, QCMakeCacheModel::StringsRole).toStringList();
+ if (prop.Type == QCMakeProperty::BOOL) {
+ int check = this->data(idx2, Qt::CheckStateRole).toInt();
+ prop.Value = check == Qt::Checked;
+ } else {
+ prop.Value = this->data(idx2, Qt::DisplayRole).toString();
+ }
+}
+
+QString QCMakeCacheModel::prefix(const QString& s)
+{
+ QString prefix = s.section('_', 0, 0);
+ if (prefix == s) {
+ prefix = QString();
+ }
+ return prefix;
+}
+
+void QCMakeCacheModel::breakProperties(
+ const QSet<QCMakeProperty>& props, QMap<QString, QCMakePropertyList>& result)
+{
+ QMap<QString, QCMakePropertyList> tmp;
+ // return a map of properties grouped by prefixes, and sorted
+ foreach (QCMakeProperty p, props) {
+ QString prefix = QCMakeCacheModel::prefix(p.Key);
+ tmp[prefix].append(p);
+ }
+ // sort it and re-org any properties with only one sub item
+ QCMakePropertyList reorgProps;
+ QMap<QString, QCMakePropertyList>::iterator iter;
+ for (iter = tmp.begin(); iter != tmp.end();) {
+ if (iter->count() == 1) {
+ reorgProps.append((*iter)[0]);
+ iter = tmp.erase(iter);
+ } else {
+ qSort(*iter);
+ ++iter;
+ }
+ }
+ if (reorgProps.count()) {
+ tmp[QString()] += reorgProps;
+ }
+ result = tmp;
+}
+
+QCMakePropertyList QCMakeCacheModel::properties() const
+{
+ QCMakePropertyList props;
+
+ if (!this->rowCount()) {
+ return props;
+ }
+
+ QList<QModelIndex> idxs;
+ idxs.append(this->index(0, 0));
+
+ // walk the entire model for property entries
+ // this works regardless of a flat view or a tree view
+ while (!idxs.isEmpty()) {
+ QModelIndex idx = idxs.last();
+ if (this->hasChildren(idx) && this->rowCount(idx)) {
+ idxs.append(this->index(0, 0, idx));
+ } else {
+ if (!data(idx, GroupRole).toInt()) {
+ // get data
+ QCMakeProperty prop;
+ this->getPropertyData(idx, prop);
+ props.append(prop);
+ }
+
+ // go to the next in the tree
+ while (!idxs.isEmpty() &&
+ (
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) && \
+ QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
+ (idxs.last().row() + 1) >= rowCount(idxs.last().parent()) ||
+#endif
+ !idxs.last().sibling(idxs.last().row() + 1, 0).isValid())) {
+ idxs.removeLast();
+ }
+ if (!idxs.isEmpty()) {
+ idxs.last() = idxs.last().sibling(idxs.last().row() + 1, 0);
+ }
+ }
+ }
+
+ return props;
+}
+
+bool QCMakeCacheModel::insertProperty(QCMakeProperty::PropertyType t,
+ const QString& name,
+ const QString& description,
+ const QVariant& value, bool advanced)
+{
+ QCMakeProperty prop;
+ prop.Key = name;
+ prop.Value = value;
+ prop.Help = description;
+ prop.Type = t;
+ prop.Advanced = advanced;
+
+ // insert at beginning
+ this->insertRow(0);
+ this->setPropertyData(this->index(0, 0), prop, true);
+ this->NewPropertyCount++;
+ return true;
+}
+
+void QCMakeCacheModel::setEditEnabled(bool e)
+{
+ this->EditEnabled = e;
+}
+
+bool QCMakeCacheModel::editEnabled() const
+{
+ return this->EditEnabled;
+}
+
+int QCMakeCacheModel::newPropertyCount() const
+{
+ return this->NewPropertyCount;
+}
+
+Qt::ItemFlags QCMakeCacheModel::flags(const QModelIndex& idx) const
+{
+ Qt::ItemFlags f = QStandardItemModel::flags(idx);
+ if (!this->EditEnabled) {
+ f &= ~Qt::ItemIsEditable;
+ return f;
+ }
+ if (QCMakeProperty::BOOL == this->data(idx, TypeRole).toInt()) {
+ f |= Qt::ItemIsUserCheckable;
+ }
+ return f;
+}
+
+QModelIndex QCMakeCacheModel::buddy(const QModelIndex& idx) const
+{
+ if (!this->hasChildren(idx) &&
+ this->data(idx, TypeRole).toInt() != QCMakeProperty::BOOL) {
+ return this->index(idx.row(), 1, idx.parent());
+ }
+ return idx;
+}
+
+QCMakeCacheModelDelegate::QCMakeCacheModelDelegate(QObject* p)
+ : QItemDelegate(p)
+ , FileDialogFlag(false)
+{
+}
+
+void QCMakeCacheModelDelegate::setFileDialogFlag(bool f)
+{
+ this->FileDialogFlag = f;
+}
+
+QWidget* QCMakeCacheModelDelegate::createEditor(QWidget* p,
+ const QStyleOptionViewItem&,
+ const QModelIndex& idx) const
+{
+ QModelIndex var = idx.sibling(idx.row(), 0);
+ int type = var.data(QCMakeCacheModel::TypeRole).toInt();
+ if (type == QCMakeProperty::BOOL) {
+ return NULL;
+ } else if (type == QCMakeProperty::PATH) {
+ QCMakePathEditor* editor =
+ new QCMakePathEditor(p, var.data(Qt::DisplayRole).toString());
+ QObject::connect(editor, SIGNAL(fileDialogExists(bool)), this,
+ SLOT(setFileDialogFlag(bool)));
+ return editor;
+ } else if (type == QCMakeProperty::FILEPATH) {
+ QCMakeFilePathEditor* editor =
+ new QCMakeFilePathEditor(p, var.data(Qt::DisplayRole).toString());
+ QObject::connect(editor, SIGNAL(fileDialogExists(bool)), this,
+ SLOT(setFileDialogFlag(bool)));
+ return editor;
+ } else if (type == QCMakeProperty::STRING &&
+ var.data(QCMakeCacheModel::StringsRole).isValid()) {
+ QCMakeComboBox* editor = new QCMakeComboBox(
+ p, var.data(QCMakeCacheModel::StringsRole).toStringList());
+ editor->setFrame(false);
+ return editor;
+ }
+
+ QLineEdit* editor = new QLineEdit(p);
+ editor->setFrame(false);
+ return editor;
+}
+
+bool QCMakeCacheModelDelegate::editorEvent(QEvent* e,
+ QAbstractItemModel* model,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index)
+{
+ Qt::ItemFlags flags = model->flags(index);
+ if (!(flags & Qt::ItemIsUserCheckable) ||
+ !(option.state & QStyle::State_Enabled) ||
+ !(flags & Qt::ItemIsEnabled)) {
+ return false;
+ }
+
+ QVariant value = index.data(Qt::CheckStateRole);
+ if (!value.isValid()) {
+ return false;
+ }
+
+ if ((e->type() == QEvent::MouseButtonRelease) ||
+ (e->type() == QEvent::MouseButtonDblClick)) {
+ // eat the double click events inside the check rect
+ if (e->type() == QEvent::MouseButtonDblClick) {
+ return true;
+ }
+ } else if (e->type() == QEvent::KeyPress) {
+ if (static_cast<QKeyEvent*>(e)->key() != Qt::Key_Space &&
+ static_cast<QKeyEvent*>(e)->key() != Qt::Key_Select) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ Qt::CheckState state =
+ (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked ? Qt::Unchecked
+ : Qt::Checked);
+ bool success = model->setData(index, state, Qt::CheckStateRole);
+ if (success) {
+ this->recordChange(model, index);
+ }
+ return success;
+}
+
+// Issue 205903 fixed in Qt 4.5.0.
+// Can remove this function and FileDialogFlag when minimum Qt version is 4.5
+bool QCMakeCacheModelDelegate::eventFilter(QObject* object, QEvent* evt)
+{
+ // workaround for what looks like a bug in Qt on Mac OS X
+ // where it doesn't create a QWidget wrapper for the native file dialog
+ // so the Qt library ends up assuming the focus was lost to something else
+
+ if (evt->type() == QEvent::FocusOut && this->FileDialogFlag) {
+ return false;
+ }
+ return QItemDelegate::eventFilter(object, evt);
+}
+
+void QCMakeCacheModelDelegate::setModelData(QWidget* editor,
+ QAbstractItemModel* model,
+ const QModelIndex& index) const
+{
+ QItemDelegate::setModelData(editor, model, index);
+ const_cast<QCMakeCacheModelDelegate*>(this)->recordChange(model, index);
+}
+
+QSize QCMakeCacheModelDelegate::sizeHint(const QStyleOptionViewItem& option,
+ const QModelIndex& index) const
+{
+ QSize sz = QItemDelegate::sizeHint(option, index);
+ QStyle* style = QApplication::style();
+
+ // increase to checkbox size
+ QStyleOptionButton opt;
+ opt.QStyleOption::operator=(option);
+ sz = sz.expandedTo(
+ style->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt, NULL)
+ .size());
+
+ return sz;
+}
+
+QSet<QCMakeProperty> QCMakeCacheModelDelegate::changes() const
+{
+ return mChanges;
+}
+
+void QCMakeCacheModelDelegate::clearChanges()
+{
+ mChanges.clear();
+}
+
+void QCMakeCacheModelDelegate::recordChange(QAbstractItemModel* model,
+ const QModelIndex& index)
+{
+ QModelIndex idx = index;
+ QAbstractItemModel* mymodel = model;
+ while (qobject_cast<QAbstractProxyModel*>(mymodel)) {
+ idx = static_cast<QAbstractProxyModel*>(mymodel)->mapToSource(idx);
+ mymodel = static_cast<QAbstractProxyModel*>(mymodel)->sourceModel();
+ }
+ QCMakeCacheModel* cache_model = qobject_cast<QCMakeCacheModel*>(mymodel);
+ if (cache_model && idx.isValid()) {
+ QCMakeProperty prop;
+ idx = idx.sibling(idx.row(), 0);
+ cache_model->getPropertyData(idx, prop);
+
+ // clean out an old one
+ QSet<QCMakeProperty>::iterator iter = mChanges.find(prop);
+ if (iter != mChanges.end()) {
+ mChanges.erase(iter);
+ }
+ // now add the new item
+ mChanges.insert(prop);
+ }
+}
diff --git a/Source/QtDialog/QCMakeCacheView.h b/Source/QtDialog/QCMakeCacheView.h
new file mode 100644
index 0000000..6ad56fb
--- /dev/null
+++ b/Source/QtDialog/QCMakeCacheView.h
@@ -0,0 +1,180 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef QCMakeCacheView_h
+#define QCMakeCacheView_h
+
+#include "QCMake.h"
+
+#include <QItemDelegate>
+#include <QSet>
+#include <QStandardItemModel>
+#include <QTreeView>
+
+class QSortFilterProxyModel;
+class QCMakeCacheModel;
+class QCMakeAdvancedFilter;
+
+/// Qt view class for cache properties
+class QCMakeCacheView : public QTreeView
+{
+ Q_OBJECT
+public:
+ QCMakeCacheView(QWidget* p);
+
+ // retrieve the QCMakeCacheModel storing all the pointers
+ // this isn't necessarily the model one would get from model()
+ QCMakeCacheModel* cacheModel() const;
+
+ // get whether to show advanced entries
+ bool showAdvanced() const;
+
+ QSize sizeHint() const { return QSize(200, 200); }
+
+public slots:
+ // set whether to show advanced entries
+ void setShowAdvanced(bool);
+ // set the search filter string. any property key or value not matching will
+ // be filtered out
+ void setSearchFilter(const QString&);
+
+protected:
+ QModelIndex moveCursor(CursorAction, Qt::KeyboardModifiers);
+ bool event(QEvent* e);
+ QCMakeCacheModel* CacheModel;
+ QCMakeAdvancedFilter* AdvancedFilter;
+ QSortFilterProxyModel* SearchFilter;
+};
+
+/// Qt model class for cache properties
+class QCMakeCacheModel : public QStandardItemModel
+{
+ Q_OBJECT
+public:
+ QCMakeCacheModel(QObject* parent);
+ ~QCMakeCacheModel();
+
+ // roles used to retrieve extra data such has help strings, types of
+ // properties, and the advanced flag
+ enum
+ {
+ HelpRole = Qt::ToolTipRole,
+ TypeRole = Qt::UserRole,
+ AdvancedRole,
+ StringsRole,
+ GroupRole
+ };
+
+ enum ViewType
+ {
+ FlatView,
+ GroupView
+ };
+
+public slots:
+ // set a list of properties. This list will be sorted and grouped according
+ // to prefix. Any property that existed already and which is found in this
+ // list of properties to set will become an old property. All others will
+ // become new properties and be marked red.
+ void setProperties(const QCMakePropertyList& props);
+
+ // set whether to show new properties in red
+ void setShowNewProperties(bool);
+
+ // clear everything from the model
+ void clear();
+
+ // set flag whether the model can currently be edited.
+ void setEditEnabled(bool);
+
+ // insert a new property at a row specifying all the information about the
+ // property
+ bool insertProperty(QCMakeProperty::PropertyType t, const QString& name,
+ const QString& description, const QVariant& value,
+ bool advanced);
+
+ // set the view type
+ void setViewType(ViewType t);
+ ViewType viewType() const;
+
+public:
+ // get the properties
+ QCMakePropertyList properties() const;
+
+ // editing enabled
+ bool editEnabled() const;
+
+ // returns how many new properties there are
+ int newPropertyCount() const;
+
+ // return flags (overloaded to modify flag based on EditEnabled flag)
+ Qt::ItemFlags flags(const QModelIndex& index) const;
+ QModelIndex buddy(const QModelIndex& idx) const;
+
+ // get the data in the model for this property
+ void getPropertyData(const QModelIndex& idx1, QCMakeProperty& prop) const;
+
+protected:
+ bool EditEnabled;
+ int NewPropertyCount;
+ bool ShowNewProperties;
+ ViewType View;
+
+ // set the data in the model for this property
+ void setPropertyData(const QModelIndex& idx1, const QCMakeProperty& p,
+ bool isNew);
+
+ // breaks up he property list into groups
+ // where each group has the same prefix up to the first underscore
+ static void breakProperties(const QSet<QCMakeProperty>& props,
+ QMap<QString, QCMakePropertyList>& result);
+
+ // gets the prefix of a string up to the first _
+ static QString prefix(const QString& s);
+};
+
+/// Qt delegate class for interaction (or other customization)
+/// with cache properties
+class QCMakeCacheModelDelegate : public QItemDelegate
+{
+ Q_OBJECT
+public:
+ QCMakeCacheModelDelegate(QObject* p);
+ /// create our own editors for cache properties
+ QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option,
+ const QModelIndex& index) const;
+ bool editorEvent(QEvent* event, QAbstractItemModel* model,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index);
+ bool eventFilter(QObject* object, QEvent* event);
+ void setModelData(QWidget* editor, QAbstractItemModel* model,
+ const QModelIndex& index) const;
+ QSize sizeHint(const QStyleOptionViewItem& option,
+ const QModelIndex& index) const;
+
+ QSet<QCMakeProperty> changes() const;
+ void clearChanges();
+
+protected slots:
+ void setFileDialogFlag(bool);
+
+protected:
+ bool FileDialogFlag;
+ // record a change to an item in the model.
+ // this simply saves the item in the set of changes
+ void recordChange(QAbstractItemModel* model, const QModelIndex& index);
+
+ // properties changed by user via this delegate
+ QSet<QCMakeProperty> mChanges;
+};
+
+#endif
diff --git a/Source/QtDialog/QCMakeWidgets.cxx b/Source/QtDialog/QCMakeWidgets.cxx
new file mode 100644
index 0000000..4b3eb34
--- /dev/null
+++ b/Source/QtDialog/QCMakeWidgets.cxx
@@ -0,0 +1,128 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "QCMakeWidgets.h"
+
+#include <QDirModel>
+#include <QFileDialog>
+#include <QFileInfo>
+#include <QResizeEvent>
+#include <QToolButton>
+
+QCMakeFileEditor::QCMakeFileEditor(QWidget* p, const QString& var)
+ : QLineEdit(p)
+ , Variable(var)
+{
+ this->ToolButton = new QToolButton(this);
+ this->ToolButton->setText("...");
+ this->ToolButton->setCursor(QCursor(Qt::ArrowCursor));
+ QObject::connect(this->ToolButton, SIGNAL(clicked(bool)), this,
+ SLOT(chooseFile()));
+}
+
+QCMakeFilePathEditor::QCMakeFilePathEditor(QWidget* p, const QString& var)
+ : QCMakeFileEditor(p, var)
+{
+ this->setCompleter(new QCMakeFileCompleter(this, false));
+}
+
+QCMakePathEditor::QCMakePathEditor(QWidget* p, const QString& var)
+ : QCMakeFileEditor(p, var)
+{
+ this->setCompleter(new QCMakeFileCompleter(this, true));
+}
+
+void QCMakeFileEditor::resizeEvent(QResizeEvent* e)
+{
+ // make the tool button fit on the right side
+ int h = e->size().height();
+ // move the line edit to make room for the tool button
+ this->setContentsMargins(0, 0, h, 0);
+ // put the tool button in its place
+ this->ToolButton->resize(h, h);
+ this->ToolButton->move(this->width() - h, 0);
+}
+
+void QCMakeFilePathEditor::chooseFile()
+{
+ // choose a file and set it
+ QString path;
+ QFileInfo info(this->text());
+ QString title;
+ if (this->Variable.isEmpty()) {
+ title = tr("Select File");
+ } else {
+ title = tr("Select File for %1");
+ title = title.arg(this->Variable);
+ }
+ this->fileDialogExists(true);
+ path =
+ QFileDialog::getOpenFileName(this, title, info.absolutePath(), QString(),
+ NULL, QFileDialog::DontResolveSymlinks);
+ this->fileDialogExists(false);
+
+ if (!path.isEmpty()) {
+ this->setText(QDir::fromNativeSeparators(path));
+ }
+}
+
+void QCMakePathEditor::chooseFile()
+{
+ // choose a file and set it
+ QString path;
+ QString title;
+ if (this->Variable.isEmpty()) {
+ title = tr("Select Path");
+ } else {
+ title = tr("Select Path for %1");
+ title = title.arg(this->Variable);
+ }
+ this->fileDialogExists(true);
+ path = QFileDialog::getExistingDirectory(this, title, this->text(),
+ QFileDialog::ShowDirsOnly |
+ QFileDialog::DontResolveSymlinks);
+ this->fileDialogExists(false);
+ if (!path.isEmpty()) {
+ this->setText(QDir::fromNativeSeparators(path));
+ }
+}
+
+// use same QDirModel for all completers
+static QDirModel* fileDirModel()
+{
+ static QDirModel* m = NULL;
+ if (!m) {
+ m = new QDirModel();
+ }
+ return m;
+}
+static QDirModel* pathDirModel()
+{
+ static QDirModel* m = NULL;
+ if (!m) {
+ m = new QDirModel();
+ m->setFilter(QDir::AllDirs | QDir::Drives | QDir::NoDotAndDotDot);
+ }
+ return m;
+}
+
+QCMakeFileCompleter::QCMakeFileCompleter(QObject* o, bool dirs)
+ : QCompleter(o)
+{
+ QDirModel* m = dirs ? pathDirModel() : fileDirModel();
+ this->setModel(m);
+}
+
+QString QCMakeFileCompleter::pathFromIndex(const QModelIndex& idx) const
+{
+ return QDir::fromNativeSeparators(QCompleter::pathFromIndex(idx));
+}
diff --git a/Source/QtDialog/QCMakeWidgets.h b/Source/QtDialog/QCMakeWidgets.h
new file mode 100644
index 0000000..f1e87ce
--- /dev/null
+++ b/Source/QtDialog/QCMakeWidgets.h
@@ -0,0 +1,89 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef QCMakeWidgets_h
+#define QCMakeWidgets_h
+
+#include <QComboBox>
+#include <QCompleter>
+#include <QLineEdit>
+
+class QToolButton;
+
+// common widgets for Qt based CMake
+
+/// Editor widget for editing paths or file paths
+class QCMakeFileEditor : public QLineEdit
+{
+ Q_OBJECT
+public:
+ QCMakeFileEditor(QWidget* p, const QString& var);
+protected slots:
+ virtual void chooseFile() = 0;
+signals:
+ void fileDialogExists(bool);
+
+protected:
+ void resizeEvent(QResizeEvent* e);
+ QToolButton* ToolButton;
+ QString Variable;
+};
+
+/// editor widget for editing files
+class QCMakePathEditor : public QCMakeFileEditor
+{
+ Q_OBJECT
+public:
+ QCMakePathEditor(QWidget* p = NULL, const QString& var = QString());
+ void chooseFile();
+};
+
+/// editor widget for editing paths
+class QCMakeFilePathEditor : public QCMakeFileEditor
+{
+ Q_OBJECT
+public:
+ QCMakeFilePathEditor(QWidget* p = NULL, const QString& var = QString());
+ void chooseFile();
+};
+
+/// completer class that returns native cmake paths
+class QCMakeFileCompleter : public QCompleter
+{
+ Q_OBJECT
+public:
+ QCMakeFileCompleter(QObject* o, bool dirs);
+ virtual QString pathFromIndex(const QModelIndex& idx) const;
+};
+
+// editor for strings
+class QCMakeComboBox : public QComboBox
+{
+ Q_OBJECT
+ Q_PROPERTY(QString value READ currentText WRITE setValue USER true);
+
+public:
+ QCMakeComboBox(QWidget* p, QStringList strings)
+ : QComboBox(p)
+ {
+ this->addItems(strings);
+ }
+ void setValue(const QString& v)
+ {
+ int i = this->findText(v);
+ if (i != -1) {
+ this->setCurrentIndex(i);
+ }
+ }
+};
+
+#endif
diff --git a/Source/QtDialog/QtDialogCPack.cmake.in b/Source/QtDialog/QtDialogCPack.cmake.in
new file mode 100644
index 0000000..7ae8605
--- /dev/null
+++ b/Source/QtDialog/QtDialogCPack.cmake.in
@@ -0,0 +1,15 @@
+set(IS_APPLE @APPLE@)
+set(CMAKE_PACKAGE_QTGUI @CMAKE_PACKAGE_QTGUI@)
+
+if(CMAKE_PACKAGE_QTGUI)
+ set(CPACK_PACKAGE_EXECUTABLES "cmake-gui" "CMake (cmake-gui)" ${CPACK_PACKAGE_EXECUTABLES})
+ set(CPACK_CREATE_DESKTOP_LINKS "cmake-gui" ${CPACK_CREATE_DESKTOP_LINKS})
+ if(IS_APPLE)
+ # for apple install we set the install prefix to
+ # / and then install
+ # cmake into the bundle for cmake-gui and must use DESTDIR
+ set(CPACK_SET_DESTDIR TRUE)
+ endif()
+endif()
+
+
diff --git a/Source/QtDialog/RegexExplorer.cxx b/Source/QtDialog/RegexExplorer.cxx
new file mode 100644
index 0000000..d23a08c
--- /dev/null
+++ b/Source/QtDialog/RegexExplorer.cxx
@@ -0,0 +1,146 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Kitware, Inc., Gregor Jasny
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "RegexExplorer.h"
+
+RegexExplorer::RegexExplorer(QWidget* p)
+ : QDialog(p)
+ , m_matched(false)
+{
+ this->setupUi(this);
+
+ for (int i = 1; i < cmsys::RegularExpression::NSUBEXP; ++i) {
+ matchNumber->addItem(QString("Match %1").arg(QString::number(i)),
+ QVariant(i));
+ }
+ matchNumber->setCurrentIndex(0);
+}
+
+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);
+ widget->setPalette(palette);
+}
+
+void RegexExplorer::on_regularExpression_textChanged(const QString& text)
+{
+#ifdef QT_NO_STL
+ m_regex = text.toAscii().constData();
+#else
+ m_regex = text.toStdString();
+#endif
+
+ bool validExpression =
+ stripEscapes(m_regex) && m_regexParser.compile(m_regex);
+ if (!validExpression) {
+ m_regexParser.set_invalid();
+ }
+
+ setStatusColor(labelRegexValid, validExpression);
+
+ on_inputText_textChanged();
+}
+
+void RegexExplorer::on_inputText_textChanged()
+{
+ if (m_regexParser.is_valid()) {
+ QString plainText = inputText->toPlainText();
+#ifdef QT_NO_STL
+ m_text = plainText.toAscii().constData();
+#else
+ m_text = plainText.toStdString();
+#endif
+ m_matched = m_regexParser.find(m_text);
+ } else {
+ m_matched = false;
+ }
+
+ setStatusColor(labelRegexMatch, m_matched);
+
+ if (!m_matched) {
+ clearMatch();
+ return;
+ }
+
+#ifdef QT_NO_STL
+ QString matchText = m_regexParser.match(0).c_str();
+#else
+ QString matchText = QString::fromStdString(m_regexParser.match(0));
+#endif
+ match0->setPlainText(matchText);
+
+ on_matchNumber_currentIndexChanged(matchNumber->currentIndex());
+}
+
+void RegexExplorer::on_matchNumber_currentIndexChanged(int index)
+{
+ if (!m_matched) {
+ return;
+ }
+
+ QVariant itemData = matchNumber->itemData(index);
+ int idx = itemData.toInt();
+
+ if (idx < 1 || idx >= cmsys::RegularExpression::NSUBEXP) {
+ return;
+ }
+
+#ifdef QT_NO_STL
+ QString match = m_regexParser.match(idx).c_str();
+#else
+ QString match = QString::fromStdString(m_regexParser.match(idx));
+#endif
+ matchN->setPlainText(match);
+}
+
+void RegexExplorer::clearMatch()
+{
+ match0->clear();
+ matchN->clear();
+}
+
+bool RegexExplorer::stripEscapes(std::string& source)
+{
+ const char* in = source.c_str();
+
+ std::string result;
+ result.reserve(source.size());
+
+ for (char inc = *in; inc != '\0'; inc = *++in) {
+ if (inc == '\\') {
+ char nextc = in[1];
+ if (nextc == 't') {
+ result.append(1, '\t');
+ in++;
+ } else if (nextc == 'n') {
+ result.append(1, '\n');
+ in++;
+ } else if (nextc == 't') {
+ result.append(1, '\t');
+ in++;
+ } else if (isalnum(nextc) || nextc == '\0') {
+ return false;
+ } else {
+ result.append(1, nextc);
+ in++;
+ }
+ } else {
+ result.append(1, inc);
+ }
+ }
+
+ source = result;
+ return true;
+}
diff --git a/Source/QtDialog/RegexExplorer.h b/Source/QtDialog/RegexExplorer.h
new file mode 100644
index 0000000..3ac8a24
--- /dev/null
+++ b/Source/QtDialog/RegexExplorer.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Kitware, Inc., Gregor Jasny
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef RegexExplorer_h
+#define RegexExplorer_h
+
+#include <QDialog>
+#include <cmsys/RegularExpression.hxx>
+#include <string>
+
+#include "ui_RegexExplorer.h"
+
+class QString;
+class QWidget;
+
+class RegexExplorer : public QDialog, public Ui::RegexExplorer
+{
+ Q_OBJECT
+public:
+ RegexExplorer(QWidget* p);
+
+private slots:
+ void on_regularExpression_textChanged(const QString& text);
+ void on_inputText_textChanged();
+ void on_matchNumber_currentIndexChanged(int index);
+
+private:
+ static void setStatusColor(QWidget* widget, bool successful);
+ static bool stripEscapes(std::string& regex);
+
+ void clearMatch();
+
+ cmsys::RegularExpression m_regexParser;
+ std::string m_text;
+ std::string m_regex;
+ bool m_matched;
+};
+
+#endif
diff --git a/Source/QtDialog/RegexExplorer.ui b/Source/QtDialog/RegexExplorer.ui
new file mode 100644
index 0000000..2c2d761
--- /dev/null
+++ b/Source/QtDialog/RegexExplorer.ui
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>RegexExplorer</class>
+ <widget class="QDialog" name="RegexExplorer">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>639</width>
+ <height>555</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Regular Expression Explorer</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Input Text</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPlainTextEdit" name="inputText"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Regular Expression</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelRegexValid">
+ <property name="text">
+ <string>Valid</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelRegexMatch">
+ <property name="text">
+ <string>Match</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="regularExpression"/>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Complete Match</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPlainTextEdit" name="match0">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QComboBox" name="matchNumber">
+ <property name="editable">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPlainTextEdit" name="matchN">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Source/QtDialog/WarningMessagesDialog.cxx b/Source/QtDialog/WarningMessagesDialog.cxx
new file mode 100644
index 0000000..3be6798
--- /dev/null
+++ b/Source/QtDialog/WarningMessagesDialog.cxx
@@ -0,0 +1,96 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Kitware, Inc., Gregor Jasny
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "WarningMessagesDialog.h"
+
+WarningMessagesDialog::WarningMessagesDialog(QWidget* prnt, QCMake* instance)
+ : QDialog(prnt)
+ , cmakeInstance(instance)
+{
+ this->setupUi(this);
+ this->setInitialValues();
+ this->setupSignals();
+}
+
+void WarningMessagesDialog::setInitialValues()
+{
+ this->suppressDeveloperWarnings->setChecked(
+ this->cmakeInstance->getSuppressDevWarnings());
+ this->suppressDeprecatedWarnings->setChecked(
+ this->cmakeInstance->getSuppressDeprecatedWarnings());
+
+ this->developerWarningsAsErrors->setChecked(
+ this->cmakeInstance->getDevWarningsAsErrors());
+ this->deprecatedWarningsAsErrors->setChecked(
+ this->cmakeInstance->getDeprecatedWarningsAsErrors());
+}
+
+void WarningMessagesDialog::setupSignals()
+{
+ QObject::connect(this->buttonBox, SIGNAL(accepted()), this,
+ SLOT(doAccept()));
+
+ QObject::connect(this->suppressDeveloperWarnings, SIGNAL(stateChanged(int)),
+ this, SLOT(doSuppressDeveloperWarningsChanged(int)));
+ QObject::connect(this->suppressDeprecatedWarnings, SIGNAL(stateChanged(int)),
+ this, SLOT(doSuppressDeprecatedWarningsChanged(int)));
+
+ QObject::connect(this->developerWarningsAsErrors, SIGNAL(stateChanged(int)),
+ this, SLOT(doDeveloperWarningsAsErrorsChanged(int)));
+ QObject::connect(this->deprecatedWarningsAsErrors, SIGNAL(stateChanged(int)),
+ this, SLOT(doDeprecatedWarningsAsErrorsChanged(int)));
+}
+
+void WarningMessagesDialog::doAccept()
+{
+ this->cmakeInstance->setSuppressDevWarnings(
+ this->suppressDeveloperWarnings->isChecked());
+ this->cmakeInstance->setSuppressDeprecatedWarnings(
+ this->suppressDeprecatedWarnings->isChecked());
+
+ this->cmakeInstance->setDevWarningsAsErrors(
+ this->developerWarningsAsErrors->isChecked());
+ this->cmakeInstance->setDeprecatedWarningsAsErrors(
+ this->deprecatedWarningsAsErrors->isChecked());
+}
+
+void WarningMessagesDialog::doSuppressDeveloperWarningsChanged(int state)
+{
+ // no warnings implies no errors either
+ if (state) {
+ this->developerWarningsAsErrors->setChecked(false);
+ }
+}
+
+void WarningMessagesDialog::doSuppressDeprecatedWarningsChanged(int state)
+{
+ // no warnings implies no errors either
+ if (state) {
+ this->deprecatedWarningsAsErrors->setChecked(false);
+ }
+}
+
+void WarningMessagesDialog::doDeveloperWarningsAsErrorsChanged(int state)
+{
+ // warnings as errors implies warnings are not suppressed
+ if (state) {
+ this->suppressDeveloperWarnings->setChecked(false);
+ }
+}
+
+void WarningMessagesDialog::doDeprecatedWarningsAsErrorsChanged(int state)
+{
+ // warnings as errors implies warnings are not suppressed
+ if (state) {
+ this->suppressDeprecatedWarnings->setChecked(false);
+ }
+}
diff --git a/Source/QtDialog/WarningMessagesDialog.h b/Source/QtDialog/WarningMessagesDialog.h
new file mode 100644
index 0000000..4bb739c
--- /dev/null
+++ b/Source/QtDialog/WarningMessagesDialog.h
@@ -0,0 +1,75 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Kitware, Inc., Gregor Jasny
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef WarningMessagesDialog_h
+#define WarningMessagesDialog_h
+
+#include <QDialog>
+#include <QWidget>
+
+#include "QCMake.h"
+#include "ui_WarningMessagesDialog.h"
+
+/**
+ * Dialog window for setting the warning message related options.
+ */
+class WarningMessagesDialog : public QDialog, public Ui_MessagesDialog
+{
+ Q_OBJECT
+
+public:
+ WarningMessagesDialog(QWidget* prnt, QCMake* instance);
+
+private slots:
+ /**
+ * Handler for the accept event of the ok/cancel button box.
+ */
+ void doAccept();
+
+ /**
+ * Handler for checked state changed event of the suppress developer warnings
+ * checkbox.
+ */
+ void doSuppressDeveloperWarningsChanged(int state);
+ /**
+ * Handler for checked state changed event of the suppress deprecated
+ * warnings checkbox.
+ */
+ void doSuppressDeprecatedWarningsChanged(int state);
+
+ /**
+ * Handler for checked state changed event of the developer warnings as
+ * errors checkbox.
+ */
+ void doDeveloperWarningsAsErrorsChanged(int state);
+ /**
+ * Handler for checked state changed event of the deprecated warnings as
+ * errors checkbox.
+ */
+ void doDeprecatedWarningsAsErrorsChanged(int state);
+
+private:
+ QCMake* cmakeInstance;
+
+ /**
+ * Set the initial values of the widgets on this dialog window, using the
+ * current state of the cache.
+ */
+ void setInitialValues();
+
+ /**
+ * Setup the signals for the widgets on this dialog window.
+ */
+ void setupSignals();
+};
+
+#endif /* MessageDialog_h */
diff --git a/Source/QtDialog/WarningMessagesDialog.ui b/Source/QtDialog/WarningMessagesDialog.ui
new file mode 100644
index 0000000..3b35cbc
--- /dev/null
+++ b/Source/QtDialog/WarningMessagesDialog.ui
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MessagesDialog</class>
+ <widget class="QDialog" name="MessagesDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>300</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Warning Messages</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Suppress Warnings</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="suppressDeveloperWarnings">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Suppress developer (author) warnings.</string>
+ </property>
+ <property name="text">
+ <string>Developer Warnings</string>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="suppressDeprecatedWarnings">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Suppress deprecated warnings.</string>
+ </property>
+ <property name="text">
+ <string>Deprecated Warnings</string>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Warnings as Errors</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QCheckBox" name="developerWarningsAsErrors">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Treat developer (author) warnings as errors.</string>
+ </property>
+ <property name="text">
+ <string>Developer Warnings as Errors</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="deprecatedWarningsAsErrors">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Treat deprecated warnings as errors.</string>
+ </property>
+ <property name="text">
+ <string>Deprecated Warnings as Errors</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>MessagesDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>MessagesDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Source/QtDialog/cmakecache.xml b/Source/QtDialog/cmakecache.xml
new file mode 100644
index 0000000..a13b5b1
--- /dev/null
+++ b/Source/QtDialog/cmakecache.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
+ <mime-type type="application/x-cmakecache">
+ <comment>CMake cache file</comment>
+ <glob pattern="CMakeCache.txt"/>
+ <sub-class-of type="text/plain"/>
+ </mime-type>
+</mime-info>
diff --git a/Source/QtIFW/CMake.Dialogs.QtGUI.qs b/Source/QtIFW/CMake.Dialogs.QtGUI.qs
new file mode 100644
index 0000000..219a0a9
--- /dev/null
+++ b/Source/QtIFW/CMake.Dialogs.QtGUI.qs
@@ -0,0 +1,21 @@
+// Component: CMake.Dialogs.QtGUI
+
+function Component()
+{
+ // Default constructor
+}
+
+Component.prototype.createOperations = function()
+{
+ // Create shortcut
+ if (installer.value("os") === "win") {
+
+ component.addOperation("CreateShortcut",
+ installer.value("TargetDir") + "/bin/cmake-gui.exe",
+ installer.value("StartMenuDir") + "/CMake (cmake-gui).lnk");
+
+ }
+
+ // Call default implementation
+ component.createOperations();
+}
diff --git a/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in b/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in
new file mode 100644
index 0000000..5c929e8
--- /dev/null
+++ b/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in
@@ -0,0 +1,21 @@
+// Component: CMake.Documentation.SphinxHTML
+
+function Component()
+{
+ // Default constructor
+}
+
+Component.prototype.createOperations = function()
+{
+ // Create shortcut
+ if (installer.value("os") === "win") {
+
+ component.addOperation("CreateShortcut",
+ installer.value("TargetDir") + "/@CMAKE_DOC_DIR@/html/index.html",
+ installer.value("StartMenuDir") + "/CMake Documentation.lnk");
+
+ }
+
+ // Call default implementation
+ component.createOperations();
+}
diff --git a/Source/QtIFW/CMake.qs.in b/Source/QtIFW/CMake.qs.in
new file mode 100644
index 0000000..828cc7c
--- /dev/null
+++ b/Source/QtIFW/CMake.qs.in
@@ -0,0 +1,22 @@
+function Component()
+{
+ // Default constructor
+}
+
+Component.prototype.createOperations = function()
+{
+ // Create shortcut
+ if (installer.value("os") === "win") {
+
+ component.addOperation("CreateShortcut",
+ installer.value("TargetDir") + "/@CMAKE_DOC_DIR@/cmake.org.html",
+ installer.value("StartMenuDir") + "/CMake Web Site.lnk");
+
+ component.addOperation("CreateShortcut",
+ installer.value("TargetDir") + "/cmake-maintenance.exe",
+ installer.value("StartMenuDir") + "/CMake Maintenance Tool.lnk");
+ }
+
+ // Call default implementation
+ component.createOperations();
+}
diff --git a/Source/QtIFW/cmake.org.html b/Source/QtIFW/cmake.org.html
new file mode 100644
index 0000000..cf5649d
--- /dev/null
+++ b/Source/QtIFW/cmake.org.html
@@ -0,0 +1,7 @@
+<html>
+<head>
+<meta http-equiv="Refresh" content="0; url=http://cmake.org/" />
+</head>
+<body>
+</body>
+</html>
diff --git a/Source/QtIFW/controlscript.qs b/Source/QtIFW/controlscript.qs
new file mode 100644
index 0000000..d1a9b10
--- /dev/null
+++ b/Source/QtIFW/controlscript.qs
@@ -0,0 +1,6 @@
+// controlscript.qs - CMake installation control script
+
+function Controller()
+{
+ // do nothing now
+}
diff --git a/Source/QtIFW/installscript.qs.in b/Source/QtIFW/installscript.qs.in
new file mode 100644
index 0000000..3411e34
--- /dev/null
+++ b/Source/QtIFW/installscript.qs.in
@@ -0,0 +1,24 @@
+function Component()
+{
+ // default constructor
+}
+
+Component.prototype.createOperations = function()
+{
+ // Create shortcut
+ if (installer.value("os") === "win") {
+
+@_CPACK_IFW_SHORTCUT_OPTIONAL@
+
+ component.addOperation("CreateShortcut",
+ installer.value("TargetDir") + "/@CMAKE_DOC_DIR@/cmake.org.html",
+ installer.value("StartMenuDir") + "/CMake Web Site.lnk");
+
+ component.addOperation("CreateShortcut",
+ installer.value("TargetDir") + "/cmake-maintenance.exe",
+ installer.value("StartMenuDir") + "/CMake Maintenance Tool.lnk");
+ }
+
+ // Call default implementation
+ component.createOperations();
+}
diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx
new file mode 100644
index 0000000..b179f83
--- /dev/null
+++ b/Source/bindexplib.cxx
@@ -0,0 +1,460 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*-------------------------------------------------------------------------
+ Portions of this source have been derived from the 'bindexplib' tool
+ provided by the CERN ROOT Data Analysis Framework project (root.cern.ch).
+ Permission has been granted by Pere Mato <pere.mato@cern.ch> to distribute
+ this derived work under the CMake license.
+-------------------------------------------------------------------------*/
+
+/*
+*----------------------------------------------------------------------
+* Program: dumpexts.exe
+* Author: Gordon Chaffee
+*
+* History: The real functionality of this file was written by
+* Matt Pietrek in 1993 in his pedump utility. I've
+* modified it to dump the externals in a bunch of object
+* files to create a .def file.
+*
+* Notes: Visual C++ puts an underscore before each exported symbol.
+* This file removes them. I don't know if this is a problem
+* this other compilers. If _MSC_VER is defined,
+* the underscore is removed. If not, it isn't. To get a
+* full dump of an object file, use the -f option. This can
+* help determine the something that may be different with a
+* compiler other than Visual C++.
+* ======================================
+* Corrections (Axel 2006-04-04):
+* Conversion to C++. Mostly.
+*
+ * Extension (Axel 2006-03-15)
+ * As soon as an object file contains an /EXPORT directive (which
+ * is generated by the compiler when a symbol is declared as
+ * declspec(dllexport)) no to-be-exported symbols are printed,
+ * as the linker will see these directives, and if those directives
+ * are present we only export selectively (i.e. we trust the
+ * programmer).
+ *
+ * ======================================
+* ======================================
+* Corrections (Valery Fine 23/02/98):
+*
+* The "(vector) deleting destructor" MUST not be exported
+* To recognize it the following test are introduced:
+* "@@UAEPAXI@Z" scalar deleting dtor
+* "@@QAEPAXI@Z" vector deleting dtor
+* "AEPAXI@Z" vector deleting dtor with thunk adjustor
+* ======================================
+* Corrections (Valery Fine 12/02/97):
+*
+* It created a wrong EXPORTS for the global pointers and constants.
+* The Section Header has been involved to discover the missing information
+* Now the pointers are correctly supplied supplied with "DATA" descriptor
+* the constants with no extra descriptor.
+*
+* Corrections (Valery Fine 16/09/96):
+*
+* It didn't work for C++ code with global variables and class definitons
+* The DumpExternalObject function has been introduced to generate .DEF file
+*
+* Author: Valery Fine 16/09/96 (E-mail: fine@vxcern.cern.ch)
+*----------------------------------------------------------------------
+*/
+#include "bindexplib.h"
+#include <cmsys/Encoding.hxx>
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+#include <string>
+#include <windows.h>
+
+typedef struct cmANON_OBJECT_HEADER_BIGOBJ {
+ /* same as ANON_OBJECT_HEADER_V2 */
+ WORD Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN
+ WORD Sig2; // Must be 0xffff
+ WORD Version; // >= 2 (implies the Flags field is present)
+ WORD Machine; // Actual machine - IMAGE_FILE_MACHINE_xxx
+ DWORD TimeDateStamp;
+ CLSID ClassID; // {D1BAA1C7-BAEE-4ba9-AF20-FAF66AA4DCB8}
+ DWORD SizeOfData; // Size of data that follows the header
+ DWORD Flags; // 0x1 -> contains metadata
+ DWORD MetaDataSize; // Size of CLR metadata
+ DWORD MetaDataOffset; // Offset of CLR metadata
+
+ /* bigobj specifics */
+ DWORD NumberOfSections; // extended from WORD
+ DWORD PointerToSymbolTable;
+ DWORD NumberOfSymbols;
+} cmANON_OBJECT_HEADER_BIGOBJ;
+
+typedef struct _cmIMAGE_SYMBOL_EX {
+ union {
+ BYTE ShortName[8];
+ struct {
+ DWORD Short; // if 0, use LongName
+ DWORD Long; // offset into string table
+ } Name;
+ DWORD LongName[2]; // PBYTE [2]
+ } N;
+ DWORD Value;
+ LONG SectionNumber;
+ WORD Type;
+ BYTE StorageClass;
+ BYTE NumberOfAuxSymbols;
+} cmIMAGE_SYMBOL_EX;
+typedef cmIMAGE_SYMBOL_EX UNALIGNED *cmPIMAGE_SYMBOL_EX;
+
+PIMAGE_SECTION_HEADER GetSectionHeaderOffset(PIMAGE_FILE_HEADER
+ pImageFileHeader)
+{
+ return (PIMAGE_SECTION_HEADER)
+ ((DWORD_PTR)pImageFileHeader +
+ IMAGE_SIZEOF_FILE_HEADER +
+ pImageFileHeader->SizeOfOptionalHeader);
+}
+
+PIMAGE_SECTION_HEADER GetSectionHeaderOffset(cmANON_OBJECT_HEADER_BIGOBJ*
+ pImageFileHeader)
+{
+ return (PIMAGE_SECTION_HEADER)
+ ((DWORD_PTR)pImageFileHeader +
+ sizeof(cmANON_OBJECT_HEADER_BIGOBJ));
+}
+
+/*
++ * Utility func, strstr with size
++ */
+const char* StrNStr(const char* start, const char* find, size_t &size) {
+ size_t len;
+ const char* hint;
+
+ if (!start || !find || !size) {
+ size = 0;
+ return 0;
+ }
+ len = strlen(find);
+
+ while ((hint = (const char*) memchr(start, find[0], size-len+1))) {
+ size -= (hint - start);
+ if (!strncmp(hint, find, len))
+ return hint;
+ start = hint + 1;
+ }
+
+ size = 0;
+ return 0;
+}
+
+template <
+ // cmANON_OBJECT_HEADER_BIGOBJ or IMAGE_FILE_HEADER
+ class ObjectHeaderType,
+ // cmPIMAGE_SYMBOL_EX or PIMAGE_SYMBOL
+ class SymbolTableType>
+class DumpSymbols
+{
+public:
+ /*
+ *----------------------------------------------------------------------
+ * Constructor --
+ *
+ * Initialize variables from pointer to object header.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ DumpSymbols(ObjectHeaderType* ih,
+ std::set<std::string>& symbols,
+ std::set<std::string>& dataSymbols,
+ bool is64)
+ :Symbols(symbols), DataSymbols(dataSymbols)
+ {
+ this->ObjectImageHeader = ih;
+ this->SymbolTable = (SymbolTableType*)
+ ((DWORD_PTR)this->ObjectImageHeader
+ + this->ObjectImageHeader->PointerToSymbolTable);
+ this->SectionHeaders =
+ GetSectionHeaderOffset(this->ObjectImageHeader);
+ this->SymbolCount = this->ObjectImageHeader->NumberOfSymbols;
+ this->Is64Bit = is64;
+ }
+
+ /*
+ *----------------------------------------------------------------------
+ * HaveExportedObjects --
+ *
+ * Returns true if export directives (declspec(dllexport)) exist.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ bool HaveExportedObjects() {
+ WORD i = 0;
+ size_t size = 0;
+ const char * rawdata = 0;
+ PIMAGE_SECTION_HEADER pDirectivesSectionHeader = 0;
+ PIMAGE_SECTION_HEADER pSectionHeaders = this->SectionHeaders;
+ for(i = 0; (i < this->ObjectImageHeader->NumberOfSections &&
+ !pDirectivesSectionHeader); i++)
+ if (!strncmp((const char*)&pSectionHeaders[i].Name[0], ".drectve",8))
+ pDirectivesSectionHeader = &pSectionHeaders[i];
+ if (!pDirectivesSectionHeader) return 0;
+
+ rawdata=(const char*)
+ this->ObjectImageHeader+pDirectivesSectionHeader->PointerToRawData;
+ if (!pDirectivesSectionHeader->PointerToRawData || !rawdata) return 0;
+
+ size = pDirectivesSectionHeader->SizeOfRawData;
+ const char* posImportFlag = rawdata;
+ while ((posImportFlag = StrNStr(posImportFlag, " /EXPORT:", size))) {
+ const char* lookingForDict = posImportFlag + 9;
+ if (!strncmp(lookingForDict, "_G__cpp_",8) ||
+ !strncmp(lookingForDict, "_G__set_cpp_",12)) {
+ posImportFlag = lookingForDict;
+ continue;
+ }
+
+ const char* lookingForDATA = posImportFlag + 9;
+ while (*(++lookingForDATA) && *lookingForDATA != ' ');
+ lookingForDATA -= 5;
+ // ignore DATA exports
+ if (strncmp(lookingForDATA, ",DATA", 5)) break;
+ posImportFlag = lookingForDATA + 5;
+ }
+ if(posImportFlag) {
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ *----------------------------------------------------------------------
+ * DumpObjFile --
+ *
+ * Dump an object file's exported symbols.
+ *----------------------------------------------------------------------
+ */
+ void DumpObjFile() {
+ if(!HaveExportedObjects()) {
+ this->DumpExternalsObjects();
+ }
+ }
+
+ /*
+ *----------------------------------------------------------------------
+ * DumpExternalsObjects --
+ *
+ * Dumps a COFF symbol table from an OBJ.
+ *----------------------------------------------------------------------
+ */
+ void DumpExternalsObjects() {
+ unsigned i;
+ PSTR stringTable;
+ std::string symbol;
+ DWORD SectChar;
+ /*
+ * The string table apparently starts right after the symbol table
+ */
+ stringTable = (PSTR)&this->SymbolTable[this->SymbolCount];
+ SymbolTableType* pSymbolTable = this->SymbolTable;
+ for ( i=0; i < this->SymbolCount; i++ ) {
+ if (pSymbolTable->SectionNumber > 0 &&
+ ( pSymbolTable->Type == 0x20 || pSymbolTable->Type == 0x0)) {
+ if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) {
+ /*
+ * The name of the Function entry points
+ */
+ if (pSymbolTable->N.Name.Short != 0) {
+ symbol = "";
+ symbol.insert(0, (const char *)pSymbolTable->N.ShortName, 8);
+ } else {
+ symbol = stringTable + pSymbolTable->N.Name.Long;
+ }
+
+ // clear out any leading spaces
+ while (isspace(symbol[0])) symbol.erase(0,1);
+ // if it starts with _ and has an @ then it is a __cdecl
+ // so remove the @ stuff for the export
+ if(symbol[0] == '_') {
+ std::string::size_type posAt = symbol.find('@');
+ if (posAt != std::string::npos) {
+ symbol.erase(posAt);
+ }
+ }
+ // For 64 bit builds we don't need to remove _
+ if(!this->Is64Bit)
+ {
+ if (symbol[0] == '_')
+ {
+ symbol.erase(0,1);
+ }
+ }
+ /*
+ Check whether it is "Scalar deleting destructor" and
+ "Vector deleting destructor"
+ */
+ const char *scalarPrefix = "??_G";
+ const char *vectorPrefix = "??_E";
+ // original code had a check for
+ // symbol.find("real@") == std::string::npos)
+ // but if this disallows memmber functions with the name real
+ // if scalarPrefix and vectorPrefix are not found then print
+ // the symbol
+ if (symbol.compare(0, 4, scalarPrefix) &&
+ symbol.compare(0, 4, vectorPrefix) )
+ {
+ SectChar =
+ this->
+ SectionHeaders[pSymbolTable->SectionNumber-1].Characteristics;
+ if (!pSymbolTable->Type && (SectChar & IMAGE_SCN_MEM_WRITE)) {
+ // Read only (i.e. constants) must be excluded
+ this->DataSymbols.insert(symbol);
+ } else {
+ if ( pSymbolTable->Type ||
+ !(SectChar & IMAGE_SCN_MEM_READ)) {
+ this->Symbols.insert(symbol);
+ } else {
+ // printf(" strange symbol: %s \n",symbol.c_str());
+ }
+ }
+ }
+ }
+ }
+ else if (pSymbolTable->SectionNumber == IMAGE_SYM_UNDEFINED &&
+ !pSymbolTable->Type && 0) {
+ /*
+ * The IMPORT global variable entry points
+ */
+ if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) {
+ symbol = stringTable + pSymbolTable->N.Name.Long;
+ while (isspace(symbol[0])) symbol.erase(0,1);
+ if (symbol[0] == '_') symbol.erase(0,1);
+ this->DataSymbols.insert(symbol);
+ }
+ }
+
+ /*
+ * Take into account any aux symbols
+ */
+ i += pSymbolTable->NumberOfAuxSymbols;
+ pSymbolTable += pSymbolTable->NumberOfAuxSymbols;
+ pSymbolTable++;
+ }
+ }
+private:
+ std::set<std::string>& Symbols;
+ std::set<std::string>& DataSymbols;
+ DWORD_PTR SymbolCount;
+ PIMAGE_SECTION_HEADER SectionHeaders;
+ ObjectHeaderType* ObjectImageHeader;
+ SymbolTableType* SymbolTable;
+ bool Is64Bit;
+};
+
+bool
+DumpFile(const char* filename,
+ std::set<std::string>& symbols,
+ std::set<std::string>& dataSymbols)
+{
+ HANDLE hFile;
+ HANDLE hFileMapping;
+ LPVOID lpFileBase;
+ PIMAGE_DOS_HEADER dosHeader;
+
+ hFile = CreateFileW(cmsys::Encoding::ToWide(filename).c_str(),
+ GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "Couldn't open file '%s' with CreateFile()\n", filename);
+ return false;
+ }
+
+ hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (hFileMapping == 0) {
+ CloseHandle(hFile);
+ fprintf(stderr, "Couldn't open file mapping with CreateFileMapping()\n");
+ return false;
+ }
+
+ lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
+ if (lpFileBase == 0) {
+ CloseHandle(hFileMapping);
+ CloseHandle(hFile);
+ fprintf(stderr, "Couldn't map view of file with MapViewOfFile()\n");
+ return false;
+ }
+
+ dosHeader = (PIMAGE_DOS_HEADER)lpFileBase;
+ if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) {
+ fprintf(stderr, "File is an executable. I don't dump those.\n");
+ return false;
+ }
+ /* Does it look like a i386 COFF OBJ file??? */
+ else if (
+ ((dosHeader->e_magic == IMAGE_FILE_MACHINE_I386) ||
+ (dosHeader->e_magic == IMAGE_FILE_MACHINE_AMD64))
+ && (dosHeader->e_sp == 0)
+ ) {
+ /*
+ * The two tests above aren't what they look like. They're
+ * really checking for IMAGE_FILE_HEADER.Machine == i386 (0x14C)
+ * and IMAGE_FILE_HEADER.SizeOfOptionalHeader == 0;
+ */
+ DumpSymbols<IMAGE_FILE_HEADER, IMAGE_SYMBOL>
+ symbolDumper((PIMAGE_FILE_HEADER) lpFileBase, symbols, dataSymbols,
+ (dosHeader->e_magic == IMAGE_FILE_MACHINE_AMD64));
+ symbolDumper.DumpObjFile();
+ } else {
+ // check for /bigobj format
+ cmANON_OBJECT_HEADER_BIGOBJ* h =
+ (cmANON_OBJECT_HEADER_BIGOBJ*) lpFileBase;
+ if(h->Sig1 == 0x0 && h->Sig2 == 0xffff) {
+ DumpSymbols<cmANON_OBJECT_HEADER_BIGOBJ, cmIMAGE_SYMBOL_EX>
+ symbolDumper((cmANON_OBJECT_HEADER_BIGOBJ*) lpFileBase, symbols,
+ dataSymbols,
+ (h->Machine == IMAGE_FILE_MACHINE_AMD64));
+ symbolDumper.DumpObjFile();
+ } else {
+ printf("unrecognized file format in '%s'\n", filename);
+ return false;
+ }
+ }
+ UnmapViewOfFile(lpFileBase);
+ CloseHandle(hFileMapping);
+ CloseHandle(hFile);
+ return true;
+}
+
+bool bindexplib::AddObjectFile(const char* filename)
+{
+ if(!DumpFile(filename, this->Symbols, this->DataSymbols))
+ {
+ return false;
+ }
+ return true;
+}
+
+void bindexplib::WriteFile(FILE* file)
+{
+ fprintf(file,"EXPORTS \n");
+ for(std::set<std::string>::const_iterator i = this->DataSymbols.begin();
+ i!= this->DataSymbols.end(); ++i)
+ {
+ fprintf(file, "\t%s \t DATA\n", i->c_str());
+ }
+ for(std::set<std::string>::const_iterator i = this->Symbols.begin();
+ i!= this->Symbols.end(); ++i)
+ {
+ fprintf(file, "\t%s\n", i->c_str());
+ }
+}
diff --git a/Source/bindexplib.h b/Source/bindexplib.h
new file mode 100644
index 0000000..8661a4a
--- /dev/null
+++ b/Source/bindexplib.h
@@ -0,0 +1,29 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef bindexplib_h
+#define bindexplib_h
+
+#include "cmStandardIncludes.h"
+
+
+class bindexplib
+{
+public:
+ bindexplib() {}
+ bool AddObjectFile(const char* filename);
+ void WriteFile(FILE* file);
+private:
+ std::set<std::string> Symbols;
+ std::set<std::string> DataSymbols;
+};
+#endif
diff --git a/Source/cmAddCompileOptionsCommand.cxx b/Source/cmAddCompileOptionsCommand.cxx
new file mode 100644
index 0000000..2223cf4
--- /dev/null
+++ b/Source/cmAddCompileOptionsCommand.cxx
@@ -0,0 +1,26 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmAddCompileOptionsCommand.h"
+
+bool cmAddCompileOptionsCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ return true;
+ }
+
+ for (std::vector<std::string>::const_iterator i = args.begin();
+ i != args.end(); ++i) {
+ this->Makefile->AddCompileOption(i->c_str());
+ }
+ return true;
+}
diff --git a/Source/cmAddCompileOptionsCommand.h b/Source/cmAddCompileOptionsCommand.h
new file mode 100644
index 0000000..dba1acd
--- /dev/null
+++ b/Source/cmAddCompileOptionsCommand.h
@@ -0,0 +1,40 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmAddCompileOptionsCommand_h
+#define cmAddCompileOptionsCommand_h
+
+#include "cmCommand.h"
+
+class cmAddCompileOptionsCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmAddCompileOptionsCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "add_compile_options"; }
+
+ cmTypeMacro(cmAddCompileOptionsCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
new file mode 100644
index 0000000..400be77
--- /dev/null
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -0,0 +1,364 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmAddCustomCommandCommand.h"
+
+#include "cmTarget.h"
+
+#include "cmSourceFile.h"
+
+// cmAddCustomCommandCommand
+bool cmAddCustomCommandCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ /* Let's complain at the end of this function about the lack of a particular
+ arg. For the moment, let's say that COMMAND, and either TARGET or SOURCE
+ are required.
+ */
+ if (args.size() < 4) {
+ this->SetError("called with wrong number of arguments.");
+ return false;
+ }
+
+ std::string source, target, main_dependency, working;
+ std::string comment_buffer;
+ const char* comment = CM_NULLPTR;
+ std::vector<std::string> depends, outputs, output, byproducts;
+ bool verbatim = false;
+ bool append = false;
+ bool uses_terminal = false;
+ std::string implicit_depends_lang;
+ cmCustomCommand::ImplicitDependsList implicit_depends;
+
+ // Accumulate one command line at a time.
+ cmCustomCommandLine currentLine;
+
+ // Save all command lines.
+ cmCustomCommandLines commandLines;
+
+ cmTarget::CustomCommandType cctype = cmTarget::POST_BUILD;
+
+ enum tdoing
+ {
+ doing_source,
+ doing_command,
+ doing_target,
+ doing_depends,
+ doing_implicit_depends_lang,
+ doing_implicit_depends_file,
+ doing_main_dependency,
+ doing_output,
+ doing_outputs,
+ doing_byproducts,
+ doing_comment,
+ doing_working_directory,
+ doing_nothing
+ };
+
+ tdoing doing = doing_nothing;
+
+ for (unsigned int j = 0; j < args.size(); ++j) {
+ std::string const& copy = args[j];
+
+ if (copy == "SOURCE") {
+ doing = doing_source;
+ } else if (copy == "COMMAND") {
+ doing = doing_command;
+
+ // Save the current command before starting the next command.
+ if (!currentLine.empty()) {
+ commandLines.push_back(currentLine);
+ currentLine.clear();
+ }
+ } else if (copy == "PRE_BUILD") {
+ cctype = cmTarget::PRE_BUILD;
+ } else if (copy == "PRE_LINK") {
+ cctype = cmTarget::PRE_LINK;
+ } else if (copy == "POST_BUILD") {
+ cctype = cmTarget::POST_BUILD;
+ } else if (copy == "VERBATIM") {
+ verbatim = true;
+ } else if (copy == "APPEND") {
+ append = true;
+ } else if (copy == "USES_TERMINAL") {
+ uses_terminal = true;
+ } else if (copy == "TARGET") {
+ doing = doing_target;
+ } else if (copy == "ARGS") {
+ // Ignore this old keyword.
+ } else if (copy == "DEPENDS") {
+ doing = doing_depends;
+ } else if (copy == "OUTPUTS") {
+ doing = doing_outputs;
+ } else if (copy == "OUTPUT") {
+ doing = doing_output;
+ } else if (copy == "BYPRODUCTS") {
+ doing = doing_byproducts;
+ } else if (copy == "WORKING_DIRECTORY") {
+ doing = doing_working_directory;
+ } else if (copy == "MAIN_DEPENDENCY") {
+ doing = doing_main_dependency;
+ } else if (copy == "IMPLICIT_DEPENDS") {
+ doing = doing_implicit_depends_lang;
+ } else if (copy == "COMMENT") {
+ doing = doing_comment;
+ } else {
+ std::string filename;
+ switch (doing) {
+ case doing_output:
+ case doing_outputs:
+ case doing_byproducts:
+ if (!cmSystemTools::FileIsFullPath(copy.c_str())) {
+ // This is an output to be generated, so it should be
+ // under the build tree. CMake 2.4 placed this under the
+ // source tree. However the only case that this change
+ // will break is when someone writes
+ //
+ // add_custom_command(OUTPUT out.txt ...)
+ //
+ // and later references "${CMAKE_CURRENT_SOURCE_DIR}/out.txt".
+ // This is fairly obscure so we can wait for someone to
+ // complain.
+ filename = this->Makefile->GetCurrentBinaryDirectory();
+ filename += "/";
+ }
+ filename += copy;
+ cmSystemTools::ConvertToUnixSlashes(filename);
+ break;
+ case doing_source:
+ // We do not want to convert the argument to SOURCE because
+ // that option is only available for backward compatibility.
+ // Old-style use of this command may use the SOURCE==TARGET
+ // trick which we must preserve. If we convert the source
+ // to a full path then it will no longer equal the target.
+ default:
+ break;
+ }
+
+ if (cmSystemTools::FileIsFullPath(filename.c_str())) {
+ filename = cmSystemTools::CollapseFullPath(filename);
+ }
+ switch (doing) {
+ case doing_working_directory:
+ working = copy;
+ break;
+ case doing_source:
+ source = copy;
+ break;
+ case doing_output:
+ output.push_back(filename);
+ break;
+ case doing_main_dependency:
+ main_dependency = copy;
+ break;
+ case doing_implicit_depends_lang:
+ implicit_depends_lang = copy;
+ doing = doing_implicit_depends_file;
+ break;
+ case doing_implicit_depends_file: {
+ // An implicit dependency starting point is also an
+ // explicit dependency.
+ std::string dep = copy;
+ cmSystemTools::ConvertToUnixSlashes(dep);
+ depends.push_back(dep);
+
+ // Add the implicit dependency language and file.
+ cmCustomCommand::ImplicitDependsPair entry(implicit_depends_lang,
+ dep);
+ implicit_depends.push_back(entry);
+
+ // Switch back to looking for a language.
+ doing = doing_implicit_depends_lang;
+ } break;
+ case doing_command:
+ currentLine.push_back(copy);
+ break;
+ case doing_target:
+ target = copy;
+ break;
+ case doing_depends: {
+ std::string dep = copy;
+ cmSystemTools::ConvertToUnixSlashes(dep);
+ depends.push_back(dep);
+ } break;
+ case doing_outputs:
+ outputs.push_back(filename);
+ break;
+ case doing_byproducts:
+ byproducts.push_back(filename);
+ break;
+ case doing_comment:
+ comment_buffer = copy;
+ comment = comment_buffer.c_str();
+ break;
+ default:
+ this->SetError("Wrong syntax. Unknown type of argument.");
+ return false;
+ }
+ }
+ }
+
+ // Store the last command line finished.
+ if (!currentLine.empty()) {
+ commandLines.push_back(currentLine);
+ currentLine.clear();
+ }
+
+ // At this point we could complain about the lack of arguments. For
+ // the moment, let's say that COMMAND, TARGET are always required.
+ if (output.empty() && target.empty()) {
+ this->SetError("Wrong syntax. A TARGET or OUTPUT must be specified.");
+ return false;
+ }
+
+ if (source.empty() && !target.empty() && !output.empty()) {
+ this->SetError(
+ "Wrong syntax. A TARGET and OUTPUT can not both be specified.");
+ return false;
+ }
+ if (append && output.empty()) {
+ this->SetError("given APPEND option with no OUTPUT.");
+ return false;
+ }
+
+ // Make sure the output names and locations are safe.
+ if (!this->CheckOutputs(output) || !this->CheckOutputs(outputs) ||
+ !this->CheckOutputs(byproducts)) {
+ return false;
+ }
+
+ // Check for an append request.
+ if (append) {
+ // Lookup an existing command.
+ if (cmSourceFile* sf =
+ this->Makefile->GetSourceFileWithOutput(output[0])) {
+ if (cmCustomCommand* cc = sf->GetCustomCommand()) {
+ cc->AppendCommands(commandLines);
+ cc->AppendDepends(depends);
+ cc->AppendImplicitDepends(implicit_depends);
+ return true;
+ }
+ }
+
+ // No command for this output exists.
+ std::ostringstream e;
+ e << "given APPEND option with output \"" << output[0]
+ << "\" which is not already a custom command output.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Convert working directory to a full path.
+ if (!working.empty()) {
+ const char* build_dir = this->Makefile->GetCurrentBinaryDirectory();
+ working = cmSystemTools::CollapseFullPath(working, build_dir);
+ }
+
+ // Choose which mode of the command to use.
+ bool escapeOldStyle = !verbatim;
+ if (source.empty() && output.empty()) {
+ // Source is empty, use the target.
+ std::vector<std::string> no_depends;
+ this->Makefile->AddCustomCommandToTarget(
+ target, byproducts, no_depends, commandLines, cctype, comment,
+ working.c_str(), escapeOldStyle, uses_terminal);
+ } 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);
+
+ // Add implicit dependency scanning requests if any were given.
+ if (!implicit_depends.empty()) {
+ bool okay = false;
+ if (cmSourceFile* sf =
+ this->Makefile->GetSourceFileWithOutput(output[0])) {
+ if (cmCustomCommand* cc = sf->GetCustomCommand()) {
+ okay = true;
+ cc->SetImplicitDepends(implicit_depends);
+ }
+ }
+ if (!okay) {
+ std::ostringstream e;
+ e << "could not locate source file with a custom command producing \""
+ << output[0] << "\" even though this command tried to create it!";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+ } else if (!byproducts.empty()) {
+ this->SetError("BYPRODUCTS may not be specified with SOURCE signatures");
+ return false;
+ } else if (uses_terminal) {
+ this->SetError("USES_TERMINAL may not be used with SOURCE signatures");
+ return false;
+ } else {
+ bool issueMessage = true;
+ std::ostringstream e;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0050)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0050) << "\n";
+ break;
+ case cmPolicies::OLD:
+ issueMessage = false;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ messageType = cmake::FATAL_ERROR;
+ break;
+ }
+
+ if (issueMessage) {
+ e << "The SOURCE signatures of add_custom_command are no longer "
+ "supported.";
+ this->Makefile->IssueMessage(messageType, e.str());
+ if (messageType == cmake::FATAL_ERROR) {
+ return false;
+ }
+ }
+
+ // Use the old-style mode for backward compatibility.
+ this->Makefile->AddCustomCommandOldStyle(target, outputs, depends, source,
+ commandLines, comment);
+ }
+
+ return true;
+}
+
+bool cmAddCustomCommandCommand::CheckOutputs(
+ const std::vector<std::string>& outputs)
+{
+ for (std::vector<std::string>::const_iterator o = outputs.begin();
+ o != outputs.end(); ++o) {
+ // Make sure the file will not be generated into the source
+ // directory during an out of source build.
+ if (!this->Makefile->CanIWriteThisFile(o->c_str())) {
+ std::string e = "attempted to have a file \"" + *o +
+ "\" in a source directory as an output of custom command.";
+ this->SetError(e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ // Make sure the output file name has no invalid characters.
+ std::string::size_type pos = o->find_first_of("#<>");
+ if (pos != o->npos) {
+ std::ostringstream msg;
+ msg << "called with OUTPUT containing a \"" << (*o)[pos]
+ << "\". This character is not allowed.";
+ this->SetError(msg.str());
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/Source/cmAddCustomCommandCommand.h b/Source/cmAddCustomCommandCommand.h
new file mode 100644
index 0000000..1164d46
--- /dev/null
+++ b/Source/cmAddCustomCommandCommand.h
@@ -0,0 +1,49 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmAddCustomCommandCommand_h
+#define cmAddCustomCommandCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmAddCustomCommandCommand
+ * \brief cmAddCustomCommandCommand defines a new command (rule) that can
+ * be executed within the build process
+ *
+ */
+
+class cmAddCustomCommandCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmAddCustomCommandCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "add_custom_command"; }
+
+ cmTypeMacro(cmAddCustomCommandCommand, cmCommand);
+
+protected:
+ bool CheckOutputs(const std::vector<std::string>& outputs);
+};
+
+#endif
diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx
new file mode 100644
index 0000000..9dc7c59
--- /dev/null
+++ b/Source/cmAddCustomTargetCommand.cxx
@@ -0,0 +1,234 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmAddCustomTargetCommand.h"
+
+#include "cmGeneratorExpression.h"
+#include "cmGlobalGenerator.h"
+
+// cmAddCustomTargetCommand
+bool cmAddCustomTargetCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string targetName = args[0];
+
+ // Check the target name.
+ if (targetName.find_first_of("/\\") != targetName.npos) {
+ std::ostringstream e;
+ e << "called with invalid target name \"" << targetName
+ << "\". Target names may not contain a slash. "
+ << "Use ADD_CUSTOM_COMMAND to generate files.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Accumulate one command line at a time.
+ cmCustomCommandLine currentLine;
+
+ // Save all command lines.
+ cmCustomCommandLines commandLines;
+
+ // Accumulate dependencies.
+ std::vector<std::string> depends, byproducts;
+ std::string working_directory;
+ bool verbatim = false;
+ bool uses_terminal = false;
+ std::string comment_buffer;
+ const char* comment = CM_NULLPTR;
+ std::vector<std::string> sources;
+
+ // Keep track of parser state.
+ enum tdoing
+ {
+ doing_command,
+ doing_depends,
+ doing_byproducts,
+ doing_working_directory,
+ doing_comment,
+ doing_source,
+ doing_nothing
+ };
+ tdoing doing = doing_command;
+
+ // Look for the ALL option.
+ bool excludeFromAll = true;
+ unsigned int start = 1;
+ if (args.size() > 1) {
+ if (args[1] == "ALL") {
+ excludeFromAll = false;
+ start = 2;
+ }
+ }
+
+ // Parse the rest of the arguments.
+ for (unsigned int j = start; j < args.size(); ++j) {
+ std::string const& copy = args[j];
+
+ if (copy == "DEPENDS") {
+ doing = doing_depends;
+ } else if (copy == "BYPRODUCTS") {
+ doing = doing_byproducts;
+ } else if (copy == "WORKING_DIRECTORY") {
+ doing = doing_working_directory;
+ } else if (copy == "VERBATIM") {
+ doing = doing_nothing;
+ verbatim = true;
+ } else if (copy == "USES_TERMINAL") {
+ doing = doing_nothing;
+ uses_terminal = true;
+ } else if (copy == "COMMENT") {
+ doing = doing_comment;
+ } else if (copy == "COMMAND") {
+ doing = doing_command;
+
+ // Save the current command before starting the next command.
+ if (!currentLine.empty()) {
+ commandLines.push_back(currentLine);
+ currentLine.clear();
+ }
+ } else if (copy == "SOURCES") {
+ doing = doing_source;
+ } else {
+ switch (doing) {
+ case doing_working_directory:
+ working_directory = copy;
+ break;
+ case doing_command:
+ currentLine.push_back(copy);
+ break;
+ case doing_byproducts: {
+ std::string filename;
+ if (!cmSystemTools::FileIsFullPath(copy.c_str())) {
+ filename = this->Makefile->GetCurrentBinaryDirectory();
+ filename += "/";
+ }
+ filename += copy;
+ cmSystemTools::ConvertToUnixSlashes(filename);
+ byproducts.push_back(filename);
+ } break;
+ case doing_depends: {
+ std::string dep = copy;
+ cmSystemTools::ConvertToUnixSlashes(dep);
+ depends.push_back(dep);
+ } break;
+ case doing_comment:
+ comment_buffer = copy;
+ comment = comment_buffer.c_str();
+ break;
+ case doing_source:
+ sources.push_back(copy);
+ break;
+ default:
+ this->SetError("Wrong syntax. Unknown type of argument.");
+ return false;
+ }
+ }
+ }
+
+ std::string::size_type pos = targetName.find_first_of("#<>");
+ if (pos != targetName.npos) {
+ std::ostringstream msg;
+ msg << "called with target name containing a \"" << targetName[pos]
+ << "\". This character is not allowed.";
+ this->SetError(msg.str());
+ return false;
+ }
+
+ // Some requirements on custom target names already exist
+ // and have been checked at this point.
+ // The following restrictions overlap but depend on policy CMP0037.
+ bool nameOk = cmGeneratorExpression::IsValidTargetName(targetName) &&
+ !cmGlobalGenerator::IsReservedTarget(targetName);
+ if (nameOk) {
+ nameOk = targetName.find(":") == std::string::npos;
+ }
+ if (!nameOk) {
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ std::ostringstream e;
+ bool issueMessage = false;
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0037)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n";
+ issueMessage = true;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ issueMessage = true;
+ messageType = cmake::FATAL_ERROR;
+ }
+ if (issueMessage) {
+ /* clang-format off */
+ e << "The target name \"" << targetName <<
+ "\" is reserved or not valid for certain "
+ "CMake features, such as generator expressions, and may result "
+ "in undefined behavior.";
+ /* clang-format on */
+ this->Makefile->IssueMessage(messageType, e.str());
+
+ if (messageType == cmake::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+
+ // Store the last command line finished.
+ if (!currentLine.empty()) {
+ commandLines.push_back(currentLine);
+ currentLine.clear();
+ }
+
+ // Enforce name uniqueness.
+ {
+ std::string msg;
+ if (!this->Makefile->EnforceUniqueName(targetName, msg, true)) {
+ this->SetError(msg);
+ return false;
+ }
+ }
+
+ // Convert working directory to a full path.
+ if (!working_directory.empty()) {
+ const char* build_dir = this->Makefile->GetCurrentBinaryDirectory();
+ working_directory =
+ cmSystemTools::CollapseFullPath(working_directory, build_dir);
+ }
+
+ if (commandLines.empty() && !byproducts.empty()) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "BYPRODUCTS may not be specified without any COMMAND");
+ return true;
+ }
+ if (commandLines.empty() && uses_terminal) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "USES_TERMINAL may not be specified without any COMMAND");
+ return true;
+ }
+
+ // Add the utility target to the makefile.
+ bool escapeOldStyle = !verbatim;
+ cmTarget* target = this->Makefile->AddUtilityCommand(
+ targetName, excludeFromAll, working_directory.c_str(), byproducts, depends,
+ commandLines, escapeOldStyle, comment, uses_terminal);
+
+ // Add additional user-specified source files to the target.
+ target->AddSources(sources);
+
+ return true;
+}
diff --git a/Source/cmAddCustomTargetCommand.h b/Source/cmAddCustomTargetCommand.h
new file mode 100644
index 0000000..120d4d4
--- /dev/null
+++ b/Source/cmAddCustomTargetCommand.h
@@ -0,0 +1,47 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmAddCustomTargetCommand_h
+#define cmAddCustomTargetCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmAddCustomTargetCommand
+ * \brief Command that adds a target to the build system.
+ *
+ * cmAddCustomTargetCommand adds an extra target to the build system.
+ * This is useful when you would like to add special
+ * targets like "install,", "clean," and so on.
+ */
+class cmAddCustomTargetCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmAddCustomTargetCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "add_custom_target"; }
+
+ cmTypeMacro(cmAddCustomTargetCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmAddDefinitionsCommand.cxx b/Source/cmAddDefinitionsCommand.cxx
new file mode 100644
index 0000000..2d0d026
--- /dev/null
+++ b/Source/cmAddDefinitionsCommand.cxx
@@ -0,0 +1,28 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmAddDefinitionsCommand.h"
+
+// cmAddDefinitionsCommand
+bool cmAddDefinitionsCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ // it is OK to have no arguments
+ if (args.size() < 1) {
+ return true;
+ }
+
+ for (std::vector<std::string>::const_iterator i = args.begin();
+ i != args.end(); ++i) {
+ this->Makefile->AddDefineFlag(i->c_str());
+ }
+ return true;
+}
diff --git a/Source/cmAddDefinitionsCommand.h b/Source/cmAddDefinitionsCommand.h
new file mode 100644
index 0000000..b30001c
--- /dev/null
+++ b/Source/cmAddDefinitionsCommand.h
@@ -0,0 +1,46 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmAddDefinitionsCommand_h
+#define cmAddDefinitionsCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmAddDefinitionsCommand
+ * \brief Specify a list of compiler defines
+ *
+ * cmAddDefinitionsCommand specifies a list of compiler defines. These defines
+ * will be added to the compile command.
+ */
+class cmAddDefinitionsCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmAddDefinitionsCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "add_definitions"; }
+
+ cmTypeMacro(cmAddDefinitionsCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmAddDependenciesCommand.cxx b/Source/cmAddDependenciesCommand.cxx
new file mode 100644
index 0000000..5cf9d3b
--- /dev/null
+++ b/Source/cmAddDependenciesCommand.cxx
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmAddDependenciesCommand.h"
+
+#include "cmGlobalGenerator.h"
+
+// cmDependenciesCommand
+bool cmAddDependenciesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string target_name = args[0];
+ if (this->Makefile->IsAlias(target_name)) {
+ std::ostringstream e;
+ e << "Cannot add target-level dependencies to alias target \""
+ << target_name << "\".\n";
+ this->Makefile->IssueMessage(cmake::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);
+ }
+ } else {
+ std::ostringstream e;
+ e << "Cannot add target-level dependencies to non-existent target \""
+ << target_name << "\".\n"
+ << "The add_dependencies works for top-level logical targets created "
+ << "by the add_executable, add_library, or add_custom_target commands. "
+ << "If you want to add file-level dependencies see the DEPENDS option "
+ << "of the add_custom_target and add_custom_command commands.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ }
+
+ return true;
+}
diff --git a/Source/cmAddDependenciesCommand.h b/Source/cmAddDependenciesCommand.h
new file mode 100644
index 0000000..c059ff2
--- /dev/null
+++ b/Source/cmAddDependenciesCommand.h
@@ -0,0 +1,45 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmDependenciessCommand_h
+#define cmDependenciessCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmAddDependenciesCommand
+ * \brief Add a dependency to a target
+ *
+ * cmAddDependenciesCommand adds a dependency to a target
+ */
+class cmAddDependenciesCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmAddDependenciesCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "add_dependencies"; }
+
+ cmTypeMacro(cmAddDependenciesCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmAddExecutableCommand.cxx b/Source/cmAddExecutableCommand.cxx
new file mode 100644
index 0000000..fec5eb8
--- /dev/null
+++ b/Source/cmAddExecutableCommand.cxx
@@ -0,0 +1,208 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmAddExecutableCommand.h"
+
+// cmExecutableCommand
+bool cmAddExecutableCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ std::vector<std::string>::const_iterator s = args.begin();
+
+ std::string exename = *s;
+
+ ++s;
+ bool use_win32 = false;
+ bool use_macbundle = false;
+ bool excludeFromAll = false;
+ bool importTarget = false;
+ bool importGlobal = false;
+ bool isAlias = false;
+ while (s != args.end()) {
+ if (*s == "WIN32") {
+ ++s;
+ use_win32 = true;
+ } else if (*s == "MACOSX_BUNDLE") {
+ ++s;
+ use_macbundle = true;
+ } else if (*s == "EXCLUDE_FROM_ALL") {
+ ++s;
+ excludeFromAll = true;
+ } else if (*s == "IMPORTED") {
+ ++s;
+ importTarget = true;
+ } else if (importTarget && *s == "GLOBAL") {
+ ++s;
+ importGlobal = true;
+ } else if (*s == "ALIAS") {
+ ++s;
+ isAlias = true;
+ } else {
+ break;
+ }
+ }
+
+ bool nameOk = cmGeneratorExpression::IsValidTargetName(exename) &&
+ !cmGlobalGenerator::IsReservedTarget(exename);
+
+ if (nameOk && !importTarget && !isAlias) {
+ nameOk = exename.find(":") == std::string::npos;
+ }
+ if (!nameOk) {
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ std::ostringstream e;
+ bool issueMessage = false;
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0037)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n";
+ issueMessage = true;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ issueMessage = true;
+ messageType = cmake::FATAL_ERROR;
+ }
+ if (issueMessage) {
+ /* clang-format off */
+ e << "The target name \"" << exename <<
+ "\" is reserved or not valid for certain "
+ "CMake features, such as generator expressions, and may result "
+ "in undefined behavior.";
+ /* clang-format on */
+ this->Makefile->IssueMessage(messageType, e.str());
+
+ if (messageType == cmake::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+
+ // Special modifiers are not allowed with IMPORTED signature.
+ if (importTarget && (use_win32 || use_macbundle || excludeFromAll)) {
+ if (use_win32) {
+ this->SetError("may not be given WIN32 for an IMPORTED target.");
+ } else if (use_macbundle) {
+ this->SetError("may not be given MACOSX_BUNDLE for an IMPORTED target.");
+ } else // if(excludeFromAll)
+ {
+ this->SetError(
+ "may not be given EXCLUDE_FROM_ALL for an IMPORTED target.");
+ }
+ return false;
+ }
+ if (isAlias) {
+ if (!cmGeneratorExpression::IsValidTargetName(exename)) {
+ this->SetError("Invalid name for ALIAS: " + exename);
+ return false;
+ }
+ if (excludeFromAll) {
+ this->SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense.");
+ return false;
+ }
+ if (importTarget || importGlobal) {
+ this->SetError("IMPORTED with ALIAS is not allowed.");
+ return false;
+ }
+ if (args.size() != 3) {
+ std::ostringstream e;
+ e << "ALIAS requires exactly one target argument.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ const char* aliasedName = s->c_str();
+ if (this->Makefile->IsAlias(aliasedName)) {
+ std::ostringstream e;
+ e << "cannot create ALIAS target \"" << exename << "\" because target \""
+ << aliasedName << "\" is itself an ALIAS.";
+ this->SetError(e.str());
+ return false;
+ }
+ cmTarget* aliasedTarget =
+ this->Makefile->FindTargetToUse(aliasedName, true);
+ if (!aliasedTarget) {
+ std::ostringstream e;
+ e << "cannot create ALIAS target \"" << exename << "\" because target \""
+ << aliasedName << "\" does not already "
+ "exist.";
+ this->SetError(e.str());
+ return false;
+ }
+ cmState::TargetType type = aliasedTarget->GetType();
+ if (type != cmState::EXECUTABLE) {
+ std::ostringstream e;
+ e << "cannot create ALIAS target \"" << exename << "\" because target \""
+ << aliasedName << "\" is not an "
+ "executable.";
+ this->SetError(e.str());
+ return false;
+ }
+ if (aliasedTarget->IsImported()) {
+ std::ostringstream e;
+ e << "cannot create ALIAS target \"" << exename << "\" because target \""
+ << aliasedName << "\" is IMPORTED.";
+ this->SetError(e.str());
+ return false;
+ }
+ this->Makefile->AddAlias(exename, aliasedName);
+ return true;
+ }
+
+ // Handle imported target creation.
+ if (importTarget) {
+ // Make sure the target does not already exist.
+ if (this->Makefile->FindTargetToUse(exename)) {
+ std::ostringstream e;
+ e << "cannot create imported target \"" << exename
+ << "\" because another target with the same name already exists.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Create the imported target.
+ this->Makefile->AddImportedTarget(exename, cmState::EXECUTABLE,
+ importGlobal);
+ return true;
+ }
+
+ // Enforce name uniqueness.
+ {
+ std::string msg;
+ if (!this->Makefile->EnforceUniqueName(exename, msg)) {
+ this->SetError(msg);
+ return false;
+ }
+ }
+
+ if (s == args.end()) {
+ this->SetError(
+ "called with incorrect number of arguments, no sources provided");
+ return false;
+ }
+
+ std::vector<std::string> srclists(s, args.end());
+ cmTarget* tgt =
+ this->Makefile->AddExecutable(exename.c_str(), srclists, excludeFromAll);
+ if (use_win32) {
+ tgt->SetProperty("WIN32_EXECUTABLE", "ON");
+ }
+ if (use_macbundle) {
+ tgt->SetProperty("MACOSX_BUNDLE", "ON");
+ }
+
+ return true;
+}
diff --git a/Source/cmAddExecutableCommand.h b/Source/cmAddExecutableCommand.h
new file mode 100644
index 0000000..133f5bf
--- /dev/null
+++ b/Source/cmAddExecutableCommand.h
@@ -0,0 +1,46 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExecutablesCommand_h
+#define cmExecutablesCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmExecutablesCommand
+ * \brief Defines a list of executables to build.
+ *
+ * cmExecutablesCommand defines a list of executable (i.e., test)
+ * programs to create.
+ */
+class cmAddExecutableCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmAddExecutableCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "add_executable"; }
+
+ cmTypeMacro(cmAddExecutableCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx
new file mode 100644
index 0000000..4516ed2
--- /dev/null
+++ b/Source/cmAddLibraryCommand.cxx
@@ -0,0 +1,370 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmAddLibraryCommand.h"
+
+#include "cmState.h"
+#include "cmake.h"
+
+// cmLibraryCommand
+bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ // Library type defaults to value of BUILD_SHARED_LIBS, if it exists,
+ // otherwise it defaults to static library.
+ cmState::TargetType type = cmState::SHARED_LIBRARY;
+ if (cmSystemTools::IsOff(
+ this->Makefile->GetDefinition("BUILD_SHARED_LIBS"))) {
+ type = cmState::STATIC_LIBRARY;
+ }
+ bool excludeFromAll = false;
+ bool importTarget = false;
+ bool importGlobal = false;
+
+ std::vector<std::string>::const_iterator s = args.begin();
+
+ std::string libName = *s;
+
+ ++s;
+
+ // If the second argument is "SHARED" or "STATIC", then it controls
+ // the type of library. Otherwise, it is treated as a source or
+ // source list name. There may be two keyword arguments, check for them
+ bool haveSpecifiedType = false;
+ bool isAlias = false;
+ while (s != args.end()) {
+ std::string libType = *s;
+ if (libType == "STATIC") {
+ if (type == cmState::INTERFACE_LIBRARY) {
+ std::ostringstream e;
+ e << "INTERFACE library specified with conflicting STATIC type.";
+ this->SetError(e.str());
+ return false;
+ }
+ ++s;
+ type = cmState::STATIC_LIBRARY;
+ haveSpecifiedType = true;
+ } else if (libType == "SHARED") {
+ if (type == cmState::INTERFACE_LIBRARY) {
+ std::ostringstream e;
+ e << "INTERFACE library specified with conflicting SHARED type.";
+ this->SetError(e.str());
+ return false;
+ }
+ ++s;
+ type = cmState::SHARED_LIBRARY;
+ haveSpecifiedType = true;
+ } else if (libType == "MODULE") {
+ if (type == cmState::INTERFACE_LIBRARY) {
+ std::ostringstream e;
+ e << "INTERFACE library specified with conflicting MODULE type.";
+ this->SetError(e.str());
+ return false;
+ }
+ ++s;
+ type = cmState::MODULE_LIBRARY;
+ haveSpecifiedType = true;
+ } else if (libType == "OBJECT") {
+ if (type == cmState::INTERFACE_LIBRARY) {
+ std::ostringstream e;
+ e << "INTERFACE library specified with conflicting OBJECT type.";
+ this->SetError(e.str());
+ return false;
+ }
+ ++s;
+ type = cmState::OBJECT_LIBRARY;
+ haveSpecifiedType = true;
+ } else if (libType == "UNKNOWN") {
+ if (type == cmState::INTERFACE_LIBRARY) {
+ std::ostringstream e;
+ e << "INTERFACE library specified with conflicting UNKNOWN type.";
+ this->SetError(e.str());
+ return false;
+ }
+ ++s;
+ type = cmState::UNKNOWN_LIBRARY;
+ haveSpecifiedType = true;
+ } else if (libType == "ALIAS") {
+ if (type == cmState::INTERFACE_LIBRARY) {
+ std::ostringstream e;
+ e << "INTERFACE library specified with conflicting ALIAS type.";
+ this->SetError(e.str());
+ return false;
+ }
+ ++s;
+ isAlias = true;
+ } else if (libType == "INTERFACE") {
+ if (haveSpecifiedType) {
+ std::ostringstream e;
+ e << "INTERFACE library specified with conflicting/multiple types.";
+ this->SetError(e.str());
+ return false;
+ }
+ if (isAlias) {
+ std::ostringstream e;
+ e << "INTERFACE library specified with conflicting ALIAS type.";
+ this->SetError(e.str());
+ return false;
+ }
+ if (excludeFromAll) {
+ std::ostringstream e;
+ e << "INTERFACE library may not be used with EXCLUDE_FROM_ALL.";
+ this->SetError(e.str());
+ return false;
+ }
+ ++s;
+ type = cmState::INTERFACE_LIBRARY;
+ haveSpecifiedType = true;
+ } else if (*s == "EXCLUDE_FROM_ALL") {
+ if (type == cmState::INTERFACE_LIBRARY) {
+ std::ostringstream e;
+ e << "INTERFACE library may not be used with EXCLUDE_FROM_ALL.";
+ this->SetError(e.str());
+ return false;
+ }
+ ++s;
+ excludeFromAll = true;
+ } else if (*s == "IMPORTED") {
+ ++s;
+ importTarget = true;
+ } else if (importTarget && *s == "GLOBAL") {
+ ++s;
+ importGlobal = true;
+ } else if (type == cmState::INTERFACE_LIBRARY && *s == "GLOBAL") {
+ std::ostringstream e;
+ e << "GLOBAL option may only be used with IMPORTED libraries.";
+ this->SetError(e.str());
+ return false;
+ } else {
+ break;
+ }
+ }
+
+ if (type == cmState::INTERFACE_LIBRARY) {
+ if (s != args.end()) {
+ std::ostringstream e;
+ e << "INTERFACE library requires no source arguments.";
+ this->SetError(e.str());
+ return false;
+ }
+ if (importGlobal && !importTarget) {
+ std::ostringstream e;
+ e << "INTERFACE library specified as GLOBAL, but not as IMPORTED.";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ bool nameOk = cmGeneratorExpression::IsValidTargetName(libName) &&
+ !cmGlobalGenerator::IsReservedTarget(libName);
+
+ if (nameOk && !importTarget && !isAlias) {
+ nameOk = libName.find(":") == std::string::npos;
+ }
+ if (!nameOk) {
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ std::ostringstream e;
+ bool issueMessage = false;
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0037)) {
+ case cmPolicies::WARN:
+ if (type != cmState::INTERFACE_LIBRARY) {
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n";
+ issueMessage = true;
+ }
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ issueMessage = true;
+ messageType = cmake::FATAL_ERROR;
+ }
+ if (issueMessage) {
+ e << "The target name \"" << libName
+ << "\" is reserved or not valid for certain "
+ "CMake features, such as generator expressions, and may result "
+ "in undefined behavior.";
+ this->Makefile->IssueMessage(messageType, e.str());
+
+ if (messageType == cmake::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+
+ if (isAlias) {
+ if (!cmGeneratorExpression::IsValidTargetName(libName)) {
+ this->SetError("Invalid name for ALIAS: " + libName);
+ return false;
+ }
+ if (excludeFromAll) {
+ this->SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense.");
+ return false;
+ }
+ if (importTarget || importGlobal) {
+ this->SetError("IMPORTED with ALIAS is not allowed.");
+ return false;
+ }
+ if (args.size() != 3) {
+ std::ostringstream e;
+ e << "ALIAS requires exactly one target argument.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ const char* aliasedName = s->c_str();
+ if (this->Makefile->IsAlias(aliasedName)) {
+ std::ostringstream e;
+ e << "cannot create ALIAS target \"" << libName << "\" because target \""
+ << aliasedName << "\" is itself an ALIAS.";
+ this->SetError(e.str());
+ return false;
+ }
+ cmTarget* aliasedTarget =
+ this->Makefile->FindTargetToUse(aliasedName, true);
+ if (!aliasedTarget) {
+ std::ostringstream e;
+ e << "cannot create ALIAS target \"" << libName << "\" because target \""
+ << aliasedName << "\" does not already "
+ "exist.";
+ this->SetError(e.str());
+ return false;
+ }
+ cmState::TargetType aliasedType = aliasedTarget->GetType();
+ if (aliasedType != cmState::SHARED_LIBRARY &&
+ aliasedType != cmState::STATIC_LIBRARY &&
+ aliasedType != cmState::MODULE_LIBRARY &&
+ aliasedType != cmState::OBJECT_LIBRARY &&
+ aliasedType != cmState::INTERFACE_LIBRARY) {
+ std::ostringstream e;
+ e << "cannot create ALIAS target \"" << libName << "\" because target \""
+ << aliasedName << "\" is not a library.";
+ this->SetError(e.str());
+ return false;
+ }
+ if (aliasedTarget->IsImported()) {
+ std::ostringstream e;
+ e << "cannot create ALIAS target \"" << libName << "\" because target \""
+ << aliasedName << "\" is IMPORTED.";
+ this->SetError(e.str());
+ return false;
+ }
+ this->Makefile->AddAlias(libName, aliasedName);
+ return true;
+ }
+
+ if (importTarget && excludeFromAll) {
+ this->SetError("excludeFromAll with IMPORTED target makes no sense.");
+ return false;
+ }
+
+ /* ideally we should check whether for the linker language of the target
+ CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to
+ STATIC. But at this point we know only the name of the target, but not
+ yet its linker language. */
+ if ((type == cmState::SHARED_LIBRARY || type == cmState::MODULE_LIBRARY) &&
+ (this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "TARGET_SUPPORTS_SHARED_LIBS") == false)) {
+ std::ostringstream w;
+ w << "ADD_LIBRARY called with "
+ << (type == cmState::SHARED_LIBRARY ? "SHARED" : "MODULE")
+ << " option but the target platform does not support dynamic linking. "
+ "Building a STATIC library instead. This may lead to problems.";
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ type = cmState::STATIC_LIBRARY;
+ }
+
+ // Handle imported target creation.
+ if (importTarget) {
+ // The IMPORTED signature requires a type to be specified explicitly.
+ if (!haveSpecifiedType) {
+ this->SetError("called with IMPORTED argument but no library type.");
+ return false;
+ }
+ if (type == cmState::OBJECT_LIBRARY) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "The OBJECT library type may not be used for IMPORTED libraries.");
+ return true;
+ }
+ if (type == cmState::INTERFACE_LIBRARY) {
+ if (!cmGeneratorExpression::IsValidTargetName(libName)) {
+ std::ostringstream e;
+ e << "Invalid name for IMPORTED INTERFACE library target: " << libName;
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ // Make sure the target does not already exist.
+ if (this->Makefile->FindTargetToUse(libName)) {
+ std::ostringstream e;
+ e << "cannot create imported target \"" << libName
+ << "\" because another target with the same name already exists.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Create the imported target.
+ this->Makefile->AddImportedTarget(libName, type, importGlobal);
+ return true;
+ }
+
+ // A non-imported target may not have UNKNOWN type.
+ if (type == cmState::UNKNOWN_LIBRARY) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "The UNKNOWN library type may be used only for IMPORTED libraries.");
+ return true;
+ }
+
+ // Enforce name uniqueness.
+ {
+ std::string msg;
+ if (!this->Makefile->EnforceUniqueName(libName, msg)) {
+ this->SetError(msg);
+ return false;
+ }
+ }
+
+ std::vector<std::string> srclists;
+
+ if (type == cmState::INTERFACE_LIBRARY) {
+ if (!cmGeneratorExpression::IsValidTargetName(libName) ||
+ libName.find("::") != std::string::npos) {
+ std::ostringstream e;
+ e << "Invalid name for INTERFACE library target: " << libName;
+ this->SetError(e.str());
+ return false;
+ }
+
+ this->Makefile->AddLibrary(libName, type, srclists, excludeFromAll);
+ return true;
+ }
+
+ if (s == args.end()) {
+ std::string msg = "You have called ADD_LIBRARY for library ";
+ msg += args[0];
+ msg += " without any source files. This typically indicates a problem ";
+ msg += "with your CMakeLists.txt file";
+ cmSystemTools::Message(msg.c_str(), "Warning");
+ }
+
+ srclists.insert(srclists.end(), s, args.end());
+
+ this->Makefile->AddLibrary(libName, type, srclists, excludeFromAll);
+
+ return true;
+}
diff --git a/Source/cmAddLibraryCommand.h b/Source/cmAddLibraryCommand.h
new file mode 100644
index 0000000..20f1bc9
--- /dev/null
+++ b/Source/cmAddLibraryCommand.h
@@ -0,0 +1,46 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLibrarysCommand_h
+#define cmLibrarysCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmLibrarysCommand
+ * \brief Defines a list of executables to build.
+ *
+ * cmLibrarysCommand defines a list of executable (i.e., test)
+ * programs to create.
+ */
+class cmAddLibraryCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmAddLibraryCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "add_library"; }
+
+ cmTypeMacro(cmAddLibraryCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx
new file mode 100644
index 0000000..63a9051
--- /dev/null
+++ b/Source/cmAddSubDirectoryCommand.cxx
@@ -0,0 +1,111 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmAddSubDirectoryCommand.h"
+
+// cmAddSubDirectoryCommand
+bool cmAddSubDirectoryCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // store the binpath
+ std::string srcArg = args[0];
+ std::string binArg;
+
+ 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") {
+ excludeFromAll = true;
+ continue;
+ } else if (binArg.empty()) {
+ binArg = *i;
+ } else {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ }
+
+ // Compute the full path to the specified source directory.
+ // Interpret a relative path with respect to the current source directory.
+ std::string srcPath;
+ if (cmSystemTools::FileIsFullPath(srcArg.c_str())) {
+ srcPath = srcArg;
+ } else {
+ srcPath = this->Makefile->GetCurrentSourceDirectory();
+ srcPath += "/";
+ srcPath += srcArg;
+ }
+ if (!cmSystemTools::FileIsDirectory(srcPath)) {
+ std::string error = "given source \"";
+ error += srcArg;
+ error += "\" which is not an existing directory.";
+ this->SetError(error);
+ return false;
+ }
+ srcPath = cmSystemTools::CollapseFullPath(srcPath);
+
+ // Compute the full path to the binary directory.
+ std::string binPath;
+ if (binArg.empty()) {
+ // No binary directory was specified. If the source directory is
+ // not a subdirectory of the current directory then it is an
+ // error.
+ if (!cmSystemTools::IsSubDirectory(
+ srcPath, this->Makefile->GetCurrentSourceDirectory())) {
+ std::ostringstream e;
+ e << "not given a binary directory but the given source directory "
+ << "\"" << srcPath << "\" is not a subdirectory of \""
+ << this->Makefile->GetCurrentSourceDirectory() << "\". "
+ << "When specifying an out-of-tree source a binary directory "
+ << "must be explicitly specified.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Remove the CurrentDirectory from the srcPath and replace it
+ // with the CurrentOutputDirectory.
+ const char* src = this->Makefile->GetCurrentSourceDirectory();
+ const char* bin = this->Makefile->GetCurrentBinaryDirectory();
+ size_t srcLen = strlen(src);
+ size_t binLen = strlen(bin);
+ if (srcLen > 0 && src[srcLen - 1] == '/') {
+ --srcLen;
+ }
+ if (binLen > 0 && bin[binLen - 1] == '/') {
+ --binLen;
+ }
+ binPath = std::string(bin, binLen) + srcPath.substr(srcLen);
+ } else {
+ // Use the binary directory specified.
+ // Interpret a relative path with respect to the current binary directory.
+ if (cmSystemTools::FileIsFullPath(binArg.c_str())) {
+ binPath = binArg;
+ } else {
+ binPath = this->Makefile->GetCurrentBinaryDirectory();
+ binPath += "/";
+ binPath += binArg;
+ }
+ }
+ binPath = cmSystemTools::CollapseFullPath(binPath);
+
+ // Add the subdirectory using the computed full paths.
+ this->Makefile->AddSubDirectory(srcPath, binPath, excludeFromAll, true);
+
+ return true;
+}
diff --git a/Source/cmAddSubDirectoryCommand.h b/Source/cmAddSubDirectoryCommand.h
new file mode 100644
index 0000000..ec1d2c8
--- /dev/null
+++ b/Source/cmAddSubDirectoryCommand.h
@@ -0,0 +1,47 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmAddSubDirectoryCommand_h
+#define cmAddSubDirectoryCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmAddSubDirectoryCommand
+ * \brief Specify a subdirectory to build
+ *
+ * cmAddSubDirectoryCommand specifies a subdirectory to process
+ * by CMake. CMake will descend
+ * into the specified source directory and process any CMakeLists.txt found.
+ */
+class cmAddSubDirectoryCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmAddSubDirectoryCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "add_subdirectory"; }
+
+ cmTypeMacro(cmAddSubDirectoryCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmAddTestCommand.cxx b/Source/cmAddTestCommand.cxx
new file mode 100644
index 0000000..204dd97
--- /dev/null
+++ b/Source/cmAddTestCommand.cxx
@@ -0,0 +1,146 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmAddTestCommand.h"
+
+#include "cmTestGenerator.h"
+
+#include "cmTest.h"
+
+// cmExecutableCommand
+bool cmAddTestCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (!args.empty() && args[0] == "NAME") {
+ return this->HandleNameMode(args);
+ }
+
+ // First argument is the name of the test Second argument is the name of
+ // the executable to run (a target or external program) Remaining arguments
+ // are the arguments to pass to the executable
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Collect the command with arguments.
+ std::vector<std::string> command;
+ command.insert(command.end(), 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.
+ cmTest* test = this->Makefile->GetTest(args[0]);
+ if (test) {
+ // If the test was already added by a new-style signature do not
+ // allow it to be duplicated.
+ if (!test->GetOldStyle()) {
+ std::ostringstream e;
+ e << " given test name \"" << args[0]
+ << "\" which already exists in this directory.";
+ this->SetError(e.str());
+ return false;
+ }
+ } else {
+ test = this->Makefile->CreateTest(args[0]);
+ test->SetOldStyle(true);
+ this->Makefile->AddTestGenerator(new cmTestGenerator(test));
+ }
+ test->SetCommand(command);
+
+ return true;
+}
+
+bool cmAddTestCommand::HandleNameMode(std::vector<std::string> const& args)
+{
+ std::string name;
+ std::vector<std::string> configurations;
+ std::string working_directory;
+ std::vector<std::string> command;
+
+ // Read the arguments.
+ enum Doing
+ {
+ DoingName,
+ DoingCommand,
+ DoingConfigs,
+ DoingWorkingDirectory,
+ DoingNone
+ };
+ Doing doing = DoingName;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "COMMAND") {
+ if (!command.empty()) {
+ this->SetError(" may be given at most one COMMAND.");
+ return false;
+ }
+ doing = DoingCommand;
+ } else if (args[i] == "CONFIGURATIONS") {
+ if (!configurations.empty()) {
+ this->SetError(" may be given at most one set of CONFIGURATIONS.");
+ return false;
+ }
+ doing = DoingConfigs;
+ } else if (args[i] == "WORKING_DIRECTORY") {
+ if (!working_directory.empty()) {
+ this->SetError(" may be given at most one WORKING_DIRECTORY.");
+ return false;
+ }
+ doing = DoingWorkingDirectory;
+ } else if (doing == DoingName) {
+ name = args[i];
+ doing = DoingNone;
+ } else if (doing == DoingCommand) {
+ command.push_back(args[i]);
+ } else if (doing == DoingConfigs) {
+ configurations.push_back(args[i]);
+ } else if (doing == DoingWorkingDirectory) {
+ working_directory = args[i];
+ doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << " given unknown argument:\n " << args[i] << "\n";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ // Require a test name.
+ if (name.empty()) {
+ this->SetError(" must be given non-empty NAME.");
+ return false;
+ }
+
+ // Require a command.
+ if (command.empty()) {
+ this->SetError(" must be given non-empty COMMAND.");
+ return false;
+ }
+
+ // Require a unique test name within the directory.
+ if (this->Makefile->GetTest(name)) {
+ std::ostringstream e;
+ e << " given test NAME \"" << name
+ << "\" which already exists in this directory.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Add the test.
+ cmTest* test = this->Makefile->CreateTest(name);
+ test->SetOldStyle(false);
+ test->SetCommand(command);
+ if (!working_directory.empty()) {
+ test->SetProperty("WORKING_DIRECTORY", working_directory.c_str());
+ }
+ this->Makefile->AddTestGenerator(new cmTestGenerator(test, configurations));
+
+ return true;
+}
diff --git a/Source/cmAddTestCommand.h b/Source/cmAddTestCommand.h
new file mode 100644
index 0000000..abff0c2
--- /dev/null
+++ b/Source/cmAddTestCommand.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmAddTestCommand_h
+#define cmAddTestCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmAddTestCommand
+ * \brief Add a test to the lists of tests to run.
+ *
+ * cmAddTestCommand adds a test to the list of tests to run .
+ */
+class cmAddTestCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmAddTestCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "add_test"; }
+
+ cmTypeMacro(cmAddTestCommand, cmCommand);
+
+private:
+ bool HandleNameMode(std::vector<std::string> const& args);
+};
+
+#endif
diff --git a/Source/cmAlgorithms.h b/Source/cmAlgorithms.h
new file mode 100644
index 0000000..ee803c8
--- /dev/null
+++ b/Source/cmAlgorithms.h
@@ -0,0 +1,397 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmAlgorithms_h
+#define cmAlgorithms_h
+
+#include "cmStandardIncludes.h"
+
+inline bool cmHasLiteralPrefixImpl(const std::string& str1, const char* str2,
+ size_t N)
+{
+ return strncmp(str1.c_str(), str2, N) == 0;
+}
+
+inline bool cmHasLiteralPrefixImpl(const char* str1, const char* str2,
+ size_t N)
+{
+ return strncmp(str1, str2, N) == 0;
+}
+
+inline bool cmHasLiteralSuffixImpl(const std::string& str1, const char* str2,
+ size_t N)
+{
+ size_t len = str1.size();
+ return len >= N && strcmp(str1.c_str() + len - N, str2) == 0;
+}
+
+inline bool cmHasLiteralSuffixImpl(const char* str1, const char* str2,
+ size_t N)
+{
+ size_t len = strlen(str1);
+ return len >= N && strcmp(str1 + len - N, str2) == 0;
+}
+
+template <typename T, size_t N>
+const T* cmArrayBegin(const T (&a)[N])
+{
+ return a;
+}
+template <typename T, size_t N>
+const T* cmArrayEnd(const T (&a)[N])
+{
+ return a + N;
+}
+template <typename T, size_t N>
+size_t cmArraySize(const T (&)[N])
+{
+ return N;
+}
+
+template <typename T, size_t N>
+bool cmHasLiteralPrefix(const T& str1, const char (&str2)[N])
+{
+ return cmHasLiteralPrefixImpl(str1, str2, N - 1);
+}
+
+template <typename T, size_t N>
+bool cmHasLiteralSuffix(const T& str1, const char (&str2)[N])
+{
+ return cmHasLiteralSuffixImpl(str1, str2, N - 1);
+}
+
+struct cmStrCmp
+{
+ cmStrCmp(const char* test)
+ : m_test(test)
+ {
+ }
+ cmStrCmp(const std::string& test)
+ : m_test(test)
+ {
+ }
+
+ bool operator()(const std::string& input) const { return m_test == input; }
+
+ bool operator()(const char* input) const
+ {
+ return strcmp(input, m_test.c_str()) == 0;
+ }
+
+private:
+ const std::string m_test;
+};
+
+template <typename FwdIt>
+FwdIt cmRotate(FwdIt first, FwdIt middle, FwdIt last)
+{
+ const typename std::iterator_traits<FwdIt>::difference_type dist =
+ std::distance(middle, last);
+ std::rotate(first, middle, last);
+ std::advance(first, dist);
+ return first;
+}
+
+namespace ContainerAlgorithms {
+
+template <typename T>
+struct cmIsPair
+{
+ enum
+ {
+ value = false
+ };
+};
+
+template <typename K, typename V>
+struct cmIsPair<std::pair<K, V> >
+{
+ enum
+ {
+ value = true
+ };
+};
+
+template <typename Range,
+ bool valueTypeIsPair = cmIsPair<typename Range::value_type>::value>
+struct DefaultDeleter
+{
+ void operator()(typename Range::value_type value) const { delete value; }
+};
+
+template <typename Range>
+struct DefaultDeleter<Range, /* valueTypeIsPair = */ true>
+{
+ void operator()(typename Range::value_type value) const
+ {
+ delete value.second;
+ }
+};
+
+template <typename FwdIt>
+FwdIt RemoveN(FwdIt i1, FwdIt i2, size_t n)
+{
+ FwdIt m = i1;
+ std::advance(m, n);
+ return cmRotate(i1, m, i2);
+}
+
+template <typename Range>
+struct BinarySearcher
+{
+ typedef typename Range::value_type argument_type;
+ BinarySearcher(Range const& r)
+ : m_range(r)
+ {
+ }
+
+ bool operator()(argument_type const& item) const
+ {
+ return std::binary_search(m_range.begin(), m_range.end(), item);
+ }
+
+private:
+ Range const& m_range;
+};
+}
+
+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)
+{
+ return cmRange<Iter1>(begin, end);
+}
+
+template <typename Range>
+cmRange<typename Range::const_iterator> cmMakeRange(Range const& range)
+{
+ return cmRange<typename Range::const_iterator>(range.begin(), range.end());
+}
+
+template <typename Range>
+void cmDeleteAll(Range const& r)
+{
+ std::for_each(r.begin(), r.end(),
+ ContainerAlgorithms::DefaultDeleter<Range>());
+}
+
+template <typename Range>
+std::string cmJoin(Range const& r, const char* delimiter)
+{
+ if (r.empty()) {
+ return std::string();
+ }
+ std::ostringstream os;
+ typedef typename Range::value_type ValueType;
+ typedef typename Range::const_iterator InputIt;
+ const InputIt first = r.begin();
+ InputIt last = r.end();
+ --last;
+ std::copy(first, last, std::ostream_iterator<ValueType>(os, delimiter));
+
+ os << *last;
+
+ return os.str();
+}
+
+template <typename Range>
+std::string cmJoin(Range const& r, std::string delimiter)
+{
+ return cmJoin(r, delimiter.c_str());
+}
+
+template <typename Range>
+typename Range::const_iterator cmRemoveN(Range& r, size_t n)
+{
+ return ContainerAlgorithms::RemoveN(r.begin(), r.end(), n);
+}
+
+template <typename Range, typename InputRange>
+typename Range::const_iterator cmRemoveIndices(Range& r, InputRange const& rem)
+{
+ typename InputRange::const_iterator remIt = rem.begin();
+ typename InputRange::const_iterator remEnd = rem.end();
+ const typename Range::iterator rangeEnd = r.end();
+ if (remIt == remEnd) {
+ return rangeEnd;
+ }
+
+ typename Range::iterator writer = r.begin();
+ std::advance(writer, *remIt);
+ typename Range::iterator pivot = writer;
+ typename InputRange::value_type prevRem = *remIt;
+ ++remIt;
+ size_t count = 1;
+ for (; writer != rangeEnd && remIt != remEnd; ++count, ++remIt) {
+ std::advance(pivot, *remIt - prevRem);
+ prevRem = *remIt;
+ writer = ContainerAlgorithms::RemoveN(writer, pivot, count);
+ }
+ return ContainerAlgorithms::RemoveN(writer, rangeEnd, count);
+}
+
+template <typename Range, typename MatchRange>
+typename Range::const_iterator cmRemoveMatching(Range& r, MatchRange const& m)
+{
+ return std::remove_if(r.begin(), r.end(),
+ ContainerAlgorithms::BinarySearcher<MatchRange>(m));
+}
+
+namespace ContainerAlgorithms {
+
+template <typename Range, typename T = typename Range::value_type>
+struct RemoveDuplicatesAPI
+{
+ typedef typename Range::const_iterator const_iterator;
+ typedef typename Range::const_iterator value_type;
+
+ static bool lessThan(value_type a, value_type b) { return *a < *b; }
+ static value_type uniqueValue(const_iterator a) { return a; }
+ template <typename It>
+ static bool valueCompare(It it, const_iterator it2)
+ {
+ return **it != *it2;
+ }
+};
+
+template <typename Range, typename T>
+struct RemoveDuplicatesAPI<Range, T*>
+{
+ typedef typename Range::const_iterator const_iterator;
+ typedef T* value_type;
+
+ static bool lessThan(value_type a, value_type b) { return a < b; }
+ static value_type uniqueValue(const_iterator a) { return *a; }
+ template <typename It>
+ static bool valueCompare(It it, const_iterator it2)
+ {
+ return *it != *it2;
+ }
+};
+}
+
+template <typename Range>
+typename Range::const_iterator cmRemoveDuplicates(Range& r)
+{
+ typedef typename ContainerAlgorithms::RemoveDuplicatesAPI<Range> API;
+ typedef typename API::value_type T;
+ std::vector<T> unique;
+ unique.reserve(r.size());
+ 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::vector<T>::iterator low = std::lower_bound(
+ unique.begin(), unique.end(), API::uniqueValue(it), API::lessThan);
+ if (low == unique.end() || API::valueCompare(low, it)) {
+ unique.insert(low, API::uniqueValue(it));
+ } else {
+ indices.push_back(count);
+ }
+ }
+ if (indices.empty()) {
+ return end;
+ }
+ return cmRemoveIndices(r, indices);
+}
+
+template <typename Range>
+std::string cmWrap(std::string prefix, Range const& r, std::string suffix,
+ std::string sep)
+{
+ if (r.empty()) {
+ return std::string();
+ }
+ return prefix + cmJoin(r, (suffix + sep + prefix).c_str()) + suffix;
+}
+
+template <typename Range>
+std::string cmWrap(char prefix, Range const& r, char suffix, std::string sep)
+{
+ return cmWrap(std::string(1, prefix), r, std::string(1, suffix), sep);
+}
+
+template <typename Range, typename T>
+typename Range::const_iterator cmFindNot(Range const& r, T const& t)
+{
+ return std::find_if(r.begin(), r.end(),
+ std::bind1st(std::not_equal_to<T>(), 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)
+{
+ return std::reverse_iterator<Iter>(it);
+}
+
+inline bool cmHasSuffix(const std::string& str, const std::string& suffix)
+{
+ if (str.size() < suffix.size()) {
+ return false;
+ }
+ return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
+}
+
+inline void cmStripSuffixIfExists(std::string& str, const std::string& suffix)
+{
+ if (cmHasSuffix(str, suffix)) {
+ str.resize(str.size() - suffix.size());
+ }
+}
+
+#endif
diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx
new file mode 100644
index 0000000..ceb7d31
--- /dev/null
+++ b/Source/cmArchiveWrite.cxx
@@ -0,0 +1,340 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2010 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmArchiveWrite.h"
+
+#include "cmLocale.h"
+#include "cmSystemTools.h"
+#include "cm_get_date.h"
+#include <cm_libarchive.h>
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+
+#ifndef __LA_SSIZE_T
+#define __LA_SSIZE_T la_ssize_t
+#endif
+
+static std::string cm_archive_error_string(struct archive* a)
+{
+ const char* e = archive_error_string(a);
+ return e ? e : "unknown error";
+}
+
+static void cm_archive_entry_copy_pathname(struct archive_entry* e,
+ const std::string& dest)
+{
+#if cmsys_STL_HAS_WSTRING
+ archive_entry_copy_pathname_w(e, cmsys::Encoding::ToWide(dest).c_str());
+#else
+ archive_entry_copy_pathname(e, dest.c_str());
+#endif
+}
+
+static void cm_archive_entry_copy_sourcepath(struct archive_entry* e,
+ const std::string& file)
+{
+#if cmsys_STL_HAS_WSTRING
+ archive_entry_copy_sourcepath_w(e, cmsys::Encoding::ToWide(file).c_str());
+#else
+ archive_entry_copy_sourcepath(e, file.c_str());
+#endif
+}
+
+class cmArchiveWrite::Entry
+{
+ struct archive_entry* Object;
+
+public:
+ Entry()
+ : Object(archive_entry_new())
+ {
+ }
+ ~Entry() { archive_entry_free(this->Object); }
+ operator struct archive_entry*() { return this->Object; }
+};
+
+struct cmArchiveWrite::Callback
+{
+ // archive_write_callback
+ static __LA_SSIZE_T Write(struct archive*, void* cd, const void* b, size_t n)
+ {
+ cmArchiveWrite* self = static_cast<cmArchiveWrite*>(cd);
+ if (self->Stream.write(static_cast<const char*>(b),
+ static_cast<std::streamsize>(n))) {
+ return static_cast<__LA_SSIZE_T>(n);
+ } else {
+ return static_cast<__LA_SSIZE_T>(-1);
+ }
+ }
+};
+
+cmArchiveWrite::cmArchiveWrite(std::ostream& os, Compress c,
+ std::string const& format)
+ : Stream(os)
+ , Archive(archive_write_new())
+ , Disk(archive_read_disk_new())
+ , Verbose(false)
+ , Format(format)
+{
+ switch (c) {
+ case CompressNone:
+ if (archive_write_add_filter_none(this->Archive) != ARCHIVE_OK) {
+ this->Error = "archive_write_add_filter_none: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return;
+ }
+ break;
+ case CompressCompress:
+ if (archive_write_add_filter_compress(this->Archive) != ARCHIVE_OK) {
+ this->Error = "archive_write_add_filter_compress: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return;
+ }
+ break;
+ case CompressGZip:
+ if (archive_write_add_filter_gzip(this->Archive) != ARCHIVE_OK) {
+ this->Error = "archive_write_add_filter_gzip: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return;
+ }
+ break;
+ case CompressBZip2:
+ if (archive_write_add_filter_bzip2(this->Archive) != ARCHIVE_OK) {
+ this->Error = "archive_write_add_filter_bzip2: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return;
+ }
+ break;
+ case CompressLZMA:
+ if (archive_write_add_filter_lzma(this->Archive) != ARCHIVE_OK) {
+ this->Error = "archive_write_add_filter_lzma: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return;
+ }
+ break;
+ case CompressXZ:
+ if (archive_write_add_filter_xz(this->Archive) != ARCHIVE_OK) {
+ this->Error = "archive_write_add_filter_xz: ";
+ 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) {
+ this->Error = "archive_read_disk_set_standard_lookup: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return;
+ }
+#endif
+
+ if (archive_write_set_format_by_name(this->Archive, format.c_str()) !=
+ ARCHIVE_OK) {
+ this->Error = "archive_write_set_format_by_name: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return;
+ }
+
+ // do not pad the last block!!
+ if (archive_write_set_bytes_in_last_block(this->Archive, 1)) {
+ this->Error = "archive_write_set_bytes_in_last_block: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return;
+ }
+
+ if (archive_write_open(
+ this->Archive, this, CM_NULLPTR,
+ reinterpret_cast<archive_write_callback*>(&Callback::Write),
+ CM_NULLPTR) != ARCHIVE_OK) {
+ this->Error = "archive_write_open: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return;
+ }
+}
+
+cmArchiveWrite::~cmArchiveWrite()
+{
+ archive_read_free(this->Disk);
+ archive_write_free(this->Archive);
+}
+
+bool cmArchiveWrite::Add(std::string path, size_t skip, const char* prefix,
+ bool recursive)
+{
+ if (this->Okay()) {
+ if (!path.empty() && path[path.size() - 1] == '/') {
+ path.erase(path.size() - 1);
+ }
+ this->AddPath(path.c_str(), skip, prefix, recursive);
+ }
+ return this->Okay();
+}
+
+bool cmArchiveWrite::AddPath(const char* path, size_t skip, const char* prefix,
+ bool recursive)
+{
+ if (!this->AddFile(path, skip, prefix)) {
+ return false;
+ }
+ if ((!cmSystemTools::FileIsDirectory(path) || !recursive) ||
+ cmSystemTools::FileIsSymlink(path)) {
+ return true;
+ }
+ cmsys::Directory d;
+ if (d.Load(path)) {
+ std::string next = path;
+ next += "/";
+ std::string::size_type end = next.size();
+ unsigned long n = d.GetNumberOfFiles();
+ for (unsigned long i = 0; i < n; ++i) {
+ const char* file = d.GetFile(i);
+ if (strcmp(file, ".") != 0 && strcmp(file, "..") != 0) {
+ next.erase(end);
+ next += file;
+ if (!this->AddPath(next.c_str(), skip, prefix)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool cmArchiveWrite::AddFile(const char* file, size_t skip, const char* prefix)
+{
+ // 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)) {
+ return true;
+ }
+ const char* out = file + skip;
+
+ cmLocaleRAII localeRAII;
+ static_cast<void>(localeRAII);
+
+ // Meta-data.
+ std::string dest = prefix ? prefix : "";
+ dest += out;
+ if (this->Verbose) {
+ std::cout << dest << "\n";
+ }
+ Entry e;
+ cm_archive_entry_copy_sourcepath(e, file);
+ cm_archive_entry_copy_pathname(e, dest);
+ if (archive_read_disk_entry_from_file(this->Disk, e, -1, CM_NULLPTR) !=
+ ARCHIVE_OK) {
+ this->Error = "archive_read_disk_entry_from_file '";
+ this->Error += file;
+ this->Error += "': ";
+ this->Error += cm_archive_error_string(this->Disk);
+ return false;
+ }
+ if (!this->MTime.empty()) {
+ time_t now;
+ time(&now);
+ time_t t = cm_get_date(now, this->MTime.c_str());
+ if (t == -1) {
+ this->Error = "unable to parse mtime '";
+ this->Error += this->MTime;
+ this->Error += "'";
+ return false;
+ }
+ archive_entry_set_mtime(e, t, 0);
+ }
+
+ // manages the uid/guid of the entry (if any)
+ if (this->Uid.IsSet() && this->Gid.IsSet()) {
+ archive_entry_set_uid(e, this->Uid.Get());
+ archive_entry_set_gid(e, this->Gid.Get());
+ }
+
+ if (!this->Uname.empty() && !this->Gname.empty()) {
+ archive_entry_set_uname(e, this->Uname.c_str());
+ archive_entry_set_gname(e, this->Gname.c_str());
+ }
+
+ // manages the permissions
+ if (this->Permissions.IsSet()) {
+ archive_entry_set_perm(e, this->Permissions.Get());
+ }
+
+ if (this->PermissionsMask.IsSet()) {
+ mode_t perm = archive_entry_perm(e);
+ archive_entry_set_perm(e, perm & this->PermissionsMask.Get());
+ }
+
+ // Clear acl and xattr fields not useful for distribution.
+ archive_entry_acl_clear(e);
+ archive_entry_xattr_clear(e);
+ archive_entry_set_fflags(e, 0, 0);
+
+ if (this->Format == "pax" || this->Format == "paxr") {
+ // Sparse files are a GNU tar extension.
+ // Do not use them in standard tar files.
+ archive_entry_sparse_clear(e);
+ }
+
+ if (archive_write_header(this->Archive, e) != ARCHIVE_OK) {
+ this->Error = "archive_write_header: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return false;
+ }
+
+ // do not copy content of symlink
+ if (!archive_entry_symlink(e)) {
+ // Content.
+ if (size_t size = static_cast<size_t>(archive_entry_size(e))) {
+ return this->AddData(file, size);
+ }
+ }
+ return true;
+}
+
+bool cmArchiveWrite::AddData(const char* file, size_t size)
+{
+ cmsys::ifstream fin(file, std::ios::in | std::ios::binary);
+ if (!fin) {
+ this->Error = "Error opening \"";
+ this->Error += file;
+ this->Error += "\": ";
+ this->Error += cmSystemTools::GetLastSystemError();
+ return false;
+ }
+
+ char buffer[16384];
+ size_t nleft = size;
+ while (nleft > 0) {
+ typedef std::streamsize ssize_type;
+ size_t const nnext = nleft > sizeof(buffer) ? sizeof(buffer) : nleft;
+ ssize_type const nnext_s = static_cast<ssize_type>(nnext);
+ fin.read(buffer, nnext_s);
+ // Some stream libraries (older HPUX) return failure at end of
+ // file on the last read even if some data were read. Check
+ // gcount instead of trusting the stream error status.
+ if (static_cast<size_t>(fin.gcount()) != nnext) {
+ break;
+ }
+ if (archive_write_data(this->Archive, buffer, nnext) != nnext_s) {
+ this->Error = "archive_write_data: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return false;
+ }
+ nleft -= nnext;
+ }
+ if (nleft > 0) {
+ this->Error = "Error reading \"";
+ this->Error += file;
+ this->Error += "\": ";
+ this->Error += cmSystemTools::GetLastSystemError();
+ return false;
+ }
+ return true;
+}
diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h
new file mode 100644
index 0000000..f847d09
--- /dev/null
+++ b/Source/cmArchiveWrite.h
@@ -0,0 +1,184 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2010 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmArchiveWrite_h
+#define cmArchiveWrite_h
+
+#include "cmStandardIncludes.h"
+
+#if !defined(CMAKE_BUILD_WITH_CMAKE)
+#error "cmArchiveWrite not allowed during bootstrap build!"
+#endif
+
+template <typename T>
+class cmArchiveWriteOptional
+{
+public:
+ cmArchiveWriteOptional() { this->Clear(); }
+ explicit cmArchiveWriteOptional(T val) { this->Set(val); }
+
+ void Set(T val)
+ {
+ this->IsValueSet = true;
+ this->Value = val;
+ }
+ void Clear() { this->IsValueSet = false; }
+ bool IsSet() const { return this->IsValueSet; }
+ T Get() const { return Value; }
+private:
+ T Value;
+ bool IsValueSet;
+};
+
+/** \class cmArchiveWrite
+ * \brief Wrapper around libarchive for writing.
+ *
+ */
+class cmArchiveWrite
+{
+ typedef void (cmArchiveWrite::*safe_bool)();
+ void safe_bool_true() {}
+public:
+ /** Compression type. */
+ enum Compress
+ {
+ CompressNone,
+ CompressCompress,
+ CompressGZip,
+ CompressBZip2,
+ CompressLZMA,
+ CompressXZ
+ };
+
+ /** Construct with output stream to which to write archive. */
+ cmArchiveWrite(std::ostream& os, Compress c = CompressNone,
+ std::string const& format = "paxr");
+
+ ~cmArchiveWrite();
+
+ /**
+ * Add a path (file or directory) to the archive. Directories are
+ * added recursively. The "path" must be readable on disk, either
+ * full path or relative to current working directory. The "skip"
+ * value indicates how many leading bytes from the input path to
+ * skip. The remaining part of the input path is appended to the
+ * "prefix" value to construct the final name in the archive.
+ */
+ bool Add(std::string path, size_t skip = 0, const char* prefix = CM_NULLPTR,
+ bool recursive = true);
+
+ /** Returns true if there has been no error. */
+ operator safe_bool() const
+ {
+ return this->Okay() ? &cmArchiveWrite::safe_bool_true : CM_NULLPTR;
+ }
+
+ /** Returns true if there has been an error. */
+ bool operator!() const { return !this->Okay(); }
+
+ /** Return the error string; empty if none. */
+ std::string GetError() const { return this->Error; }
+
+ // TODO: More general callback instead of hard-coding calls to
+ // std::cout.
+ void SetVerbose(bool v) { this->Verbose = v; }
+
+ void SetMTime(std::string const& t) { this->MTime = t; }
+
+ //! Sets the permissions of the added files/folders
+ void SetPermissions(mode_t permissions_)
+ {
+ this->Permissions.Set(permissions_);
+ }
+
+ //! Clears permissions - default is used instead
+ void ClearPermissions() { this->Permissions.Clear(); }
+
+ //! Sets the permissions mask of files/folders
+ //!
+ //! The permissions will be copied from the existing file
+ //! or folder. The mask will then be applied to unset
+ //! some of them
+ void SetPermissionsMask(mode_t permissionsMask_)
+ {
+ this->PermissionsMask.Set(permissionsMask_);
+ }
+
+ //! Clears permissions mask - default is used instead
+ void ClearPermissionsMask() { this->PermissionsMask.Clear(); }
+
+ //! Sets UID and GID to be used in the tar file
+ void SetUIDAndGID(int uid_, int gid_)
+ {
+ this->Uid.Set(uid_);
+ this->Gid.Set(gid_);
+ }
+
+ //! Clears UID and GID to be used in the tar file - default is used instead
+ void ClearUIDAndGID()
+ {
+ this->Uid.Clear();
+ this->Gid.Clear();
+ }
+
+ //! Sets UNAME and GNAME to be used in the tar file
+ void SetUNAMEAndGNAME(const std::string& uname_, const std::string& gname_)
+ {
+ this->Uname = uname_;
+ this->Gname = gname_;
+ }
+
+ //! Clears UNAME and GNAME to be used in the tar file
+ //! default is used instead
+ void ClearUNAMEAndGNAME()
+ {
+ this->Uname = "";
+ this->Gname = "";
+ }
+
+private:
+ bool Okay() const { return this->Error.empty(); }
+ bool AddPath(const char* path, size_t skip, const char* prefix,
+ bool recursive = true);
+ bool AddFile(const char* file, size_t skip, const char* prefix);
+ bool AddData(const char* file, size_t size);
+
+ struct Callback;
+ friend struct Callback;
+
+ class Entry;
+
+ std::ostream& Stream;
+ struct archive* Archive;
+ struct archive* Disk;
+ bool Verbose;
+ std::string Format;
+ std::string Error;
+ std::string MTime;
+
+ //! UID of the user in the tar file
+ cmArchiveWriteOptional<int> Uid;
+
+ //! GUID of the user in the tar file
+ cmArchiveWriteOptional<int> Gid;
+
+ //! UNAME/GNAME of the user (does not override UID/GID)
+ //!@{
+ std::string Uname;
+ std::string Gname;
+ //!@}
+
+ //! Permissions on files/folders
+ cmArchiveWriteOptional<mode_t> Permissions;
+ cmArchiveWriteOptional<mode_t> PermissionsMask;
+};
+
+#endif
diff --git a/Source/cmAuxSourceDirectoryCommand.cxx b/Source/cmAuxSourceDirectoryCommand.cxx
new file mode 100644
index 0000000..78f67a4
--- /dev/null
+++ b/Source/cmAuxSourceDirectoryCommand.cxx
@@ -0,0 +1,77 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmAuxSourceDirectoryCommand.h"
+
+#include "cmSourceFile.h"
+
+#include <cmsys/Directory.hxx>
+
+// cmAuxSourceDirectoryCommand
+bool cmAuxSourceDirectoryCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 2 || args.size() > 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string sourceListValue;
+ std::string templateDirectory = args[0];
+ std::string tdir;
+ if (!cmSystemTools::FileIsFullPath(templateDirectory.c_str())) {
+ tdir = this->Makefile->GetCurrentSourceDirectory();
+ tdir += "/";
+ tdir += templateDirectory;
+ } else {
+ tdir = templateDirectory;
+ }
+
+ // was the list already populated
+ const char* def = this->Makefile->GetDefinition(args[1]);
+ if (def) {
+ sourceListValue = def;
+ }
+
+ // Load all the files in the directory
+ cmsys::Directory dir;
+ if (dir.Load(tdir.c_str())) {
+ size_t numfiles = dir.GetNumberOfFiles();
+ for (size_t i = 0; i < numfiles; ++i) {
+ std::string file = dir.GetFile(static_cast<unsigned long>(i));
+ // Split the filename into base and extension
+ std::string::size_type dotpos = file.rfind(".");
+ if (dotpos != std::string::npos) {
+ std::string ext = file.substr(dotpos + 1);
+ std::string base = file.substr(0, dotpos);
+ // Process only source files
+ std::vector<std::string> srcExts =
+ this->Makefile->GetCMakeInstance()->GetSourceExtensions();
+ if (!base.empty() &&
+ std::find(srcExts.begin(), srcExts.end(), ext) != srcExts.end()) {
+ std::string fullname = templateDirectory;
+ fullname += "/";
+ fullname += file;
+ // add the file as a class file so
+ // depends can be done
+ cmSourceFile* sf = this->Makefile->GetOrCreateSource(fullname);
+ sf->SetProperty("ABSTRACT", "0");
+ if (!sourceListValue.empty()) {
+ sourceListValue += ";";
+ }
+ sourceListValue += fullname;
+ }
+ }
+ }
+ }
+ this->Makefile->AddDefinition(args[1], sourceListValue.c_str());
+ return true;
+}
diff --git a/Source/cmAuxSourceDirectoryCommand.h b/Source/cmAuxSourceDirectoryCommand.h
new file mode 100644
index 0000000..6301cb2
--- /dev/null
+++ b/Source/cmAuxSourceDirectoryCommand.h
@@ -0,0 +1,49 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmAuxSourceDirectoryCommand_h
+#define cmAuxSourceDirectoryCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmAuxSourceDirectoryCommand
+ * \brief Specify auxiliary source code directories.
+ *
+ * cmAuxSourceDirectoryCommand specifies source code directories
+ * that must be built as part of this build process. This directories
+ * are not recursively processed like the SUBDIR command (cmSubdirCommand).
+ * A side effect of this command is to create a subdirectory in the build
+ * directory structure.
+ */
+class cmAuxSourceDirectoryCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmAuxSourceDirectoryCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "aux_source_directory"; }
+
+ cmTypeMacro(cmAuxSourceDirectoryCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmBootstrapCommands1.cxx b/Source/cmBootstrapCommands1.cxx
new file mode 100644
index 0000000..2de8770
--- /dev/null
+++ b/Source/cmBootstrapCommands1.cxx
@@ -0,0 +1,96 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+// This file is used to compile all the commands
+// that CMake knows about at compile time.
+// This is sort of a boot strapping approach since you would
+// like to have CMake to build CMake.
+#include "cmAddCustomCommandCommand.cxx"
+#include "cmAddCustomTargetCommand.cxx"
+#include "cmAddDefinitionsCommand.cxx"
+#include "cmAddDependenciesCommand.cxx"
+#include "cmAddExecutableCommand.cxx"
+#include "cmAddLibraryCommand.cxx"
+#include "cmAddSubDirectoryCommand.cxx"
+#include "cmAddTestCommand.cxx"
+#include "cmBreakCommand.cxx"
+#include "cmBuildCommand.cxx"
+#include "cmCMakeMinimumRequired.cxx"
+#include "cmCMakePolicyCommand.cxx"
+#include "cmCommandArgumentsHelper.cxx"
+#include "cmCommands.h"
+#include "cmConfigureFileCommand.cxx"
+#include "cmContinueCommand.cxx"
+#include "cmCoreTryCompile.cxx"
+#include "cmCreateTestSourceList.cxx"
+#include "cmDefinePropertyCommand.cxx"
+#include "cmElseCommand.cxx"
+#include "cmEnableLanguageCommand.cxx"
+#include "cmEnableTestingCommand.cxx"
+#include "cmEndForEachCommand.cxx"
+#include "cmEndFunctionCommand.cxx"
+#include "cmEndIfCommand.cxx"
+#include "cmEndMacroCommand.cxx"
+#include "cmEndWhileCommand.cxx"
+#include "cmExecProgramCommand.cxx"
+#include "cmExecuteProcessCommand.cxx"
+#include "cmFileCommand.cxx"
+#include "cmFindBase.cxx"
+#include "cmFindCommon.cxx"
+#include "cmFindFileCommand.cxx"
+#include "cmFindLibraryCommand.cxx"
+#include "cmFindPackageCommand.cxx"
+#include "cmFindPathCommand.cxx"
+#include "cmFindProgramCommand.cxx"
+#include "cmForEachCommand.cxx"
+#include "cmFunctionCommand.cxx"
+#include "cmParseArgumentsCommand.cxx"
+#include "cmPathLabel.cxx"
+#include "cmSearchPath.cxx"
+
+void GetBootstrapCommands1(std::vector<cmCommand*>& commands)
+{
+ commands.push_back(new cmAddCustomCommandCommand);
+ commands.push_back(new cmAddCustomTargetCommand);
+ commands.push_back(new cmAddDefinitionsCommand);
+ commands.push_back(new cmAddDependenciesCommand);
+ commands.push_back(new cmAddExecutableCommand);
+ commands.push_back(new cmAddLibraryCommand);
+ commands.push_back(new cmAddSubDirectoryCommand);
+ commands.push_back(new cmAddTestCommand);
+ commands.push_back(new cmBreakCommand);
+ commands.push_back(new cmBuildCommand);
+ commands.push_back(new cmCMakeMinimumRequired);
+ commands.push_back(new cmCMakePolicyCommand);
+ commands.push_back(new cmConfigureFileCommand);
+ commands.push_back(new cmContinueCommand);
+ commands.push_back(new cmCreateTestSourceList);
+ commands.push_back(new cmDefinePropertyCommand);
+ commands.push_back(new cmElseCommand);
+ commands.push_back(new cmEnableLanguageCommand);
+ commands.push_back(new cmEnableTestingCommand);
+ commands.push_back(new cmEndForEachCommand);
+ commands.push_back(new cmEndFunctionCommand);
+ commands.push_back(new cmEndIfCommand);
+ commands.push_back(new cmEndMacroCommand);
+ commands.push_back(new cmEndWhileCommand);
+ commands.push_back(new cmExecProgramCommand);
+ commands.push_back(new cmExecuteProcessCommand);
+ commands.push_back(new cmFileCommand);
+ commands.push_back(new cmFindFileCommand);
+ commands.push_back(new cmFindLibraryCommand);
+ commands.push_back(new cmFindPackageCommand);
+ commands.push_back(new cmFindPathCommand);
+ commands.push_back(new cmFindProgramCommand);
+ commands.push_back(new cmForEachCommand);
+ commands.push_back(new cmFunctionCommand);
+ commands.push_back(new cmParseArgumentsCommand);
+}
diff --git a/Source/cmBootstrapCommands2.cxx b/Source/cmBootstrapCommands2.cxx
new file mode 100644
index 0000000..38d008d
--- /dev/null
+++ b/Source/cmBootstrapCommands2.cxx
@@ -0,0 +1,103 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+// This file is used to compile all the commands
+// that CMake knows about at compile time.
+// This is sort of a boot strapping approach since you would
+// like to have CMake to build CMake.
+#include "cmCommands.h"
+#include "cmConditionEvaluator.cxx"
+#include "cmExpandedCommandArgument.cxx"
+#include "cmGetCMakePropertyCommand.cxx"
+#include "cmGetDirectoryPropertyCommand.cxx"
+#include "cmGetFilenameComponentCommand.cxx"
+#include "cmGetPropertyCommand.cxx"
+#include "cmGetSourceFilePropertyCommand.cxx"
+#include "cmGetTargetPropertyCommand.cxx"
+#include "cmGetTestPropertyCommand.cxx"
+#include "cmHexFileConverter.cxx"
+#include "cmIfCommand.cxx"
+#include "cmIncludeCommand.cxx"
+#include "cmIncludeDirectoryCommand.cxx"
+#include "cmIncludeRegularExpressionCommand.cxx"
+#include "cmInstallCommand.cxx"
+#include "cmInstallCommandArguments.cxx"
+#include "cmInstallFilesCommand.cxx"
+#include "cmInstallTargetsCommand.cxx"
+#include "cmLinkDirectoriesCommand.cxx"
+#include "cmListCommand.cxx"
+#include "cmMacroCommand.cxx"
+#include "cmMakeDirectoryCommand.cxx"
+#include "cmMarkAsAdvancedCommand.cxx"
+#include "cmMathCommand.cxx"
+#include "cmMessageCommand.cxx"
+#include "cmOptionCommand.cxx"
+#include "cmProjectCommand.cxx"
+#include "cmReturnCommand.cxx"
+#include "cmSeparateArgumentsCommand.cxx"
+#include "cmSetCommand.cxx"
+#include "cmSetDirectoryPropertiesCommand.cxx"
+#include "cmSetPropertyCommand.cxx"
+#include "cmSetSourceFilesPropertiesCommand.cxx"
+#include "cmSetTargetPropertiesCommand.cxx"
+#include "cmSetTestsPropertiesCommand.cxx"
+#include "cmSiteNameCommand.cxx"
+#include "cmStringCommand.cxx"
+#include "cmSubdirCommand.cxx"
+#include "cmTargetLinkLibrariesCommand.cxx"
+#include "cmTimestamp.cxx"
+#include "cmTryCompileCommand.cxx"
+#include "cmTryRunCommand.cxx"
+#include "cmUnsetCommand.cxx"
+#include "cmWhileCommand.cxx"
+
+void GetBootstrapCommands2(std::vector<cmCommand*>& commands)
+{
+ commands.push_back(new cmGetCMakePropertyCommand);
+ commands.push_back(new cmGetDirectoryPropertyCommand);
+ commands.push_back(new cmGetFilenameComponentCommand);
+ commands.push_back(new cmGetPropertyCommand);
+ commands.push_back(new cmGetSourceFilePropertyCommand);
+ commands.push_back(new cmGetTargetPropertyCommand);
+ commands.push_back(new cmIfCommand);
+ commands.push_back(new cmIncludeCommand);
+ commands.push_back(new cmIncludeDirectoryCommand);
+ commands.push_back(new cmIncludeRegularExpressionCommand);
+ commands.push_back(new cmInstallCommand);
+ commands.push_back(new cmInstallFilesCommand);
+ commands.push_back(new cmInstallTargetsCommand);
+ commands.push_back(new cmLinkDirectoriesCommand);
+ commands.push_back(new cmListCommand);
+ commands.push_back(new cmMacroCommand);
+ commands.push_back(new cmMakeDirectoryCommand);
+ commands.push_back(new cmMarkAsAdvancedCommand);
+ commands.push_back(new cmMathCommand);
+ commands.push_back(new cmMessageCommand);
+ commands.push_back(new cmOptionCommand);
+ commands.push_back(new cmProjectCommand);
+ commands.push_back(new cmReturnCommand);
+ commands.push_back(new cmSeparateArgumentsCommand);
+ commands.push_back(new cmSetCommand);
+ commands.push_back(new cmSetDirectoryPropertiesCommand);
+ commands.push_back(new cmSetPropertyCommand);
+ commands.push_back(new cmSetSourceFilesPropertiesCommand);
+ commands.push_back(new cmSetTargetPropertiesCommand);
+ commands.push_back(new cmGetTestPropertyCommand);
+ commands.push_back(new cmSetTestsPropertiesCommand);
+ commands.push_back(new cmSiteNameCommand);
+ commands.push_back(new cmStringCommand);
+ commands.push_back(new cmSubdirCommand);
+ commands.push_back(new cmTargetLinkLibrariesCommand);
+ commands.push_back(new cmTryCompileCommand);
+ commands.push_back(new cmTryRunCommand);
+ commands.push_back(new cmUnsetCommand);
+ commands.push_back(new cmWhileCommand);
+}
diff --git a/Source/cmBreakCommand.cxx b/Source/cmBreakCommand.cxx
new file mode 100644
index 0000000..fd57705
--- /dev/null
+++ b/Source/cmBreakCommand.cxx
@@ -0,0 +1,76 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmBreakCommand.h"
+
+// cmBreakCommand
+bool cmBreakCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (!this->Makefile->IsLoopBlock()) {
+ bool issueMessage = true;
+ std::ostringstream e;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0055)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0055) << "\n";
+ break;
+ case cmPolicies::OLD:
+ issueMessage = false;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ messageType = cmake::FATAL_ERROR;
+ break;
+ }
+
+ if (issueMessage) {
+ e << "A BREAK command was found outside of a proper "
+ "FOREACH or WHILE loop scope.";
+ this->Makefile->IssueMessage(messageType, e.str());
+ if (messageType == cmake::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+
+ status.SetBreakInvoked(true);
+
+ if (!args.empty()) {
+ bool issueMessage = true;
+ std::ostringstream e;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0055)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0055) << "\n";
+ break;
+ case cmPolicies::OLD:
+ issueMessage = false;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ messageType = cmake::FATAL_ERROR;
+ break;
+ }
+
+ if (issueMessage) {
+ e << "The BREAK command does not accept any arguments.";
+ this->Makefile->IssueMessage(messageType, e.str());
+ if (messageType == cmake::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/Source/cmBreakCommand.h b/Source/cmBreakCommand.h
new file mode 100644
index 0000000..3b585e2
--- /dev/null
+++ b/Source/cmBreakCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmBreakCommand_h
+#define cmBreakCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmBreakCommand
+ * \brief Break from an enclosing foreach or while loop
+ *
+ * cmBreakCommand returns from an enclosing foreach or while loop
+ */
+class cmBreakCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmBreakCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "break"; }
+
+ cmTypeMacro(cmBreakCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmBuildCommand.cxx b/Source/cmBuildCommand.cxx
new file mode 100644
index 0000000..fb143a2
--- /dev/null
+++ b/Source/cmBuildCommand.cxx
@@ -0,0 +1,129 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmBuildCommand.h"
+
+#include "cmGlobalGenerator.h"
+
+bool cmBuildCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ // Support the legacy signature of the command:
+ //
+ if (2 == args.size()) {
+ return this->TwoArgsSignature(args);
+ }
+
+ return this->MainSignature(args);
+}
+
+bool cmBuildCommand::MainSignature(std::vector<std::string> const& args)
+{
+ if (args.size() < 1) {
+ this->SetError("requires at least one argument naming a CMake variable");
+ return false;
+ }
+
+ // The cmake variable in which to store the result.
+ const char* variable = args[0].c_str();
+
+ // Parse remaining arguments.
+ const char* configuration = CM_NULLPTR;
+ const char* project_name = CM_NULLPTR;
+ std::string target;
+ enum Doing
+ {
+ DoingNone,
+ DoingConfiguration,
+ DoingProjectName,
+ DoingTarget
+ };
+ Doing doing = DoingNone;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "CONFIGURATION") {
+ doing = DoingConfiguration;
+ } else if (args[i] == "PROJECT_NAME") {
+ doing = DoingProjectName;
+ } else if (args[i] == "TARGET") {
+ doing = DoingTarget;
+ } else if (doing == DoingConfiguration) {
+ doing = DoingNone;
+ configuration = args[i].c_str();
+ } else if (doing == DoingProjectName) {
+ doing = DoingNone;
+ project_name = args[i].c_str();
+ } else if (doing == DoingTarget) {
+ doing = DoingNone;
+ target = args[i];
+ } else {
+ std::ostringstream e;
+ e << "unknown argument \"" << args[i] << "\"";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ // If null/empty CONFIGURATION argument, cmake --build uses 'Debug'
+ // in the currently implemented multi-configuration global generators...
+ // so we put this code here to end up with the same default configuration
+ // as the original 2-arg build_command signature:
+ //
+ if (!configuration || !*configuration) {
+ configuration = getenv("CMAKE_CONFIG_TYPE");
+ }
+ if (!configuration || !*configuration) {
+ configuration = "Release";
+ }
+
+ if (project_name && *project_name) {
+ this->Makefile->IssueMessage(
+ cmake::AUTHOR_WARNING,
+ "Ignoring PROJECT_NAME option because it has no effect.");
+ }
+
+ std::string makecommand =
+ this->Makefile->GetGlobalGenerator()->GenerateCMakeBuildCommand(
+ target, configuration, "", this->Makefile->IgnoreErrorsCMP0061());
+
+ this->Makefile->AddDefinition(variable, makecommand.c_str());
+
+ return true;
+}
+
+bool cmBuildCommand::TwoArgsSignature(std::vector<std::string> const& args)
+{
+ if (args.size() < 2) {
+ this->SetError("called with less than two arguments");
+ return false;
+ }
+
+ const char* define = args[0].c_str();
+ const char* cacheValue = this->Makefile->GetDefinition(define);
+
+ std::string configType = "Release";
+ const char* cfg = getenv("CMAKE_CONFIG_TYPE");
+ if (cfg && *cfg) {
+ configType = cfg;
+ }
+
+ std::string makecommand =
+ this->Makefile->GetGlobalGenerator()->GenerateCMakeBuildCommand(
+ "", configType, "", this->Makefile->IgnoreErrorsCMP0061());
+
+ if (cacheValue) {
+ return true;
+ }
+ this->Makefile->AddCacheDefinition(define, makecommand.c_str(),
+ "Command used to build entire project "
+ "from the command line.",
+ cmState::STRING);
+ return true;
+}
diff --git a/Source/cmBuildCommand.h b/Source/cmBuildCommand.h
new file mode 100644
index 0000000..552e5ff
--- /dev/null
+++ b/Source/cmBuildCommand.h
@@ -0,0 +1,58 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmBuildCommand_h
+#define cmBuildCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmBuildCommand
+ * \brief build_command command
+ *
+ * cmBuildCommand implements the build_command CMake command
+ */
+class cmBuildCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmBuildCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The primary command signature with optional, KEYWORD-based args.
+ */
+ virtual bool MainSignature(std::vector<std::string> const& args);
+
+ /**
+ * Legacy "exactly 2 args required" signature.
+ */
+ virtual bool TwoArgsSignature(std::vector<std::string> const& args);
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "build_command"; }
+
+ cmTypeMacro(cmBuildCommand, cmCommand);
+
+private:
+ bool IgnoreErrors() const;
+};
+
+#endif
diff --git a/Source/cmBuildNameCommand.cxx b/Source/cmBuildNameCommand.cxx
new file mode 100644
index 0000000..27234d7
--- /dev/null
+++ b/Source/cmBuildNameCommand.cxx
@@ -0,0 +1,67 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmBuildNameCommand.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+// cmBuildNameCommand
+bool cmBuildNameCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (this->Disallowed(
+ cmPolicies::CMP0036,
+ "The build_name command should not be called; see CMP0036.")) {
+ return true;
+ }
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ const char* cacheValue = this->Makefile->GetDefinition(args[0]);
+ if (cacheValue) {
+ // do we need to correct the value?
+ cmsys::RegularExpression reg("[()/]");
+ if (reg.find(cacheValue)) {
+ std::string cv = cacheValue;
+ std::replace(cv.begin(), cv.end(), '/', '_');
+ std::replace(cv.begin(), cv.end(), '(', '_');
+ std::replace(cv.begin(), cv.end(), ')', '_');
+ this->Makefile->AddCacheDefinition(args[0], cv.c_str(), "Name of build.",
+ cmState::STRING);
+ }
+ return true;
+ }
+
+ std::string buildname = "WinNT";
+ if (this->Makefile->GetDefinition("UNIX")) {
+ buildname = "";
+ cmSystemTools::RunSingleCommand("uname -a", &buildname, &buildname);
+ if (!buildname.empty()) {
+ std::string RegExp = "([^ ]*) [^ ]* ([^ ]*) ";
+ cmsys::RegularExpression reg(RegExp.c_str());
+ if (reg.find(buildname.c_str())) {
+ buildname = reg.match(1) + "-" + reg.match(2);
+ }
+ }
+ }
+ std::string compiler = "${CMAKE_CXX_COMPILER}";
+ this->Makefile->ExpandVariablesInString(compiler);
+ buildname += "-";
+ buildname += cmSystemTools::GetFilenameName(compiler);
+ std::replace(buildname.begin(), buildname.end(), '/', '_');
+ std::replace(buildname.begin(), buildname.end(), '(', '_');
+ std::replace(buildname.begin(), buildname.end(), ')', '_');
+
+ this->Makefile->AddCacheDefinition(args[0], buildname.c_str(),
+ "Name of build.", cmState::STRING);
+ return true;
+}
diff --git a/Source/cmBuildNameCommand.h b/Source/cmBuildNameCommand.h
new file mode 100644
index 0000000..4a1641bd
--- /dev/null
+++ b/Source/cmBuildNameCommand.h
@@ -0,0 +1,28 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmBuildNameCommand_h
+#define cmBuildNameCommand_h
+
+#include "cmCommand.h"
+
+class cmBuildNameCommand : public cmCommand
+{
+public:
+ cmTypeMacro(cmBuildNameCommand, cmCommand);
+ cmCommand* Clone() CM_OVERRIDE { return new cmBuildNameCommand; }
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+ std::string GetName() const CM_OVERRIDE { return "build_name"; }
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+};
+
+#endif
diff --git a/Source/cmCLocaleEnvironmentScope.cxx b/Source/cmCLocaleEnvironmentScope.cxx
new file mode 100644
index 0000000..a19dbae
--- /dev/null
+++ b/Source/cmCLocaleEnvironmentScope.cxx
@@ -0,0 +1,62 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCLocaleEnvironmentScope.h"
+
+#include "cmSystemTools.h"
+
+#include <sstream>
+
+cmCLocaleEnvironmentScope::cmCLocaleEnvironmentScope()
+{
+ this->SetEnv("LANGUAGE", "");
+ this->SetEnv("LC_MESSAGES", "C");
+
+ std::string lcAll = this->GetEnv("LC_ALL");
+
+ if (!lcAll.empty()) {
+ this->SetEnv("LC_ALL", "");
+ this->SetEnv("LC_CTYPE", lcAll);
+ }
+}
+
+std::string cmCLocaleEnvironmentScope::GetEnv(std::string const& key)
+{
+ const char* value = cmSystemTools::GetEnv(key);
+ return value ? value : std::string();
+}
+
+void cmCLocaleEnvironmentScope::SetEnv(std::string const& key,
+ std::string const& value)
+{
+ std::string oldValue = this->GetEnv(key);
+
+ this->EnvironmentBackup.insert(std::make_pair(key, oldValue));
+
+ if (value.empty()) {
+ cmSystemTools::UnsetEnv(key.c_str());
+ } else {
+ std::ostringstream tmp;
+ tmp << key << "=" << value;
+ cmSystemTools::PutEnv(tmp.str());
+ }
+}
+
+cmCLocaleEnvironmentScope::~cmCLocaleEnvironmentScope()
+{
+ for (backup_map_t::const_iterator i = this->EnvironmentBackup.begin();
+ i != this->EnvironmentBackup.end(); ++i) {
+ std::ostringstream tmp;
+ tmp << i->first << "=" << i->second;
+ cmSystemTools::PutEnv(tmp.str());
+ }
+}
diff --git a/Source/cmCLocaleEnvironmentScope.h b/Source/cmCLocaleEnvironmentScope.h
new file mode 100644
index 0000000..b011741
--- /dev/null
+++ b/Source/cmCLocaleEnvironmentScope.h
@@ -0,0 +1,32 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCLocaleEnvironmentScope_h
+#define cmCLocaleEnvironmentScope_h
+
+#include "cmStandardIncludes.h"
+
+class cmCLocaleEnvironmentScope
+{
+public:
+ cmCLocaleEnvironmentScope();
+ ~cmCLocaleEnvironmentScope();
+
+private:
+ std::string GetEnv(std::string const& key);
+ void SetEnv(std::string const& key, std::string const& value);
+
+ typedef std::map<std::string, std::string> backup_map_t;
+ backup_map_t EnvironmentBackup;
+};
+
+#endif
diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx
new file mode 100644
index 0000000..fdbd5e7
--- /dev/null
+++ b/Source/cmCMakeHostSystemInformationCommand.cxx
@@ -0,0 +1,103 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCMakeHostSystemInformationCommand.h"
+
+// cmCMakeHostSystemInformation
+bool cmCMakeHostSystemInformationCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ size_t current_index = 0;
+
+ if (args.size() < (current_index + 2) || args[current_index] != "RESULT") {
+ this->SetError("missing RESULT specification.");
+ return false;
+ }
+
+ std::string variable = args[current_index + 1];
+ current_index += 2;
+
+ if (args.size() < (current_index + 2) || args[current_index] != "QUERY") {
+ this->SetError("missing QUERY specification");
+ return false;
+ }
+
+ cmsys::SystemInformation info;
+ info.RunCPUCheck();
+ info.RunOSCheck();
+ info.RunMemoryCheck();
+
+ std::string result_list;
+ for (size_t i = current_index + 1; i < args.size(); ++i) {
+ std::string key = args[i];
+ if (i != current_index + 1) {
+ result_list += ";";
+ }
+ std::string value;
+ if (!this->GetValue(info, key, value))
+ return false;
+
+ result_list += value;
+ }
+
+ this->Makefile->AddDefinition(variable, result_list.c_str());
+
+ return true;
+}
+
+bool cmCMakeHostSystemInformationCommand::GetValue(
+ cmsys::SystemInformation& info, std::string const& key, std::string& value)
+{
+ if (key == "NUMBER_OF_LOGICAL_CORES") {
+ value = this->ValueToString(info.GetNumberOfLogicalCPU());
+ } else if (key == "NUMBER_OF_PHYSICAL_CORES") {
+ value = this->ValueToString(info.GetNumberOfPhysicalCPU());
+ } else if (key == "HOSTNAME") {
+ value = this->ValueToString(info.GetHostname());
+ } else if (key == "FQDN") {
+ value = this->ValueToString(info.GetFullyQualifiedDomainName());
+ } else if (key == "TOTAL_VIRTUAL_MEMORY") {
+ value = this->ValueToString(info.GetTotalVirtualMemory());
+ } else if (key == "AVAILABLE_VIRTUAL_MEMORY") {
+ value = this->ValueToString(info.GetAvailableVirtualMemory());
+ } else if (key == "TOTAL_PHYSICAL_MEMORY") {
+ value = this->ValueToString(info.GetTotalPhysicalMemory());
+ } else if (key == "AVAILABLE_PHYSICAL_MEMORY") {
+ value = this->ValueToString(info.GetAvailablePhysicalMemory());
+ } else {
+ std::string e = "does not recognize <key> " + key;
+ this->SetError(e);
+ return false;
+ }
+
+ return true;
+}
+
+std::string cmCMakeHostSystemInformationCommand::ValueToString(
+ size_t value) const
+{
+ std::ostringstream tmp;
+ tmp << value;
+ return tmp.str();
+}
+
+std::string cmCMakeHostSystemInformationCommand::ValueToString(
+ const char* value) const
+{
+ std::string safe_string = value ? value : "";
+ return safe_string;
+}
+
+std::string cmCMakeHostSystemInformationCommand::ValueToString(
+ std::string const& value) const
+{
+ return value;
+}
diff --git a/Source/cmCMakeHostSystemInformationCommand.h b/Source/cmCMakeHostSystemInformationCommand.h
new file mode 100644
index 0000000..8e6f0f5
--- /dev/null
+++ b/Source/cmCMakeHostSystemInformationCommand.h
@@ -0,0 +1,67 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCMakeHostSystemInformationCommand_h
+#define cmCMakeHostSystemInformationCommand_h
+
+#include "cmCommand.h"
+
+#include <cmsys/SystemInformation.hxx>
+
+/** \class cmCMakeHostSystemInformationCommand
+ * \brief Query host system specific information
+ *
+ * cmCMakeHostSystemInformationCommand queries system information of
+ * the sytem on which CMake runs.
+ */
+class cmCMakeHostSystemInformationCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ return new cmCMakeHostSystemInformationCommand;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE
+ {
+ return "cmake_host_system_information";
+ }
+
+ cmTypeMacro(cmCMakeHostSystemInformationCommand, cmCommand);
+
+private:
+ bool GetValue(cmsys::SystemInformation& info, std::string const& key,
+ std::string& value);
+
+ std::string ValueToString(size_t value) const;
+ std::string ValueToString(const char* value) const;
+ std::string ValueToString(std::string const& value) const;
+};
+
+#endif
diff --git a/Source/cmCMakeMinimumRequired.cxx b/Source/cmCMakeMinimumRequired.cxx
new file mode 100644
index 0000000..1376845
--- /dev/null
+++ b/Source/cmCMakeMinimumRequired.cxx
@@ -0,0 +1,117 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCMakeMinimumRequired.h"
+
+#include "cmVersion.h"
+
+// cmCMakeMinimumRequired
+bool cmCMakeMinimumRequired::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ // Process arguments.
+ std::string version_string;
+ bool doing_version = false;
+ for (unsigned int i = 0; i < args.size(); ++i) {
+ if (args[i] == "VERSION") {
+ doing_version = true;
+ } else if (args[i] == "FATAL_ERROR") {
+ if (doing_version) {
+ this->SetError("called with no value for VERSION.");
+ return false;
+ }
+ doing_version = false;
+ } else if (doing_version) {
+ doing_version = false;
+ version_string = args[i];
+ } else {
+ this->UnknownArguments.push_back(args[i]);
+ }
+ }
+ if (doing_version) {
+ this->SetError("called with no value for VERSION.");
+ return false;
+ }
+
+ // Make sure there was a version to check.
+ if (version_string.empty()) {
+ return this->EnforceUnknownArguments();
+ }
+
+ // Save the required version string.
+ this->Makefile->AddDefinition("CMAKE_MINIMUM_REQUIRED_VERSION",
+ version_string.c_str());
+
+ // Get the current version number.
+ unsigned int current_major = cmVersion::GetMajorVersion();
+ unsigned int current_minor = cmVersion::GetMinorVersion();
+ unsigned int current_patch = cmVersion::GetPatchVersion();
+ unsigned int current_tweak = cmVersion::GetTweakVersion();
+
+ // Parse at least two components of the version number.
+ // Use zero for those not specified.
+ unsigned int required_major = 0;
+ unsigned int required_minor = 0;
+ unsigned int required_patch = 0;
+ unsigned int required_tweak = 0;
+ if (sscanf(version_string.c_str(), "%u.%u.%u.%u", &required_major,
+ &required_minor, &required_patch, &required_tweak) < 2) {
+ std::ostringstream e;
+ e << "could not parse VERSION \"" << version_string << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Compare the version numbers.
+ if ((current_major < required_major) ||
+ (current_major == required_major && current_minor < required_minor) ||
+ (current_major == required_major && current_minor == required_minor &&
+ current_patch < required_patch) ||
+ (current_major == required_major && current_minor == required_minor &&
+ current_patch == required_patch && current_tweak < required_tweak)) {
+ // The current version is too low.
+ std::ostringstream e;
+ e << "CMake " << version_string
+ << " or higher is required. You are running version "
+ << cmVersion::GetCMakeVersion();
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+
+ // The version is not from the future, so enforce unknown arguments.
+ if (!this->EnforceUnknownArguments()) {
+ return false;
+ }
+
+ if (required_major < 2 || (required_major == 2 && required_minor < 4)) {
+ this->Makefile->IssueMessage(
+ cmake::AUTHOR_WARNING,
+ "Compatibility with CMake < 2.4 is not supported by CMake >= 3.0.");
+ this->Makefile->SetPolicyVersion("2.4");
+ } else {
+ this->Makefile->SetPolicyVersion(version_string.c_str());
+ }
+
+ return true;
+}
+
+bool cmCMakeMinimumRequired::EnforceUnknownArguments()
+{
+ if (!this->UnknownArguments.empty()) {
+ std::ostringstream e;
+ e << "called with unknown argument \"" << this->UnknownArguments[0]
+ << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ return true;
+}
diff --git a/Source/cmCMakeMinimumRequired.h b/Source/cmCMakeMinimumRequired.h
new file mode 100644
index 0000000..4231eb4
--- /dev/null
+++ b/Source/cmCMakeMinimumRequired.h
@@ -0,0 +1,54 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCMakeMinimumRequired_h
+#define cmCMakeMinimumRequired_h
+
+#include "cmCommand.h"
+
+/** \class cmCMakeMinimumRequired
+ * \brief cmake_minimum_required command
+ *
+ * cmCMakeMinimumRequired implements the cmake_minimum_required CMake command
+ */
+class cmCMakeMinimumRequired : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmCMakeMinimumRequired; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "cmake_minimum_required"; }
+
+ cmTypeMacro(cmCMakeMinimumRequired, cmCommand);
+
+private:
+ std::vector<std::string> UnknownArguments;
+ bool EnforceUnknownArguments();
+};
+
+#endif
diff --git a/Source/cmCMakePolicyCommand.cxx b/Source/cmCMakePolicyCommand.cxx
new file mode 100644
index 0000000..07e0885
--- /dev/null
+++ b/Source/cmCMakePolicyCommand.cxx
@@ -0,0 +1,157 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCMakePolicyCommand.h"
+
+#include "cmVersion.h"
+
+// cmCMakePolicyCommand
+bool cmCMakePolicyCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("requires at least one argument.");
+ return false;
+ }
+
+ if (args[0] == "SET") {
+ return this->HandleSetMode(args);
+ } else if (args[0] == "GET") {
+ return this->HandleGetMode(args);
+ } else if (args[0] == "PUSH") {
+ if (args.size() > 1) {
+ this->SetError("PUSH may not be given additional arguments.");
+ return false;
+ }
+ this->Makefile->PushPolicy();
+ return true;
+ } else if (args[0] == "POP") {
+ if (args.size() > 1) {
+ this->SetError("POP may not be given additional arguments.");
+ return false;
+ }
+ this->Makefile->PopPolicy();
+ return true;
+ } else if (args[0] == "VERSION") {
+ return this->HandleVersionMode(args);
+ }
+
+ std::ostringstream e;
+ e << "given unknown first argument \"" << args[0] << "\"";
+ this->SetError(e.str());
+ return false;
+}
+
+bool cmCMakePolicyCommand::HandleSetMode(std::vector<std::string> const& args)
+{
+ if (args.size() != 3) {
+ this->SetError("SET must be given exactly 2 additional arguments.");
+ return false;
+ }
+
+ cmPolicies::PolicyStatus status;
+ if (args[2] == "OLD") {
+ status = cmPolicies::OLD;
+ } else if (args[2] == "NEW") {
+ status = cmPolicies::NEW;
+ } else {
+ std::ostringstream e;
+ e << "SET given unrecognized policy status \"" << args[2] << "\"";
+ this->SetError(e.str());
+ return false;
+ }
+
+ if (!this->Makefile->SetPolicy(args[1].c_str(), status)) {
+ this->SetError("SET failed to set policy.");
+ return false;
+ }
+ if (args[1] == "CMP0001" &&
+ (status == cmPolicies::WARN || status == cmPolicies::OLD)) {
+ if (!(this->Makefile->GetState()->GetInitializedCacheValue(
+ "CMAKE_BACKWARDS_COMPATIBILITY"))) {
+ // Set it to 2.4 because that is the last version where the
+ // variable had meaning.
+ this->Makefile->AddCacheDefinition(
+ "CMAKE_BACKWARDS_COMPATIBILITY", "2.4",
+ "For backwards compatibility, what version of CMake "
+ "commands and "
+ "syntax should this version of CMake try to support.",
+ cmState::STRING);
+ }
+ }
+ return true;
+}
+
+bool cmCMakePolicyCommand::HandleGetMode(std::vector<std::string> const& args)
+{
+ if (args.size() != 3) {
+ this->SetError("GET must be given exactly 2 additional arguments.");
+ return false;
+ }
+
+ // Get arguments.
+ std::string const& id = args[1];
+ std::string const& var = args[2];
+
+ // Lookup the policy number.
+ cmPolicies::PolicyID pid;
+ if (!cmPolicies::GetPolicyID(id.c_str(), pid)) {
+ std::ostringstream e;
+ e << "GET given policy \"" << id << "\" which is not known to this "
+ << "version of CMake.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Lookup the policy setting.
+ cmPolicies::PolicyStatus status = this->Makefile->GetPolicyStatus(pid);
+ switch (status) {
+ case cmPolicies::OLD:
+ // Report that the policy is set to OLD.
+ this->Makefile->AddDefinition(var, "OLD");
+ break;
+ case cmPolicies::WARN:
+ // Report that the policy is not set.
+ this->Makefile->AddDefinition(var, "");
+ break;
+ case cmPolicies::NEW:
+ // Report that the policy is set to NEW.
+ this->Makefile->AddDefinition(var, "NEW");
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ // The policy is required to be set before anything needs it.
+ {
+ std::ostringstream e;
+ e << cmPolicies::GetRequiredPolicyError(pid) << "\n"
+ << "The call to cmake_policy(GET " << id << " ...) at which this "
+ << "error appears requests the policy, and this version of CMake "
+ << "requires that the policy be set to NEW before it is checked.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ }
+ }
+
+ return true;
+}
+
+bool cmCMakePolicyCommand::HandleVersionMode(
+ std::vector<std::string> const& args)
+{
+ if (args.size() <= 1) {
+ this->SetError("VERSION not given an argument");
+ return false;
+ } else if (args.size() >= 3) {
+ this->SetError("VERSION given too many arguments");
+ return false;
+ }
+ this->Makefile->SetPolicyVersion(args[1].c_str());
+ return true;
+}
diff --git a/Source/cmCMakePolicyCommand.h b/Source/cmCMakePolicyCommand.h
new file mode 100644
index 0000000..fd4ab0a
--- /dev/null
+++ b/Source/cmCMakePolicyCommand.h
@@ -0,0 +1,56 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCMakePolicyCommand_h
+#define cmCMakePolicyCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmCMakePolicyCommand
+ * \brief Set how CMake should handle policies
+ *
+ * cmCMakePolicyCommand sets how CMake should deal with backwards
+ * compatibility policies.
+ */
+class cmCMakePolicyCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmCMakePolicyCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "cmake_policy"; }
+
+ cmTypeMacro(cmCMakePolicyCommand, cmCommand);
+
+private:
+ bool HandleSetMode(std::vector<std::string> const& args);
+ bool HandleGetMode(std::vector<std::string> const& args);
+ bool HandleVersionMode(std::vector<std::string> const& args);
+};
+
+#endif
diff --git a/Source/cmCPackPropertiesGenerator.cxx b/Source/cmCPackPropertiesGenerator.cxx
new file mode 100644
index 0000000..af01c7d
--- /dev/null
+++ b/Source/cmCPackPropertiesGenerator.cxx
@@ -0,0 +1,43 @@
+#include "cmCPackPropertiesGenerator.h"
+
+#include "cmLocalGenerator.h"
+#include "cmOutputConverter.h"
+
+cmCPackPropertiesGenerator::cmCPackPropertiesGenerator(
+ cmLocalGenerator* lg, cmInstalledFile const& installedFile,
+ std::vector<std::string> const& configurations)
+ : cmScriptGenerator("CPACK_BUILD_CONFIG", configurations)
+ , LG(lg)
+ , InstalledFile(installedFile)
+{
+ this->ActionsPerConfig = true;
+}
+
+void cmCPackPropertiesGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent const& indent)
+{
+ std::string const& expandedFileName =
+ this->InstalledFile.GetNameExpression().Evaluate(this->LG, config);
+
+ cmInstalledFile::PropertyMapType const& properties =
+ this->InstalledFile.GetProperties();
+
+ for (cmInstalledFile::PropertyMapType::const_iterator i = properties.begin();
+ i != properties.end(); ++i) {
+ std::string const& name = i->first;
+ cmInstalledFile::Property const& property = i->second;
+
+ os << indent << "set_property(INSTALL "
+ << cmOutputConverter::EscapeForCMake(expandedFileName) << " PROPERTY "
+ << cmOutputConverter::EscapeForCMake(name);
+
+ for (cmInstalledFile::ExpressionVectorType::const_iterator j =
+ property.ValueExpressions.begin();
+ j != property.ValueExpressions.end(); ++j) {
+ std::string value = (*j)->Evaluate(this->LG, config);
+ os << " " << cmOutputConverter::EscapeForCMake(value);
+ }
+
+ os << ")\n";
+ }
+}
diff --git a/Source/cmCPackPropertiesGenerator.h b/Source/cmCPackPropertiesGenerator.h
new file mode 100644
index 0000000..4d092f6
--- /dev/null
+++ b/Source/cmCPackPropertiesGenerator.h
@@ -0,0 +1,39 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCPackPropertiesGenerator_h
+#define cmCPackPropertiesGenerator_h
+
+#include "cmInstalledFile.h"
+#include "cmScriptGenerator.h"
+
+class cmLocalGenerator;
+
+/** \class cmCPackPropertiesGenerator
+ * \brief Support class for generating CPackProperties.cmake.
+ *
+ */
+class cmCPackPropertiesGenerator : public cmScriptGenerator
+{
+public:
+ cmCPackPropertiesGenerator(cmLocalGenerator* lg,
+ cmInstalledFile const& installedFile,
+ std::vector<std::string> const& configurations);
+
+protected:
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent const& indent) CM_OVERRIDE;
+
+ cmLocalGenerator* LG;
+ cmInstalledFile const& InstalledFile;
+};
+
+#endif
diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx
new file mode 100644
index 0000000..f97791a
--- /dev/null
+++ b/Source/cmCPluginAPI.cxx
@@ -0,0 +1,852 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+ this file contains the implementation of the C API to CMake. Generally
+ these routines just manipulate arguments and then call the associated
+ methods on the CMake classes. */
+
+#include "cmCPluginAPI.h"
+
+#include "cmMakefile.h"
+#include "cmVersion.h"
+
+#include "cmSourceFile.h"
+
+#include <stdlib.h>
+
+#ifdef __QNX__
+#include <malloc.h> /* for malloc/free on QNX */
+#endif
+
+extern "C" {
+
+void CCONV* cmGetClientData(void* info)
+{
+ return ((cmLoadedCommandInfo*)info)->ClientData;
+}
+
+void CCONV cmSetClientData(void* info, void* cd)
+{
+ ((cmLoadedCommandInfo*)info)->ClientData = cd;
+}
+
+void CCONV cmSetError(void* info, const char* err)
+{
+ if (((cmLoadedCommandInfo*)info)->Error) {
+ free(((cmLoadedCommandInfo*)info)->Error);
+ }
+ ((cmLoadedCommandInfo*)info)->Error = strdup(err);
+}
+
+unsigned int CCONV cmGetCacheMajorVersion(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ cmState* state = mf->GetState();
+ return state->GetCacheMajorVersion();
+}
+unsigned int CCONV cmGetCacheMinorVersion(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ cmState* state = mf->GetState();
+ return state->GetCacheMinorVersion();
+}
+
+unsigned int CCONV cmGetMajorVersion(void*)
+{
+ return cmVersion::GetMajorVersion();
+}
+
+unsigned int CCONV cmGetMinorVersion(void*)
+{
+ return cmVersion::GetMinorVersion();
+}
+
+void CCONV cmAddDefinition(void* arg, const char* name, const char* value)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ mf->AddDefinition(name, value);
+}
+
+/* Add a definition to this makefile and the global cmake cache. */
+void CCONV cmAddCacheDefinition(void* arg, const char* name, const char* value,
+ const char* doc, int type)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+
+ switch (type) {
+ case CM_CACHE_BOOL:
+ mf->AddCacheDefinition(name, value, doc, cmState::BOOL);
+ break;
+ case CM_CACHE_PATH:
+ mf->AddCacheDefinition(name, value, doc, cmState::PATH);
+ break;
+ case CM_CACHE_FILEPATH:
+ mf->AddCacheDefinition(name, value, doc, cmState::FILEPATH);
+ break;
+ case CM_CACHE_STRING:
+ mf->AddCacheDefinition(name, value, doc, cmState::STRING);
+ break;
+ case CM_CACHE_INTERNAL:
+ mf->AddCacheDefinition(name, value, doc, cmState::INTERNAL);
+ break;
+ case CM_CACHE_STATIC:
+ mf->AddCacheDefinition(name, value, doc, cmState::STATIC);
+ break;
+ }
+}
+
+const char* CCONV cmGetProjectName(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ static std::string name;
+ name = mf->GetStateSnapshot().GetProjectName();
+ return name.c_str();
+}
+
+const char* CCONV cmGetHomeDirectory(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return mf->GetHomeDirectory();
+}
+const char* CCONV cmGetHomeOutputDirectory(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return mf->GetHomeOutputDirectory();
+}
+const char* CCONV cmGetStartDirectory(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return mf->GetCurrentSourceDirectory();
+}
+const char* CCONV cmGetStartOutputDirectory(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return mf->GetCurrentBinaryDirectory();
+}
+const char* CCONV cmGetCurrentDirectory(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return mf->GetCurrentSourceDirectory();
+}
+const char* CCONV cmGetCurrentOutputDirectory(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return mf->GetCurrentBinaryDirectory();
+}
+const char* CCONV cmGetDefinition(void* arg, const char* def)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return mf->GetDefinition(def);
+}
+
+int CCONV cmIsOn(void* arg, const char* name)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return static_cast<int>(mf->IsOn(name));
+}
+
+/** Check if a command exists. */
+int CCONV cmCommandExists(void* arg, const char* name)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return static_cast<int>(mf->GetState()->GetCommand(name) ? 1 : 0);
+}
+
+void CCONV cmAddDefineFlag(void* arg, const char* definition)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ mf->AddDefineFlag(definition);
+}
+
+void CCONV cmAddLinkDirectoryForTarget(void* arg, const char* tgt,
+ const char* d)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ mf->AddLinkDirectoryForTarget(tgt, d);
+}
+
+void CCONV cmAddExecutable(void* arg, const char* exename, int numSrcs,
+ const char** srcs, int win32)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ std::vector<std::string> srcs2;
+ int i;
+ for (i = 0; i < numSrcs; ++i) {
+ srcs2.push_back(srcs[i]);
+ }
+ cmTarget* tg = mf->AddExecutable(exename, srcs2);
+ if (win32) {
+ tg->SetProperty("WIN32_EXECUTABLE", "ON");
+ }
+}
+
+void CCONV cmAddUtilityCommand(void* arg, const char* utilityName,
+ const char* command, const char* arguments,
+ int all, int numDepends, const char** depends,
+ int, const char**)
+{
+ // Get the makefile instance. Perform an extra variable expansion
+ // now because the API caller expects it.
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+
+ // Construct the command line for the command.
+ cmCustomCommandLine commandLine;
+ std::string expand = command;
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ if (arguments && arguments[0]) {
+ // TODO: Parse arguments!
+ expand = arguments;
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ }
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(commandLine);
+
+ // Accumulate the list of dependencies.
+ std::vector<std::string> depends2;
+ for (int i = 0; i < numDepends; ++i) {
+ expand = depends[i];
+ depends2.push_back(mf->ExpandVariablesInString(expand));
+ }
+
+ // Pass the call to the makefile instance.
+ mf->AddUtilityCommand(utilityName, (all ? false : true), CM_NULLPTR,
+ depends2, commandLines);
+}
+void CCONV cmAddCustomCommand(void* arg, const char* source,
+ const char* command, int numArgs,
+ const char** args, int numDepends,
+ const char** depends, int numOutputs,
+ const char** outputs, const char* target)
+{
+ // Get the makefile instance. Perform an extra variable expansion
+ // now because the API caller expects it.
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+
+ // Construct the command line for the command.
+ cmCustomCommandLine commandLine;
+ std::string expand = command;
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ for (int i = 0; i < numArgs; ++i) {
+ expand = args[i];
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ }
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(commandLine);
+
+ // Accumulate the list of dependencies.
+ std::vector<std::string> depends2;
+ for (int i = 0; i < numDepends; ++i) {
+ expand = depends[i];
+ depends2.push_back(mf->ExpandVariablesInString(expand));
+ }
+
+ // Accumulate the list of outputs.
+ std::vector<std::string> outputs2;
+ for (int i = 0; i < numOutputs; ++i) {
+ expand = outputs[i];
+ outputs2.push_back(mf->ExpandVariablesInString(expand));
+ }
+
+ // Pass the call to the makefile instance.
+ const char* no_comment = CM_NULLPTR;
+ mf->AddCustomCommandOldStyle(target, outputs2, depends2, source,
+ commandLines, no_comment);
+}
+
+void CCONV cmAddCustomCommandToOutput(void* arg, const char* output,
+ const char* command, int numArgs,
+ const char** args,
+ const char* main_dependency,
+ int numDepends, const char** depends)
+{
+ // Get the makefile instance. Perform an extra variable expansion
+ // now because the API caller expects it.
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+
+ // Construct the command line for the command.
+ cmCustomCommandLine commandLine;
+ std::string expand = command;
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ for (int i = 0; i < numArgs; ++i) {
+ expand = args[i];
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ }
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(commandLine);
+
+ // Accumulate the list of dependencies.
+ std::vector<std::string> depends2;
+ for (int i = 0; i < numDepends; ++i) {
+ expand = depends[i];
+ depends2.push_back(mf->ExpandVariablesInString(expand));
+ }
+
+ // Pass the call to the makefile instance.
+ const char* no_comment = CM_NULLPTR;
+ const char* no_working_dir = CM_NULLPTR;
+ mf->AddCustomCommandToOutput(output, depends2, main_dependency, commandLines,
+ no_comment, no_working_dir);
+}
+
+void CCONV cmAddCustomCommandToTarget(void* arg, const char* target,
+ const char* command, int numArgs,
+ const char** args, int commandType)
+{
+ // Get the makefile instance.
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+
+ // Construct the command line for the command. Perform an extra
+ // variable expansion now because the API caller expects it.
+ cmCustomCommandLine commandLine;
+ std::string expand = command;
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ for (int i = 0; i < numArgs; ++i) {
+ expand = args[i];
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ }
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(commandLine);
+
+ // Select the command type.
+ cmTarget::CustomCommandType cctype = cmTarget::POST_BUILD;
+ switch (commandType) {
+ case CM_PRE_BUILD:
+ cctype = cmTarget::PRE_BUILD;
+ break;
+ case CM_PRE_LINK:
+ cctype = cmTarget::PRE_LINK;
+ break;
+ case CM_POST_BUILD:
+ cctype = cmTarget::POST_BUILD;
+ break;
+ }
+
+ // Pass the call to the makefile instance.
+ std::vector<std::string> no_byproducts;
+ std::vector<std::string> no_depends;
+ const char* no_comment = CM_NULLPTR;
+ const char* no_working_dir = CM_NULLPTR;
+ mf->AddCustomCommandToTarget(target, no_byproducts, no_depends, commandLines,
+ cctype, no_comment, no_working_dir);
+}
+
+void CCONV cmAddLinkLibraryForTarget(void* arg, const char* tgt,
+ const char* value, int libtype)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+
+ switch (libtype) {
+ case CM_LIBRARY_GENERAL:
+ mf->AddLinkLibraryForTarget(tgt, value, GENERAL_LibraryType);
+ break;
+ case CM_LIBRARY_DEBUG:
+ mf->AddLinkLibraryForTarget(tgt, value, DEBUG_LibraryType);
+ break;
+ case CM_LIBRARY_OPTIMIZED:
+ mf->AddLinkLibraryForTarget(tgt, value, OPTIMIZED_LibraryType);
+ break;
+ }
+}
+
+void CCONV cmAddLibrary(void* arg, const char* libname, int shared,
+ int numSrcs, const char** srcs)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ std::vector<std::string> srcs2;
+ int i;
+ for (i = 0; i < numSrcs; ++i) {
+ srcs2.push_back(srcs[i]);
+ }
+ mf->AddLibrary(libname,
+ (shared ? cmState::SHARED_LIBRARY : cmState::STATIC_LIBRARY),
+ srcs2);
+}
+
+char CCONV* cmExpandVariablesInString(void* arg, const char* source,
+ int escapeQuotes, int atOnly)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ std::string barf = source;
+ std::string result = mf->ExpandVariablesInString(
+ barf, (escapeQuotes ? true : false), (atOnly ? true : false));
+ char* res = static_cast<char*>(malloc(result.size() + 1));
+ if (result.size()) {
+ strcpy(res, result.c_str());
+ }
+ res[result.size()] = '\0';
+ return res;
+}
+
+int CCONV cmExecuteCommand(void* arg, const char* name, int numArgs,
+ const char** args)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ cmListFileFunction lff;
+ lff.Name = name;
+ for (int i = 0; i < numArgs; ++i) {
+ // Assume all arguments are quoted.
+ lff.Arguments.push_back(
+ cmListFileArgument(args[i], cmListFileArgument::Quoted, 0));
+ }
+ cmExecutionStatus status;
+ return mf->ExecuteCommand(lff, status);
+}
+
+void CCONV cmExpandSourceListArguments(void* arg, int numArgs,
+ const char** args, int* resArgc,
+ char*** resArgv,
+ unsigned int startArgumentIndex)
+{
+ (void)arg;
+ (void)startArgumentIndex;
+ std::vector<std::string> result;
+ int i;
+ for (i = 0; i < numArgs; ++i) {
+ result.push_back(args[i]);
+ }
+ int resargc = static_cast<int>(result.size());
+ char** resargv = CM_NULLPTR;
+ if (resargc) {
+ resargv = (char**)malloc(resargc * sizeof(char*));
+ }
+ for (i = 0; i < resargc; ++i) {
+ resargv[i] = strdup(result[i].c_str());
+ }
+ *resArgc = resargc;
+ *resArgv = resargv;
+}
+
+void CCONV cmFreeArguments(int argc, char** argv)
+{
+ int i;
+ for (i = 0; i < argc; ++i) {
+ free(argv[i]);
+ }
+ if (argv) {
+ free(argv);
+ }
+}
+
+int CCONV cmGetTotalArgumentSize(int argc, char** argv)
+{
+ int i;
+ int result = 0;
+ for (i = 0; i < argc; ++i) {
+ if (argv[i]) {
+ result = result + static_cast<int>(strlen(argv[i]));
+ }
+ }
+ return result;
+}
+
+// Source file proxy object to support the old cmSourceFile/cmMakefile
+// API for source files.
+struct cmCPluginAPISourceFile
+{
+ cmCPluginAPISourceFile()
+ : RealSourceFile(CM_NULLPTR)
+ {
+ }
+ cmSourceFile* RealSourceFile;
+ std::string SourceName;
+ std::string SourceExtension;
+ std::string FullPath;
+ std::vector<std::string> Depends;
+ cmPropertyMap Properties;
+};
+
+// Keep a map from real cmSourceFile instances stored in a makefile to
+// the CPluginAPI proxy source file.
+class cmCPluginAPISourceFileMap
+ : public std::map<cmSourceFile*, cmCPluginAPISourceFile*>
+{
+public:
+ typedef std::map<cmSourceFile*, cmCPluginAPISourceFile*> derived;
+ typedef derived::iterator iterator;
+ typedef derived::value_type value_type;
+ ~cmCPluginAPISourceFileMap()
+ {
+ for (iterator i = this->begin(); i != this->end(); ++i) {
+ delete i->second;
+ }
+ }
+};
+cmCPluginAPISourceFileMap cmCPluginAPISourceFiles;
+
+void* CCONV cmCreateSourceFile(void)
+{
+ return (void*)new cmCPluginAPISourceFile;
+}
+
+void* CCONV cmCreateNewSourceFile(void*)
+{
+ cmCPluginAPISourceFile* sf = new cmCPluginAPISourceFile;
+ return (void*)sf;
+}
+
+void CCONV cmDestroySourceFile(void* arg)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ // Only delete if it was created by cmCreateSourceFile or
+ // cmCreateNewSourceFile and is therefore not in the map.
+ if (!sf->RealSourceFile) {
+ delete sf;
+ }
+}
+
+void CCONV* cmGetSource(void* arg, const char* name)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ if (cmSourceFile* rsf = mf->GetSource(name)) {
+ // Lookup the proxy source file object for this source.
+ cmCPluginAPISourceFileMap::iterator i = cmCPluginAPISourceFiles.find(rsf);
+ if (i == cmCPluginAPISourceFiles.end()) {
+ // Create a proxy source file object for this source.
+ cmCPluginAPISourceFile* sf = new cmCPluginAPISourceFile;
+ sf->RealSourceFile = rsf;
+ sf->FullPath = rsf->GetFullPath();
+ sf->SourceName =
+ cmSystemTools::GetFilenameWithoutLastExtension(sf->FullPath);
+ sf->SourceExtension =
+ cmSystemTools::GetFilenameLastExtension(sf->FullPath);
+
+ // Store the proxy in the map so it can be re-used and deleted later.
+ cmCPluginAPISourceFileMap::value_type entry(rsf, sf);
+ i = cmCPluginAPISourceFiles.insert(entry).first;
+ }
+ return (void*)i->second;
+ } else {
+ return CM_NULLPTR;
+ }
+}
+
+void* CCONV cmAddSource(void* arg, void* arg2)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ cmCPluginAPISourceFile* osf = static_cast<cmCPluginAPISourceFile*>(arg2);
+ if (osf->FullPath.empty()) {
+ return CM_NULLPTR;
+ }
+
+ // Create the real cmSourceFile instance and copy over saved information.
+ cmSourceFile* rsf = mf->GetOrCreateSource(osf->FullPath);
+ rsf->GetProperties() = osf->Properties;
+ for (std::vector<std::string>::iterator i = osf->Depends.begin();
+ i != osf->Depends.end(); ++i) {
+ rsf->AddDepend(i->c_str());
+ }
+
+ // Create the proxy for the real source file.
+ cmCPluginAPISourceFile* sf = new cmCPluginAPISourceFile;
+ sf->RealSourceFile = rsf;
+ sf->FullPath = osf->FullPath;
+ sf->SourceName = osf->SourceName;
+ sf->SourceExtension = osf->SourceExtension;
+
+ // Store the proxy in the map so it can be re-used and deleted later.
+ cmCPluginAPISourceFiles[rsf] = sf;
+ return (void*)sf;
+}
+
+const char* CCONV cmSourceFileGetSourceName(void* arg)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ return sf->SourceName.c_str();
+}
+
+const char* CCONV cmSourceFileGetFullPath(void* arg)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ return sf->FullPath.c_str();
+}
+
+const char* CCONV cmSourceFileGetProperty(void* arg, const char* prop)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ if (cmSourceFile* rsf = sf->RealSourceFile) {
+ return rsf->GetProperty(prop);
+ } else {
+ if (!strcmp(prop, "LOCATION")) {
+ return sf->FullPath.c_str();
+ }
+ return sf->Properties.GetPropertyValue(prop);
+ }
+}
+
+int CCONV cmSourceFileGetPropertyAsBool(void* arg, const char* prop)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ if (cmSourceFile* rsf = sf->RealSourceFile) {
+ return rsf->GetPropertyAsBool(prop) ? 1 : 0;
+ } else {
+ return cmSystemTools::IsOn(cmSourceFileGetProperty(arg, prop)) ? 1 : 0;
+ }
+}
+
+void CCONV cmSourceFileSetProperty(void* arg, const char* prop,
+ const char* value)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ if (cmSourceFile* rsf = sf->RealSourceFile) {
+ rsf->SetProperty(prop, value);
+ } else if (prop) {
+ if (!value) {
+ value = "NOTFOUND";
+ }
+ sf->Properties.SetProperty(prop, value);
+ }
+}
+
+void CCONV cmSourceFileAddDepend(void* arg, const char* depend)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ if (cmSourceFile* rsf = sf->RealSourceFile) {
+ rsf->AddDepend(depend);
+ } else {
+ sf->Depends.push_back(depend);
+ }
+}
+
+void CCONV cmSourceFileSetName(void* arg, const char* name, const char* dir,
+ int numSourceExtensions,
+ const char** sourceExtensions,
+ int numHeaderExtensions,
+ const char** headerExtensions)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ if (sf->RealSourceFile) {
+ // SetName is allowed only on temporary source files created by
+ // the command for building and passing to AddSource.
+ return;
+ }
+ std::vector<std::string> sourceExts;
+ std::vector<std::string> headerExts;
+ int i;
+ for (i = 0; i < numSourceExtensions; ++i) {
+ sourceExts.push_back(sourceExtensions[i]);
+ }
+ for (i = 0; i < numHeaderExtensions; ++i) {
+ headerExts.push_back(headerExtensions[i]);
+ }
+
+ // Save the original name given.
+ sf->SourceName = name;
+
+ // Convert the name to a full path in case the given name is a
+ // relative path.
+ std::string pathname = cmSystemTools::CollapseFullPath(name, dir);
+
+ // First try and see whether the listed file can be found
+ // as is without extensions added on.
+ std::string hname = pathname;
+ if (cmSystemTools::FileExists(hname.c_str())) {
+ sf->SourceName = cmSystemTools::GetFilenamePath(name);
+ if (sf->SourceName.size() > 0) {
+ sf->SourceName += "/";
+ }
+ sf->SourceName += cmSystemTools::GetFilenameWithoutLastExtension(name);
+ std::string::size_type pos = hname.rfind('.');
+ if (pos != std::string::npos) {
+ sf->SourceExtension = hname.substr(pos + 1, hname.size() - pos);
+ if (cmSystemTools::FileIsFullPath(name)) {
+ std::string::size_type pos2 = hname.rfind('/');
+ if (pos2 != std::string::npos) {
+ sf->SourceName = hname.substr(pos2 + 1, pos - pos2 - 1);
+ }
+ }
+ }
+
+ sf->FullPath = hname;
+ return;
+ }
+
+ // Next, try the various source extensions
+ for (std::vector<std::string>::const_iterator ext = sourceExts.begin();
+ ext != sourceExts.end(); ++ext) {
+ hname = pathname;
+ hname += ".";
+ hname += *ext;
+ if (cmSystemTools::FileExists(hname.c_str())) {
+ 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) {
+ hname = pathname;
+ hname += ".";
+ hname += *ext;
+ if (cmSystemTools::FileExists(hname.c_str())) {
+ sf->SourceExtension = *ext;
+ sf->FullPath = hname;
+ return;
+ }
+ }
+
+ 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::vector<std::string>::const_iterator ext = headerExts.begin();
+ ext != headerExts.end(); ++ext) {
+ e << " ." << *ext;
+ }
+ cmSystemTools::Error(e.str().c_str());
+ return;
+}
+
+void CCONV cmSourceFileSetName2(void* arg, const char* name, const char* dir,
+ const char* ext, int headerFileOnly)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ if (sf->RealSourceFile) {
+ // SetName is allowed only on temporary source files created by
+ // the command for building and passing to AddSource.
+ return;
+ }
+
+ // Implement the old SetName method code here.
+ if (headerFileOnly) {
+ sf->Properties.SetProperty("HEADER_FILE_ONLY", "1");
+ }
+ sf->SourceName = name;
+ std::string fname = sf->SourceName;
+ if (ext && strlen(ext)) {
+ fname += ".";
+ fname += ext;
+ }
+ sf->FullPath = cmSystemTools::CollapseFullPath(fname.c_str(), dir);
+ cmSystemTools::ConvertToUnixSlashes(sf->FullPath);
+ sf->SourceExtension = ext;
+}
+
+char* CCONV cmGetFilenameWithoutExtension(const char* name)
+{
+ std::string sres = cmSystemTools::GetFilenameWithoutExtension(name);
+ char* result = (char*)malloc(sres.size() + 1);
+ strcpy(result, sres.c_str());
+ return result;
+}
+
+char* CCONV cmGetFilenamePath(const char* name)
+{
+ std::string sres = cmSystemTools::GetFilenamePath(name);
+ char* result = (char*)malloc(sres.size() + 1);
+ strcpy(result, sres.c_str());
+ return result;
+}
+
+char* CCONV cmCapitalized(const char* name)
+{
+ std::string sres = cmSystemTools::Capitalized(name);
+ char* result = (char*)malloc(sres.size() + 1);
+ strcpy(result, sres.c_str());
+ return result;
+}
+
+void CCONV cmCopyFileIfDifferent(const char* name1, const char* name2)
+{
+ cmSystemTools::CopyFileIfDifferent(name1, name2);
+}
+
+void CCONV cmRemoveFile(const char* name)
+{
+ cmSystemTools::RemoveFile(name);
+}
+
+void CCONV cmDisplayStatus(void* arg, const char* message)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ mf->DisplayStatus(message, -1);
+}
+
+void CCONV cmFree(void* data)
+{
+ free(data);
+}
+
+void CCONV DefineSourceFileProperty(void* arg, const char* name,
+ const char* briefDocs,
+ const char* longDocs, int chained)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ mf->GetState()->DefineProperty(name, cmProperty::SOURCE_FILE, briefDocs,
+ longDocs, chained != 0);
+}
+
+} // close the extern "C" scope
+
+cmCAPI cmStaticCAPI = {
+ cmGetClientData,
+ cmGetTotalArgumentSize,
+ cmFreeArguments,
+ cmSetClientData,
+ cmSetError,
+ cmAddCacheDefinition,
+ cmAddCustomCommand,
+ cmAddDefineFlag,
+ cmAddDefinition,
+ cmAddExecutable,
+ cmAddLibrary,
+ cmAddLinkDirectoryForTarget,
+ cmAddLinkLibraryForTarget,
+ cmAddUtilityCommand,
+ cmCommandExists,
+ cmExecuteCommand,
+ cmExpandSourceListArguments,
+ cmExpandVariablesInString,
+ cmGetCacheMajorVersion,
+ cmGetCacheMinorVersion,
+ cmGetCurrentDirectory,
+ cmGetCurrentOutputDirectory,
+ cmGetDefinition,
+ cmGetHomeDirectory,
+ cmGetHomeOutputDirectory,
+ cmGetMajorVersion,
+ cmGetMinorVersion,
+ cmGetProjectName,
+ cmGetStartDirectory,
+ cmGetStartOutputDirectory,
+ cmIsOn,
+
+ cmAddSource,
+ cmCreateSourceFile,
+ cmDestroySourceFile,
+ cmGetSource,
+ cmSourceFileAddDepend,
+ cmSourceFileGetProperty,
+ cmSourceFileGetPropertyAsBool,
+ cmSourceFileGetSourceName,
+ cmSourceFileGetFullPath,
+ cmSourceFileSetName,
+ cmSourceFileSetName2,
+ cmSourceFileSetProperty,
+
+ cmCapitalized,
+ cmCopyFileIfDifferent,
+ cmGetFilenameWithoutExtension,
+ cmGetFilenamePath,
+ cmRemoveFile,
+ cmFree,
+
+ cmAddCustomCommandToOutput,
+ cmAddCustomCommandToTarget,
+ cmDisplayStatus,
+ cmCreateNewSourceFile,
+ DefineSourceFileProperty,
+};
diff --git a/Source/cmCPluginAPI.h b/Source/cmCPluginAPI.h
new file mode 100644
index 0000000..4d9a9a7
--- /dev/null
+++ b/Source/cmCPluginAPI.h
@@ -0,0 +1,234 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/* This header file defines the API that loadable commands can use. In many
+ of these commands C++ instances of cmMakefile of cmSourceFile are passed
+ in as arguments or returned. In these cases they are passed as a void *
+ argument. In the function prototypes mf is used to represent a makefile
+ and sf is used to represent a source file. The functions are grouped
+ loosely into four groups 1) Utility 2) cmMakefile 3) cmSourceFile 4)
+ cmSystemTools. Within each grouping functions are listed alphabetically */
+/*=========================================================================*/
+#ifndef cmCPluginAPI_h
+#define cmCPluginAPI_h
+
+#define CMAKE_VERSION_MAJOR 2
+#define CMAKE_VERSION_MINOR 5
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __WATCOMC__
+#define CCONV __cdecl
+#else
+#define CCONV
+#endif
+/*=========================================================================
+this is the structure of function entry points that a plugin may call. This
+structure must be kept in sync with the static decaled at the bottom of
+cmCPLuginAPI.cxx
+=========================================================================*/
+typedef struct
+{
+ /*=========================================================================
+ Here we define the set of functions that a plugin may call. The first goup
+ of functions are utility functions that are specific to the plugin API
+ =========================================================================*/
+ /* set/Get the ClientData in the cmLoadedCommandInfo structure, this is how
+ information is passed from the InitialPass to FInalPass for commands
+ that need a FinalPass and need information from the InitialPass */
+ void*(CCONV* GetClientData)(void* info);
+ /* return the summed size in characters of all the arguments */
+ int(CCONV* GetTotalArgumentSize)(int argc, char** argv);
+ /* free all the memory associated with an argc, argv pair */
+ void(CCONV* FreeArguments)(int argc, char** argv);
+ /* set/Get the ClientData in the cmLoadedCommandInfo structure, this is how
+ information is passed from the InitialPass to FInalPass for commands
+ that need a FinalPass and need information from the InitialPass */
+ void(CCONV* SetClientData)(void* info, void* cd);
+ /* when an error occurs, call this function to set the error string */
+ void(CCONV* SetError)(void* info, const char* err);
+
+ /*=========================================================================
+ The following functions all directly map to methods in the cmMakefile
+ class. See cmMakefile.h for descriptions of what each method does. All of
+ these methods take the void * makefile pointer as their first argument.
+ =========================================================================*/
+ void(CCONV* AddCacheDefinition)(void* mf, const char* name,
+ const char* value, const char* doc,
+ int cachetype);
+ void(CCONV* AddCustomCommand)(void* mf, const char* source,
+ const char* command, int numArgs,
+ const char** args, int numDepends,
+ const char** depends, int numOutputs,
+ const char** outputs, const char* target);
+ void(CCONV* AddDefineFlag)(void* mf, const char* definition);
+ void(CCONV* AddDefinition)(void* mf, const char* name, const char* value);
+ void(CCONV* AddExecutable)(void* mf, const char* exename, int numSrcs,
+ const char** srcs, int win32);
+ void(CCONV* AddLibrary)(void* mf, const char* libname, int shared,
+ int numSrcs, const char** srcs);
+ void(CCONV* AddLinkDirectoryForTarget)(void* mf, const char* tgt,
+ const char* d);
+ void(CCONV* AddLinkLibraryForTarget)(void* mf, const char* tgt,
+ const char* libname, int libtype);
+ void(CCONV* AddUtilityCommand)(void* mf, const char* utilityName,
+ const char* command, const char* arguments,
+ int all, int numDepends, const char** depends,
+ int numOutputs, const char** outputs);
+ int(CCONV* CommandExists)(void* mf, const char* name);
+ int(CCONV* ExecuteCommand)(void* mf, const char* name, int numArgs,
+ const char** args);
+ void(CCONV* ExpandSourceListArguments)(void* mf, int argc, const char** argv,
+ int* resArgc, char*** resArgv,
+ unsigned int startArgumentIndex);
+ char*(CCONV* ExpandVariablesInString)(void* mf, const char* source,
+ int escapeQuotes, int atOnly);
+ unsigned int(CCONV* GetCacheMajorVersion)(void* mf);
+ unsigned int(CCONV* GetCacheMinorVersion)(void* mf);
+ const char*(CCONV* GetCurrentDirectory)(void* mf);
+ const char*(CCONV* GetCurrentOutputDirectory)(void* mf);
+ const char*(CCONV* GetDefinition)(void* mf, const char* def);
+ const char*(CCONV* GetHomeDirectory)(void* mf);
+ const char*(CCONV* GetHomeOutputDirectory)(void* mf);
+ unsigned int(CCONV* GetMajorVersion)(void* mf);
+ unsigned int(CCONV* GetMinorVersion)(void* mf);
+ const char*(CCONV* GetProjectName)(void* mf);
+ const char*(CCONV* GetStartDirectory)(void* mf);
+ const char*(CCONV* GetStartOutputDirectory)(void* mf);
+ int(CCONV* IsOn)(void* mf, const char* name);
+
+ /*=========================================================================
+ The following functions are designed to operate or manipulate
+ cmSourceFiles. Please see cmSourceFile.h for additional information on many
+ of these methods. Some of these methods are in cmMakefile.h.
+ =========================================================================*/
+ void*(CCONV* AddSource)(void* mf, void* sf);
+ void*(CCONV* CreateSourceFile)();
+ void(CCONV* DestroySourceFile)(void* sf);
+ void*(CCONV* GetSource)(void* mf, const char* sourceName);
+ void(CCONV* SourceFileAddDepend)(void* sf, const char* depend);
+ const char*(CCONV* SourceFileGetProperty)(void* sf, const char* prop);
+ int(CCONV* SourceFileGetPropertyAsBool)(void* sf, const char* prop);
+ const char*(CCONV* SourceFileGetSourceName)(void* sf);
+ const char*(CCONV* SourceFileGetFullPath)(void* sf);
+ void(CCONV* SourceFileSetName)(void* sf, const char* name, const char* dir,
+ int numSourceExtensions,
+ const char** sourceExtensions,
+ int numHeaderExtensions,
+ const char** headerExtensions);
+ void(CCONV* SourceFileSetName2)(void* sf, const char* name, const char* dir,
+ const char* ext, int headerFileOnly);
+ void(CCONV* SourceFileSetProperty)(void* sf, const char* prop,
+ const char* value);
+
+ /*=========================================================================
+ The following methods are from cmSystemTools.h see that file for specific
+ documentation on each method.
+ =========================================================================*/
+ char*(CCONV* Capitalized)(const char*);
+ void(CCONV* CopyFileIfDifferent)(const char* f1, const char* f2);
+ char*(CCONV* GetFilenameWithoutExtension)(const char*);
+ char*(CCONV* GetFilenamePath)(const char*);
+ void(CCONV* RemoveFile)(const char* f1);
+ void(CCONV* Free)(void*);
+
+ /*=========================================================================
+ The following are new functions added after 1.6
+ =========================================================================*/
+ void(CCONV* AddCustomCommandToOutput)(void* mf, const char* output,
+ const char* command, int numArgs,
+ const char** args,
+ const char* main_dependency,
+ int numDepends, const char** depends);
+ void(CCONV* AddCustomCommandToTarget)(void* mf, const char* target,
+ const char* command, int numArgs,
+ const char** args, int commandType);
+
+ /* display status information */
+ void(CCONV* DisplaySatus)(void* info, const char* message);
+
+ /* new functions added after 2.4 */
+ void*(CCONV* CreateNewSourceFile)(void* mf);
+ void(CCONV* DefineSourceFileProperty)(void* mf, const char* name,
+ const char* briefDocs,
+ const char* longDocs, int chained);
+
+ /* this is the end of the C function stub API structure */
+} cmCAPI;
+
+/*=========================================================================
+CM_PLUGIN_EXPORT should be used by plugins
+=========================================================================*/
+#ifdef _WIN32
+#define CM_PLUGIN_EXPORT __declspec(dllexport)
+#else
+#define CM_PLUGIN_EXPORT
+#endif
+
+/*=========================================================================
+define the different types of cache entries, see cmCacheManager.h for more
+information
+=========================================================================*/
+#define CM_CACHE_BOOL 0
+#define CM_CACHE_PATH 1
+#define CM_CACHE_FILEPATH 2
+#define CM_CACHE_STRING 3
+#define CM_CACHE_INTERNAL 4
+#define CM_CACHE_STATIC 5
+
+/*=========================================================================
+define the different types of compiles a library may be
+=========================================================================*/
+#define CM_LIBRARY_GENERAL 0
+#define CM_LIBRARY_DEBUG 1
+#define CM_LIBRARY_OPTIMIZED 2
+
+/*=========================================================================
+define the different types of custom commands for a target
+=========================================================================*/
+#define CM_PRE_BUILD 0
+#define CM_PRE_LINK 1
+#define CM_POST_BUILD 2
+
+/*=========================================================================
+Finally we define the key data structures and function prototypes
+=========================================================================*/
+typedef const char*(CCONV* CM_DOC_FUNCTION)();
+typedef int(CCONV* CM_INITIAL_PASS_FUNCTION)(void* info, void* mf, int argc,
+ char* []);
+typedef void(CCONV* CM_FINAL_PASS_FUNCTION)(void* info, void* mf);
+typedef void(CCONV* CM_DESTRUCTOR_FUNCTION)(void* info);
+
+typedef struct
+{
+ unsigned long reserved1; /* Reserved for future use. DO NOT USE. */
+ unsigned long reserved2; /* Reserved for future use. DO NOT USE. */
+ cmCAPI* CAPI;
+ int m_Inherited; /* this ivar is no longer used in CMake 2.2 or later */
+ CM_INITIAL_PASS_FUNCTION InitialPass;
+ CM_FINAL_PASS_FUNCTION FinalPass;
+ CM_DESTRUCTOR_FUNCTION Destructor;
+ CM_DOC_FUNCTION GetTerseDocumentation;
+ CM_DOC_FUNCTION GetFullDocumentation;
+ const char* Name;
+ char* Error;
+ void* ClientData;
+} cmLoadedCommandInfo;
+
+typedef void(CCONV* CM_INIT_FUNCTION)(cmLoadedCommandInfo*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
new file mode 100644
index 0000000..9950a84
--- /dev/null
+++ b/Source/cmCTest.cxx
@@ -0,0 +1,2807 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCurl.h" // include before anything that includes windows.h
+
+#include "cmCTest.h"
+
+#include "cmAlgorithms.h"
+#include "cmCTestCommand.h"
+#include "cmCTestStartCommand.h"
+#include "cmDynamicLoader.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmState.h"
+#include "cmVersionMacros.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+#include <cmsys/Base64.h>
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/SystemInformation.hxx>
+
+#include "cmCTestBuildAndTestHandler.h"
+#include "cmCTestBuildHandler.h"
+#include "cmCTestConfigureHandler.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmCTestMemCheckHandler.h"
+#include "cmCTestScriptHandler.h"
+#include "cmCTestSubmitHandler.h"
+#include "cmCTestTestHandler.h"
+#include "cmCTestUpdateHandler.h"
+#include "cmCTestUploadHandler.h"
+
+#include "cmVersion.h"
+
+#include <cmsys/Glob.hxx>
+#include <cmsys/Process.h>
+#include <cmsys/RegularExpression.hxx>
+
+#include <ctype.h>
+#include <float.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include <cm_auto_ptr.hxx>
+
+#include <cm_zlib.h>
+#include <cmsys/Base64.h>
+
+#if defined(__BEOS__) || defined(__HAIKU__)
+#include <be/kernel/OS.h> /* disable_debugger() API. */
+#endif
+
+#define DEBUGOUT \
+ std::cout << __LINE__ << " "; \
+ std::cout
+#define DEBUGERR \
+ std::cerr << __LINE__ << " "; \
+ std::cerr
+
+struct tm* cmCTest::GetNightlyTime(std::string const& str, bool tomorrowtag)
+{
+ struct tm* lctime;
+ time_t tctime = time(CM_NULLPTR);
+ lctime = gmtime(&tctime);
+ char buf[1024];
+ // add todays year day and month to the time in str because
+ // curl_getdate no longer assumes the day is today
+ sprintf(buf, "%d%02d%02d %s", lctime->tm_year + 1900, lctime->tm_mon + 1,
+ lctime->tm_mday, str.c_str());
+ cmCTestLog(this, OUTPUT, "Determine Nightly Start Time"
+ << std::endl
+ << " Specified time: " << str << std::endl);
+ // Convert the nightly start time to seconds. Since we are
+ // providing only a time and a timezone, the current date of
+ // the local machine is assumed. Consequently, nightlySeconds
+ // is the time at which the nightly dashboard was opened or
+ // will be opened on the date of the current client machine.
+ // As such, this time may be in the past or in the future.
+ time_t ntime = curl_getdate(buf, &tctime);
+ cmCTestLog(this, DEBUG, " Get curl time: " << ntime << std::endl);
+ tctime = time(CM_NULLPTR);
+ cmCTestLog(this, DEBUG, " Get the current time: " << tctime << std::endl);
+
+ const int dayLength = 24 * 60 * 60;
+ cmCTestLog(this, DEBUG, "Seconds: " << tctime << std::endl);
+ while (ntime > tctime) {
+ // If nightlySeconds is in the past, this is the current
+ // open dashboard, then return nightlySeconds. If
+ // nightlySeconds is in the future, this is the next
+ // dashboard to be opened, so subtract 24 hours to get the
+ // time of the current open dashboard
+ ntime -= dayLength;
+ cmCTestLog(this, DEBUG, "Pick yesterday" << std::endl);
+ cmCTestLog(this, DEBUG, " Future time, subtract day: " << ntime
+ << std::endl);
+ }
+ while (tctime > (ntime + dayLength)) {
+ ntime += dayLength;
+ cmCTestLog(this, DEBUG, " Past time, add day: " << ntime << std::endl);
+ }
+ cmCTestLog(this, DEBUG, "nightlySeconds: " << ntime << std::endl);
+ cmCTestLog(this, DEBUG, " Current time: " << tctime << " Nightly time: "
+ << ntime << std::endl);
+ if (tomorrowtag) {
+ cmCTestLog(this, OUTPUT, " Use future tag, Add a day" << std::endl);
+ ntime += dayLength;
+ }
+ lctime = gmtime(&ntime);
+ return lctime;
+}
+
+std::string cmCTest::CleanString(const std::string& str)
+{
+ std::string::size_type spos = str.find_first_not_of(" \n\t\r\f\v");
+ std::string::size_type epos = str.find_last_not_of(" \n\t\r\f\v");
+ if (spos == str.npos) {
+ return std::string();
+ }
+ if (epos != str.npos) {
+ epos = epos - spos + 1;
+ }
+ return str.substr(spos, epos);
+}
+
+std::string cmCTest::CurrentTime()
+{
+ time_t currenttime = time(CM_NULLPTR);
+ struct tm* t = localtime(&currenttime);
+ // return ::CleanString(ctime(&currenttime));
+ char current_time[1024];
+ if (this->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);
+ }
+ cmCTestLog(this, DEBUG, " Current_Time: " << current_time << std::endl);
+ return cmCTest::CleanString(current_time);
+}
+
+std::string cmCTest::GetCostDataFile()
+{
+ std::string fname = this->GetCTestConfiguration("CostDataFile");
+ if (fname == "") {
+ fname = this->GetBinaryDir() + "/Testing/Temporary/CTestCostData.txt";
+ }
+ return fname;
+}
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+static size_t HTTPResponseCallback(void* ptr, size_t size, size_t nmemb,
+ void* data)
+{
+ int realsize = (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.c_str())) {
+ 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
+ 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, (void*)&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 (std::string::size_type pos = 0; pos < str.size(); pos++) {
+ unsigned char ch = str[pos];
+ if ((ch > 126 || ch < 32 || ch == '&' || ch == '%' || ch == '+' ||
+ ch == '=' || ch == '@') &&
+ ch != 9) {
+ sprintf(buffer, "%02x;", (unsigned int)ch);
+ ost << buffer;
+ } else {
+ ost << ch;
+ }
+ }
+ return ost.str();
+}
+
+std::string cmCTest::DecodeURL(const std::string& in)
+{
+ std::string out;
+ for (const char* c = in.c_str(); *c; ++c) {
+ if (*c == '%' && isxdigit(*(c + 1)) && isxdigit(*(c + 2))) {
+ char buf[3] = { *(c + 1), *(c + 2), 0 };
+ out.append(1, char(strtoul(buf, CM_NULLPTR, 16)));
+ c += 2;
+ } else {
+ out.append(1, *c);
+ }
+ }
+ return out;
+}
+
+cmCTest::cmCTest()
+{
+ this->LabelSummary = true;
+ this->ParallelLevel = 1;
+ this->ParallelLevelSetInCli = false;
+ this->TestLoad = 0;
+ this->SubmitIndex = 0;
+ this->Failover = false;
+ this->BatchJobs = false;
+ this->ForceNewCTestProcess = false;
+ this->TomorrowTag = false;
+ this->Verbose = false;
+
+ this->Debug = false;
+ this->ShowLineNumbers = false;
+ this->Quiet = false;
+ this->ExtraVerbose = false;
+ this->ProduceXML = false;
+ this->ShowOnly = false;
+ this->RunConfigurationScript = false;
+ this->UseHTTP10 = false;
+ this->PrintLabels = false;
+ this->CompressTestOutput = true;
+ this->CompressMemCheckOutput = true;
+ this->TestModel = cmCTest::EXPERIMENTAL;
+ this->MaxTestNameWidth = 30;
+ this->InteractiveDebugMode = true;
+ this->TimeOut = 0;
+ this->GlobalTimeout = 0;
+ this->LastStopTimeout = 24 * 60 * 60;
+ this->CompressXMLFiles = false;
+ this->CTestConfigFile = "";
+ this->ScheduleType = "";
+ this->StopTime = "";
+ this->NextDayStopTime = false;
+ this->OutputLogFile = CM_NULLPTR;
+ this->OutputLogFileLastTag = -1;
+ this->SuppressUpdatingCTestConfiguration = false;
+ this->DartVersion = 1;
+ this->DropSiteCDash = false;
+ this->OutputTestOutputOnTestFailure = false;
+ this->ComputedCompressTestOutput = false;
+ this->ComputedCompressMemCheckOutput = false;
+ this->RepeatTests = 1; // default to run each test once
+ this->RepeatUntilFail = false;
+ if (const char* outOnFail =
+ cmSystemTools::GetEnv("CTEST_OUTPUT_ON_FAILURE")) {
+ this->OutputTestOutputOnTestFailure = !cmSystemTools::IsOff(outOnFail);
+ }
+ 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");
+
+ // 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->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;
+
+ cmCTest::t_TestingHandlers::iterator it;
+ for (it = this->TestingHandlers.begin(); it != this->TestingHandlers.end();
+ ++it) {
+ it->second->SetCTestInstance(this);
+ }
+
+ // Make sure we can capture the build tool output.
+ cmSystemTools::EnableVSConsoleOutput();
+}
+
+cmCTest::~cmCTest()
+{
+ cmDeleteAll(this->TestingHandlers);
+ this->SetOutputLogFileName(CM_NULLPTR);
+}
+
+void cmCTest::SetParallelLevel(int level)
+{
+ this->ParallelLevel = level < 1 ? 1 : level;
+}
+
+void cmCTest::SetTestLoad(unsigned long load)
+{
+ this->TestLoad = load;
+}
+
+bool cmCTest::ShouldCompressTestOutput()
+{
+ if (!this->ComputedCompressTestOutput) {
+ std::string cdashVersion = this->GetCDashVersion();
+ // version >= 1.6?
+ bool cdashSupportsGzip =
+ cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER,
+ cdashVersion.c_str(), "1.6") ||
+ cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
+ cdashVersion.c_str(), "1.6");
+ this->CompressTestOutput &= cdashSupportsGzip;
+ this->ComputedCompressTestOutput = true;
+ }
+ return this->CompressTestOutput;
+}
+
+bool cmCTest::ShouldCompressMemCheckOutput()
+{
+ if (!this->ComputedCompressMemCheckOutput) {
+ std::string cdashVersion = this->GetCDashVersion();
+
+ bool compressionSupported = cmSystemTools::VersionCompare(
+ cmSystemTools::OP_GREATER, cdashVersion.c_str(), "1.9.0");
+ this->CompressMemCheckOutput &= compressionSupported;
+ this->ComputedCompressMemCheckOutput = true;
+ }
+ return this->CompressMemCheckOutput;
+}
+
+std::string cmCTest::GetCDashVersion()
+{
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ // First query the server. If that fails, fall back to the local setting
+ std::string response;
+ std::string url = "http://";
+ url += this->GetCTestConfiguration("DropSite");
+
+ std::string cdashUri = this->GetCTestConfiguration("DropLocation");
+ cdashUri = cdashUri.substr(0, cdashUri.find("/submit.php"));
+
+ int res = 1;
+ if (!cdashUri.empty()) {
+ url += cdashUri + "/api/getversion.php";
+ res = cmCTest::HTTPRequest(url, cmCTest::HTTP_GET, response, "", "", 3);
+ }
+
+ return res ? this->GetCTestConfiguration("CDashVersion") : response;
+#else
+ return this->GetCTestConfiguration("CDashVersion");
+#endif
+}
+
+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()) {
+ return i->second;
+ }
+
+ // The string does not name a valid part.
+ return PartCount;
+}
+
+int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
+{
+ bool quiet = false;
+ if (command && command->ShouldBeQuiet()) {
+ quiet = true;
+ }
+
+ cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
+ if (!this->InteractiveDebugMode) {
+ this->BlockTestErrorDiagnostics();
+ } else {
+ cmSystemTools::PutEnv("CTEST_INTERACTIVE_DEBUG_MODE=1");
+ }
+
+ this->BinaryDir = binary_dir;
+ cmSystemTools::ConvertToUnixSlashes(this->BinaryDir);
+
+ this->UpdateCTestConfiguration();
+
+ cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
+ if (this->ProduceXML) {
+ cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
+ cmCTestOptionalLog(
+ this, OUTPUT, " Site: "
+ << this->GetCTestConfiguration("Site") << std::endl
+ << " Build name: "
+ << cmCTest::SafeBuildIdField(this->GetCTestConfiguration("BuildName"))
+ << std::endl,
+ quiet);
+ cmCTestOptionalLog(this, DEBUG, "Produce XML is on" << std::endl, quiet);
+ if (this->TestModel == cmCTest::NIGHTLY &&
+ this->GetCTestConfiguration("NightlyStartTime").empty()) {
+ cmCTestOptionalLog(
+ this, WARNING,
+ "WARNING: No nightly start time found please set in CTestConfig.cmake"
+ " or DartConfig.cmake"
+ << std::endl,
+ quiet);
+ cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl,
+ quiet);
+ return 0;
+ }
+ }
+
+ cmake cm;
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator gg(&cm);
+ CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(&gg, cm.GetCurrentSnapshot()));
+ if (!this->ReadCustomConfigurationFileTree(this->BinaryDir.c_str(),
+ mf.get())) {
+ cmCTestOptionalLog(
+ this, DEBUG, "Cannot find custom configuration file tree" << std::endl,
+ quiet);
+ return 0;
+ }
+
+ if (this->ProduceXML) {
+ // Verify "Testing" directory exists:
+ //
+ std::string testingDir = this->BinaryDir + "/Testing";
+ if (cmSystemTools::FileExists(testingDir.c_str())) {
+ if (!cmSystemTools::FileIsDirectory(testingDir)) {
+ cmCTestLog(this, ERROR_MESSAGE, "File "
+ << testingDir
+ << " is in the place of the testing directory"
+ << std::endl);
+ return 0;
+ }
+ } else {
+ if (!cmSystemTools::MakeDirectory(testingDir.c_str())) {
+ cmCTestLog(this, ERROR_MESSAGE, "Cannot create directory "
+ << testingDir << std::endl);
+ return 0;
+ }
+ }
+
+ // Create new "TAG" file or read existing one:
+ //
+ bool createNewTag = true;
+ if (command) {
+ createNewTag = command->ShouldCreateNewTag();
+ }
+
+ std::string tagfile = testingDir + "/TAG";
+ cmsys::ifstream tfin(tagfile.c_str());
+ std::string tag;
+
+ if (createNewTag) {
+ time_t tctime = time(CM_NULLPTR);
+ if (this->TomorrowTag) {
+ tctime += (24 * 60 * 60);
+ }
+ struct tm* lctime = gmtime(&tctime);
+ if (tfin && cmSystemTools::GetLineFromStream(tfin, tag)) {
+ int year = 0;
+ int mon = 0;
+ int day = 0;
+ int hour = 0;
+ int min = 0;
+ sscanf(tag.c_str(), "%04d%02d%02d-%02d%02d", &year, &mon, &day, &hour,
+ &min);
+ if (year != lctime->tm_year + 1900 || mon != lctime->tm_mon + 1 ||
+ day != lctime->tm_mday) {
+ tag = "";
+ }
+ std::string tagmode;
+ if (cmSystemTools::GetLineFromStream(tfin, tagmode)) {
+ if (tagmode.size() > 4 && !this->Parts[PartStart]) {
+ this->TestModel = cmCTest::GetTestModelFromString(tagmode.c_str());
+ }
+ }
+ tfin.close();
+ }
+ if (tag.empty() || (CM_NULLPTR != command) || this->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) {
+ lctime = this->GetNightlyTime(
+ this->GetCTestConfiguration("NightlyStartTime"),
+ this->TomorrowTag);
+ }
+ char datestring[100];
+ sprintf(datestring, "%04d%02d%02d-%02d%02d", lctime->tm_year + 1900,
+ lctime->tm_mon + 1, lctime->tm_mday, lctime->tm_hour,
+ lctime->tm_min);
+ tag = datestring;
+ cmsys::ofstream ofs(tagfile.c_str());
+ if (ofs) {
+ ofs << tag << std::endl;
+ ofs << this->GetTestModelString() << std::endl;
+ }
+ ofs.close();
+ if (CM_NULLPTR == command) {
+ cmCTestOptionalLog(this, OUTPUT, "Create new tag: "
+ << tag << " - " << this->GetTestModelString()
+ << std::endl,
+ quiet);
+ }
+ }
+ } else {
+ if (tfin) {
+ cmSystemTools::GetLineFromStream(tfin, tag);
+ tfin.close();
+ }
+
+ if (tag.empty()) {
+ cmCTestLog(this, ERROR_MESSAGE, "Cannot read existing TAG file in "
+ << testingDir << std::endl);
+ return 0;
+ }
+
+ cmCTestOptionalLog(this, OUTPUT, " Use existing tag: "
+ << tag << " - " << this->GetTestModelString()
+ << std::endl,
+ quiet);
+ }
+
+ this->CurrentTag = tag;
+ }
+
+ return 1;
+}
+
+bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command)
+{
+ std::string src_dir = this->GetCTestConfiguration("SourceDirectory");
+ std::string bld_dir = this->GetCTestConfiguration("BuildDirectory");
+ this->DartVersion = 1;
+ this->DropSiteCDash = false;
+ for (Part p = PartStart; p != PartCount; p = Part(p + 1)) {
+ this->Parts[p].SubmitFiles.clear();
+ }
+
+ cmMakefile* mf = command->GetMakefile();
+ std::string fname;
+
+ std::string src_dir_fname = src_dir;
+ src_dir_fname += "/CTestConfig.cmake";
+ cmSystemTools::ConvertToUnixSlashes(src_dir_fname);
+
+ std::string bld_dir_fname = bld_dir;
+ bld_dir_fname += "/CTestConfig.cmake";
+ cmSystemTools::ConvertToUnixSlashes(bld_dir_fname);
+
+ if (cmSystemTools::FileExists(bld_dir_fname.c_str())) {
+ fname = bld_dir_fname;
+ } else if (cmSystemTools::FileExists(src_dir_fname.c_str())) {
+ fname = src_dir_fname;
+ }
+
+ if (!fname.empty()) {
+ cmCTestOptionalLog(this, OUTPUT, " Reading ctest configuration file: "
+ << fname << std::endl,
+ command->ShouldBeQuiet());
+ bool readit = mf->ReadDependentFile(fname.c_str());
+ if (!readit) {
+ std::string m = "Could not find include file: ";
+ m += fname;
+ command->SetError(m);
+ return false;
+ }
+ } else {
+ cmCTestOptionalLog(this, WARNING,
+ "Cannot locate CTest configuration: in BuildDirectory: "
+ << bld_dir_fname << std::endl,
+ command->ShouldBeQuiet());
+ cmCTestOptionalLog(
+ this, WARNING, "Cannot locate CTest configuration: in SourceDirectory: "
+ << src_dir_fname << std::endl,
+ command->ShouldBeQuiet());
+ }
+
+ this->SetCTestConfigurationFromCMakeVariable(mf, "NightlyStartTime",
+ "CTEST_NIGHTLY_START_TIME",
+ command->ShouldBeQuiet());
+ this->SetCTestConfigurationFromCMakeVariable(mf, "Site", "CTEST_SITE",
+ command->ShouldBeQuiet());
+ this->SetCTestConfigurationFromCMakeVariable(
+ mf, "BuildName", "CTEST_BUILD_NAME", command->ShouldBeQuiet());
+ const char* dartVersion = mf->GetDefinition("CTEST_DART_SERVER_VERSION");
+ if (dartVersion) {
+ this->DartVersion = atoi(dartVersion);
+ if (this->DartVersion < 0) {
+ cmCTestLog(this, ERROR_MESSAGE, "Invalid Dart server version: "
+ << dartVersion << ". Please specify the version number."
+ << std::endl);
+ return false;
+ }
+ }
+ this->DropSiteCDash = mf->IsOn("CTEST_DROP_SITE_CDASH");
+
+ if (!this->Initialize(bld_dir.c_str(), command)) {
+ return false;
+ }
+ cmCTestOptionalLog(this, OUTPUT, " Use "
+ << this->GetTestModelString()
+ << " tag: " << this->GetCurrentTag() << std::endl,
+ command->ShouldBeQuiet());
+ return true;
+}
+
+bool cmCTest::UpdateCTestConfiguration()
+{
+ if (this->SuppressUpdatingCTestConfiguration) {
+ return true;
+ }
+ std::string fileName = this->CTestConfigFile;
+ if (fileName.empty()) {
+ fileName = this->BinaryDir + "/CTestConfiguration.ini";
+ if (!cmSystemTools::FileExists(fileName.c_str())) {
+ fileName = this->BinaryDir + "/DartConfiguration.tcl";
+ }
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ "UpdateCTestConfiguration from :" << fileName << "\n");
+ if (!cmSystemTools::FileExists(fileName.c_str())) {
+ // No need to exit if we are not producing XML
+ if (this->ProduceXML) {
+ cmCTestLog(this, ERROR_MESSAGE, "Cannot find file: " << fileName
+ << std::endl);
+ return false;
+ }
+ } else {
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Parse Config file:" << fileName
+ << "\n");
+ // parse the dart test file
+ cmsys::ifstream fin(fileName.c_str());
+
+ if (!fin) {
+ return false;
+ }
+
+ char buffer[1024];
+ while (fin) {
+ buffer[0] = 0;
+ fin.getline(buffer, 1023);
+ buffer[1023] = 0;
+ std::string line = cmCTest::CleanString(buffer);
+ if (line.empty()) {
+ continue;
+ }
+ while (fin && (line[line.size() - 1] == '\\')) {
+ line = line.substr(0, line.size() - 1);
+ buffer[0] = 0;
+ fin.getline(buffer, 1023);
+ buffer[1023] = 0;
+ line += cmCTest::CleanString(buffer);
+ }
+ if (line[0] == '#') {
+ continue;
+ }
+ std::string::size_type cpos = line.find_first_of(':');
+ if (cpos == line.npos) {
+ continue;
+ }
+ std::string key = line.substr(0, cpos);
+ std::string value =
+ cmCTest::CleanString(line.substr(cpos + 1, line.npos));
+ this->CTestConfiguration[key] = value;
+ }
+ fin.close();
+ }
+ if (!this->GetCTestConfiguration("BuildDirectory").empty()) {
+ this->BinaryDir = this->GetCTestConfiguration("BuildDirectory");
+ cmSystemTools::ChangeDirectory(this->BinaryDir);
+ }
+ this->TimeOut = atoi(this->GetCTestConfiguration("TimeOut").c_str());
+ std::string const& testLoad = this->GetCTestConfiguration("TestLoad");
+ if (!testLoad.empty()) {
+ unsigned long load;
+ if (cmSystemTools::StringToULong(testLoad.c_str(), &load)) {
+ this->SetTestLoad(load);
+ } else {
+ cmCTestLog(this, WARNING,
+ "Invalid value for 'Test Load' : " << testLoad << std::endl);
+ }
+ }
+ if (this->ProduceXML) {
+ this->CompressXMLFiles = cmSystemTools::IsOn(
+ this->GetCTestConfiguration("CompressSubmission").c_str());
+ }
+ return true;
+}
+
+void cmCTest::BlockTestErrorDiagnostics()
+{
+ cmSystemTools::PutEnv("DART_TEST_FROM_DART=1");
+ cmSystemTools::PutEnv("DASHBOARD_TEST_FROM_CTEST=" CMake_VERSION);
+#if defined(_WIN32)
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+#elif defined(__BEOS__) || defined(__HAIKU__)
+ disable_debugger(1);
+#endif
+}
+
+void cmCTest::SetTestModel(int mode)
+{
+ this->InteractiveDebugMode = false;
+ this->TestModel = mode;
+}
+
+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();
+ }
+ return true;
+ }
+ Part p = this->GetPartFromName(ttype);
+ if (p != PartCount) {
+ this->Parts[p].Enable();
+ return true;
+ } else {
+ if (report) {
+ cmCTestLog(this, ERROR_MESSAGE, "Don't know about test \""
+ << ttype << "\" yet..." << std::endl);
+ }
+ return false;
+ }
+}
+
+void cmCTest::Finalize()
+{
+}
+
+bool cmCTest::OpenOutputFile(const std::string& path, const std::string& name,
+ cmGeneratedFileStream& stream, bool compress)
+{
+ std::string testingDir = this->BinaryDir + "/Testing";
+ if (!path.empty()) {
+ testingDir += "/" + path;
+ }
+ if (cmSystemTools::FileExists(testingDir.c_str())) {
+ if (!cmSystemTools::FileIsDirectory(testingDir)) {
+ cmCTestLog(this, ERROR_MESSAGE, "File "
+ << testingDir << " is in the place of the testing directory"
+ << std::endl);
+ return false;
+ }
+ } else {
+ if (!cmSystemTools::MakeDirectory(testingDir.c_str())) {
+ cmCTestLog(this, ERROR_MESSAGE, "Cannot create directory " << testingDir
+ << std::endl);
+ return false;
+ }
+ }
+ std::string filename = testingDir + "/" + name;
+ stream.Open(filename.c_str());
+ if (!stream) {
+ cmCTestLog(this, ERROR_MESSAGE, "Problem opening file: " << filename
+ << std::endl);
+ return false;
+ }
+ if (compress) {
+ if (this->CompressXMLFiles) {
+ stream.SetCompression(true);
+ }
+ }
+ return true;
+}
+
+bool cmCTest::AddIfExists(Part part, const char* file)
+{
+ if (this->CTestFileExists(file)) {
+ this->AddSubmitFile(part, file);
+ } else {
+ std::string name = file;
+ name += ".gz";
+ if (this->CTestFileExists(name)) {
+ this->AddSubmitFile(part, file);
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmCTest::CTestFileExists(const std::string& filename)
+{
+ std::string testingDir =
+ this->BinaryDir + "/Testing/" + this->CurrentTag + "/" + filename;
+ return cmSystemTools::FileExists(testingDir.c_str());
+}
+
+cmCTestGenericHandler* cmCTest::GetInitializedHandler(const char* handler)
+{
+ cmCTest::t_TestingHandlers::iterator it =
+ this->TestingHandlers.find(handler);
+ if (it == this->TestingHandlers.end()) {
+ return CM_NULLPTR;
+ }
+ it->second->Initialize();
+ return it->second;
+}
+
+cmCTestGenericHandler* cmCTest::GetHandler(const char* handler)
+{
+ cmCTest::t_TestingHandlers::iterator it =
+ this->TestingHandlers.find(handler);
+ if (it == this->TestingHandlers.end()) {
+ return CM_NULLPTR;
+ }
+ return it->second;
+}
+
+int cmCTest::ExecuteHandler(const char* shandler)
+{
+ cmCTestGenericHandler* handler = this->GetHandler(shandler);
+ if (!handler) {
+ return -1;
+ }
+ handler->Initialize();
+ return handler->ProcessHandler();
+}
+
+int cmCTest::ProcessTests()
+{
+ int res = 0;
+ bool notest = true;
+ int update_count = 0;
+
+ for (Part p = PartStart; notest && p != PartCount; p = Part(p + 1)) {
+ notest = !this->Parts[p];
+ }
+ if (this->Parts[PartUpdate] && (this->GetRemainingTimeAllowed() - 120 > 0)) {
+ cmCTestGenericHandler* uphandler = this->GetHandler("update");
+ uphandler->SetPersistentOption(
+ "SourceDirectory",
+ this->GetCTestConfiguration("SourceDirectory").c_str());
+ update_count = uphandler->ProcessHandler();
+ if (update_count < 0) {
+ res |= cmCTest::UPDATE_ERRORS;
+ }
+ }
+ if (this->TestModel == cmCTest::CONTINUOUS && !update_count) {
+ return 0;
+ }
+ if (this->Parts[PartConfigure] &&
+ (this->GetRemainingTimeAllowed() - 120 > 0)) {
+ if (this->GetHandler("configure")->ProcessHandler() < 0) {
+ res |= cmCTest::CONFIGURE_ERRORS;
+ }
+ }
+ if (this->Parts[PartBuild] && (this->GetRemainingTimeAllowed() - 120 > 0)) {
+ this->UpdateCTestConfiguration();
+ if (this->GetHandler("build")->ProcessHandler() < 0) {
+ res |= cmCTest::BUILD_ERRORS;
+ }
+ }
+ if ((this->Parts[PartTest] || notest) &&
+ (this->GetRemainingTimeAllowed() - 120 > 0)) {
+ this->UpdateCTestConfiguration();
+ if (this->GetHandler("test")->ProcessHandler() < 0) {
+ res |= cmCTest::TEST_ERRORS;
+ }
+ }
+ if (this->Parts[PartCoverage] &&
+ (this->GetRemainingTimeAllowed() - 120 > 0)) {
+ this->UpdateCTestConfiguration();
+ if (this->GetHandler("coverage")->ProcessHandler() < 0) {
+ res |= cmCTest::COVERAGE_ERRORS;
+ }
+ }
+ if (this->Parts[PartMemCheck] &&
+ (this->GetRemainingTimeAllowed() - 120 > 0)) {
+ this->UpdateCTestConfiguration();
+ if (this->GetHandler("memcheck")->ProcessHandler() < 0) {
+ res |= cmCTest::MEMORY_ERRORS;
+ }
+ }
+ if (!notest) {
+ std::string notes_dir = this->BinaryDir + "/Testing/Notes";
+ if (cmSystemTools::FileIsDirectory(notes_dir)) {
+ cmsys::Directory d;
+ d.Load(notes_dir);
+ unsigned long kk;
+ for (kk = 0; kk < d.GetNumberOfFiles(); kk++) {
+ const char* file = d.GetFile(kk);
+ std::string fullname = notes_dir + "/" + file;
+ if (cmSystemTools::FileExists(fullname.c_str()) &&
+ !cmSystemTools::FileIsDirectory(fullname)) {
+ if (!this->NotesFiles.empty()) {
+ this->NotesFiles += ";";
+ }
+ this->NotesFiles += fullname;
+ this->Parts[PartNotes].Enable();
+ }
+ }
+ }
+ }
+ if (this->Parts[PartNotes]) {
+ this->UpdateCTestConfiguration();
+ if (!this->NotesFiles.empty()) {
+ this->GenerateNotesFile(this->NotesFiles.c_str());
+ }
+ }
+ if (this->Parts[PartSubmit]) {
+ this->UpdateCTestConfiguration();
+ if (this->GetHandler("submit")->ProcessHandler() < 0) {
+ res |= cmCTest::SUBMIT_ERRORS;
+ }
+ }
+ if (res != 0) {
+ cmCTestLog(this, ERROR_MESSAGE, "Errors while running CTest" << std::endl);
+ }
+ return res;
+}
+
+std::string cmCTest::GetTestModelString()
+{
+ if (!this->SpecificTrack.empty()) {
+ return this->SpecificTrack;
+ }
+ switch (this->TestModel) {
+ case cmCTest::NIGHTLY:
+ return "Nightly";
+ case cmCTest::CONTINUOUS:
+ return "Continuous";
+ }
+ return "Experimental";
+}
+
+int cmCTest::GetTestModelFromString(const char* str)
+{
+ if (!str) {
+ return cmCTest::EXPERIMENTAL;
+ }
+ std::string rstr = cmSystemTools::LowerCase(str);
+ if (cmHasLiteralPrefix(rstr.c_str(), "cont")) {
+ return cmCTest::CONTINUOUS;
+ }
+ if (cmHasLiteralPrefix(rstr.c_str(), "nigh")) {
+ return cmCTest::NIGHTLY;
+ }
+ return cmCTest::EXPERIMENTAL;
+}
+
+//######################################################################
+//######################################################################
+//######################################################################
+//######################################################################
+
+int cmCTest::RunMakeCommand(const char* command, std::string& output,
+ int* retVal, const char* dir, int timeout,
+ std::ostream& ofs)
+{
+ // First generate the command and arguments
+ std::vector<std::string> args = cmSystemTools::ParseArguments(command);
+
+ if (args.empty()) {
+ return false;
+ }
+
+ std::vector<const char*> argv;
+ for (std::vector<std::string>::const_iterator a = args.begin();
+ a != args.end(); ++a) {
+ argv.push_back(a->c_str());
+ }
+ argv.push_back(CM_NULLPTR);
+
+ output = "";
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Run command:");
+ std::vector<const char*>::iterator ait;
+ for (ait = argv.begin(); ait != argv.end() && *ait; ++ait) {
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, " \"" << *ait << "\"");
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, std::endl);
+
+ // Now create process object
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ cmsysProcess_SetTimeout(cp, timeout);
+ cmsysProcess_Execute(cp);
+
+ // Initialize tick's
+ std::string::size_type tick = 0;
+ std::string::size_type tick_len = 1024;
+ std::string::size_type tick_line_len = 50;
+
+ char* data;
+ int length;
+ cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, " Each . represents "
+ << tick_len << " bytes of output" << std::endl
+ << " " << std::flush);
+ while (cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR)) {
+ for (int cc = 0; cc < length; ++cc) {
+ if (data[cc] == 0) {
+ data[cc] = '\n';
+ }
+ }
+ output.append(data, length);
+ while (output.size() > (tick * tick_len)) {
+ tick++;
+ cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, "." << std::flush);
+ if (tick % tick_line_len == 0 && tick > 0) {
+ cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
+ " Size: " << int((double(output.size()) / 1024.0) + 1)
+ << "K" << std::endl
+ << " " << std::flush);
+ }
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(data, length));
+ if (ofs) {
+ ofs << cmCTestLogWrite(data, length);
+ }
+ }
+ cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, " Size of output: "
+ << int(double(output.size()) / 1024.0) << "K" << std::endl);
+
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+
+ int result = cmsysProcess_GetState(cp);
+
+ if (result == cmsysProcess_State_Exited) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ "Command exited with the value: " << *retVal << std::endl);
+ } else if (result == cmsysProcess_State_Exception) {
+ *retVal = cmsysProcess_GetExitException(cp);
+ cmCTestLog(this, WARNING, "There was an exception: " << *retVal
+ << std::endl);
+ } else if (result == cmsysProcess_State_Expired) {
+ cmCTestLog(this, WARNING, "There was a timeout" << std::endl);
+ } else if (result == cmsysProcess_State_Error) {
+ output += "\n*** ERROR executing: ";
+ output += cmsysProcess_GetErrorString(cp);
+ output += "\n***The build process failed.";
+ cmCTestLog(this, ERROR_MESSAGE, "There was an error: "
+ << cmsysProcess_GetErrorString(cp) << std::endl);
+ }
+
+ cmsysProcess_Delete(cp);
+
+ return result;
+}
+
+//######################################################################
+//######################################################################
+//######################################################################
+//######################################################################
+
+int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
+ int* retVal, std::ostream* log, double testTimeOut,
+ std::vector<std::string>* environment)
+{
+ bool modifyEnv = (environment && !environment->empty());
+
+ // determine how much time we have
+ double timeout = this->GetRemainingTimeAllowed() - 120;
+ if (this->TimeOut > 0 && this->TimeOut < timeout) {
+ timeout = this->TimeOut;
+ }
+ if (testTimeOut > 0 && testTimeOut < this->GetRemainingTimeAllowed()) {
+ timeout = testTimeOut;
+ }
+
+ // always have at least 1 second if we got to here
+ if (timeout <= 0) {
+ timeout = 1;
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ "Test timeout computed to be: " << timeout << "\n");
+ if (cmSystemTools::SameFile(argv[0], cmSystemTools::GetCTestCommand()) &&
+ !this->ForceNewCTestProcess) {
+ cmCTest inst;
+ inst.ConfigType = this->ConfigType;
+ inst.TimeOut = timeout;
+
+ // Capture output of the child ctest.
+ std::ostringstream oss;
+ inst.SetStreams(&oss, &oss);
+
+ std::vector<std::string> args;
+ for (unsigned int i = 0; i < argv.size(); ++i) {
+ if (argv[i]) {
+ // make sure we pass the timeout in for any build and test
+ // invocations. Since --build-generator is required this is a
+ // good place to check for it, and to add the arguments in
+ if (strcmp(argv[i], "--build-generator") == 0 && timeout > 0) {
+ args.push_back("--test-timeout");
+ std::ostringstream msg;
+ msg << timeout;
+ args.push_back(msg.str());
+ }
+ args.push_back(argv[i]);
+ }
+ }
+ if (log) {
+ *log << "* Run internal CTest" << std::endl;
+ }
+ std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory();
+
+ CM_AUTO_PTR<cmSystemTools::SaveRestoreEnvironment> saveEnv;
+ if (modifyEnv) {
+ saveEnv.reset(new cmSystemTools::SaveRestoreEnvironment);
+ cmSystemTools::AppendEnv(*environment);
+ }
+
+ *retVal = inst.Run(args, output);
+ if (output) {
+ *output += oss.str();
+ }
+ if (log && output) {
+ *log << *output;
+ }
+ cmSystemTools::ChangeDirectory(oldpath);
+ if (output) {
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ "Internal cmCTest object used to run test." << std::endl
+ << *output
+ << std::endl);
+ }
+
+ return cmsysProcess_State_Exited;
+ }
+ std::vector<char> tempOutput;
+ if (output) {
+ *output = "";
+ }
+
+ CM_AUTO_PTR<cmSystemTools::SaveRestoreEnvironment> saveEnv;
+ if (modifyEnv) {
+ saveEnv.reset(new cmSystemTools::SaveRestoreEnvironment);
+ cmSystemTools::AppendEnv(*environment);
+ }
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
+ if (cmSystemTools::GetRunCommandHideConsole()) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ }
+
+ cmsysProcess_SetTimeout(cp, timeout);
+ cmsysProcess_Execute(cp);
+
+ char* data;
+ int length;
+ while (cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR)) {
+ if (output) {
+ tempOutput.insert(tempOutput.end(), data, data + length);
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(data, length));
+ if (log) {
+ log->write(data, length);
+ }
+ }
+
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+ if (output && tempOutput.begin() != tempOutput.end()) {
+ output->append(&*tempOutput.begin(), tempOutput.size());
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "-- Process completed"
+ << std::endl);
+
+ int result = cmsysProcess_GetState(cp);
+
+ if (result == cmsysProcess_State_Exited) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ if (*retVal != 0 && this->OutputTestOutputOnTestFailure) {
+ OutputTestErrors(tempOutput);
+ }
+ } else if (result == cmsysProcess_State_Exception) {
+ if (this->OutputTestOutputOnTestFailure) {
+ OutputTestErrors(tempOutput);
+ }
+ *retVal = cmsysProcess_GetExitException(cp);
+ std::string outerr = "\n*** Exception executing: ";
+ outerr += cmsysProcess_GetExceptionString(cp);
+ if (output) {
+ *output += outerr;
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl
+ << std::flush);
+ } else if (result == cmsysProcess_State_Error) {
+ std::string outerr = "\n*** ERROR executing: ";
+ outerr += cmsysProcess_GetErrorString(cp);
+ if (output) {
+ *output += outerr;
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl
+ << std::flush);
+ }
+ cmsysProcess_Delete(cp);
+
+ return result;
+}
+
+std::string cmCTest::SafeBuildIdField(const std::string& value)
+{
+ std::string safevalue(value);
+
+ if (safevalue != "") {
+ // Disallow non-filename and non-space whitespace characters.
+ // If they occur, replace them with ""
+ //
+ const char* disallowed = "\\:*?\"<>|\n\r\t\f\v";
+
+ if (safevalue.find_first_of(disallowed) != value.npos) {
+ std::string::size_type i = 0;
+ std::string::size_type n = strlen(disallowed);
+ char replace[2];
+ replace[1] = 0;
+
+ for (i = 0; i < n; ++i) {
+ replace[0] = disallowed[i];
+ cmSystemTools::ReplaceString(safevalue, replace, "");
+ }
+ }
+ }
+
+ if (safevalue == "") {
+ safevalue = "(empty)";
+ }
+
+ return safevalue;
+}
+
+void cmCTest::StartXML(cmXMLWriter& xml, bool append)
+{
+ if (this->CurrentTag.empty()) {
+ cmCTestLog(this, ERROR_MESSAGE, "Current Tag empty, this may mean"
+ " NightlStartTime was not set correctly."
+ << std::endl);
+ cmSystemTools::SetFatalErrorOccured();
+ }
+
+ // find out about the system
+ cmsys::SystemInformation info;
+ info.RunCPUCheck();
+ info.RunOSCheck();
+ info.RunMemoryCheck();
+
+ std::string buildname =
+ cmCTest::SafeBuildIdField(this->GetCTestConfiguration("BuildName"));
+ std::string stamp = cmCTest::SafeBuildIdField(this->CurrentTag + "-" +
+ this->GetTestModelString());
+ std::string site =
+ cmCTest::SafeBuildIdField(this->GetCTestConfiguration("Site"));
+
+ xml.StartDocument();
+ xml.StartElement("Site");
+ xml.Attribute("BuildName", buildname);
+ xml.BreakAttributes();
+ xml.Attribute("BuildStamp", stamp);
+ xml.Attribute("Name", site);
+ xml.Attribute("Generator",
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
+ if (append) {
+ xml.Attribute("Append", "true");
+ }
+ xml.Attribute("CompilerName", this->GetCTestConfiguration("Compiler"));
+ xml.Attribute("CompilerVersion",
+ this->GetCTestConfiguration("CompilerVersion"));
+ xml.Attribute("OSName", info.GetOSName());
+ xml.Attribute("Hostname", info.GetHostname());
+ xml.Attribute("OSRelease", info.GetOSRelease());
+ xml.Attribute("OSVersion", info.GetOSVersion());
+ xml.Attribute("OSPlatform", info.GetOSPlatform());
+ xml.Attribute("Is64Bits", info.Is64Bits());
+ xml.Attribute("VendorString", info.GetVendorString());
+ xml.Attribute("VendorID", info.GetVendorID());
+ xml.Attribute("FamilyID", info.GetFamilyID());
+ xml.Attribute("ModelID", info.GetModelID());
+ xml.Attribute("ProcessorCacheSize", info.GetProcessorCacheSize());
+ xml.Attribute("NumberOfLogicalCPU", info.GetNumberOfLogicalCPU());
+ xml.Attribute("NumberOfPhysicalCPU", info.GetNumberOfPhysicalCPU());
+ xml.Attribute("TotalVirtualMemory", info.GetTotalVirtualMemory());
+ xml.Attribute("TotalPhysicalMemory", info.GetTotalPhysicalMemory());
+ xml.Attribute("LogicalProcessorsPerPhysical",
+ info.GetLogicalProcessorsPerPhysical());
+ xml.Attribute("ProcessorClockFrequency", info.GetProcessorClockFrequency());
+
+ std::string changeId = this->GetCTestConfiguration("ChangeId");
+ if (!changeId.empty()) {
+ xml.Attribute("ChangeId", changeId);
+ }
+
+ this->AddSiteProperties(xml);
+}
+
+void cmCTest::AddSiteProperties(cmXMLWriter& xml)
+{
+ cmCTestScriptHandler* ch =
+ static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+ cmake* cm = ch->GetCMake();
+ // if no CMake then this is the old style script and props like
+ // this will not work anyway.
+ if (!cm) {
+ return;
+ }
+ // This code should go when cdash is changed to use labels only
+ const char* subproject = cm->GetState()->GetGlobalProperty("SubProject");
+ if (subproject) {
+ xml.StartElement("Subproject");
+ xml.Attribute("name", subproject);
+ const char* labels =
+ ch->GetCMake()->GetState()->GetGlobalProperty("SubProjectLabels");
+ if (labels) {
+ xml.StartElement("Labels");
+ std::string l = labels;
+ std::vector<std::string> args;
+ cmSystemTools::ExpandListArgument(l, args);
+ for (std::vector<std::string>::iterator i = args.begin();
+ i != args.end(); ++i) {
+ xml.Element("Label", *i);
+ }
+ xml.EndElement();
+ }
+ xml.EndElement();
+ }
+
+ // This code should stay when cdash only does label based sub-projects
+ const char* label = cm->GetState()->GetGlobalProperty("Label");
+ if (label) {
+ xml.StartElement("Labels");
+ xml.Element("Label", label);
+ xml.EndElement();
+ }
+}
+
+void cmCTest::EndXML(cmXMLWriter& xml)
+{
+ xml.EndElement(); // Site
+ xml.EndDocument();
+}
+
+int cmCTest::GenerateCTestNotesOutput(cmXMLWriter& xml,
+ const cmCTest::VectorOfStrings& files)
+{
+ std::string buildname =
+ cmCTest::SafeBuildIdField(this->GetCTestConfiguration("BuildName"));
+ cmCTest::VectorOfStrings::const_iterator it;
+ xml.StartDocument();
+ xml.ProcessingInstruction("xml-stylesheet",
+ "type=\"text/xsl\" "
+ "href=\"Dart/Source/Server/XSL/Build.xsl "
+ "<file:///Dart/Source/Server/XSL/Build.xsl> \"");
+ xml.StartElement("Site");
+ xml.Attribute("BuildName", buildname);
+ xml.Attribute("BuildStamp",
+ this->CurrentTag + "-" + this->GetTestModelString());
+ xml.Attribute("Name", this->GetCTestConfiguration("Site"));
+ xml.Attribute("Generator",
+ std::string("ctest") + cmVersion::GetCMakeVersion());
+ this->AddSiteProperties(xml);
+ xml.StartElement("Notes");
+
+ for (it = files.begin(); it != files.end(); it++) {
+ cmCTestLog(this, OUTPUT, "\tAdd file: " << *it << std::endl);
+ std::string note_time = this->CurrentTime();
+ xml.StartElement("Note");
+ xml.Attribute("Name", *it);
+ xml.Element("Time", cmSystemTools::GetTime());
+ xml.Element("DateTime", note_time);
+ xml.StartElement("Text");
+ cmsys::ifstream ifs(it->c_str());
+ if (ifs) {
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ xml.Content(line);
+ xml.Content("\n");
+ }
+ ifs.close();
+ } else {
+ xml.Content("Problem reading file: " + *it + "\n");
+ cmCTestLog(this, ERROR_MESSAGE, "Problem reading file: "
+ << *it << " while creating notes" << std::endl);
+ }
+ xml.EndElement(); // Text
+ xml.EndElement(); // Note
+ }
+ xml.EndElement(); // Notes
+ xml.EndElement(); // Site
+ xml.EndDocument();
+ return 1;
+}
+
+int cmCTest::GenerateNotesFile(const VectorOfStrings& files)
+{
+ cmGeneratedFileStream ofs;
+ if (!this->OpenOutputFile(this->CurrentTag, "Notes.xml", ofs)) {
+ cmCTestLog(this, ERROR_MESSAGE, "Cannot open notes file" << std::endl);
+ return 1;
+ }
+ cmXMLWriter xml(ofs);
+ this->GenerateCTestNotesOutput(xml, files);
+ return 0;
+}
+
+int cmCTest::GenerateNotesFile(const char* cfiles)
+{
+ if (!cfiles) {
+ return 1;
+ }
+
+ VectorOfStrings files;
+
+ cmCTestLog(this, OUTPUT, "Create notes file" << std::endl);
+
+ files = cmSystemTools::SplitString(cfiles, ';');
+ if (files.empty()) {
+ return 1;
+ }
+
+ return this->GenerateNotesFile(files);
+}
+
+std::string cmCTest::Base64GzipEncodeFile(std::string const& file)
+{
+ std::string tarFile = file + "_temp.tar.gz";
+ std::vector<std::string> files;
+ files.push_back(file);
+
+ if (!cmSystemTools::CreateTar(tarFile.c_str(), files,
+ cmSystemTools::TarCompressGZip, false)) {
+ cmCTestLog(this, ERROR_MESSAGE, "Error creating tar while "
+ "encoding file: "
+ << file << std::endl);
+ return "";
+ }
+ std::string base64 = this->Base64EncodeFile(tarFile);
+ cmSystemTools::RemoveFile(tarFile);
+ return base64;
+}
+
+std::string cmCTest::Base64EncodeFile(std::string const& file)
+{
+ size_t const len = cmSystemTools::FileLength(file);
+ cmsys::ifstream ifs(file.c_str(), std::ios::in
+#ifdef _WIN32
+ | std::ios::binary
+#endif
+ );
+ unsigned char* file_buffer = new unsigned char[len + 1];
+ ifs.read(reinterpret_cast<char*>(file_buffer), len);
+ ifs.close();
+
+ unsigned char* encoded_buffer = new unsigned char[(len * 3) / 2 + 5];
+
+ size_t const rlen = cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1);
+
+ std::string base64 = "";
+ for (size_t i = 0; i < rlen; i++) {
+ base64 += encoded_buffer[i];
+ }
+ delete[] file_buffer;
+ delete[] encoded_buffer;
+
+ return base64;
+}
+
+bool cmCTest::SubmitExtraFiles(const VectorOfStrings& files)
+{
+ VectorOfStrings::const_iterator it;
+ for (it = files.begin(); it != files.end(); ++it) {
+ if (!cmSystemTools::FileExists(it->c_str())) {
+ cmCTestLog(this, ERROR_MESSAGE, "Cannot find extra file: "
+ << *it << " to submit." << std::endl;);
+ return false;
+ }
+ this->AddSubmitFile(PartExtraFiles, it->c_str());
+ }
+ return true;
+}
+
+bool cmCTest::SubmitExtraFiles(const char* cfiles)
+{
+ if (!cfiles) {
+ return 1;
+ }
+
+ VectorOfStrings files;
+
+ cmCTestLog(this, OUTPUT, "Submit extra files" << std::endl);
+
+ files = cmSystemTools::SplitString(cfiles, ';');
+ if (files.empty()) {
+ return 1;
+ }
+
+ return this->SubmitExtraFiles(files);
+}
+
+// for a -D argument convert the next argument into
+// the proper list of dashboard steps via SetTest
+bool cmCTest::AddTestsForDashboardType(std::string& targ)
+{
+ if (targ == "Experimental") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Start");
+ this->SetTest("Configure");
+ this->SetTest("Build");
+ this->SetTest("Test");
+ this->SetTest("Coverage");
+ this->SetTest("Submit");
+ } else if (targ == "ExperimentalStart") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Start");
+ } else if (targ == "ExperimentalUpdate") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Update");
+ } else if (targ == "ExperimentalConfigure") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Configure");
+ } else if (targ == "ExperimentalBuild") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Build");
+ } else if (targ == "ExperimentalTest") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Test");
+ } else if (targ == "ExperimentalMemCheck" || targ == "ExperimentalPurify") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("MemCheck");
+ } else if (targ == "ExperimentalCoverage") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Coverage");
+ } else if (targ == "ExperimentalSubmit") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Submit");
+ } else if (targ == "Continuous") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Start");
+ this->SetTest("Update");
+ this->SetTest("Configure");
+ this->SetTest("Build");
+ this->SetTest("Test");
+ this->SetTest("Coverage");
+ this->SetTest("Submit");
+ } else if (targ == "ContinuousStart") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Start");
+ } else if (targ == "ContinuousUpdate") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Update");
+ } else if (targ == "ContinuousConfigure") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Configure");
+ } else if (targ == "ContinuousBuild") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Build");
+ } else if (targ == "ContinuousTest") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Test");
+ } else if (targ == "ContinuousMemCheck" || targ == "ContinuousPurify") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("MemCheck");
+ } else if (targ == "ContinuousCoverage") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Coverage");
+ } else if (targ == "ContinuousSubmit") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Submit");
+ } else if (targ == "Nightly") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Start");
+ this->SetTest("Update");
+ this->SetTest("Configure");
+ this->SetTest("Build");
+ this->SetTest("Test");
+ this->SetTest("Coverage");
+ this->SetTest("Submit");
+ } else if (targ == "NightlyStart") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Start");
+ } else if (targ == "NightlyUpdate") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Update");
+ } else if (targ == "NightlyConfigure") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Configure");
+ } else if (targ == "NightlyBuild") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Build");
+ } else if (targ == "NightlyTest") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Test");
+ } else if (targ == "NightlyMemCheck" || targ == "NightlyPurify") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("MemCheck");
+ } else if (targ == "NightlyCoverage") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Coverage");
+ } else if (targ == "NightlySubmit") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Submit");
+ } else if (targ == "MemoryCheck") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Start");
+ this->SetTest("Configure");
+ this->SetTest("Build");
+ this->SetTest("MemCheck");
+ this->SetTest("Coverage");
+ this->SetTest("Submit");
+ } else if (targ == "NightlyMemoryCheck") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Start");
+ this->SetTest("Update");
+ this->SetTest("Configure");
+ this->SetTest("Build");
+ this->SetTest("MemCheck");
+ this->SetTest("Coverage");
+ this->SetTest("Submit");
+ } else {
+ return false;
+ }
+ return true;
+}
+
+void cmCTest::ErrorMessageUnknownDashDValue(std::string& val)
+{
+ cmCTestLog(this, ERROR_MESSAGE,
+ "CTest -D called with incorrect option: " << val << std::endl);
+
+ cmCTestLog(
+ this, ERROR_MESSAGE, "Available options are:"
+ << std::endl
+ << " ctest -D Continuous" << std::endl
+ << " ctest -D Continuous(Start|Update|Configure|Build)" << std::endl
+ << " ctest -D Continuous(Test|Coverage|MemCheck|Submit)" << std::endl
+ << " ctest -D Experimental" << std::endl
+ << " ctest -D Experimental(Start|Update|Configure|Build)" << std::endl
+ << " ctest -D Experimental(Test|Coverage|MemCheck|Submit)" << std::endl
+ << " ctest -D Nightly" << std::endl
+ << " ctest -D Nightly(Start|Update|Configure|Build)" << std::endl
+ << " ctest -D Nightly(Test|Coverage|MemCheck|Submit)" << std::endl
+ << " ctest -D NightlyMemoryCheck" << std::endl);
+}
+
+bool cmCTest::CheckArgument(const std::string& arg, const char* varg1,
+ const char* varg2)
+{
+ return (varg1 && arg == varg1) || (varg2 && arg == varg2);
+}
+
+// Processes one command line argument (and its arguments if any)
+// for many simple options and then returns
+bool cmCTest::HandleCommandLineArguments(size_t& i,
+ std::vector<std::string>& args,
+ std::string& errormsg)
+{
+ std::string arg = args[i];
+ if (this->CheckArgument(arg, "-F")) {
+ this->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;
+ } else if (arg.find("-j") == 0) {
+ int plevel = atoi(arg.substr(2).c_str());
+ this->SetParallelLevel(plevel);
+ this->ParallelLevelSetInCli = true;
+ }
+ if (this->CheckArgument(arg, "--repeat-until-fail")) {
+ if (i >= args.size() - 1) {
+ errormsg = "'--repeat-until-fail' requires an argument";
+ return false;
+ }
+ i++;
+ long repeat = 1;
+ if (!cmSystemTools::StringToLong(args[i].c_str(), &repeat)) {
+ errormsg =
+ "'--repeat-until-fail' given non-integer value '" + args[i] + "'";
+ return false;
+ }
+ this->RepeatTests = static_cast<int>(repeat);
+ if (repeat > 1) {
+ this->RepeatUntilFail = true;
+ }
+ }
+
+ if (this->CheckArgument(arg, "--test-load") && i < args.size() - 1) {
+ i++;
+ unsigned long load;
+ if (cmSystemTools::StringToULong(args[i].c_str(), &load)) {
+ this->SetTestLoad(load);
+ } else {
+ cmCTestLog(this, WARNING,
+ "Invalid value for 'Test Load' : " << args[i] << std::endl);
+ }
+ }
+
+ if (this->CheckArgument(arg, "--no-compress-output")) {
+ this->CompressTestOutput = false;
+ this->CompressMemCheckOutput = false;
+ }
+
+ if (this->CheckArgument(arg, "--print-labels")) {
+ this->PrintLabels = true;
+ }
+
+ if (this->CheckArgument(arg, "--http1.0")) {
+ this->UseHTTP10 = true;
+ }
+
+ if (this->CheckArgument(arg, "--timeout") && i < args.size() - 1) {
+ i++;
+ double timeout = (double)atof(args[i].c_str());
+ this->GlobalTimeout = timeout;
+ }
+
+ if (this->CheckArgument(arg, "--stop-time") && i < args.size() - 1) {
+ i++;
+ this->SetStopTime(args[i]);
+ }
+
+ if (this->CheckArgument(arg, "-C", "--build-config") &&
+ i < args.size() - 1) {
+ i++;
+ this->SetConfigType(args[i].c_str());
+ }
+
+ if (this->CheckArgument(arg, "--debug")) {
+ this->Debug = true;
+ this->ShowLineNumbers = true;
+ }
+ if (this->CheckArgument(arg, "--track") && i < args.size() - 1) {
+ i++;
+ this->SpecificTrack = args[i];
+ }
+ if (this->CheckArgument(arg, "--show-line-numbers")) {
+ this->ShowLineNumbers = true;
+ }
+ if (this->CheckArgument(arg, "--no-label-summary")) {
+ this->LabelSummary = false;
+ }
+ if (this->CheckArgument(arg, "-Q", "--quiet")) {
+ this->Quiet = true;
+ }
+ if (this->CheckArgument(arg, "-V", "--verbose")) {
+ this->Verbose = true;
+ }
+ if (this->CheckArgument(arg, "-B")) {
+ this->BatchJobs = true;
+ }
+ if (this->CheckArgument(arg, "-VV", "--extra-verbose")) {
+ this->ExtraVerbose = true;
+ this->Verbose = true;
+ }
+ if (this->CheckArgument(arg, "--output-on-failure")) {
+ this->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));
+ }
+ } else {
+ cmCTestLog(this, WARNING,
+ "Invalid value for '--test-output-size-passed': " << args[i]
+ << "\n");
+ }
+ }
+ if (this->CheckArgument(arg, "--test-output-size-failed") &&
+ 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->SetTestOutputSizeFailed(int(outputSize));
+ }
+ } else {
+ cmCTestLog(this, WARNING,
+ "Invalid value for '--test-output-size-failed': " << args[i]
+ << "\n");
+ }
+ }
+ if (this->CheckArgument(arg, "-N", "--show-only")) {
+ this->ShowOnly = true;
+ }
+
+ if (this->CheckArgument(arg, "-O", "--output-log") && i < args.size() - 1) {
+ i++;
+ this->SetOutputLogFileName(args[i].c_str());
+ }
+
+ if (this->CheckArgument(arg, "--tomorrow-tag")) {
+ this->TomorrowTag = true;
+ }
+ if (this->CheckArgument(arg, "--force-new-ctest-process")) {
+ this->ForceNewCTestProcess = true;
+ }
+ if (this->CheckArgument(arg, "-W", "--max-width") && i < args.size() - 1) {
+ i++;
+ this->MaxTestNameWidth = atoi(args[i].c_str());
+ }
+ if (this->CheckArgument(arg, "--interactive-debug-mode") &&
+ i < args.size() - 1) {
+ i++;
+ this->InteractiveDebugMode = cmSystemTools::IsOn(args[i].c_str());
+ }
+ 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;
+ }
+ }
+
+ if (this->CheckArgument(arg, "--overwrite") && i < args.size() - 1) {
+ i++;
+ this->AddCTestConfigurationOverwrite(args[i]);
+ }
+ if (this->CheckArgument(arg, "-A", "--add-notes") && i < args.size() - 1) {
+ this->ProduceXML = true;
+ this->SetTest("Notes");
+ i++;
+ this->SetNotesFiles(args[i].c_str());
+ }
+
+ // options that control what tests are run
+ 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());
+ }
+ if (this->CheckArgument(arg, "-U", "--union")) {
+ this->GetHandler("test")->SetPersistentOption("UseUnion", "true");
+ this->GetHandler("memcheck")->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());
+ }
+ 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());
+ }
+ if (this->CheckArgument(arg, "-LE", "--label-exclude") &&
+ i < args.size() - 1) {
+ i++;
+ this->GetHandler("test")->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());
+ }
+
+ if (this->CheckArgument(arg, "--rerun-failed")) {
+ this->GetHandler("test")->SetPersistentOption("RerunFailed", "true");
+ this->GetHandler("memcheck")->SetPersistentOption("RerunFailed", "true");
+ }
+ return true;
+}
+
+// handle the -S -SR and -SP arguments
+void cmCTest::HandleScriptArguments(size_t& i, std::vector<std::string>& args,
+ bool& SRArgumentSpecified)
+{
+ std::string arg = args[i];
+ if (this->CheckArgument(arg, "-SP", "--script-new-process") &&
+ i < args.size() - 1) {
+ this->RunConfigurationScript = true;
+ i++;
+ cmCTestScriptHandler* ch =
+ static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+ // -SR is an internal argument, -SP should be ignored when it is passed
+ if (!SRArgumentSpecified) {
+ ch->AddConfigurationScript(args[i].c_str(), false);
+ }
+ }
+
+ if (this->CheckArgument(arg, "-SR", "--script-run") && i < args.size() - 1) {
+ SRArgumentSpecified = true;
+ this->RunConfigurationScript = true;
+ i++;
+ cmCTestScriptHandler* ch =
+ static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+ ch->AddConfigurationScript(args[i].c_str(), true);
+ }
+
+ if (this->CheckArgument(arg, "-S", "--script") && i < args.size() - 1) {
+ this->RunConfigurationScript = true;
+ i++;
+ cmCTestScriptHandler* ch =
+ static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+ // -SR is an internal argument, -S should be ignored when it is passed
+ if (!SRArgumentSpecified) {
+ ch->AddConfigurationScript(args[i].c_str(), true);
+ }
+ }
+}
+
+bool cmCTest::AddVariableDefinition(const std::string& arg)
+{
+ std::string name;
+ std::string value;
+ cmState::CacheEntryType type = cmState::UNINITIALIZED;
+
+ if (cmake::ParseCacheEntry(arg, name, value, type)) {
+ this->Definitions[name] = value;
+ return true;
+ }
+
+ return false;
+}
+
+// the main entry point of ctest, called from main
+int cmCTest::Run(std::vector<std::string>& args, std::string* output)
+{
+ const char* ctestExec = "ctest";
+ bool cmakeAndTest = false;
+ bool executeTests = true;
+ bool SRArgumentSpecified = false;
+
+ // copy the command line
+ this->InitialCommandLineArguments.insert(
+ this->InitialCommandLineArguments.end(), args.begin(), args.end());
+
+ // process the command line arguments
+ for (size_t i = 1; i < args.size(); ++i) {
+ // handle the simple commandline arguments
+ std::string errormsg;
+ if (!this->HandleCommandLineArguments(i, args, errormsg)) {
+ cmSystemTools::Error(errormsg.c_str());
+ return 1;
+ }
+
+ // handle the script arguments -S -SR -SP
+ this->HandleScriptArguments(i, args, SRArgumentSpecified);
+
+ // handle a request for a dashboard
+ std::string arg = args[i];
+ if (this->CheckArgument(arg, "-D", "--dashboard") && i < args.size() - 1) {
+ this->ProduceXML = true;
+ i++;
+ std::string targ = args[i];
+ // AddTestsForDashboard parses the dashboard type and converts it
+ // into the separate stages
+ if (!this->AddTestsForDashboardType(targ)) {
+ if (!this->AddVariableDefinition(targ)) {
+ this->ErrorMessageUnknownDashDValue(targ);
+ executeTests = false;
+ }
+ }
+ }
+
+ // If it's not exactly -D, but it starts with -D, then try to parse out
+ // a variable definition from it, same as CMake does. Unsuccessful
+ // attempts are simply ignored since previous ctest versions ignore
+ // this too. (As well as many other unknown command line args.)
+ //
+ if (arg != "-D" && cmSystemTools::StringStartsWith(arg.c_str(), "-D")) {
+ std::string input = arg.substr(2);
+ this->AddVariableDefinition(input);
+ }
+
+ if (this->CheckArgument(arg, "-T", "--test-action") &&
+ (i < args.size() - 1)) {
+ this->ProduceXML = true;
+ i++;
+ if (!this->SetTest(args[i].c_str(), false)) {
+ executeTests = false;
+ cmCTestLog(this, ERROR_MESSAGE,
+ "CTest -T called with incorrect option: " << args[i]
+ << std::endl);
+ cmCTestLog(this, ERROR_MESSAGE, "Available options are:"
+ << std::endl
+ << " " << ctestExec << " -T all" << std::endl
+ << " " << ctestExec << " -T start" << std::endl
+ << " " << ctestExec << " -T update" << std::endl
+ << " " << ctestExec << " -T configure" << std::endl
+ << " " << ctestExec << " -T build" << std::endl
+ << " " << ctestExec << " -T test" << std::endl
+ << " " << ctestExec << " -T coverage" << std::endl
+ << " " << ctestExec << " -T memcheck" << std::endl
+ << " " << ctestExec << " -T notes" << std::endl
+ << " " << ctestExec << " -T submit" << std::endl);
+ }
+ }
+
+ // what type of test model
+ if (this->CheckArgument(arg, "-M", "--test-model") &&
+ (i < args.size() - 1)) {
+ i++;
+ std::string const& str = args[i];
+ if (cmSystemTools::LowerCase(str) == "nightly") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ } else if (cmSystemTools::LowerCase(str) == "continuous") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ } else if (cmSystemTools::LowerCase(str) == "experimental") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ } else {
+ executeTests = false;
+ cmCTestLog(this, ERROR_MESSAGE,
+ "CTest -M called with incorrect option: " << str
+ << std::endl);
+ cmCTestLog(this, ERROR_MESSAGE, "Available options are:"
+ << std::endl
+ << " " << ctestExec << " -M Continuous" << std::endl
+ << " " << ctestExec << " -M Experimental" << std::endl
+ << " " << ctestExec << " -M Nightly" << std::endl);
+ }
+ }
+
+ if (this->CheckArgument(arg, "--extra-submit") && i < args.size() - 1) {
+ this->ProduceXML = true;
+ this->SetTest("Submit");
+ i++;
+ if (!this->SubmitExtraFiles(args[i].c_str())) {
+ return 0;
+ }
+ }
+
+ // --build-and-test options
+ if (this->CheckArgument(arg, "--build-and-test") && i < args.size() - 1) {
+ cmakeAndTest = true;
+ }
+
+ if (this->CheckArgument(arg, "--schedule-random")) {
+ this->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
+ cmCTest::t_TestingHandlers::iterator it;
+ for (it = this->TestingHandlers.begin(); it != this->TestingHandlers.end();
+ ++it) {
+ if (!it->second->ProcessCommandLineArguments(arg, i, args)) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Problem parsing command line arguments within a handler");
+ return 0;
+ }
+ }
+ } // the close of the for argument loop
+
+ if (!this->ParallelLevelSetInCli) {
+ if (const char* parallel = cmSystemTools::GetEnv("CTEST_PARALLEL_LEVEL")) {
+ int plevel = atoi(parallel);
+ this->SetParallelLevel(plevel);
+ }
+ }
+
+ // now what sould cmake do? if --build-and-test was specified then
+ // we run the build and test handler and return
+ if (cmakeAndTest) {
+ this->Verbose = true;
+ cmCTestBuildAndTestHandler* handler =
+ static_cast<cmCTestBuildAndTestHandler*>(this->GetHandler("buildtest"));
+ int retv = handler->ProcessHandler();
+ *output = handler->GetOutput();
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ cmDynamicLoader::FlushCache();
+#endif
+ if (retv != 0) {
+ cmCTestLog(this, DEBUG,
+ "build and test failing returning: " << retv << std::endl);
+ }
+ return retv;
+ }
+
+ if (executeTests) {
+ int res;
+ // call process directory
+ if (this->RunConfigurationScript) {
+ if (this->ExtraVerbose) {
+ cmCTestLog(this, OUTPUT, "* Extra verbosity turned on" << std::endl);
+ }
+ cmCTest::t_TestingHandlers::iterator it;
+ for (it = this->TestingHandlers.begin();
+ it != this->TestingHandlers.end(); ++it) {
+ it->second->SetVerbose(this->ExtraVerbose);
+ it->second->SetSubmitIndex(this->SubmitIndex);
+ }
+ this->GetHandler("script")->SetVerbose(this->Verbose);
+ res = this->GetHandler("script")->ProcessHandler();
+ if (res != 0) {
+ cmCTestLog(this, DEBUG,
+ "running script failing returning: " << res << std::endl);
+ }
+
+ } 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;
+ cmCTest::t_TestingHandlers::iterator it;
+ for (it = this->TestingHandlers.begin();
+ it != this->TestingHandlers.end(); ++it) {
+ it->second->SetVerbose(this->Verbose);
+ it->second->SetSubmitIndex(this->SubmitIndex);
+ }
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ if (!this->Initialize(cwd.c_str(), CM_NULLPTR)) {
+ res = 12;
+ cmCTestLog(this, ERROR_MESSAGE, "Problem initializing the dashboard."
+ << std::endl);
+ } else {
+ res = this->ProcessTests();
+ }
+ this->Finalize();
+ }
+ if (res != 0) {
+ cmCTestLog(this, DEBUG,
+ "Running a test(s) failed returning : " << res << std::endl);
+ }
+ return res;
+ }
+
+ return 1;
+}
+
+void cmCTest::SetNotesFiles(const char* notes)
+{
+ if (!notes) {
+ return;
+ }
+ this->NotesFiles = notes;
+}
+
+void cmCTest::SetStopTime(std::string const& time)
+{
+ this->StopTime = time;
+ this->DetermineNextDayStop();
+}
+
+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);
+
+ std::string fname = dir;
+ fname += "/CTestCustom.cmake";
+ cmCTestLog(this, DEBUG, "* Check for file: " << fname << std::endl);
+ if (cmSystemTools::FileExists(fname.c_str())) {
+ cmCTestLog(this, DEBUG, "* Read custom CTest configuration file: "
+ << fname << std::endl);
+ bool erroroc = cmSystemTools::GetErrorOccuredFlag();
+ cmSystemTools::ResetErrorOccuredFlag();
+
+ if (!mf->ReadListFile(fname.c_str()) ||
+ cmSystemTools::GetErrorOccuredFlag()) {
+ cmCTestLog(this, ERROR_MESSAGE, "Problem reading custom configuration: "
+ << fname << std::endl);
+ }
+ found = true;
+ if (erroroc) {
+ cmSystemTools::SetErrorOccured();
+ }
+ }
+
+ std::string rexpr = dir;
+ rexpr += "/CTestCustom.ctest";
+ cmCTestLog(this, DEBUG, "* Check for file: " << rexpr << std::endl);
+ if (!found && cmSystemTools::FileExists(rexpr.c_str())) {
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.FindFiles(rexpr);
+ std::vector<std::string>& files = gl.GetFiles();
+ std::vector<std::string>::iterator fileIt;
+ for (fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
+ cmCTestLog(this, DEBUG, "* Read custom CTest configuration file: "
+ << *fileIt << std::endl);
+ if (!mf->ReadListFile(fileIt->c_str()) ||
+ cmSystemTools::GetErrorOccuredFlag()) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Problem reading custom configuration: " << *fileIt
+ << std::endl);
+ }
+ }
+ found = true;
+ }
+
+ if (found) {
+ cmCTest::t_TestingHandlers::iterator it;
+ for (it = this->TestingHandlers.begin(); it != this->TestingHandlers.end();
+ ++it) {
+ cmCTestLog(this, DEBUG,
+ "* Read custom CTest configuration vectors for handler: "
+ << it->first << " (" << it->second << ")" << std::endl);
+ it->second->PopulateCustomVectors(mf);
+ }
+ }
+
+ return 1;
+}
+
+void cmCTest::PopulateCustomVector(cmMakefile* mf, const std::string& def,
+ std::vector<std::string>& vec)
+{
+ const char* dval = mf->GetDefinition(def);
+ if (!dval) {
+ return;
+ }
+ cmCTestLog(this, DEBUG, "PopulateCustomVector: " << def << std::endl);
+
+ vec.clear();
+ cmSystemTools::ExpandListArgument(dval, vec);
+
+ for (std::vector<std::string>::const_iterator it = vec.begin();
+ it != vec.end(); ++it) {
+ cmCTestLog(this, DEBUG, " -- " << *it << std::endl);
+ }
+}
+
+void cmCTest::PopulateCustomInteger(cmMakefile* mf, const std::string& def,
+ int& val)
+{
+ const char* dval = mf->GetDefinition(def);
+ if (!dval) {
+ return;
+ }
+ val = atoi(dval);
+}
+
+std::string cmCTest::GetShortPathToFile(const char* cfname)
+{
+ const std::string& sourceDir = cmSystemTools::CollapseFullPath(
+ this->GetCTestConfiguration("SourceDirectory"));
+ const std::string& buildDir = cmSystemTools::CollapseFullPath(
+ this->GetCTestConfiguration("BuildDirectory"));
+ std::string fname = cmSystemTools::CollapseFullPath(cfname);
+
+ // Find relative paths to both directories
+ std::string srcRelpath =
+ cmSystemTools::RelativePath(sourceDir.c_str(), fname.c_str());
+ std::string bldRelpath =
+ cmSystemTools::RelativePath(buildDir.c_str(), fname.c_str());
+
+ // If any contains "." it is not parent directory
+ bool inSrc = srcRelpath.find("..") == srcRelpath.npos;
+ bool inBld = bldRelpath.find("..") == bldRelpath.npos;
+ // TODO: Handle files with .. in their name
+
+ std::string* res = CM_NULLPTR;
+
+ if (inSrc && inBld) {
+ // If both have relative path with no dots, pick the shorter one
+ if (srcRelpath.size() < bldRelpath.size()) {
+ res = &srcRelpath;
+ } else {
+ res = &bldRelpath;
+ }
+ } else if (inSrc) {
+ res = &srcRelpath;
+ } else if (inBld) {
+ res = &bldRelpath;
+ }
+
+ std::string path;
+
+ if (!res) {
+ path = fname;
+ } else {
+ cmSystemTools::ConvertToUnixSlashes(*res);
+
+ path = "./" + *res;
+ if (path[path.size() - 1] == '/') {
+ path = path.substr(0, path.size() - 1);
+ }
+ }
+
+ cmsys::SystemTools::ReplaceString(path, ":", "_");
+ cmsys::SystemTools::ReplaceString(path, " ", "_");
+ return path;
+}
+
+std::string cmCTest::GetCTestConfiguration(const std::string& name)
+{
+ if (this->CTestConfigurationOverwrites.find(name) !=
+ this->CTestConfigurationOverwrites.end()) {
+ return this->CTestConfigurationOverwrites[name];
+ }
+ return this->CTestConfiguration[name];
+}
+
+void cmCTest::EmptyCTestConfiguration()
+{
+ this->CTestConfiguration.clear();
+}
+
+void cmCTest::DetermineNextDayStop()
+{
+ struct tm* lctime;
+ time_t current_time = time(CM_NULLPTR);
+ lctime = gmtime(&current_time);
+ int gm_hour = lctime->tm_hour;
+ time_t gm_time = mktime(lctime);
+ lctime = localtime(&current_time);
+ int local_hour = lctime->tm_hour;
+
+ int tzone_offset = local_hour - gm_hour;
+ if (gm_time > current_time && gm_hour < local_hour) {
+ // this means gm_time is on the next day
+ tzone_offset -= 24;
+ } else if (gm_time < current_time && gm_hour > local_hour) {
+ // this means gm_time is on the previous day
+ tzone_offset += 24;
+ }
+
+ tzone_offset *= 100;
+ char buf[1024];
+ sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900,
+ lctime->tm_mon + 1, lctime->tm_mday, this->StopTime.c_str(),
+ tzone_offset);
+
+ time_t stop_time = curl_getdate(buf, &current_time);
+
+ if (stop_time < current_time) {
+ this->NextDayStopTime = true;
+ }
+}
+
+void cmCTest::SetCTestConfiguration(const char* name, const char* value,
+ bool suppress)
+{
+ cmCTestOptionalLog(this, HANDLER_VERBOSE_OUTPUT, "SetCTestConfiguration:"
+ << name << ":" << (value ? value : "(null)") << "\n",
+ suppress);
+
+ if (!name) {
+ return;
+ }
+ if (!value) {
+ this->CTestConfiguration.erase(name);
+ return;
+ }
+ this->CTestConfiguration[name] = value;
+}
+
+std::string cmCTest::GetCurrentTag()
+{
+ return this->CurrentTag;
+}
+
+std::string cmCTest::GetBinaryDir()
+{
+ return this->BinaryDir;
+}
+
+std::string const& cmCTest::GetConfigType()
+{
+ return this->ConfigType;
+}
+
+bool cmCTest::GetShowOnly()
+{
+ return this->ShowOnly;
+}
+
+int cmCTest::GetMaxTestNameWidth() const
+{
+ return this->MaxTestNameWidth;
+}
+
+void cmCTest::SetProduceXML(bool v)
+{
+ this->ProduceXML = v;
+}
+
+bool cmCTest::GetProduceXML()
+{
+ return this->ProduceXML;
+}
+
+const char* cmCTest::GetSpecificTrack()
+{
+ if (this->SpecificTrack.empty()) {
+ return CM_NULLPTR;
+ }
+ return this->SpecificTrack.c_str();
+}
+
+void cmCTest::SetSpecificTrack(const char* track)
+{
+ if (!track) {
+ this->SpecificTrack = "";
+ return;
+ }
+ this->SpecificTrack = track;
+}
+
+void cmCTest::AddSubmitFile(Part part, const char* name)
+{
+ this->Parts[part].SubmitFiles.push_back(name);
+}
+
+void cmCTest::AddCTestConfigurationOverwrite(const std::string& overStr)
+{
+ size_t epos = overStr.find('=');
+ if (epos == overStr.npos) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "CTest configuration overwrite specified in the wrong format."
+ << std::endl
+ << "Valid format is: --overwrite key=value" << std::endl
+ << "The specified was: --overwrite " << overStr << std::endl);
+ return;
+ }
+ std::string key = overStr.substr(0, epos);
+ std::string value = overStr.substr(epos + 1, overStr.npos);
+ this->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;
+ cmSystemTools::PutEnv(confTypeEnv);
+}
+
+bool cmCTest::SetCTestConfigurationFromCMakeVariable(
+ cmMakefile* mf, const char* dconfig, const std::string& cmake_var,
+ bool suppress)
+{
+ const char* ctvar;
+ ctvar = mf->GetDefinition(cmake_var);
+ if (!ctvar) {
+ return false;
+ }
+ cmCTestOptionalLog(this, HANDLER_VERBOSE_OUTPUT,
+ "SetCTestConfigurationFromCMakeVariable:"
+ << dconfig << ":" << cmake_var << std::endl,
+ suppress);
+ this->SetCTestConfiguration(dconfig, ctvar, suppress);
+ return true;
+}
+
+bool cmCTest::RunCommand(const char* command, std::string* stdOut,
+ std::string* stdErr, int* retVal, const char* dir,
+ double timeout)
+{
+ std::vector<std::string> args = cmSystemTools::ParseArguments(command);
+
+ if (args.empty()) {
+ return false;
+ }
+
+ std::vector<const char*> argv;
+ for (std::vector<std::string>::const_iterator a = args.begin();
+ a != args.end(); ++a) {
+ argv.push_back(a->c_str());
+ }
+ argv.push_back(CM_NULLPTR);
+
+ *stdOut = "";
+ *stdErr = "";
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ if (cmSystemTools::GetRunCommandHideConsole()) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ }
+ cmsysProcess_SetTimeout(cp, timeout);
+ cmsysProcess_Execute(cp);
+
+ std::vector<char> tempOutput;
+ std::vector<char> tempError;
+ char* data;
+ int length;
+ int res;
+ bool done = false;
+ while (!done) {
+ res = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR);
+ switch (res) {
+ case cmsysProcess_Pipe_STDOUT:
+ tempOutput.insert(tempOutput.end(), data, data + length);
+ break;
+ case cmsysProcess_Pipe_STDERR:
+ tempError.insert(tempError.end(), data, data + length);
+ break;
+ default:
+ done = true;
+ }
+ if ((res == cmsysProcess_Pipe_STDOUT || res == cmsysProcess_Pipe_STDERR) &&
+ this->ExtraVerbose) {
+ cmSystemTools::Stdout(data, length);
+ }
+ }
+
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+ if (!tempOutput.empty()) {
+ stdOut->append(&*tempOutput.begin(), tempOutput.size());
+ }
+ if (!tempError.empty()) {
+ stdErr->append(&*tempError.begin(), tempError.size());
+ }
+
+ bool result = true;
+ if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
+ if (retVal) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ } else {
+ if (cmsysProcess_GetExitValue(cp) != 0) {
+ result = false;
+ }
+ }
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) {
+ const char* exception_str = cmsysProcess_GetExceptionString(cp);
+ cmCTestLog(this, ERROR_MESSAGE, exception_str << std::endl);
+ stdErr->append(exception_str, strlen(exception_str));
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
+ const char* error_str = cmsysProcess_GetErrorString(cp);
+ cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
+ stdErr->append(error_str, strlen(error_str));
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) {
+ const char* error_str = "Process terminated due to timeout\n";
+ cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
+ stdErr->append(error_str, strlen(error_str));
+ result = false;
+ }
+
+ cmsysProcess_Delete(cp);
+ return result;
+}
+
+void cmCTest::SetOutputLogFileName(const char* name)
+{
+ if (this->OutputLogFile) {
+ delete this->OutputLogFile;
+ this->OutputLogFile = CM_NULLPTR;
+ }
+ if (name) {
+ this->OutputLogFile = new cmGeneratedFileStream(name);
+ }
+}
+
+static const char* cmCTestStringLogType[] = { "DEBUG",
+ "OUTPUT",
+ "HANDLER_OUTPUT",
+ "HANDLER_PROGRESS_OUTPUT",
+ "HANDLER_VERBOSE_OUTPUT",
+ "WARNING",
+ "ERROR_MESSAGE",
+ CM_NULLPTR };
+
+#ifdef cerr
+#undef cerr
+#endif
+#ifdef cout
+#undef cout
+#endif
+
+#define cmCTestLogOutputFileLine(stream) \
+ if (this->ShowLineNumbers) { \
+ (stream) << std::endl << file << ":" << line << " "; \
+ }
+
+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)
+{
+ if (!msg || !*msg) {
+ return;
+ }
+ if (suppress && logType != cmCTest::ERROR_MESSAGE) {
+ return;
+ }
+ if (logType == cmCTest::HANDLER_PROGRESS_OUTPUT &&
+ (this->Debug || this->ExtraVerbose)) {
+ return;
+ }
+ if (this->OutputLogFile) {
+ bool display = true;
+ if (logType == cmCTest::DEBUG && !this->Debug) {
+ display = false;
+ }
+ if (logType == cmCTest::HANDLER_VERBOSE_OUTPUT && !this->Debug &&
+ !this->ExtraVerbose) {
+ display = false;
+ }
+ if (display) {
+ cmCTestLogOutputFileLine(*this->OutputLogFile);
+ if (logType != this->OutputLogFileLastTag) {
+ *this->OutputLogFile << "[";
+ if (logType >= OTHER || logType < 0) {
+ *this->OutputLogFile << "OTHER";
+ } else {
+ *this->OutputLogFile << cmCTestStringLogType[logType];
+ }
+ *this->OutputLogFile << "] " << std::endl << std::flush;
+ }
+ *this->OutputLogFile << msg << std::flush;
+ if (logType != this->OutputLogFileLastTag) {
+ *this->OutputLogFile << std::endl << std::flush;
+ this->OutputLogFileLastTag = logType;
+ }
+ }
+ }
+ if (!this->Quiet) {
+ std::ostream& out = *this->StreamOut;
+ std::ostream& err = *this->StreamErr;
+ switch (logType) {
+ case DEBUG:
+ if (this->Debug) {
+ cmCTestLogOutputFileLine(out);
+ out << msg;
+ out.flush();
+ }
+ break;
+ case OUTPUT:
+ case HANDLER_OUTPUT:
+ if (this->Debug || this->Verbose) {
+ cmCTestLogOutputFileLine(out);
+ out << msg;
+ out.flush();
+ }
+ break;
+ case HANDLER_VERBOSE_OUTPUT:
+ if (this->Debug || this->ExtraVerbose) {
+ cmCTestLogOutputFileLine(out);
+ out << msg;
+ out.flush();
+ }
+ break;
+ case WARNING:
+ cmCTestLogOutputFileLine(err);
+ err << msg;
+ err.flush();
+ break;
+ case ERROR_MESSAGE:
+ cmCTestLogOutputFileLine(err);
+ err << msg;
+ err.flush();
+ cmSystemTools::SetErrorOccured();
+ break;
+ default:
+ cmCTestLogOutputFileLine(out);
+ out << msg;
+ out.flush();
+ }
+ }
+}
+
+double cmCTest::GetRemainingTimeAllowed()
+{
+ if (!this->GetHandler("script")) {
+ return 1.0e7;
+ }
+
+ cmCTestScriptHandler* ch =
+ static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+
+ return ch->GetRemainingTimeAllowed();
+}
+
+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());
+ }
+ cmCTestLog(this, HANDLER_OUTPUT, test_outputs << std::endl << std::flush);
+}
+
+bool cmCTest::CompressString(std::string& str)
+{
+ int ret;
+ z_stream strm;
+
+ unsigned char* in =
+ reinterpret_cast<unsigned char*>(const_cast<char*>(str.c_str()));
+ // zlib makes the guarantee that this is the maximum output size
+ int outSize =
+ static_cast<int>(static_cast<double>(str.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 false;
+ }
+
+ strm.avail_in = static_cast<uInt>(str.size());
+ strm.next_in = in;
+ strm.avail_out = outSize;
+ strm.next_out = out;
+ ret = deflate(&strm, Z_FINISH);
+
+ if (ret == Z_STREAM_ERROR || ret != Z_STREAM_END) {
+ cmCTestLog(this, ERROR_MESSAGE, "Error during gzip compression."
+ << std::endl);
+ delete[] out;
+ return false;
+ }
+
+ (void)deflateEnd(&strm);
+
+ // Now base64 encode the resulting binary string
+ unsigned char* base64EncodedBuffer = new unsigned char[(outSize * 3) / 2];
+
+ size_t rlen =
+ cmsysBase64_Encode(out, strm.total_out, base64EncodedBuffer, 1);
+
+ str = "";
+ str.append(reinterpret_cast<char*>(base64EncodedBuffer), rlen);
+
+ delete[] base64EncodedBuffer;
+ delete[] out;
+
+ return true;
+}
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
new file mode 100644
index 0000000..833cd96
--- /dev/null
+++ b/Source/cmCTest.h
@@ -0,0 +1,626 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCTest_h
+#define cmCTest_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmListFileCache.h"
+#include <time.h>
+
+class cmake;
+class cmMakefile;
+class cmCTestGenericHandler;
+class cmGeneratedFileStream;
+class cmCTestCommand;
+class cmCTestScriptHandler;
+class cmCTestStartCommand;
+class cmXMLWriter;
+
+#define cmCTestLog(ctSelf, logType, msg) \
+ do { \
+ std::ostringstream cmCTestLog_msg; \
+ cmCTestLog_msg << msg; \
+ (ctSelf)->Log(cmCTest::logType, __FILE__, __LINE__, \
+ cmCTestLog_msg.str().c_str()); \
+ } while (0)
+
+#define cmCTestOptionalLog(ctSelf, logType, msg, suppress) \
+ do { \
+ std::ostringstream cmCTestLog_msg; \
+ cmCTestLog_msg << msg; \
+ (ctSelf)->Log(cmCTest::logType, __FILE__, __LINE__, \
+ cmCTestLog_msg.str().c_str(), suppress); \
+ } while (0)
+
+#ifdef cerr
+#undef cerr
+#endif
+#define cerr no_cerr_use_cmCTestLog
+
+#ifdef cout
+#undef cout
+#endif
+#define cout no_cout_use_cmCTestLog
+
+class cmCTest
+{
+ friend class cmCTestRunTest;
+ friend class cmCTestMultiProcessHandler;
+
+public:
+ /** Enumerate parts of the testing and submission process. */
+ enum Part
+ {
+ PartStart,
+ PartUpdate,
+ PartConfigure,
+ PartBuild,
+ PartTest,
+ PartCoverage,
+ PartMemCheck,
+ PartSubmit,
+ PartNotes,
+ PartExtraFiles,
+ PartUpload,
+ PartCount // Update names in constructor when adding a part
+ };
+
+ /** Representation of one part. */
+ struct PartInfo
+ {
+ PartInfo()
+ : Enabled(false)
+ {
+ }
+
+ void SetName(const std::string& name) { this->Name = name; }
+ const std::string& GetName() const { return this->Name; }
+
+ void Enable() { this->Enabled = true; }
+ operator bool() const { return this->Enabled; }
+
+ std::vector<std::string> SubmitFiles;
+
+ private:
+ bool Enabled;
+ 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<cmsys::String> VectorOfStrings;
+ typedef std::set<std::string> SetOfStrings;
+
+ ///! Process Command line arguments
+ int Run(std::vector<std::string>&, std::string* output = CM_NULLPTR);
+
+ /**
+ * Initialize and finalize testing
+ */
+ bool InitializeFromCommand(cmCTestStartCommand* command);
+ void Finalize();
+
+ /**
+ * Process the tests. This is the main routine. The execution of the
+ * tests should look like this:
+ *
+ * ctest foo;
+ * foo.Initialize();
+ * // Set some things on foo
+ * foo.ProcessTests();
+ * foo.Finalize();
+ */
+ int ProcessTests();
+
+ /*
+ * A utility function that returns the nightly time
+ */
+ struct tm* GetNightlyTime(std::string const& str, bool tomorrowtag);
+
+ /*
+ * Is the tomorrow tag set?
+ */
+ bool GetTomorrowTag() { return this->TomorrowTag; }
+
+ /**
+ * Try to run tests of the project
+ */
+ int TestDirectory(bool memcheck);
+
+ ///! what is the configuraiton type, e.g. Debug, Release etc.
+ std::string const& GetConfigType();
+ double GetTimeOut() { return this->TimeOut; }
+ void SetTimeOut(double t) { this->TimeOut = t; }
+
+ double GetGlobalTimeout() { return this->GlobalTimeout; }
+
+ // how many test to run at the same time
+ int GetParallelLevel() { return this->ParallelLevel; }
+ void SetParallelLevel(int);
+
+ unsigned long GetTestLoad() { return this->TestLoad; }
+ void SetTestLoad(unsigned long);
+
+ /**
+ * Check if CTest file exists
+ */
+ bool CTestFileExists(const std::string& filename);
+ bool AddIfExists(Part part, const char* file);
+
+ /**
+ * Set the cmake test
+ */
+ bool SetTest(const char*, bool report = true);
+
+ /**
+ * Set the cmake test mode (experimental, nightly, continuous).
+ */
+ void SetTestModel(int mode);
+ int GetTestModel() { return this->TestModel; }
+
+ std::string GetTestModelString();
+ static int GetTestModelFromString(const char* str);
+ static std::string CleanString(const std::string& str);
+ std::string GetCTestConfiguration(const std::string& name);
+ void SetCTestConfiguration(const char* name, const char* value,
+ bool suppress = false);
+ void EmptyCTestConfiguration();
+
+ /**
+ * constructor and destructor
+ */
+ cmCTest();
+ ~cmCTest();
+
+ //! Set the notes files to be created.
+ void SetNotesFiles(const char* notes);
+
+ void PopulateCustomVector(cmMakefile* mf, const std::string& definition,
+ std::vector<std::string>& vec);
+ void PopulateCustomInteger(cmMakefile* mf, const std::string& def, int& val);
+
+ ///! Get the current time as string
+ std::string CurrentTime();
+
+ //! tar/gzip and then base 64 encode a file
+ std::string Base64GzipEncodeFile(std::string const& file);
+ //! base64 encode a file
+ std::string Base64EncodeFile(std::string const& file);
+
+ /**
+ * Return the time remaining that the script is allowed to run in
+ * seconds if the user has set the variable CTEST_TIME_LIMIT. If that has
+ * not been set it returns 1e7 seconds
+ */
+ double GetRemainingTimeAllowed();
+
+ ///! Open file in the output directory and set the stream
+ bool OpenOutputFile(const std::string& path, const std::string& name,
+ cmGeneratedFileStream& stream, bool compress = false);
+
+ ///! Should we only show what we would do?
+ bool GetShowOnly();
+
+ bool ShouldUseHTTP10() { return this->UseHTTP10; }
+
+ bool ShouldPrintLabels() { return this->PrintLabels; }
+
+ bool ShouldCompressTestOutput();
+ bool ShouldCompressMemCheckOutput();
+ bool CompressString(std::string& str);
+
+ std::string GetCDashVersion();
+
+ std::string GetStopTime() { return this->StopTime; }
+ void SetStopTime(std::string const& time);
+
+ // Used for parallel ctest job scheduling
+ std::string GetScheduleType() { return this->ScheduleType; }
+ void SetScheduleType(std::string type) { this->ScheduleType = type; }
+
+ ///! The max output width
+ int GetMaxTestNameWidth() const;
+ void SetMaxTestNameWidth(int w) { this->MaxTestNameWidth = w; }
+
+ /**
+ * Run a single executable command and put the stdout and stderr
+ * in output.
+ *
+ * If verbose is false, no user-viewable output from the program
+ * being run will be generated.
+ *
+ * If timeout is specified, the command will be terminated after
+ * timeout expires. Timeout is specified in seconds.
+ *
+ * Argument retVal should be a pointer to the location where the
+ * exit code will be stored. If the retVal is not specified and
+ * the program exits with a code other than 0, then the this
+ * function will return false.
+ *
+ * If the command has spaces in the path the caller MUST call
+ * cmSystemTools::ConvertToRunCommandPath on the command before passing
+ * it into this function or it will not work. The command must be correctly
+ * escaped for this to with spaces.
+ */
+ bool RunCommand(const char* command, std::string* stdOut,
+ std::string* stdErr, int* retVal = CM_NULLPTR,
+ const char* dir = CM_NULLPTR, double timeout = 0.0);
+
+ //! Clean/make safe for xml the given value such that it may be used as
+ // one of the key fields by CDash when computing the buildid.
+ static std::string SafeBuildIdField(const std::string& value);
+
+ //! Start CTest XML output file
+ void StartXML(cmXMLWriter& xml, bool append);
+
+ //! End CTest XML output file
+ void EndXML(cmXMLWriter& xml);
+
+ //! 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, int timeout, std::ostream& ofs);
+
+ /*
+ * return the current tag
+ */
+ std::string GetCurrentTag();
+
+ //! Get the path to the build tree
+ std::string GetBinaryDir();
+
+ //! Get the short path to the file. This means if the file is in binary or
+ // source directory, it will become /.../relative/path/to/file
+ std::string GetShortPathToFile(const char* fname);
+
+ enum
+ {
+ EXPERIMENTAL,
+ NIGHTLY,
+ CONTINUOUS
+ };
+
+ // provide some more detailed info on the return code for ctest
+ enum
+ {
+ UPDATE_ERRORS = 0x01,
+ CONFIGURE_ERRORS = 0x02,
+ BUILD_ERRORS = 0x04,
+ TEST_ERRORS = 0x08,
+ MEMORY_ERRORS = 0x10,
+ COVERAGE_ERRORS = 0x20,
+ SUBMIT_ERRORS = 0x40
+ };
+
+ ///! Are we producing XML
+ bool GetProduceXML();
+ void SetProduceXML(bool v);
+
+ //! Run command specialized for tests. Returns process status and retVal is
+ // return value or exception. If environment is non-null, it is used to set
+ // environment variables prior to running the test. After running the test,
+ // environment variables are restored to their previous values.
+ int RunTest(std::vector<const char*> args, std::string* output, int* retVal,
+ std::ostream* logfile, double testTimeOut,
+ std::vector<std::string>* environment);
+
+ /**
+ * 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);
+
+ /*
+ * Set the CTest variable from CMake variable
+ */
+ bool SetCTestConfigurationFromCMakeVariable(cmMakefile* mf,
+ const char* dconfig,
+ const std::string& cmake_var,
+ bool suppress = false);
+
+ //! Make string safe to be send as an URL
+ static std::string MakeURLSafe(const std::string&);
+
+ /** Decode a URL to the original string. */
+ static std::string DecodeURL(const std::string&);
+
+ //! Should ctect configuration be updated. When using new style ctest
+ // script, this should be true.
+ void SetSuppressUpdatingCTestConfiguration(bool val)
+ {
+ this->SuppressUpdatingCTestConfiguration = val;
+ }
+
+ //! Add overwrite to ctest configuration.
+ // The format is key=value
+ void AddCTestConfigurationOverwrite(const std::string& encstr);
+
+ //! Create XML file that contains all the notes specified
+ int GenerateNotesFile(const VectorOfStrings& files);
+
+ //! Submit extra files to the server
+ bool SubmitExtraFiles(const char* files);
+ bool SubmitExtraFiles(const VectorOfStrings& files);
+
+ //! Set the output log file name
+ void SetOutputLogFileName(const char* name);
+
+ //! Set the visual studio or Xcode config type
+ void SetConfigType(const char* ct);
+
+ //! Various log types
+ enum
+ {
+ DEBUG = 0,
+ OUTPUT,
+ HANDLER_OUTPUT,
+ HANDLER_PROGRESS_OUTPUT,
+ HANDLER_VERBOSE_OUTPUT,
+ WARNING,
+ ERROR_MESSAGE,
+ OTHER
+ };
+
+ //! Add log to the output
+ void Log(int logType, const char* file, int line, const char* msg,
+ bool suppress = false);
+
+ //! Get the version of dart server
+ int GetDartVersion() { return this->DartVersion; }
+ int GetDropSiteCDash() { return this->DropSiteCDash; }
+
+ //! 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(); }
+
+ //! 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;
+ }
+
+ //! 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 SetBatchJobs(bool batch = true) { this->BatchJobs = batch; }
+ bool GetBatchJobs() { return this->BatchJobs; }
+
+ bool GetVerbose() { return this->Verbose; }
+ bool GetExtraVerbose() { return this->ExtraVerbose; }
+
+ /** Direct process output to given streams. */
+ void SetStreams(std::ostream* out, std::ostream* err)
+ {
+ this->StreamOut = out;
+ this->StreamErr = err;
+ }
+ void AddSiteProperties(cmXMLWriter& xml);
+ bool GetLabelSummary() { return this->LabelSummary; }
+
+ std::string GetCostDataFile();
+
+ const std::map<std::string, std::string>& GetDefinitions()
+ {
+ return this->Definitions;
+ }
+ // return the number of times a test should be run
+ int GetTestRepeat() { return this->RepeatTests; }
+ // return true if test should run until fail
+ bool GetRepeatUntilFail() { return this->RepeatUntilFail; }
+private:
+ int RepeatTests;
+ bool RepeatUntilFail;
+ std::string ConfigType;
+ std::string ScheduleType;
+ std::string StopTime;
+ bool NextDayStopTime;
+ bool Verbose;
+ bool ExtraVerbose;
+ bool ProduceXML;
+ bool LabelSummary;
+ bool UseHTTP10;
+ bool PrintLabels;
+ bool Failover;
+ bool BatchJobs;
+
+ bool ForceNewCTestProcess;
+
+ bool RunConfigurationScript;
+
+ // flag for lazy getter (optimization)
+ bool ComputedCompressTestOutput;
+ bool ComputedCompressMemCheckOutput;
+
+ int GenerateNotesFile(const char* files);
+
+ void DetermineNextDayStop();
+
+ // these are helper classes
+ typedef std::map<std::string, cmCTestGenericHandler*> t_TestingHandlers;
+ t_TestingHandlers TestingHandlers;
+
+ bool ShowOnly;
+
+ //! Map of configuration properties
+ typedef std::map<std::string, std::string> CTestConfigurationMap;
+
+ std::string CTestConfigFile;
+ // 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;
+
+ double TimeOut;
+
+ double GlobalTimeout;
+
+ int LastStopTimeout;
+
+ 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;
+ bool CompressMemCheckOutput;
+
+ void InitStreams();
+ std::ostream* StreamOut;
+ std::ostream* StreamErr;
+
+ void BlockTestErrorDiagnostics();
+
+ /**
+ * Initialize a dashboard run in the given build tree. The "command"
+ * argument is non-NULL when running from a command-driven (ctest_start)
+ * dashboard script, and NULL when running from the CTest command
+ * line. Note that a declarative dashboard script does not actually
+ * call this method because it sets CTEST_COMMAND to drive a build
+ * through the ctest command line.
+ */
+ int Initialize(const char* binary_dir, cmCTestStartCommand* command);
+
+ //! parse the option after -D and convert it into the appropriate steps
+ bool AddTestsForDashboardType(std::string& targ);
+
+ //! read as "emit an error message for an unknown -D value"
+ void ErrorMessageUnknownDashDValue(std::string& val);
+
+ //! add a variable definition from a command line -D value
+ bool AddVariableDefinition(const std::string& arg);
+
+ //! parse and process most common command line arguments
+ bool HandleCommandLineArguments(size_t& i, std::vector<std::string>& args,
+ std::string& errormsg);
+
+ //! hande the -S -SP and -SR arguments
+ void HandleScriptArguments(size_t& i, std::vector<std::string>& args,
+ bool& SRArgumentSpecified);
+
+ //! Reread the configuration file
+ bool UpdateCTestConfiguration();
+
+ //! Create note from files.
+ int GenerateCTestNotesOutput(cmXMLWriter& xml, const VectorOfStrings& files);
+
+ //! Check if the argument is the one specified
+ bool CheckArgument(const std::string& arg, const char* varg1,
+ const char* varg2 = CM_NULLPTR);
+
+ //! Output errors from a test
+ void OutputTestErrors(std::vector<char> const& process_output);
+
+ bool SuppressUpdatingCTestConfiguration;
+
+ bool Debug;
+ bool ShowLineNumbers;
+ bool Quiet;
+
+ int DartVersion;
+ bool DropSiteCDash;
+
+ std::vector<std::string> InitialCommandLineArguments;
+
+ int SubmitIndex;
+
+ cmGeneratedFileStream* OutputLogFile;
+ int OutputLogFileLastTag;
+
+ bool OutputTestOutputOnTestFailure;
+
+ std::map<std::string, std::string> Definitions;
+};
+
+class cmCTestLogWrite
+{
+public:
+ cmCTestLogWrite(const char* data, size_t length)
+ : Data(data)
+ , Length(length)
+ {
+ }
+
+ const char* Data;
+ size_t Length;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const cmCTestLogWrite& c)
+{
+ if (!c.Length) {
+ return os;
+ }
+ os.write(c.Data, c.Length);
+ os.flush();
+ return os;
+}
+
+#endif
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
new file mode 100644
index 0000000..bdd7303
--- /dev/null
+++ b/Source/cmCacheManager.cxx
@@ -0,0 +1,657 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCacheManager.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+#include "cmake.h"
+
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/RegularExpression.hxx>
+
+cmCacheManager::cmCacheManager()
+{
+ this->CacheMajorVersion = 0;
+ this->CacheMinorVersion = 0;
+}
+
+void cmCacheManager::CleanCMakeFiles(const std::string& path)
+{
+ std::string glob = path;
+ glob += cmake::GetCMakeFilesDirectory();
+ glob += "/*.cmake";
+ cmsys::Glob globIt;
+ globIt.FindFiles(glob);
+ std::vector<std::string> files = globIt.GetFiles();
+ std::for_each(files.begin(), files.end(), cmSystemTools::RemoveFile);
+}
+
+bool cmCacheManager::LoadCache(const std::string& path, bool internal,
+ std::set<std::string>& excludes,
+ std::set<std::string>& includes)
+{
+ std::string cacheFile = path;
+ cacheFile += "/CMakeCache.txt";
+ // clear the old cache, if we are reading in internal values
+ if (internal) {
+ this->Cache.clear();
+ }
+ if (!cmSystemTools::FileExists(cacheFile.c_str())) {
+ this->CleanCMakeFiles(path);
+ return false;
+ }
+
+ cmsys::ifstream fin(cacheFile.c_str());
+ if (!fin) {
+ return false;
+ }
+ const char* realbuffer;
+ std::string buffer;
+ std::string entryKey;
+ unsigned int lineno = 0;
+ while (fin) {
+ // Format is key:type=value
+ std::string helpString;
+ CacheEntry e;
+ cmSystemTools::GetLineFromStream(fin, buffer);
+ lineno++;
+ realbuffer = buffer.c_str();
+ while (*realbuffer != '0' &&
+ (*realbuffer == ' ' || *realbuffer == '\t' || *realbuffer == '\r' ||
+ *realbuffer == '\n')) {
+ if (*realbuffer == '\n') {
+ lineno++;
+ }
+ realbuffer++;
+ }
+ // skip blank lines and comment lines
+ if (realbuffer[0] == '#' || realbuffer[0] == 0) {
+ continue;
+ }
+ while (realbuffer[0] == '/' && realbuffer[1] == '/') {
+ if ((realbuffer[2] == '\\') && (realbuffer[3] == 'n')) {
+ helpString += "\n";
+ helpString += &realbuffer[4];
+ } else {
+ helpString += &realbuffer[2];
+ }
+ cmSystemTools::GetLineFromStream(fin, buffer);
+ lineno++;
+ realbuffer = buffer.c_str();
+ if (!fin) {
+ continue;
+ }
+ }
+ e.SetProperty("HELPSTRING", helpString.c_str());
+ if (cmState::ParseCacheEntry(realbuffer, entryKey, e.Value, e.Type)) {
+ if (excludes.find(entryKey) == excludes.end()) {
+ // Load internal values if internal is set.
+ // If the entry is not internal to the cache being loaded
+ // or if it is in the list of internal entries to be
+ // imported, load it.
+ if (internal || (e.Type != cmState::INTERNAL) ||
+ (includes.find(entryKey) != includes.end())) {
+ // If we are loading the cache from another project,
+ // make all loaded entries internal so that it is
+ // not visible in the gui
+ if (!internal) {
+ e.Type = cmState::INTERNAL;
+ helpString = "DO NOT EDIT, ";
+ helpString += entryKey;
+ helpString += " loaded from external file. "
+ "To change this value edit this file: ";
+ helpString += path;
+ helpString += "/CMakeCache.txt";
+ e.SetProperty("HELPSTRING", helpString.c_str());
+ }
+ if (!this->ReadPropertyEntry(entryKey, e)) {
+ e.Initialized = true;
+ this->Cache[entryKey] = e;
+ }
+ }
+ }
+ } else {
+ std::ostringstream error;
+ error << "Parse error in cache file " << cacheFile;
+ error << " on line " << lineno << ". Offending entry: " << realbuffer;
+ cmSystemTools::Error(error.str().c_str());
+ }
+ }
+ this->CacheMajorVersion = 0;
+ this->CacheMinorVersion = 0;
+ if (const char* cmajor =
+ this->GetInitializedCacheValue("CMAKE_CACHE_MAJOR_VERSION")) {
+ unsigned int v = 0;
+ if (sscanf(cmajor, "%u", &v) == 1) {
+ this->CacheMajorVersion = v;
+ }
+ if (const char* cminor =
+ this->GetInitializedCacheValue("CMAKE_CACHE_MINOR_VERSION")) {
+ if (sscanf(cminor, "%u", &v) == 1) {
+ this->CacheMinorVersion = v;
+ }
+ }
+ } else {
+ // CMake version not found in the list file.
+ // Set as version 0.0
+ this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION", "0",
+ "Minor version of cmake used to create the "
+ "current loaded cache",
+ cmState::INTERNAL);
+ this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION", "0",
+ "Major version of cmake used to create the "
+ "current loaded cache",
+ cmState::INTERNAL);
+ }
+ // check to make sure the cache directory has not
+ // been moved
+ const char* oldDir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
+ if (internal && oldDir) {
+ std::string currentcwd = path;
+ std::string oldcwd = oldDir;
+ cmSystemTools::ConvertToUnixSlashes(currentcwd);
+ currentcwd += "/CMakeCache.txt";
+ oldcwd += "/CMakeCache.txt";
+ if (!cmSystemTools::SameFile(oldcwd, currentcwd)) {
+ std::string message =
+ std::string("The current CMakeCache.txt directory ") + currentcwd +
+ std::string(" is different than the directory ") +
+ std::string(this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR")) +
+ std::string(" where CMakeCache.txt was created. This may result "
+ "in binaries being created in the wrong place. If you "
+ "are not sure, reedit the CMakeCache.txt");
+ cmSystemTools::Error(message.c_str());
+ }
+ }
+ return true;
+}
+
+const char* cmCacheManager::PersistentProperties[] = { "ADVANCED", "MODIFIED",
+ "STRINGS", CM_NULLPTR };
+
+bool cmCacheManager::ReadPropertyEntry(std::string const& entryKey,
+ CacheEntry& e)
+{
+ // All property entries are internal.
+ if (e.Type != cmState::INTERNAL) {
+ return false;
+ }
+
+ const char* end = entryKey.c_str() + entryKey.size();
+ for (const char** p = this->PersistentProperties; *p; ++p) {
+ std::string::size_type plen = strlen(*p) + 1;
+ if (entryKey.size() > plen && *(end - plen) == '-' &&
+ strcmp(end - plen + 1, *p) == 0) {
+ std::string key = entryKey.substr(0, entryKey.size() - plen);
+ cmCacheManager::CacheIterator it = this->GetCacheIterator(key.c_str());
+ if (it.IsAtEnd()) {
+ // Create an entry and store the property.
+ CacheEntry& ne = this->Cache[key];
+ ne.Type = cmState::UNINITIALIZED;
+ ne.SetProperty(*p, e.Value.c_str());
+ } else {
+ // Store this property on its entry.
+ it.SetProperty(*p, e.Value.c_str());
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmCacheManager::WritePropertyEntries(std::ostream& os,
+ CacheIterator const& i)
+{
+ for (const char** p = this->PersistentProperties; *p; ++p) {
+ if (const char* value = i.GetProperty(*p)) {
+ std::string helpstring = *p;
+ helpstring += " property for variable: ";
+ helpstring += i.GetName();
+ cmCacheManager::OutputHelpString(os, helpstring);
+
+ std::string key = i.GetName();
+ key += "-";
+ key += *p;
+ this->OutputKey(os, key);
+ os << ":INTERNAL=";
+ this->OutputValue(os, value);
+ os << "\n";
+ }
+ }
+}
+
+bool cmCacheManager::SaveCache(const std::string& path)
+{
+ std::string cacheFile = path;
+ cacheFile += "/CMakeCache.txt";
+ cmGeneratedFileStream fout(cacheFile.c_str());
+ fout.SetCopyIfDifferent(true);
+ if (!fout) {
+ cmSystemTools::Error("Unable to open cache file for save. ",
+ cacheFile.c_str());
+ cmSystemTools::ReportLastSystemError("");
+ return false;
+ }
+ // before writing the cache, update the version numbers
+ // to the
+ char temp[1024];
+ sprintf(temp, "%d", cmVersion::GetMinorVersion());
+ this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION", temp,
+ "Minor version of cmake used to create the "
+ "current loaded cache",
+ cmState::INTERNAL);
+ sprintf(temp, "%d", cmVersion::GetMajorVersion());
+ this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION", temp,
+ "Major version of cmake used to create the "
+ "current loaded cache",
+ cmState::INTERNAL);
+ sprintf(temp, "%d", cmVersion::GetPatchVersion());
+ this->AddCacheEntry("CMAKE_CACHE_PATCH_VERSION", temp,
+ "Patch version of cmake used to create the "
+ "current loaded cache",
+ cmState::INTERNAL);
+
+ // Let us store the current working directory so that if somebody
+ // Copies it, he will not be surprised
+ std::string currentcwd = path;
+ if (currentcwd[0] >= 'A' && currentcwd[0] <= 'Z' && currentcwd[1] == ':') {
+ // Cast added to avoid compiler warning. Cast is ok because
+ // value is guaranteed to fit in char by the above if...
+ currentcwd[0] = static_cast<char>(currentcwd[0] - 'A' + 'a');
+ }
+ cmSystemTools::ConvertToUnixSlashes(currentcwd);
+ this->AddCacheEntry("CMAKE_CACHEFILE_DIR", currentcwd.c_str(),
+ "This is the directory where this CMakeCache.txt"
+ " was created",
+ cmState::INTERNAL);
+
+ /* clang-format off */
+ fout << "# This is the CMakeCache file.\n"
+ << "# For build in directory: " << currentcwd << "\n"
+ << "# It was generated by CMake: "
+ << cmSystemTools::GetCMakeCommand() << std::endl;
+ /* clang-format on */
+
+ /* clang-format off */
+ fout << "# You can edit this file to change values found and used by cmake."
+ << std::endl
+ << "# If you do not want to change any of the values, simply exit the "
+ "editor." << std::endl
+ << "# If you do want to change a value, simply edit, save, and exit "
+ "the editor." << std::endl
+ << "# The syntax for the file is as follows:\n"
+ << "# KEY:TYPE=VALUE\n"
+ << "# KEY is the name of a variable in the cache.\n"
+ << "# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT "
+ "TYPE!." << std::endl
+ << "# VALUE is the current value for the KEY.\n\n";
+ /* clang-format on */
+
+ fout << "########################\n";
+ fout << "# EXTERNAL cache entries\n";
+ fout << "########################\n";
+ fout << "\n";
+
+ for (std::map<std::string, CacheEntry>::const_iterator i =
+ this->Cache.begin();
+ i != this->Cache.end(); ++i) {
+ const CacheEntry& ce = (*i).second;
+ cmState::CacheEntryType t = ce.Type;
+ if (!ce.Initialized) {
+ /*
+ // This should be added in, but is not for now.
+ cmSystemTools::Error("Cache entry \"", (*i).first.c_str(),
+ "\" is uninitialized");
+ */
+ } else if (t != cmState::INTERNAL) {
+ // Format is key:type=value
+ if (const char* help = ce.GetProperty("HELPSTRING")) {
+ cmCacheManager::OutputHelpString(fout, help);
+ } else {
+ cmCacheManager::OutputHelpString(fout, "Missing description");
+ }
+ this->OutputKey(fout, i->first);
+ fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
+ this->OutputValue(fout, ce.Value);
+ fout << "\n\n";
+ }
+ }
+
+ fout << "\n";
+ fout << "########################\n";
+ fout << "# INTERNAL cache entries\n";
+ fout << "########################\n";
+ fout << "\n";
+
+ for (cmCacheManager::CacheIterator i = this->NewIterator(); !i.IsAtEnd();
+ i.Next()) {
+ if (!i.Initialized()) {
+ continue;
+ }
+
+ cmState::CacheEntryType t = i.GetType();
+ this->WritePropertyEntries(fout, i);
+ if (t == cmState::INTERNAL) {
+ // Format is key:type=value
+ if (const char* help = i.GetProperty("HELPSTRING")) {
+ this->OutputHelpString(fout, help);
+ }
+ this->OutputKey(fout, i.GetName());
+ fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
+ this->OutputValue(fout, i.GetValue());
+ fout << "\n";
+ }
+ }
+ fout << "\n";
+ fout.Close();
+ std::string checkCacheFile = path;
+ checkCacheFile += cmake::GetCMakeFilesDirectory();
+ cmSystemTools::MakeDirectory(checkCacheFile.c_str());
+ 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());
+ return false;
+ }
+ checkCache << "# This file is generated by cmake for dependency checking "
+ "of the CMakeCache.txt file\n";
+ return true;
+}
+
+bool cmCacheManager::DeleteCache(const std::string& path)
+{
+ std::string cacheFile = path;
+ cmSystemTools::ConvertToUnixSlashes(cacheFile);
+ std::string cmakeFiles = cacheFile;
+ cacheFile += "/CMakeCache.txt";
+ if (cmSystemTools::FileExists(cacheFile.c_str())) {
+ cmSystemTools::RemoveFile(cacheFile);
+ // now remove the files in the CMakeFiles directory
+ // this cleans up language cache files
+ cmakeFiles += cmake::GetCMakeFilesDirectory();
+ if (cmSystemTools::FileIsDirectory(cmakeFiles)) {
+ cmSystemTools::RemoveADirectory(cmakeFiles);
+ }
+ }
+ return true;
+}
+
+void cmCacheManager::OutputKey(std::ostream& fout, std::string const& key)
+{
+ // support : in key name by double quoting
+ const char* q =
+ (key.find(':') != key.npos || key.find("//") == 0) ? "\"" : "";
+ fout << q << key << q;
+}
+
+void cmCacheManager::OutputValue(std::ostream& fout, std::string const& value)
+{
+ // if value has trailing space or tab, enclose it in single quotes
+ if (!value.empty() &&
+ (value[value.size() - 1] == ' ' || value[value.size() - 1] == '\t')) {
+ fout << '\'' << value << '\'';
+ } else {
+ fout << value;
+ }
+}
+
+void cmCacheManager::OutputHelpString(std::ostream& fout,
+ const std::string& helpString)
+{
+ std::string::size_type end = helpString.size();
+ if (end == 0) {
+ return;
+ }
+ std::string oneLine;
+ std::string::size_type pos = 0;
+ for (std::string::size_type i = 0; i <= end; i++) {
+ if ((i == end) || (helpString[i] == '\n') ||
+ ((i - pos >= 60) && (helpString[i] == ' '))) {
+ fout << "//";
+ if (helpString[pos] == '\n') {
+ pos++;
+ fout << "\\n";
+ }
+ oneLine = helpString.substr(pos, i - pos);
+ fout << oneLine << "\n";
+ pos = i;
+ }
+ }
+}
+
+void cmCacheManager::RemoveCacheEntry(const std::string& key)
+{
+ CacheEntryMap::iterator i = this->Cache.find(key);
+ if (i != this->Cache.end()) {
+ this->Cache.erase(i);
+ }
+}
+
+cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry(
+ const std::string& key)
+{
+ CacheEntryMap::iterator i = this->Cache.find(key);
+ if (i != this->Cache.end()) {
+ return &i->second;
+ }
+ return CM_NULLPTR;
+}
+
+cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator(const char* key)
+{
+ return CacheIterator(*this, key);
+}
+
+const char* cmCacheManager::GetInitializedCacheValue(
+ const std::string& key) const
+{
+ CacheEntryMap::const_iterator i = this->Cache.find(key);
+ if (i != this->Cache.end() && i->second.Initialized) {
+ return i->second.Value.c_str();
+ }
+ return CM_NULLPTR;
+}
+
+void cmCacheManager::PrintCache(std::ostream& out) const
+{
+ out << "=================================================" << std::endl;
+ out << "CMakeCache Contents:" << std::endl;
+ for (std::map<std::string, CacheEntry>::const_iterator i =
+ this->Cache.begin();
+ i != this->Cache.end(); ++i) {
+ if ((*i).second.Type != cmState::INTERNAL) {
+ out << (*i).first << " = " << (*i).second.Value << std::endl;
+ }
+ }
+ out << "\n\n";
+ out << "To change values in the CMakeCache, " << std::endl
+ << "edit CMakeCache.txt in your output directory.\n";
+ out << "=================================================" << std::endl;
+}
+
+void cmCacheManager::AddCacheEntry(const std::string& key, const char* value,
+ const char* helpString,
+ cmState::CacheEntryType type)
+{
+ CacheEntry& e = this->Cache[key];
+ if (value) {
+ e.Value = value;
+ e.Initialized = true;
+ } else {
+ e.Value = "";
+ }
+ e.Type = type;
+ // make sure we only use unix style paths
+ if (type == cmState::FILEPATH || type == cmState::PATH) {
+ if (e.Value.find(';') != e.Value.npos) {
+ std::vector<std::string> paths;
+ cmSystemTools::ExpandListArgument(e.Value, paths);
+ const char* sep = "";
+ e.Value = "";
+ for (std::vector<std::string>::iterator i = paths.begin();
+ i != paths.end(); ++i) {
+ cmSystemTools::ConvertToUnixSlashes(*i);
+ e.Value += sep;
+ e.Value += *i;
+ sep = ";";
+ }
+ } else {
+ cmSystemTools::ConvertToUnixSlashes(e.Value);
+ }
+ }
+ e.SetProperty("HELPSTRING", helpString
+ ? helpString
+ : "(This variable does not exist and should not be used)");
+}
+
+bool cmCacheManager::CacheIterator::IsAtEnd() const
+{
+ return this->Position == this->Container.Cache.end();
+}
+
+void cmCacheManager::CacheIterator::Begin()
+{
+ this->Position = this->Container.Cache.begin();
+}
+
+bool cmCacheManager::CacheIterator::Find(const std::string& key)
+{
+ this->Position = this->Container.Cache.find(key);
+ return !this->IsAtEnd();
+}
+
+void cmCacheManager::CacheIterator::Next()
+{
+ if (!this->IsAtEnd()) {
+ ++this->Position;
+ }
+}
+
+std::vector<std::string> cmCacheManager::CacheIterator::GetPropertyList() const
+{
+ return this->GetEntry().GetPropertyList();
+}
+
+void cmCacheManager::CacheIterator::SetValue(const char* value)
+{
+ if (this->IsAtEnd()) {
+ return;
+ }
+ CacheEntry* entry = &this->GetEntry();
+ if (value) {
+ entry->Value = value;
+ entry->Initialized = true;
+ } else {
+ entry->Value = "";
+ }
+}
+
+bool cmCacheManager::CacheIterator::GetValueAsBool() const
+{
+ return cmSystemTools::IsOn(this->GetEntry().Value.c_str());
+}
+
+std::vector<std::string> cmCacheManager::CacheEntry::GetPropertyList() const
+{
+ return this->Properties.GetPropertyList();
+}
+
+const char* cmCacheManager::CacheEntry::GetProperty(
+ const std::string& prop) const
+{
+ if (prop == "TYPE") {
+ return cmState::CacheEntryTypeToString(this->Type);
+ } else if (prop == "VALUE") {
+ return this->Value.c_str();
+ }
+ return this->Properties.GetPropertyValue(prop);
+}
+
+void cmCacheManager::CacheEntry::SetProperty(const std::string& prop,
+ const char* value)
+{
+ if (prop == "TYPE") {
+ this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
+ } else if (prop == "VALUE") {
+ this->Value = value ? value : "";
+ } else {
+ this->Properties.SetProperty(prop, value);
+ }
+}
+
+void cmCacheManager::CacheEntry::AppendProperty(const std::string& prop,
+ const char* value,
+ bool asString)
+{
+ if (prop == "TYPE") {
+ this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
+ } else if (prop == "VALUE") {
+ if (value) {
+ if (!this->Value.empty() && *value && !asString) {
+ this->Value += ";";
+ }
+ this->Value += value;
+ }
+ } else {
+ this->Properties.AppendProperty(prop, value, asString);
+ }
+}
+
+const char* cmCacheManager::CacheIterator::GetProperty(
+ const std::string& prop) const
+{
+ if (!this->IsAtEnd()) {
+ return this->GetEntry().GetProperty(prop);
+ }
+ return CM_NULLPTR;
+}
+
+void cmCacheManager::CacheIterator::SetProperty(const std::string& p,
+ const char* v)
+{
+ if (!this->IsAtEnd()) {
+ this->GetEntry().SetProperty(p, v);
+ }
+}
+
+void cmCacheManager::CacheIterator::AppendProperty(const std::string& p,
+ const char* v,
+ bool asString)
+{
+ if (!this->IsAtEnd()) {
+ this->GetEntry().AppendProperty(p, v, asString);
+ }
+}
+
+bool cmCacheManager::CacheIterator::GetPropertyAsBool(
+ const std::string& prop) const
+{
+ if (const char* value = this->GetProperty(prop)) {
+ return cmSystemTools::IsOn(value);
+ }
+ return false;
+}
+
+void cmCacheManager::CacheIterator::SetProperty(const std::string& p, bool v)
+{
+ this->SetProperty(p, v ? "ON" : "OFF");
+}
+
+bool cmCacheManager::CacheIterator::PropertyExists(
+ const std::string& prop) const
+{
+ return this->GetProperty(prop) != CM_NULLPTR;
+}
diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h
new file mode 100644
index 0000000..2331867
--- /dev/null
+++ b/Source/cmCacheManager.h
@@ -0,0 +1,235 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCacheManager_h
+#define cmCacheManager_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmPropertyMap.h"
+#include "cmState.h"
+
+class cmMarkAsAdvancedCommand;
+
+/** \class cmCacheManager
+ * \brief Control class for cmake's cache
+ *
+ * Load and Save CMake cache files.
+ *
+ */
+class cmCacheManager
+{
+public:
+ cmCacheManager();
+ class CacheIterator;
+ friend class cmCacheManager::CacheIterator;
+
+private:
+ struct CacheEntry
+ {
+ std::string Value;
+ cmState::CacheEntryType Type;
+ cmPropertyMap Properties;
+ std::vector<std::string> GetPropertyList() const;
+ const char* GetProperty(const std::string&) const;
+ void SetProperty(const std::string& property, const char* value);
+ void AppendProperty(const std::string& property, const char* value,
+ bool asString = false);
+ bool Initialized;
+ CacheEntry()
+ : Value("")
+ , Type(cmState::UNINITIALIZED)
+ , Initialized(false)
+ {
+ }
+ };
+
+public:
+ class CacheIterator
+ {
+ public:
+ void Begin();
+ bool Find(const std::string&);
+ bool IsAtEnd() const;
+ void Next();
+ std::string GetName() const { return this->Position->first; }
+ std::vector<std::string> GetPropertyList() const;
+ const char* GetProperty(const std::string&) const;
+ bool GetPropertyAsBool(const std::string&) const;
+ bool PropertyExists(const std::string&) const;
+ void SetProperty(const std::string& property, const char* value);
+ void AppendProperty(const std::string& property, const char* value,
+ bool asString = false);
+ void SetProperty(const std::string& property, bool value);
+ const char* GetValue() const { return this->GetEntry().Value.c_str(); }
+ bool GetValueAsBool() const;
+ void SetValue(const char*);
+ cmState::CacheEntryType GetType() const { return this->GetEntry().Type; }
+ void SetType(cmState::CacheEntryType ty) { this->GetEntry().Type = ty; }
+ bool Initialized() { return this->GetEntry().Initialized; }
+ cmCacheManager& Container;
+ std::map<std::string, CacheEntry>::iterator Position;
+ CacheIterator(cmCacheManager& cm)
+ : Container(cm)
+ {
+ this->Begin();
+ }
+ CacheIterator(cmCacheManager& cm, const char* key)
+ : Container(cm)
+ {
+ if (key) {
+ this->Find(key);
+ }
+ }
+
+ private:
+ CacheEntry const& GetEntry() const { return this->Position->second; }
+ CacheEntry& GetEntry() { return this->Position->second; }
+ };
+
+ ///! 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.
+ 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 ouput path/CMakeCache.txt
+ bool SaveCache(const std::string& path);
+
+ ///! Delete the cache given
+ bool DeleteCache(const std::string& path);
+
+ ///! Print the cache to a stream
+ void PrintCache(std::ostream&) const;
+
+ ///! Get the iterator for an entry with a given key.
+ cmCacheManager::CacheIterator GetCacheIterator(const char* key = CM_NULLPTR);
+
+ ///! Remove an entry from the cache
+ void RemoveCacheEntry(const std::string& key);
+
+ ///! 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
+ const char* GetInitializedCacheValue(const std::string& key) const;
+
+ const char* GetCacheEntryValue(const std::string& key)
+ {
+ cmCacheManager::CacheIterator it = this->GetCacheIterator(key.c_str());
+ if (it.IsAtEnd()) {
+ return CM_NULLPTR;
+ }
+ return it.GetValue();
+ }
+
+ const char* GetCacheEntryProperty(std::string const& key,
+ std::string const& propName)
+ {
+ return this->GetCacheIterator(key.c_str()).GetProperty(propName);
+ }
+
+ cmState::CacheEntryType GetCacheEntryType(std::string const& key)
+ {
+ return this->GetCacheIterator(key.c_str()).GetType();
+ }
+
+ bool GetCacheEntryPropertyAsBool(std::string const& key,
+ std::string const& propName)
+ {
+ return this->GetCacheIterator(key.c_str()).GetPropertyAsBool(propName);
+ }
+
+ void SetCacheEntryProperty(std::string const& key,
+ std::string const& propName,
+ std::string const& value)
+ {
+ this->GetCacheIterator(key.c_str()).SetProperty(propName, value.c_str());
+ }
+
+ void SetCacheEntryBoolProperty(std::string const& key,
+ std::string const& propName, bool value)
+ {
+ this->GetCacheIterator(key.c_str()).SetProperty(propName, value);
+ }
+
+ void SetCacheEntryValue(std::string const& key, std::string const& value)
+ {
+ this->GetCacheIterator(key.c_str()).SetValue(value.c_str());
+ }
+
+ void RemoveCacheEntryProperty(std::string const& key,
+ std::string const& propName)
+ {
+ this->GetCacheIterator(key.c_str())
+ .SetProperty(propName, (void*)CM_NULLPTR);
+ }
+
+ void AppendCacheEntryProperty(std::string const& key,
+ std::string const& propName,
+ std::string const& value,
+ bool asString = false)
+ {
+ this->GetCacheIterator(key.c_str())
+ .AppendProperty(propName, value.c_str(), asString);
+ }
+
+ std::vector<std::string> GetCacheEntryKeys()
+ {
+ std::vector<std::string> definitions;
+ definitions.reserve(this->GetSize());
+ cmCacheManager::CacheIterator cit = this->GetCacheIterator();
+ for (cit.Begin(); !cit.IsAtEnd(); cit.Next()) {
+ definitions.push_back(cit.GetName());
+ }
+ return definitions;
+ }
+
+ /** Get the version of CMake that wrote the cache. */
+ unsigned int GetCacheMajorVersion() const { return this->CacheMajorVersion; }
+ unsigned int GetCacheMinorVersion() const { return this->CacheMinorVersion; }
+
+protected:
+ ///! Add an entry into the cache
+ void AddCacheEntry(const std::string& key, const char* value,
+ const char* helpString, cmState::CacheEntryType type);
+
+ ///! Get a cache entry object for a key
+ CacheEntry* GetCacheEntry(const std::string& key);
+ ///! Clean out the CMakeFiles directory if no CMakeCache.txt
+ void CleanCMakeFiles(const std::string& path);
+
+ // Cache version info
+ unsigned int CacheMajorVersion;
+ unsigned int CacheMinorVersion;
+
+private:
+ cmake* CMakeInstance;
+ typedef std::map<std::string, CacheEntry> CacheEntryMap;
+ static void OutputHelpString(std::ostream& fout,
+ const std::string& helpString);
+ static void OutputKey(std::ostream& fout, std::string const& key);
+ static void OutputValue(std::ostream& fout, std::string const& value);
+
+ static const char* PersistentProperties[];
+ bool ReadPropertyEntry(std::string const& key, CacheEntry& e);
+ void WritePropertyEntries(std::ostream& os, CacheIterator const& i);
+
+ CacheEntryMap Cache;
+ // Only cmake and cmState should be able to add cache values
+ // the commands should never use the cmCacheManager directly
+ friend class cmState; // allow access to add cache values
+ friend class cmake; // allow access to add cache values
+};
+
+#endif
diff --git a/Source/cmCallVisualStudioMacro.cxx b/Source/cmCallVisualStudioMacro.cxx
new file mode 100644
index 0000000..515699d
--- /dev/null
+++ b/Source/cmCallVisualStudioMacro.cxx
@@ -0,0 +1,460 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCallVisualStudioMacro.h"
+
+#include "cmSystemTools.h"
+
+#if defined(_MSC_VER)
+#define HAVE_COMDEF_H
+#endif
+
+// Just for this file:
+//
+static bool LogErrorsAsMessages;
+
+#if defined(HAVE_COMDEF_H)
+
+#include <comdef.h>
+
+// Copied from a correct comdef.h to avoid problems with deficient versions
+// of comdef.h that exist in the wild... Fixes issue #7533.
+//
+#ifdef _NATIVE_WCHAR_T_DEFINED
+#ifdef _DEBUG
+#pragma comment(lib, "comsuppwd.lib")
+#else
+#pragma comment(lib, "comsuppw.lib")
+#endif
+#else
+#ifdef _DEBUG
+#pragma comment(lib, "comsuppd.lib")
+#else
+#pragma comment(lib, "comsupp.lib")
+#endif
+#endif
+
+///! 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) { \
+ std::ostringstream _hresult_oss; \
+ _hresult_oss.flags(std::ios::hex); \
+ _hresult_oss << context << " failed HRESULT, hr = 0x" << hr \
+ << std::endl; \
+ _hresult_oss.flags(std::ios::dec); \
+ _hresult_oss << __FILE__ << "(" << __LINE__ << ")"; \
+ cmSystemTools::Message(_hresult_oss.str().c_str()); \
+ } \
+ }
+
+///! Using the given instance of Visual Studio, call the named macro
+HRESULT InstanceCallMacro(IDispatch* vsIDE, const std::string& macro,
+ const std::string& args)
+{
+ HRESULT hr = E_POINTER;
+
+ _bstr_t macroName(macro.c_str());
+ _bstr_t macroArgs(args.c_str());
+
+ if (0 != vsIDE) {
+ DISPID dispid = (DISPID)-1;
+ OLECHAR* name = L"ExecuteCommand";
+
+ hr =
+ vsIDE->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
+ ReportHRESULT(hr, "GetIDsOfNames(ExecuteCommand)");
+
+ if (SUCCEEDED(hr)) {
+ VARIANTARG vargs[2];
+ DISPPARAMS params;
+ VARIANT result;
+ EXCEPINFO excep;
+ UINT arg = (UINT)-1;
+
+ // No VariantInit or VariantClear calls are necessary for
+ // these two vargs. They are both local _bstr_t variables
+ // that remain in scope for the duration of the Invoke call.
+ //
+ V_VT(&vargs[1]) = VT_BSTR;
+ V_BSTR(&vargs[1]) = macroName;
+ V_VT(&vargs[0]) = VT_BSTR;
+ V_BSTR(&vargs[0]) = macroArgs;
+
+ params.rgvarg = &vargs[0];
+ params.rgdispidNamedArgs = 0;
+ params.cArgs = sizeof(vargs) / sizeof(vargs[0]);
+ params.cNamedArgs = 0;
+
+ VariantInit(&result);
+
+ memset(&excep, 0, sizeof(excep));
+
+ hr = vsIDE->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
+ DISPATCH_METHOD, &params, &result, &excep, &arg);
+
+ std::ostringstream oss;
+ oss << std::endl;
+ oss << "Invoke(ExecuteCommand)" << std::endl;
+ oss << " Macro: " << macro << std::endl;
+ oss << " Args: " << args << std::endl;
+
+ if (DISP_E_EXCEPTION == hr) {
+ oss << "DISP_E_EXCEPTION EXCEPINFO:" << excep.wCode << std::endl;
+ oss << " wCode: " << excep.wCode << std::endl;
+ oss << " wReserved: " << excep.wReserved << std::endl;
+ if (excep.bstrSource) {
+ oss << " bstrSource: " << (const char*)(_bstr_t)excep.bstrSource
+ << std::endl;
+ }
+ if (excep.bstrDescription) {
+ oss << " bstrDescription: "
+ << (const char*)(_bstr_t)excep.bstrDescription << std::endl;
+ }
+ if (excep.bstrHelpFile) {
+ oss << " bstrHelpFile: " << (const char*)(_bstr_t)excep.bstrHelpFile
+ << std::endl;
+ }
+ oss << " dwHelpContext: " << excep.dwHelpContext << std::endl;
+ oss << " pvReserved: " << excep.pvReserved << std::endl;
+ oss << " pfnDeferredFillIn: " << excep.pfnDeferredFillIn << std::endl;
+ oss << " scode: " << excep.scode << std::endl;
+ }
+
+ std::string exstr(oss.str());
+ ReportHRESULT(hr, exstr.c_str());
+
+ VariantClear(&result);
+ }
+ }
+
+ return hr;
+}
+
+///! 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";
+
+ hr =
+ vsIDE->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
+ ReportHRESULT(hr, "GetIDsOfNames(Solution)");
+
+ if (SUCCEEDED(hr)) {
+ DISPPARAMS params;
+ VARIANT result;
+ EXCEPINFO excep;
+ UINT arg = (UINT)-1;
+
+ params.rgvarg = 0;
+ params.rgdispidNamedArgs = 0;
+ params.cArgs = 0;
+ params.cNamedArgs = 0;
+
+ VariantInit(&result);
+
+ memset(&excep, 0, sizeof(excep));
+
+ hr = vsIDE->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
+ DISPATCH_PROPERTYGET, &params, &result, &excep, &arg);
+ ReportHRESULT(hr, "Invoke(Solution)");
+
+ if (SUCCEEDED(hr)) {
+ vsSolution = V_DISPATCH(&result);
+ }
+
+ VariantClear(&result);
+ }
+ }
+
+ return hr;
+}
+
+///! 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";
+
+ hr = vsSolution->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT,
+ &dispid);
+ ReportHRESULT(hr, "GetIDsOfNames(FullName)");
+
+ if (SUCCEEDED(hr)) {
+ DISPPARAMS params;
+ VARIANT result;
+ EXCEPINFO excep;
+ UINT arg = (UINT)-1;
+
+ params.rgvarg = 0;
+ params.rgdispidNamedArgs = 0;
+ params.cArgs = 0;
+ params.cNamedArgs = 0;
+
+ VariantInit(&result);
+
+ memset(&excep, 0, sizeof(excep));
+
+ hr = vsSolution->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
+ DISPATCH_PROPERTYGET, &params, &result, &excep,
+ &arg);
+ ReportHRESULT(hr, "Invoke(FullName)");
+
+ if (SUCCEEDED(hr)) {
+ fullName = (std::string)(_bstr_t)V_BSTR(&result);
+ }
+
+ VariantClear(&result);
+ }
+ }
+
+ return hr;
+}
+
+///! Get the FullName property from the Solution object, given the IDE object
+HRESULT GetIDESolutionFullName(IDispatch* vsIDE, std::string& fullName)
+{
+ IDispatchPtr vsSolution;
+ HRESULT hr = GetSolutionObject(vsIDE, vsSolution);
+ ReportHRESULT(hr, "GetSolutionObject");
+
+ if (SUCCEEDED(hr)) {
+ GetSolutionFullName(vsSolution, fullName);
+ ReportHRESULT(hr, "GetSolutionFullName");
+ }
+
+ return hr;
+}
+
+///! 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
+
+ IRunningObjectTablePtr runningObjectTable;
+ IEnumMonikerPtr monikerEnumerator;
+ IMonikerPtr moniker;
+ ULONG numFetched = 0;
+
+ HRESULT hr = GetRunningObjectTable(0, &runningObjectTable);
+ ReportHRESULT(hr, "GetRunningObjectTable");
+
+ if (SUCCEEDED(hr)) {
+ hr = runningObjectTable->EnumRunning(&monikerEnumerator);
+ ReportHRESULT(hr, "EnumRunning");
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = monikerEnumerator->Reset();
+ ReportHRESULT(hr, "Reset");
+ }
+
+ if (SUCCEEDED(hr)) {
+ while (S_OK == monikerEnumerator->Next(1, &moniker, &numFetched)) {
+ std::string runningObjectName;
+ IUnknownPtr runningObjectVal;
+ IBindCtxPtr ctx;
+
+ hr = CreateBindCtx(0, &ctx);
+ ReportHRESULT(hr, "CreateBindCtx");
+
+ if (SUCCEEDED(hr)) {
+ LPOLESTR displayName = 0;
+ hr = moniker->GetDisplayName(ctx, 0, &displayName);
+ ReportHRESULT(hr, "GetDisplayName");
+ if (displayName) {
+ runningObjectName = (std::string)(_bstr_t)displayName;
+ CoTaskMemFree(displayName);
+ }
+
+ hr = runningObjectTable->GetObject(moniker, &runningObjectVal);
+ ReportHRESULT(hr, "GetObject");
+ if (SUCCEEDED(hr)) {
+ mrot.insert(std::make_pair(runningObjectName, runningObjectVal));
+ }
+ }
+
+ numFetched = 0;
+ moniker = 0;
+ }
+ }
+
+ return hr;
+}
+
+///! 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") {
+ return true;
+ }
+
+ // Otherwise, make lowercase local copies, convert to Unix slashes, and
+ // see if the resulting strings are the same:
+ std::string s1 = cmSystemTools::LowerCase(slnFile);
+ std::string s2 = cmSystemTools::LowerCase(slnName);
+ cmSystemTools::ConvertToUnixSlashes(s1);
+ cmSystemTools::ConvertToUnixSlashes(s2);
+
+ 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.
+HRESULT FindVisualStudioInstances(const std::string& slnFile,
+ std::vector<IDispatchPtr>& instances)
+{
+ std::map<std::string, IUnknownPtr> mrot;
+
+ HRESULT hr = GetRunningInstances(mrot);
+ ReportHRESULT(hr, "GetRunningInstances");
+
+ if (SUCCEEDED(hr)) {
+ std::map<std::string, IUnknownPtr>::iterator it;
+ for (it = mrot.begin(); it != mrot.end(); ++it) {
+ if (cmSystemTools::StringStartsWith(it->first.c_str(),
+ "!VisualStudio.DTE.")) {
+ IDispatchPtr disp(it->second);
+ if (disp != (IDispatch*)0) {
+ std::string slnName;
+ hr = GetIDESolutionFullName(disp, slnName);
+ ReportHRESULT(hr, "GetIDESolutionFullName");
+
+ if (FilesSameSolution(slnFile, slnName)) {
+ instances.push_back(disp);
+
+ // std::cout << "Found Visual Studio instance." << std::endl;
+ // std::cout << " ROT entry name: " << it->first << std::endl;
+ // std::cout << " ROT entry object: "
+ // << (IUnknown*) it->second << std::endl;
+ // std::cout << " slnFile: " << slnFile << std::endl;
+ // std::cout << " slnName: " << slnName << std::endl;
+ }
+ }
+ }
+ }
+ }
+
+ return hr;
+}
+
+#endif // defined(HAVE_COMDEF_H)
+
+int cmCallVisualStudioMacro::GetNumberOfRunningVisualStudioInstances(
+ const std::string& slnFile)
+{
+ int count = 0;
+
+ LogErrorsAsMessages = false;
+
+#if defined(HAVE_COMDEF_H)
+ HRESULT hr = CoInitialize(0);
+ ReportHRESULT(hr, "CoInitialize");
+
+ if (SUCCEEDED(hr)) {
+ std::vector<IDispatchPtr> instances;
+ hr = FindVisualStudioInstances(slnFile, instances);
+ ReportHRESULT(hr, "FindVisualStudioInstances");
+
+ if (SUCCEEDED(hr)) {
+ count = static_cast<int>(instances.size());
+ }
+
+ // Force release all COM pointers before CoUninitialize:
+ instances.clear();
+
+ CoUninitialize();
+ }
+#else
+ (void)slnFile;
+#endif
+
+ return count;
+}
+
+///! 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,
+ const bool logErrorsAsMessages)
+{
+ int err = 1; // no comdef.h
+
+ LogErrorsAsMessages = logErrorsAsMessages;
+
+#if defined(HAVE_COMDEF_H)
+ err = 2; // error initializing
+
+ HRESULT hr = CoInitialize(0);
+ ReportHRESULT(hr, "CoInitialize");
+
+ if (SUCCEEDED(hr)) {
+ std::vector<IDispatchPtr> instances;
+ hr = FindVisualStudioInstances(slnFile, instances);
+ ReportHRESULT(hr, "FindVisualStudioInstances");
+
+ if (SUCCEEDED(hr)) {
+ err = 0; // no error
+
+ std::vector<IDispatchPtr>::iterator it;
+ for (it = instances.begin(); it != instances.end(); ++it) {
+ hr = InstanceCallMacro(*it, macro, args);
+ ReportHRESULT(hr, "InstanceCallMacro");
+
+ if (FAILED(hr)) {
+ err = 3; // error attempting to call the macro
+ }
+ }
+
+ if (instances.empty()) {
+ // no instances to call
+
+ // cmSystemTools::Message(
+ // "cmCallVisualStudioMacro::CallMacro no instances found to call",
+ // "Warning");
+ }
+ }
+
+ // Force release all COM pointers before CoUninitialize:
+ instances.clear();
+
+ CoUninitialize();
+ }
+#else
+ (void)slnFile;
+ (void)macro;
+ (void)args;
+ if (LogErrorsAsMessages) {
+ cmSystemTools::Message("cmCallVisualStudioMacro::CallMacro is not "
+ "supported on this platform");
+ }
+#endif
+
+ if (err && LogErrorsAsMessages) {
+ std::ostringstream oss;
+ oss << "cmCallVisualStudioMacro::CallMacro failed, err = " << err;
+ cmSystemTools::Message(oss.str().c_str());
+ }
+
+ return 0;
+}
diff --git a/Source/cmCallVisualStudioMacro.h b/Source/cmCallVisualStudioMacro.h
new file mode 100644
index 0000000..e516fe2
--- /dev/null
+++ b/Source/cmCallVisualStudioMacro.h
@@ -0,0 +1,43 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCallVisualStudioMacro_h
+#define cmCallVisualStudioMacro_h
+
+#include "cmStandardIncludes.h"
+
+/** \class cmCallVisualStudioMacro
+ * \brief Control class for communicating with CMake's Visual Studio macros
+ *
+ * Find running instances of Visual Studio by full path solution name.
+ * Call a Visual Studio IDE macro in any of those instances.
+ */
+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.
+ 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.
+ static int GetNumberOfRunningVisualStudioInstances(
+ const std::string& slnFile);
+
+protected:
+private:
+};
+
+#endif
diff --git a/Source/cmCommand.h b/Source/cmCommand.h
new file mode 100644
index 0000000..a5f20e6
--- /dev/null
+++ b/Source/cmCommand.h
@@ -0,0 +1,185 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCommand_h
+#define cmCommand_h
+
+#include "cmObject.h"
+
+#include "cmCommandArgumentsHelper.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+
+/** \class cmCommand
+ * \brief Superclass for all commands in CMake.
+ *
+ * cmCommand is the base class for all commands in CMake. A command
+ * manifests as an entry in CMakeLists.txt and produces one or
+ * more makefile rules. Commands are associated with a particular
+ * makefile. This base class cmCommand defines the API for commands
+ * to support such features as enable/disable, inheritance,
+ * documentation, and construction.
+ */
+class cmCommand : public cmObject
+{
+public:
+ cmTypeMacro(cmCommand, cmObject);
+
+ /**
+ * Construct the command. By default it is enabled with no makefile.
+ */
+ cmCommand()
+ {
+ this->Makefile = CM_NULLPTR;
+ this->Enabled = true;
+ }
+
+ /**
+ * Need virtual destructor to destroy real command type.
+ */
+ ~cmCommand() CM_OVERRIDE {}
+
+ /**
+ * Specify the makefile.
+ */
+ void SetMakefile(cmMakefile* m) { this->Makefile = m; }
+ cmMakefile* GetMakefile() { return this->Makefile; }
+
+ /**
+ * This is called by the cmMakefile when the command is first
+ * encountered in the CMakeLists.txt file. It expands the command's
+ * arguments and then invokes the InitialPass.
+ */
+ virtual bool InvokeInitialPass(const std::vector<cmListFileArgument>& args,
+ cmExecutionStatus& status)
+ {
+ std::vector<std::string> expandedArguments;
+ if (!this->Makefile->ExpandArguments(args, expandedArguments)) {
+ // There was an error expanding arguments. It was already
+ // reported, so we can skip this command without error.
+ return true;
+ }
+ return this->InitialPass(expandedArguments, status);
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ virtual bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&) = 0;
+
+ /**
+ * This is called at the end after all the information
+ * specified by the command is accumulated. Most commands do
+ * not implement this method. At this point, reading and
+ * writing to the cache can be done.
+ */
+ virtual void FinalPass() {}
+
+ /**
+ * Does this command have a final pass? Query after InitialPass.
+ */
+ virtual bool HasFinalPass() const { return false; }
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ virtual cmCommand* Clone() = 0;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ virtual bool IsScriptable() const { return false; }
+
+ /**
+ * This is used to avoid including this command
+ * in documentation. This is mainly used by
+ * cmMacroHelperCommand and cmFunctionHelperCommand
+ * which cannot provide appropriate documentation.
+ */
+ virtual bool ShouldAppearInDocumentation() const { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ virtual std::string GetName() const = 0;
+
+ /**
+ * Enable the command.
+ */
+ void EnabledOn() { this->Enabled = true; }
+
+ /**
+ * Disable the command.
+ */
+ void EnabledOff() { this->Enabled = false; }
+
+ /**
+ * Query whether the command is enabled.
+ */
+ bool GetEnabled() const { return this->Enabled; }
+
+ /**
+ * Disable or enable the command.
+ */
+ void SetEnabled(bool enabled) { this->Enabled = enabled; }
+
+ /**
+ * Return the last error string.
+ */
+ const char* GetError()
+ {
+ if (this->Error.empty()) {
+ this->Error = this->GetName();
+ this->Error += " unknown error.";
+ }
+ return this->Error.c_str();
+ }
+
+ /**
+ * Set the error message
+ */
+ void SetError(const std::string& e)
+ {
+ this->Error = this->GetName();
+ this->Error += " ";
+ this->Error += e;
+ }
+
+ /** Check if the command is disallowed by a policy. */
+ bool Disallowed(cmPolicies::PolicyID pol, const char* e)
+ {
+ switch (this->Makefile->GetPolicyStatus(pol)) {
+ case cmPolicies::WARN:
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(pol));
+ case cmPolicies::OLD:
+ return false;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e);
+ break;
+ }
+ return true;
+ }
+
+protected:
+ cmMakefile* Makefile;
+ cmCommandArgumentsHelper Helper;
+
+private:
+ bool Enabled;
+ std::string Error;
+};
+
+#endif
diff --git a/Source/cmCommandArgumentLexer.cxx b/Source/cmCommandArgumentLexer.cxx
new file mode 100644
index 0000000..e23ef8a
--- /dev/null
+++ b/Source/cmCommandArgumentLexer.cxx
@@ -0,0 +1,2077 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmStandardIncludes.h"
+
+#line 2 "cmCommandArgumentLexer.cxx"
+
+#line 4 "cmCommandArgumentLexer.cxx"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE cmCommandArgument_yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via cmCommandArgument_yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void cmCommandArgument_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void cmCommandArgument_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmCommandArgument_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void cmCommandArgument_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmCommandArgument_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmCommandArgument_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void cmCommandArgument_yypop_buffer_state (yyscan_t yyscanner );
+
+static void cmCommandArgument_yyensure_buffer_stack (yyscan_t yyscanner );
+static void cmCommandArgument_yy_load_buffer_state (yyscan_t yyscanner );
+static void cmCommandArgument_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER cmCommandArgument_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE cmCommandArgument_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmCommandArgument_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmCommandArgument_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *cmCommandArgument_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *cmCommandArgument_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void cmCommandArgument_yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer cmCommandArgument_yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ cmCommandArgument_yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ cmCommandArgument_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ cmCommandArgument_yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ cmCommandArgument_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cmCommandArgument_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 14
+#define YY_END_OF_BUFFER 15
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[30] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 15, 9, 10, 7,
+ 6, 14, 11, 5, 12, 13, 9, 0, 0, 4,
+ 7, 0, 8, 2, 0, 3, 0, 1, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 3, 1, 1, 1, 1,
+ 1, 1, 4, 1, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 1, 1, 1,
+ 1, 1, 1, 5, 4, 4, 4, 4, 6, 4,
+ 4, 4, 4, 4, 4, 4, 4, 7, 4, 4,
+ 4, 4, 4, 4, 4, 8, 4, 4, 4, 4,
+ 1, 9, 1, 1, 4, 1, 4, 4, 4, 4,
+
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 10, 1, 11, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[12] =
+ { 0,
+ 1, 2, 3, 4, 3, 4, 4, 4, 3, 5,
+ 3
+ } ;
+
+static yyconst flex_int16_t yy_base[35] =
+ { 0,
+ 0, 0, 31, 30, 29, 28, 36, 0, 6, 16,
+ 0, 41, 41, 41, 0, 41, 0, 22, 22, 41,
+ 18, 18, 41, 41, 7, 41, 4, 41, 41, 20,
+ 21, 26, 9, 30
+ } ;
+
+static yyconst flex_int16_t yy_def[35] =
+ { 0,
+ 29, 1, 1, 1, 1, 1, 29, 30, 31, 32,
+ 33, 29, 29, 29, 34, 29, 30, 31, 18, 29,
+ 32, 33, 29, 29, 18, 29, 18, 29, 0, 29,
+ 29, 29, 29, 29
+ } ;
+
+static yyconst flex_int16_t yy_nxt[53] =
+ { 0,
+ 8, 8, 9, 10, 11, 10, 10, 10, 12, 13,
+ 14, 19, 22, 28, 27, 20, 17, 17, 17, 17,
+ 17, 17, 26, 17, 18, 18, 21, 21, 25, 21,
+ 23, 24, 23, 23, 23, 29, 16, 16, 15, 15,
+ 7, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29
+ } ;
+
+static yyconst flex_int16_t yy_chk[53] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 9, 33, 27, 25, 9, 10, 10, 21, 21,
+ 30, 30, 22, 30, 31, 31, 32, 32, 19, 32,
+ 34, 18, 34, 34, 34, 7, 6, 5, 4, 3,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29
+ } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "cmCommandArgumentLexer.in.l"
+#line 2 "cmCommandArgumentLexer.in.l"
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run flex like this:
+
+ flex --prefix=cmCommandArgument_yy --header-file=cmCommandArgumentLexer.h -ocmCommandArgumentLexer.cxx cmCommandArgumentLexer.in.l
+
+Modify cmCommandArgumentLexer.cxx:
+ - add #include "cmStandardIncludes.h" to top of file
+ - put header block at top of file
+ - remove TABs
+ - remove "yyscanner" argument from these methods:
+ yy_fatal_error, cmCommandArgument_yyalloc, cmCommandArgument_yyrealloc, cmCommandArgument_yyfree
+ - remove all YY_BREAK lines occurring right after return statements
+ - change while ( 1 ) to for(;;)
+ - add "return 0;" to end of cmCommandArgument_yylex
+
+Modify cmCommandArgumentLexer.h:
+ - remove TABs
+ - remove the yy_init_globals function
+ - remove the block that includes unistd.h
+ - remove #line directives (avoids bogus warning on old Sun)
+
+*/
+
+#include "cmStandardLexer.h"
+
+#include "cmCommandArgumentParserHelper.h"
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ { result = yyextra->LexInput(buf, max_size); }
+
+/* Include the set of tokens from the parser. */
+#include "cmCommandArgumentParserTokens.h"
+
+/*--------------------------------------------------------------------------*/
+
+
+#line 508 "cmCommandArgumentLexer.cxx"
+
+#define INITIAL 0
+#define ESCAPES 1
+#define NOESCAPES 2
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+int cmCommandArgument_yylex_init (yyscan_t* scanner);
+
+int cmCommandArgument_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int cmCommandArgument_yylex_destroy (yyscan_t yyscanner );
+
+int cmCommandArgument_yyget_debug (yyscan_t yyscanner );
+
+void cmCommandArgument_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE cmCommandArgument_yyget_extra (yyscan_t yyscanner );
+
+void cmCommandArgument_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *cmCommandArgument_yyget_in (yyscan_t yyscanner );
+
+void cmCommandArgument_yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *cmCommandArgument_yyget_out (yyscan_t yyscanner );
+
+void cmCommandArgument_yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+int cmCommandArgument_yyget_leng (yyscan_t yyscanner );
+
+char *cmCommandArgument_yyget_text (yyscan_t yyscanner );
+
+int cmCommandArgument_yyget_lineno (yyscan_t yyscanner );
+
+void cmCommandArgument_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int cmCommandArgument_yywrap (yyscan_t yyscanner );
+#else
+extern int cmCommandArgument_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int cmCommandArgument_yylex (yyscan_t yyscanner);
+
+#define YY_DECL int cmCommandArgument_yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+#line 64 "cmCommandArgumentLexer.in.l"
+
+
+#line 732 "cmCommandArgumentLexer.cxx"
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ cmCommandArgument_yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ cmCommandArgument_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ cmCommandArgument_yy_load_buffer_state(yyscanner );
+ }
+
+ for(;;) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 30 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 41 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 66 "cmCommandArgumentLexer.in.l"
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext+1, strlen(yytext)-2);
+ return cal_ENVCURLY;
+}
+case 2:
+YY_RULE_SETUP
+#line 72 "cmCommandArgumentLexer.in.l"
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext+1, strlen(yytext)-2);
+ return cal_NCURLY;
+}
+case 3:
+YY_RULE_SETUP
+#line 78 "cmCommandArgumentLexer.in.l"
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext+1, strlen(yytext)-2);
+ return cal_ATNAME;
+}
+case 4:
+YY_RULE_SETUP
+#line 84 "cmCommandArgumentLexer.in.l"
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->DCURLYVariable;
+ return cal_DCURLY;
+}
+case 5:
+YY_RULE_SETUP
+#line 91 "cmCommandArgumentLexer.in.l"
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->RCURLYVariable;
+ return cal_RCURLY;
+}
+case 6:
+YY_RULE_SETUP
+#line 98 "cmCommandArgumentLexer.in.l"
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->ATVariable;
+ return cal_AT;
+}
+case 7:
+YY_RULE_SETUP
+#line 105 "cmCommandArgumentLexer.in.l"
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ return cal_NAME;
+}
+case 8:
+YY_RULE_SETUP
+#line 111 "cmCommandArgumentLexer.in.l"
+{
+ if ( !yyextra->HandleEscapeSymbol(yylvalp, *(yytext+1)) )
+ {
+ return cal_ERROR;
+ }
+ return cal_SYMBOL;
+}
+case 9:
+/* rule 9 can match eol */
+YY_RULE_SETUP
+#line 119 "cmCommandArgumentLexer.in.l"
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ return cal_SYMBOL;
+}
+case 10:
+YY_RULE_SETUP
+#line 125 "cmCommandArgumentLexer.in.l"
+{
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->DOLLARVariable;
+ return cal_DOLLAR;
+}
+case 11:
+YY_RULE_SETUP
+#line 131 "cmCommandArgumentLexer.in.l"
+{
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->LCURLYVariable;
+ return cal_LCURLY;
+}
+case 12:
+YY_RULE_SETUP
+#line 137 "cmCommandArgumentLexer.in.l"
+{
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->BSLASHVariable;
+ return cal_BSLASH;
+}
+case 13:
+YY_RULE_SETUP
+#line 143 "cmCommandArgumentLexer.in.l"
+{
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->BSLASHVariable;
+ return cal_SYMBOL;
+}
+case 14:
+YY_RULE_SETUP
+#line 149 "cmCommandArgumentLexer.in.l"
+ECHO;
+ YY_BREAK
+#line 943 "cmCommandArgumentLexer.cxx"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(ESCAPES):
+case YY_STATE_EOF(NOESCAPES):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * cmCommandArgument_yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( cmCommandArgument_yywrap(yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+return 0; /* this should not happen but it quiets some compilers */
+} /* end of cmCommandArgument_yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ cmCommandArgument_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, (size_t) num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ cmCommandArgument_yyrestart(yyin ,yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) cmCommandArgument_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 30 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 30 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 29);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ cmCommandArgument_yyrestart(yyin ,yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( cmCommandArgument_yywrap(yyscanner ) )
+ return EOF;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void cmCommandArgument_yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ cmCommandArgument_yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ cmCommandArgument_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ cmCommandArgument_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+ cmCommandArgument_yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void cmCommandArgument_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * cmCommandArgument_yypop_buffer_state();
+ * cmCommandArgument_yypush_buffer_state(new_buffer);
+ */
+ cmCommandArgument_yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ cmCommandArgument_yy_load_buffer_state(yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (cmCommandArgument_yywrap()) processing, but the only time this flag
+ * is looked at is after cmCommandArgument_yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void cmCommandArgument_yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE cmCommandArgument_yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) cmCommandArgument_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in cmCommandArgument_yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) cmCommandArgument_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in cmCommandArgument_yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ cmCommandArgument_yy_init_buffer(b,file ,yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with cmCommandArgument_yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void cmCommandArgument_yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ cmCommandArgument_yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+ cmCommandArgument_yyfree((void *) b ,yyscanner );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a cmCommandArgument_yyrestart() or at EOF.
+ */
+ static void cmCommandArgument_yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ cmCommandArgument_yy_flush_buffer(b ,yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then cmCommandArgument_yy_init_buffer was _probably_
+ * called from cmCommandArgument_yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void cmCommandArgument_yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ cmCommandArgument_yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void cmCommandArgument_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ cmCommandArgument_yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from cmCommandArgument_yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from cmCommandArgument_yy_switch_to_buffer. */
+ cmCommandArgument_yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void cmCommandArgument_yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ cmCommandArgument_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ cmCommandArgument_yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void cmCommandArgument_yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ int num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)cmCommandArgument_yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in cmCommandArgument_yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)cmCommandArgument_yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in cmCommandArgument_yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cmCommandArgument_yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) cmCommandArgument_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in cmCommandArgument_yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ cmCommandArgument_yy_switch_to_buffer(b ,yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to cmCommandArgument_yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * cmCommandArgument_yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE cmCommandArgument_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+
+ return cmCommandArgument_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to cmCommandArgument_yylex() will
+ * scan from a @e copy of @a yybytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cmCommandArgument_yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) cmCommandArgument_yyalloc(n ,yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in cmCommandArgument_yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = cmCommandArgument_yy_scan_buffer(buf,n ,yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in cmCommandArgument_yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t)
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE cmCommandArgument_yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int cmCommandArgument_yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int cmCommandArgument_yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *cmCommandArgument_yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *cmCommandArgument_yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int cmCommandArgument_yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *cmCommandArgument_yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void cmCommandArgument_yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number The line number to set.
+ * @param yyscanner The scanner object.
+ */
+void cmCommandArgument_yyset_lineno (int line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "cmCommandArgument_yyset_lineno called with no buffer" , yyscanner);
+
+ yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param column_no The column number to set.
+ * @param yyscanner The scanner object.
+ */
+void cmCommandArgument_yyset_column (int column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "cmCommandArgument_yyset_column called with no buffer" , yyscanner);
+
+ yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see cmCommandArgument_yy_switch_to_buffer
+ */
+void cmCommandArgument_yyset_in (FILE * in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = in_str ;
+}
+
+void cmCommandArgument_yyset_out (FILE * out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = out_str ;
+}
+
+int cmCommandArgument_yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void cmCommandArgument_yyset_debug (int bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+/* User-visible API */
+
+/* cmCommandArgument_yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int cmCommandArgument_yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) cmCommandArgument_yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* cmCommandArgument_yylex_init_extra has the same functionality as cmCommandArgument_yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to cmCommandArgument_yyalloc in
+ * the yyextra field.
+ */
+
+int cmCommandArgument_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+ struct yyguts_t dummy_yyguts;
+
+ cmCommandArgument_yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) cmCommandArgument_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ cmCommandArgument_yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from cmCommandArgument_yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = 0;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = (char *) 0;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * cmCommandArgument_yylex_init()
+ */
+ return 0;
+}
+
+/* cmCommandArgument_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int cmCommandArgument_yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ cmCommandArgument_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ cmCommandArgument_yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ cmCommandArgument_yyfree(yyg->yy_buffer_stack ,yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ cmCommandArgument_yyfree(yyg->yy_start_stack ,yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * cmCommandArgument_yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ cmCommandArgument_yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *cmCommandArgument_yyalloc (yy_size_t size , yyscan_t)
+{
+ return (void *) malloc( size );
+}
+
+void *cmCommandArgument_yyrealloc (void * ptr, yy_size_t size , yyscan_t)
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void cmCommandArgument_yyfree (void * ptr , yyscan_t)
+{
+ free( (char *) ptr ); /* see cmCommandArgument_yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 149 "cmCommandArgumentLexer.in.l"
+
+
+
+/*--------------------------------------------------------------------------*/
+void cmCommandArgument_SetupEscapes(yyscan_t yyscanner, bool noEscapes)
+{
+ /* Hack into the internal flex-generated scanner to set the state. */
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if(noEscapes)
+ {
+ BEGIN(NOESCAPES);
+ }
+ else
+ {
+ BEGIN(ESCAPES);
+ }
+}
+
diff --git a/Source/cmCommandArgumentLexer.h b/Source/cmCommandArgumentLexer.h
new file mode 100644
index 0000000..2ea3fa2
--- /dev/null
+++ b/Source/cmCommandArgumentLexer.h
@@ -0,0 +1,333 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCommandArgument_yyHEADER_H
+#define cmCommandArgument_yyHEADER_H 1
+#define cmCommandArgument_yyIN_HEADER 1
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void cmCommandArgument_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void cmCommandArgument_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmCommandArgument_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void cmCommandArgument_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmCommandArgument_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmCommandArgument_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void cmCommandArgument_yypop_buffer_state (yyscan_t yyscanner );
+
+YY_BUFFER_STATE cmCommandArgument_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmCommandArgument_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmCommandArgument_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *cmCommandArgument_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *cmCommandArgument_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void cmCommandArgument_yyfree (void * ,yyscan_t yyscanner );
+
+/* Begin user sect3 */
+
+#define cmCommandArgument_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+#define ESCAPES 1
+#define NOESCAPES 2
+
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+int cmCommandArgument_yylex_init (yyscan_t* scanner);
+
+int cmCommandArgument_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int cmCommandArgument_yylex_destroy (yyscan_t yyscanner );
+
+int cmCommandArgument_yyget_debug (yyscan_t yyscanner );
+
+void cmCommandArgument_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE cmCommandArgument_yyget_extra (yyscan_t yyscanner );
+
+void cmCommandArgument_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *cmCommandArgument_yyget_in (yyscan_t yyscanner );
+
+void cmCommandArgument_yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *cmCommandArgument_yyget_out (yyscan_t yyscanner );
+
+void cmCommandArgument_yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+int cmCommandArgument_yyget_leng (yyscan_t yyscanner );
+
+char *cmCommandArgument_yyget_text (yyscan_t yyscanner );
+
+int cmCommandArgument_yyget_lineno (yyscan_t yyscanner );
+
+void cmCommandArgument_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int cmCommandArgument_yywrap (yyscan_t yyscanner );
+#else
+extern int cmCommandArgument_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int cmCommandArgument_yylex (yyscan_t yyscanner);
+
+#define YY_DECL int cmCommandArgument_yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#undef cmCommandArgument_yyIN_HEADER
+#endif /* cmCommandArgument_yyHEADER_H */
diff --git a/Source/cmCommandArgumentLexer.in.l b/Source/cmCommandArgumentLexer.in.l
new file mode 100644
index 0000000..24a0eec
--- /dev/null
+++ b/Source/cmCommandArgumentLexer.in.l
@@ -0,0 +1,162 @@
+%{
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run flex like this:
+
+ flex --prefix=cmCommandArgument_yy --header-file=cmCommandArgumentLexer.h -ocmCommandArgumentLexer.cxx cmCommandArgumentLexer.in.l
+
+Modify cmCommandArgumentLexer.cxx:
+ - add #include "cmStandardIncludes.h" to top of file
+ - put header block at top of file
+ - remove TABs
+ - remove use of the 'register' storage class specifier
+ - remove "yyscanner" argument from these methods:
+ yy_fatal_error, cmCommandArgument_yyalloc, cmCommandArgument_yyrealloc, cmCommandArgument_yyfree
+ - remove all YY_BREAK lines occurring right after return statements
+ - change while ( 1 ) to for(;;)
+ - add "return 0;" to end of cmCommandArgument_yylex
+
+Modify cmCommandArgumentLexer.h:
+ - remove TABs
+ - remove the yy_init_globals function
+ - remove the block that includes unistd.h
+ - remove #line directives (avoids bogus warning on old Sun)
+
+*/
+
+#include "cmStandardLexer.h"
+
+#include "cmCommandArgumentParserHelper.h"
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ { result = yyextra->LexInput(buf, max_size); }
+
+/* Include the set of tokens from the parser. */
+#include "cmCommandArgumentParserTokens.h"
+
+/*--------------------------------------------------------------------------*/
+%}
+
+%option reentrant
+%option noyywrap
+%option nounput
+%pointer
+%s ESCAPES
+%s NOESCAPES
+
+%%
+
+\$ENV\{ {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext+1, strlen(yytext)-2);
+ return cal_ENVCURLY;
+}
+
+\$[A-Za-z0-9/_.+-]+\{ {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext+1, strlen(yytext)-2);
+ return cal_NCURLY;
+}
+
+@[A-Za-z0-9/_.+-]+@ {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext+1, strlen(yytext)-2);
+ return cal_ATNAME;
+}
+
+"${" {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->DCURLYVariable;
+ return cal_DCURLY;
+}
+
+"}" {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->RCURLYVariable;
+ return cal_RCURLY;
+}
+
+"@" {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->ATVariable;
+ return cal_AT;
+}
+
+[A-Za-z0-9/_.+-]+ {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ return cal_NAME;
+}
+
+<ESCAPES>\\. {
+ if ( !yyextra->HandleEscapeSymbol(yylvalp, *(yytext+1)) )
+ {
+ return cal_ERROR;
+ }
+ return cal_SYMBOL;
+}
+
+[^\${}\\@]+ {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ return cal_SYMBOL;
+}
+
+"$" {
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->DOLLARVariable;
+ return cal_DOLLAR;
+}
+
+"{" {
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->LCURLYVariable;
+ return cal_LCURLY;
+}
+
+<ESCAPES>"\\" {
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->BSLASHVariable;
+ return cal_BSLASH;
+}
+
+<NOESCAPES>"\\" {
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = yyextra->BSLASHVariable;
+ return cal_SYMBOL;
+}
+
+%%
+
+/*--------------------------------------------------------------------------*/
+void cmCommandArgument_SetupEscapes(yyscan_t yyscanner, bool noEscapes)
+{
+ /* Hack into the internal flex-generated scanner to set the state. */
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if(noEscapes)
+ {
+ BEGIN(NOESCAPES);
+ }
+ else
+ {
+ BEGIN(ESCAPES);
+ }
+}
diff --git a/Source/cmCommandArgumentParser.cxx b/Source/cmCommandArgumentParser.cxx
new file mode 100644
index 0000000..9f8a4de
--- /dev/null
+++ b/Source/cmCommandArgumentParser.cxx
@@ -0,0 +1,1829 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names. */
+#define yyparse cmCommandArgument_yyparse
+#define yylex cmCommandArgument_yylex
+#define yyerror cmCommandArgument_yyerror
+#define yylval cmCommandArgument_yylval
+#define yychar cmCommandArgument_yychar
+#define yydebug cmCommandArgument_yydebug
+#define yynerrs cmCommandArgument_yynerrs
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ cal_ENVCURLY = 258,
+ cal_NCURLY = 259,
+ cal_DCURLY = 260,
+ cal_DOLLAR = 261,
+ cal_LCURLY = 262,
+ cal_RCURLY = 263,
+ cal_NAME = 264,
+ cal_BSLASH = 265,
+ cal_SYMBOL = 266,
+ cal_AT = 267,
+ cal_ERROR = 268,
+ cal_ATNAME = 269
+ };
+#endif
+/* Tokens. */
+#define cal_ENVCURLY 258
+#define cal_NCURLY 259
+#define cal_DCURLY 260
+#define cal_DOLLAR 261
+#define cal_LCURLY 262
+#define cal_RCURLY 263
+#define cal_NAME 264
+#define cal_BSLASH 265
+#define cal_SYMBOL 266
+#define cal_AT 267
+#define cal_ERROR 268
+#define cal_ATNAME 269
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 1 "cmCommandArgumentParser.y"
+
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --yacc --name-prefix=cmCommandArgument_yy --defines=cmCommandArgumentParserTokens.h -ocmCommandArgumentParser.cxx cmCommandArgumentParser.y
+
+Modify cmCommandArgumentParser.cxx:
+ - remove TABs
+ - put header block at top of file
+
+*/
+
+#include "cmStandardIncludes.h"
+
+/* Configure the parser to use a lexer object. */
+#define YYPARSE_PARAM yyscanner
+#define YYLEX_PARAM yyscanner
+#define YYERROR_VERBOSE 1
+#define cmCommandArgument_yyerror(x) \
+ cmCommandArgumentError(yyscanner, x)
+#define yyGetParser (cmCommandArgument_yyget_extra(yyscanner))
+
+/* Make sure malloc and free are available on QNX. */
+#ifdef __QNX__
+# include <malloc.h>
+#endif
+
+/* Make sure the parser uses standard memory allocation. The default
+ generated parser malloc/free declarations do not work on all
+ platforms. */
+#include <stdlib.h>
+#define YYMALLOC malloc
+#define YYFREE free
+
+/*-------------------------------------------------------------------------*/
+#include "cmCommandArgumentParserHelper.h" /* Interface to parser object. */
+#include "cmCommandArgumentLexer.h" /* Interface to lexer object. */
+#include "cmCommandArgumentParserTokens.h" /* Need YYSTYPE for YY_DECL. */
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Internal utility functions. */
+static void cmCommandArgumentError(yyscan_t yyscanner, const char* message);
+
+#define YYDEBUG 1
+/* Configure the parser to support large input. */
+#define YYMAXDEPTH 100000
+#define YYINITDEPTH 10000
+
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch statement contains default but no
+ case. */
+# pragma warning (disable: 4244) /* loss of precision */
+# pragma warning (disable: 4702) /* unreachable code */
+#endif
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 216 of yacc.c. */
+#line 227 "cmCommandArgumentParser.cxx"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 25
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 40
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 15
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 10
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 24
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 33
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 269
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint8 yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 10, 11, 14, 16, 18,
+ 20, 22, 24, 26, 28, 30, 34, 38, 42, 44,
+ 46, 49, 50, 53, 55
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 16, 0, -1, 17, -1, 18, -1, 18, 10, -1,
+ -1, 19, 18, -1, 20, -1, 21, -1, 9, -1,
+ 12, -1, 6, -1, 7, -1, 8, -1, 11, -1,
+ 3, 22, 8, -1, 4, 23, 8, -1, 5, 23,
+ 8, -1, 14, -1, 23, -1, 11, 22, -1, -1,
+ 24, 23, -1, 9, -1, 21, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint8 yyrline[] =
+{
+ 0, 116, 116, 123, 128, 134, 138, 144, 149, 155,
+ 160, 165, 170, 175, 180, 186, 192, 198, 204, 210,
+ 215, 221, 225, 231, 236
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "cal_ENVCURLY", "cal_NCURLY",
+ "cal_DCURLY", "\"$\"", "\"{\"", "\"}\"", "cal_NAME", "\"\\\\\"",
+ "cal_SYMBOL", "\"@\"", "cal_ERROR", "cal_ATNAME", "$accept", "Start",
+ "GoalWithOptionalBackSlash", "Goal", "String", "OuterText", "Variable",
+ "EnvVarName", "MultipleIds", "ID", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 15, 16, 17, 17, 18, 18, 19, 19, 20,
+ 20, 20, 20, 20, 20, 21, 21, 21, 21, 22,
+ 22, 23, 23, 24, 24
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 1, 1, 2, 0, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 3, 3, 3, 1, 1,
+ 2, 0, 2, 1, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 5, 21, 21, 21, 11, 12, 13, 9, 14, 10,
+ 18, 0, 2, 3, 5, 7, 8, 23, 21, 24,
+ 0, 19, 21, 0, 0, 1, 4, 6, 20, 15,
+ 22, 16, 17
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 11, 12, 13, 14, 15, 19, 20, 21, 22
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -3
+static const yytype_int8 yypact[] =
+{
+ 0, 14, 26, 26, -3, -3, -3, -3, -3, -3,
+ -3, 10, -3, 3, 0, -3, -3, -3, 14, -3,
+ 7, -3, 26, 13, 16, -3, -3, -3, -3, -3,
+ -3, -3, -3
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -3, -3, -3, 8, -3, -3, 2, 9, -2, -3
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+ 23, 24, 16, 1, 2, 3, 4, 5, 6, 7,
+ 25, 8, 9, 26, 10, 29, 16, 1, 2, 3,
+ 30, 31, 27, 17, 32, 18, 0, 28, 10, 1,
+ 2, 3, 0, 0, 0, 17, 0, 0, 0, 0,
+ 10
+};
+
+static const yytype_int8 yycheck[] =
+{
+ 2, 3, 0, 3, 4, 5, 6, 7, 8, 9,
+ 0, 11, 12, 10, 14, 8, 14, 3, 4, 5,
+ 22, 8, 14, 9, 8, 11, -1, 18, 14, 3,
+ 4, 5, -1, -1, -1, 9, -1, -1, -1, -1,
+ 14
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 3, 4, 5, 6, 7, 8, 9, 11, 12,
+ 14, 16, 17, 18, 19, 20, 21, 9, 11, 21,
+ 22, 23, 24, 23, 23, 0, 10, 18, 22, 8,
+ 23, 8, 8
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval)
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ /* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+#line 117 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = 0;
+ yyGetParser->SetResult((yyvsp[(1) - (1)].str));
+}
+ break;
+
+ case 3:
+#line 124 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+}
+ break;
+
+ case 4:
+#line 129 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->CombineUnions((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str));
+}
+ break;
+
+ case 5:
+#line 134 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = 0;
+}
+ break;
+
+ case 6:
+#line 139 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->CombineUnions((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str));
+}
+ break;
+
+ case 7:
+#line 145 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+}
+ break;
+
+ case 8:
+#line 150 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+}
+ break;
+
+ case 9:
+#line 156 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+}
+ break;
+
+ case 10:
+#line 161 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+}
+ break;
+
+ case 11:
+#line 166 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+}
+ break;
+
+ case 12:
+#line 171 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+}
+ break;
+
+ case 13:
+#line 176 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+}
+ break;
+
+ case 14:
+#line 181 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+}
+ break;
+
+ case 15:
+#line 187 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->ExpandSpecialVariable((yyvsp[(1) - (3)].str),(yyvsp[(2) - (3)].str));
+ //std::cerr << __LINE__ << " here: [" << $<str>1 << "] [" << $<str>2 << "] [" << $<str>3 << "]" << std::endl;
+}
+ break;
+
+ case 16:
+#line 193 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->ExpandSpecialVariable((yyvsp[(1) - (3)].str),(yyvsp[(2) - (3)].str));
+ //std::cerr << __LINE__ << " here: [" << $<str>1 << "] [" << $<str>2 << "] [" << $<str>3 << "]" << std::endl;
+}
+ break;
+
+ case 17:
+#line 199 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->ExpandVariable((yyvsp[(2) - (3)].str));
+ //std::cerr << __LINE__ << " here: [" << $<str>1 << "] [" << $<str>2 << "] [" << $<str>3 << "]" << std::endl;
+}
+ break;
+
+ case 18:
+#line 205 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->ExpandVariableForAt((yyvsp[(1) - (1)].str));
+}
+ break;
+
+ case 19:
+#line 211 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+}
+ break;
+
+ case 20:
+#line 216 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (2)].str);
+}
+ break;
+
+ case 21:
+#line 221 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = 0;
+}
+ break;
+
+ case 22:
+#line 226 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->CombineUnions((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str));
+}
+ break;
+
+ case 23:
+#line 232 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+}
+ break;
+
+ case 24:
+#line 237 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+}
+ break;
+
+
+/* Line 1267 of yacc.c. */
+#line 1606 "cmCommandArgumentParser.cxx"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+#line 242 "cmCommandArgumentParser.y"
+
+/* End of grammar */
+
+/*--------------------------------------------------------------------------*/
+void cmCommandArgumentError(yyscan_t yyscanner, const char* message)
+{
+ yyGetParser->Error(message);
+}
+
+
diff --git a/Source/cmCommandArgumentParser.y b/Source/cmCommandArgumentParser.y
new file mode 100644
index 0000000..b1d53f6
--- /dev/null
+++ b/Source/cmCommandArgumentParser.y
@@ -0,0 +1,240 @@
+%{
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --yacc --name-prefix=cmCommandArgument_yy --defines=cmCommandArgumentParserTokens.h -ocmCommandArgumentParser.cxx cmCommandArgumentParser.y
+
+Modify cmCommandArgumentParser.cxx:
+ - remove TABs
+ - remove use of the 'register' storage class specifier
+ - put header block at top of file
+
+*/
+
+#include "cmStandardIncludes.h"
+
+/* Configure the parser to use a lexer object. */
+#define YYPARSE_PARAM yyscanner
+#define YYLEX_PARAM yyscanner
+#define YYERROR_VERBOSE 1
+#define cmCommandArgument_yyerror(x) \
+ cmCommandArgumentError(yyscanner, x)
+#define yyGetParser (cmCommandArgument_yyget_extra(yyscanner))
+
+/* Make sure malloc and free are available on QNX. */
+#ifdef __QNX__
+# include <malloc.h>
+#endif
+
+/* Make sure the parser uses standard memory allocation. The default
+ generated parser malloc/free declarations do not work on all
+ platforms. */
+#include <stdlib.h>
+#define YYMALLOC malloc
+#define YYFREE free
+
+/*-------------------------------------------------------------------------*/
+#include "cmCommandArgumentParserHelper.h" /* Interface to parser object. */
+#include "cmCommandArgumentLexer.h" /* Interface to lexer object. */
+#include "cmCommandArgumentParserTokens.h" /* Need YYSTYPE for YY_DECL. */
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Internal utility functions. */
+static void cmCommandArgumentError(yyscan_t yyscanner, const char* message);
+
+#define YYDEBUG 1
+/* Configure the parser to support large input. */
+#define YYMAXDEPTH 100000
+#define YYINITDEPTH 10000
+
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch statement contains default but no
+ case. */
+# pragma warning (disable: 4244) /* loss of precision */
+# pragma warning (disable: 4702) /* unreachable code */
+#endif
+%}
+
+/* Generate a reentrant parser object. */
+%pure_parser
+
+/*
+%union {
+ char* string;
+}
+*/
+
+/*-------------------------------------------------------------------------*/
+/* Tokens */
+%token cal_ENVCURLY
+%token cal_NCURLY
+%token cal_DCURLY
+%token cal_DOLLAR "$"
+%token cal_LCURLY "{"
+%token cal_RCURLY "}"
+%token cal_NAME
+%token cal_BSLASH "\\"
+%token cal_SYMBOL
+%token cal_AT "@"
+%token cal_ERROR
+%token cal_ATNAME
+
+/*-------------------------------------------------------------------------*/
+/* grammar */
+%%
+
+
+Start:
+GoalWithOptionalBackSlash
+{
+ $<str>$ = 0;
+ yyGetParser->SetResult($<str>1);
+}
+
+GoalWithOptionalBackSlash:
+Goal
+{
+ $<str>$ = $<str>1;
+}
+|
+Goal cal_BSLASH
+{
+ $<str>$ = yyGetParser->CombineUnions($<str>1, $<str>2);
+}
+
+Goal:
+{
+ $<str>$ = 0;
+}
+|
+String Goal
+{
+ $<str>$ = yyGetParser->CombineUnions($<str>1, $<str>2);
+}
+
+String:
+OuterText
+{
+ $<str>$ = $<str>1;
+}
+|
+Variable
+{
+ $<str>$ = $<str>1;
+}
+
+OuterText:
+cal_NAME
+{
+ $<str>$ = $<str>1;
+}
+|
+cal_AT
+{
+ $<str>$ = $<str>1;
+}
+|
+cal_DOLLAR
+{
+ $<str>$ = $<str>1;
+}
+|
+cal_LCURLY
+{
+ $<str>$ = $<str>1;
+}
+|
+cal_RCURLY
+{
+ $<str>$ = $<str>1;
+}
+|
+cal_SYMBOL
+{
+ $<str>$ = $<str>1;
+}
+
+Variable:
+cal_ENVCURLY EnvVarName cal_RCURLY
+{
+ $<str>$ = yyGetParser->ExpandSpecialVariable($<str>1,$<str>2);
+ //std::cerr << __LINE__ << " here: [" << $<str>1 << "] [" << $<str>2 << "] [" << $<str>3 << "]" << std::endl;
+}
+|
+cal_NCURLY MultipleIds cal_RCURLY
+{
+ $<str>$ = yyGetParser->ExpandSpecialVariable($<str>1,$<str>2);
+ //std::cerr << __LINE__ << " here: [" << $<str>1 << "] [" << $<str>2 << "] [" << $<str>3 << "]" << std::endl;
+}
+|
+cal_DCURLY MultipleIds cal_RCURLY
+{
+ $<str>$ = yyGetParser->ExpandVariable($<str>2);
+ //std::cerr << __LINE__ << " here: [" << $<str>1 << "] [" << $<str>2 << "] [" << $<str>3 << "]" << std::endl;
+}
+|
+cal_ATNAME
+{
+ $<str>$ = yyGetParser->ExpandVariableForAt($<str>1);
+}
+
+EnvVarName:
+MultipleIds
+{
+ $<str>$ = $<str>1;
+}
+|
+cal_SYMBOL EnvVarName
+{
+ $<str>$ = $<str>1;
+}
+
+MultipleIds:
+{
+ $<str>$ = 0;
+}
+|
+ID MultipleIds
+{
+ $<str>$ = yyGetParser->CombineUnions($<str>1, $<str>2);
+}
+
+ID:
+cal_NAME
+{
+ $<str>$ = $<str>1;
+}
+|
+Variable
+{
+ $<str>$ = $<str>1;
+}
+
+
+%%
+/* End of grammar */
+
+/*--------------------------------------------------------------------------*/
+void cmCommandArgumentError(yyscan_t yyscanner, const char* message)
+{
+ yyGetParser->Error(message);
+}
+
diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx
new file mode 100644
index 0000000..294117c
--- /dev/null
+++ b/Source/cmCommandArgumentParserHelper.cxx
@@ -0,0 +1,321 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCommandArgumentParserHelper.h"
+
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmState.h"
+#include "cmSystemTools.h"
+
+#include "cmCommandArgumentLexer.h"
+
+int cmCommandArgument_yyparse(yyscan_t yyscanner);
+//
+cmCommandArgumentParserHelper::cmCommandArgumentParserHelper()
+{
+ this->WarnUninitialized = false;
+ this->CheckSystemVars = false;
+ this->FileLine = -1;
+ this->FileName = CM_NULLPTR;
+ this->RemoveEmpty = true;
+ this->EmptyVariable[0] = 0;
+ strcpy(this->DCURLYVariable, "${");
+ strcpy(this->RCURLYVariable, "}");
+ strcpy(this->ATVariable, "@");
+ strcpy(this->DOLLARVariable, "$");
+ strcpy(this->LCURLYVariable, "{");
+ strcpy(this->BSLASHVariable, "\\");
+
+ this->NoEscapeMode = false;
+ this->ReplaceAtSyntax = false;
+}
+
+cmCommandArgumentParserHelper::~cmCommandArgumentParserHelper()
+{
+ this->CleanupParser();
+}
+
+void cmCommandArgumentParserHelper::SetLineFile(long line, const char* file)
+{
+ this->FileLine = line;
+ this->FileName = file;
+}
+
+char* cmCommandArgumentParserHelper::AddString(const std::string& str)
+{
+ if (str.empty()) {
+ return this->EmptyVariable;
+ }
+ char* stVal = new char[str.size() + 1];
+ strcpy(stVal, str.c_str());
+ this->Variables.push_back(stVal);
+ return stVal;
+}
+
+char* cmCommandArgumentParserHelper::ExpandSpecialVariable(const char* key,
+ const char* var)
+{
+ if (!key) {
+ return this->ExpandVariable(var);
+ }
+ if (!var) {
+ return this->EmptyVariable;
+ }
+ if (strcmp(key, "ENV") == 0) {
+ char* ptr = getenv(var);
+ if (ptr) {
+ if (this->EscapeQuotes) {
+ return this->AddString(cmSystemTools::EscapeQuotes(ptr));
+ } else {
+ return ptr;
+ }
+ }
+ return this->EmptyVariable;
+ }
+ if (strcmp(key, "CACHE") == 0) {
+ if (const char* c =
+ this->Makefile->GetState()->GetInitializedCacheValue(var)) {
+ if (this->EscapeQuotes) {
+ return this->AddString(cmSystemTools::EscapeQuotes(c));
+ } else {
+ return this->AddString(c);
+ }
+ }
+ return this->EmptyVariable;
+ }
+ std::ostringstream e;
+ e << "Syntax $" << key << "{} is not supported. "
+ << "Only ${}, $ENV{}, and $CACHE{} are allowed.";
+ this->SetError(e.str());
+ return CM_NULLPTR;
+}
+
+char* cmCommandArgumentParserHelper::ExpandVariable(const char* var)
+{
+ if (!var) {
+ return CM_NULLPTR;
+ }
+ if (this->FileLine >= 0 && strcmp(var, "CMAKE_CURRENT_LIST_LINE") == 0) {
+ std::ostringstream ostr;
+ ostr << this->FileLine;
+ return this->AddString(ostr.str());
+ }
+ const char* value = this->Makefile->GetDefinition(var);
+ if (!value && !this->RemoveEmpty) {
+ // check to see if we need to print a warning
+ // if strict mode is on and the variable has
+ // not been "cleared"/initialized with a set(foo ) call
+ if (this->WarnUninitialized && !this->Makefile->VariableInitialized(var)) {
+ if (this->CheckSystemVars ||
+ cmSystemTools::IsSubDirectory(this->FileName,
+ this->Makefile->GetHomeDirectory()) ||
+ cmSystemTools::IsSubDirectory(
+ this->FileName, this->Makefile->GetHomeOutputDirectory())) {
+ std::ostringstream msg;
+ msg << "uninitialized variable \'" << var << "\'";
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, msg.str());
+ }
+ }
+ return CM_NULLPTR;
+ }
+ if (this->EscapeQuotes && value) {
+ return this->AddString(cmSystemTools::EscapeQuotes(value));
+ }
+ return this->AddString(value ? value : "");
+}
+
+char* cmCommandArgumentParserHelper::ExpandVariableForAt(const char* var)
+{
+ if (this->ReplaceAtSyntax) {
+ // try to expand the variable
+ char* ret = this->ExpandVariable(var);
+ // if the return was 0 and we want to replace empty strings
+ // then return an empty string
+ if (!ret && this->RemoveEmpty) {
+ return this->AddString("");
+ }
+ // if the ret was not 0, then return it
+ if (ret) {
+ return ret;
+ }
+ }
+ // at this point we want to put it back because of one of these cases:
+ // - this->ReplaceAtSyntax is false
+ // - this->ReplaceAtSyntax is true, but this->RemoveEmpty is false,
+ // and the variable was not defined
+ std::string ref = "@";
+ ref += var;
+ ref += "@";
+ return this->AddString(ref);
+}
+
+char* cmCommandArgumentParserHelper::CombineUnions(char* in1, char* in2)
+{
+ if (!in1) {
+ return in2;
+ } else if (!in2) {
+ return in1;
+ }
+ size_t len = strlen(in1) + strlen(in2) + 1;
+ char* out = new char[len];
+ strcpy(out, in1);
+ strcat(out, in2);
+ this->Variables.push_back(out);
+ return out;
+}
+
+void cmCommandArgumentParserHelper::AllocateParserType(
+ cmCommandArgumentParserHelper::ParserType* pt, const char* str, int len)
+{
+ pt->str = CM_NULLPTR;
+ if (len == 0) {
+ len = static_cast<int>(strlen(str));
+ }
+ if (len == 0) {
+ return;
+ }
+ pt->str = new char[len + 1];
+ strncpy(pt->str, str, len);
+ pt->str[len] = 0;
+ this->Variables.push_back(pt->str);
+}
+
+bool cmCommandArgumentParserHelper::HandleEscapeSymbol(
+ cmCommandArgumentParserHelper::ParserType* pt, char symbol)
+{
+ switch (symbol) {
+ case '\\':
+ case '"':
+ case ' ':
+ case '#':
+ case '(':
+ case ')':
+ case '$':
+ case '@':
+ case '^':
+ this->AllocateParserType(pt, &symbol, 1);
+ break;
+ case ';':
+ this->AllocateParserType(pt, "\\;", 2);
+ break;
+ case 't':
+ this->AllocateParserType(pt, "\t", 1);
+ break;
+ case 'n':
+ this->AllocateParserType(pt, "\n", 1);
+ break;
+ case 'r':
+ this->AllocateParserType(pt, "\r", 1);
+ break;
+ case '0':
+ this->AllocateParserType(pt, "\0", 1);
+ break;
+ default: {
+ std::ostringstream e;
+ e << "Invalid escape sequence \\" << symbol;
+ this->SetError(e.str());
+ }
+ return false;
+ }
+ return true;
+}
+
+void cmCommandArgument_SetupEscapes(yyscan_t yyscanner, bool noEscapes);
+
+int cmCommandArgumentParserHelper::ParseString(const char* str, int verb)
+{
+ if (!str) {
+ return 0;
+ }
+ this->Verbose = verb;
+ this->InputBuffer = str;
+ this->InputBufferPos = 0;
+ this->CurrentLine = 0;
+
+ this->Result = "";
+
+ yyscan_t yyscanner;
+ cmCommandArgument_yylex_init(&yyscanner);
+ cmCommandArgument_yyset_extra(this, yyscanner);
+ cmCommandArgument_SetupEscapes(yyscanner, this->NoEscapeMode);
+ int res = cmCommandArgument_yyparse(yyscanner);
+ cmCommandArgument_yylex_destroy(yyscanner);
+ if (res != 0) {
+ return 0;
+ }
+
+ this->CleanupParser();
+
+ if (Verbose) {
+ std::cerr << "Expanding [" << str << "] produced: [" << this->Result << "]"
+ << std::endl;
+ }
+ return 1;
+}
+
+void cmCommandArgumentParserHelper::CleanupParser()
+{
+ std::vector<char*>::iterator sit;
+ for (sit = this->Variables.begin(); sit != this->Variables.end(); ++sit) {
+ delete[] * sit;
+ }
+ this->Variables.erase(this->Variables.begin(), this->Variables.end());
+}
+
+int cmCommandArgumentParserHelper::LexInput(char* buf, int maxlen)
+{
+ if (maxlen < 1) {
+ return 0;
+ }
+ if (this->InputBufferPos < this->InputBuffer.size()) {
+ buf[0] = this->InputBuffer[this->InputBufferPos++];
+ if (buf[0] == '\n') {
+ this->CurrentLine++;
+ }
+ return (1);
+ } else {
+ buf[0] = '\n';
+ return (0);
+ }
+}
+
+void cmCommandArgumentParserHelper::Error(const char* str)
+{
+ unsigned long pos = static_cast<unsigned long>(this->InputBufferPos);
+ std::ostringstream ostr;
+ ostr << str << " (" << pos << ")";
+ this->SetError(ostr.str());
+}
+
+void cmCommandArgumentParserHelper::SetMakefile(const cmMakefile* mf)
+{
+ this->Makefile = mf;
+ this->WarnUninitialized = mf->GetCMakeInstance()->GetWarnUninitialized();
+ this->CheckSystemVars = mf->GetCMakeInstance()->GetCheckSystemVars();
+}
+
+void cmCommandArgumentParserHelper::SetResult(const char* value)
+{
+ if (!value) {
+ this->Result = "";
+ return;
+ }
+ this->Result = value;
+}
+
+void cmCommandArgumentParserHelper::SetError(std::string const& msg)
+{
+ // Keep only the first error.
+ if (this->ErrorString.empty()) {
+ this->ErrorString = msg;
+ }
+}
diff --git a/Source/cmCommandArgumentParserHelper.h b/Source/cmCommandArgumentParserHelper.h
new file mode 100644
index 0000000..97b706c
--- /dev/null
+++ b/Source/cmCommandArgumentParserHelper.h
@@ -0,0 +1,109 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCommandArgumentParserHelper_h
+#define cmCommandArgumentParserHelper_h
+
+#include "cmStandardIncludes.h"
+
+#define YYSTYPE cmCommandArgumentParserHelper::ParserType
+#define YYSTYPE_IS_DECLARED
+#define YY_EXTRA_TYPE cmCommandArgumentParserHelper*
+#define YY_DECL \
+ int cmCommandArgument_yylex(YYSTYPE* yylvalp, yyscan_t yyscanner)
+
+/** \class cmCommandArgumentParserHelper
+ * \brief Helper class for parsing java source files
+ *
+ * Finds dependencies for java file and list of outputs
+ */
+
+class cmMakefile;
+
+class cmCommandArgumentParserHelper
+{
+public:
+ typedef struct
+ {
+ char* str;
+ } ParserType;
+
+ cmCommandArgumentParserHelper();
+ ~cmCommandArgumentParserHelper();
+
+ int ParseString(const char* str, int verb);
+
+ // For the lexer:
+ void AllocateParserType(cmCommandArgumentParserHelper::ParserType* pt,
+ const char* str, int len = 0);
+ bool HandleEscapeSymbol(cmCommandArgumentParserHelper::ParserType* pt,
+ char symbol);
+
+ int LexInput(char* buf, int maxlen);
+ void Error(const char* str);
+
+ // For yacc
+ char* CombineUnions(char* in1, char* in2);
+
+ char* ExpandSpecialVariable(const char* key, const char* var);
+ char* ExpandVariable(const char* var);
+ char* ExpandVariableForAt(const char* var);
+ void SetResult(const char* value);
+
+ void SetMakefile(const cmMakefile* mf);
+
+ std::string& GetResult() { return this->Result; }
+
+ void SetLineFile(long line, const char* file);
+ void SetEscapeQuotes(bool b) { this->EscapeQuotes = b; }
+ void SetNoEscapeMode(bool b) { this->NoEscapeMode = b; }
+ void SetReplaceAtSyntax(bool b) { this->ReplaceAtSyntax = b; }
+ void SetRemoveEmpty(bool b) { this->RemoveEmpty = b; }
+
+ const char* GetError() { return this->ErrorString.c_str(); }
+ char EmptyVariable[1];
+ char DCURLYVariable[3];
+ char RCURLYVariable[3];
+ char ATVariable[3];
+ char DOLLARVariable[3];
+ char LCURLYVariable[3];
+ char BSLASHVariable[3];
+
+private:
+ std::string::size_type InputBufferPos;
+ std::string InputBuffer;
+ std::vector<char> OutputBuffer;
+
+ void Print(const char* place, const char* str);
+ void SafePrintMissing(const char* str, int line, int cnt);
+
+ char* AddString(const std::string& str);
+
+ void CleanupParser();
+ void SetError(std::string const& msg);
+
+ std::vector<char*> Variables;
+ const cmMakefile* Makefile;
+ std::string Result;
+ std::string ErrorString;
+ const char* FileName;
+ long FileLine;
+ int CurrentLine;
+ int Verbose;
+ bool WarnUninitialized;
+ bool CheckSystemVars;
+ bool EscapeQuotes;
+ bool NoEscapeMode;
+ bool ReplaceAtSyntax;
+ bool RemoveEmpty;
+};
+
+#endif
diff --git a/Source/cmCommandArgumentParserTokens.h b/Source/cmCommandArgumentParserTokens.h
new file mode 100644
index 0000000..7fb58e2
--- /dev/null
+++ b/Source/cmCommandArgumentParserTokens.h
@@ -0,0 +1,92 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ cal_ENVCURLY = 258,
+ cal_NCURLY = 259,
+ cal_DCURLY = 260,
+ cal_DOLLAR = 261,
+ cal_LCURLY = 262,
+ cal_RCURLY = 263,
+ cal_NAME = 264,
+ cal_BSLASH = 265,
+ cal_SYMBOL = 266,
+ cal_AT = 267,
+ cal_ERROR = 268,
+ cal_ATNAME = 269
+ };
+#endif
+/* Tokens. */
+#define cal_ENVCURLY 258
+#define cal_NCURLY 259
+#define cal_DCURLY 260
+#define cal_DOLLAR 261
+#define cal_LCURLY 262
+#define cal_RCURLY 263
+#define cal_NAME 264
+#define cal_BSLASH 265
+#define cal_SYMBOL 266
+#define cal_AT 267
+#define cal_ERROR 268
+#define cal_ATNAME 269
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
diff --git a/Source/cmCommandArgumentsHelper.cxx b/Source/cmCommandArgumentsHelper.cxx
new file mode 100644
index 0000000..1345bd5
--- /dev/null
+++ b/Source/cmCommandArgumentsHelper.cxx
@@ -0,0 +1,262 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCommandArgumentsHelper.h"
+
+cmCommandArgument::cmCommandArgument(cmCommandArgumentsHelper* args,
+ const char* key,
+ cmCommandArgumentGroup* group)
+ : Key(key)
+ , Group(group)
+ , WasActive(false)
+ , ArgumentsBeforeEmpty(true)
+ , CurrentIndex(0)
+{
+ if (args != CM_NULLPTR) {
+ args->AddArgument(this);
+ }
+
+ if (this->Group != CM_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 != CM_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;
+ }
+
+ std::set<const cmCommandArgument*>::const_iterator argIt =
+ this->ArgumentsBefore.find(current);
+ if (argIt != this->ArgumentsBefore.end()) {
+ return true;
+ }
+
+ return false;
+}
+
+bool cmCommandArgument::KeyMatches(const std::string& key) const
+{
+ if ((this->Key == CM_NULLPTR) || (this->Key[0] == '\0')) {
+ return true;
+ }
+ return (key == this->Key);
+}
+
+void cmCommandArgument::ApplyOwnGroup()
+{
+ if (this->Group != CM_NULLPTR) {
+ for (std::vector<cmCommandArgument*>::const_iterator it =
+ this->Group->ContainedArguments.begin();
+ it != this->Group->ContainedArguments.end(); ++it) {
+ if (*it != this) {
+ this->ArgumentsBefore.insert(*it);
+ }
+ }
+ }
+}
+
+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(CM_NULLPTR)
+{
+ if ((key == CM_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 == CM_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 == CM_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 = "";
+}
+
+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 (std::vector<cmCommandArgument*>::iterator it =
+ this->ContainedArguments.begin();
+ it != this->ContainedArguments.end(); ++it) {
+ (*it)->Follows(arg);
+ }
+}
+
+void cmCommandArgumentGroup::FollowsGroup(const cmCommandArgumentGroup* group)
+{
+ for (std::vector<cmCommandArgument*>::iterator it =
+ this->ContainedArguments.begin();
+ it != this->ContainedArguments.end(); ++it) {
+ (*it)->FollowsGroup(group);
+ }
+}
+
+void cmCommandArgumentsHelper::Parse(const std::vector<std::string>* args,
+ std::vector<std::string>* unconsumedArgs)
+{
+ if (args == CM_NULLPTR) {
+ return;
+ }
+
+ for (std::vector<cmCommandArgument*>::iterator argIt =
+ this->Arguments.begin();
+ argIt != this->Arguments.end(); ++argIt) {
+ (*argIt)->ApplyOwnGroup();
+ (*argIt)->Reset();
+ }
+
+ cmCommandArgument* activeArgument = CM_NULLPTR;
+ const cmCommandArgument* previousArgument = CM_NULLPTR;
+ for (std::vector<std::string>::const_iterator it = args->begin();
+ it != args->end(); ++it) {
+ for (std::vector<cmCommandArgument*>::iterator argIt =
+ this->Arguments.begin();
+ argIt != this->Arguments.end(); ++argIt) {
+ if ((*argIt)->KeyMatches(*it) &&
+ ((*argIt)->MayFollow(previousArgument))) {
+ activeArgument = *argIt;
+ activeArgument->Activate();
+ break;
+ }
+ }
+
+ if (activeArgument) {
+ bool argDone = activeArgument->Consume(*it);
+ previousArgument = activeArgument;
+ if (argDone) {
+ activeArgument = CM_NULLPTR;
+ }
+ } else {
+ if (unconsumedArgs != CM_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
new file mode 100644
index 0000000..9133148
--- /dev/null
+++ b/Source/cmCommandArgumentsHelper.h
@@ -0,0 +1,201 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCommandArgumentsHelper_h
+#define cmCommandArgumentsHelper_h
+
+#include "cmStandardIncludes.h"
+
+class cmCommandArgumentsHelper;
+class cmCommandArgumentGroup;
+
+/* 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 = CM_NULLPTR);
+ virtual ~cmCommandArgument() {}
+
+ /// 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 = CM_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;
+ cmCAStringVector();
+ bool DoConsume(const std::string& arg, unsigned int index) CM_OVERRIDE;
+ void DoReset() CM_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 = CM_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) CM_OVERRIDE;
+ void DoReset() CM_OVERRIDE;
+ cmCAString();
+};
+
+/** 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 = CM_NULLPTR);
+
+ /// Has it been enabled ?
+ bool IsEnabled() const { return this->Enabled; }
+private:
+ bool Enabled;
+ bool DoConsume(const std::string& arg, unsigned int index) CM_OVERRIDE;
+ void DoReset() CM_OVERRIDE;
+ cmCAEnabler();
+};
+
+/** 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 = CM_NULLPTR);
+
+ /// Is it still enabled ?
+ bool IsEnabled() const { return this->Enabled; }
+private:
+ bool Enabled;
+ bool DoConsume(const std::string& arg, unsigned int index) CM_OVERRIDE;
+ void DoReset() CM_OVERRIDE;
+ cmCADisabler();
+};
+
+/** 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:
+ cmCommandArgumentGroup() {}
+
+ /// 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/cmCommands.cxx.in b/Source/cmCommands.cxx.in
new file mode 100644
index 0000000..e23bbd1
--- /dev/null
+++ b/Source/cmCommands.cxx.in
@@ -0,0 +1,19 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCommands.h"
+
+@COMMAND_INCLUDES@
+
+void GetPredefinedCommands(std::vector<cmCommand*>& commands)
+{
+@NEW_COMMANDS@
+}
diff --git a/Source/cmCommands.h b/Source/cmCommands.h
new file mode 100644
index 0000000..d0f1ab7
--- /dev/null
+++ b/Source/cmCommands.h
@@ -0,0 +1,31 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCommands_h
+#define cmCommands_h
+
+#include "cmStandardIncludes.h"
+
+#include <vector>
+
+class cmCommand;
+/**
+ * Global function to return all compiled in commands.
+ * To add a new command edit cmCommands.cxx or cmBootstrapCommands[12].cxx
+ * and add your command.
+ * It is up to the caller to delete the commands created by this
+ * call.
+ */
+void GetBootstrapCommands1(std::vector<cmCommand*>& commands);
+void GetBootstrapCommands2(std::vector<cmCommand*>& commands);
+void GetPredefinedCommands(std::vector<cmCommand*>& commands);
+
+#endif
diff --git a/Source/cmCommandsForBootstrap.cxx b/Source/cmCommandsForBootstrap.cxx
new file mode 100644
index 0000000..5f397a1
--- /dev/null
+++ b/Source/cmCommandsForBootstrap.cxx
@@ -0,0 +1,16 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCommands.h"
+
+void GetPredefinedCommands(std::vector<cmCommand*>&)
+{
+}
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
new file mode 100644
index 0000000..7ad18f0
--- /dev/null
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -0,0 +1,235 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCommonTargetGenerator.h"
+
+#include "cmComputeLinkInformation.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalCommonGenerator.h"
+#include "cmLocalCommonGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmSystemTools.h"
+
+cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt)
+ : GeneratorTarget(gt)
+ , Makefile(gt->Makefile)
+ , LocalGenerator(static_cast<cmLocalCommonGenerator*>(gt->LocalGenerator))
+ , GlobalGenerator(static_cast<cmGlobalCommonGenerator*>(
+ gt->LocalGenerator->GetGlobalGenerator()))
+ , ConfigName(LocalGenerator->GetConfigName())
+ , ModuleDefinitionFile(GeneratorTarget->GetModuleDefinitionFile(ConfigName))
+{
+}
+
+cmCommonTargetGenerator::~cmCommonTargetGenerator()
+{
+}
+
+std::string const& cmCommonTargetGenerator::GetConfigName() const
+{
+ return this->ConfigName;
+}
+
+std::string cmCommonTargetGenerator::Convert(
+ std::string const& source, cmOutputConverter::RelativeRoot relative,
+ cmOutputConverter::OutputFormat output)
+{
+ return this->LocalGenerator->Convert(source, relative, output);
+}
+
+const char* cmCommonTargetGenerator::GetFeature(const std::string& feature)
+{
+ return this->GeneratorTarget->GetFeature(feature, this->ConfigName);
+}
+
+bool cmCommonTargetGenerator::GetFeatureAsBool(const std::string& feature)
+{
+ return this->GeneratorTarget->GetFeatureAsBool(feature, this->ConfigName);
+}
+
+void cmCommonTargetGenerator::AddFeatureFlags(std::string& flags,
+ const std::string& lang)
+{
+ // Add language-specific flags.
+ this->LocalGenerator->AddLanguageFlags(flags, lang, this->ConfigName);
+
+ if (this->GetFeatureAsBool("INTERPROCEDURAL_OPTIMIZATION")) {
+ this->LocalGenerator->AppendFeatureOptions(flags, lang, "IPO");
+ }
+}
+
+void cmCommonTargetGenerator::AddModuleDefinitionFlag(std::string& flags)
+{
+ if (!this->ModuleDefinitionFile) {
+ return;
+ }
+
+ // TODO: Create a per-language flag variable.
+ const char* defFileFlag =
+ this->Makefile->GetDefinition("CMAKE_LINK_DEF_FILE_FLAG");
+ if (!defFileFlag) {
+ return;
+ }
+
+ // Append the flag and value. Use ConvertToLinkReference to help
+ // vs6's "cl -link" pass it to the linker.
+ std::string flag = defFileFlag;
+ flag += (this->LocalGenerator->ConvertToLinkReference(
+ this->ModuleDefinitionFile->GetFullPath()));
+ this->LocalGenerator->AppendFlags(flags, flag);
+}
+
+void cmCommonTargetGenerator::AppendFortranFormatFlags(
+ std::string& flags, cmSourceFile const& source)
+{
+ const char* srcfmt = source.GetProperty("Fortran_FORMAT");
+ cmOutputConverter::FortranFormat format =
+ cmOutputConverter::GetFortranFormat(srcfmt);
+ if (format == cmOutputConverter::FortranFormatNone) {
+ const char* tgtfmt = this->GeneratorTarget->GetProperty("Fortran_FORMAT");
+ format = cmOutputConverter::GetFortranFormat(tgtfmt);
+ }
+ const char* var = CM_NULLPTR;
+ switch (format) {
+ case cmOutputConverter::FortranFormatFixed:
+ var = "CMAKE_Fortran_FORMAT_FIXED_FLAG";
+ break;
+ case cmOutputConverter::FortranFormatFree:
+ var = "CMAKE_Fortran_FORMAT_FREE_FLAG";
+ break;
+ default:
+ break;
+ }
+ if (var) {
+ this->LocalGenerator->AppendFlags(flags,
+ this->Makefile->GetDefinition(var));
+ }
+}
+
+std::string cmCommonTargetGenerator::GetFlags(const std::string& l)
+{
+ ByLanguageMap::iterator i = this->FlagsByLanguage.find(l);
+ if (i == this->FlagsByLanguage.end()) {
+ std::string flags;
+
+ this->LocalGenerator->GetTargetCompileFlags(this->GeneratorTarget,
+ this->ConfigName, l, flags);
+
+ ByLanguageMap::value_type entry(l, flags);
+ i = this->FlagsByLanguage.insert(entry).first;
+ }
+ return i->second;
+}
+
+std::string cmCommonTargetGenerator::GetDefines(const std::string& l)
+{
+ ByLanguageMap::iterator i = this->DefinesByLanguage.find(l);
+ if (i == this->DefinesByLanguage.end()) {
+ std::set<std::string> defines;
+ this->LocalGenerator->GetTargetDefines(this->GeneratorTarget,
+ this->ConfigName, l, defines);
+
+ std::string definesString;
+ this->LocalGenerator->JoinDefines(defines, definesString, l);
+
+ ByLanguageMap::value_type entry(l, definesString);
+ i = this->DefinesByLanguage.insert(entry).first;
+ }
+ return i->second;
+}
+
+std::string cmCommonTargetGenerator::GetIncludes(std::string const& l)
+{
+ ByLanguageMap::iterator i = this->IncludesByLanguage.find(l);
+ if (i == this->IncludesByLanguage.end()) {
+ std::string includes;
+ this->AddIncludeFlags(includes, l);
+ ByLanguageMap::value_type entry(l, includes);
+ i = this->IncludesByLanguage.insert(entry).first;
+ }
+ return i->second;
+}
+
+std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories()
+ const
+{
+ std::vector<std::string> dirs;
+ std::set<cmGeneratorTarget const*> emitted;
+ if (cmComputeLinkInformation* cli =
+ this->GeneratorTarget->GetLinkInformation(this->ConfigName)) {
+ cmComputeLinkInformation::ItemVector const& items = cli->GetItems();
+ for (cmComputeLinkInformation::ItemVector::const_iterator i =
+ items.begin();
+ i != items.end(); ++i) {
+ cmGeneratorTarget const* linkee = i->Target;
+ if (linkee && !linkee->IsImported()
+ // We can ignore the INTERFACE_LIBRARY items because
+ // Target->GetLinkInformation already processed their
+ // link interface and they don't have any output themselves.
+ && linkee->GetType() != cmState::INTERFACE_LIBRARY &&
+ emitted.insert(linkee).second) {
+ cmLocalGenerator* lg = linkee->GetLocalGenerator();
+ std::string di = lg->GetCurrentBinaryDirectory();
+ di += "/";
+ di += lg->GetTargetDirectory(linkee);
+ dirs.push_back(di);
+ }
+ }
+ }
+ return dirs;
+}
+
+std::string cmCommonTargetGenerator::GetManifests()
+{
+ std::vector<cmSourceFile const*> manifest_srcs;
+ this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName);
+
+ std::vector<std::string> manifests;
+ for (std::vector<cmSourceFile const*>::iterator mi = manifest_srcs.begin();
+ mi != manifest_srcs.end(); ++mi) {
+ manifests.push_back(this->Convert(
+ (*mi)->GetFullPath(), this->LocalGenerator->GetWorkingDirectory(),
+ cmOutputConverter::SHELL));
+ }
+
+ return cmJoin(manifests, " ");
+}
+
+void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags,
+ const std::string& lang,
+ const char* name, bool so)
+{
+ // Lookup the flag to specify the version.
+ std::string fvar = "CMAKE_";
+ fvar += lang;
+ fvar += "_OSX_";
+ fvar += name;
+ fvar += "_VERSION_FLAG";
+ const char* flag = this->Makefile->GetDefinition(fvar);
+
+ // Skip if no such flag.
+ if (!flag) {
+ return;
+ }
+
+ // Lookup the target version information.
+ int major;
+ int minor;
+ int patch;
+ this->GeneratorTarget->GetTargetVersion(so, major, minor, patch);
+ if (major > 0 || minor > 0 || patch > 0) {
+ // Append the flag since a non-zero version is specified.
+ std::ostringstream vflag;
+ vflag << flag << major << "." << minor << "." << patch;
+ this->LocalGenerator->AppendFlags(flags, vflag.str());
+ }
+}
diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h
new file mode 100644
index 0000000..0bafde9
--- /dev/null
+++ b/Source/cmCommonTargetGenerator.h
@@ -0,0 +1,81 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCommonTargetGenerator_h
+#define cmCommonTargetGenerator_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmLocalGenerator.h"
+
+class cmGeneratorTarget;
+class cmGlobalCommonGenerator;
+class cmLocalCommonGenerator;
+class cmMakefile;
+class cmSourceFile;
+
+/** \class cmCommonTargetGenerator
+ * \brief Common infrastructure for Makefile and Ninja per-target generators
+ */
+class cmCommonTargetGenerator
+{
+public:
+ cmCommonTargetGenerator(cmGeneratorTarget* gt);
+ virtual ~cmCommonTargetGenerator();
+
+ std::string const& GetConfigName() const;
+
+protected:
+ // Add language feature flags.
+ void AddFeatureFlags(std::string& flags, const std::string& lang);
+
+ // Feature query methods.
+ const char* GetFeature(const std::string& feature);
+ bool GetFeatureAsBool(const std::string& feature);
+
+ // Helper to add flag for windows .def file.
+ void AddModuleDefinitionFlag(std::string& flags);
+
+ cmGeneratorTarget* GeneratorTarget;
+ cmMakefile* Makefile;
+ cmLocalCommonGenerator* LocalGenerator;
+ cmGlobalCommonGenerator* GlobalGenerator;
+ std::string ConfigName;
+
+ // The windows module definition source file (.def), if any.
+ cmSourceFile const* ModuleDefinitionFile;
+
+ std::string Convert(
+ std::string const& source, cmOutputConverter::RelativeRoot relative,
+ cmOutputConverter::OutputFormat output = cmOutputConverter::UNCHANGED);
+
+ void AppendFortranFormatFlags(std::string& flags,
+ cmSourceFile const& source);
+
+ virtual void AddIncludeFlags(std::string& flags,
+ std::string const& lang) = 0;
+
+ void AppendOSXVerFlag(std::string& flags, const std::string& lang,
+ const char* name, bool so);
+
+ typedef std::map<std::string, std::string> ByLanguageMap;
+ std::string GetFlags(const std::string& l);
+ ByLanguageMap FlagsByLanguage;
+ std::string GetDefines(const std::string& l);
+ ByLanguageMap DefinesByLanguage;
+ std::string GetIncludes(std::string const& l);
+ ByLanguageMap IncludesByLanguage;
+ std::string GetManifests();
+
+ std::vector<std::string> GetLinkedTargetDirectories() const;
+};
+
+#endif
diff --git a/Source/cmComputeComponentGraph.cxx b/Source/cmComputeComponentGraph.cxx
new file mode 100644
index 0000000..4f21c3a
--- /dev/null
+++ b/Source/cmComputeComponentGraph.cxx
@@ -0,0 +1,142 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmComputeComponentGraph.h"
+
+#include <algorithm>
+
+#include <assert.h>
+
+cmComputeComponentGraph::cmComputeComponentGraph(Graph const& input)
+ : InputGraph(input)
+{
+ // Identify components.
+ this->Tarjan();
+
+ // Compute the component graph.
+ this->ComponentGraph.resize(0);
+ this->ComponentGraph.resize(this->Components.size());
+ this->TransferEdges();
+}
+
+cmComputeComponentGraph::~cmComputeComponentGraph()
+{
+}
+
+void cmComputeComponentGraph::Tarjan()
+{
+ int n = static_cast<int>(this->InputGraph.size());
+ TarjanEntry entry = { 0, 0 };
+ this->TarjanEntries.resize(0);
+ this->TarjanEntries.resize(n, entry);
+ this->TarjanComponents.resize(0);
+ this->TarjanComponents.resize(n, -1);
+ this->TarjanWalkId = 0;
+ this->TarjanVisited.resize(0);
+ this->TarjanVisited.resize(n, 0);
+ for (int i = 0; i < n; ++i) {
+ // Start a new DFS from this node if it has never been visited.
+ if (!this->TarjanVisited[i]) {
+ assert(this->TarjanStack.empty());
+ ++this->TarjanWalkId;
+ this->TarjanIndex = 0;
+ this->TarjanVisit(i);
+ }
+ }
+}
+
+void cmComputeComponentGraph::TarjanVisit(int i)
+{
+ // We are now visiting this node.
+ this->TarjanVisited[i] = this->TarjanWalkId;
+
+ // Initialize the entry.
+ this->TarjanEntries[i].Root = i;
+ this->TarjanComponents[i] = -1;
+ this->TarjanEntries[i].VisitIndex = ++this->TarjanIndex;
+ this->TarjanStack.push(i);
+
+ // Follow outgoing edges.
+ EdgeList const& nl = this->InputGraph[i];
+ for (EdgeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni) {
+ int j = *ni;
+
+ // Ignore edges to nodes that have been reached by a previous DFS
+ // walk. Since we did not reach the current node from that walk
+ // it must not belong to the same component and it has already
+ // been assigned to a component.
+ if (this->TarjanVisited[j] > 0 &&
+ this->TarjanVisited[j] < this->TarjanWalkId) {
+ continue;
+ }
+
+ // Visit the destination if it has not yet been visited.
+ if (!this->TarjanVisited[j]) {
+ this->TarjanVisit(j);
+ }
+
+ // If the destination has not yet been assigned to a component,
+ // check if it has a better root for the current object.
+ if (this->TarjanComponents[j] < 0) {
+ if (this->TarjanEntries[this->TarjanEntries[j].Root].VisitIndex <
+ this->TarjanEntries[this->TarjanEntries[i].Root].VisitIndex) {
+ this->TarjanEntries[i].Root = this->TarjanEntries[j].Root;
+ }
+ }
+ }
+
+ // Check if we have found a component.
+ if (this->TarjanEntries[i].Root == i) {
+ // Yes. Create it.
+ int c = static_cast<int>(this->Components.size());
+ this->Components.push_back(NodeList());
+ NodeList& component = this->Components[c];
+
+ // Populate the component list.
+ int j;
+ do {
+ // Get the next member of the component.
+ j = this->TarjanStack.top();
+ this->TarjanStack.pop();
+
+ // Assign the member to the component.
+ this->TarjanComponents[j] = c;
+ this->TarjanEntries[j].Root = i;
+
+ // Store the node in its component.
+ component.push_back(j);
+ } while (j != i);
+
+ // Sort the component members for clarity.
+ std::sort(component.begin(), component.end());
+ }
+}
+
+void cmComputeComponentGraph::TransferEdges()
+{
+ // Map inter-component edges in the original graph to edges in the
+ // component graph.
+ int n = static_cast<int>(this->InputGraph.size());
+ for (int i = 0; i < n; ++i) {
+ int i_component = this->TarjanComponents[i];
+ EdgeList const& nl = this->InputGraph[i];
+ for (EdgeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni) {
+ int j = *ni;
+ int j_component = this->TarjanComponents[j];
+ if (i_component != j_component) {
+ // We do not attempt to combine duplicate edges, but instead
+ // store the inter-component edges with suitable multiplicity.
+ this->ComponentGraph[i_component].push_back(
+ cmGraphEdge(j_component, ni->IsStrong()));
+ }
+ }
+ }
+}
diff --git a/Source/cmComputeComponentGraph.h b/Source/cmComputeComponentGraph.h
new file mode 100644
index 0000000..fb95f9a
--- /dev/null
+++ b/Source/cmComputeComponentGraph.h
@@ -0,0 +1,87 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmComputeComponentGraph_h
+#define cmComputeComponentGraph_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmGraphAdjacencyList.h"
+
+#include <stack>
+
+/** \class cmComputeComponentGraph
+ * \brief Analyze a graph to determine strongly connected components.
+ *
+ * Convert a directed graph into a directed acyclic graph whose nodes
+ * correspond to strongly connected components of the original graph.
+ *
+ * We use Tarjan's algorithm to enumerate the components efficiently.
+ * An advantage of this approach is that the components are identified
+ * in a topologically sorted order.
+ */
+class cmComputeComponentGraph
+{
+public:
+ // Represent the graph with an adjacency list.
+ typedef cmGraphNodeList NodeList;
+ typedef cmGraphEdgeList EdgeList;
+ typedef cmGraphAdjacencyList Graph;
+
+ cmComputeComponentGraph(Graph const& input);
+ ~cmComputeComponentGraph();
+
+ /** Get the adjacency list of the component graph. */
+ Graph const& GetComponentGraph() const { return this->ComponentGraph; }
+ EdgeList const& GetComponentGraphEdges(int c) const
+ {
+ return this->ComponentGraph[c];
+ }
+
+ /** Get map from component index to original node indices. */
+ std::vector<NodeList> const& GetComponents() const
+ {
+ return this->Components;
+ }
+ NodeList const& GetComponent(int c) const { return this->Components[c]; }
+
+ /** Get map from original node index to component index. */
+ std::vector<int> const& GetComponentMap() const
+ {
+ return this->TarjanComponents;
+ }
+
+private:
+ void TransferEdges();
+
+ Graph const& InputGraph;
+ Graph ComponentGraph;
+
+ // Tarjan's algorithm.
+ struct TarjanEntry
+ {
+ int Root;
+ int VisitIndex;
+ };
+ std::vector<int> TarjanVisited;
+ std::vector<int> TarjanComponents;
+ std::vector<TarjanEntry> TarjanEntries;
+ std::vector<NodeList> Components;
+ std::stack<int> TarjanStack;
+ int TarjanWalkId;
+ int TarjanIndex;
+ void Tarjan();
+ void TarjanVisit(int i);
+
+ // Connected components.
+};
+
+#endif
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
new file mode 100644
index 0000000..fffb77d
--- /dev/null
+++ b/Source/cmComputeLinkDepends.cxx
@@ -0,0 +1,859 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmComputeLinkDepends.h"
+
+#include "cmAlgorithms.h"
+#include "cmComputeComponentGraph.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+#include <assert.h>
+
+/*
+
+This file computes an ordered list of link items to use when linking a
+single target in one configuration. Each link item is identified by
+the string naming it. A graph of dependencies is created in which
+each node corresponds to one item and directed edges lead from nodes to
+those which must *follow* them on the link line. For example, the
+graph
+
+ A -> B -> C
+
+will lead to the link line order
+
+ A B C
+
+The set of items placed in the graph is formed with a breadth-first
+search of the link dependencies starting from the main target.
+
+There are two types of items: those with known direct dependencies and
+those without known dependencies. We will call the two types "known
+items" and "unknown items", respectively. Known items are those whose
+names correspond to targets (built or imported) and those for which an
+old-style <item>_LIB_DEPENDS variable is defined. All other items are
+unknown and we must infer dependencies for them. For items that look
+like flags (beginning with '-') we trivially infer no dependencies,
+and do not include them in the dependencies of other items.
+
+Known items have dependency lists ordered based on how the user
+specified them. We can use this order to infer potential dependencies
+of unknown items. For example, if link items A and B are unknown and
+items X and Y are known, then we might have the following dependency
+lists:
+
+ X: Y A B
+ Y: A B
+
+The explicitly known dependencies form graph edges
+
+ X -> Y , X -> A , X -> B , Y -> A , Y -> B
+
+We can also infer the edge
+
+ A -> B
+
+because *every* time A appears B is seen on its right. We do not know
+whether A really needs symbols from B to link, but it *might* so we
+must preserve their order. This is the case also for the following
+explicit lists:
+
+ X: A B Y
+ Y: A B
+
+Here, A is followed by the set {B,Y} in one list, and {B} in the other
+list. The intersection of these sets is {B}, so we can infer that A
+depends on at most B. Meanwhile B is followed by the set {Y} in one
+list and {} in the other. The intersection is {} so we can infer that
+B has no dependencies.
+
+Let's make a more complex example by adding unknown item C and
+considering these dependency lists:
+
+ X: A B Y C
+ Y: A C B
+
+The explicit edges are
+
+ X -> Y , X -> A , X -> B , X -> C , Y -> A , Y -> B , Y -> C
+
+For the unknown items, we infer dependencies by looking at the
+"follow" sets:
+
+ A: intersect( {B,Y,C} , {C,B} ) = {B,C} ; infer edges A -> B , A -> C
+ B: intersect( {Y,C} , {} ) = {} ; infer no edges
+ C: intersect( {} , {B} ) = {} ; infer no edges
+
+Note that targets are never inferred as dependees because outside
+libraries should not depend on them.
+
+------------------------------------------------------------------------------
+
+The initial exploration of dependencies using a BFS associates an
+integer index with each link item. When the graph is built outgoing
+edges are sorted by this index.
+
+After the initial exploration of the link interface tree, any
+transitive (dependent) shared libraries that were encountered and not
+included in the interface are processed in their own BFS. This BFS
+follows only the dependent library lists and not the link interfaces.
+They are added to the link items with a mark indicating that the are
+transitive dependencies. Then cmComputeLinkInformation deals with
+them on a per-platform basis.
+
+The complete graph formed from all known and inferred dependencies may
+not be acyclic, so an acyclic version must be created.
+The original graph is converted to a directed acyclic graph in which
+each node corresponds to a strongly connected component of the
+original graph. For example, the dependency graph
+
+ X -> A -> B -> C -> A -> Y
+
+contains strongly connected components {X}, {A,B,C}, and {Y}. The
+implied directed acyclic graph (DAG) is
+
+ {X} -> {A,B,C} -> {Y}
+
+We then compute a topological order for the DAG nodes to serve as a
+reference for satisfying dependencies efficiently. We perform the DFS
+in reverse order and assign topological order indices counting down so
+that the result is as close to the original BFS order as possible
+without violating dependencies.
+
+------------------------------------------------------------------------------
+
+The final link entry order is constructed as follows. We first walk
+through and emit the *original* link line as specified by the user.
+As each item is emitted, a set of pending nodes in the component DAG
+is maintained. When a pending component has been completely seen, it
+is removed from the pending set and its dependencies (following edges
+of the DAG) are added. A trivial component (those with one item) is
+complete as soon as its item is seen. A non-trivial component (one
+with more than one item; assumed to be static libraries) is complete
+when *all* its entries have been seen *twice* (all entries seen once,
+then all entries seen again, not just each entry twice). A pending
+component tracks which items have been seen and a count of how many
+times the component needs to be seen (once for trivial components,
+twice for non-trivial). If at any time another component finishes and
+re-adds an already pending component, the pending component is reset
+so that it needs to be seen in its entirety again. This ensures that
+all dependencies of a component are satisfied no matter where it
+appears.
+
+After the original link line has been completed, we append to it the
+remaining pending components and their dependencies. This is done by
+repeatedly emitting the first item from the first pending component
+and following the same update rules as when traversing the original
+link line. Since the pending components are kept in topological order
+they are emitted with minimal repeats (we do not want to emit a
+component just to have it added again when another component is
+completed later). This process continues until no pending components
+remain. We know it will terminate because the component graph is
+guaranteed to be acyclic.
+
+The final list of items produced by this procedure consists of the
+original user link line followed by minimal additional items needed to
+satisfy dependencies. The final list is then filtered to de-duplicate
+items that we know the linker will re-use automatically (shared libs).
+
+*/
+
+cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target,
+ const std::string& config)
+{
+ // Store context information.
+ this->Target = target;
+ this->Makefile = this->Target->Target->GetMakefile();
+ this->GlobalGenerator =
+ this->Target->GetLocalGenerator()->GetGlobalGenerator();
+ this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance();
+
+ // The configuration being linked.
+ this->HasConfig = !config.empty();
+ this->Config = (this->HasConfig) ? config : std::string();
+ std::vector<std::string> debugConfigs =
+ this->Makefile->GetCMakeInstance()->GetDebugConfigs();
+ this->LinkType = CMP0003_ComputeLinkType(this->Config, debugConfigs);
+
+ // Enable debug mode if requested.
+ this->DebugMode = this->Makefile->IsOn("CMAKE_LINK_DEPENDS_DEBUG_MODE");
+
+ // Assume no compatibility until set.
+ this->OldLinkDirMode = false;
+
+ // No computation has been done.
+ this->CCG = CM_NULLPTR;
+}
+
+cmComputeLinkDepends::~cmComputeLinkDepends()
+{
+ cmDeleteAll(this->InferredDependSets);
+ delete this->CCG;
+}
+
+void cmComputeLinkDepends::SetOldLinkDirMode(bool b)
+{
+ this->OldLinkDirMode = b;
+}
+
+std::vector<cmComputeLinkDepends::LinkEntry> const&
+cmComputeLinkDepends::Compute()
+{
+ // Follow the link dependencies of the target to be linked.
+ this->AddDirectLinkEntries();
+
+ // Complete the breadth-first search of dependencies.
+ while (!this->BFSQueue.empty()) {
+ // Get the next entry.
+ BFSEntry qe = this->BFSQueue.front();
+ this->BFSQueue.pop();
+
+ // Follow the entry's dependencies.
+ this->FollowLinkEntry(qe);
+ }
+
+ // Complete the search of shared library dependencies.
+ while (!this->SharedDepQueue.empty()) {
+ // Handle the next entry.
+ this->HandleSharedDependency(this->SharedDepQueue.front());
+ this->SharedDepQueue.pop();
+ }
+
+ // Infer dependencies of targets for which they were not known.
+ this->InferDependencies();
+
+ // Cleanup the constraint graph.
+ this->CleanConstraintGraph();
+
+ // Display the constraint graph.
+ if (this->DebugMode) {
+ fprintf(stderr, "---------------------------------------"
+ "---------------------------------------\n");
+ fprintf(stderr, "Link dependency analysis for target %s, config %s\n",
+ this->Target->GetName().c_str(),
+ this->HasConfig ? this->Config.c_str() : "noconfig");
+ this->DisplayConstraintGraph();
+ }
+
+ // Compute the final ordering.
+ this->OrderLinkEntires();
+
+ // Compute the final set of link entries.
+ // 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;
+ 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.
+ bool uniquify = t && t->GetType() == cmState::SHARED_LIBRARY;
+ if (!uniquify || emmitted.insert(i).second) {
+ this->FinalLinkEntries.push_back(e);
+ }
+ }
+ // Reverse the resulting order since we iterated in reverse.
+ std::reverse(this->FinalLinkEntries.begin(), this->FinalLinkEntries.end());
+
+ // Display the final set.
+ if (this->DebugMode) {
+ this->DisplayFinalEntries();
+ }
+
+ return this->FinalLinkEntries;
+}
+
+std::map<std::string, int>::iterator cmComputeLinkDepends::AllocateLinkEntry(
+ std::string const& item)
+{
+ std::map<std::string, int>::value_type index_entry(
+ item, static_cast<int>(this->EntryList.size()));
+ std::map<std::string, int>::iterator lei =
+ this->LinkEntryIndex.insert(index_entry).first;
+ this->EntryList.push_back(LinkEntry());
+ this->InferredDependSets.push_back(CM_NULLPTR);
+ this->EntryConstraintGraph.push_back(EdgeList());
+ return lei;
+}
+
+int cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item)
+{
+ // Check if the item entry has already been added.
+ std::map<std::string, int>::iterator lei = this->LinkEntryIndex.find(item);
+ if (lei != this->LinkEntryIndex.end()) {
+ // Yes. We do not need to follow the item's dependencies again.
+ return lei->second;
+ }
+
+ // Allocate a spot for the item entry.
+ lei = this->AllocateLinkEntry(item);
+
+ // Initialize the item entry.
+ int index = lei->second;
+ LinkEntry& entry = this->EntryList[index];
+ entry.Item = item;
+ entry.Target = item.Target;
+ entry.IsFlag = (!entry.Target && item[0] == '-' && item[1] != 'l' &&
+ item.substr(0, 10) != "-framework");
+
+ // If the item has dependencies queue it to follow them.
+ if (entry.Target) {
+ // Target dependencies are always known. Follow them.
+ BFSEntry qe = { index, CM_NULLPTR };
+ this->BFSQueue.push(qe);
+ } else {
+ // Look for an old-style <item>_LIB_DEPENDS variable.
+ std::string var = entry.Item;
+ var += "_LIB_DEPENDS";
+ if (const char* val = this->Makefile->GetDefinition(var)) {
+ // The item dependencies are known. Follow them.
+ BFSEntry qe = { index, val };
+ this->BFSQueue.push(qe);
+ } else if (!entry.IsFlag) {
+ // The item dependencies are not known. We need to infer them.
+ this->InferredDependSets[index] = new DependSetList;
+ }
+ }
+
+ return index;
+}
+
+void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
+{
+ // Get this entry representation.
+ int depender_index = qe.Index;
+ LinkEntry const& entry = this->EntryList[depender_index];
+
+ // Follow the item's dependencies.
+ if (entry.Target) {
+ // Follow the target dependencies.
+ if (cmLinkInterface const* iface =
+ entry.Target->GetLinkInterface(this->Config, this->Target)) {
+ const bool isIface =
+ entry.Target->GetType() == cmState::INTERFACE_LIBRARY;
+ // This target provides its own link interface information.
+ this->AddLinkEntries(depender_index, iface->Libraries);
+
+ if (isIface) {
+ return;
+ }
+
+ // Handle dependent shared libraries.
+ this->FollowSharedDeps(depender_index, iface);
+
+ // Support for CMP0003.
+ for (std::vector<cmLinkItem>::const_iterator oi =
+ iface->WrongConfigLibraries.begin();
+ oi != iface->WrongConfigLibraries.end(); ++oi) {
+ this->CheckWrongConfigItem(*oi);
+ }
+ }
+ } else {
+ // Follow the old-style dependency list.
+ this->AddVarLinkEntries(depender_index, qe.LibDepends);
+ }
+}
+
+void cmComputeLinkDepends::FollowSharedDeps(int depender_index,
+ cmLinkInterface const* iface,
+ bool follow_interface)
+{
+ // Follow dependencies if we have not followed them already.
+ if (this->SharedDepFollowed.insert(depender_index).second) {
+ if (follow_interface) {
+ this->QueueSharedDependencies(depender_index, iface->Libraries);
+ }
+ this->QueueSharedDependencies(depender_index, iface->SharedDeps);
+ }
+}
+
+void cmComputeLinkDepends::QueueSharedDependencies(
+ int depender_index, std::vector<cmLinkItem> const& deps)
+{
+ for (std::vector<cmLinkItem>::const_iterator li = deps.begin();
+ li != deps.end(); ++li) {
+ SharedDepEntry qe;
+ qe.Item = *li;
+ qe.DependerIndex = depender_index;
+ this->SharedDepQueue.push(qe);
+ }
+}
+
+void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
+{
+ // Check if the target already has an entry.
+ std::map<std::string, int>::iterator lei =
+ this->LinkEntryIndex.find(dep.Item);
+ if (lei == this->LinkEntryIndex.end()) {
+ // Allocate a spot for the item entry.
+ lei = this->AllocateLinkEntry(dep.Item);
+
+ // Initialize the item entry.
+ LinkEntry& entry = this->EntryList[lei->second];
+ entry.Item = dep.Item;
+ entry.Target = dep.Item.Target;
+
+ // This item was added specifically because it is a dependent
+ // shared library. It may get special treatment
+ // in cmComputeLinkInformation.
+ entry.IsSharedDep = true;
+ }
+
+ // Get the link entry for this target.
+ int index = lei->second;
+ LinkEntry& entry = this->EntryList[index];
+
+ // This shared library dependency must follow the item that listed
+ // it.
+ this->EntryConstraintGraph[dep.DependerIndex].push_back(index);
+
+ // Target items may have their own dependencies.
+ if (entry.Target) {
+ if (cmLinkInterface const* iface =
+ entry.Target->GetLinkInterface(this->Config, this->Target)) {
+ // Follow public and private dependencies transitively.
+ this->FollowSharedDeps(index, iface, true);
+ }
+ }
+}
+
+void cmComputeLinkDepends::AddVarLinkEntries(int depender_index,
+ const char* value)
+{
+ // This is called to add the dependencies named by
+ // <item>_LIB_DEPENDS. The variable contains a semicolon-separated
+ // list. The list contains link-type;item pairs and just items.
+ std::vector<std::string> deplist;
+ cmSystemTools::ExpandListArgument(value, deplist);
+
+ // Look for entries meant for this configuration.
+ std::vector<cmLinkItem> actual_libs;
+ cmTargetLinkLibraryType llt = GENERAL_LibraryType;
+ bool haveLLT = false;
+ for (std::vector<std::string>::const_iterator di = deplist.begin();
+ di != deplist.end(); ++di) {
+ if (*di == "debug") {
+ llt = DEBUG_LibraryType;
+ haveLLT = true;
+ } else if (*di == "optimized") {
+ llt = OPTIMIZED_LibraryType;
+ haveLLT = true;
+ } else if (*di == "general") {
+ llt = GENERAL_LibraryType;
+ haveLLT = true;
+ } else if (!di->empty()) {
+ // If no explicit link type was given prior to this entry then
+ // check if the entry has its own link type variable. This is
+ // needed for compatibility with dependency files generated by
+ // the export_library_dependencies command from CMake 2.4 and
+ // lower.
+ if (!haveLLT) {
+ std::string var = *di;
+ var += "_LINK_TYPE";
+ if (const char* val = this->Makefile->GetDefinition(var)) {
+ if (strcmp(val, "debug") == 0) {
+ llt = DEBUG_LibraryType;
+ } else if (strcmp(val, "optimized") == 0) {
+ llt = OPTIMIZED_LibraryType;
+ }
+ }
+ }
+
+ // If the library is meant for this link type then use it.
+ if (llt == GENERAL_LibraryType || llt == this->LinkType) {
+ cmLinkItem item(*di, this->FindTargetToLink(depender_index, *di));
+ actual_libs.push_back(item);
+ } else if (this->OldLinkDirMode) {
+ cmLinkItem item(*di, this->FindTargetToLink(depender_index, *di));
+ this->CheckWrongConfigItem(item);
+ }
+
+ // Reset the link type until another explicit type is given.
+ llt = GENERAL_LibraryType;
+ haveLLT = false;
+ }
+ }
+
+ // Add the entries from this list.
+ this->AddLinkEntries(depender_index, actual_libs);
+}
+
+void cmComputeLinkDepends::AddDirectLinkEntries()
+{
+ // Add direct link dependencies in this configuration.
+ cmLinkImplementation const* impl =
+ this->Target->GetLinkImplementation(this->Config);
+ this->AddLinkEntries(-1, impl->Libraries);
+ for (std::vector<cmLinkItem>::const_iterator wi =
+ impl->WrongConfigLibraries.begin();
+ wi != impl->WrongConfigLibraries.end(); ++wi) {
+ this->CheckWrongConfigItem(*wi);
+ }
+}
+
+template <typename T>
+void cmComputeLinkDepends::AddLinkEntries(int depender_index,
+ std::vector<T> const& libs)
+{
+ // Track inferred dependency sets implied by this list.
+ std::map<int, DependSet> dependSets;
+
+ // Loop over the libraries linked directly by the depender.
+ for (typename std::vector<T>::const_iterator li = libs.begin();
+ li != libs.end(); ++li) {
+ // Skip entries that will resolve to the target getting linked or
+ // are empty.
+ cmLinkItem const& item = *li;
+ if (item == this->Target->GetName() || item.empty()) {
+ continue;
+ }
+
+ // Add a link entry for this item.
+ int dependee_index = this->AddLinkEntry(*li);
+
+ // The dependee must come after the depender.
+ if (depender_index >= 0) {
+ this->EntryConstraintGraph[depender_index].push_back(dependee_index);
+ } else {
+ // This is a direct dependency of the target being linked.
+ this->OriginalEntries.push_back(dependee_index);
+ }
+
+ // Update the inferred dependencies for earlier items.
+ for (std::map<int, DependSet>::iterator dsi = dependSets.begin();
+ dsi != dependSets.end(); ++dsi) {
+ // Add this item to the inferred dependencies of other items.
+ // Target items are never inferred dependees because unknown
+ // items are outside libraries that should not be depending on
+ // targets.
+ if (!this->EntryList[dependee_index].Target &&
+ !this->EntryList[dependee_index].IsFlag &&
+ dependee_index != dsi->first) {
+ dsi->second.insert(dependee_index);
+ }
+ }
+
+ // If this item needs to have dependencies inferred, do so.
+ if (this->InferredDependSets[dependee_index]) {
+ // Make sure an entry exists to hold the set for the item.
+ dependSets[dependee_index];
+ }
+ }
+
+ // Store the inferred dependency sets discovered for this list.
+ for (std::map<int, DependSet>::iterator dsi = dependSets.begin();
+ dsi != dependSets.end(); ++dsi) {
+ this->InferredDependSets[dsi->first]->push_back(dsi->second);
+ }
+}
+
+cmGeneratorTarget const* cmComputeLinkDepends::FindTargetToLink(
+ int depender_index, const std::string& name)
+{
+ // Look for a target in the scope of the depender.
+ cmGeneratorTarget const* from = this->Target;
+ if (depender_index >= 0) {
+ if (cmGeneratorTarget const* depender =
+ this->EntryList[depender_index].Target) {
+ from = depender;
+ }
+ }
+ return from->FindTargetToLink(name);
+}
+
+void cmComputeLinkDepends::InferDependencies()
+{
+ // The inferred dependency sets for each item list the possible
+ // dependencies. The intersection of the sets for one item form its
+ // inferred dependencies.
+ for (unsigned int depender_index = 0;
+ depender_index < this->InferredDependSets.size(); ++depender_index) {
+ // Skip items for which dependencies do not need to be inferred or
+ // for which the inferred dependency sets are empty.
+ DependSetList* sets = this->InferredDependSets[depender_index];
+ if (!sets || sets->empty()) {
+ continue;
+ }
+
+ // Intersect the sets for this item.
+ DependSetList::const_iterator i = sets->begin();
+ DependSet common = *i;
+ for (++i; i != sets->end(); ++i) {
+ DependSet intersection;
+ std::set_intersection(common.begin(), common.end(), i->begin(), i->end(),
+ std::inserter(intersection, intersection.begin()));
+ common = intersection;
+ }
+
+ // Add the inferred dependencies to the graph.
+ cmGraphEdgeList& edges = this->EntryConstraintGraph[depender_index];
+ edges.insert(edges.end(), common.begin(), common.end());
+ }
+}
+
+void cmComputeLinkDepends::CleanConstraintGraph()
+{
+ for (Graph::iterator i = this->EntryConstraintGraph.begin();
+ i != this->EntryConstraintGraph.end(); ++i) {
+ // Sort the outgoing edges for each graph node so that the
+ // original order will be preserved as much as possible.
+ std::sort(i->begin(), i->end());
+
+ // Make the edge list unique.
+ i->erase(std::unique(i->begin(), i->end()), i->end());
+ }
+}
+
+void cmComputeLinkDepends::DisplayConstraintGraph()
+{
+ // Display the graph nodes and their edges.
+ std::ostringstream e;
+ for (unsigned int i = 0; i < this->EntryConstraintGraph.size(); ++i) {
+ EdgeList const& nl = this->EntryConstraintGraph[i];
+ e << "item " << i << " is [" << this->EntryList[i].Item << "]\n";
+ e << cmWrap(" item ", nl, " must follow it", "\n") << "\n";
+ }
+ fprintf(stderr, "%s\n", e.str().c_str());
+}
+
+void cmComputeLinkDepends::OrderLinkEntires()
+{
+ // Compute the DAG of strongly connected components. The algorithm
+ // used by cmComputeComponentGraph should identify the components in
+ // the same order in which the items were originally discovered in
+ // the BFS. This should preserve the original order when no
+ // constraints disallow it.
+ this->CCG = new cmComputeComponentGraph(this->EntryConstraintGraph);
+
+ // The component graph is guaranteed to be acyclic. Start a DFS
+ // from every entry to compute a topological order for the
+ // components.
+ Graph const& cgraph = this->CCG->GetComponentGraph();
+ int n = static_cast<int>(cgraph.size());
+ this->ComponentVisited.resize(cgraph.size(), 0);
+ this->ComponentOrder.resize(cgraph.size(), n);
+ this->ComponentOrderId = n;
+ // Run in reverse order so the topological order will preserve the
+ // original order where there are no constraints.
+ for (int c = n - 1; c >= 0; --c) {
+ this->VisitComponent(c);
+ }
+
+ // Display the component graph.
+ if (this->DebugMode) {
+ this->DisplayComponents();
+ }
+
+ // Start with the original link line.
+ for (std::vector<int>::const_iterator i = this->OriginalEntries.begin();
+ i != this->OriginalEntries.end(); ++i) {
+ this->VisitEntry(*i);
+ }
+
+ // Now explore anything left pending. Since the component graph is
+ // guaranteed to be acyclic we know this will terminate.
+ while (!this->PendingComponents.empty()) {
+ // Visit one entry from the first pending component. The visit
+ // logic will update the pending components accordingly. Since
+ // the pending components are kept in topological order this will
+ // not repeat one.
+ int e = *this->PendingComponents.begin()->second.Entries.begin();
+ this->VisitEntry(e);
+ }
+}
+
+void cmComputeLinkDepends::DisplayComponents()
+{
+ fprintf(stderr, "The strongly connected components are:\n");
+ std::vector<NodeList> const& components = this->CCG->GetComponents();
+ for (unsigned int c = 0; c < components.size(); ++c) {
+ fprintf(stderr, "Component (%u):\n", c);
+ NodeList const& nl = components[c];
+ for (NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni) {
+ int i = *ni;
+ fprintf(stderr, " item %d [%s]\n", i, this->EntryList[i].Item.c_str());
+ }
+ EdgeList const& ol = this->CCG->GetComponentGraphEdges(c);
+ for (EdgeList::const_iterator oi = ol.begin(); oi != ol.end(); ++oi) {
+ int i = *oi;
+ fprintf(stderr, " followed by Component (%d)\n", i);
+ }
+ fprintf(stderr, " topo order index %d\n", this->ComponentOrder[c]);
+ }
+ fprintf(stderr, "\n");
+}
+
+void cmComputeLinkDepends::VisitComponent(unsigned int c)
+{
+ // Check if the node has already been visited.
+ if (this->ComponentVisited[c]) {
+ return;
+ }
+
+ // We are now visiting this component so mark it.
+ this->ComponentVisited[c] = 1;
+
+ // Visit the neighbors of the component first.
+ // 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);
+ }
+
+ // Assign an ordering id to this component.
+ this->ComponentOrder[c] = --this->ComponentOrderId;
+}
+
+void cmComputeLinkDepends::VisitEntry(int index)
+{
+ // Include this entry on the link line.
+ this->FinalLinkOrder.push_back(index);
+
+ // This entry has now been seen. Update its component.
+ bool completed = false;
+ int component = this->CCG->GetComponentMap()[index];
+ std::map<int, PendingComponent>::iterator mi =
+ this->PendingComponents.find(this->ComponentOrder[component]);
+ if (mi != this->PendingComponents.end()) {
+ // The entry is in an already pending component.
+ PendingComponent& pc = mi->second;
+
+ // Remove the entry from those pending in its component.
+ pc.Entries.erase(index);
+ if (pc.Entries.empty()) {
+ // The complete component has been seen since it was last needed.
+ --pc.Count;
+
+ if (pc.Count == 0) {
+ // The component has been completed.
+ this->PendingComponents.erase(mi);
+ completed = true;
+ } else {
+ // The whole component needs to be seen again.
+ NodeList const& nl = this->CCG->GetComponent(component);
+ assert(nl.size() > 1);
+ pc.Entries.insert(nl.begin(), nl.end());
+ }
+ }
+ } else {
+ // The entry is not in an already pending component.
+ NodeList const& nl = this->CCG->GetComponent(component);
+ if (nl.size() > 1) {
+ // This is a non-trivial component. It is now pending.
+ PendingComponent& pc = this->MakePendingComponent(component);
+
+ // The starting entry has already been seen.
+ pc.Entries.erase(index);
+ } else {
+ // This is a trivial component, so it is already complete.
+ completed = true;
+ }
+ }
+
+ // If the entry completed a component, the component's dependencies
+ // are now pending.
+ if (completed) {
+ EdgeList const& ol = this->CCG->GetComponentGraphEdges(component);
+ for (EdgeList::const_iterator oi = ol.begin(); oi != ol.end(); ++oi) {
+ // This entire component is now pending no matter whether it has
+ // been partially seen already.
+ this->MakePendingComponent(*oi);
+ }
+ }
+}
+
+cmComputeLinkDepends::PendingComponent&
+cmComputeLinkDepends::MakePendingComponent(unsigned int component)
+{
+ // Create an entry (in topological order) for the component.
+ PendingComponent& pc =
+ this->PendingComponents[this->ComponentOrder[component]];
+ pc.Id = component;
+ NodeList const& nl = this->CCG->GetComponent(component);
+
+ if (nl.size() == 1) {
+ // Trivial components need be seen only once.
+ pc.Count = 1;
+ } else {
+ // This is a non-trivial strongly connected component of the
+ // original graph. It consists of two or more libraries
+ // (archives) that mutually require objects from one another. In
+ // the worst case we may have to repeat the list of libraries as
+ // many times as there are object files in the biggest archive.
+ // For now we just list them twice.
+ //
+ // The list of items in the component has been sorted by the order
+ // of discovery in the original BFS of dependencies. This has the
+ // advantage that the item directly linked by a target requiring
+ // this component will come first which minimizes the number of
+ // repeats needed.
+ pc.Count = this->ComputeComponentCount(nl);
+ }
+
+ // Store the entries to be seen.
+ pc.Entries.insert(nl.begin(), nl.end());
+
+ return pc;
+}
+
+int cmComputeLinkDepends::ComputeComponentCount(NodeList const& nl)
+{
+ unsigned int count = 2;
+ for (NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni) {
+ if (cmGeneratorTarget const* target = this->EntryList[*ni].Target) {
+ if (cmLinkInterface const* iface =
+ target->GetLinkInterface(this->Config, this->Target)) {
+ if (iface->Multiplicity > count) {
+ count = iface->Multiplicity;
+ }
+ }
+ }
+ }
+ return count;
+}
+
+void cmComputeLinkDepends::DisplayFinalEntries()
+{
+ fprintf(stderr, "target [%s] links to:\n", this->Target->GetName().c_str());
+ for (std::vector<LinkEntry>::const_iterator lei =
+ this->FinalLinkEntries.begin();
+ lei != this->FinalLinkEntries.end(); ++lei) {
+ if (lei->Target) {
+ fprintf(stderr, " target [%s]\n", lei->Target->GetName().c_str());
+ } else {
+ fprintf(stderr, " item [%s]\n", lei->Item.c_str());
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+void cmComputeLinkDepends::CheckWrongConfigItem(cmLinkItem const& item)
+{
+ if (!this->OldLinkDirMode) {
+ return;
+ }
+
+ // For CMake 2.4 bug-compatibility we need to consider the output
+ // directories of targets linked in another configuration as link
+ // directories.
+ if (item.Target && !item.Target->IsImported()) {
+ this->OldWrongConfigItems.insert(item.Target);
+ }
+}
diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h
new file mode 100644
index 0000000..4a33aff
--- /dev/null
+++ b/Source/cmComputeLinkDepends.h
@@ -0,0 +1,177 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmComputeLinkDepends_h
+#define cmComputeLinkDepends_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmGraphAdjacencyList.h"
+#include "cmLinkItem.h"
+
+#include <queue>
+
+class cmComputeComponentGraph;
+class cmGlobalGenerator;
+class cmMakefile;
+class cmGeneratorTarget;
+class cmake;
+
+/** \class cmComputeLinkDepends
+ * \brief Compute link dependencies for targets.
+ */
+class cmComputeLinkDepends
+{
+public:
+ cmComputeLinkDepends(cmGeneratorTarget const* target,
+ const std::string& config);
+ ~cmComputeLinkDepends();
+
+ // Basic information about each link item.
+ struct LinkEntry
+ {
+ std::string Item;
+ cmGeneratorTarget const* Target;
+ bool IsSharedDep;
+ bool IsFlag;
+ LinkEntry()
+ : Item()
+ , Target(CM_NULLPTR)
+ , IsSharedDep(false)
+ , IsFlag(false)
+ {
+ }
+ LinkEntry(LinkEntry const& r)
+ : Item(r.Item)
+ , Target(r.Target)
+ , IsSharedDep(r.IsSharedDep)
+ , IsFlag(r.IsFlag)
+ {
+ }
+ };
+
+ typedef std::vector<LinkEntry> EntryVector;
+ EntryVector const& Compute();
+
+ void SetOldLinkDirMode(bool b);
+ std::set<cmGeneratorTarget const*> const& GetOldWrongConfigItems() const
+ {
+ return this->OldWrongConfigItems;
+ }
+
+private:
+ // Context information.
+ cmGeneratorTarget const* Target;
+ cmMakefile* Makefile;
+ cmGlobalGenerator const* GlobalGenerator;
+ cmake* CMakeInstance;
+ std::string Config;
+ EntryVector FinalLinkEntries;
+
+ std::map<std::string, int>::iterator AllocateLinkEntry(
+ std::string const& item);
+ int AddLinkEntry(cmLinkItem const& item);
+ void AddVarLinkEntries(int depender_index, const char* value);
+ void AddDirectLinkEntries();
+ template <typename T>
+ void AddLinkEntries(int depender_index, std::vector<T> const& libs);
+ cmGeneratorTarget const* FindTargetToLink(int depender_index,
+ const std::string& name);
+
+ // One entry for each unique item.
+ std::vector<LinkEntry> EntryList;
+ std::map<std::string, int> LinkEntryIndex;
+
+ // BFS of initial dependencies.
+ struct BFSEntry
+ {
+ int Index;
+ const char* LibDepends;
+ };
+ std::queue<BFSEntry> BFSQueue;
+ void FollowLinkEntry(BFSEntry const&);
+
+ // Shared libraries that are included only because they are
+ // dependencies of other shared libraries, not because they are part
+ // of the interface.
+ struct SharedDepEntry
+ {
+ cmLinkItem Item;
+ int DependerIndex;
+ };
+ std::queue<SharedDepEntry> SharedDepQueue;
+ std::set<int> SharedDepFollowed;
+ void FollowSharedDeps(int depender_index, cmLinkInterface const* iface,
+ bool follow_interface = false);
+ void QueueSharedDependencies(int depender_index,
+ std::vector<cmLinkItem> const& deps);
+ void HandleSharedDependency(SharedDepEntry const& dep);
+
+ // Dependency inferral for each link item.
+ struct DependSet : public std::set<int>
+ {
+ };
+ struct DependSetList : public std::vector<DependSet>
+ {
+ };
+ std::vector<DependSetList*> InferredDependSets;
+ void InferDependencies();
+
+ // Ordering constraint graph adjacency list.
+ typedef cmGraphNodeList NodeList;
+ typedef cmGraphEdgeList EdgeList;
+ typedef cmGraphAdjacencyList Graph;
+ Graph EntryConstraintGraph;
+ void CleanConstraintGraph();
+ void DisplayConstraintGraph();
+
+ // Ordering algorithm.
+ void OrderLinkEntires();
+ std::vector<char> ComponentVisited;
+ std::vector<int> ComponentOrder;
+
+ struct PendingComponent
+ {
+ // The real component id. Needed because the map is indexed by
+ // component topological index.
+ int Id;
+
+ // The number of times the component needs to be seen. This is
+ // always 1 for trivial components and is initially 2 for
+ // non-trivial components.
+ int Count;
+
+ // The entries yet to be seen to complete the component.
+ std::set<int> Entries;
+ };
+ std::map<int, PendingComponent> PendingComponents;
+ cmComputeComponentGraph* CCG;
+ std::vector<int> FinalLinkOrder;
+ void DisplayComponents();
+ void VisitComponent(unsigned int c);
+ void VisitEntry(int index);
+ PendingComponent& MakePendingComponent(unsigned int component);
+ int ComputeComponentCount(NodeList const& nl);
+ void DisplayFinalEntries();
+
+ // Record of the original link line.
+ std::vector<int> OriginalEntries;
+ std::set<cmGeneratorTarget const*> OldWrongConfigItems;
+ void CheckWrongConfigItem(cmLinkItem const& item);
+
+ int ComponentOrderId;
+ cmTargetLinkLibraryType LinkType;
+ bool HasConfig;
+ bool DebugMode;
+ bool OldLinkDirMode;
+};
+
+#endif
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
new file mode 100644
index 0000000..7db5df3
--- /dev/null
+++ b/Source/cmComputeLinkInformation.cxx
@@ -0,0 +1,1827 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmComputeLinkInformation.h"
+
+#include "cmComputeLinkDepends.h"
+#include "cmOrderDirectories.h"
+
+#include "cmAlgorithms.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmState.h"
+#include "cmake.h"
+
+#include <ctype.h>
+
+//#define CM_COMPUTE_LINK_INFO_DEBUG
+
+/*
+Notes about linking on various platforms:
+
+------------------------------------------------------------------------------
+
+Linux, FreeBSD, Mac OS X, IRIX, Sun, Windows:
+
+Linking to libraries using the full path works fine.
+
+------------------------------------------------------------------------------
+
+On AIX, more work is needed.
+
+ The "-bnoipath" option is needed. From "man ld":
+
+ Note: If you specify a shared object, or an archive file
+ containing a shared object, with an absolute or relative path
+ name, instead of with the -lName flag, the path name is
+ included in the import file ID string in the loader section of
+ the output file. You can override this behavior with the
+ -bnoipath option.
+
+ noipath
+
+ For shared objects listed on the command-line, rather than
+ specified with the -l flag, use a null path component when
+ listing the shared object in the loader section of the
+ output file. A null path component is always used for
+ shared objects specified with the -l flag. This option
+ does not affect the specification of a path component by
+ using a line beginning with #! in an import file. The
+ default is the ipath option.
+
+ This prevents the full path specified on the compile line from being
+ compiled directly into the binary.
+
+ By default the linker places -L paths in the embedded runtime path.
+ In order to implement CMake's RPATH interface correctly, we need the
+ -blibpath:Path option. From "man ld":
+
+ libpath:Path
+
+ Uses Path as the library path when writing the loader section
+ of the output file. Path is neither checked for validity nor
+ used when searching for libraries specified by the -l flag.
+ Path overrides any library paths generated when the -L flag is
+ used.
+
+ If you do not specify any -L flags, or if you specify the
+ nolibpath option, the default library path information is
+ written in the loader section of the output file. The default
+ library path information is the value of the LIBPATH
+ environment variable if it is defined, and /usr/lib:/lib,
+ otherwise.
+
+ We can pass -Wl,-blibpath:/usr/lib:/lib always to avoid the -L stuff
+ and not break when the user sets LIBPATH. Then if we want to add an
+ rpath we insert it into the option before /usr/lib.
+
+------------------------------------------------------------------------------
+
+On HP-UX, more work is needed. There are differences between
+versions.
+
+ld: 92453-07 linker linker ld B.10.33 990520
+
+ Linking with a full path works okay for static and shared libraries.
+ The linker seems to always put the full path to where the library
+ was found in the binary whether using a full path or -lfoo syntax.
+ Transitive link dependencies work just fine due to the full paths.
+
+ It has the "-l:libfoo.sl" option. The +nodefaultrpath is accepted
+ but not documented and does not seem to do anything. There is no
+ +forceload option.
+
+ld: 92453-07 linker ld HP Itanium(R) B.12.41 IPF/IPF
+
+ Linking with a full path works okay for static libraries.
+
+ Linking with a full path works okay for shared libraries. However
+ dependent (transitive) libraries of those linked directly must be
+ either found with an rpath stored in the direct dependencies or
+ found in -L paths as if they were specified with "-l:libfoo.sl"
+ (really "-l:<soname>"). The search matches that of the dynamic
+ loader but only with -L paths. In other words, if we have an
+ executable that links to shared library bar which links to shared
+ library foo, the link line for the exe must contain
+
+ /dir/with/bar/libbar.sl -L/dir/with/foo
+
+ It does not matter whether the exe wants to link to foo directly or
+ whether /dir/with/foo/libfoo.sl is listed. The -L path must still
+ be present. It should match the runtime path computed for the
+ executable taking all directly and transitively linked libraries
+ into account.
+
+ The "+nodefaultrpath" option should be used to avoid getting -L
+ paths in the rpath unless we add our own rpath with +b. This means
+ that skip-build-rpath should use this option.
+
+ See documentation in "man ld", "man dld.so", and
+ http://docs.hp.com/en/B2355-90968/creatingandusinglibraries.htm
+
+ +[no]defaultrpath
+ +defaultrpath is the default. Include any paths that are
+ specified with -L in the embedded path, unless you specify the
+ +b option. If you use +b, only the path list specified by +b is
+ in the embedded path.
+
+ The +nodefaultrpath option removes all library paths that were
+ specified with the -L option from the embedded path. The linker
+ searches the library paths specified by the -L option at link
+ time. At run time, the only library paths searched are those
+ specified by the environment variables LD_LIBRARY_PATH and
+ SHLIB_PATH, library paths specified by the +b linker option, and
+ finally the default library paths.
+
+ +rpathfirst
+ This option will cause the paths specified in RPATH (embedded
+ path) to be used before the paths specified in LD_LIBRARY_PATH
+ or SHLIB_PATH, in searching for shared libraries. This changes
+ the default search order of LD_LIBRARY_PATH, SHLIB_PATH, and
+ RPATH (embedded path).
+
+------------------------------------------------------------------------------
+Notes about dependent (transitive) shared libraries:
+
+On non-Windows systems shared libraries may have transitive
+dependencies. In order to support LINK_INTERFACE_LIBRARIES we must
+support linking to a shared library without listing all the libraries
+to which it links. Some linkers want to be able to find the
+transitive dependencies (dependent libraries) of shared libraries
+listed on the command line.
+
+ - On Windows, DLLs are not directly linked, and the import libraries
+ have no transitive dependencies.
+
+ - On Mac OS X 10.5 and above transitive dependencies are not needed.
+
+ - On Mac OS X 10.4 and below we need to actually list the dependencies.
+ Otherwise when using -isysroot for universal binaries it cannot
+ find the dependent libraries. Listing them on the command line
+ tells the linker where to find them, but unfortunately also links
+ the library.
+
+ - On HP-UX, the linker wants to find the transitive dependencies of
+ shared libraries in the -L paths even if the dependent libraries
+ are given on the link line.
+
+ - On AIX the transitive dependencies are not needed.
+
+ - On SGI, the linker wants to find the transitive dependencies of
+ shared libraries in the -L paths if they are not given on the link
+ line. Transitive linking can be disabled using the options
+
+ -no_transitive_link -Wl,-no_transitive_link
+
+ which disable it. Both options must be given when invoking the
+ linker through the compiler.
+
+ - On Sun, the linker wants to find the transitive dependencies of
+ shared libraries in the -L paths if they are not given on the link
+ line.
+
+ - On Linux, FreeBSD, and QNX:
+
+ The linker wants to find the transitive dependencies of shared
+ libraries in the "-rpath-link" paths option if they have not been
+ given on the link line. The option is like rpath but just for
+ link time:
+
+ -Wl,-rpath-link,"/path1:/path2"
+
+For -rpath-link, we need a separate runtime path ordering pass
+including just the dependent libraries that are not linked.
+
+For -L paths on non-HP, we can do the same thing as with rpath-link
+but put the results in -L paths. The paths should be listed at the
+end to avoid conflicting with user search paths (?).
+
+For -L paths on HP, we should do a runtime path ordering pass with
+all libraries, both linked and non-linked. Even dependent
+libraries that are also linked need to be listed in -L paths.
+
+In our implementation we add all dependent libraries to the runtime
+path computation. Then the auto-generated RPATH will find everything.
+
+------------------------------------------------------------------------------
+Notes about shared libraries with not builtin soname:
+
+Some UNIX shared libraries may be created with no builtin soname. On
+some platforms such libraries cannot be linked using the path to their
+location because the linker will copy the path into the field used to
+find the library at runtime.
+
+ Apple: ../libfoo.dylib ==> libfoo.dylib # ok, uses install_name
+ SGI: ../libfoo.so ==> libfoo.so # ok
+ AIX: ../libfoo.so ==> libfoo.so # ok
+ Linux: ../libfoo.so ==> ../libfoo.so # bad
+ HP-UX: ../libfoo.so ==> ../libfoo.so # bad
+ Sun: ../libfoo.so ==> ../libfoo.so # bad
+ FreeBSD: ../libfoo.so ==> ../libfoo.so # bad
+
+In order to link these libraries we need to use the old-style split
+into -L.. and -lfoo options. This should be fairly safe because most
+problems with -lfoo options were related to selecting shared libraries
+instead of static but in this case we want the shared lib. Link
+directory ordering needs to be done to make sure these shared
+libraries are found first. There should be very few restrictions
+because this need be done only for shared libraries without soname-s.
+
+*/
+
+cmComputeLinkInformation::cmComputeLinkInformation(
+ const cmGeneratorTarget* target, const std::string& config)
+{
+ // Store context information.
+ this->Target = target;
+ this->Makefile = this->Target->Target->GetMakefile();
+ this->GlobalGenerator =
+ this->Target->GetLocalGenerator()->GetGlobalGenerator();
+ this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance();
+
+ // Check whether to recognize OpenBSD-style library versioned names.
+ this->OpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
+
+ // The configuration being linked.
+ this->Config = config;
+
+ // Allocate internals.
+ this->OrderLinkerSearchPath = new cmOrderDirectories(
+ this->GlobalGenerator, target, "linker search path");
+ this->OrderRuntimeSearchPath = new cmOrderDirectories(
+ this->GlobalGenerator, target, "runtime search path");
+ this->OrderDependentRPath = CM_NULLPTR;
+
+ // Get the language used for linking this target.
+ this->LinkLanguage = this->Target->GetLinkerLanguage(config);
+ if (this->LinkLanguage.empty()) {
+ // The Compute method will do nothing, so skip the rest of the
+ // initialization.
+ return;
+ }
+
+ // Check whether we should use an import library for linking a target.
+ this->UseImportLibrary =
+ this->Makefile->IsDefinitionSet("CMAKE_IMPORT_LIBRARY_SUFFIX");
+
+ // Check whether we should skip dependencies on shared library files.
+ this->LinkDependsNoShared =
+ this->Target->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED");
+
+ // On platforms without import libraries there may be a special flag
+ // to use when creating a plugin (module) that obtains symbols from
+ // the program that will load it.
+ this->LoaderFlag = CM_NULLPTR;
+ if (!this->UseImportLibrary &&
+ this->Target->GetType() == cmState::MODULE_LIBRARY) {
+ std::string loader_flag_var = "CMAKE_SHARED_MODULE_LOADER_";
+ loader_flag_var += this->LinkLanguage;
+ loader_flag_var += "_FLAG";
+ this->LoaderFlag = this->Makefile->GetDefinition(loader_flag_var);
+ }
+
+ // Get options needed to link libraries.
+ this->LibLinkFlag =
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG");
+ this->LibLinkFileFlag =
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FILE_FLAG");
+ this->LibLinkSuffix =
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
+
+ // Get options needed to specify RPATHs.
+ this->RuntimeUseChrpath = false;
+ if (this->Target->GetType() != cmState::STATIC_LIBRARY) {
+ const char* tType =
+ ((this->Target->GetType() == cmState::EXECUTABLE) ? "EXECUTABLE"
+ : "SHARED_LIBRARY");
+ std::string rtVar = "CMAKE_";
+ rtVar += tType;
+ rtVar += "_RUNTIME_";
+ rtVar += this->LinkLanguage;
+ rtVar += "_FLAG";
+ std::string rtSepVar = rtVar + "_SEP";
+ this->RuntimeFlag = this->Makefile->GetSafeDefinition(rtVar);
+ this->RuntimeSep = this->Makefile->GetSafeDefinition(rtSepVar);
+ this->RuntimeAlways = (this->Makefile->GetSafeDefinition(
+ "CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH"));
+
+ this->RuntimeUseChrpath = this->Target->IsChrpathUsed(config);
+
+ // Get options needed to help find dependent libraries.
+ std::string rlVar = "CMAKE_";
+ rlVar += tType;
+ rlVar += "_RPATH_LINK_";
+ rlVar += this->LinkLanguage;
+ rlVar += "_FLAG";
+ this->RPathLinkFlag = this->Makefile->GetSafeDefinition(rlVar);
+ }
+
+ // Check if we need to include the runtime search path at link time.
+ {
+ std::string var = "CMAKE_SHARED_LIBRARY_LINK_";
+ var += this->LinkLanguage;
+ var += "_WITH_RUNTIME_PATH";
+ this->LinkWithRuntimePath = this->Makefile->IsOn(var);
+ }
+
+ // Check the platform policy for missing soname case.
+ this->NoSONameUsesPath =
+ this->Makefile->IsOn("CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME");
+
+ // Get link type information.
+ this->ComputeLinkTypeInfo();
+
+ // Setup the link item parser.
+ this->ComputeItemParserInfo();
+
+ // Setup framework support.
+ this->ComputeFrameworkInfo();
+
+ // Choose a mode for dealing with shared library dependencies.
+ this->SharedDependencyMode = SharedDepModeNone;
+ if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_FILES")) {
+ this->SharedDependencyMode = SharedDepModeLink;
+ } else if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_DIRS")) {
+ this->SharedDependencyMode = SharedDepModeLibDir;
+ } else if (!this->RPathLinkFlag.empty()) {
+ this->SharedDependencyMode = SharedDepModeDir;
+ this->OrderDependentRPath = new cmOrderDirectories(
+ this->GlobalGenerator, target, "dependent library path");
+ }
+
+ // Add the search path entries requested by the user to path ordering.
+ this->OrderLinkerSearchPath->AddUserDirectories(
+ this->Target->GetLinkDirectories());
+ this->OrderRuntimeSearchPath->AddUserDirectories(
+ this->Target->GetLinkDirectories());
+
+ // Set up the implicit link directories.
+ this->LoadImplicitLinkInfo();
+ this->OrderLinkerSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
+ this->OrderRuntimeSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
+ if (this->OrderDependentRPath) {
+ this->OrderDependentRPath->SetImplicitDirectories(this->ImplicitLinkDirs);
+ this->OrderDependentRPath->AddLanguageDirectories(this->RuntimeLinkDirs);
+ }
+
+ // Decide whether to enable compatible library search path mode.
+ // There exists code that effectively does
+ //
+ // /path/to/libA.so -lB
+ //
+ // where -lB is meant to link to /path/to/libB.so. This is broken
+ // because it specified -lB without specifying a link directory (-L)
+ // in which to search for B. This worked in CMake 2.4 and below
+ // because -L/path/to would be added by the -L/-l split for A. In
+ // order to support such projects we need to add the directories
+ // containing libraries linked with a full path to the -L path.
+ this->OldLinkDirMode =
+ this->Target->GetPolicyStatusCMP0003() != cmPolicies::NEW;
+ if (this->OldLinkDirMode) {
+ // Construct a mask to not bother with this behavior for link
+ // directories already specified by the user.
+ std::vector<std::string> const& dirs = this->Target->GetLinkDirectories();
+ this->OldLinkDirMask.insert(dirs.begin(), dirs.end());
+ }
+
+ this->CMP0060Warn = this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0060");
+}
+
+cmComputeLinkInformation::~cmComputeLinkInformation()
+{
+ delete this->OrderLinkerSearchPath;
+ delete this->OrderRuntimeSearchPath;
+ delete this->OrderDependentRPath;
+}
+
+cmComputeLinkInformation::ItemVector const&
+cmComputeLinkInformation::GetItems()
+{
+ return this->Items;
+}
+
+std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
+{
+ return this->OrderLinkerSearchPath->GetOrderedDirectories();
+}
+
+std::string cmComputeLinkInformation::GetRPathLinkString()
+{
+ // If there is no separate linker runtime search flag (-rpath-link)
+ // there is no reason to compute a string.
+ if (!this->OrderDependentRPath) {
+ return "";
+ }
+
+ // Construct the linker runtime search path.
+ return cmJoin(this->OrderDependentRPath->GetOrderedDirectories(), ":");
+}
+
+std::vector<std::string> const& cmComputeLinkInformation::GetDepends()
+{
+ return this->Depends;
+}
+
+std::vector<std::string> const& cmComputeLinkInformation::GetFrameworkPaths()
+{
+ return this->FrameworkPaths;
+}
+
+const std::set<const cmGeneratorTarget*>&
+cmComputeLinkInformation::GetSharedLibrariesLinked()
+{
+ return this->SharedLibrariesLinked;
+}
+
+bool cmComputeLinkInformation::Compute()
+{
+ // Skip targets that do not link.
+ if (!(this->Target->GetType() == cmState::EXECUTABLE ||
+ this->Target->GetType() == cmState::SHARED_LIBRARY ||
+ this->Target->GetType() == cmState::MODULE_LIBRARY ||
+ this->Target->GetType() == cmState::STATIC_LIBRARY)) {
+ return false;
+ }
+
+ // 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());
+ return false;
+ }
+
+ // Compute the ordered link line items.
+ cmComputeLinkDepends cld(this->Target, this->Config);
+ cld.SetOldLinkDirMode(this->OldLinkDirMode);
+ cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute();
+
+ // Add the link line items.
+ for (cmComputeLinkDepends::EntryVector::const_iterator lei =
+ linkEntries.begin();
+ lei != linkEntries.end(); ++lei) {
+ if (lei->IsSharedDep) {
+ this->AddSharedDepItem(lei->Item, lei->Target);
+ } else {
+ this->AddItem(lei->Item, lei->Target);
+ }
+ }
+
+ // Restore the target link type so the correct system runtime
+ // libraries are found.
+ const char* lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC");
+ if (cmSystemTools::IsOn(lss)) {
+ this->SetCurrentLinkType(LinkStatic);
+ } else {
+ this->SetCurrentLinkType(this->StartLinkType);
+ }
+
+ // Finish listing compatibility paths.
+ if (this->OldLinkDirMode) {
+ // For CMake 2.4 bug-compatibility we need to consider the output
+ // directories of targets linked in another configuration as link
+ // directories.
+ std::set<cmGeneratorTarget const*> const& wrongItems =
+ cld.GetOldWrongConfigItems();
+ for (std::set<cmGeneratorTarget const*>::const_iterator i =
+ wrongItems.begin();
+ i != wrongItems.end(); ++i) {
+ cmGeneratorTarget const* tgt = *i;
+ bool implib = (this->UseImportLibrary &&
+ (tgt->GetType() == cmState::SHARED_LIBRARY));
+ std::string lib = tgt->GetFullPath(this->Config, implib, true);
+ this->OldLinkDirItems.push_back(lib);
+ }
+ }
+
+ // Finish setting up linker search directories.
+ if (!this->FinishLinkerSearchDirectories()) {
+ return false;
+ }
+
+ // Add implicit language runtime libraries and directories.
+ this->AddImplicitLinkInfo();
+
+ if (!this->CMP0060WarnItems.empty()) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0060) << "\n"
+ "Some library files are in directories implicitly searched by "
+ "the linker when invoked for " << this->LinkLanguage << ":\n"
+ " " << cmJoin(this->CMP0060WarnItems, "\n ") << "\n"
+ "For compatibility with older versions of CMake, the generated "
+ "link line will ask the linker to search for these by library "
+ "name."
+ ;
+ /* clang-format on */
+ this->CMakeInstance->IssueMessage(cmake::AUTHOR_WARNING, w.str(),
+ this->Target->GetBacktrace());
+ }
+
+ return true;
+}
+
+void cmComputeLinkInformation::AddImplicitLinkInfo()
+{
+ // The link closure lists all languages whose implicit info is needed.
+ cmGeneratorTarget::LinkClosure const* lc =
+ this->Target->GetLinkClosure(this->Config);
+ for (std::vector<std::string>::const_iterator li = lc->Languages.begin();
+ li != lc->Languages.end(); ++li) {
+ // Skip those of the linker language. They are implicit.
+ if (*li != this->LinkLanguage) {
+ this->AddImplicitLinkInfo(*li);
+ }
+ }
+}
+
+void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang)
+{
+ // Add libraries for this language that are not implied by the
+ // linker language.
+ std::string libVar = "CMAKE_";
+ libVar += lang;
+ libVar += "_IMPLICIT_LINK_LIBRARIES";
+ if (const char* libs = this->Makefile->GetDefinition(libVar)) {
+ std::vector<std::string> libsVec;
+ cmSystemTools::ExpandListArgument(libs, libsVec);
+ for (std::vector<std::string>::const_iterator i = libsVec.begin();
+ i != libsVec.end(); ++i) {
+ if (this->ImplicitLinkLibs.find(*i) == this->ImplicitLinkLibs.end()) {
+ this->AddItem(*i, CM_NULLPTR);
+ }
+ }
+ }
+
+ // Add linker search paths for this language that are not
+ // implied by the linker language.
+ std::string dirVar = "CMAKE_";
+ dirVar += lang;
+ dirVar += "_IMPLICIT_LINK_DIRECTORIES";
+ if (const char* dirs = this->Makefile->GetDefinition(dirVar)) {
+ std::vector<std::string> dirsVec;
+ cmSystemTools::ExpandListArgument(dirs, dirsVec);
+ this->OrderLinkerSearchPath->AddLanguageDirectories(dirsVec);
+ }
+}
+
+void cmComputeLinkInformation::AddItem(std::string const& item,
+ cmGeneratorTarget const* tgt)
+{
+ // Compute the proper name to use to link this library.
+ const std::string& config = this->Config;
+ bool impexe = (tgt && tgt->IsExecutableWithExports());
+ if (impexe && !this->UseImportLibrary && !this->LoaderFlag) {
+ // Skip linking to executables on platforms with no import
+ // libraries or loader flags.
+ return;
+ }
+
+ if (tgt && tgt->IsLinkable()) {
+ // This is a CMake target. Ask the target for its real name.
+ if (impexe && this->LoaderFlag) {
+ // This link item is an executable that may provide symbols
+ // used by this target. A special flag is needed on this
+ // platform. Add it now.
+ std::string linkItem;
+ linkItem = this->LoaderFlag;
+
+ std::string exe = tgt->GetFullPath(config, this->UseImportLibrary, true);
+ linkItem += exe;
+ this->Items.push_back(Item(linkItem, true, tgt));
+ this->Depends.push_back(exe);
+ } else if (tgt->GetType() == cmState::INTERFACE_LIBRARY) {
+ // Add the interface library as an item so it can be considered as part
+ // of COMPATIBLE_INTERFACE_ enforcement. The generators will ignore
+ // this for the actual link line.
+ this->Items.push_back(Item(std::string(), false, tgt));
+ } else {
+ // Decide whether to use an import library.
+ bool implib = (this->UseImportLibrary &&
+ (impexe || tgt->GetType() == cmState::SHARED_LIBRARY));
+
+ // Pass the full path to the target file.
+ std::string lib = tgt->GetFullPath(config, implib, true);
+ if (!this->LinkDependsNoShared ||
+ tgt->GetType() != cmState::SHARED_LIBRARY) {
+ this->Depends.push_back(lib);
+ }
+
+ this->AddTargetItem(lib, tgt);
+ this->AddLibraryRuntimeInfo(lib, tgt);
+ }
+ } else {
+ // This is not a CMake target. Use the name given.
+ if (cmSystemTools::FileIsFullPath(item.c_str())) {
+ if (cmSystemTools::FileIsDirectory(item)) {
+ // This is a directory.
+ this->AddDirectoryItem(item);
+ } else {
+ // Use the full path given to the library file.
+ this->Depends.push_back(item);
+ this->AddFullItem(item);
+ this->AddLibraryRuntimeInfo(item);
+ }
+ } else {
+ // This is a library or option specified by the user.
+ this->AddUserItem(item, true);
+ }
+ }
+}
+
+void cmComputeLinkInformation::AddSharedDepItem(std::string const& item,
+ const cmGeneratorTarget* tgt)
+{
+ // If dropping shared library dependencies, ignore them.
+ if (this->SharedDependencyMode == SharedDepModeNone) {
+ return;
+ }
+
+ // The user may have incorrectly named an item. Skip items that are
+ // not full paths to shared libraries.
+ if (tgt) {
+ // The target will provide a full path. Make sure it is a shared
+ // library.
+ if (tgt->GetType() != cmState::SHARED_LIBRARY) {
+ return;
+ }
+ } else {
+ // Skip items that are not full paths. We will not be able to
+ // reliably specify them.
+ if (!cmSystemTools::FileIsFullPath(item.c_str())) {
+ return;
+ }
+
+ // Get the name of the library from the file name.
+ std::string file = cmSystemTools::GetFilenameName(item);
+ if (!this->ExtractSharedLibraryName.find(file.c_str())) {
+ // This is not the name of a shared library.
+ return;
+ }
+ }
+
+ // If in linking mode, just link to the shared library.
+ if (this->SharedDependencyMode == SharedDepModeLink) {
+ this->AddItem(item, tgt);
+ return;
+ }
+
+ // Get a full path to the dependent shared library.
+ // Add it to the runtime path computation so that the target being
+ // linked will be able to find it.
+ std::string lib;
+ if (tgt) {
+ lib = tgt->GetFullPath(this->Config, this->UseImportLibrary);
+ this->AddLibraryRuntimeInfo(lib, tgt);
+ } else {
+ lib = item;
+ this->AddLibraryRuntimeInfo(lib);
+ }
+
+ // Check if we need to include the dependent shared library in other
+ // path ordering.
+ cmOrderDirectories* order = CM_NULLPTR;
+ if (this->SharedDependencyMode == SharedDepModeLibDir &&
+ !this->LinkWithRuntimePath /* AddLibraryRuntimeInfo adds it */) {
+ // Add the item to the linker search path.
+ order = this->OrderLinkerSearchPath;
+ } else if (this->SharedDependencyMode == SharedDepModeDir) {
+ // Add the item to the separate dependent library search path.
+ order = this->OrderDependentRPath;
+ }
+ if (order) {
+ if (tgt) {
+ std::string soName = tgt->GetSOName(this->Config);
+ const char* soname = soName.empty() ? CM_NULLPTR : soName.c_str();
+ order->AddRuntimeLibrary(lib, soname);
+ } else {
+ order->AddRuntimeLibrary(lib);
+ }
+ }
+}
+
+void cmComputeLinkInformation::ComputeLinkTypeInfo()
+{
+ // Check whether archives may actually be shared libraries.
+ this->ArchivesMayBeShared =
+ this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
+ "TARGET_ARCHIVES_MAY_BE_SHARED_LIBS");
+
+ // First assume we cannot do link type stuff.
+ this->LinkTypeEnabled = false;
+
+ // Lookup link type selection flags.
+ const char* static_link_type_flag = CM_NULLPTR;
+ const char* shared_link_type_flag = CM_NULLPTR;
+ const char* target_type_str = CM_NULLPTR;
+ switch (this->Target->GetType()) {
+ case cmState::EXECUTABLE:
+ target_type_str = "EXE";
+ break;
+ case cmState::SHARED_LIBRARY:
+ target_type_str = "SHARED_LIBRARY";
+ break;
+ case cmState::MODULE_LIBRARY:
+ target_type_str = "SHARED_MODULE";
+ break;
+ default:
+ break;
+ }
+ if (target_type_str) {
+ std::string static_link_type_flag_var = "CMAKE_";
+ static_link_type_flag_var += target_type_str;
+ static_link_type_flag_var += "_LINK_STATIC_";
+ static_link_type_flag_var += this->LinkLanguage;
+ static_link_type_flag_var += "_FLAGS";
+ static_link_type_flag =
+ this->Makefile->GetDefinition(static_link_type_flag_var);
+
+ std::string shared_link_type_flag_var = "CMAKE_";
+ shared_link_type_flag_var += target_type_str;
+ shared_link_type_flag_var += "_LINK_DYNAMIC_";
+ shared_link_type_flag_var += this->LinkLanguage;
+ shared_link_type_flag_var += "_FLAGS";
+ shared_link_type_flag =
+ this->Makefile->GetDefinition(shared_link_type_flag_var);
+ }
+
+ // We can support link type switching only if all needed flags are
+ // known.
+ if (static_link_type_flag && *static_link_type_flag &&
+ shared_link_type_flag && *shared_link_type_flag) {
+ this->LinkTypeEnabled = true;
+ this->StaticLinkTypeFlag = static_link_type_flag;
+ this->SharedLinkTypeFlag = shared_link_type_flag;
+ }
+
+ // Lookup the starting link type from the target (linked statically?).
+ const char* lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC");
+ this->StartLinkType = cmSystemTools::IsOn(lss) ? LinkStatic : LinkShared;
+ this->CurrentLinkType = this->StartLinkType;
+}
+
+void cmComputeLinkInformation::ComputeItemParserInfo()
+{
+ // Get possible library name prefixes.
+ cmMakefile* mf = this->Makefile;
+ this->AddLinkPrefix(mf->GetDefinition("CMAKE_STATIC_LIBRARY_PREFIX"));
+ this->AddLinkPrefix(mf->GetDefinition("CMAKE_SHARED_LIBRARY_PREFIX"));
+
+ // Import library names should be matched and treated as shared
+ // libraries for the purposes of linking.
+ this->AddLinkExtension(mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"),
+ LinkShared);
+ this->AddLinkExtension(mf->GetDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"),
+ LinkStatic);
+ this->AddLinkExtension(mf->GetDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"),
+ LinkShared);
+ this->AddLinkExtension(mf->GetDefinition("CMAKE_LINK_LIBRARY_SUFFIX"),
+ LinkUnknown);
+ if (const char* linkSuffixes =
+ mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) {
+ std::vector<std::string> linkSuffixVec;
+ cmSystemTools::ExpandListArgument(linkSuffixes, linkSuffixVec);
+ for (std::vector<std::string>::iterator i = linkSuffixVec.begin();
+ i != linkSuffixVec.end(); ++i) {
+ this->AddLinkExtension(i->c_str(), LinkUnknown);
+ }
+ }
+ if (const char* sharedSuffixes =
+ mf->GetDefinition("CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES")) {
+ std::vector<std::string> sharedSuffixVec;
+ cmSystemTools::ExpandListArgument(sharedSuffixes, sharedSuffixVec);
+ for (std::vector<std::string>::iterator i = sharedSuffixVec.begin();
+ i != sharedSuffixVec.end(); ++i) {
+ this->AddLinkExtension(i->c_str(), LinkShared);
+ }
+ }
+
+ // Compute a regex to match link extensions.
+ std::string libext =
+ this->CreateExtensionRegex(this->LinkExtensions, LinkUnknown);
+
+ // Create regex to remove any library extension.
+ std::string reg("(.*)");
+ reg += libext;
+ this->OrderLinkerSearchPath->SetLinkExtensionInfo(this->LinkExtensions, reg);
+
+ // Create a regex to match a library name. Match index 1 will be
+ // the prefix if it exists and empty otherwise. Match index 2 will
+ // be the library name. Match index 3 will be the library
+ // extension.
+ reg = "^(";
+ for (std::set<std::string>::iterator p = this->LinkPrefixes.begin();
+ p != this->LinkPrefixes.end(); ++p) {
+ reg += *p;
+ reg += "|";
+ }
+ reg += ")";
+ reg += "([^/:]*)";
+
+ // Create a regex to match any library name.
+ std::string reg_any = reg;
+ reg_any += libext;
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "any regex [%s]\n", reg_any.c_str());
+#endif
+ this->ExtractAnyLibraryName.compile(reg_any.c_str());
+
+ // Create a regex to match static library names.
+ if (!this->StaticLinkExtensions.empty()) {
+ std::string reg_static = reg;
+ reg_static +=
+ this->CreateExtensionRegex(this->StaticLinkExtensions, LinkStatic);
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "static regex [%s]\n", reg_static.c_str());
+#endif
+ this->ExtractStaticLibraryName.compile(reg_static.c_str());
+ }
+
+ // Create a regex to match shared library names.
+ if (!this->SharedLinkExtensions.empty()) {
+ std::string reg_shared = reg;
+ this->SharedRegexString =
+ this->CreateExtensionRegex(this->SharedLinkExtensions, LinkShared);
+ reg_shared += this->SharedRegexString;
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "shared regex [%s]\n", reg_shared.c_str());
+#endif
+ this->ExtractSharedLibraryName.compile(reg_shared.c_str());
+ }
+}
+
+void cmComputeLinkInformation::AddLinkPrefix(const char* p)
+{
+ if (p && *p) {
+ this->LinkPrefixes.insert(p);
+ }
+}
+
+void cmComputeLinkInformation::AddLinkExtension(const char* e, LinkType type)
+{
+ if (e && *e) {
+ if (type == LinkStatic) {
+ this->StaticLinkExtensions.push_back(e);
+ }
+ if (type == LinkShared) {
+ this->SharedLinkExtensions.push_back(e);
+ }
+ this->LinkExtensions.push_back(e);
+ }
+}
+
+std::string cmComputeLinkInformation::CreateExtensionRegex(
+ std::vector<std::string> const& exts, LinkType type)
+{
+ // Build a list of extension choices.
+ std::string libext = "(";
+ const char* sep = "";
+ for (std::vector<std::string>::const_iterator i = exts.begin();
+ i != exts.end(); ++i) {
+ // Separate this choice from the previous one.
+ libext += sep;
+ sep = "|";
+
+ // Store this extension choice with the "." escaped.
+ libext += "\\";
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ libext += this->NoCaseExpression(i->c_str());
+#else
+ libext += *i;
+#endif
+ }
+
+ // Finish the list.
+ libext += ")";
+
+ // Add an optional OpenBSD version component.
+ if (this->OpenBSD) {
+ libext += "(\\.[0-9]+\\.[0-9]+)?";
+ } else if (type == LinkShared) {
+ libext += "(\\.[0-9]+)?";
+ }
+
+ libext += "$";
+ return libext;
+}
+
+std::string cmComputeLinkInformation::NoCaseExpression(const char* str)
+{
+ std::string ret;
+ const char* s = str;
+ while (*s) {
+ if (*s == '.') {
+ ret += *s;
+ } else {
+ ret += "[";
+ ret += static_cast<char>(tolower(*s));
+ ret += static_cast<char>(toupper(*s));
+ ret += "]";
+ }
+ s++;
+ }
+ return ret;
+}
+
+void cmComputeLinkInformation::SetCurrentLinkType(LinkType lt)
+{
+ // If we are changing the current link type add the flag to tell the
+ // linker about it.
+ if (this->CurrentLinkType != lt) {
+ this->CurrentLinkType = lt;
+
+ if (this->LinkTypeEnabled) {
+ switch (this->CurrentLinkType) {
+ case LinkStatic:
+ this->Items.push_back(Item(this->StaticLinkTypeFlag, false));
+ break;
+ case LinkShared:
+ this->Items.push_back(Item(this->SharedLinkTypeFlag, false));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void cmComputeLinkInformation::AddTargetItem(std::string const& item,
+ cmGeneratorTarget const* target)
+{
+ // This is called to handle a link item that is a full path to a target.
+ // If the target is not a static library make sure the link type is
+ // shared. This is because dynamic-mode linking can handle both
+ // shared and static libraries but static-mode can handle only
+ // static libraries. If a previous user item changed the link type
+ // to static we need to make sure it is back to shared.
+ if (target->GetType() != cmState::STATIC_LIBRARY) {
+ this->SetCurrentLinkType(LinkShared);
+ }
+
+ // Keep track of shared library targets linked.
+ if (target->GetType() == cmState::SHARED_LIBRARY) {
+ this->SharedLibrariesLinked.insert(target);
+ }
+
+ // Handle case of an imported shared library with no soname.
+ if (this->NoSONameUsesPath &&
+ target->IsImportedSharedLibWithoutSOName(this->Config)) {
+ this->AddSharedLibNoSOName(item);
+ return;
+ }
+
+ // If this platform wants a flag before the full path, add it.
+ if (!this->LibLinkFileFlag.empty()) {
+ this->Items.push_back(Item(this->LibLinkFileFlag, false));
+ }
+
+ // For compatibility with CMake 2.4 include the item's directory in
+ // the linker search path.
+ if (this->OldLinkDirMode && !target->IsFrameworkOnApple() &&
+ this->OldLinkDirMask.find(cmSystemTools::GetFilenamePath(item)) ==
+ this->OldLinkDirMask.end()) {
+ this->OldLinkDirItems.push_back(item);
+ }
+
+ // Now add the full path to the library.
+ this->Items.push_back(Item(item, true, target));
+}
+
+void cmComputeLinkInformation::AddFullItem(std::string const& item)
+{
+ // Check for the implicit link directory special case.
+ if (this->CheckImplicitDirItem(item)) {
+ return;
+ }
+
+ // Check for case of shared library with no builtin soname.
+ if (this->NoSONameUsesPath && this->CheckSharedLibNoSOName(item)) {
+ return;
+ }
+
+ // Full path libraries should specify a valid library file name.
+ // See documentation of CMP0008.
+ std::string generator = this->GlobalGenerator->GetName();
+ if (this->Target->GetPolicyStatusCMP0008() != cmPolicies::NEW &&
+ (generator.find("Visual Studio") != generator.npos ||
+ generator.find("Xcode") != generator.npos)) {
+ std::string file = cmSystemTools::GetFilenameName(item);
+ if (!this->ExtractAnyLibraryName.find(file.c_str())) {
+ this->HandleBadFullItem(item, file);
+ return;
+ }
+ }
+
+ // This is called to handle a link item that is a full path.
+ // If the target is not a static library make sure the link type is
+ // shared. This is because dynamic-mode linking can handle both
+ // shared and static libraries but static-mode can handle only
+ // static libraries. If a previous user item changed the link type
+ // to static we need to make sure it is back to shared.
+ if (this->LinkTypeEnabled) {
+ std::string name = cmSystemTools::GetFilenameName(item);
+ if (this->ExtractSharedLibraryName.find(name)) {
+ this->SetCurrentLinkType(LinkShared);
+ } else if (!this->ExtractStaticLibraryName.find(item)) {
+ // We cannot determine the type. Assume it is the target's
+ // default type.
+ this->SetCurrentLinkType(this->StartLinkType);
+ }
+ }
+
+ // For compatibility with CMake 2.4 include the item's directory in
+ // the linker search path.
+ if (this->OldLinkDirMode &&
+ this->OldLinkDirMask.find(cmSystemTools::GetFilenamePath(item)) ==
+ this->OldLinkDirMask.end()) {
+ this->OldLinkDirItems.push_back(item);
+ }
+
+ // If this platform wants a flag before the full path, add it.
+ if (!this->LibLinkFileFlag.empty()) {
+ this->Items.push_back(Item(this->LibLinkFileFlag, false));
+ }
+
+ // Now add the full path to the library.
+ this->Items.push_back(Item(item, true));
+}
+
+bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item)
+{
+ // We only switch to a pathless item if the link type may be
+ // enforced. Fortunately only platforms that support link types
+ // seem to have magic per-architecture implicit link directories.
+ if (!this->LinkTypeEnabled) {
+ return false;
+ }
+
+ // Check if this item is in an implicit link directory.
+ std::string dir = cmSystemTools::GetFilenamePath(item);
+ if (this->ImplicitLinkDirs.find(dir) == this->ImplicitLinkDirs.end()) {
+ // Only libraries in implicit link directories are converted to
+ // pathless items.
+ return false;
+ }
+
+ // Only apply the policy below if the library file is one that can
+ // be found by the linker.
+ std::string file = cmSystemTools::GetFilenameName(item);
+ if (!this->ExtractAnyLibraryName.find(file)) {
+ return false;
+ }
+
+ // Check the policy for whether we should use the approach below.
+ switch (this->Target->GetPolicyStatusCMP0060()) {
+ case cmPolicies::WARN:
+ if (this->CMP0060Warn) {
+ // Print the warning at most once for this item.
+ std::string const& wid = "CMP0060-WARNING-GIVEN-" + item;
+ if (!this->CMakeInstance->GetPropertyAsBool(wid)) {
+ this->CMakeInstance->SetProperty(wid, "1");
+ this->CMP0060WarnItems.insert(item);
+ }
+ }
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ return false;
+ }
+
+ // Many system linkers support multiple architectures by
+ // automatically selecting the implicit linker search path for the
+ // current architecture. If the library appears in an implicit link
+ // directory then just report the file name without the directory
+ // portion. This will allow the system linker to locate the proper
+ // library for the architecture at link time.
+ this->AddUserItem(file, false);
+
+ // Make sure the link directory ordering will find the library.
+ this->OrderLinkerSearchPath->AddLinkLibrary(item);
+
+ return true;
+}
+
+void cmComputeLinkInformation::AddUserItem(std::string const& item,
+ bool pathNotKnown)
+{
+ // This is called to handle a link item that does not match a CMake
+ // target and is not a full path. We check here if it looks like a
+ // library file name to automatically request the proper link type
+ // from the linker. For example:
+ //
+ // foo ==> -lfoo
+ // libfoo.a ==> -Wl,-Bstatic -lfoo
+
+ // Pass flags through untouched.
+ if (item[0] == '-' || item[0] == '$' || item[0] == '`') {
+ // if this is a -l option then we might need to warn about
+ // CMP0003 so put it in OldUserFlagItems, if it is not a -l
+ // or -Wl,-l (-framework -pthread), then allow it without a
+ // CMP0003 as -L will not affect those other linker flags
+ if (item.find("-l") == 0 || item.find("-Wl,-l") == 0) {
+ // This is a linker option provided by the user.
+ this->OldUserFlagItems.push_back(item);
+ }
+
+ // Restore the target link type since this item does not specify
+ // one.
+ this->SetCurrentLinkType(this->StartLinkType);
+
+ // Use the item verbatim.
+ this->Items.push_back(Item(item, false));
+ return;
+ }
+
+ // Parse out the prefix, base, and suffix components of the
+ // library name. If the name matches that of a shared or static
+ // library then set the link type accordingly.
+ //
+ // Search for shared library names first because some platforms
+ // have shared libraries with names that match the static library
+ // pattern. For example cygwin and msys use the convention
+ // libfoo.dll.a for import libraries and libfoo.a for static
+ // libraries. On AIX a library with the name libfoo.a can be
+ // shared!
+ std::string lib;
+ if (this->ExtractSharedLibraryName.find(item)) {
+// This matches a shared library file name.
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "shared regex matched [%s] [%s] [%s]\n",
+ this->ExtractSharedLibraryName.match(1).c_str(),
+ this->ExtractSharedLibraryName.match(2).c_str(),
+ this->ExtractSharedLibraryName.match(3).c_str());
+#endif
+ // Set the link type to shared.
+ this->SetCurrentLinkType(LinkShared);
+
+ // Use just the library name so the linker will search.
+ lib = this->ExtractSharedLibraryName.match(2);
+ } else if (this->ExtractStaticLibraryName.find(item)) {
+// This matches a static library file name.
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "static regex matched [%s] [%s] [%s]\n",
+ this->ExtractStaticLibraryName.match(1).c_str(),
+ this->ExtractStaticLibraryName.match(2).c_str(),
+ this->ExtractStaticLibraryName.match(3).c_str());
+#endif
+ // Set the link type to static.
+ this->SetCurrentLinkType(LinkStatic);
+
+ // Use just the library name so the linker will search.
+ lib = this->ExtractStaticLibraryName.match(2);
+ } else if (this->ExtractAnyLibraryName.find(item)) {
+// This matches a library file name.
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "any regex matched [%s] [%s] [%s]\n",
+ this->ExtractAnyLibraryName.match(1).c_str(),
+ this->ExtractAnyLibraryName.match(2).c_str(),
+ this->ExtractAnyLibraryName.match(3).c_str());
+#endif
+ // Restore the target link type since this item does not specify
+ // one.
+ this->SetCurrentLinkType(this->StartLinkType);
+
+ // Use just the library name so the linker will search.
+ lib = this->ExtractAnyLibraryName.match(2);
+ } else {
+ // This is a name specified by the user.
+ if (pathNotKnown) {
+ this->OldUserFlagItems.push_back(item);
+ }
+
+ // We must ask the linker to search for a library with this name.
+ // Restore the target link type since this item does not specify
+ // one.
+ this->SetCurrentLinkType(this->StartLinkType);
+ lib = item;
+ }
+
+ // Create an option to ask the linker to search for the library.
+ std::string out = this->LibLinkFlag;
+ out += lib;
+ out += this->LibLinkSuffix;
+ this->Items.push_back(Item(out, false));
+
+ // Here we could try to find the library the linker will find and
+ // add a runtime information entry for it. It would probably not be
+ // reliable and we want to encourage use of full paths for library
+ // specification.
+}
+
+void cmComputeLinkInformation::AddFrameworkItem(std::string const& item)
+{
+ // Try to separate the framework name and path.
+ if (!this->SplitFramework.find(item.c_str())) {
+ std::ostringstream e;
+ e << "Could not parse framework path \"" << item << "\" "
+ << "linked by target " << this->Target->GetName() << ".";
+ cmSystemTools::Error(e.str().c_str());
+ return;
+ }
+
+ std::string fw_path = this->SplitFramework.match(1);
+ std::string fw = this->SplitFramework.match(2);
+ std::string full_fw = fw_path;
+ full_fw += "/";
+ full_fw += fw;
+ full_fw += ".framework";
+ full_fw += "/";
+ full_fw += fw;
+
+ // Add the directory portion to the framework search path.
+ this->AddFrameworkPath(fw_path);
+
+ // add runtime information
+ this->AddLibraryRuntimeInfo(full_fw);
+
+ // Add the item using the -framework option.
+ this->Items.push_back(Item("-framework", false));
+ cmOutputConverter converter(this->Makefile->GetStateSnapshot());
+ fw = converter.EscapeForShell(fw);
+ this->Items.push_back(Item(fw, false));
+}
+
+void cmComputeLinkInformation::AddDirectoryItem(std::string const& item)
+{
+ if (this->Makefile->IsOn("APPLE") &&
+ cmSystemTools::IsPathToFramework(item.c_str())) {
+ this->AddFrameworkItem(item);
+ } else {
+ this->DropDirectoryItem(item);
+ }
+}
+
+void cmComputeLinkInformation::DropDirectoryItem(std::string const& item)
+{
+ // A full path to a directory was found as a link item. Warn the
+ // user.
+ std::ostringstream e;
+ e << "WARNING: Target \"" << this->Target->GetName()
+ << "\" requests linking to directory \"" << item << "\". "
+ << "Targets may link only to libraries. "
+ << "CMake is dropping the item.";
+ cmSystemTools::Message(e.str().c_str());
+}
+
+void cmComputeLinkInformation::ComputeFrameworkInfo()
+{
+ // Avoid adding implicit framework paths.
+ std::vector<std::string> implicitDirVec;
+
+ // Get platform-wide implicit directories.
+ if (const char* implicitLinks = this->Makefile->GetDefinition(
+ "CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES")) {
+ cmSystemTools::ExpandListArgument(implicitLinks, implicitDirVec);
+ }
+
+ // Get language-specific implicit directories.
+ std::string implicitDirVar = "CMAKE_";
+ implicitDirVar += this->LinkLanguage;
+ implicitDirVar += "_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES";
+ if (const char* implicitDirs =
+ this->Makefile->GetDefinition(implicitDirVar)) {
+ cmSystemTools::ExpandListArgument(implicitDirs, implicitDirVec);
+ }
+
+ this->FrameworkPathsEmmitted.insert(implicitDirVec.begin(),
+ implicitDirVec.end());
+
+ // Regular expression to extract a framework path and name.
+ this->SplitFramework.compile("(.*)/(.*)\\.framework$");
+}
+
+void cmComputeLinkInformation::AddFrameworkPath(std::string const& p)
+{
+ if (this->FrameworkPathsEmmitted.insert(p).second) {
+ this->FrameworkPaths.push_back(p);
+ }
+}
+
+bool cmComputeLinkInformation::CheckSharedLibNoSOName(std::string const& item)
+{
+ // This platform will use the path to a library as its soname if the
+ // library is given via path and was not built with an soname. If
+ // this is a shared library that might be the case.
+ std::string file = cmSystemTools::GetFilenameName(item);
+ if (this->ExtractSharedLibraryName.find(file)) {
+ // If we can guess the soname fairly reliably then assume the
+ // library has one. Otherwise assume the library has no builtin
+ // soname.
+ std::string soname;
+ if (!cmSystemTools::GuessLibrarySOName(item, soname)) {
+ this->AddSharedLibNoSOName(item);
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmComputeLinkInformation::AddSharedLibNoSOName(std::string const& item)
+{
+ // We have a full path to a shared library with no soname. We need
+ // to ask the linker to locate the item because otherwise the path
+ // we give to it will be embedded in the target linked. Then at
+ // runtime the dynamic linker will search for the library using the
+ // path instead of just the name.
+ std::string file = cmSystemTools::GetFilenameName(item);
+ this->AddUserItem(file, false);
+
+ // Make sure the link directory ordering will find the library.
+ this->OrderLinkerSearchPath->AddLinkLibrary(item);
+}
+
+void cmComputeLinkInformation::HandleBadFullItem(std::string const& item,
+ std::string const& file)
+{
+ // Do not depend on things that do not exist.
+ std::vector<std::string>::iterator i =
+ std::find(this->Depends.begin(), this->Depends.end(), item);
+ if (i != this->Depends.end()) {
+ this->Depends.erase(i);
+ }
+
+ // Tell the linker to search for the item and provide the proper
+ // path for it. Do not contribute to any CMP0003 warning (do not
+ // put in OldLinkDirItems or OldUserFlagItems).
+ this->AddUserItem(file, false);
+ this->OrderLinkerSearchPath->AddLinkLibrary(item);
+
+ // Produce any needed message.
+ switch (this->Target->GetPolicyStatusCMP0008()) {
+ case cmPolicies::WARN: {
+ // Print the warning at most once for this item.
+ std::string wid = "CMP0008-WARNING-GIVEN-";
+ wid += item;
+ if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(wid)) {
+ this->CMakeInstance->GetState()->SetGlobalProperty(wid, "1");
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0008) << "\n"
+ << "Target \"" << this->Target->GetName() << "\" links to item\n"
+ << " " << item << "\n"
+ << "which is a full-path but not a valid library file name.";
+ /* clang-format on */
+ this->CMakeInstance->IssueMessage(cmake::AUTHOR_WARNING, w.str(),
+ this->Target->GetBacktrace());
+ }
+ }
+ case cmPolicies::OLD:
+ // OLD behavior does not warn.
+ break;
+ case cmPolicies::NEW:
+ // NEW behavior will not get here.
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS: {
+ std::ostringstream e;
+ /* clang-format off */
+ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0008) << "\n"
+ << "Target \"" << this->Target->GetName() << "\" links to item\n"
+ << " " << item << "\n"
+ << "which is a full-path but not a valid library file name.";
+ /* clang-format on */
+ this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR, e.str(),
+ this->Target->GetBacktrace());
+ } break;
+ }
+}
+
+bool cmComputeLinkInformation::FinishLinkerSearchDirectories()
+{
+ // Support broken projects if necessary.
+ if (this->OldLinkDirItems.empty() || this->OldUserFlagItems.empty() ||
+ !this->OldLinkDirMode) {
+ return true;
+ }
+
+ // Enforce policy constraints.
+ switch (this->Target->GetPolicyStatusCMP0003()) {
+ case cmPolicies::WARN:
+ if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
+ "CMP0003-WARNING-GIVEN")) {
+ this->CMakeInstance->GetState()->SetGlobalProperty(
+ "CMP0003-WARNING-GIVEN", "1");
+ std::ostringstream w;
+ this->PrintLinkPolicyDiagnosis(w);
+ this->CMakeInstance->IssueMessage(cmake::AUTHOR_WARNING, w.str(),
+ this->Target->GetBacktrace());
+ }
+ case cmPolicies::OLD:
+ // OLD behavior is to add the paths containing libraries with
+ // known full paths as link directories.
+ break;
+ case cmPolicies::NEW:
+ // Should never happen due to assignment of OldLinkDirMode
+ return true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS: {
+ std::ostringstream e;
+ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0003) << "\n";
+ this->PrintLinkPolicyDiagnosis(e);
+ this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR, e.str(),
+ this->Target->GetBacktrace());
+ return false;
+ }
+ }
+
+ // Add the link directories for full path items.
+ for (std::vector<std::string>::const_iterator i =
+ this->OldLinkDirItems.begin();
+ i != this->OldLinkDirItems.end(); ++i) {
+ this->OrderLinkerSearchPath->AddLinkLibrary(*i);
+ }
+ return true;
+}
+
+void cmComputeLinkInformation::PrintLinkPolicyDiagnosis(std::ostream& os)
+{
+ // Tell the user what to do.
+ /* clang-format off */
+ os << "Policy CMP0003 should be set before this line. "
+ << "Add code such as\n"
+ << " if(COMMAND cmake_policy)\n"
+ << " cmake_policy(SET CMP0003 NEW)\n"
+ << " endif(COMMAND cmake_policy)\n"
+ << "as early as possible but after the most recent call to "
+ << "cmake_minimum_required or cmake_policy(VERSION). ";
+ /* clang-format on */
+
+ // List the items that might need the old-style paths.
+ os << "This warning appears because target \"" << this->Target->GetName()
+ << "\" "
+ << "links to some libraries for which the linker must search:\n";
+ {
+ // Format the list of unknown items to be as short as possible while
+ // still fitting in the allowed width (a true solution would be the
+ // bin packing problem if we were allowed to change the order).
+ std::string::size_type max_size = 76;
+ std::string line;
+ const char* sep = " ";
+ for (std::vector<std::string>::const_iterator i =
+ this->OldUserFlagItems.begin();
+ i != this->OldUserFlagItems.end(); ++i) {
+ // If the addition of another item will exceed the limit then
+ // output the current line and reset it. Note that the separator
+ // is either " " or ", " which is always 2 characters.
+ if (!line.empty() && (line.size() + i->size() + 2) > max_size) {
+ os << line << "\n";
+ sep = " ";
+ line = "";
+ }
+ line += sep;
+ line += *i;
+ // Convert to the other separator.
+ sep = ", ";
+ }
+ if (!line.empty()) {
+ os << line << "\n";
+ }
+ }
+
+ // List the paths old behavior is adding.
+ os << "and other libraries with known full path:\n";
+ std::set<std::string> emitted;
+ for (std::vector<std::string>::const_iterator i =
+ this->OldLinkDirItems.begin();
+ i != this->OldLinkDirItems.end(); ++i) {
+ if (emitted.insert(cmSystemTools::GetFilenamePath(*i)).second) {
+ os << " " << *i << "\n";
+ }
+ }
+
+ // Explain.
+ os << "CMake is adding directories in the second list to the linker "
+ << "search path in case they are needed to find libraries from the "
+ << "first list (for backwards compatibility with CMake 2.4). "
+ << "Set policy CMP0003 to OLD or NEW to enable or disable this "
+ << "behavior explicitly. "
+ << "Run \"cmake --help-policy CMP0003\" for more information.";
+}
+
+void cmComputeLinkInformation::LoadImplicitLinkInfo()
+{
+ std::vector<std::string> implicitDirVec;
+
+ // Get platform-wide implicit directories.
+ if (const char* implicitLinks = (this->Makefile->GetDefinition(
+ "CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES"))) {
+ cmSystemTools::ExpandListArgument(implicitLinks, implicitDirVec);
+ }
+
+ // Append library architecture to all implicit platform directories
+ // and add them to the set
+ if (const char* libraryArch =
+ this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) {
+ for (std::vector<std::string>::const_iterator i = implicitDirVec.begin();
+ i != implicitDirVec.end(); ++i) {
+ this->ImplicitLinkDirs.insert(*i + "/" + libraryArch);
+ }
+ }
+
+ // Get language-specific implicit directories.
+ std::string implicitDirVar = "CMAKE_";
+ implicitDirVar += this->LinkLanguage;
+ implicitDirVar += "_IMPLICIT_LINK_DIRECTORIES";
+ if (const char* implicitDirs =
+ this->Makefile->GetDefinition(implicitDirVar)) {
+ cmSystemTools::ExpandListArgument(implicitDirs, implicitDirVec);
+ }
+
+ // Store implicit link directories.
+ this->ImplicitLinkDirs.insert(implicitDirVec.begin(), implicitDirVec.end());
+
+ // Get language-specific implicit libraries.
+ std::vector<std::string> implicitLibVec;
+ std::string implicitLibVar = "CMAKE_";
+ implicitLibVar += this->LinkLanguage;
+ implicitLibVar += "_IMPLICIT_LINK_LIBRARIES";
+ if (const char* implicitLibs =
+ this->Makefile->GetDefinition(implicitLibVar)) {
+ cmSystemTools::ExpandListArgument(implicitLibs, implicitLibVec);
+ }
+
+ // Store implicit link libraries.
+ for (std::vector<std::string>::const_iterator i = implicitLibVec.begin();
+ i != implicitLibVec.end(); ++i) {
+ // Items starting in '-' but not '-l' are flags, not libraries,
+ // and should not be filtered by this implicit list.
+ std::string const& item = *i;
+ if (item[0] != '-' || item[1] == 'l') {
+ this->ImplicitLinkLibs.insert(item);
+ }
+ }
+
+ // Get platform specific rpath link directories
+ if (const char* rpathDirs =
+ (this->Makefile->GetDefinition("CMAKE_PLATFORM_RUNTIME_PATH"))) {
+ cmSystemTools::ExpandListArgument(rpathDirs, this->RuntimeLinkDirs);
+ }
+}
+
+std::vector<std::string> const&
+cmComputeLinkInformation::GetRuntimeSearchPath()
+{
+ return this->OrderRuntimeSearchPath->GetOrderedDirectories();
+}
+
+void cmComputeLinkInformation::AddLibraryRuntimeInfo(
+ std::string const& fullPath, cmGeneratorTarget const* target)
+{
+ // Ignore targets on Apple where install_name is not @rpath.
+ // The dependenty library can be found with other means such as
+ // @loader_path or full paths.
+ if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ if (!target->HasMacOSXRpathInstallNameDir(this->Config)) {
+ return;
+ }
+ }
+
+ // Libraries with unknown type must be handled using just the file
+ // on disk.
+ if (target->GetType() == cmState::UNKNOWN_LIBRARY) {
+ this->AddLibraryRuntimeInfo(fullPath);
+ return;
+ }
+
+ // Skip targets that are not shared libraries (modules cannot be linked).
+ if (target->GetType() != cmState::SHARED_LIBRARY) {
+ return;
+ }
+
+ // Try to get the soname of the library. Only files with this name
+ // could possibly conflict.
+ std::string soName = target->GetSOName(this->Config);
+ const char* soname = soName.empty() ? CM_NULLPTR : soName.c_str();
+
+ // Include this library in the runtime path ordering.
+ this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath, soname);
+ if (this->LinkWithRuntimePath) {
+ this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath, soname);
+ }
+}
+
+void cmComputeLinkInformation::AddLibraryRuntimeInfo(
+ std::string const& fullPath)
+{
+ // Get the name of the library from the file name.
+ bool is_shared_library = false;
+ std::string file = cmSystemTools::GetFilenameName(fullPath);
+
+ if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ // Check that @rpath is part of the install name.
+ // If it isn't, return.
+ std::string soname;
+ if (!cmSystemTools::GuessLibraryInstallName(fullPath, soname)) {
+ return;
+ }
+
+ if (soname.find("@rpath") == std::string::npos) {
+ return;
+ }
+ }
+
+ is_shared_library = this->ExtractSharedLibraryName.find(file);
+
+ if (!is_shared_library) {
+ // On some platforms (AIX) a shared library may look static.
+ if (this->ArchivesMayBeShared) {
+ if (this->ExtractStaticLibraryName.find(file.c_str())) {
+ // This is the name of a shared library or archive.
+ is_shared_library = true;
+ }
+ }
+ }
+
+ // It could be an Apple framework
+ if (!is_shared_library) {
+ if (fullPath.find(".framework") != std::string::npos) {
+ static cmsys::RegularExpression splitFramework(
+ "^(.*)/(.*).framework/(.*)$");
+ if (splitFramework.find(fullPath) &&
+ (std::string::npos !=
+ splitFramework.match(3).find(splitFramework.match(2)))) {
+ is_shared_library = true;
+ }
+ }
+ }
+
+ if (!is_shared_library) {
+ return;
+ }
+
+ // Include this library in the runtime path ordering.
+ this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath);
+ if (this->LinkWithRuntimePath) {
+ this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath);
+ }
+}
+
+static void cmCLI_ExpandListUnique(const char* str,
+ std::vector<std::string>& out,
+ std::set<std::string>& emitted)
+{
+ std::vector<std::string> tmp;
+ cmSystemTools::ExpandListArgument(str, tmp);
+ for (std::vector<std::string>::iterator i = tmp.begin(); i != tmp.end();
+ ++i) {
+ if (emitted.insert(*i).second) {
+ out.push_back(*i);
+ }
+ }
+}
+
+void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
+ bool for_install)
+{
+ // Select whether to generate runtime search directories.
+ bool outputRuntime =
+ !this->Makefile->IsOn("CMAKE_SKIP_RPATH") && !this->RuntimeFlag.empty();
+
+ // Select whether to generate an rpath for the install tree or the
+ // build tree.
+ bool linking_for_install =
+ (for_install ||
+ this->Target->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"));
+ bool use_install_rpath =
+ (outputRuntime && this->Target->HaveInstallTreeRPATH() &&
+ linking_for_install);
+ bool use_build_rpath =
+ (outputRuntime && this->Target->HaveBuildTreeRPATH(this->Config) &&
+ !linking_for_install);
+ bool use_link_rpath = outputRuntime && linking_for_install &&
+ !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH") &&
+ this->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH");
+
+ // Construct the RPATH.
+ std::set<std::string> emitted;
+ if (use_install_rpath) {
+ const char* install_rpath = this->Target->GetProperty("INSTALL_RPATH");
+ cmCLI_ExpandListUnique(install_rpath, runtimeDirs, emitted);
+ }
+ if (use_build_rpath || use_link_rpath) {
+ std::string rootPath = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
+ const char* stagePath =
+ this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
+ const char* installPrefix =
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
+ cmSystemTools::ConvertToUnixSlashes(rootPath);
+ std::vector<std::string> const& rdirs = this->GetRuntimeSearchPath();
+ for (std::vector<std::string>::const_iterator ri = rdirs.begin();
+ ri != rdirs.end(); ++ri) {
+ // Put this directory in the rpath if using build-tree rpath
+ // support or if using the link path as an rpath.
+ if (use_build_rpath) {
+ std::string d = *ri;
+ if (!rootPath.empty() && d.find(rootPath) == 0) {
+ d = d.substr(rootPath.size());
+ } else if (stagePath && *stagePath && d.find(stagePath) == 0) {
+ std::string suffix = d.substr(strlen(stagePath));
+ d = installPrefix;
+ d += "/";
+ d += suffix;
+ cmSystemTools::ConvertToUnixSlashes(d);
+ }
+ if (emitted.insert(d).second) {
+ runtimeDirs.push_back(d);
+ }
+ } else if (use_link_rpath) {
+ // Do not add any path inside the source or build tree.
+ const char* topSourceDir = this->CMakeInstance->GetHomeDirectory();
+ const char* topBinaryDir =
+ this->CMakeInstance->GetHomeOutputDirectory();
+ if (!cmSystemTools::ComparePath(*ri, topSourceDir) &&
+ !cmSystemTools::ComparePath(*ri, topBinaryDir) &&
+ !cmSystemTools::IsSubDirectory(*ri, topSourceDir) &&
+ !cmSystemTools::IsSubDirectory(*ri, topBinaryDir)) {
+ std::string d = *ri;
+ if (!rootPath.empty() && d.find(rootPath) == 0) {
+ d = d.substr(rootPath.size());
+ } else if (stagePath && *stagePath && d.find(stagePath) == 0) {
+ std::string suffix = d.substr(strlen(stagePath));
+ d = installPrefix;
+ d += "/";
+ d += suffix;
+ cmSystemTools::ConvertToUnixSlashes(d);
+ }
+ if (emitted.insert(d).second) {
+ runtimeDirs.push_back(d);
+ }
+ }
+ }
+ }
+ }
+
+ // Add runtime paths required by the languages to always be
+ // present. This is done even when skipping rpath support.
+ {
+ cmGeneratorTarget::LinkClosure const* lc =
+ this->Target->GetLinkClosure(this->Config);
+ for (std::vector<std::string>::const_iterator li = lc->Languages.begin();
+ li != lc->Languages.end(); ++li) {
+ std::string useVar =
+ "CMAKE_" + *li + "_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH";
+ if (this->Makefile->IsOn(useVar)) {
+ std::string dirVar = "CMAKE_" + *li + "_IMPLICIT_LINK_DIRECTORIES";
+ if (const char* dirs = this->Makefile->GetDefinition(dirVar)) {
+ cmCLI_ExpandListUnique(dirs, runtimeDirs, emitted);
+ }
+ }
+ }
+ }
+
+ // Add runtime paths required by the platform to always be
+ // present. This is done even when skipping rpath support.
+ cmCLI_ExpandListUnique(this->RuntimeAlways.c_str(), runtimeDirs, emitted);
+}
+
+std::string cmComputeLinkInformation::GetRPathString(bool for_install)
+{
+ // Get the directories to use.
+ std::vector<std::string> runtimeDirs;
+ this->GetRPath(runtimeDirs, for_install);
+
+ // Concatenate the paths.
+ std::string rpath = cmJoin(runtimeDirs, this->GetRuntimeSep());
+
+ // If the rpath will be replaced at install time, prepare space.
+ if (!for_install && this->RuntimeUseChrpath) {
+ if (!rpath.empty()) {
+ // Add one trailing separator so the linker does not re-use the
+ // rpath .dynstr entry for a symbol name that happens to match
+ // the end of the rpath string.
+ rpath += this->GetRuntimeSep();
+ }
+
+ // Make sure it is long enough to hold the replacement value.
+ std::string::size_type minLength = this->GetChrpathString().length();
+ while (rpath.length() < minLength) {
+ rpath += this->GetRuntimeSep();
+ }
+ }
+
+ return rpath;
+}
+
+std::string cmComputeLinkInformation::GetChrpathString()
+{
+ if (!this->RuntimeUseChrpath) {
+ return "";
+ }
+
+ return this->GetRPathString(true);
+}
diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h
new file mode 100644
index 0000000..023c781
--- /dev/null
+++ b/Source/cmComputeLinkInformation.h
@@ -0,0 +1,209 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmComputeLinkInformation_h
+#define cmComputeLinkInformation_h
+
+#include "cmStandardIncludes.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+class cmake;
+class cmGlobalGenerator;
+class cmMakefile;
+class cmGeneratorTarget;
+class cmOrderDirectories;
+
+/** \class cmComputeLinkInformation
+ * \brief Compute link information for a target in one configuration.
+ */
+class cmComputeLinkInformation
+{
+public:
+ cmComputeLinkInformation(cmGeneratorTarget const* target,
+ const std::string& config);
+ ~cmComputeLinkInformation();
+ bool Compute();
+
+ struct Item
+ {
+ Item()
+ : Value()
+ , IsPath(true)
+ , Target(CM_NULLPTR)
+ {
+ }
+ Item(Item const& item)
+ : Value(item.Value)
+ , IsPath(item.IsPath)
+ , Target(item.Target)
+ {
+ }
+ Item(std::string const& v, bool p,
+ cmGeneratorTarget const* target = CM_NULLPTR)
+ : Value(v)
+ , IsPath(p)
+ , Target(target)
+ {
+ }
+ std::string Value;
+ bool IsPath;
+ cmGeneratorTarget const* Target;
+ };
+ typedef std::vector<Item> ItemVector;
+ ItemVector const& GetItems();
+ std::vector<std::string> const& GetDirectories();
+ std::vector<std::string> const& GetDepends();
+ std::vector<std::string> const& GetFrameworkPaths();
+ std::string GetLinkLanguage() const { return this->LinkLanguage; }
+ std::vector<std::string> const& GetRuntimeSearchPath();
+ std::string const& GetRuntimeFlag() const { return this->RuntimeFlag; }
+ std::string const& GetRuntimeSep() const { return this->RuntimeSep; }
+ void GetRPath(std::vector<std::string>& runtimeDirs, bool for_install);
+ std::string GetRPathString(bool for_install);
+ std::string GetChrpathString();
+ std::set<cmGeneratorTarget const*> const& GetSharedLibrariesLinked();
+
+ std::string const& GetRPathLinkFlag() const { return this->RPathLinkFlag; }
+ std::string GetRPathLinkString();
+
+private:
+ void AddItem(std::string const& item, const cmGeneratorTarget* tgt);
+ void AddSharedDepItem(std::string const& item, cmGeneratorTarget const* tgt);
+
+ // Output information.
+ ItemVector Items;
+ std::vector<std::string> Directories;
+ std::vector<std::string> Depends;
+ std::vector<std::string> FrameworkPaths;
+ std::vector<std::string> RuntimeSearchPath;
+ std::set<cmGeneratorTarget const*> SharedLibrariesLinked;
+
+ // Context information.
+ cmGeneratorTarget const* Target;
+ cmMakefile* Makefile;
+ cmGlobalGenerator* GlobalGenerator;
+ cmake* CMakeInstance;
+
+ // Configuration information.
+ std::string Config;
+ std::string LinkLanguage;
+
+ // Modes for dealing with dependent shared libraries.
+ enum SharedDepMode
+ {
+ SharedDepModeNone, // Drop
+ SharedDepModeDir, // List dir in -rpath-link flag
+ SharedDepModeLibDir, // List dir in linker search path
+ SharedDepModeLink // List file on link line
+ };
+
+ const char* LoaderFlag;
+ std::string LibLinkFlag;
+ std::string LibLinkFileFlag;
+ std::string LibLinkSuffix;
+ std::string RuntimeFlag;
+ std::string RuntimeSep;
+ std::string RuntimeAlways;
+ std::string RPathLinkFlag;
+ SharedDepMode SharedDependencyMode;
+
+ enum LinkType
+ {
+ LinkUnknown,
+ LinkStatic,
+ LinkShared
+ };
+ void SetCurrentLinkType(LinkType lt);
+
+ // Link type adjustment.
+ void ComputeLinkTypeInfo();
+ LinkType StartLinkType;
+ LinkType CurrentLinkType;
+ std::string StaticLinkTypeFlag;
+ std::string SharedLinkTypeFlag;
+
+ // Link item parsing.
+ void ComputeItemParserInfo();
+ std::vector<std::string> StaticLinkExtensions;
+ std::vector<std::string> SharedLinkExtensions;
+ std::vector<std::string> LinkExtensions;
+ std::set<std::string> LinkPrefixes;
+ cmsys::RegularExpression ExtractStaticLibraryName;
+ cmsys::RegularExpression ExtractSharedLibraryName;
+ cmsys::RegularExpression ExtractAnyLibraryName;
+ std::string SharedRegexString;
+ void AddLinkPrefix(const char* p);
+ void AddLinkExtension(const char* e, LinkType type);
+ std::string CreateExtensionRegex(std::vector<std::string> const& exts,
+ LinkType type);
+ std::string NoCaseExpression(const char* str);
+
+ // Handling of link items.
+ void AddTargetItem(std::string const& item, const cmGeneratorTarget* target);
+ void AddFullItem(std::string const& item);
+ bool CheckImplicitDirItem(std::string const& item);
+ void AddUserItem(std::string const& item, bool pathNotKnown);
+ void AddDirectoryItem(std::string const& item);
+ void AddFrameworkItem(std::string const& item);
+ void DropDirectoryItem(std::string const& item);
+ bool CheckSharedLibNoSOName(std::string const& item);
+ void AddSharedLibNoSOName(std::string const& item);
+ void HandleBadFullItem(std::string const& item, std::string const& file);
+
+ // Framework info.
+ void ComputeFrameworkInfo();
+ void AddFrameworkPath(std::string const& p);
+ std::set<std::string> FrameworkPathsEmmitted;
+ cmsys::RegularExpression SplitFramework;
+
+ // Linker search path computation.
+ cmOrderDirectories* OrderLinkerSearchPath;
+ bool FinishLinkerSearchDirectories();
+ void PrintLinkPolicyDiagnosis(std::ostream&);
+
+ // Implicit link libraries and directories for linker language.
+ void LoadImplicitLinkInfo();
+ void AddImplicitLinkInfo();
+ void AddImplicitLinkInfo(std::string const& lang);
+ std::set<std::string> ImplicitLinkDirs;
+ std::set<std::string> ImplicitLinkLibs;
+
+ // Additional paths configured by the runtime linker
+ std::vector<std::string> RuntimeLinkDirs;
+
+ // Linker search path compatibility mode.
+ std::set<std::string> OldLinkDirMask;
+ std::vector<std::string> OldLinkDirItems;
+ std::vector<std::string> OldUserFlagItems;
+ std::set<std::string> CMP0060WarnItems;
+ // Dependent library path computation.
+ cmOrderDirectories* OrderDependentRPath;
+ // Runtime path computation.
+ cmOrderDirectories* OrderRuntimeSearchPath;
+
+ bool OldLinkDirMode;
+ bool OpenBSD;
+ bool LinkDependsNoShared;
+ bool UseImportLibrary;
+ bool RuntimeUseChrpath;
+ bool NoSONameUsesPath;
+ bool LinkWithRuntimePath;
+ bool LinkTypeEnabled;
+ bool ArchivesMayBeShared;
+ bool CMP0060Warn;
+
+ void AddLibraryRuntimeInfo(std::string const& fullPath,
+ const cmGeneratorTarget* target);
+ void AddLibraryRuntimeInfo(std::string const& fullPath);
+};
+
+#endif
diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx
new file mode 100644
index 0000000..ff7eb0b
--- /dev/null
+++ b/Source/cmComputeTargetDepends.cxx
@@ -0,0 +1,591 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmComputeTargetDepends.h"
+
+#include "cmComputeComponentGraph.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+#include <algorithm>
+
+#include <assert.h>
+
+/*
+
+This class is meant to analyze inter-target dependencies globally
+during the generation step. The goal is to produce a set of direct
+dependencies for each target such that no cycles are left and the
+build order is safe.
+
+For most target types cyclic dependencies are not allowed. However
+STATIC libraries may depend on each other in a cyclic fashion. In
+general the directed dependency graph forms a directed-acyclic-graph
+of strongly connected components. All strongly connected components
+should consist of only STATIC_LIBRARY targets.
+
+In order to safely break dependency cycles we must preserve all other
+dependencies passing through the corresponding strongly connected component.
+The approach taken by this class is as follows:
+
+ - Collect all targets and form the original dependency graph
+ - Run Tarjan's algorithm to extract the strongly connected components
+ (error if any member of a non-trivial component is not STATIC)
+ - The original dependencies imply a DAG on the components.
+ Use the implied DAG to construct a final safe set of dependencies.
+
+The final dependency set is constructed as follows:
+
+ - For each connected component targets are placed in an arbitrary
+ order. Each target depends on the target following it in the order.
+ The first target is designated the head and the last target the tail.
+ (most components will be just 1 target anyway)
+
+ - Original dependencies between targets in different components are
+ converted to connect the depender's component tail to the
+ dependee's component head.
+
+In most cases this will reproduce the original dependencies. However
+when there are cycles of static libraries they will be broken in a
+safe manner.
+
+For example, consider targets A0, A1, A2, B0, B1, B2, and C with these
+dependencies:
+
+ A0 -> A1 -> A2 -> A0 , B0 -> B1 -> B2 -> B0 -> A0 , C -> B0
+
+Components may be identified as
+
+ Component 0: A0, A1, A2
+ Component 1: B0, B1, B2
+ Component 2: C
+
+Intra-component dependencies are:
+
+ 0: A0 -> A1 -> A2 , head=A0, tail=A2
+ 1: B0 -> B1 -> B2 , head=B0, tail=B2
+ 2: head=C, tail=C
+
+The inter-component dependencies are converted as:
+
+ B0 -> A0 is component 1->0 and becomes B2 -> A0
+ C -> B0 is component 2->1 and becomes C -> B0
+
+This leads to the final target dependencies:
+
+ C -> B0 -> B1 -> B2 -> A0 -> A1 -> A2
+
+These produce a safe build order since C depends directly or
+transitively on all the static libraries it links.
+
+*/
+
+cmComputeTargetDepends::cmComputeTargetDepends(cmGlobalGenerator* gg)
+{
+ this->GlobalGenerator = gg;
+ cmake* cm = this->GlobalGenerator->GetCMakeInstance();
+ this->DebugMode =
+ cm->GetState()->GetGlobalPropertyAsBool("GLOBAL_DEPENDS_DEBUG_MODE");
+ this->NoCycles =
+ cm->GetState()->GetGlobalPropertyAsBool("GLOBAL_DEPENDS_NO_CYCLES");
+}
+
+cmComputeTargetDepends::~cmComputeTargetDepends()
+{
+}
+
+bool cmComputeTargetDepends::Compute()
+{
+ // Build the original graph.
+ this->CollectTargets();
+ this->CollectDepends();
+ if (this->DebugMode) {
+ this->DisplayGraph(this->InitialGraph, "initial");
+ }
+
+ // Identify components.
+ cmComputeComponentGraph ccg(this->InitialGraph);
+ if (this->DebugMode) {
+ this->DisplayComponents(ccg);
+ }
+ if (!this->CheckComponents(ccg)) {
+ return false;
+ }
+
+ // Compute the final dependency graph.
+ if (!this->ComputeFinalDepends(ccg)) {
+ return false;
+ }
+ if (this->DebugMode) {
+ this->DisplayGraph(this->FinalGraph, "final");
+ }
+
+ return true;
+}
+
+void cmComputeTargetDepends::GetTargetDirectDepends(cmGeneratorTarget const* t,
+ cmTargetDependSet& deps)
+{
+ // Lookup the index for this target. All targets should be known by
+ // this point.
+ std::map<cmGeneratorTarget const*, int>::const_iterator tii =
+ this->TargetIndex.find(t);
+ assert(tii != this->TargetIndex.end());
+ int i = tii->second;
+
+ // Get its final dependencies.
+ EdgeList const& nl = this->FinalGraph[i];
+ for (EdgeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni) {
+ cmGeneratorTarget const* dep = this->Targets[*ni];
+ cmTargetDependSet::iterator di = deps.insert(dep).first;
+ di->SetType(ni->IsStrong());
+ }
+}
+
+void cmComputeTargetDepends::CollectTargets()
+{
+ // Collect all targets from all generators.
+ std::vector<cmLocalGenerator*> const& lgens =
+ this->GlobalGenerator->GetLocalGenerators();
+ for (unsigned int i = 0; i < lgens.size(); ++i) {
+ const std::vector<cmGeneratorTarget*> targets =
+ lgens[i]->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::const_iterator ti = targets.begin();
+ ti != targets.end(); ++ti) {
+ cmGeneratorTarget* gt = *ti;
+ int index = static_cast<int>(this->Targets.size());
+ this->TargetIndex[gt] = index;
+ this->Targets.push_back(gt);
+ }
+ }
+}
+
+void cmComputeTargetDepends::CollectDepends()
+{
+ // Allocate the dependency graph adjacency lists.
+ this->InitialGraph.resize(this->Targets.size());
+
+ // Compute each dependency list.
+ for (unsigned int i = 0; i < this->Targets.size(); ++i) {
+ this->CollectTargetDepends(i);
+ }
+}
+
+void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
+{
+ // Get the depender.
+ cmGeneratorTarget const* depender = this->Targets[depender_index];
+ if (depender->GetType() == cmState::INTERFACE_LIBRARY) {
+ return;
+ }
+
+ // Loop over all targets linked directly in all configs.
+ // We need to make targets depend on the union of all config-specific
+ // dependencies in all targets, because the generated build-systems can't
+ // deal with config-specific dependencies.
+ {
+ std::set<std::string> emitted;
+
+ std::vector<std::string> configs;
+ depender->Makefile->GetConfigurations(configs);
+ if (configs.empty()) {
+ configs.push_back("");
+ }
+ for (std::vector<std::string>::const_iterator it = configs.begin();
+ it != configs.end(); ++it) {
+ std::vector<cmSourceFile const*> objectFiles;
+ depender->GetExternalObjects(objectFiles, *it);
+ for (std::vector<cmSourceFile const*>::const_iterator oi =
+ objectFiles.begin();
+ oi != objectFiles.end(); ++oi) {
+ std::string objLib = (*oi)->GetObjectLibrary();
+ if (!objLib.empty() && emitted.insert(objLib).second) {
+ if (depender->GetType() != cmState::EXECUTABLE &&
+ depender->GetType() != cmState::STATIC_LIBRARY &&
+ depender->GetType() != cmState::SHARED_LIBRARY &&
+ depender->GetType() != cmState::MODULE_LIBRARY) {
+ this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
+ cmake::FATAL_ERROR,
+ "Only executables and non-OBJECT libraries may "
+ "reference target objects.",
+ depender->GetBacktrace());
+ return;
+ }
+ const_cast<cmGeneratorTarget*>(depender)->Target->AddUtility(objLib);
+ }
+ }
+
+ cmLinkImplementation const* impl = depender->GetLinkImplementation(*it);
+
+ // A target should not depend on itself.
+ emitted.insert(depender->GetName());
+ for (std::vector<cmLinkImplItem>::const_iterator lib =
+ impl->Libraries.begin();
+ lib != impl->Libraries.end(); ++lib) {
+ // Don't emit the same library twice for this target.
+ if (emitted.insert(*lib).second) {
+ this->AddTargetDepend(depender_index, *lib, true);
+ this->AddInterfaceDepends(depender_index, *lib, emitted);
+ }
+ }
+ }
+ }
+
+ // Loop over all utility dependencies.
+ {
+ std::set<cmLinkItem> const& tutils = depender->GetUtilityItems();
+ std::set<std::string> emitted;
+ // A target should not depend on itself.
+ emitted.insert(depender->GetName());
+ for (std::set<cmLinkItem>::const_iterator util = tutils.begin();
+ util != tutils.end(); ++util) {
+ // Don't emit the same utility twice for this target.
+ if (emitted.insert(*util).second) {
+ this->AddTargetDepend(depender_index, *util, false);
+ }
+ }
+ }
+}
+
+void cmComputeTargetDepends::AddInterfaceDepends(
+ int depender_index, const cmGeneratorTarget* dependee,
+ const std::string& config, std::set<std::string>& emitted)
+{
+ cmGeneratorTarget const* depender = this->Targets[depender_index];
+ if (cmLinkInterface const* iface =
+ dependee->GetLinkInterface(config, depender)) {
+ for (std::vector<cmLinkItem>::const_iterator lib =
+ iface->Libraries.begin();
+ lib != iface->Libraries.end(); ++lib) {
+ // Don't emit the same library twice for this target.
+ if (emitted.insert(*lib).second) {
+ this->AddTargetDepend(depender_index, *lib, true);
+ this->AddInterfaceDepends(depender_index, *lib, emitted);
+ }
+ }
+ }
+}
+
+void cmComputeTargetDepends::AddInterfaceDepends(
+ int depender_index, cmLinkItem const& dependee_name,
+ std::set<std::string>& emitted)
+{
+ cmGeneratorTarget const* depender = this->Targets[depender_index];
+ cmGeneratorTarget const* dependee = dependee_name.Target;
+ // Skip targets that will not really be linked. This is probably a
+ // name conflict between an external library and an executable
+ // within the project.
+ if (dependee && dependee->GetType() == cmState::EXECUTABLE &&
+ !dependee->IsExecutableWithExports()) {
+ dependee = CM_NULLPTR;
+ }
+
+ if (dependee) {
+ this->AddInterfaceDepends(depender_index, dependee, "", emitted);
+ std::vector<std::string> configs;
+ depender->Makefile->GetConfigurations(configs);
+ for (std::vector<std::string>::const_iterator it = configs.begin();
+ it != configs.end(); ++it) {
+ // A target should not depend on itself.
+ emitted.insert(depender->GetName());
+ this->AddInterfaceDepends(depender_index, dependee, *it, emitted);
+ }
+ }
+}
+
+void cmComputeTargetDepends::AddTargetDepend(int depender_index,
+ cmLinkItem const& dependee_name,
+ bool linking)
+{
+ // Get the depender.
+ cmGeneratorTarget const* depender = this->Targets[depender_index];
+
+ // Check the target's makefile first.
+ cmGeneratorTarget const* dependee = dependee_name.Target;
+
+ if (!dependee && !linking &&
+ (depender->GetType() != cmState::GLOBAL_TARGET)) {
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ bool issueMessage = false;
+ std::ostringstream e;
+ switch (depender->GetPolicyStatusCMP0046()) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0046) << "\n";
+ issueMessage = true;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ issueMessage = true;
+ messageType = cmake::FATAL_ERROR;
+ }
+ if (issueMessage) {
+ cmake* cm = this->GlobalGenerator->GetCMakeInstance();
+
+ e << "The dependency target \"" << dependee_name << "\" of target \""
+ << depender->GetName() << "\" does not exist.";
+
+ cmListFileBacktrace const* backtrace =
+ depender->GetUtilityBacktrace(dependee_name);
+ if (backtrace) {
+ cm->IssueMessage(messageType, e.str(), *backtrace);
+ } else {
+ cm->IssueMessage(messageType, e.str());
+ }
+ }
+ }
+
+ // Skip targets that will not really be linked. This is probably a
+ // name conflict between an external library and an executable
+ // within the project.
+ if (linking && dependee && dependee->GetType() == cmState::EXECUTABLE &&
+ !dependee->IsExecutableWithExports()) {
+ dependee = CM_NULLPTR;
+ }
+
+ if (dependee) {
+ this->AddTargetDepend(depender_index, dependee, linking);
+ }
+}
+
+void cmComputeTargetDepends::AddTargetDepend(int depender_index,
+ const cmGeneratorTarget* dependee,
+ bool linking)
+{
+ if (dependee->IsImported() ||
+ dependee->GetType() == cmState::INTERFACE_LIBRARY) {
+ // Skip IMPORTED and INTERFACE targets but follow their utility
+ // dependencies.
+ std::set<cmLinkItem> const& utils = dependee->GetUtilityItems();
+ for (std::set<cmLinkItem>::const_iterator i = utils.begin();
+ i != utils.end(); ++i) {
+ if (cmGeneratorTarget const* transitive_dependee = i->Target) {
+ this->AddTargetDepend(depender_index, transitive_dependee, false);
+ }
+ }
+ } else {
+ // Lookup the index for this target. All targets should be known by
+ // this point.
+ std::map<cmGeneratorTarget const*, int>::const_iterator tii =
+ this->TargetIndex.find(dependee);
+ assert(tii != this->TargetIndex.end());
+ int dependee_index = tii->second;
+
+ // Add this entry to the dependency graph.
+ this->InitialGraph[depender_index].push_back(
+ cmGraphEdge(dependee_index, !linking));
+ }
+}
+
+void cmComputeTargetDepends::DisplayGraph(Graph const& graph,
+ const std::string& name)
+{
+ fprintf(stderr, "The %s target dependency graph is:\n", name.c_str());
+ int n = static_cast<int>(graph.size());
+ for (int depender_index = 0; depender_index < n; ++depender_index) {
+ EdgeList const& nl = graph[depender_index];
+ cmGeneratorTarget const* depender = this->Targets[depender_index];
+ fprintf(stderr, "target %d is [%s]\n", depender_index,
+ depender->GetName().c_str());
+ for (EdgeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni) {
+ int dependee_index = *ni;
+ cmGeneratorTarget const* dependee = this->Targets[dependee_index];
+ fprintf(stderr, " depends on target %d [%s] (%s)\n", dependee_index,
+ dependee->GetName().c_str(), ni->IsStrong() ? "strong" : "weak");
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+void cmComputeTargetDepends::DisplayComponents(
+ cmComputeComponentGraph const& ccg)
+{
+ fprintf(stderr, "The strongly connected components are:\n");
+ std::vector<NodeList> const& components = ccg.GetComponents();
+ int n = static_cast<int>(components.size());
+ for (int c = 0; c < n; ++c) {
+ NodeList const& nl = components[c];
+ fprintf(stderr, "Component (%d):\n", c);
+ for (NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni) {
+ int i = *ni;
+ fprintf(stderr, " contains target %d [%s]\n", i,
+ this->Targets[i]->GetName().c_str());
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+bool cmComputeTargetDepends::CheckComponents(
+ cmComputeComponentGraph const& ccg)
+{
+ // All non-trivial components should consist only of static
+ // libraries.
+ std::vector<NodeList> const& components = ccg.GetComponents();
+ int nc = static_cast<int>(components.size());
+ for (int c = 0; c < nc; ++c) {
+ // Get the current component.
+ NodeList const& nl = components[c];
+
+ // Skip trivial components.
+ if (nl.size() < 2) {
+ continue;
+ }
+
+ // Immediately complain if no cycles are allowed at all.
+ if (this->NoCycles) {
+ this->ComplainAboutBadComponent(ccg, c);
+ return false;
+ }
+
+ // Make sure the component is all STATIC_LIBRARY targets.
+ for (NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni) {
+ if (this->Targets[*ni]->GetType() != cmState::STATIC_LIBRARY) {
+ this->ComplainAboutBadComponent(ccg, c);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void cmComputeTargetDepends::ComplainAboutBadComponent(
+ cmComputeComponentGraph const& ccg, int c, bool strong)
+{
+ // Construct the error message.
+ std::ostringstream e;
+ e << "The inter-target dependency graph contains the following "
+ << "strongly connected component (cycle):\n";
+ std::vector<NodeList> const& components = ccg.GetComponents();
+ std::vector<int> const& cmap = ccg.GetComponentMap();
+ NodeList const& cl = components[c];
+ for (NodeList::const_iterator ci = cl.begin(); ci != cl.end(); ++ci) {
+ // Get the depender.
+ int i = *ci;
+ cmGeneratorTarget const* depender = this->Targets[i];
+
+ // Describe the depender.
+ e << " \"" << depender->GetName() << "\" of type "
+ << cmState::GetTargetTypeName(depender->GetType()) << "\n";
+
+ // List its dependencies that are inside the component.
+ EdgeList const& nl = this->InitialGraph[i];
+ for (EdgeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni) {
+ int j = *ni;
+ if (cmap[j] == c) {
+ cmGeneratorTarget const* dependee = this->Targets[j];
+ e << " depends on \"" << dependee->GetName() << "\""
+ << " (" << (ni->IsStrong() ? "strong" : "weak") << ")\n";
+ }
+ }
+ }
+ if (strong) {
+ // Custom command executable dependencies cannot occur within a
+ // component of static libraries. The cycle must appear in calls
+ // to add_dependencies.
+ e << "The component contains at least one cycle consisting of strong "
+ << "dependencies (created by add_dependencies) that cannot be broken.";
+ } else if (this->NoCycles) {
+ e << "The GLOBAL_DEPENDS_NO_CYCLES global property is enabled, so "
+ << "cyclic dependencies are not allowed even among static libraries.";
+ } else {
+ e << "At least one of these targets is not a STATIC_LIBRARY. "
+ << "Cyclic dependencies are allowed only among static libraries.";
+ }
+ cmSystemTools::Error(e.str().c_str());
+}
+
+bool cmComputeTargetDepends::IntraComponent(std::vector<int> const& cmap,
+ int c, int i, int* head,
+ std::set<int>& emitted,
+ std::set<int>& visited)
+{
+ if (!visited.insert(i).second) {
+ // Cycle in utility depends!
+ return false;
+ }
+ if (emitted.insert(i).second) {
+ // Honor strong intra-component edges in the final order.
+ EdgeList const& el = this->InitialGraph[i];
+ for (EdgeList::const_iterator ei = el.begin(); ei != el.end(); ++ei) {
+ int j = *ei;
+ if (cmap[j] == c && ei->IsStrong()) {
+ this->FinalGraph[i].push_back(cmGraphEdge(j, true));
+ if (!this->IntraComponent(cmap, c, j, head, emitted, visited)) {
+ return false;
+ }
+ }
+ }
+
+ // Prepend to a linear linked-list of intra-component edges.
+ if (*head >= 0) {
+ this->FinalGraph[i].push_back(cmGraphEdge(*head, false));
+ } else {
+ this->ComponentTail[c] = i;
+ }
+ *head = i;
+ }
+ return true;
+}
+
+bool cmComputeTargetDepends::ComputeFinalDepends(
+ cmComputeComponentGraph const& ccg)
+{
+ // Get the component graph information.
+ std::vector<NodeList> const& components = ccg.GetComponents();
+ Graph const& cgraph = ccg.GetComponentGraph();
+
+ // Allocate the final graph.
+ this->FinalGraph.resize(0);
+ this->FinalGraph.resize(this->InitialGraph.size());
+
+ // Choose intra-component edges to linearize dependencies.
+ std::vector<int> const& cmap = ccg.GetComponentMap();
+ this->ComponentHead.resize(components.size());
+ this->ComponentTail.resize(components.size());
+ int nc = static_cast<int>(components.size());
+ for (int c = 0; c < nc; ++c) {
+ int head = -1;
+ std::set<int> emitted;
+ NodeList const& nl = components[c];
+ for (NodeList::const_reverse_iterator ni = nl.rbegin(); ni != nl.rend();
+ ++ni) {
+ std::set<int> visited;
+ if (!this->IntraComponent(cmap, c, *ni, &head, emitted, visited)) {
+ // Cycle in add_dependencies within component!
+ this->ComplainAboutBadComponent(ccg, c, true);
+ return false;
+ }
+ }
+ this->ComponentHead[c] = head;
+ }
+
+ // Convert inter-component edges to connect component tails to heads.
+ int n = static_cast<int>(cgraph.size());
+ for (int depender_component = 0; depender_component < n;
+ ++depender_component) {
+ int depender_component_tail = this->ComponentTail[depender_component];
+ EdgeList const& nl = cgraph[depender_component];
+ for (EdgeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni) {
+ int dependee_component = *ni;
+ int dependee_component_head = this->ComponentHead[dependee_component];
+ this->FinalGraph[depender_component_tail].push_back(
+ cmGraphEdge(dependee_component_head, ni->IsStrong()));
+ }
+ }
+ return true;
+}
diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h
new file mode 100644
index 0000000..9e51d4d
--- /dev/null
+++ b/Source/cmComputeTargetDepends.h
@@ -0,0 +1,94 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmComputeTargetDepends_h
+#define cmComputeTargetDepends_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmGraphAdjacencyList.h"
+
+#include <stack>
+
+class cmComputeComponentGraph;
+class cmGlobalGenerator;
+class cmLinkItem;
+class cmGeneratorTarget;
+class cmTargetDependSet;
+
+/** \class cmComputeTargetDepends
+ * \brief Compute global interdependencies among targets.
+ *
+ * Static libraries may form cycles in the target dependency graph.
+ * This class evaluates target dependencies globally and adjusts them
+ * to remove cycles while preserving a safe build order.
+ */
+class cmComputeTargetDepends
+{
+public:
+ cmComputeTargetDepends(cmGlobalGenerator* gg);
+ ~cmComputeTargetDepends();
+
+ bool Compute();
+
+ std::vector<cmGeneratorTarget const*> const& GetTargets() const
+ {
+ return this->Targets;
+ }
+ void GetTargetDirectDepends(cmGeneratorTarget const* t,
+ cmTargetDependSet& deps);
+
+private:
+ void CollectTargets();
+ void CollectDepends();
+ void CollectTargetDepends(int depender_index);
+ void AddTargetDepend(int depender_index, cmLinkItem const& dependee_name,
+ bool linking);
+ void AddTargetDepend(int depender_index, cmGeneratorTarget const* dependee,
+ bool linking);
+ bool ComputeFinalDepends(cmComputeComponentGraph const& ccg);
+ void AddInterfaceDepends(int depender_index, cmLinkItem const& dependee_name,
+ std::set<std::string>& emitted);
+ void AddInterfaceDepends(int depender_index,
+ cmGeneratorTarget const* dependee,
+ const std::string& config,
+ std::set<std::string>& emitted);
+ cmGlobalGenerator* GlobalGenerator;
+ bool DebugMode;
+ bool NoCycles;
+
+ // Collect all targets.
+ std::vector<cmGeneratorTarget const*> Targets;
+ std::map<cmGeneratorTarget const*, int> TargetIndex;
+
+ // Represent the target dependency graph. The entry at each
+ // top-level index corresponds to a depender whose dependencies are
+ // listed.
+ typedef cmGraphNodeList NodeList;
+ typedef cmGraphEdgeList EdgeList;
+ typedef cmGraphAdjacencyList Graph;
+ Graph InitialGraph;
+ Graph FinalGraph;
+ void DisplayGraph(Graph const& graph, const std::string& name);
+
+ // Deal with connected components.
+ void DisplayComponents(cmComputeComponentGraph const& ccg);
+ bool CheckComponents(cmComputeComponentGraph const& ccg);
+ void ComplainAboutBadComponent(cmComputeComponentGraph const& ccg, int c,
+ bool strong = false);
+
+ std::vector<int> ComponentHead;
+ std::vector<int> ComponentTail;
+ bool IntraComponent(std::vector<int> const& cmap, int c, int i, int* head,
+ std::set<int>& emitted, std::set<int>& visited);
+};
+
+#endif
diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx
new file mode 100644
index 0000000..67b2571
--- /dev/null
+++ b/Source/cmConditionEvaluator.cxx
@@ -0,0 +1,727 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmConditionEvaluator.h"
+
+#include "cmAlgorithms.h"
+#include "cmOutputConverter.h"
+
+static std::string const keyAND = "AND";
+static std::string const keyCOMMAND = "COMMAND";
+static std::string const keyDEFINED = "DEFINED";
+static std::string const keyEQUAL = "EQUAL";
+static std::string const keyEXISTS = "EXISTS";
+static std::string const keyGREATER = "GREATER";
+static std::string const keyIN_LIST = "IN_LIST";
+static std::string const keyIS_ABSOLUTE = "IS_ABSOLUTE";
+static std::string const keyIS_DIRECTORY = "IS_DIRECTORY";
+static std::string const keyIS_NEWER_THAN = "IS_NEWER_THAN";
+static std::string const keyIS_SYMLINK = "IS_SYMLINK";
+static std::string const keyLESS = "LESS";
+static std::string const keyMATCHES = "MATCHES";
+static std::string const keyNOT = "NOT";
+static std::string const keyOR = "OR";
+static std::string const keyParenL = "(";
+static std::string const keyParenR = ")";
+static std::string const keyPOLICY = "POLICY";
+static std::string const keySTREQUAL = "STREQUAL";
+static std::string const keySTRGREATER = "STRGREATER";
+static std::string const keySTRLESS = "STRLESS";
+static std::string const keyTARGET = "TARGET";
+static std::string const keyTEST = "TEST";
+static std::string const keyVERSION_EQUAL = "VERSION_EQUAL";
+static std::string const keyVERSION_GREATER = "VERSION_GREATER";
+static std::string const keyVERSION_LESS = "VERSION_LESS";
+
+cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile,
+ const cmListFileContext& context,
+ const cmListFileBacktrace& bt)
+ : Makefile(makefile)
+ , ExecutionContext(context)
+ , Backtrace(bt)
+ , Policy12Status(makefile.GetPolicyStatus(cmPolicies::CMP0012))
+ , Policy54Status(makefile.GetPolicyStatus(cmPolicies::CMP0054))
+ , Policy57Status(makefile.GetPolicyStatus(cmPolicies::CMP0057))
+ , Policy64Status(makefile.GetPolicyStatus(cmPolicies::CMP0064))
+{
+}
+
+//=========================================================================
+// order of operations,
+// 1. ( ) -- parenthetical groups
+// 2. IS_DIRECTORY EXISTS COMMAND DEFINED etc predicates
+// 3. MATCHES LESS GREATER EQUAL STRLESS STRGREATER STREQUAL etc binary ops
+// 4. NOT
+// 5. AND OR
+//
+// There is an issue on whether the arguments should be values of references,
+// for example IF (FOO AND BAR) should that compare the strings FOO and BAR
+// or should it really do IF (${FOO} AND ${BAR}) Currently IS_DIRECTORY
+// EXISTS COMMAND and DEFINED all take values. EQUAL, LESS and GREATER can
+// take numeric values or variable names. STRLESS and STRGREATER take
+// variable names but if the variable name is not found it will use the name
+// directly. AND OR take variables or the values 0 or 1.
+
+bool cmConditionEvaluator::IsTrue(
+ const std::vector<cmExpandedCommandArgument>& args, std::string& errorString,
+ cmake::MessageType& status)
+{
+ errorString = "";
+
+ // handle empty invocation
+ if (args.size() < 1) {
+ return false;
+ }
+
+ // store the reduced args in this vector
+ cmArgumentList newArgs;
+
+ // copy to the list structure
+ newArgs.insert(newArgs.end(), 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
+ // parens
+ if (!this->HandleLevel0(newArgs, errorString, status)) {
+ return false;
+ }
+ // predicates
+ if (!this->HandleLevel1(newArgs, errorString, status)) {
+ return false;
+ }
+ // binary ops
+ if (!this->HandleLevel2(newArgs, errorString, status)) {
+ return false;
+ }
+
+ // NOT
+ if (!this->HandleLevel3(newArgs, errorString, status)) {
+ return false;
+ }
+ // AND OR
+ if (!this->HandleLevel4(newArgs, errorString, status)) {
+ return false;
+ }
+
+ // now at the end there should only be one argument left
+ if (newArgs.size() != 1) {
+ errorString = "Unknown arguments specified";
+ status = cmake::FATAL_ERROR;
+ return false;
+ }
+
+ return this->GetBooleanValueWithAutoDereference(*(newArgs.begin()),
+ errorString, status, true);
+}
+
+//=========================================================================
+const char* cmConditionEvaluator::GetDefinitionIfUnquoted(
+ cmExpandedCommandArgument const& argument) const
+{
+ if ((this->Policy54Status != cmPolicies::WARN &&
+ this->Policy54Status != cmPolicies::OLD) &&
+ argument.WasQuoted()) {
+ return CM_NULLPTR;
+ }
+
+ const char* def = this->Makefile.GetDefinition(argument.GetValue());
+
+ if (def && argument.WasQuoted() &&
+ this->Policy54Status == cmPolicies::WARN) {
+ if (!this->Makefile.HasCMP0054AlreadyBeenReported(
+ this->ExecutionContext)) {
+ std::ostringstream e;
+ e << (cmPolicies::GetPolicyWarning(cmPolicies::CMP0054)) << "\n";
+ e << "Quoted variables like \"" << argument.GetValue()
+ << "\" will no longer be dereferenced "
+ "when the policy is set to NEW. "
+ "Since the policy is not set the OLD behavior will be used.";
+
+ this->Makefile.GetCMakeInstance()->IssueMessage(
+ cmake::AUTHOR_WARNING, e.str(), this->Backtrace);
+ }
+ }
+
+ return def;
+}
+
+//=========================================================================
+const char* cmConditionEvaluator::GetVariableOrString(
+ const cmExpandedCommandArgument& argument) const
+{
+ const char* def = this->GetDefinitionIfUnquoted(argument);
+
+ if (!def) {
+ def = argument.c_str();
+ }
+
+ return def;
+}
+
+//=========================================================================
+bool cmConditionEvaluator::IsKeyword(std::string const& keyword,
+ cmExpandedCommandArgument& argument) const
+{
+ if ((this->Policy54Status != cmPolicies::WARN &&
+ this->Policy54Status != cmPolicies::OLD) &&
+ argument.WasQuoted()) {
+ return false;
+ }
+
+ bool isKeyword = argument.GetValue() == keyword;
+
+ if (isKeyword && argument.WasQuoted() &&
+ this->Policy54Status == cmPolicies::WARN) {
+ if (!this->Makefile.HasCMP0054AlreadyBeenReported(
+ this->ExecutionContext)) {
+ std::ostringstream e;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0054) << "\n";
+ e << "Quoted keywords like \"" << argument.GetValue()
+ << "\" will no longer be interpreted as keywords "
+ "when the policy is set to NEW. "
+ "Since the policy is not set the OLD behavior will be used.";
+
+ this->Makefile.GetCMakeInstance()->IssueMessage(
+ cmake::AUTHOR_WARNING, e.str(), this->Backtrace);
+ }
+ }
+
+ return isKeyword;
+}
+
+//=========================================================================
+bool cmConditionEvaluator::GetBooleanValue(
+ cmExpandedCommandArgument& arg) const
+{
+ // Check basic constants.
+ if (arg == "0") {
+ return false;
+ }
+ if (arg == "1") {
+ return true;
+ }
+
+ // Check named constants.
+ if (cmSystemTools::IsOn(arg.c_str())) {
+ return true;
+ }
+ if (cmSystemTools::IsOff(arg.c_str())) {
+ return false;
+ }
+
+ // Check for numbers.
+ if (!arg.empty()) {
+ char* end;
+ double d = strtod(arg.c_str(), &end);
+ if (*end == '\0') {
+ // The whole string is a number. Use C conversion to bool.
+ return d ? true : false;
+ }
+ }
+
+ // Check definition.
+ const char* def = this->GetDefinitionIfUnquoted(arg);
+ return !cmSystemTools::IsOff(def);
+}
+
+//=========================================================================
+// Boolean value behavior from CMake 2.6.4 and below.
+bool cmConditionEvaluator::GetBooleanValueOld(
+ cmExpandedCommandArgument const& arg, bool one) const
+{
+ if (one) {
+ // Old IsTrue behavior for single argument.
+ if (arg == "0") {
+ return false;
+ } else if (arg == "1") {
+ return true;
+ } else {
+ const char* def = this->GetDefinitionIfUnquoted(arg);
+ return !cmSystemTools::IsOff(def);
+ }
+ } else {
+ // Old GetVariableOrNumber behavior.
+ const char* def = this->GetDefinitionIfUnquoted(arg);
+ if (!def && atoi(arg.c_str())) {
+ def = arg.c_str();
+ }
+ return !cmSystemTools::IsOff(def);
+ }
+}
+
+//=========================================================================
+// returns the resulting boolean value
+bool cmConditionEvaluator::GetBooleanValueWithAutoDereference(
+ cmExpandedCommandArgument& newArg, std::string& errorString,
+ cmake::MessageType& status, bool oneArg) const
+{
+ // Use the policy if it is set.
+ if (this->Policy12Status == cmPolicies::NEW) {
+ return GetBooleanValue(newArg);
+ } else if (this->Policy12Status == cmPolicies::OLD) {
+ return GetBooleanValueOld(newArg, oneArg);
+ }
+
+ // Check policy only if old and new results differ.
+ bool newResult = this->GetBooleanValue(newArg);
+ bool oldResult = this->GetBooleanValueOld(newArg, oneArg);
+ if (newResult != oldResult) {
+ switch (this->Policy12Status) {
+ case cmPolicies::WARN: {
+ errorString = "An argument named \"" + newArg.GetValue() +
+ "\" appears in a conditional statement. " +
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0012);
+ status = cmake::AUTHOR_WARNING;
+ }
+ case cmPolicies::OLD:
+ return oldResult;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS: {
+ errorString = "An argument named \"" + newArg.GetValue() +
+ "\" appears in a conditional statement. " +
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0012);
+ status = cmake::FATAL_ERROR;
+ }
+ case cmPolicies::NEW:
+ break;
+ }
+ }
+ return newResult;
+}
+
+//=========================================================================
+void cmConditionEvaluator::IncrementArguments(
+ cmArgumentList& newArgs, cmArgumentList::iterator& argP1,
+ cmArgumentList::iterator& argP2) const
+{
+ if (argP1 != newArgs.end()) {
+ argP1++;
+ argP2 = argP1;
+ if (argP1 != newArgs.end()) {
+ argP2++;
+ }
+ }
+}
+
+//=========================================================================
+// helper function to reduce code duplication
+void cmConditionEvaluator::HandlePredicate(
+ bool value, int& reducible, cmArgumentList::iterator& arg,
+ cmArgumentList& newArgs, cmArgumentList::iterator& argP1,
+ cmArgumentList::iterator& argP2) const
+{
+ if (value) {
+ *arg = cmExpandedCommandArgument("1", true);
+ } else {
+ *arg = cmExpandedCommandArgument("0", true);
+ }
+ newArgs.erase(argP1);
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ reducible = 1;
+}
+
+//=========================================================================
+// helper function to reduce code duplication
+void cmConditionEvaluator::HandleBinaryOp(bool value, int& reducible,
+ cmArgumentList::iterator& arg,
+ cmArgumentList& newArgs,
+ cmArgumentList::iterator& argP1,
+ cmArgumentList::iterator& argP2)
+{
+ if (value) {
+ *arg = cmExpandedCommandArgument("1", true);
+ } else {
+ *arg = cmExpandedCommandArgument("0", true);
+ }
+ newArgs.erase(argP2);
+ newArgs.erase(argP1);
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ reducible = 1;
+}
+
+//=========================================================================
+// level 0 processes parenthetical expressions
+bool cmConditionEvaluator::HandleLevel0(cmArgumentList& newArgs,
+ std::string& errorString,
+ cmake::MessageType& status)
+{
+ int reducible;
+ do {
+ reducible = 0;
+ cmArgumentList::iterator arg = newArgs.begin();
+ while (arg != newArgs.end()) {
+ if (IsKeyword(keyParenL, *arg)) {
+ // search for the closing paren for this opening one
+ cmArgumentList::iterator argClose;
+ argClose = arg;
+ argClose++;
+ unsigned int depth = 1;
+ while (argClose != newArgs.end() && depth) {
+ if (this->IsKeyword(keyParenL, *argClose)) {
+ depth++;
+ }
+ if (this->IsKeyword(keyParenR, *argClose)) {
+ depth--;
+ }
+ argClose++;
+ }
+ if (depth) {
+ errorString = "mismatched parenthesis in condition";
+ status = cmake::FATAL_ERROR;
+ return false;
+ }
+ // store the reduced args in this vector
+ std::vector<cmExpandedCommandArgument> newArgs2;
+
+ // copy to the list structure
+ cmArgumentList::iterator argP1 = arg;
+ argP1++;
+ newArgs2.insert(newArgs2.end(), argP1, argClose);
+ newArgs2.pop_back();
+ // now recursively invoke IsTrue to handle the values inside the
+ // parenthetical expression
+ bool value = this->IsTrue(newArgs2, errorString, status);
+ if (value) {
+ *arg = cmExpandedCommandArgument("1", true);
+ } else {
+ *arg = cmExpandedCommandArgument("0", true);
+ }
+ argP1 = arg;
+ argP1++;
+ // remove the now evaluated parenthetical expression
+ newArgs.erase(argP1, argClose);
+ }
+ ++arg;
+ }
+ } while (reducible);
+ return true;
+}
+
+//=========================================================================
+// level one handles most predicates except for NOT
+bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&,
+ cmake::MessageType&)
+{
+ int reducible;
+ do {
+ reducible = 0;
+ cmArgumentList::iterator arg = newArgs.begin();
+ cmArgumentList::iterator argP1;
+ cmArgumentList::iterator argP2;
+ while (arg != newArgs.end()) {
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ // does a file exist
+ if (this->IsKeyword(keyEXISTS, *arg) && argP1 != newArgs.end()) {
+ this->HandlePredicate(cmSystemTools::FileExists(argP1->c_str()),
+ reducible, arg, newArgs, argP1, argP2);
+ }
+ // does a directory with this name exist
+ if (this->IsKeyword(keyIS_DIRECTORY, *arg) && argP1 != newArgs.end()) {
+ this->HandlePredicate(cmSystemTools::FileIsDirectory(argP1->c_str()),
+ reducible, arg, newArgs, argP1, argP2);
+ }
+ // does a symlink with this name exist
+ if (this->IsKeyword(keyIS_SYMLINK, *arg) && argP1 != newArgs.end()) {
+ this->HandlePredicate(cmSystemTools::FileIsSymlink(argP1->c_str()),
+ reducible, arg, newArgs, argP1, argP2);
+ }
+ // is the given path an absolute path ?
+ if (this->IsKeyword(keyIS_ABSOLUTE, *arg) && argP1 != newArgs.end()) {
+ this->HandlePredicate(cmSystemTools::FileIsFullPath(argP1->c_str()),
+ reducible, arg, newArgs, argP1, argP2);
+ }
+ // does a command exist
+ if (this->IsKeyword(keyCOMMAND, *arg) && argP1 != newArgs.end()) {
+ cmCommand* command =
+ this->Makefile.GetState()->GetCommand(argP1->c_str());
+ this->HandlePredicate(command ? true : false, reducible, arg, newArgs,
+ argP1, argP2);
+ }
+ // does a policy exist
+ if (this->IsKeyword(keyPOLICY, *arg) && argP1 != newArgs.end()) {
+ cmPolicies::PolicyID pid;
+ this->HandlePredicate(cmPolicies::GetPolicyID(argP1->c_str(), pid),
+ reducible, arg, newArgs, argP1, argP2);
+ }
+ // does a target exist
+ if (this->IsKeyword(keyTARGET, *arg) && argP1 != newArgs.end()) {
+ this->HandlePredicate(
+ this->Makefile.FindTargetToUse(argP1->GetValue()) ? true : false,
+ reducible, arg, newArgs, argP1, argP2);
+ }
+ // does a test exist
+ if (this->Policy64Status != cmPolicies::OLD &&
+ this->Policy64Status != cmPolicies::WARN) {
+ if (this->IsKeyword(keyTEST, *arg) && argP1 != newArgs.end()) {
+ const cmTest* haveTest = this->Makefile.GetTest(argP1->c_str());
+ this->HandlePredicate(haveTest ? true : false, reducible, arg,
+ newArgs, argP1, argP2);
+ }
+ } else if (this->Policy64Status == cmPolicies::WARN &&
+ this->IsKeyword(keyTEST, *arg)) {
+ std::ostringstream e;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0064) << "\n";
+ e << "TEST will be interpreted as an operator "
+ "when the policy is set to NEW. "
+ "Since the policy is not set the OLD behavior will be used.";
+
+ this->Makefile.IssueMessage(cmake::AUTHOR_WARNING, e.str());
+ }
+ // is a variable defined
+ if (this->IsKeyword(keyDEFINED, *arg) && argP1 != newArgs.end()) {
+ size_t argP1len = argP1->GetValue().size();
+ bool bdef = false;
+ if (argP1len > 4 && argP1->GetValue().substr(0, 4) == "ENV{" &&
+ argP1->GetValue().operator[](argP1len - 1) == '}') {
+ std::string env = argP1->GetValue().substr(4, argP1len - 5);
+ bdef = cmSystemTools::GetEnv(env.c_str()) ? true : false;
+ } else {
+ bdef = this->Makefile.IsDefinitionSet(argP1->GetValue());
+ }
+ this->HandlePredicate(bdef, reducible, arg, newArgs, argP1, argP2);
+ }
+ ++arg;
+ }
+ } while (reducible);
+ return true;
+}
+
+//=========================================================================
+// level two handles most binary operations except for AND OR
+bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs,
+ std::string& errorString,
+ cmake::MessageType& status)
+{
+ int reducible;
+ std::string def_buf;
+ const char* def;
+ const char* def2;
+ do {
+ reducible = 0;
+ cmArgumentList::iterator arg = newArgs.begin();
+ cmArgumentList::iterator argP1;
+ cmArgumentList::iterator argP2;
+ while (arg != newArgs.end()) {
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
+ IsKeyword(keyMATCHES, *argP1)) {
+ def = this->GetVariableOrString(*arg);
+ if (def != arg->c_str() // yes, we compare the pointer value
+ && cmHasLiteralPrefix(arg->GetValue(), "CMAKE_MATCH_")) {
+ // The string to match is owned by our match result variables.
+ // Move it to our own buffer before clearing them.
+ def_buf = def;
+ def = def_buf.c_str();
+ }
+ const char* rex = argP2->c_str();
+ this->Makefile.ClearMatches();
+ cmsys::RegularExpression regEntry;
+ if (!regEntry.compile(rex)) {
+ std::ostringstream error;
+ error << "Regular expression \"" << rex << "\" cannot compile";
+ errorString = error.str();
+ status = cmake::FATAL_ERROR;
+ return false;
+ }
+ if (regEntry.find(def)) {
+ this->Makefile.StoreMatches(regEntry);
+ *arg = cmExpandedCommandArgument("1", true);
+ } else {
+ *arg = cmExpandedCommandArgument("0", true);
+ }
+ newArgs.erase(argP2);
+ newArgs.erase(argP1);
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ reducible = 1;
+ }
+
+ if (argP1 != newArgs.end() && this->IsKeyword(keyMATCHES, *arg)) {
+ *arg = cmExpandedCommandArgument("0", true);
+ newArgs.erase(argP1);
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ reducible = 1;
+ }
+
+ if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
+ (this->IsKeyword(keyLESS, *argP1) ||
+ this->IsKeyword(keyGREATER, *argP1) ||
+ this->IsKeyword(keyEQUAL, *argP1))) {
+ def = this->GetVariableOrString(*arg);
+ def2 = this->GetVariableOrString(*argP2);
+ double lhs;
+ double rhs;
+ bool result;
+ if (sscanf(def, "%lg", &lhs) != 1 || sscanf(def2, "%lg", &rhs) != 1) {
+ result = false;
+ } else if (*(argP1) == keyLESS) {
+ result = (lhs < rhs);
+ } else if (*(argP1) == keyGREATER) {
+ result = (lhs > rhs);
+ } else {
+ result = (lhs == rhs);
+ }
+ this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
+ }
+
+ if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
+ (this->IsKeyword(keySTRLESS, *argP1) ||
+ this->IsKeyword(keySTREQUAL, *argP1) ||
+ this->IsKeyword(keySTRGREATER, *argP1))) {
+ def = this->GetVariableOrString(*arg);
+ def2 = this->GetVariableOrString(*argP2);
+ int val = strcmp(def, def2);
+ bool result;
+ if (*(argP1) == keySTRLESS) {
+ result = (val < 0);
+ } else if (*(argP1) == keySTRGREATER) {
+ result = (val > 0);
+ } else // strequal
+ {
+ result = (val == 0);
+ }
+ this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
+ }
+
+ if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
+ (this->IsKeyword(keyVERSION_LESS, *argP1) ||
+ this->IsKeyword(keyVERSION_GREATER, *argP1) ||
+ this->IsKeyword(keyVERSION_EQUAL, *argP1))) {
+ def = this->GetVariableOrString(*arg);
+ def2 = this->GetVariableOrString(*argP2);
+ cmSystemTools::CompareOp op = cmSystemTools::OP_EQUAL;
+ if (*argP1 == keyVERSION_LESS) {
+ op = cmSystemTools::OP_LESS;
+ } else if (*argP1 == keyVERSION_GREATER) {
+ op = cmSystemTools::OP_GREATER;
+ }
+ bool result = cmSystemTools::VersionCompare(op, def, def2);
+ this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
+ }
+
+ // is file A newer than file B
+ if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
+ this->IsKeyword(keyIS_NEWER_THAN, *argP1)) {
+ int fileIsNewer = 0;
+ bool success = cmSystemTools::FileTimeCompare(
+ arg->GetValue(), (argP2)->GetValue(), &fileIsNewer);
+ this->HandleBinaryOp(
+ (success == false || fileIsNewer == 1 || fileIsNewer == 0),
+ reducible, arg, newArgs, argP1, argP2);
+ }
+
+ if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
+ this->IsKeyword(keyIN_LIST, *argP1)) {
+ if (this->Policy57Status != cmPolicies::OLD &&
+ this->Policy57Status != cmPolicies::WARN) {
+ bool result = false;
+
+ def = this->GetVariableOrString(*arg);
+ def2 = this->Makefile.GetDefinition(argP2->GetValue());
+
+ if (def2) {
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(def2, list, true);
+
+ result = std::find(list.begin(), list.end(), def) != list.end();
+ }
+
+ this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
+ } else if (this->Policy57Status == cmPolicies::WARN) {
+ std::ostringstream e;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0057) << "\n";
+ e << "IN_LIST will be interpreted as an operator "
+ "when the policy is set to NEW. "
+ "Since the policy is not set the OLD behavior will be used.";
+
+ this->Makefile.IssueMessage(cmake::AUTHOR_WARNING, e.str());
+ }
+ }
+
+ ++arg;
+ }
+ } while (reducible);
+ return true;
+}
+
+//=========================================================================
+// level 3 handles NOT
+bool cmConditionEvaluator::HandleLevel3(cmArgumentList& newArgs,
+ std::string& errorString,
+ cmake::MessageType& status)
+{
+ int reducible;
+ do {
+ reducible = 0;
+ cmArgumentList::iterator arg = newArgs.begin();
+ cmArgumentList::iterator argP1;
+ cmArgumentList::iterator argP2;
+ while (arg != newArgs.end()) {
+ argP1 = arg;
+ IncrementArguments(newArgs, argP1, argP2);
+ if (argP1 != newArgs.end() && IsKeyword(keyNOT, *arg)) {
+ bool rhs = this->GetBooleanValueWithAutoDereference(
+ *argP1, errorString, status);
+ this->HandlePredicate(!rhs, reducible, arg, newArgs, argP1, argP2);
+ }
+ ++arg;
+ }
+ } while (reducible);
+ return true;
+}
+
+//=========================================================================
+// level 4 handles AND OR
+bool cmConditionEvaluator::HandleLevel4(cmArgumentList& newArgs,
+ std::string& errorString,
+ cmake::MessageType& status)
+{
+ int reducible;
+ bool lhs;
+ bool rhs;
+ do {
+ reducible = 0;
+ cmArgumentList::iterator arg = newArgs.begin();
+ cmArgumentList::iterator argP1;
+ cmArgumentList::iterator argP2;
+ while (arg != newArgs.end()) {
+ argP1 = arg;
+ IncrementArguments(newArgs, argP1, argP2);
+ if (argP1 != newArgs.end() && IsKeyword(keyAND, *argP1) &&
+ argP2 != newArgs.end()) {
+ lhs =
+ this->GetBooleanValueWithAutoDereference(*arg, errorString, status);
+ rhs = this->GetBooleanValueWithAutoDereference(*argP2, errorString,
+ status);
+ this->HandleBinaryOp((lhs && rhs), reducible, arg, newArgs, argP1,
+ argP2);
+ }
+
+ if (argP1 != newArgs.end() && this->IsKeyword(keyOR, *argP1) &&
+ argP2 != newArgs.end()) {
+ lhs =
+ this->GetBooleanValueWithAutoDereference(*arg, errorString, status);
+ rhs = this->GetBooleanValueWithAutoDereference(*argP2, errorString,
+ status);
+ this->HandleBinaryOp((lhs || rhs), reducible, arg, newArgs, argP1,
+ argP2);
+ }
+ ++arg;
+ }
+ } while (reducible);
+ return true;
+}
diff --git a/Source/cmConditionEvaluator.h b/Source/cmConditionEvaluator.h
new file mode 100644
index 0000000..3f8c984
--- /dev/null
+++ b/Source/cmConditionEvaluator.h
@@ -0,0 +1,93 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmConditionEvaluator_h
+#define cmConditionEvaluator_h
+
+#include "cmCommand.h"
+#include "cmExpandedCommandArgument.h"
+
+#include <list>
+
+class cmConditionEvaluator
+{
+public:
+ typedef std::list<cmExpandedCommandArgument> cmArgumentList;
+
+ cmConditionEvaluator(cmMakefile& makefile, cmListFileContext const& context,
+ cmListFileBacktrace const& bt);
+
+ // this is a shared function for both If and Else to determine if the
+ // arguments were valid, and if so, was the response true. If there is
+ // an error, the errorString will be set.
+ bool IsTrue(const std::vector<cmExpandedCommandArgument>& args,
+ std::string& errorString, cmake::MessageType& status);
+
+private:
+ // Filter the given variable definition based on policy CMP0054.
+ const char* GetDefinitionIfUnquoted(
+ const cmExpandedCommandArgument& argument) const;
+
+ const char* GetVariableOrString(
+ const cmExpandedCommandArgument& argument) const;
+
+ bool IsKeyword(std::string const& keyword,
+ cmExpandedCommandArgument& argument) const;
+
+ bool GetBooleanValue(cmExpandedCommandArgument& arg) const;
+
+ bool GetBooleanValueOld(cmExpandedCommandArgument const& arg,
+ bool one) const;
+
+ bool GetBooleanValueWithAutoDereference(cmExpandedCommandArgument& newArg,
+ std::string& errorString,
+ cmake::MessageType& status,
+ bool oneArg = false) const;
+
+ void IncrementArguments(cmArgumentList& newArgs,
+ cmArgumentList::iterator& argP1,
+ cmArgumentList::iterator& argP2) const;
+
+ void HandlePredicate(bool value, int& reducible,
+ cmArgumentList::iterator& arg, cmArgumentList& newArgs,
+ cmArgumentList::iterator& argP1,
+ cmArgumentList::iterator& argP2) const;
+
+ void HandleBinaryOp(bool value, int& reducible,
+ cmArgumentList::iterator& arg, cmArgumentList& newArgs,
+ cmArgumentList::iterator& argP1,
+ cmArgumentList::iterator& argP2);
+
+ bool HandleLevel0(cmArgumentList& newArgs, std::string& errorString,
+ cmake::MessageType& status);
+
+ bool HandleLevel1(cmArgumentList& newArgs, std::string&,
+ cmake::MessageType&);
+
+ bool HandleLevel2(cmArgumentList& newArgs, std::string& errorString,
+ cmake::MessageType& status);
+
+ bool HandleLevel3(cmArgumentList& newArgs, std::string& errorString,
+ cmake::MessageType& status);
+
+ bool HandleLevel4(cmArgumentList& newArgs, std::string& errorString,
+ cmake::MessageType& status);
+
+ cmMakefile& Makefile;
+ cmListFileContext ExecutionContext;
+ cmListFileBacktrace Backtrace;
+ cmPolicies::PolicyStatus Policy12Status;
+ cmPolicies::PolicyStatus Policy54Status;
+ cmPolicies::PolicyStatus Policy57Status;
+ cmPolicies::PolicyStatus Policy64Status;
+};
+
+#endif
diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in
new file mode 100644
index 0000000..7e48b2d
--- /dev/null
+++ b/Source/cmConfigure.cmake.h.in
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmConfigure_h
+#define cmConfigure_h
+
+#include <cmsys/Configure.hxx>
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4786)
+#pragma warning(disable : 4503)
+#endif
+
+#ifdef __ICL
+#pragma warning(disable : 985)
+#pragma warning(disable : 1572) /* floating-point equality test */
+#endif
+
+#cmakedefine HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE
+#cmakedefine HAVE_UNSETENV
+#cmakedefine CMAKE_USE_ELF_PARSER
+#cmakedefine CMAKE_USE_MACH_PARSER
+#cmakedefine CMAKE_ENCODING_UTF8
+#cmakedefine CMake_HAVE_CXX_NULLPTR
+#cmakedefine CMake_HAVE_CXX_OVERRIDE
+#cmakedefine CMake_HAVE_CXX_UNORDERED_MAP
+#cmakedefine CMake_HAVE_CXX_UNORDERED_SET
+#define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@"
+#define CMAKE_DATA_DIR "/@CMAKE_DATA_DIR@"
+
+#ifdef CMake_HAVE_CXX_NULLPTR
+#define CM_NULLPTR nullptr
+#else
+#define CM_NULLPTR 0
+#endif
+
+#ifdef CMake_HAVE_CXX_OVERRIDE
+#define CM_OVERRIDE override
+#else
+#define CM_OVERRIDE
+#endif
+
+#endif
diff --git a/Source/cmConfigureFileCommand.cxx b/Source/cmConfigureFileCommand.cxx
new file mode 100644
index 0000000..899a674
--- /dev/null
+++ b/Source/cmConfigureFileCommand.cxx
@@ -0,0 +1,117 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmConfigureFileCommand.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+// cmConfigureFileCommand
+bool cmConfigureFileCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments, expected 2");
+ return false;
+ }
+
+ const char* inFile = args[0].c_str();
+ if (!cmSystemTools::FileIsFullPath(inFile)) {
+ this->InputFile = this->Makefile->GetCurrentSourceDirectory();
+ this->InputFile += "/";
+ }
+ this->InputFile += inFile;
+
+ // If the input location is a directory, error out.
+ if (cmSystemTools::FileIsDirectory(this->InputFile)) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "input location\n"
+ << " " << this->InputFile << "\n"
+ << "is a directory but a file was expected.";
+ /* clang-format on */
+ this->SetError(e.str());
+ return false;
+ }
+
+ const char* outFile = args[1].c_str();
+ if (!cmSystemTools::FileIsFullPath(outFile)) {
+ this->OutputFile = this->Makefile->GetCurrentBinaryDirectory();
+ this->OutputFile += "/";
+ }
+ this->OutputFile += outFile;
+
+ // If the output location is already a directory put the file in it.
+ if (cmSystemTools::FileIsDirectory(this->OutputFile)) {
+ this->OutputFile += "/";
+ this->OutputFile += cmSystemTools::GetFilenameName(inFile);
+ }
+
+ if (!this->Makefile->CanIWriteThisFile(this->OutputFile.c_str())) {
+ std::string e = "attempted to configure a file: " + this->OutputFile +
+ " into a source directory.";
+ this->SetError(e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ std::string errorMessage;
+ if (!this->NewLineStyle.ReadFromArguments(args, errorMessage)) {
+ this->SetError(errorMessage);
+ return false;
+ }
+ this->CopyOnly = false;
+ this->EscapeQuotes = false;
+
+ std::string unknown_args;
+ this->AtOnly = false;
+ for (unsigned int i = 2; i < args.size(); ++i) {
+ if (args[i] == "COPYONLY") {
+ this->CopyOnly = true;
+ if (this->NewLineStyle.IsValid()) {
+ this->SetError("COPYONLY could not be used in combination "
+ "with NEWLINE_STYLE");
+ return false;
+ }
+ } else if (args[i] == "ESCAPE_QUOTES") {
+ this->EscapeQuotes = true;
+ } else if (args[i] == "@ONLY") {
+ this->AtOnly = true;
+ } else if (args[i] == "IMMEDIATE") {
+ /* Ignore legacy option. */
+ } else if (args[i] == "NEWLINE_STYLE" || args[i] == "LF" ||
+ args[i] == "UNIX" || args[i] == "CRLF" || args[i] == "WIN32" ||
+ args[i] == "DOS") {
+ /* Options handled by NewLineStyle member above. */
+ } else {
+ unknown_args += " ";
+ unknown_args += args[i];
+ unknown_args += "\n";
+ }
+ }
+ if (!unknown_args.empty()) {
+ std::string msg = "configure_file called with unknown argument(s):\n";
+ msg += unknown_args;
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, msg);
+ }
+
+ if (!this->ConfigureFile()) {
+ this->SetError("Problem configuring file");
+ return false;
+ }
+
+ return true;
+}
+
+int cmConfigureFileCommand::ConfigureFile()
+{
+ return this->Makefile->ConfigureFile(
+ this->InputFile.c_str(), this->OutputFile.c_str(), this->CopyOnly,
+ this->AtOnly, this->EscapeQuotes, this->NewLineStyle);
+}
diff --git a/Source/cmConfigureFileCommand.h b/Source/cmConfigureFileCommand.h
new file mode 100644
index 0000000..1da65c8
--- /dev/null
+++ b/Source/cmConfigureFileCommand.h
@@ -0,0 +1,53 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmConfigureFileCommand_h
+#define cmConfigureFileCommand_h
+
+#include "cmCommand.h"
+
+class cmConfigureFileCommand : public cmCommand
+{
+public:
+ cmTypeMacro(cmConfigureFileCommand, cmCommand);
+
+ cmCommand* Clone() CM_OVERRIDE { return new cmConfigureFileCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "configure_file"; }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+private:
+ int ConfigureFile();
+
+ cmNewLineStyle NewLineStyle;
+
+ std::string InputFile;
+ std::string OutputFile;
+ bool CopyOnly;
+ bool EscapeQuotes;
+ bool AtOnly;
+};
+
+#endif
diff --git a/Source/cmContinueCommand.cxx b/Source/cmContinueCommand.cxx
new file mode 100644
index 0000000..c8c1b7d
--- /dev/null
+++ b/Source/cmContinueCommand.cxx
@@ -0,0 +1,37 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmContinueCommand.h"
+
+// cmContinueCommand
+bool cmContinueCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (!this->Makefile->IsLoopBlock()) {
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR,
+ "A CONTINUE command was found outside of a "
+ "proper FOREACH or WHILE loop scope.");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+
+ status.SetContinueInvoked(true);
+
+ if (!args.empty()) {
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR,
+ "The CONTINUE command does not accept any "
+ "arguments.");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+
+ return true;
+}
diff --git a/Source/cmContinueCommand.h b/Source/cmContinueCommand.h
new file mode 100644
index 0000000..6fa9af2
--- /dev/null
+++ b/Source/cmContinueCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmContinueCommand_h
+#define cmContinueCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmContinueCommand
+ * \brief Continue from an enclosing foreach or while loop
+ *
+ * cmContinueCommand returns from an enclosing foreach or while loop
+ */
+class cmContinueCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmContinueCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "continue"; }
+
+ cmTypeMacro(cmContinueCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
new file mode 100644
index 0000000..e9367b1
--- /dev/null
+++ b/Source/cmCoreTryCompile.cxx
@@ -0,0 +1,695 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2011 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCoreTryCompile.h"
+
+#include "cmAlgorithms.h"
+#include "cmExportTryCompileFileGenerator.h"
+#include "cmGlobalGenerator.h"
+#include "cmOutputConverter.h"
+#include "cmake.h"
+#include <cmsys/Directory.hxx>
+
+#include <assert.h>
+
+static std::string const kCMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN =
+ "CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN";
+static std::string const kCMAKE_C_COMPILER_TARGET = "CMAKE_C_COMPILER_TARGET";
+static std::string const kCMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN =
+ "CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN";
+static std::string const kCMAKE_CXX_COMPILER_TARGET =
+ "CMAKE_CXX_COMPILER_TARGET";
+static std::string const kCMAKE_ENABLE_EXPORTS = "CMAKE_ENABLE_EXPORTS";
+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_OSX_ARCHITECTURES = "CMAKE_OSX_ARCHITECTURES";
+static std::string const kCMAKE_OSX_DEPLOYMENT_TARGET =
+ "CMAKE_OSX_DEPLOYMENT_TARGET";
+static std::string const kCMAKE_OSX_SYSROOT = "CMAKE_OSX_SYSROOT";
+static std::string const kCMAKE_POSITION_INDEPENDENT_CODE =
+ "CMAKE_POSITION_INDEPENDENT_CODE";
+static std::string const kCMAKE_SYSROOT = "CMAKE_SYSROOT";
+static std::string const kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES =
+ "CMAKE_TRY_COMPILE_OSX_ARCHITECTURES";
+static std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES =
+ "CMAKE_TRY_COMPILE_PLATFORM_VARIABLES";
+
+int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
+ bool isTryRun)
+{
+ this->BinaryDirectory = argv[1].c_str();
+ this->OutputFile = "";
+ // which signature were we called with ?
+ this->SrcFileSignature = true;
+
+ cmState::TargetType targetType = cmState::EXECUTABLE;
+ const char* tt =
+ this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_TARGET_TYPE");
+ if (!isTryRun && tt && *tt) {
+ if (strcmp(tt, cmState::GetTargetTypeName(cmState::EXECUTABLE)) == 0) {
+ targetType = cmState::EXECUTABLE;
+ } else if (strcmp(tt, cmState::GetTargetTypeName(
+ cmState::STATIC_LIBRARY)) == 0) {
+ targetType = cmState::STATIC_LIBRARY;
+ } else {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR, std::string("Invalid value '") + tt +
+ "' for "
+ "CMAKE_TRY_COMPILE_TARGET_TYPE. Only "
+ "'" +
+ cmState::GetTargetTypeName(cmState::EXECUTABLE) + "' and "
+ "'" +
+ cmState::GetTargetTypeName(cmState::STATIC_LIBRARY) +
+ "' "
+ "are allowed.");
+ return -1;
+ }
+ }
+
+ const char* sourceDirectory = argv[2].c_str();
+ const char* projectName = CM_NULLPTR;
+ std::string targetName;
+ std::vector<std::string> cmakeFlags(1, "CMAKE_FLAGS"); // fake argv[0]
+ std::vector<std::string> compileDefs;
+ std::string outputVariable;
+ std::string copyFile;
+ std::string copyFileError;
+ std::vector<std::string> targets;
+ std::string libsToLink = " ";
+ bool useOldLinkLibs = true;
+ char targetNameBuf[64];
+ bool didOutputVariable = false;
+ bool didCopyFile = false;
+ bool didCopyFileError = false;
+ bool useSources = argv[2] == "SOURCES";
+ std::vector<std::string> sources;
+
+ enum Doing
+ {
+ DoingNone,
+ DoingCMakeFlags,
+ DoingCompileDefinitions,
+ DoingLinkLibraries,
+ DoingOutputVariable,
+ DoingCopyFile,
+ DoingCopyFileError,
+ DoingSources
+ };
+ Doing doing = useSources ? DoingSources : DoingNone;
+ for (size_t i = 3; i < argv.size(); ++i) {
+ if (argv[i] == "CMAKE_FLAGS") {
+ doing = DoingCMakeFlags;
+ } else if (argv[i] == "COMPILE_DEFINITIONS") {
+ doing = DoingCompileDefinitions;
+ } else if (argv[i] == "LINK_LIBRARIES") {
+ doing = DoingLinkLibraries;
+ useOldLinkLibs = false;
+ } else if (argv[i] == "OUTPUT_VARIABLE") {
+ doing = DoingOutputVariable;
+ didOutputVariable = true;
+ } else if (argv[i] == "COPY_FILE") {
+ doing = DoingCopyFile;
+ didCopyFile = true;
+ } else if (argv[i] == "COPY_FILE_ERROR") {
+ doing = DoingCopyFileError;
+ didCopyFileError = true;
+ } else if (doing == DoingCMakeFlags) {
+ cmakeFlags.push_back(argv[i]);
+ } else if (doing == DoingCompileDefinitions) {
+ compileDefs.push_back(argv[i]);
+ } else if (doing == DoingLinkLibraries) {
+ libsToLink += "\"" + cmSystemTools::TrimWhitespace(argv[i]) + "\" ";
+ if (cmTarget* tgt = this->Makefile->FindTargetToUse(argv[i])) {
+ switch (tgt->GetType()) {
+ case cmState::SHARED_LIBRARY:
+ case cmState::STATIC_LIBRARY:
+ case cmState::INTERFACE_LIBRARY:
+ case cmState::UNKNOWN_LIBRARY:
+ break;
+ case cmState::EXECUTABLE:
+ if (tgt->IsExecutableWithExports()) {
+ break;
+ }
+ default:
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "Only libraries may be used as try_compile or try_run IMPORTED "
+ "LINK_LIBRARIES. Got " +
+ std::string(tgt->GetName()) + " of "
+ "type " +
+ cmState::GetTargetTypeName(tgt->GetType()) + ".");
+ return -1;
+ }
+ if (tgt->IsImported()) {
+ targets.push_back(argv[i]);
+ }
+ }
+ } else if (doing == DoingOutputVariable) {
+ outputVariable = argv[i].c_str();
+ doing = DoingNone;
+ } else if (doing == DoingCopyFile) {
+ copyFile = argv[i].c_str();
+ doing = DoingNone;
+ } else if (doing == DoingCopyFileError) {
+ copyFileError = argv[i].c_str();
+ doing = DoingNone;
+ } else if (doing == DoingSources) {
+ sources.push_back(argv[i]);
+ } else if (i == 3) {
+ this->SrcFileSignature = false;
+ projectName = argv[i].c_str();
+ } else if (i == 4 && !this->SrcFileSignature) {
+ targetName = argv[i].c_str();
+ } else {
+ std::ostringstream m;
+ m << "try_compile given unknown argument \"" << argv[i] << "\".";
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str());
+ }
+ }
+
+ if (didCopyFile && copyFile.empty()) {
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR,
+ "COPY_FILE must be followed by a file path");
+ return -1;
+ }
+
+ if (didCopyFileError && copyFileError.empty()) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "COPY_FILE_ERROR must be followed by a variable name");
+ return -1;
+ }
+
+ if (didCopyFileError && !didCopyFile) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR, "COPY_FILE_ERROR may be used only with COPY_FILE");
+ return -1;
+ }
+
+ if (didOutputVariable && outputVariable.empty()) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "OUTPUT_VARIABLE must be followed by a variable name");
+ return -1;
+ }
+
+ if (useSources && sources.empty()) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "SOURCES must be followed by at least one source file");
+ return -1;
+ }
+
+ // compute the binary dir when TRY_COMPILE is called with a src file
+ // signature
+ if (this->SrcFileSignature) {
+ this->BinaryDirectory += cmake::GetCMakeFilesDirectory();
+ this->BinaryDirectory += "/CMakeTmp";
+ } else {
+ // only valid for srcfile signatures
+ if (!compileDefs.empty()) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "COMPILE_DEFINITIONS specified on a srcdir type TRY_COMPILE");
+ return -1;
+ }
+ if (!copyFile.empty()) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "COPY_FILE specified on a srcdir type TRY_COMPILE");
+ return -1;
+ }
+ }
+ // make sure the binary directory exists
+ cmSystemTools::MakeDirectory(this->BinaryDirectory.c_str());
+
+ // do not allow recursive try Compiles
+ if (this->BinaryDirectory == this->Makefile->GetHomeOutputDirectory()) {
+ std::ostringstream e;
+ e << "Attempt at a recursive or nested TRY_COMPILE in directory\n"
+ << " " << this->BinaryDirectory << "\n";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return -1;
+ }
+
+ std::string outFileName = this->BinaryDirectory + "/CMakeLists.txt";
+ // which signature are we using? If we are using var srcfile bindir
+ if (this->SrcFileSignature) {
+ // remove any CMakeCache.txt files so we will have a clean test
+ std::string ccFile = this->BinaryDirectory + "/CMakeCache.txt";
+ cmSystemTools::RemoveFile(ccFile);
+
+ // Choose sources.
+ if (!useSources) {
+ sources.push_back(argv[2]);
+ }
+
+ // Detect languages to enable.
+ cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ std::set<std::string> testLangs;
+ for (std::vector<std::string>::iterator si = sources.begin();
+ si != sources.end(); ++si) {
+ std::string ext = cmSystemTools::GetFilenameLastExtension(*si);
+ std::string lang = gg->GetLanguageFromExtension(ext.c_str());
+ if (!lang.empty()) {
+ testLangs.insert(lang);
+ } else {
+ std::ostringstream err;
+ err << "Unknown extension \"" << ext << "\" for file\n"
+ << " " << *si << "\n"
+ << "try_compile() works only for enabled languages. "
+ << "Currently these are:\n ";
+ std::vector<std::string> langs;
+ gg->GetEnabledLanguages(langs);
+ err << cmJoin(langs, " ");
+ err << "\nSee project() command to enable other languages.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, err.str());
+ return -1;
+ }
+ }
+
+ std::string const tcConfig =
+ this->Makefile->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
+
+ // we need to create a directory and CMakeLists file etc...
+ // first create the directories
+ sourceDirectory = this->BinaryDirectory.c_str();
+
+ // now create a CMakeLists.txt file in that directory
+ FILE* fout = cmsys::SystemTools::Fopen(outFileName, "w");
+ if (!fout) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "Failed to open\n"
+ << " " << outFileName << "\n"
+ << cmSystemTools::GetLastSystemError();
+ /* clang-format on */
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return -1;
+ }
+
+ const char* def = this->Makefile->GetDefinition("CMAKE_MODULE_PATH");
+ fprintf(fout, "cmake_minimum_required(VERSION %u.%u.%u.%u)\n",
+ cmVersion::GetMajorVersion(), cmVersion::GetMinorVersion(),
+ cmVersion::GetPatchVersion(), cmVersion::GetTweakVersion());
+ if (def) {
+ fprintf(fout, "set(CMAKE_MODULE_PATH \"%s\")\n", def);
+ }
+
+ std::string projectLangs;
+ for (std::set<std::string>::iterator li = testLangs.begin();
+ li != testLangs.end(); ++li) {
+ projectLangs += " " + *li;
+ std::string rulesOverrideBase = "CMAKE_USER_MAKE_RULES_OVERRIDE";
+ std::string rulesOverrideLang = rulesOverrideBase + "_" + *li;
+ if (const char* rulesOverridePath =
+ this->Makefile->GetDefinition(rulesOverrideLang)) {
+ fprintf(fout, "set(%s \"%s\")\n", rulesOverrideLang.c_str(),
+ rulesOverridePath);
+ } else if (const char* rulesOverridePath2 =
+ this->Makefile->GetDefinition(rulesOverrideBase)) {
+ fprintf(fout, "set(%s \"%s\")\n", rulesOverrideBase.c_str(),
+ rulesOverridePath2);
+ }
+ }
+ fprintf(fout, "project(CMAKE_TRY_COMPILE%s)\n", projectLangs.c_str());
+ fprintf(fout, "set(CMAKE_VERBOSE_MAKEFILE 1)\n");
+ for (std::set<std::string>::iterator li = testLangs.begin();
+ li != testLangs.end(); ++li) {
+ std::string langFlags = "CMAKE_" + *li + "_FLAGS";
+ const char* flags = this->Makefile->GetDefinition(langFlags);
+ fprintf(fout, "set(CMAKE_%s_FLAGS %s)\n", li->c_str(),
+ cmOutputConverter::EscapeForCMake(flags ? flags : "").c_str());
+ fprintf(fout, "set(CMAKE_%s_FLAGS \"${CMAKE_%s_FLAGS}"
+ " ${COMPILE_DEFINITIONS}\")\n",
+ li->c_str(), li->c_str());
+ }
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0066)) {
+ case cmPolicies::WARN:
+ if (this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0066")) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0066) << "\n"
+ "For compatibility with older versions of CMake, try_compile "
+ "is not honoring caller config-specific compiler flags "
+ "(e.g. CMAKE_C_FLAGS_DEBUG) in the test project."
+ ;
+ /* clang-format on */
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ }
+ case cmPolicies::OLD:
+ // OLD behavior is to do nothing.
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0066));
+ case cmPolicies::NEW: {
+ // NEW behavior is to pass config-specific compiler flags.
+ static std::string const cfgDefault = "DEBUG";
+ std::string const cfg =
+ !tcConfig.empty() ? cmSystemTools::UpperCase(tcConfig) : cfgDefault;
+ for (std::set<std::string>::iterator li = testLangs.begin();
+ li != testLangs.end(); ++li) {
+ std::string const langFlagsCfg = "CMAKE_" + *li + "_FLAGS_" + cfg;
+ const char* flagsCfg = this->Makefile->GetDefinition(langFlagsCfg);
+ fprintf(fout, "set(%s %s)\n", langFlagsCfg.c_str(),
+ cmOutputConverter::EscapeForCMake(flagsCfg ? flagsCfg : "")
+ .c_str());
+ }
+ } break;
+ }
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0056)) {
+ case cmPolicies::WARN:
+ if (this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0056")) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0056) << "\n"
+ "For compatibility with older versions of CMake, try_compile "
+ "is not honoring caller link flags (e.g. CMAKE_EXE_LINKER_FLAGS) "
+ "in the test project."
+ ;
+ /* clang-format on */
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ }
+ case cmPolicies::OLD:
+ // OLD behavior is to do nothing.
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0056));
+ case cmPolicies::NEW:
+ // NEW behavior is to pass linker flags.
+ {
+ const char* exeLinkFlags =
+ this->Makefile->GetDefinition("CMAKE_EXE_LINKER_FLAGS");
+ fprintf(
+ fout, "set(CMAKE_EXE_LINKER_FLAGS %s)\n",
+ cmOutputConverter::EscapeForCMake(exeLinkFlags ? exeLinkFlags : "")
+ .c_str());
+ }
+ break;
+ }
+ fprintf(fout, "set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS}"
+ " ${EXE_LINKER_FLAGS}\")\n");
+ fprintf(fout, "include_directories(${INCLUDE_DIRECTORIES})\n");
+ fprintf(fout, "set(CMAKE_SUPPRESS_REGENERATION 1)\n");
+ fprintf(fout, "link_directories(${LINK_DIRECTORIES})\n");
+ // handle any compile flags we need to pass on
+ if (!compileDefs.empty()) {
+ fprintf(fout, "add_definitions(%s)\n", cmJoin(compileDefs, " ").c_str());
+ }
+
+ /* Use a random file name to avoid rapid creation and deletion
+ of the same executable name (some filesystems fail on that). */
+ sprintf(targetNameBuf, "cmTC_%05x", cmSystemTools::RandomSeed() & 0xFFFFF);
+ targetName = targetNameBuf;
+
+ if (!targets.empty()) {
+ std::string fname = "/" + std::string(targetName) + "Targets.cmake";
+ cmExportTryCompileFileGenerator tcfg(gg, targets, this->Makefile);
+ tcfg.SetExportFile((this->BinaryDirectory + fname).c_str());
+ tcfg.SetConfig(tcConfig);
+
+ if (!tcfg.GenerateImportFile()) {
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR,
+ "could not write export file.");
+ fclose(fout);
+ return -1;
+ }
+ fprintf(fout, "\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/%s\")\n\n",
+ fname.c_str());
+ }
+
+ // Forward a set of variables to the inner project cache.
+ {
+ std::set<std::string> vars;
+ vars.insert(kCMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN);
+ vars.insert(kCMAKE_C_COMPILER_TARGET);
+ vars.insert(kCMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN);
+ vars.insert(kCMAKE_CXX_COMPILER_TARGET);
+ vars.insert(kCMAKE_ENABLE_EXPORTS);
+ vars.insert(kCMAKE_LINK_SEARCH_END_STATIC);
+ vars.insert(kCMAKE_LINK_SEARCH_START_STATIC);
+ vars.insert(kCMAKE_OSX_ARCHITECTURES);
+ vars.insert(kCMAKE_OSX_DEPLOYMENT_TARGET);
+ vars.insert(kCMAKE_OSX_SYSROOT);
+ vars.insert(kCMAKE_POSITION_INDEPENDENT_CODE);
+ vars.insert(kCMAKE_SYSROOT);
+
+ if (const char* varListStr = this->Makefile->GetDefinition(
+ kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) {
+ std::vector<std::string> varList;
+ cmSystemTools::ExpandListArgument(varListStr, varList);
+ vars.insert(varList.begin(), varList.end());
+ }
+
+ /* for the TRY_COMPILEs we want to be able to specify the architecture.
+ So the user can set CMAKE_OSX_ARCHITECTURES to i386;ppc and then set
+ CMAKE_TRY_COMPILE_OSX_ARCHITECTURES first to i386 and then to ppc to
+ have the tests run for each specific architecture. Since
+ cmLocalGenerator doesn't allow building for "the other"
+ architecture only via CMAKE_OSX_ARCHITECTURES.
+ */
+ if (const char* tcArchs = this->Makefile->GetDefinition(
+ kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES)) {
+ vars.erase(kCMAKE_OSX_ARCHITECTURES);
+ std::string flag = "-DCMAKE_OSX_ARCHITECTURES=" + std::string(tcArchs);
+ cmakeFlags.push_back(flag);
+ }
+
+ for (std::set<std::string>::iterator vi = vars.begin(); vi != vars.end();
+ ++vi) {
+ std::string const& var = *vi;
+ if (const char* val = this->Makefile->GetDefinition(var)) {
+ std::string flag = "-D" + var + "=" + val;
+ cmakeFlags.push_back(flag);
+ }
+ }
+ }
+
+ /* Set the appropriate policy information for ENABLE_EXPORTS */
+ fprintf(fout, "cmake_policy(SET CMP0065 %s)\n",
+ this->Makefile->GetPolicyStatus(cmPolicies::CMP0065) ==
+ cmPolicies::NEW
+ ? "NEW"
+ : "OLD");
+
+ if (targetType == cmState::EXECUTABLE) {
+ /* Put the executable at a known location (for COPY_FILE). */
+ fprintf(fout, "set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"%s\")\n",
+ this->BinaryDirectory.c_str());
+ /* Create the actual executable. */
+ fprintf(fout, "add_executable(%s", targetName.c_str());
+ } else // if (targetType == cmState::STATIC_LIBRARY)
+ {
+ /* Put the static library at a known location (for COPY_FILE). */
+ fprintf(fout, "set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY \"%s\")\n",
+ this->BinaryDirectory.c_str());
+ /* Create the actual static library. */
+ fprintf(fout, "add_library(%s STATIC", targetName.c_str());
+ }
+ for (std::vector<std::string>::iterator si = sources.begin();
+ si != sources.end(); ++si) {
+ fprintf(fout, " \"%s\"", si->c_str());
+
+ // Add dependencies on any non-temporary sources.
+ if (si->find("CMakeTmp") == si->npos) {
+ this->Makefile->AddCMakeDependFile(*si);
+ }
+ }
+ fprintf(fout, ")\n");
+ if (useOldLinkLibs) {
+ fprintf(fout, "target_link_libraries(%s ${LINK_LIBRARIES})\n",
+ targetName.c_str());
+ } else {
+ fprintf(fout, "target_link_libraries(%s %s)\n", targetName.c_str(),
+ libsToLink.c_str());
+ }
+ fclose(fout);
+ projectName = "CMAKE_TRY_COMPILE";
+ }
+
+ bool erroroc = cmSystemTools::GetErrorOccuredFlag();
+ cmSystemTools::ResetErrorOccuredFlag();
+ std::string output;
+ // actually do the try compile now that everything is setup
+ int res = this->Makefile->TryCompile(
+ sourceDirectory, this->BinaryDirectory, projectName, targetName,
+ this->SrcFileSignature, &cmakeFlags, output);
+ if (erroroc) {
+ cmSystemTools::SetErrorOccured();
+ }
+
+ // set the result var to the return value to indicate success or failure
+ this->Makefile->AddCacheDefinition(argv[0], (res == 0 ? "TRUE" : "FALSE"),
+ "Result of TRY_COMPILE",
+ cmState::INTERNAL);
+
+ if (!outputVariable.empty()) {
+ this->Makefile->AddDefinition(outputVariable, output.c_str());
+ }
+
+ if (this->SrcFileSignature) {
+ std::string copyFileErrorMessage;
+ this->FindOutputFile(targetName, targetType);
+
+ if ((res == 0) && !copyFile.empty()) {
+ if (this->OutputFile.empty() ||
+ !cmSystemTools::CopyFileAlways(this->OutputFile, copyFile)) {
+ std::ostringstream emsg;
+ /* clang-format off */
+ emsg << "Cannot copy output executable\n"
+ << " '" << this->OutputFile << "'\n"
+ << "to destination specified by COPY_FILE:\n"
+ << " '" << copyFile << "'\n";
+ /* clang-format on */
+ if (!this->FindErrorMessage.empty()) {
+ emsg << this->FindErrorMessage.c_str();
+ }
+ if (copyFileError.empty()) {
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, emsg.str());
+ return -1;
+ } else {
+ copyFileErrorMessage = emsg.str();
+ }
+ }
+ }
+
+ if (!copyFileError.empty()) {
+ this->Makefile->AddDefinition(copyFileError,
+ copyFileErrorMessage.c_str());
+ }
+ }
+ return res;
+}
+
+void cmCoreTryCompile::CleanupFiles(const char* binDir)
+{
+ if (!binDir) {
+ return;
+ }
+
+ std::string bdir = binDir;
+ if (bdir.find("CMakeTmp") == std::string::npos) {
+ cmSystemTools::Error(
+ "TRY_COMPILE attempt to remove -rf directory that does not contain "
+ "CMakeTmp:",
+ binDir);
+ return;
+ }
+
+ cmsys::Directory dir;
+ dir.Load(binDir);
+ size_t fileNum;
+ std::set<std::string> deletedFiles;
+ for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) {
+ if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") &&
+ strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..")) {
+
+ if (deletedFiles.find(dir.GetFile(
+ static_cast<unsigned long>(fileNum))) == deletedFiles.end()) {
+ deletedFiles.insert(dir.GetFile(static_cast<unsigned long>(fileNum)));
+ std::string fullPath = binDir;
+ fullPath += "/";
+ fullPath += dir.GetFile(static_cast<unsigned long>(fileNum));
+ if (cmSystemTools::FileIsDirectory(fullPath)) {
+ this->CleanupFiles(fullPath.c_str());
+ cmSystemTools::RemoveADirectory(fullPath);
+ } else {
+#ifdef _WIN32
+ // Sometimes anti-virus software hangs on to new files so we
+ // cannot delete them immediately. Try a few times.
+ cmSystemTools::WindowsFileRetry retry =
+ cmSystemTools::GetWindowsFileRetry();
+ while (!cmSystemTools::RemoveFile(fullPath.c_str()) &&
+ --retry.Count &&
+ cmSystemTools::FileExists(fullPath.c_str())) {
+ cmSystemTools::Delay(retry.Delay);
+ }
+ if (retry.Count == 0)
+#else
+ if (!cmSystemTools::RemoveFile(fullPath))
+#endif
+ {
+ std::string m = "Remove failed on file: " + fullPath;
+ cmSystemTools::ReportLastSystemError(m.c_str());
+ }
+ }
+ }
+ }
+ }
+}
+
+void cmCoreTryCompile::FindOutputFile(const std::string& targetName,
+ cmState::TargetType targetType)
+{
+ this->FindErrorMessage = "";
+ this->OutputFile = "";
+ std::string tmpOutputFile = "/";
+ if (targetType == cmState::EXECUTABLE) {
+ tmpOutputFile += targetName;
+ tmpOutputFile +=
+ this->Makefile->GetSafeDefinition("CMAKE_EXECUTABLE_SUFFIX");
+ } else // if (targetType == cmState::STATIC_LIBRARY)
+ {
+ tmpOutputFile +=
+ this->Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX");
+ tmpOutputFile += targetName;
+ tmpOutputFile +=
+ this->Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX");
+ }
+
+ // a list of directories where to search for the compilation result
+ // at first directly in the binary dir
+ std::vector<std::string> searchDirs;
+ searchDirs.push_back("");
+
+ const char* config =
+ this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
+ // if a config was specified try that first
+ if (config && config[0]) {
+ std::string tmp = "/";
+ tmp += config;
+ searchDirs.push_back(tmp);
+ }
+ searchDirs.push_back("/Debug");
+#if defined(__APPLE__)
+ std::string app = "/Debug/" + targetName + ".app";
+ searchDirs.push_back(app);
+#endif
+ searchDirs.push_back("/Development");
+
+ for (std::vector<std::string>::const_iterator it = searchDirs.begin();
+ it != searchDirs.end(); ++it) {
+ std::string command = this->BinaryDirectory;
+ command += *it;
+ command += tmpOutputFile;
+ if (cmSystemTools::FileExists(command.c_str())) {
+ this->OutputFile = cmSystemTools::CollapseFullPath(command);
+ return;
+ }
+ }
+
+ std::ostringstream emsg;
+ emsg << "Unable to find the executable at any of:\n";
+ emsg << cmWrap(" " + this->BinaryDirectory, searchDirs, tmpOutputFile, "\n")
+ << "\n";
+ this->FindErrorMessage = emsg.str();
+ return;
+}
diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h
new file mode 100644
index 0000000..6a3b049
--- /dev/null
+++ b/Source/cmCoreTryCompile.h
@@ -0,0 +1,57 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCoreTryCompile_h
+#define cmCoreTryCompile_h
+
+#include "cmCommand.h"
+
+/** \class cmCoreTryCompile
+ * \brief Base class for cmTryCompileCommand and cmTryRunCommand
+ *
+ * cmCoreTryCompile implements the functionality to build a program.
+ * It is the base class for cmTryCompileCommand and cmTryRunCommand.
+ */
+class cmCoreTryCompile : public cmCommand
+{
+public:
+protected:
+ /**
+ * This is the core code for try compile. It is here so that other
+ * commands, such as TryRun can access the same logic without
+ * duplication.
+ */
+ int TryCompileCode(std::vector<std::string> const& argv, bool isTryRun);
+
+ /**
+ * This deletes all the files created by TryCompileCode.
+ * This way we do not have to rely on the timing and
+ * dependencies of makefiles.
+ */
+ void CleanupFiles(const char* binDir);
+
+ /**
+ * This tries to find the (executable) file created by
+ TryCompileCode. The result is stored in OutputFile. If nothing is found,
+ the error message is stored in FindErrorMessage.
+ */
+ void FindOutputFile(const std::string& targetName,
+ cmState::TargetType targetType);
+
+ cmTypeMacro(cmCoreTryCompile, cmCommand);
+
+ std::string BinaryDirectory;
+ std::string OutputFile;
+ std::string FindErrorMessage;
+ bool SrcFileSignature;
+};
+
+#endif
diff --git a/Source/cmCreateTestSourceList.cxx b/Source/cmCreateTestSourceList.cxx
new file mode 100644
index 0000000..d8c629c
--- /dev/null
+++ b/Source/cmCreateTestSourceList.cxx
@@ -0,0 +1,163 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCreateTestSourceList.h"
+
+#include "cmSourceFile.h"
+
+// cmCreateTestSourceList
+bool cmCreateTestSourceList::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 3) {
+ this->SetError("called with wrong number of arguments.");
+ return false;
+ }
+
+ std::vector<std::string>::const_iterator i = args.begin();
+ std::string extraInclude;
+ std::string function;
+ std::vector<std::string> tests;
+ // extract extra include and function ot
+ for (; i != args.end(); i++) {
+ if (*i == "EXTRA_INCLUDE") {
+ ++i;
+ if (i == args.end()) {
+ this->SetError("incorrect arguments to EXTRA_INCLUDE");
+ return false;
+ }
+ extraInclude = "#include \"";
+ extraInclude += *i;
+ extraInclude += "\"\n";
+ } else if (*i == "FUNCTION") {
+ ++i;
+ if (i == args.end()) {
+ this->SetError("incorrect arguments to FUNCTION");
+ return false;
+ }
+ function = *i;
+ function += "(&ac, &av);\n";
+ } else {
+ tests.push_back(*i);
+ }
+ }
+ i = tests.begin();
+
+ // Name of the source list
+
+ const char* sourceList = i->c_str();
+ ++i;
+
+ // Name of the test driver
+ // make sure they specified an extension
+ if (cmSystemTools::GetFilenameExtension(*i).size() < 2) {
+ this->SetError(
+ "You must specify a file extension for the test driver file.");
+ return false;
+ }
+ std::string driver = this->Makefile->GetCurrentBinaryDirectory();
+ driver += "/";
+ driver += *i;
+ ++i;
+
+ std::string configFile = cmSystemTools::GetCMakeRoot();
+
+ configFile += "/Templates/TestDriver.cxx.in";
+ // Create the test driver file
+
+ std::vector<std::string>::const_iterator testsBegin = i;
+ std::vector<std::string> tests_func_name;
+
+ // The rest of the arguments consist of a list of test source files.
+ // Sadly, they can be in directories. Let's find a unique function
+ // name for the corresponding test, and push it to the tests_func_name
+ // list.
+ // For the moment:
+ // - replace spaces ' ', ':' and '/' with underscores '_'
+ std::string forwardDeclareCode;
+ for (i = testsBegin; i != tests.end(); ++i) {
+ if (*i == "EXTRA_INCLUDE") {
+ break;
+ }
+ std::string func_name;
+ if (!cmSystemTools::GetFilenamePath(*i).empty()) {
+ func_name = cmSystemTools::GetFilenamePath(*i) + "/" +
+ cmSystemTools::GetFilenameWithoutLastExtension(*i);
+ } else {
+ func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
+ }
+ cmSystemTools::ConvertToUnixSlashes(func_name);
+ std::replace(func_name.begin(), func_name.end(), ' ', '_');
+ std::replace(func_name.begin(), func_name.end(), '/', '_');
+ std::replace(func_name.begin(), func_name.end(), ':', '_');
+ tests_func_name.push_back(func_name);
+ forwardDeclareCode += "int ";
+ forwardDeclareCode += func_name;
+ forwardDeclareCode += "(int, char*[]);\n";
+ }
+
+ std::string functionMapCode;
+ int numTests = 0;
+ std::vector<std::string>::iterator j;
+ for (i = testsBegin, j = tests_func_name.begin(); i != tests.end();
+ ++i, ++j) {
+ std::string func_name;
+ if (!cmSystemTools::GetFilenamePath(*i).empty()) {
+ func_name = cmSystemTools::GetFilenamePath(*i) + "/" +
+ cmSystemTools::GetFilenameWithoutLastExtension(*i);
+ } else {
+ func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
+ }
+ functionMapCode += " {\n"
+ " \"";
+ functionMapCode += func_name;
+ functionMapCode += "\",\n"
+ " ";
+ functionMapCode += *j;
+ functionMapCode += "\n"
+ " },\n";
+ numTests++;
+ }
+ if (!extraInclude.empty()) {
+ this->Makefile->AddDefinition("CMAKE_TESTDRIVER_EXTRA_INCLUDES",
+ extraInclude.c_str());
+ }
+ if (!function.empty()) {
+ this->Makefile->AddDefinition("CMAKE_TESTDRIVER_ARGVC_FUNCTION",
+ function.c_str());
+ }
+ this->Makefile->AddDefinition("CMAKE_FORWARD_DECLARE_TESTS",
+ forwardDeclareCode.c_str());
+ 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)) {
+ res = false;
+ }
+
+ // Construct the source list.
+ std::string sourceListValue;
+ {
+ cmSourceFile* sf = this->Makefile->GetOrCreateSource(driver);
+ sf->SetProperty("ABSTRACT", "0");
+ sourceListValue = args[1];
+ }
+ for (i = testsBegin; i != tests.end(); ++i) {
+ cmSourceFile* sf = this->Makefile->GetOrCreateSource(*i);
+ sf->SetProperty("ABSTRACT", "0");
+ sourceListValue += ";";
+ sourceListValue += *i;
+ }
+
+ this->Makefile->AddDefinition(sourceList, sourceListValue.c_str());
+ return res;
+}
diff --git a/Source/cmCreateTestSourceList.h b/Source/cmCreateTestSourceList.h
new file mode 100644
index 0000000..2025ecd
--- /dev/null
+++ b/Source/cmCreateTestSourceList.h
@@ -0,0 +1,45 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCreateTestSourceList_h
+#define cmCreateTestSourceList_h
+
+#include "cmCommand.h"
+
+/** \class cmCreateTestSourceList
+ * \brief Test driver generation command
+ *
+ */
+
+class cmCreateTestSourceList : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmCreateTestSourceList; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "create_test_sourcelist"; }
+
+ cmTypeMacro(cmCreateTestSourceList, cmCommand);
+};
+
+#endif
diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx
new file mode 100644
index 0000000..8d60c1f
--- /dev/null
+++ b/Source/cmCryptoHash.cxx
@@ -0,0 +1,123 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCryptoHash.h"
+
+#include "cm_sha2.h"
+#include <cmsys/FStream.hxx>
+#include <cmsys/MD5.h>
+
+CM_AUTO_PTR<cmCryptoHash> cmCryptoHash::New(const char* algo)
+{
+ if (strcmp(algo, "MD5") == 0) {
+ return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHashMD5);
+ } else if (strcmp(algo, "SHA1") == 0) {
+ return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHashSHA1);
+ } else if (strcmp(algo, "SHA224") == 0) {
+ return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHashSHA224);
+ } else if (strcmp(algo, "SHA256") == 0) {
+ return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHashSHA256);
+ } else if (strcmp(algo, "SHA384") == 0) {
+ return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHashSHA384);
+ } else if (strcmp(algo, "SHA512") == 0) {
+ return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHashSHA512);
+ } else {
+ return CM_AUTO_PTR<cmCryptoHash>(CM_NULLPTR);
+ }
+}
+
+std::string cmCryptoHash::HashString(const std::string& input)
+{
+ this->Initialize();
+ this->Append(reinterpret_cast<unsigned char const*>(input.c_str()),
+ static_cast<int>(input.size()));
+ return this->Finalize();
+}
+
+std::string cmCryptoHash::HashFile(const std::string& file)
+{
+ cmsys::ifstream fin(file.c_str(), std::ios::in | std::ios::binary);
+ if (!fin) {
+ return "";
+ }
+
+ this->Initialize();
+
+ // Should be efficient enough on most system:
+ cm_sha2_uint64_t buffer[512];
+ char* buffer_c = reinterpret_cast<char*>(buffer);
+ unsigned char const* buffer_uc =
+ reinterpret_cast<unsigned char const*>(buffer);
+ // This copy loop is very sensitive on certain platforms with
+ // slightly broken stream libraries (like HPUX). Normally, it is
+ // incorrect to not check the error condition on the fin.read()
+ // before using the data, but the fin.gcount() will be zero if an
+ // error occurred. Therefore, the loop should be safe everywhere.
+ while (fin) {
+ fin.read(buffer_c, sizeof(buffer));
+ if (int gcount = static_cast<int>(fin.gcount())) {
+ this->Append(buffer_uc, gcount);
+ }
+ }
+ if (fin.eof()) {
+ return this->Finalize();
+ }
+ return "";
+}
+
+cmCryptoHashMD5::cmCryptoHashMD5()
+ : MD5(cmsysMD5_New())
+{
+}
+
+cmCryptoHashMD5::~cmCryptoHashMD5()
+{
+ cmsysMD5_Delete(this->MD5);
+}
+
+void cmCryptoHashMD5::Initialize()
+{
+ cmsysMD5_Initialize(this->MD5);
+}
+
+void cmCryptoHashMD5::Append(unsigned char const* buf, int sz)
+{
+ cmsysMD5_Append(this->MD5, buf, sz);
+}
+
+std::string cmCryptoHashMD5::Finalize()
+{
+ char md5out[32];
+ cmsysMD5_FinalizeHex(this->MD5, md5out);
+ return std::string(md5out, 32);
+}
+
+#define cmCryptoHash_SHA_CLASS_IMPL(SHA) \
+ cmCryptoHash##SHA::cmCryptoHash##SHA() \
+ : SHA(new SHA_CTX) \
+ { \
+ } \
+ cmCryptoHash##SHA::~cmCryptoHash##SHA() { delete this->SHA; } \
+ void cmCryptoHash##SHA::Initialize() { SHA##_Init(this->SHA); } \
+ void cmCryptoHash##SHA::Append(unsigned char const* buf, int sz) \
+ { \
+ SHA##_Update(this->SHA, buf, sz); \
+ } \
+ std::string cmCryptoHash##SHA::Finalize() \
+ { \
+ char out[SHA##_DIGEST_STRING_LENGTH]; \
+ SHA##_End(this->SHA, out); \
+ return std::string(out, SHA##_DIGEST_STRING_LENGTH - 1); \
+ }
+
+cmCryptoHash_SHA_CLASS_IMPL(SHA1) cmCryptoHash_SHA_CLASS_IMPL(SHA224)
+ cmCryptoHash_SHA_CLASS_IMPL(SHA256) cmCryptoHash_SHA_CLASS_IMPL(SHA384)
+ cmCryptoHash_SHA_CLASS_IMPL(SHA512)
diff --git a/Source/cmCryptoHash.h b/Source/cmCryptoHash.h
new file mode 100644
index 0000000..6aaaf93
--- /dev/null
+++ b/Source/cmCryptoHash.h
@@ -0,0 +1,70 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCryptoHash_h
+#define cmCryptoHash_h
+
+#include "cmStandardIncludes.h"
+
+#include <cm_auto_ptr.hxx>
+
+class cmCryptoHash
+{
+public:
+ virtual ~cmCryptoHash() {}
+ static CM_AUTO_PTR<cmCryptoHash> New(const char* algo);
+ std::string HashString(const std::string& input);
+ std::string HashFile(const std::string& file);
+
+protected:
+ virtual void Initialize() = 0;
+ virtual void Append(unsigned char const*, int) = 0;
+ virtual std::string Finalize() = 0;
+};
+
+class cmCryptoHashMD5 : public cmCryptoHash
+{
+ struct cmsysMD5_s* MD5;
+
+public:
+ cmCryptoHashMD5();
+ ~cmCryptoHashMD5() CM_OVERRIDE;
+
+protected:
+ void Initialize() CM_OVERRIDE;
+ void Append(unsigned char const* buf, int sz) CM_OVERRIDE;
+ std::string Finalize() CM_OVERRIDE;
+};
+
+#define cmCryptoHash_SHA_CLASS_DECL(SHA) \
+ class cmCryptoHash##SHA : public cmCryptoHash \
+ { \
+ union _SHA_CTX* SHA; \
+ \
+ public: \
+ cmCryptoHash##SHA(); \
+ ~cmCryptoHash##SHA(); \
+ \
+ protected: \
+ virtual void Initialize(); \
+ virtual void Append(unsigned char const* buf, int sz); \
+ virtual std::string Finalize(); \
+ }
+
+cmCryptoHash_SHA_CLASS_DECL(SHA1);
+cmCryptoHash_SHA_CLASS_DECL(SHA224);
+cmCryptoHash_SHA_CLASS_DECL(SHA256);
+cmCryptoHash_SHA_CLASS_DECL(SHA384);
+cmCryptoHash_SHA_CLASS_DECL(SHA512);
+
+#undef cmCryptoHash_SHA_CLASS_DECL
+
+#endif
diff --git a/Source/cmCurl.cxx b/Source/cmCurl.cxx
new file mode 100644
index 0000000..5bc4f91
--- /dev/null
+++ b/Source/cmCurl.cxx
@@ -0,0 +1,62 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCurl.h"
+
+#include "cmSystemTools.h"
+
+// curl versions before 7.21.5 did not provide this error code
+#if defined(LIBCURL_VERSION_NUM) && LIBCURL_VERSION_NUM < 0x071505
+#define CURLE_NOT_BUILT_IN 4
+#endif
+
+#define check_curl_result(result, errstr) \
+ if (result != CURLE_OK && result != CURLE_NOT_BUILT_IN) { \
+ e += e.empty() ? "" : "\n"; \
+ e += errstr; \
+ e += ::curl_easy_strerror(result); \
+ }
+
+std::string cmCurlSetCAInfo(::CURL* curl, const char* cafile)
+{
+ std::string e;
+ if (cafile && *cafile) {
+ ::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_CAINFO, cafile);
+ check_curl_result(res, "Unable to set TLS/SSL Verify CAINFO: ");
+ }
+#if !defined(CMAKE_USE_SYSTEM_CURL) && !defined(_WIN32) && \
+ !defined(__APPLE__) && !defined(CURL_CA_BUNDLE) && !defined(CURL_CA_PATH)
+#define CMAKE_CAFILE_FEDORA "/etc/pki/tls/certs/ca-bundle.crt"
+ else if (cmSystemTools::FileExists(CMAKE_CAFILE_FEDORA, true)) {
+ ::CURLcode res =
+ ::curl_easy_setopt(curl, CURLOPT_CAINFO, CMAKE_CAFILE_FEDORA);
+ check_curl_result(res, "Unable to set TLS/SSL Verify CAINFO: ");
+ }
+#undef CMAKE_CAFILE_FEDORA
+ else {
+#define CMAKE_CAFILE_COMMON "/etc/ssl/certs/ca-certificates.crt"
+ if (cmSystemTools::FileExists(CMAKE_CAFILE_COMMON, true)) {
+ ::CURLcode res =
+ ::curl_easy_setopt(curl, CURLOPT_CAINFO, CMAKE_CAFILE_COMMON);
+ check_curl_result(res, "Unable to set TLS/SSL Verify CAINFO: ");
+ }
+#undef CMAKE_CAFILE_COMMON
+#define CMAKE_CAPATH_COMMON "/etc/ssl/certs"
+ if (cmSystemTools::FileIsDirectory(CMAKE_CAPATH_COMMON)) {
+ ::CURLcode res =
+ ::curl_easy_setopt(curl, CURLOPT_CAPATH, CMAKE_CAPATH_COMMON);
+ check_curl_result(res, "Unable to set TLS/SSL Verify CAPATH: ");
+ }
+#undef CMAKE_CAPATH_COMMON
+ }
+#endif
+ return e;
+}
diff --git a/Source/cmCurl.h b/Source/cmCurl.h
new file mode 100644
index 0000000..26bf94e
--- /dev/null
+++ b/Source/cmCurl.h
@@ -0,0 +1,21 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCurl_h
+#define cmCurl_h
+
+#include "cmStandardIncludes.h"
+
+#include "cm_curl.h"
+
+std::string cmCurlSetCAInfo(::CURL* curl, const char* cafile = CM_NULLPTR);
+
+#endif
diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx
new file mode 100644
index 0000000..7533369
--- /dev/null
+++ b/Source/cmCustomCommand.cxx
@@ -0,0 +1,137 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCustomCommand.h"
+
+#include "cmMakefile.h"
+
+#include <cm_auto_ptr.hxx>
+
+cmCustomCommand::cmCustomCommand()
+ : Backtrace()
+{
+ this->HaveComment = false;
+ this->EscapeOldStyle = true;
+ this->EscapeAllowMakeVars = false;
+ this->UsesTerminal = false;
+}
+
+cmCustomCommand::cmCustomCommand(cmMakefile const* mf,
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines,
+ const char* comment,
+ const char* workingDirectory)
+ : Outputs(outputs)
+ , Byproducts(byproducts)
+ , Depends(depends)
+ , CommandLines(commandLines)
+ , Backtrace()
+ , Comment(comment ? comment : "")
+ , WorkingDirectory(workingDirectory ? workingDirectory : "")
+ , HaveComment(comment != CM_NULLPTR)
+ , EscapeAllowMakeVars(false)
+ , EscapeOldStyle(true)
+{
+ if (mf) {
+ this->Backtrace = mf->GetBacktrace();
+ }
+}
+
+const std::vector<std::string>& cmCustomCommand::GetOutputs() const
+{
+ return this->Outputs;
+}
+
+const std::vector<std::string>& cmCustomCommand::GetByproducts() const
+{
+ return this->Byproducts;
+}
+
+const std::vector<std::string>& cmCustomCommand::GetDepends() const
+{
+ return this->Depends;
+}
+
+const cmCustomCommandLines& cmCustomCommand::GetCommandLines() const
+{
+ return this->CommandLines;
+}
+
+const char* cmCustomCommand::GetComment() const
+{
+ const char* no_comment = CM_NULLPTR;
+ return this->HaveComment ? this->Comment.c_str() : no_comment;
+}
+
+void cmCustomCommand::AppendCommands(const cmCustomCommandLines& commandLines)
+{
+ this->CommandLines.insert(this->CommandLines.end(), commandLines.begin(),
+ commandLines.end());
+}
+
+void cmCustomCommand::AppendDepends(const std::vector<std::string>& depends)
+{
+ this->Depends.insert(this->Depends.end(), depends.begin(), depends.end());
+}
+
+bool cmCustomCommand::GetEscapeOldStyle() const
+{
+ return this->EscapeOldStyle;
+}
+
+void cmCustomCommand::SetEscapeOldStyle(bool b)
+{
+ this->EscapeOldStyle = b;
+}
+
+bool cmCustomCommand::GetEscapeAllowMakeVars() const
+{
+ return this->EscapeAllowMakeVars;
+}
+
+void cmCustomCommand::SetEscapeAllowMakeVars(bool b)
+{
+ this->EscapeAllowMakeVars = b;
+}
+
+cmListFileBacktrace const& cmCustomCommand::GetBacktrace() const
+{
+ return this->Backtrace;
+}
+
+cmCustomCommand::ImplicitDependsList const&
+cmCustomCommand::GetImplicitDepends() const
+{
+ return this->ImplicitDepends;
+}
+
+void cmCustomCommand::SetImplicitDepends(ImplicitDependsList const& l)
+{
+ this->ImplicitDepends = l;
+}
+
+void cmCustomCommand::AppendImplicitDepends(ImplicitDependsList const& l)
+{
+ this->ImplicitDepends.insert(this->ImplicitDepends.end(), l.begin(),
+ l.end());
+}
+
+bool cmCustomCommand::GetUsesTerminal() const
+{
+ return this->UsesTerminal;
+}
+
+void cmCustomCommand::SetUsesTerminal(bool b)
+{
+ this->UsesTerminal = b;
+}
diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h
new file mode 100644
index 0000000..c2b9738
--- /dev/null
+++ b/Source/cmCustomCommand.h
@@ -0,0 +1,106 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCustomCommand_h
+#define cmCustomCommand_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmListFileCache.h"
+class cmMakefile;
+
+/** \class cmCustomCommand
+ * \brief A class to encapsulate a custom command
+ *
+ * cmCustomCommand encapsulates the properties of a custom command
+ */
+class cmCustomCommand
+{
+public:
+ /** Default and copy constructors for STL containers. */
+ cmCustomCommand();
+
+ /** Main constructor specifies all information for the command. */
+ cmCustomCommand(cmMakefile const* mf,
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines,
+ const char* comment, const char* workingDirectory);
+
+ /** Get the output file produced by the command. */
+ const std::vector<std::string>& GetOutputs() const;
+
+ /** Get the extra files produced by the command. */
+ const std::vector<std::string>& GetByproducts() const;
+
+ /** Get the vector that holds the list of dependencies. */
+ const std::vector<std::string>& GetDepends() const;
+
+ /** Get the working directory. */
+ std::string const& GetWorkingDirectory() const
+ {
+ return this->WorkingDirectory;
+ }
+
+ /** Get the list of command lines. */
+ const cmCustomCommandLines& GetCommandLines() const;
+
+ /** Get the comment string for the command. */
+ const char* GetComment() const;
+
+ /** Append to the list of command lines. */
+ void AppendCommands(const cmCustomCommandLines& commandLines);
+
+ /** Append to the list of dependencies. */
+ void AppendDepends(const std::vector<std::string>& depends);
+
+ /** Set/Get whether old-style escaping should be used. */
+ bool GetEscapeOldStyle() const;
+ void SetEscapeOldStyle(bool b);
+
+ /** Set/Get whether the build tool can replace variables in
+ arguments to the command. */
+ bool GetEscapeAllowMakeVars() const;
+ void SetEscapeAllowMakeVars(bool b);
+
+ /** Backtrace of the command that created this custom command. */
+ cmListFileBacktrace const& GetBacktrace() const;
+
+ typedef std::pair<std::string, std::string> ImplicitDependsPair;
+ class ImplicitDependsList : public std::vector<ImplicitDependsPair>
+ {
+ };
+ void SetImplicitDepends(ImplicitDependsList const&);
+ void AppendImplicitDepends(ImplicitDependsList const&);
+ ImplicitDependsList const& GetImplicitDepends() const;
+
+ /** Set/Get whether this custom command should be given access to the
+ real console (if possible). */
+ bool GetUsesTerminal() const;
+ void SetUsesTerminal(bool b);
+
+private:
+ std::vector<std::string> Outputs;
+ std::vector<std::string> Byproducts;
+ std::vector<std::string> Depends;
+ cmCustomCommandLines CommandLines;
+ cmListFileBacktrace Backtrace;
+ ImplicitDependsList ImplicitDepends;
+ std::string Comment;
+ std::string WorkingDirectory;
+ bool HaveComment;
+ bool EscapeAllowMakeVars;
+ bool EscapeOldStyle;
+ bool UsesTerminal;
+};
+
+#endif
diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
new file mode 100644
index 0000000..6165bcf
--- /dev/null
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -0,0 +1,162 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2010 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCustomCommandGenerator.h"
+
+#include "cmCustomCommand.h"
+#include "cmGeneratorExpression.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+
+cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
+ const std::string& config,
+ cmLocalGenerator* lg)
+ : CC(cc)
+ , Config(config)
+ , LG(lg)
+ , OldStyle(cc.GetEscapeOldStyle())
+ , MakeVars(cc.GetEscapeAllowMakeVars())
+ , GE(new cmGeneratorExpression(cc.GetBacktrace()))
+ , DependsDone(false)
+{
+}
+
+cmCustomCommandGenerator::~cmCustomCommandGenerator()
+{
+ delete this->GE;
+}
+
+unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const
+{
+ return static_cast<unsigned int>(this->CC.GetCommandLines().size());
+}
+
+bool cmCustomCommandGenerator::UseCrossCompilingEmulator(unsigned int c) const
+{
+ std::string const& argv0 = this->CC.GetCommandLines()[c][0];
+ cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
+ if (target && target->GetType() == cmState::EXECUTABLE) {
+ return target->GetProperty("CROSSCOMPILING_EMULATOR") != CM_NULLPTR;
+ }
+ return false;
+}
+
+std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
+{
+ std::string const& argv0 = this->CC.GetCommandLines()[c][0];
+ cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
+ if (target && target->GetType() == cmState::EXECUTABLE &&
+ (target->IsImported() ||
+ !this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING"))) {
+ return target->GetLocation(this->Config);
+ }
+ if (target && target->GetType() == cmState::EXECUTABLE) {
+ const char* emulator = target->GetProperty("CROSSCOMPILING_EMULATOR");
+ if (emulator) {
+ return std::string(emulator);
+ }
+ }
+
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = this->GE->Parse(argv0);
+ std::string exe = cge->Evaluate(this->LG, this->Config);
+
+ return exe;
+}
+
+std::string escapeForShellOldStyle(const std::string& str)
+{
+ std::string result;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // if there are spaces
+ std::string temp = str;
+ if (temp.find(" ") != std::string::npos &&
+ temp.find("\"") == std::string::npos) {
+ result = "\"";
+ result += str;
+ result += "\"";
+ return result;
+ }
+ return str;
+#else
+ for (const char* ch = str.c_str(); *ch != '\0'; ++ch) {
+ if (*ch == ' ') {
+ result += '\\';
+ }
+ result += *ch;
+ }
+ return result;
+#endif
+}
+
+void cmCustomCommandGenerator::AppendArguments(unsigned int c,
+ std::string& cmd) const
+{
+ unsigned int offset = 1;
+ if (this->UseCrossCompilingEmulator(c)) {
+ offset = 0;
+ }
+ cmCustomCommandLine const& commandLine = this->CC.GetCommandLines()[c];
+ for (unsigned int j = offset; j < commandLine.size(); ++j) {
+ std::string arg =
+ this->GE->Parse(commandLine[j])->Evaluate(this->LG, this->Config);
+ cmd += " ";
+ if (this->OldStyle) {
+ cmd += escapeForShellOldStyle(arg);
+ } else {
+ cmOutputConverter converter(this->LG->GetStateSnapshot());
+ cmd += converter.EscapeForShell(arg, this->MakeVars);
+ }
+ }
+}
+
+const char* cmCustomCommandGenerator::GetComment() const
+{
+ return this->CC.GetComment();
+}
+
+std::string cmCustomCommandGenerator::GetWorkingDirectory() const
+{
+ return this->CC.GetWorkingDirectory();
+}
+
+std::vector<std::string> const& cmCustomCommandGenerator::GetOutputs() const
+{
+ return this->CC.GetOutputs();
+}
+
+std::vector<std::string> const& cmCustomCommandGenerator::GetByproducts() const
+{
+ return this->CC.GetByproducts();
+}
+
+std::vector<std::string> const& cmCustomCommandGenerator::GetDepends() const
+{
+ if (!this->DependsDone) {
+ this->DependsDone = true;
+ std::vector<std::string> depends = this->CC.GetDepends();
+ for (std::vector<std::string>::const_iterator i = depends.begin();
+ i != depends.end(); ++i) {
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = this->GE->Parse(*i);
+ std::vector<std::string> result;
+ cmSystemTools::ExpandListArgument(cge->Evaluate(this->LG, this->Config),
+ result);
+ for (std::vector<std::string>::iterator it = result.begin();
+ it != result.end(); ++it) {
+ if (cmSystemTools::FileIsFullPath(it->c_str())) {
+ *it = cmSystemTools::CollapseFullPath(*it);
+ }
+ }
+ this->Depends.insert(this->Depends.end(), result.begin(), result.end());
+ }
+ }
+ return this->Depends;
+}
diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h
new file mode 100644
index 0000000..a361153
--- /dev/null
+++ b/Source/cmCustomCommandGenerator.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2010 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCustomCommandGenerator_h
+#define cmCustomCommandGenerator_h
+
+#include "cmStandardIncludes.h"
+
+class cmCustomCommand;
+class cmLocalGenerator;
+class cmGeneratorExpression;
+
+class cmCustomCommandGenerator
+{
+ cmCustomCommand const& CC;
+ std::string Config;
+ cmLocalGenerator* LG;
+ bool OldStyle;
+ bool MakeVars;
+ cmGeneratorExpression* GE;
+ mutable bool DependsDone;
+ mutable std::vector<std::string> Depends;
+
+public:
+ cmCustomCommandGenerator(cmCustomCommand const& cc,
+ const std::string& config, cmLocalGenerator* lg);
+ ~cmCustomCommandGenerator();
+ cmCustomCommand const& GetCC() const { return this->CC; }
+ unsigned int GetNumberOfCommands() const;
+ std::string GetCommand(unsigned int c) const;
+ bool UseCrossCompilingEmulator(unsigned int c) const;
+ void AppendArguments(unsigned int c, std::string& cmd) const;
+ const char* GetComment() const;
+ std::string GetWorkingDirectory() const;
+ std::vector<std::string> const& GetOutputs() const;
+ std::vector<std::string> const& GetByproducts() const;
+ std::vector<std::string> const& GetDepends() const;
+};
+
+#endif
diff --git a/Source/cmCustomCommandLines.h b/Source/cmCustomCommandLines.h
new file mode 100644
index 0000000..c67550e
--- /dev/null
+++ b/Source/cmCustomCommandLines.h
@@ -0,0 +1,38 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCustomCommandLines_h
+#define cmCustomCommandLines_h
+
+#include <cmConfigure.h> // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+/** Data structure to represent a single command line. */
+class cmCustomCommandLine : public std::vector<std::string>
+{
+public:
+ typedef std::vector<std::string> Superclass;
+ typedef Superclass::iterator iterator;
+ typedef Superclass::const_iterator const_iterator;
+};
+
+/** Data structure to represent a list of command lines. */
+class cmCustomCommandLines : public std::vector<cmCustomCommandLine>
+{
+public:
+ typedef std::vector<cmCustomCommandLine> Superclass;
+ typedef Superclass::iterator iterator;
+ typedef Superclass::const_iterator const_iterator;
+};
+
+#endif
diff --git a/Source/cmDefinePropertyCommand.cxx b/Source/cmDefinePropertyCommand.cxx
new file mode 100644
index 0000000..484a970
--- /dev/null
+++ b/Source/cmDefinePropertyCommand.cxx
@@ -0,0 +1,108 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmDefinePropertyCommand.h"
+
+#include "cmState.h"
+#include "cmake.h"
+
+bool cmDefinePropertyCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Get the scope in which to define the property.
+ cmProperty::ScopeType scope;
+ if (args[0] == "GLOBAL") {
+ scope = cmProperty::GLOBAL;
+ } else if (args[0] == "DIRECTORY") {
+ scope = cmProperty::DIRECTORY;
+ } else if (args[0] == "TARGET") {
+ scope = cmProperty::TARGET;
+ } else if (args[0] == "SOURCE") {
+ scope = cmProperty::SOURCE_FILE;
+ } else if (args[0] == "TEST") {
+ scope = cmProperty::TEST;
+ } else if (args[0] == "VARIABLE") {
+ scope = cmProperty::VARIABLE;
+ } else if (args[0] == "CACHED_VARIABLE") {
+ scope = cmProperty::CACHED_VARIABLE;
+ } else {
+ std::ostringstream e;
+ e << "given invalid scope " << args[0] << ". "
+ << "Valid scopes are "
+ << "GLOBAL, DIRECTORY, TARGET, SOURCE, "
+ << "TEST, VARIABLE, CACHED_VARIABLE.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Parse remaining arguments.
+ bool inherited = false;
+ enum Doing
+ {
+ DoingNone,
+ DoingProperty,
+ DoingBrief,
+ DoingFull
+ };
+ Doing doing = DoingNone;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "PROPERTY") {
+ doing = DoingProperty;
+ } else if (args[i] == "BRIEF_DOCS") {
+ doing = DoingBrief;
+ } else if (args[i] == "FULL_DOCS") {
+ doing = DoingFull;
+ } else if (args[i] == "INHERITED") {
+ doing = DoingNone;
+ inherited = true;
+ } else if (doing == DoingProperty) {
+ doing = DoingNone;
+ this->PropertyName = args[i];
+ } else if (doing == DoingBrief) {
+ this->BriefDocs += args[i];
+ } else if (doing == DoingFull) {
+ this->FullDocs += args[i];
+ } else {
+ std::ostringstream e;
+ e << "given invalid argument \"" << args[i] << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ // Make sure a property name was found.
+ if (this->PropertyName.empty()) {
+ this->SetError("not given a PROPERTY <name> argument.");
+ return false;
+ }
+
+ // Make sure documentation was given.
+ if (this->BriefDocs.empty()) {
+ this->SetError("not given a BRIEF_DOCS <brief-doc> argument.");
+ return false;
+ }
+ if (this->FullDocs.empty()) {
+ this->SetError("not given a FULL_DOCS <full-doc> argument.");
+ return false;
+ }
+
+ // Actually define the property.
+ this->Makefile->GetState()->DefineProperty(
+ this->PropertyName, scope, this->BriefDocs.c_str(), this->FullDocs.c_str(),
+ inherited);
+
+ return true;
+}
diff --git a/Source/cmDefinePropertyCommand.h b/Source/cmDefinePropertyCommand.h
new file mode 100644
index 0000000..9cc19c4
--- /dev/null
+++ b/Source/cmDefinePropertyCommand.h
@@ -0,0 +1,42 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmDefinesPropertyCommand_h
+#define cmDefinesPropertyCommand_h
+
+#include "cmCommand.h"
+
+class cmDefinePropertyCommand : public cmCommand
+{
+public:
+ cmCommand* Clone() CM_OVERRIDE { return new cmDefinePropertyCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "define_property"; }
+
+ cmTypeMacro(cmDefinePropertyCommand, cmCommand);
+
+private:
+ std::string PropertyName;
+ std::string BriefDocs;
+ std::string FullDocs;
+};
+
+#endif
diff --git a/Source/cmDefinitions.cxx b/Source/cmDefinitions.cxx
new file mode 100644
index 0000000..e0fb59b
--- /dev/null
+++ b/Source/cmDefinitions.cxx
@@ -0,0 +1,125 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmDefinitions.h"
+
+#include <assert.h>
+
+cmDefinitions::Def cmDefinitions::NoDef;
+
+cmDefinitions::Def const& cmDefinitions::GetInternal(const std::string& key,
+ StackIter begin,
+ StackIter end, bool raise)
+{
+ assert(begin != end);
+ MapType::iterator i = begin->Map.find(key);
+ if (i != begin->Map.end()) {
+ i->second.Used = true;
+ return i->second;
+ }
+ StackIter it = begin;
+ ++it;
+ if (it == end) {
+ return cmDefinitions::NoDef;
+ }
+ Def const& def = cmDefinitions::GetInternal(key, it, end, raise);
+ if (!raise) {
+ return def;
+ }
+ return begin->Map.insert(MapType::value_type(key, def)).first->second;
+}
+
+const char* cmDefinitions::Get(const std::string& key, StackIter begin,
+ StackIter end)
+{
+ Def const& def = cmDefinitions::GetInternal(key, begin, end, false);
+ return def.Exists ? def.c_str() : CM_NULLPTR;
+}
+
+void cmDefinitions::Raise(const std::string& key, StackIter begin,
+ StackIter end)
+{
+ cmDefinitions::GetInternal(key, begin, end, true);
+}
+
+bool cmDefinitions::HasKey(const std::string& key, StackIter begin,
+ StackIter end)
+{
+ for (StackIter it = begin; it != end; ++it) {
+ MapType::const_iterator i = it->Map.find(key);
+ if (i != it->Map.end()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmDefinitions::Set(const std::string& key, const char* value)
+{
+ Def def(value);
+ this->Map[key] = def;
+}
+
+std::vector<std::string> cmDefinitions::UnusedKeys() const
+{
+ std::vector<std::string> keys;
+ keys.reserve(this->Map.size());
+ // Consider local definitions.
+ for (MapType::const_iterator mi = this->Map.begin(); mi != this->Map.end();
+ ++mi) {
+ if (!mi->second.Used) {
+ keys.push_back(mi->first);
+ }
+ }
+ return keys;
+}
+
+cmDefinitions cmDefinitions::MakeClosure(StackIter begin, StackIter end)
+{
+ cmDefinitions closure;
+ std::set<std::string> undefined;
+ for (StackIter it = begin; it != end; ++it) {
+ // Consider local definitions.
+ for (MapType::const_iterator mi = it->Map.begin(); mi != it->Map.end();
+ ++mi) {
+ // Use this key if it is not already set or unset.
+ if (closure.Map.find(mi->first) == closure.Map.end() &&
+ undefined.find(mi->first) == undefined.end()) {
+ if (mi->second.Exists) {
+ closure.Map.insert(*mi);
+ } else {
+ undefined.insert(mi->first);
+ }
+ }
+ }
+ }
+ return closure;
+}
+
+std::vector<std::string> cmDefinitions::ClosureKeys(StackIter begin,
+ StackIter end)
+{
+ std::set<std::string> bound;
+ std::vector<std::string> defined;
+
+ for (StackIter it = begin; it != end; ++it) {
+ defined.reserve(defined.size() + it->Map.size());
+ for (MapType::const_iterator mi = it->Map.begin(); mi != it->Map.end();
+ ++mi) {
+ // Use this key if it is not already set or unset.
+ if (bound.insert(mi->first).second && mi->second.Exists) {
+ defined.push_back(mi->first);
+ }
+ }
+ }
+
+ return defined;
+}
diff --git a/Source/cmDefinitions.h b/Source/cmDefinitions.h
new file mode 100644
index 0000000..8f1813c
--- /dev/null
+++ b/Source/cmDefinitions.h
@@ -0,0 +1,109 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmDefinitions_h
+#define cmDefinitions_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmLinkedTree.h"
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+#include <unordered_map>
+#else
+#include "cmsys/hash_map.hxx"
+#endif
+#endif
+
+#include <list>
+
+/** \class cmDefinitions
+ * \brief Store a scope of variable definitions for CMake language.
+ *
+ * This stores the state of variable definitions (set or unset) for
+ * one scope. Sets are always local. Gets search parent scopes
+ * transitively and save results locally.
+ */
+class cmDefinitions
+{
+ typedef cmLinkedTree<cmDefinitions>::iterator StackIter;
+
+public:
+ static const char* Get(const std::string& key, StackIter begin,
+ StackIter end);
+
+ static void Raise(const std::string& key, StackIter begin, StackIter end);
+
+ static bool HasKey(const std::string& key, StackIter begin, StackIter end);
+
+ /** Set (or unset if null) a value associated with a key. */
+ void Set(const std::string& key, const char* value);
+
+ std::vector<std::string> UnusedKeys() const;
+
+ static std::vector<std::string> ClosureKeys(StackIter begin, StackIter end);
+
+ static cmDefinitions MakeClosure(StackIter begin, StackIter end);
+
+private:
+ // String with existence boolean.
+ struct Def : public std::string
+ {
+ private:
+ typedef std::string std_string;
+
+ public:
+ Def()
+ : std_string()
+ , Exists(false)
+ , Used(false)
+ {
+ }
+ Def(const char* v)
+ : std_string(v ? v : "")
+ , Exists(v ? true : false)
+ , Used(false)
+ {
+ }
+ Def(const std_string& v)
+ : std_string(v)
+ , Exists(true)
+ , Used(false)
+ {
+ }
+ Def(Def const& d)
+ : std_string(d)
+ , Exists(d.Exists)
+ , Used(d.Used)
+ {
+ }
+ bool Exists;
+ bool Used;
+ };
+ static Def NoDef;
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+ typedef std::unordered_map<std::string, Def> MapType;
+#else
+ typedef cmsys::hash_map<std::string, Def> MapType;
+#endif
+#else
+ typedef std::map<std::string, Def> MapType;
+#endif
+ MapType Map;
+
+ static Def const& GetInternal(const std::string& key, StackIter begin,
+ StackIter end, bool raise);
+};
+
+#endif
diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx
new file mode 100644
index 0000000..b25e3ce
--- /dev/null
+++ b/Source/cmDepends.cxx
@@ -0,0 +1,282 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmDepends.h"
+
+#include "cmFileTimeComparison.h"
+#include "cmGeneratedFileStream.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include <cmsys/FStream.hxx>
+#include <string.h>
+
+cmDepends::cmDepends(cmLocalGenerator* lg, const char* targetDir)
+ : CompileDirectory()
+ , LocalGenerator(lg)
+ , Verbose(false)
+ , FileComparison(CM_NULLPTR)
+ , TargetDirectory(targetDir)
+ , MaxPath(16384)
+ , Dependee(new char[MaxPath])
+ , Depender(new char[MaxPath])
+{
+}
+
+cmDepends::~cmDepends()
+{
+ delete[] this->Dependee;
+ delete[] this->Depender;
+}
+
+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();
+ const char* 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;
+ }
+ std::string const& obj = *si++;
+ dependencies[obj].insert(src);
+ }
+ for (std::map<std::string, std::set<std::string> >::const_iterator it =
+ dependencies.begin();
+ it != dependencies.end(); ++it) {
+
+ // Write the dependencies for this pair.
+ if (!this->WriteDependencies(it->second, it->first, makeDepends,
+ internalDepends)) {
+ return false;
+ }
+ }
+
+ return this->Finalize(makeDepends, internalDepends);
+}
+
+bool cmDepends::Finalize(std::ostream&, std::ostream&)
+{
+ return true;
+}
+
+bool cmDepends::Check(const char* makeFile, const char* internalFile,
+ std::map<std::string, DependencyVector>& validDeps)
+{
+ // Dependency checks must be done in proper working directory.
+ std::string oldcwd = ".";
+ if (this->CompileDirectory != ".") {
+ // Get the CWD but do not call CollapseFullPath because
+ // we only need it to cd back, and the form does not matter
+ oldcwd = cmSystemTools::GetCurrentWorkingDirectory(false);
+ cmSystemTools::ChangeDirectory(this->CompileDirectory);
+ }
+
+ // Check whether dependencies must be regenerated.
+ bool okay = true;
+ cmsys::ifstream fin(internalFile);
+ if (!(fin && this->CheckDependencies(fin, internalFile, validDeps))) {
+ // Clear all dependencies so they will be regenerated.
+ this->Clear(makeFile);
+ cmSystemTools::RemoveFile(internalFile);
+ okay = false;
+ }
+
+ // Restore working directory.
+ if (oldcwd != ".") {
+ cmSystemTools::ChangeDirectory(oldcwd);
+ }
+
+ return okay;
+}
+
+void cmDepends::Clear(const char* file)
+{
+ // Print verbose output.
+ if (this->Verbose) {
+ std::ostringstream msg;
+ msg << "Clearing dependencies in \"" << file << "\"." << std::endl;
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+
+ // Write an empty dependency file.
+ cmGeneratedFileStream depFileStream(file);
+ depFileStream << "# Empty dependencies file\n"
+ << "# This may be replaced when dependencies are built."
+ << std::endl;
+}
+
+bool cmDepends::WriteDependencies(const std::set<std::string>&,
+ const std::string&, std::ostream&,
+ std::ostream&)
+{
+ // This should be implemented by the subclass.
+ return false;
+}
+
+bool cmDepends::CheckDependencies(
+ std::istream& internalDepends, const char* internalDependsFileName,
+ std::map<std::string, DependencyVector>& validDeps)
+{
+ // 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 = CM_NULLPTR;
+
+ while (internalDepends.getline(this->Dependee, this->MaxPath)) {
+ if (this->Dependee[0] == 0 || this->Dependee[0] == '#' ||
+ this->Dependee[0] == '\r') {
+ continue;
+ }
+ size_t len = internalDepends.gcount() - 1;
+ if (this->Dependee[len - 1] == '\r') {
+ len--;
+ this->Dependee[len] = 0;
+ }
+ 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);
+ // 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];
+ continue;
+ }
+ /*
+ // Parse the dependency line.
+ if(!this->ParseDependency(line.c_str()))
+ {
+ continue;
+ }
+ */
+
+ // Dependencies must be regenerated
+ // * if the dependee does not exist
+ // * if the depender exists and is older than the dependee.
+ // * if the depender does not exist, but the dependee is newer than the
+ // depends file
+ bool regenerate = false;
+ const char* dependee = this->Dependee + 1;
+ const char* depender = this->Depender;
+ if (currentDependencies != CM_NULLPTR) {
+ currentDependencies->push_back(dependee);
+ }
+
+ if (!cmSystemTools::FileExists(dependee)) {
+ // The dependee does not exist.
+ regenerate = true;
+
+ // Print verbose output.
+ if (this->Verbose) {
+ std::ostringstream msg;
+ msg << "Dependee \"" << dependee << "\" does not exist for depender \""
+ << depender << "\"." << std::endl;
+ cmSystemTools::Stdout(msg.str().c_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().c_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().c_str());
+ }
+ }
+ }
+ }
+ if (regenerate) {
+ // Dependencies must be regenerated.
+ okay = false;
+
+ // Remove the information of this depender from the map, it needs
+ // to be rescanned
+ if (currentDependencies != CM_NULLPTR) {
+ validDeps.erase(this->Depender);
+ currentDependencies = CM_NULLPTR;
+ }
+
+ // Remove the depender to be sure it is rebuilt.
+ if (dependerExists) {
+ cmSystemTools::RemoveFile(depender);
+ dependerExists = false;
+ }
+ }
+ }
+
+ return okay;
+}
+
+void cmDepends::SetIncludePathFromLanguage(const std::string& lang)
+{
+ // Look for the new per "TARGET_" variant first:
+ const char* includePath = CM_NULLPTR;
+ std::string includePathVar = "CMAKE_";
+ includePathVar += lang;
+ includePathVar += "_TARGET_INCLUDE_PATH";
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ includePath = mf->GetDefinition(includePathVar);
+ if (includePath) {
+ cmSystemTools::ExpandListArgument(includePath, this->IncludePath);
+ } else {
+ // Fallback to the old directory level variable if no per-target var:
+ includePathVar = "CMAKE_";
+ includePathVar += lang;
+ includePathVar += "_INCLUDE_PATH";
+ includePath = mf->GetDefinition(includePathVar);
+ if (includePath) {
+ cmSystemTools::ExpandListArgument(includePath, this->IncludePath);
+ }
+ }
+}
diff --git a/Source/cmDepends.h b/Source/cmDepends.h
new file mode 100644
index 0000000..0e1cbb9
--- /dev/null
+++ b/Source/cmDepends.h
@@ -0,0 +1,127 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmDepends_h
+#define cmDepends_h
+
+#include "cmStandardIncludes.h"
+
+class cmFileTimeComparison;
+class cmLocalGenerator;
+
+/** \class cmDepends
+ * \brief Dependency scanner superclass.
+ *
+ * This class is responsible for maintaining a .depends.make file in
+ * the build tree corresponding to an object file. Subclasses help it
+ * maintain dependencies for particular languages.
+ */
+class cmDepends
+{
+public:
+ /** Instances need to know the build directory name and the relative
+ path from the build directory to the target file. */
+ cmDepends(cmLocalGenerator* lg = CM_NULLPTR, const char* targetDir = "");
+
+ /** at what level will the compile be done from */
+ void SetCompileDirectory(const char* dir) { this->CompileDirectory = dir; }
+
+ /** Set the local generator for the directory in which we are
+ scanning dependencies. This is not a full local generator; it
+ has been setup to do relative path conversions for the current
+ directory. */
+ void SetLocalGenerator(cmLocalGenerator* lg) { this->LocalGenerator = lg; }
+
+ /** Set the specific language to be scanned. */
+ void SetLanguage(const std::string& lang) { this->Language = lang; }
+
+ /** Set the target build directory. */
+ void SetTargetDirectory(const char* dir) { this->TargetDirectory = dir; }
+
+ /** should this be verbose in its output */
+ void SetVerbose(bool verb) { this->Verbose = verb; }
+
+ /** Virtual destructor to cleanup subclasses properly. */
+ virtual ~cmDepends();
+
+ /** 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 char* makeFile, const char* internalFile,
+ std::map<std::string, DependencyVector>& validDeps);
+
+ /** Clear dependencies for the target file so they will be regenerated. */
+ void Clear(const char* file);
+
+ /** Set the file comparison object */
+ void SetFileComparison(cmFileTimeComparison* fc)
+ {
+ this->FileComparison = fc;
+ }
+
+protected:
+ // Write dependencies for the target file to the given stream.
+ // Return true for success and false for failure.
+ virtual bool WriteDependencies(const std::set<std::string>& sources,
+ const std::string& obj,
+ std::ostream& makeDepends,
+ std::ostream& internalDepends);
+
+ // 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 char* internalDependsFileName,
+ std::map<std::string, DependencyVector>& validDeps);
+
+ // Finalize the dependency information for the target.
+ virtual bool Finalize(std::ostream& makeDepends,
+ std::ostream& internalDepends);
+
+ // The directory in which the build rule for the target file is executed.
+ std::string CompileDirectory;
+
+ // The local generator.
+ cmLocalGenerator* LocalGenerator;
+
+ // Flag for verbose output.
+ bool Verbose;
+ cmFileTimeComparison* FileComparison;
+
+ std::string Language;
+
+ // The full path to the target's build directory.
+ std::string TargetDirectory;
+
+ size_t MaxPath;
+ char* Dependee;
+ char* Depender;
+
+ // The include file search path.
+ std::vector<std::string> IncludePath;
+
+ void SetIncludePathFromLanguage(const std::string& lang);
+
+private:
+ cmDepends(cmDepends const&); // Purposely not implemented.
+ void operator=(cmDepends const&); // Purposely not implemented.
+};
+
+#endif
diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx
new file mode 100644
index 0000000..18e123e
--- /dev/null
+++ b/Source/cmDependsC.cxx
@@ -0,0 +1,495 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmDependsC.h"
+
+#include "cmAlgorithms.h"
+#include "cmFileTimeComparison.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include <cmsys/FStream.hxx>
+
+#include <ctype.h> // isspace
+
+#define INCLUDE_REGEX_LINE \
+ "^[ \t]*#[ \t]*(include|import)[ \t]*[<\"]([^\">]+)([\">])"
+
+#define INCLUDE_REGEX_LINE_MARKER "#IncludeRegexLine: "
+#define INCLUDE_REGEX_SCAN_MARKER "#IncludeRegexScan: "
+#define INCLUDE_REGEX_COMPLAIN_MARKER "#IncludeRegexComplain: "
+#define INCLUDE_REGEX_TRANSFORM_MARKER "#IncludeRegexTransform: "
+
+cmDependsC::cmDependsC()
+ : ValidDeps(CM_NULLPTR)
+{
+}
+
+cmDependsC::cmDependsC(
+ cmLocalGenerator* lg, const char* targetDir, const std::string& lang,
+ const std::map<std::string, DependencyVector>* validDeps)
+ : cmDepends(lg, targetDir)
+ , ValidDeps(validDeps)
+{
+ cmMakefile* mf = lg->GetMakefile();
+
+ // Configure the include file search path.
+ this->SetIncludePathFromLanguage(lang);
+
+ // Configure regular expressions.
+ std::string scanRegex = "^.*$";
+ std::string complainRegex = "^$";
+ {
+ std::string scanRegexVar = "CMAKE_";
+ scanRegexVar += lang;
+ scanRegexVar += "_INCLUDE_REGEX_SCAN";
+ if (const char* sr = mf->GetDefinition(scanRegexVar)) {
+ scanRegex = sr;
+ }
+ std::string complainRegexVar = "CMAKE_";
+ complainRegexVar += lang;
+ complainRegexVar += "_INCLUDE_REGEX_COMPLAIN";
+ if (const char* cr = mf->GetDefinition(complainRegexVar)) {
+ complainRegex = cr;
+ }
+ }
+
+ this->IncludeRegexLine.compile(INCLUDE_REGEX_LINE);
+ this->IncludeRegexScan.compile(scanRegex.c_str());
+ this->IncludeRegexComplain.compile(complainRegex.c_str());
+ this->IncludeRegexLineString = INCLUDE_REGEX_LINE_MARKER INCLUDE_REGEX_LINE;
+ this->IncludeRegexScanString = INCLUDE_REGEX_SCAN_MARKER;
+ this->IncludeRegexScanString += scanRegex;
+ this->IncludeRegexComplainString = INCLUDE_REGEX_COMPLAIN_MARKER;
+ this->IncludeRegexComplainString += complainRegex;
+
+ this->SetupTransforms();
+
+ this->CacheFileName = this->TargetDirectory;
+ this->CacheFileName += "/";
+ this->CacheFileName += lang;
+ this->CacheFileName += ".includecache";
+
+ this->ReadCacheFile();
+}
+
+cmDependsC::~cmDependsC()
+{
+ this->WriteCacheFile();
+ cmDeleteAll(this->FileCache);
+}
+
+bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
+ const std::string& obj,
+ std::ostream& makeDepends,
+ std::ostream& internalDepends)
+{
+ // Make sure this is a scanning instance.
+ if (sources.empty() || sources.begin()->empty()) {
+ cmSystemTools::Error("Cannot scan dependencies without a source file.");
+ return false;
+ }
+ if (obj.empty()) {
+ cmSystemTools::Error("Cannot scan dependencies without an object file.");
+ return false;
+ }
+
+ std::set<std::string> dependencies;
+ bool haveDeps = false;
+
+ if (this->ValidDeps != CM_NULLPTR) {
+ std::map<std::string, DependencyVector>::const_iterator tmpIt =
+ this->ValidDeps->find(obj);
+ if (tmpIt != this->ValidDeps->end()) {
+ dependencies.insert(tmpIt->second.begin(), tmpIt->second.end());
+ haveDeps = true;
+ }
+ }
+
+ if (!haveDeps) {
+ // Walk the dependency graph starting with the source file.
+ int srcFiles = (int)sources.size();
+ this->Encountered.clear();
+
+ for (std::set<std::string>::const_iterator srcIt = sources.begin();
+ srcIt != sources.end(); ++srcIt) {
+ UnscannedEntry root;
+ root.FileName = *srcIt;
+ this->Unscanned.push(root);
+ this->Encountered.insert(*srcIt);
+ }
+
+ 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();
+ this->Unscanned.pop();
+
+ // If not a full path, find the file in the include path.
+ std::string fullName;
+ if ((srcFiles > 0) ||
+ cmSystemTools::FileIsFullPath(current.FileName.c_str())) {
+ if (cmSystemTools::FileExists(current.FileName.c_str(), true)) {
+ fullName = current.FileName;
+ }
+ } else if (!current.QuotedLocation.empty() &&
+ cmSystemTools::FileExists(current.QuotedLocation.c_str(),
+ true)) {
+ // The include statement producing this entry was a double-quote
+ // include and the included file is present in the directory of
+ // the source containing the include statement.
+ fullName = current.QuotedLocation;
+ } else {
+ std::map<std::string, std::string>::iterator headerLocationIt =
+ this->HeaderLocationCache.find(current.FileName);
+ if (headerLocationIt != this->HeaderLocationCache.end()) {
+ fullName = headerLocationIt->second;
+ } else {
+ for (std::vector<std::string>::const_iterator i =
+ this->IncludePath.begin();
+ i != this->IncludePath.end(); ++i) {
+ // 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);
+
+ // Look for the file in this location.
+ if (cmSystemTools::FileExists(tempPathStr.c_str(), true)) {
+ fullName = tempPathStr;
+ HeaderLocationCache[current.FileName] = fullName;
+ break;
+ }
+ }
+ }
+ }
+
+ // Complain if the file cannot be found and matches the complain
+ // regex.
+ if (fullName.empty() &&
+ this->IncludeRegexComplain.find(current.FileName.c_str())) {
+ cmSystemTools::Error("Cannot find file \"", current.FileName.c_str(),
+ "\".");
+ return false;
+ }
+
+ // Scan the file if it was found and has not been scanned already.
+ if (!fullName.empty() && (scanned.find(fullName) == scanned.end())) {
+ // Record scanned files.
+ scanned.insert(fullName);
+
+ // Check whether this file is already in the cache
+ std::map<std::string, cmIncludeLines*>::iterator fileIt =
+ this->FileCache.find(fullName);
+ if (fileIt != this->FileCache.end()) {
+ fileIt->second->Used = true;
+ dependencies.insert(fullName);
+ for (std::vector<UnscannedEntry>::const_iterator incIt =
+ fileIt->second->UnscannedEntries.begin();
+ incIt != fileIt->second->UnscannedEntries.end(); ++incIt) {
+ if (this->Encountered.find(incIt->FileName) ==
+ this->Encountered.end()) {
+ this->Encountered.insert(incIt->FileName);
+ this->Unscanned.push(*incIt);
+ }
+ }
+ } else {
+
+ // Try to scan the file. Just leave it out if we cannot find
+ // it.
+ cmsys::ifstream fin(fullName.c_str());
+ if (fin) {
+ cmsys::FStream::BOM bom = cmsys::FStream::ReadBOM(fin);
+ if (bom == cmsys::FStream::BOM_None ||
+ bom == cmsys::FStream::BOM_UTF8) {
+ // Add this file as a dependency.
+ dependencies.insert(fullName);
+
+ // Scan this file for new dependencies. Pass the directory
+ // containing the file to handle double-quote includes.
+ std::string dir = cmSystemTools::GetFilenamePath(fullName);
+ this->Scan(fin, dir.c_str(), fullName);
+ } else {
+ // Skip file with encoding we do not implement.
+ }
+ }
+ }
+ }
+
+ srcFiles--;
+ }
+ }
+
+ // Write the dependencies to the output stream. Makefile rules
+ // written by the original local generator for this directory
+ // convert the dependencies to paths relative to the home output
+ // directory. We must do the same here.
+ std::string obj_i =
+ this->LocalGenerator->Convert(obj, cmOutputConverter::HOME_OUTPUT);
+ std::string obj_m = this->LocalGenerator->ConvertToOutputFormat(
+ obj_i, cmOutputConverter::MAKERULE);
+ internalDepends << obj_i << std::endl;
+
+ for (std::set<std::string>::const_iterator i = dependencies.begin();
+ i != dependencies.end(); ++i) {
+ makeDepends << obj_m << ": "
+ << this->LocalGenerator->Convert(
+ *i, cmOutputConverter::HOME_OUTPUT,
+ cmOutputConverter::MAKERULE)
+ << std::endl;
+ internalDepends << " " << *i << std::endl;
+ }
+ makeDepends << std::endl;
+
+ return true;
+}
+
+void cmDependsC::ReadCacheFile()
+{
+ if (this->CacheFileName.empty()) {
+ return;
+ }
+ cmsys::ifstream fin(this->CacheFileName.c_str());
+ if (!fin) {
+ return;
+ }
+
+ std::string line;
+ cmIncludeLines* cacheEntry = CM_NULLPTR;
+ bool haveFileName = false;
+
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (line.empty()) {
+ cacheEntry = CM_NULLPTR;
+ haveFileName = false;
+ continue;
+ }
+ // 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.c_str(),
+ line.c_str(), &newer);
+
+ if (res && newer == 1) // cache is newer than the parsed file
+ {
+ cacheEntry = new cmIncludeLines;
+ this->FileCache[line] = cacheEntry;
+ }
+ // file doesn't exist, check that the regular expressions
+ // haven't changed
+ else if (!res) {
+ if (line.find(INCLUDE_REGEX_LINE_MARKER) == 0) {
+ if (line != this->IncludeRegexLineString) {
+ return;
+ }
+ } else if (line.find(INCLUDE_REGEX_SCAN_MARKER) == 0) {
+ if (line != this->IncludeRegexScanString) {
+ return;
+ }
+ } else if (line.find(INCLUDE_REGEX_COMPLAIN_MARKER) == 0) {
+ if (line != this->IncludeRegexComplainString) {
+ return;
+ }
+ } else if (line.find(INCLUDE_REGEX_TRANSFORM_MARKER) == 0) {
+ if (line != this->IncludeRegexTransformString) {
+ return;
+ }
+ }
+ }
+ } else if (cacheEntry != CM_NULLPTR) {
+ UnscannedEntry entry;
+ entry.FileName = line;
+ if (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (line != "-") {
+ entry.QuotedLocation = line;
+ }
+ cacheEntry->UnscannedEntries.push_back(entry);
+ }
+ }
+ }
+}
+
+void cmDependsC::WriteCacheFile() const
+{
+ if (this->CacheFileName.empty()) {
+ return;
+ }
+ cmsys::ofstream cacheOut(this->CacheFileName.c_str());
+ if (!cacheOut) {
+ return;
+ }
+
+ cacheOut << this->IncludeRegexLineString << "\n\n";
+ cacheOut << this->IncludeRegexScanString << "\n\n";
+ cacheOut << this->IncludeRegexComplainString << "\n\n";
+ cacheOut << this->IncludeRegexTransformString << "\n\n";
+
+ for (std::map<std::string, cmIncludeLines*>::const_iterator fileIt =
+ this->FileCache.begin();
+ fileIt != this->FileCache.end(); ++fileIt) {
+ if (fileIt->second->Used) {
+ cacheOut << fileIt->first << std::endl;
+
+ for (std::vector<UnscannedEntry>::const_iterator incIt =
+ fileIt->second->UnscannedEntries.begin();
+ incIt != fileIt->second->UnscannedEntries.end(); ++incIt) {
+ cacheOut << incIt->FileName << std::endl;
+ if (incIt->QuotedLocation.empty()) {
+ cacheOut << "-" << std::endl;
+ } else {
+ cacheOut << incIt->QuotedLocation << std::endl;
+ }
+ }
+ cacheOut << std::endl;
+ }
+ }
+}
+
+void cmDependsC::Scan(std::istream& is, const char* directory,
+ const std::string& fullName)
+{
+ cmIncludeLines* newCacheEntry = new cmIncludeLines;
+ newCacheEntry->Used = true;
+ this->FileCache[fullName] = newCacheEntry;
+
+ // Read one line at a time.
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(is, line)) {
+ // Transform the line content first.
+ if (!this->TransformRules.empty()) {
+ this->TransformLine(line);
+ }
+
+ // Match include directives.
+ if (this->IncludeRegexLine.find(line.c_str())) {
+ // Get the file being included.
+ UnscannedEntry entry;
+ entry.FileName = this->IncludeRegexLine.match(2);
+ cmSystemTools::ConvertToUnixSlashes(entry.FileName);
+ if (this->IncludeRegexLine.match(3) == "\"" &&
+ !cmSystemTools::FileIsFullPath(entry.FileName.c_str())) {
+ // This was a double-quoted include with a relative path. We
+ // must check for the file in the directory containing the
+ // file we are scanning.
+ entry.QuotedLocation =
+ cmSystemTools::CollapseCombinedPath(directory, entry.FileName);
+ }
+
+ // Queue the file if it has not yet been encountered and it
+ // matches the regular expression for recursive scanning. Note
+ // that this check does not account for the possibility of two
+ // headers with the same name in different directories when one
+ // is included by double-quotes and the other by angle brackets.
+ // It also does not work properly if two header files with the same
+ // name exist in different directories, and both are included from a
+ // file their own directory by simply using "filename.h" (#12619)
+ // This kind of problem will be fixed when a more
+ // preprocessor-like implementation of this scanner is created.
+ if (this->IncludeRegexScan.find(entry.FileName.c_str())) {
+ newCacheEntry->UnscannedEntries.push_back(entry);
+ if (this->Encountered.find(entry.FileName) ==
+ this->Encountered.end()) {
+ this->Encountered.insert(entry.FileName);
+ this->Unscanned.push(entry);
+ }
+ }
+ }
+ }
+}
+
+void cmDependsC::SetupTransforms()
+{
+ // Get the transformation rules.
+ std::vector<std::string> transformRules;
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ if (const char* xform = mf->GetDefinition("CMAKE_INCLUDE_TRANSFORMS")) {
+ cmSystemTools::ExpandListArgument(xform, transformRules, true);
+ }
+ for (std::vector<std::string>::const_iterator tri = transformRules.begin();
+ tri != transformRules.end(); ++tri) {
+ this->ParseTransform(*tri);
+ }
+
+ this->IncludeRegexTransformString = INCLUDE_REGEX_TRANSFORM_MARKER;
+ if (!this->TransformRules.empty()) {
+ // Construct the regular expression to match lines to be
+ // transformed.
+ std::string xform = "^([ \t]*#[ \t]*(include|import)[ \t]*)(";
+ const char* sep = "";
+ for (TransformRulesType::const_iterator tri = this->TransformRules.begin();
+ tri != this->TransformRules.end(); ++tri) {
+ xform += sep;
+ xform += tri->first;
+ sep = "|";
+ }
+ xform += ")[ \t]*\\(([^),]*)\\)";
+ this->IncludeRegexTransform.compile(xform.c_str());
+
+ // Build a string that encodes all transformation rules and will
+ // change when rules are changed.
+ this->IncludeRegexTransformString += xform;
+ for (TransformRulesType::const_iterator tri = this->TransformRules.begin();
+ tri != this->TransformRules.end(); ++tri) {
+ this->IncludeRegexTransformString += " ";
+ this->IncludeRegexTransformString += tri->first;
+ this->IncludeRegexTransformString += "(%)=";
+ this->IncludeRegexTransformString += tri->second;
+ }
+ }
+}
+
+void cmDependsC::ParseTransform(std::string const& xform)
+{
+ // A transform rule is of the form SOME_MACRO(%)=value-with-%
+ // We can simply separate with "(%)=".
+ std::string::size_type pos = xform.find("(%)=");
+ if (pos == xform.npos || pos == 0) {
+ return;
+ }
+ std::string name = xform.substr(0, pos);
+ std::string value = xform.substr(pos + 4, xform.npos);
+ this->TransformRules[name] = value;
+}
+
+void cmDependsC::TransformLine(std::string& line)
+{
+ // Check for a transform rule match. Return if none.
+ if (!this->IncludeRegexTransform.find(line.c_str())) {
+ return;
+ }
+ TransformRulesType::const_iterator tri =
+ this->TransformRules.find(this->IncludeRegexTransform.match(3));
+ if (tri == this->TransformRules.end()) {
+ return;
+ }
+
+ // Construct the transformed line.
+ std::string newline = this->IncludeRegexTransform.match(1);
+ std::string arg = this->IncludeRegexTransform.match(4);
+ for (const char* c = tri->second.c_str(); *c; ++c) {
+ if (*c == '%') {
+ newline += arg;
+ } else {
+ newline += *c;
+ }
+ }
+
+ // Return the transformed line.
+ line = newline;
+}
diff --git a/Source/cmDependsC.h b/Source/cmDependsC.h
new file mode 100644
index 0000000..bde07b7
--- /dev/null
+++ b/Source/cmDependsC.h
@@ -0,0 +1,102 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmDependsC_h
+#define cmDependsC_h
+
+#include "cmDepends.h"
+
+#include <cmsys/RegularExpression.hxx>
+#include <queue>
+
+/** \class cmDependsC
+ * \brief Dependency scanner for C and C++ object files.
+ */
+class cmDependsC : public cmDepends
+{
+public:
+ /** Checking instances need to know the build directory name and the
+ relative path from the build directory to the target file. */
+ cmDependsC();
+ cmDependsC(cmLocalGenerator* lg, const char* targetDir,
+ const std::string& lang,
+ const std::map<std::string, DependencyVector>* validDeps);
+
+ /** Virtual destructor to cleanup subclasses properly. */
+ ~cmDependsC() CM_OVERRIDE;
+
+protected:
+ // Implement writing/checking methods required by superclass.
+ bool WriteDependencies(const std::set<std::string>& sources,
+ const std::string& obj, std::ostream& makeDepends,
+ std::ostream& internalDepends) CM_OVERRIDE;
+
+ // Method to scan a single file.
+ void Scan(std::istream& is, const char* directory,
+ const std::string& fullName);
+
+ // Regular expression to identify C preprocessor include directives.
+ cmsys::RegularExpression IncludeRegexLine;
+
+ // Regular expressions to choose which include files to scan
+ // recursively and which to complain about not finding.
+ cmsys::RegularExpression IncludeRegexScan;
+ cmsys::RegularExpression IncludeRegexComplain;
+ std::string IncludeRegexLineString;
+ std::string IncludeRegexScanString;
+ std::string IncludeRegexComplainString;
+
+ // Regex to transform #include lines.
+ std::string IncludeRegexTransformString;
+ cmsys::RegularExpression IncludeRegexTransform;
+ typedef std::map<std::string, std::string> TransformRulesType;
+ TransformRulesType TransformRules;
+ void SetupTransforms();
+ void ParseTransform(std::string const& xform);
+ void TransformLine(std::string& line);
+
+public:
+ // Data structures for dependency graph walk.
+ struct UnscannedEntry
+ {
+ std::string FileName;
+ std::string QuotedLocation;
+ };
+
+ struct cmIncludeLines
+ {
+ cmIncludeLines()
+ : Used(false)
+ {
+ }
+ std::vector<UnscannedEntry> UnscannedEntries;
+ bool Used;
+ };
+
+protected:
+ const std::map<std::string, DependencyVector>* ValidDeps;
+ std::set<std::string> Encountered;
+ std::queue<UnscannedEntry> Unscanned;
+
+ std::map<std::string, cmIncludeLines*> FileCache;
+ std::map<std::string, std::string> HeaderLocationCache;
+
+ std::string CacheFileName;
+
+ void WriteCacheFile() const;
+ void ReadCacheFile();
+
+private:
+ cmDependsC(cmDependsC const&); // Purposely not implemented.
+ void operator=(cmDependsC const&); // Purposely not implemented.
+};
+
+#endif
diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx
new file mode 100644
index 0000000..9ea1e48
--- /dev/null
+++ b/Source/cmDependsFortran.cxx
@@ -0,0 +1,701 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmDependsFortran.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include "cmFortranParser.h" /* Interface to parser object. */
+#include <assert.h>
+#include <cmsys/FStream.hxx>
+
+// TODO: Test compiler for the case of the mod file. Some always
+// use lower case and some always use upper case. I do not know if any
+// use the case from the source code.
+
+class cmDependsFortranInternals
+{
+public:
+ // The set of modules provided by this target.
+ std::set<std::string> TargetProvides;
+
+ // Map modules required by this target to locations.
+ typedef std::map<std::string, std::string> TargetRequiresMap;
+ TargetRequiresMap TargetRequires;
+
+ // Information about each object file.
+ typedef std::map<std::string, cmFortranSourceInfo> ObjectInfoMap;
+ ObjectInfoMap ObjectInfo;
+
+ cmFortranSourceInfo& CreateObjectInfo(const char* obj, const char* src)
+ {
+ std::map<std::string, cmFortranSourceInfo>::iterator i =
+ this->ObjectInfo.find(obj);
+ if (i == this->ObjectInfo.end()) {
+ std::map<std::string, cmFortranSourceInfo>::value_type entry(
+ obj, cmFortranSourceInfo());
+ i = this->ObjectInfo.insert(entry).first;
+ i->second.Source = src;
+ }
+ return i->second;
+ }
+};
+
+cmDependsFortran::cmDependsFortran()
+ : Internal(CM_NULLPTR)
+{
+}
+
+cmDependsFortran::cmDependsFortran(cmLocalGenerator* lg)
+ : cmDepends(lg)
+ , Internal(new cmDependsFortranInternals)
+{
+ // Configure the include file search path.
+ this->SetIncludePathFromLanguage("Fortran");
+
+ // Get the list of definitions.
+ std::vector<std::string> definitions;
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ if (const char* c_defines =
+ mf->GetDefinition("CMAKE_TARGET_DEFINITIONS_Fortran")) {
+ cmSystemTools::ExpandListArgument(c_defines, definitions);
+ }
+
+ // translate i.e. FOO=BAR to FOO and add it to the list of defined
+ // preprocessor symbols
+ for (std::vector<std::string>::const_iterator it = definitions.begin();
+ it != definitions.end(); ++it) {
+ std::string def = *it;
+ std::string::size_type assignment = def.find('=');
+ if (assignment != std::string::npos) {
+ def = it->substr(0, assignment);
+ }
+ this->PPDefinitions.insert(def);
+ }
+}
+
+cmDependsFortran::~cmDependsFortran()
+{
+ delete this->Internal;
+}
+
+bool cmDependsFortran::WriteDependencies(const std::set<std::string>& sources,
+ const std::string& obj, std::ostream&,
+ std::ostream&)
+{
+ // Make sure this is a scanning instance.
+ if (sources.empty() || sources.begin()->empty()) {
+ cmSystemTools::Error("Cannot scan dependencies without a source file.");
+ return false;
+ }
+ if (obj.empty()) {
+ cmSystemTools::Error("Cannot scan dependencies without an object file.");
+ return false;
+ }
+
+ bool okay = true;
+ for (std::set<std::string>::const_iterator it = sources.begin();
+ it != sources.end(); ++it) {
+ const std::string& src = *it;
+ // Get the information object for this source.
+ cmFortranSourceInfo& info =
+ this->Internal->CreateObjectInfo(obj.c_str(), src.c_str());
+
+ // Create the parser object. The constructor takes info by reference,
+ // so we may look into the resulting objects later.
+ cmFortranParser parser(this->IncludePath, this->PPDefinitions, info);
+
+ // Push on the starting file.
+ cmFortranParser_FilePush(&parser, src.c_str());
+
+ // Parse the translation unit.
+ if (cmFortran_yyparse(parser.Scanner) != 0) {
+ // Failed to parse the file. Report failure to write dependencies.
+ okay = false;
+ }
+ }
+ return okay;
+}
+
+bool cmDependsFortran::Finalize(std::ostream& makeDepends,
+ std::ostream& internalDepends)
+{
+ // Prepare the module search process.
+ this->LocateModules();
+
+ // Get the directory in which stamp files will be stored.
+ const char* stamp_dir = this->TargetDirectory.c_str();
+
+ // Get the directory in which module files will be created.
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ std::string mod_dir =
+ mf->GetSafeDefinition("CMAKE_Fortran_TARGET_MODULE_DIR");
+ if (mod_dir.empty()) {
+ mod_dir = this->LocalGenerator->GetCurrentBinaryDirectory();
+ }
+
+ // Actually write dependencies to the streams.
+ typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap;
+ ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
+ for (ObjectInfoMap::const_iterator i = objInfo.begin(); i != objInfo.end();
+ ++i) {
+ if (!this->WriteDependenciesReal(i->first.c_str(), i->second, mod_dir,
+ stamp_dir, makeDepends,
+ internalDepends)) {
+ return false;
+ }
+ }
+
+ // Store the list of modules provided by this target.
+ std::string fiName = this->TargetDirectory;
+ fiName += "/fortran.internal";
+ cmGeneratedFileStream fiStream(fiName.c_str());
+ fiStream << "# The fortran modules provided by this target.\n";
+ fiStream << "provides\n";
+ std::set<std::string> const& provides = this->Internal->TargetProvides;
+ for (std::set<std::string>::const_iterator i = provides.begin();
+ i != provides.end(); ++i) {
+ fiStream << " " << *i << "\n";
+ }
+
+ // Create a script to clean the modules.
+ if (!provides.empty()) {
+ std::string fcName = this->TargetDirectory;
+ fcName += "/cmake_clean_Fortran.cmake";
+ cmGeneratedFileStream fcStream(fcName.c_str());
+ fcStream << "# Remove fortran modules provided by this target.\n";
+ fcStream << "FILE(REMOVE";
+ for (std::set<std::string>::const_iterator i = provides.begin();
+ i != provides.end(); ++i) {
+ std::string mod_upper = mod_dir;
+ mod_upper += "/";
+ mod_upper += cmSystemTools::UpperCase(*i);
+ mod_upper += ".mod";
+ std::string mod_lower = mod_dir;
+ mod_lower += "/";
+ mod_lower += *i;
+ mod_lower += ".mod";
+ std::string stamp = stamp_dir;
+ stamp += "/";
+ stamp += *i;
+ stamp += ".mod.stamp";
+ fcStream << "\n";
+ fcStream << " \""
+ << this->LocalGenerator->Convert(
+ mod_lower, cmOutputConverter::START_OUTPUT)
+ << "\"\n";
+ fcStream << " \""
+ << this->LocalGenerator->Convert(
+ mod_upper, cmOutputConverter::START_OUTPUT)
+ << "\"\n";
+ fcStream << " \""
+ << this->LocalGenerator->Convert(
+ stamp, cmOutputConverter::START_OUTPUT)
+ << "\"\n";
+ }
+ fcStream << " )\n";
+ }
+ return true;
+}
+
+void cmDependsFortran::LocateModules()
+{
+ // Collect the set of modules provided and required by all sources.
+ typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap;
+ ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
+ for (ObjectInfoMap::const_iterator infoI = objInfo.begin();
+ infoI != objInfo.end(); ++infoI) {
+ cmFortranSourceInfo const& info = infoI->second;
+ // Include this module in the set provided by this target.
+ this->Internal->TargetProvides.insert(info.Provides.begin(),
+ info.Provides.end());
+
+ for (std::set<std::string>::const_iterator i = info.Requires.begin();
+ i != info.Requires.end(); ++i) {
+ this->Internal->TargetRequires[*i] = "";
+ }
+ }
+
+ // Short-circuit for simple targets.
+ if (this->Internal->TargetRequires.empty()) {
+ return;
+ }
+
+ // Match modules provided by this target to those it requires.
+ this->MatchLocalModules();
+
+ // Load information about other targets.
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ std::vector<std::string> infoFiles;
+ if (const char* infoFilesValue =
+ mf->GetDefinition("CMAKE_TARGET_LINKED_INFO_FILES")) {
+ cmSystemTools::ExpandListArgument(infoFilesValue, infoFiles);
+ }
+ for (std::vector<std::string>::const_iterator i = infoFiles.begin();
+ i != infoFiles.end(); ++i) {
+ std::string targetDir = cmSystemTools::GetFilenamePath(*i);
+ std::string fname = targetDir + "/fortran.internal";
+ cmsys::ifstream fin(fname.c_str());
+ if (fin) {
+ this->MatchRemoteModules(fin, targetDir.c_str());
+ }
+ }
+}
+
+void cmDependsFortran::MatchLocalModules()
+{
+ const char* stampDir = this->TargetDirectory.c_str();
+ std::set<std::string> const& provides = this->Internal->TargetProvides;
+ for (std::set<std::string>::const_iterator i = provides.begin();
+ i != provides.end(); ++i) {
+ this->ConsiderModule(i->c_str(), stampDir);
+ }
+}
+
+void cmDependsFortran::MatchRemoteModules(std::istream& fin,
+ const char* stampDir)
+{
+ std::string line;
+ bool doing_provides = false;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ // Ignore comments and empty lines.
+ if (line.empty() || line[0] == '#' || line[0] == '\r') {
+ continue;
+ }
+
+ if (line[0] == ' ') {
+ if (doing_provides) {
+ this->ConsiderModule(line.c_str() + 1, stampDir);
+ }
+ } else if (line == "provides") {
+ doing_provides = true;
+ } else {
+ doing_provides = false;
+ }
+ }
+}
+
+void cmDependsFortran::ConsiderModule(const char* name, const char* stampDir)
+{
+ // Locate each required module.
+ typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap;
+ TargetRequiresMap::iterator required =
+ this->Internal->TargetRequires.find(name);
+ if (required != this->Internal->TargetRequires.end() &&
+ required->second.empty()) {
+ // The module is provided by a CMake target. It will have a stamp file.
+ std::string stampFile = stampDir;
+ stampFile += "/";
+ stampFile += name;
+ stampFile += ".mod.stamp";
+ required->second = stampFile;
+ }
+}
+
+bool cmDependsFortran::WriteDependenciesReal(const char* obj,
+ cmFortranSourceInfo const& info,
+ std::string const& mod_dir,
+ const char* stamp_dir,
+ std::ostream& makeDepends,
+ std::ostream& internalDepends)
+{
+ typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap;
+
+ // Get the source file for this object.
+ const char* src = info.Source.c_str();
+
+ // Write the include dependencies to the output stream.
+ std::string obj_i =
+ this->LocalGenerator->Convert(obj, cmOutputConverter::HOME_OUTPUT);
+ std::string obj_m = this->LocalGenerator->ConvertToOutputFormat(
+ obj_i, cmOutputConverter::MAKERULE);
+ internalDepends << obj_i << std::endl;
+ internalDepends << " " << src << std::endl;
+ for (std::set<std::string>::const_iterator i = info.Includes.begin();
+ i != info.Includes.end(); ++i) {
+ makeDepends << obj_m << ": "
+ << this->LocalGenerator->Convert(
+ *i, cmOutputConverter::HOME_OUTPUT,
+ cmOutputConverter::MAKERULE)
+ << std::endl;
+ internalDepends << " " << *i << std::endl;
+ }
+ makeDepends << std::endl;
+
+ // Write module requirements to the output stream.
+ for (std::set<std::string>::const_iterator i = info.Requires.begin();
+ i != info.Requires.end(); ++i) {
+ // Require only modules not provided in the same source.
+ if (std::set<std::string>::const_iterator(info.Provides.find(*i)) !=
+ info.Provides.end()) {
+ continue;
+ }
+
+ // If the module is provided in this target special handling is
+ // needed.
+ if (this->Internal->TargetProvides.find(*i) !=
+ this->Internal->TargetProvides.end()) {
+ // The module is provided by a different source in the same
+ // target. Add the proxy dependency to make sure the other
+ // source builds first.
+ std::string proxy = stamp_dir;
+ proxy += "/";
+ proxy += *i;
+ proxy += ".mod.proxy";
+ proxy = this->LocalGenerator->Convert(
+ proxy, cmOutputConverter::HOME_OUTPUT, cmOutputConverter::MAKERULE);
+
+ // since we require some things add them to our list of requirements
+ makeDepends << obj_m << ".requires: " << proxy << std::endl;
+ }
+
+ // The object file should depend on timestamped files for the
+ // modules it uses.
+ TargetRequiresMap::const_iterator required =
+ this->Internal->TargetRequires.find(*i);
+ if (required == this->Internal->TargetRequires.end()) {
+ abort();
+ }
+ if (!required->second.empty()) {
+ // This module is known. Depend on its timestamp file.
+ std::string stampFile = this->LocalGenerator->Convert(
+ required->second, cmOutputConverter::HOME_OUTPUT,
+ cmOutputConverter::MAKERULE);
+ makeDepends << obj_m << ": " << stampFile << "\n";
+ } else {
+ // This module is not known to CMake. Try to locate it where
+ // the compiler will and depend on that.
+ std::string module;
+ if (this->FindModule(*i, module)) {
+ module = this->LocalGenerator->Convert(
+ module, cmOutputConverter::HOME_OUTPUT, cmOutputConverter::MAKERULE);
+ makeDepends << obj_m << ": " << module << "\n";
+ }
+ }
+ }
+
+ // Write provided modules to the output stream.
+ for (std::set<std::string>::const_iterator i = info.Provides.begin();
+ i != info.Provides.end(); ++i) {
+ std::string proxy = stamp_dir;
+ proxy += "/";
+ proxy += *i;
+ proxy += ".mod.proxy";
+ proxy = this->LocalGenerator->Convert(
+ proxy, cmOutputConverter::HOME_OUTPUT, cmOutputConverter::MAKERULE);
+ makeDepends << proxy << ": " << obj_m << ".provides" << std::endl;
+ }
+
+ // If any modules are provided then they must be converted to stamp files.
+ if (!info.Provides.empty()) {
+ // Create a target to copy the module after the object file
+ // changes.
+ makeDepends << obj_m << ".provides.build:\n";
+ for (std::set<std::string>::const_iterator i = info.Provides.begin();
+ i != info.Provides.end(); ++i) {
+ // Include this module in the set provided by this target.
+ this->Internal->TargetProvides.insert(*i);
+
+ // Always use lower case for the mod stamp file name. The
+ // cmake_copy_f90_mod will call back to this class, which will
+ // try various cases for the real mod file name.
+ std::string m = cmSystemTools::LowerCase(*i);
+ std::string modFile = mod_dir;
+ modFile += "/";
+ modFile += *i;
+ modFile = this->LocalGenerator->Convert(
+ modFile, cmOutputConverter::HOME_OUTPUT, cmOutputConverter::SHELL);
+ std::string stampFile = stamp_dir;
+ stampFile += "/";
+ stampFile += m;
+ stampFile += ".mod.stamp";
+ stampFile = this->LocalGenerator->Convert(
+ stampFile, cmOutputConverter::HOME_OUTPUT, cmOutputConverter::SHELL);
+ makeDepends << "\t$(CMAKE_COMMAND) -E cmake_copy_f90_mod " << modFile
+ << " " << stampFile;
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ const char* cid = mf->GetDefinition("CMAKE_Fortran_COMPILER_ID");
+ if (cid && *cid) {
+ makeDepends << " " << cid;
+ }
+ makeDepends << "\n";
+ }
+ // After copying the modules update the timestamp file so that
+ // copying will not be done again until the source rebuilds.
+ makeDepends << "\t$(CMAKE_COMMAND) -E touch " << obj_m
+ << ".provides.build\n";
+
+ // Make sure the module timestamp rule is evaluated by the time
+ // the target finishes building.
+ std::string driver = this->TargetDirectory;
+ driver += "/build";
+ driver = this->LocalGenerator->Convert(
+ driver, cmOutputConverter::HOME_OUTPUT, cmOutputConverter::MAKERULE);
+ makeDepends << driver << ": " << obj_m << ".provides.build\n";
+ }
+
+ return true;
+}
+
+bool cmDependsFortran::FindModule(std::string const& name, std::string& module)
+{
+ // Construct possible names for the module file.
+ std::string mod_upper = cmSystemTools::UpperCase(name);
+ std::string mod_lower = name;
+ mod_upper += ".mod";
+ mod_lower += ".mod";
+
+ // Search the include path for the module.
+ std::string fullName;
+ for (std::vector<std::string>::const_iterator i = this->IncludePath.begin();
+ i != this->IncludePath.end(); ++i) {
+ // Try the lower-case name.
+ fullName = *i;
+ fullName += "/";
+ fullName += mod_lower;
+ if (cmSystemTools::FileExists(fullName.c_str(), true)) {
+ module = fullName;
+ return true;
+ }
+
+ // Try the upper-case name.
+ fullName = *i;
+ fullName += "/";
+ fullName += mod_upper;
+ if (cmSystemTools::FileExists(fullName.c_str(), true)) {
+ module = fullName;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmDependsFortran::CopyModule(const std::vector<std::string>& args)
+{
+ // Implements
+ //
+ // $(CMAKE_COMMAND) -E cmake_copy_f90_mod input.mod output.mod.stamp
+ // [compiler-id]
+ //
+ // Note that the case of the .mod file depends on the compiler. In
+ // the future this copy could also account for the fact that some
+ // compilers include a timestamp in the .mod file so it changes even
+ // when the interface described in the module does not.
+
+ std::string mod = args[2];
+ std::string stamp = args[3];
+ std::string compilerId;
+ if (args.size() >= 5) {
+ compilerId = args[4];
+ }
+ std::string mod_dir = cmSystemTools::GetFilenamePath(mod);
+ if (!mod_dir.empty()) {
+ mod_dir += "/";
+ }
+ std::string mod_upper = mod_dir;
+ mod_upper += cmSystemTools::UpperCase(cmSystemTools::GetFilenameName(mod));
+ std::string mod_lower = mod_dir;
+ mod_lower += cmSystemTools::LowerCase(cmSystemTools::GetFilenameName(mod));
+ mod += ".mod";
+ mod_upper += ".mod";
+ mod_lower += ".mod";
+ if (cmSystemTools::FileExists(mod_upper.c_str(), true)) {
+ if (cmDependsFortran::ModulesDiffer(mod_upper.c_str(), stamp.c_str(),
+ compilerId.c_str())) {
+ if (!cmSystemTools::CopyFileAlways(mod_upper, stamp)) {
+ std::cerr << "Error copying Fortran module from \"" << mod_upper
+ << "\" to \"" << stamp << "\".\n";
+ return false;
+ }
+ }
+ return true;
+ } else if (cmSystemTools::FileExists(mod_lower.c_str(), true)) {
+ if (cmDependsFortran::ModulesDiffer(mod_lower.c_str(), stamp.c_str(),
+ compilerId.c_str())) {
+ if (!cmSystemTools::CopyFileAlways(mod_lower, stamp)) {
+ std::cerr << "Error copying Fortran module from \"" << mod_lower
+ << "\" to \"" << stamp << "\".\n";
+ return false;
+ }
+ }
+ return true;
+ }
+
+ std::cerr << "Error copying Fortran module \"" << args[2] << "\". Tried \""
+ << mod_upper << "\" and \"" << mod_lower << "\".\n";
+ return false;
+}
+
+// Helper function to look for a short sequence in a stream. If this
+// is later used for longer sequences it should be re-written using an
+// efficient string search algorithm such as Boyer-Moore.
+static bool cmFortranStreamContainsSequence(std::istream& ifs, const char* seq,
+ int len)
+{
+ assert(len > 0);
+
+ int cur = 0;
+ while (cur < len) {
+ // Get the next character.
+ int token = ifs.get();
+ if (!ifs) {
+ return false;
+ }
+
+ // Check the character.
+ if (token == static_cast<int>(seq[cur])) {
+ ++cur;
+ } else {
+ // Assume the sequence has no repeating subsequence.
+ cur = 0;
+ }
+ }
+
+ // The entire sequence was matched.
+ return true;
+}
+
+// Helper function to compare the remaining content in two streams.
+static bool cmFortranStreamsDiffer(std::istream& ifs1, std::istream& ifs2)
+{
+ // Compare the remaining content.
+ for (;;) {
+ int ifs1_c = ifs1.get();
+ int ifs2_c = ifs2.get();
+ if (!ifs1 && !ifs2) {
+ // We have reached the end of both streams simultaneously.
+ // The streams are identical.
+ return false;
+ }
+
+ if (!ifs1 || !ifs2 || ifs1_c != ifs2_c) {
+ // We have reached the end of one stream before the other or
+ // found differing content. The streams are different.
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool cmDependsFortran::ModulesDiffer(const char* modFile,
+ const char* stampFile,
+ const char* compilerId)
+{
+ /*
+ gnu >= 4.9:
+ A mod file is an ascii file compressed with gzip.
+ Compiling twice produces identical modules.
+
+ gnu < 4.9:
+ A mod file is an ascii file.
+ <bar.mod>
+ FORTRAN module created from /path/to/foo.f90 on Sun Dec 30 22:47:58 2007
+ If you edit this, you'll get what you deserve.
+ ...
+ </bar.mod>
+ As you can see the first line contains the date.
+
+ intel:
+ A mod file is a binary file.
+ However, looking into both generated bar.mod files with a hex editor
+ shows that they differ only before a sequence linefeed-zero (0x0A 0x00)
+ which is located some bytes in front of the absoulte path to the source
+ file.
+
+ sun:
+ A mod file is a binary file. Compiling twice produces identical modules.
+
+ others:
+ TODO ...
+ */
+
+ /* Compilers which do _not_ produce different mod content when the same
+ * source is compiled twice
+ * -SunPro
+ */
+ if (strcmp(compilerId, "SunPro") == 0) {
+ return cmSystemTools::FilesDiffer(modFile, stampFile);
+ }
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+ cmsys::ifstream finModFile(modFile, std::ios::in | std::ios::binary);
+ cmsys::ifstream finStampFile(stampFile, std::ios::in | std::ios::binary);
+#else
+ cmsys::ifstream finModFile(modFile);
+ cmsys::ifstream finStampFile(stampFile);
+#endif
+ if (!finModFile || !finStampFile) {
+ // At least one of the files does not exist. The modules differ.
+ return true;
+ }
+
+ /* Compilers which _do_ produce different mod content when the same
+ * source is compiled twice
+ * -GNU
+ * -Intel
+ *
+ * Eat the stream content until all recompile only related changes
+ * are left behind.
+ */
+ if (strcmp(compilerId, "GNU") == 0) {
+ // GNU Fortran 4.9 and later compress .mod files with gzip
+ // but also do not include a date so we can fall through to
+ // compare them without skipping any prefix.
+ unsigned char hdr[2];
+ bool okay = !finModFile.read(reinterpret_cast<char*>(hdr), 2).fail();
+ finModFile.seekg(0);
+ if (!okay || hdr[0] != 0x1f || hdr[1] != 0x8b) {
+ const char seq[1] = { '\n' };
+ const int seqlen = 1;
+
+ if (!cmFortranStreamContainsSequence(finModFile, seq, seqlen)) {
+ // The module is of unexpected format. Assume it is different.
+ std::cerr << compilerId << " fortran module " << modFile
+ << " has unexpected format." << std::endl;
+ return true;
+ }
+
+ if (!cmFortranStreamContainsSequence(finStampFile, seq, seqlen)) {
+ // The stamp must differ if the sequence is not contained.
+ return true;
+ }
+ }
+ } else if (strcmp(compilerId, "Intel") == 0) {
+ const char seq[2] = { '\n', '\0' };
+ const int seqlen = 2;
+
+ if (!cmFortranStreamContainsSequence(finModFile, seq, seqlen)) {
+ // The module is of unexpected format. Assume it is different.
+ std::cerr << compilerId << " fortran module " << modFile
+ << " has unexpected format." << std::endl;
+ return true;
+ }
+
+ if (!cmFortranStreamContainsSequence(finStampFile, seq, seqlen)) {
+ // The stamp must differ if the sequence is not contained.
+ return true;
+ }
+ }
+
+ // Compare the remaining content. If no compiler id matched above,
+ // including the case none was given, this will compare the whole
+ // content.
+ if (!cmFortranStreamsDiffer(finModFile, finStampFile)) {
+ return false;
+ }
+
+ // The modules are different.
+ return true;
+}
diff --git a/Source/cmDependsFortran.h b/Source/cmDependsFortran.h
new file mode 100644
index 0000000..f4385eb
--- /dev/null
+++ b/Source/cmDependsFortran.h
@@ -0,0 +1,85 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFortran_h
+#define cmFortran_h
+
+#include "cmDepends.h"
+
+class cmDependsFortranInternals;
+class cmFortranSourceInfo;
+
+/** \class cmDependsFortran
+ * \brief Dependency scanner for Fortran object files.
+ */
+class cmDependsFortran : public cmDepends
+{
+public:
+ /** Checking instances need to know the build directory name and the
+ relative path from the build directory to the target file. */
+ cmDependsFortran();
+
+ /** Scanning need to know the build directory name, the relative
+ path from the build directory to the target file, the source
+ file from which to start scanning, the include file search
+ path, and the target directory. */
+ cmDependsFortran(cmLocalGenerator* lg);
+
+ /** Virtual destructor to cleanup subclasses properly. */
+ ~cmDependsFortran() CM_OVERRIDE;
+
+ /** Callback from build system after a .mod file has been generated
+ by a Fortran90 compiler to copy the .mod file to the
+ corresponding stamp file. */
+ static bool CopyModule(const std::vector<std::string>& args);
+
+ /** Determine if a mod file and the corresponding mod.stamp file
+ are representing different module information. */
+ static bool ModulesDiffer(const char* modFile, const char* stampFile,
+ const char* compilerId);
+
+protected:
+ // Finalize the dependency information for the target.
+ bool Finalize(std::ostream& makeDepends,
+ std::ostream& internalDepends) CM_OVERRIDE;
+
+ // Find all the modules required by the target.
+ void LocateModules();
+ void MatchLocalModules();
+ void MatchRemoteModules(std::istream& fin, const char* stampDir);
+ void ConsiderModule(const char* name, const char* stampDir);
+ bool FindModule(std::string const& name, std::string& module);
+
+ // Implement writing/checking methods required by superclass.
+ bool WriteDependencies(const std::set<std::string>& sources,
+ const std::string& file, std::ostream& makeDepends,
+ std::ostream& internalDepends) CM_OVERRIDE;
+
+ // Actually write the depenencies to the streams.
+ bool WriteDependenciesReal(const char* obj, cmFortranSourceInfo const& info,
+ std::string const& mod_dir, const char* stamp_dir,
+ std::ostream& makeDepends,
+ std::ostream& internalDepends);
+
+ // The source file from which to start scanning.
+ std::string SourceFile;
+
+ std::set<std::string> PPDefinitions;
+
+ // Internal implementation details.
+ cmDependsFortranInternals* Internal;
+
+private:
+ cmDependsFortran(cmDependsFortran const&); // Purposely not implemented.
+ void operator=(cmDependsFortran const&); // Purposely not implemented.
+};
+
+#endif
diff --git a/Source/cmDependsJava.cxx b/Source/cmDependsJava.cxx
new file mode 100644
index 0000000..4f5e2ae
--- /dev/null
+++ b/Source/cmDependsJava.cxx
@@ -0,0 +1,42 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmDependsJava.h"
+
+#include "cmDependsJavaParserHelper.h"
+#include "cmSystemTools.h"
+
+cmDependsJava::cmDependsJava()
+{
+}
+
+cmDependsJava::~cmDependsJava()
+{
+}
+
+bool cmDependsJava::WriteDependencies(const std::set<std::string>& sources,
+ const std::string&, std::ostream&,
+ std::ostream&)
+{
+ // Make sure this is a scanning instance.
+ if (sources.empty() || sources.begin()->empty()) {
+ cmSystemTools::Error("Cannot scan dependencies without an source file.");
+ return false;
+ }
+
+ return true;
+}
+
+bool cmDependsJava::CheckDependencies(std::istream&, const char*,
+ std::map<std::string, DependencyVector>&)
+{
+ return true;
+}
diff --git a/Source/cmDependsJava.h b/Source/cmDependsJava.h
new file mode 100644
index 0000000..5bb3039
--- /dev/null
+++ b/Source/cmDependsJava.h
@@ -0,0 +1,44 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmDependsJava_h
+#define cmDependsJava_h
+
+#include "cmDepends.h"
+
+/** \class cmDependsJava
+ * \brief Dependency scanner for Java class files.
+ */
+class cmDependsJava : public cmDepends
+{
+public:
+ /** Checking instances need to know the build directory name and the
+ relative path from the build directory to the target file. */
+ cmDependsJava();
+
+ /** Virtual destructor to cleanup subclasses properly. */
+ ~cmDependsJava() CM_OVERRIDE;
+
+protected:
+ // Implement writing/checking methods required by superclass.
+ bool WriteDependencies(const std::set<std::string>& sources,
+ const std::string& file, std::ostream& makeDepends,
+ std::ostream& internalDepends) CM_OVERRIDE;
+ bool CheckDependencies(
+ std::istream& internalDepends, const char* internalDependsFileName,
+ std::map<std::string, DependencyVector>& validDeps) CM_OVERRIDE;
+
+private:
+ cmDependsJava(cmDependsJava const&); // Purposely not implemented.
+ void operator=(cmDependsJava const&); // Purposely not implemented.
+};
+
+#endif
diff --git a/Source/cmDependsJavaLexer.cxx b/Source/cmDependsJavaLexer.cxx
new file mode 100644
index 0000000..f7676d9
--- /dev/null
+++ b/Source/cmDependsJavaLexer.cxx
@@ -0,0 +1,2542 @@
+#include "cmStandardIncludes.h"
+#line 2 "cmDependsJavaLexer.cxx"
+
+#line 4 "cmDependsJavaLexer.cxx"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 31
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#if defined(__BEOS__) || defined (__HAIKU__)
+#include <unistd.h> /* prevents a conflict with a #define later on... */
+#endif
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+int cmDependsJava_yylex_init (yyscan_t* scanner);
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE cmDependsJava_yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via cmDependsJava_yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void cmDependsJava_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void cmDependsJava_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmDependsJava_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void cmDependsJava_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmDependsJava_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmDependsJava_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void cmDependsJava_yypop_buffer_state (yyscan_t yyscanner );
+
+static void cmDependsJava_yyensure_buffer_stack (yyscan_t yyscanner );
+static void cmDependsJava_yy_load_buffer_state (yyscan_t yyscanner );
+static void cmDependsJava_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER cmDependsJava_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE cmDependsJava_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmDependsJava_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmDependsJava_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *cmDependsJava_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *cmDependsJava_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void cmDependsJava_yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer cmDependsJava_yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ cmDependsJava_yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ cmDependsJava_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ cmDependsJava_yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ cmDependsJava_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cmDependsJava_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 111
+#define YY_END_OF_BUFFER 112
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[327] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 112, 110, 109, 109,
+ 77, 4, 73, 94, 60, 110, 93, 92, 105, 99,
+ 68, 89, 74, 71, 56, 56, 67, 103, 86, 75,
+ 79, 102, 107, 64, 63, 65, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 70, 96, 69, 104, 3, 3, 6, 111, 5,
+ 78, 95, 61, 62, 0, 0, 106, 101, 100, 91,
+ 90, 57, 1, 0, 72, 57, 56, 57, 0, 56,
+ 0, 88, 87, 76, 80, 81, 107, 66, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 18, 107,
+
+ 107, 107, 107, 107, 107, 26, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 97, 98, 2, 55, 55,
+ 0, 0, 0, 108, 57, 0, 57, 58, 85, 82,
+ 83, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 25, 107,
+ 107, 30, 107, 107, 34, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 50, 107, 107, 107, 0, 0, 58, 84, 107,
+ 107, 107, 107, 11, 12, 107, 14, 107, 107, 107,
+
+ 107, 20, 107, 107, 107, 107, 107, 107, 107, 107,
+ 32, 107, 59, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 46, 107, 107, 54, 51, 107,
+ 107, 107, 107, 107, 10, 13, 15, 107, 107, 107,
+ 107, 22, 24, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 40, 107, 107, 43, 107, 107, 47,
+ 107, 107, 53, 107, 8, 107, 107, 107, 19, 107,
+ 107, 107, 28, 107, 107, 33, 107, 107, 107, 38,
+ 39, 41, 107, 44, 107, 48, 107, 107, 107, 9,
+ 107, 17, 21, 23, 107, 107, 107, 35, 36, 107,
+
+ 107, 107, 107, 107, 7, 16, 107, 107, 107, 107,
+ 42, 107, 107, 52, 107, 107, 31, 37, 107, 49,
+ 27, 29, 107, 107, 45, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 5, 1, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 19,
+ 19, 19, 19, 19, 19, 20, 20, 21, 22, 23,
+ 24, 25, 26, 1, 27, 27, 27, 28, 29, 28,
+ 30, 30, 30, 30, 30, 31, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 32, 30, 30,
+ 33, 34, 35, 36, 30, 1, 37, 38, 39, 40,
+
+ 41, 42, 43, 44, 45, 30, 46, 47, 48, 49,
+ 50, 51, 30, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[65] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 3, 3, 3,
+ 1, 1, 1, 1, 1, 1, 3, 3, 3, 4,
+ 4, 4, 1, 1, 1, 1, 3, 3, 3, 3,
+ 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[334] =
+ { 0,
+ 0, 0, 401, 400, 62, 63, 411, 414, 414, 414,
+ 386, 414, 414, 385, 61, 374, 414, 414, 383, 57,
+ 414, 56, 54, 65, 74, 43, 414, 414, 55, 382,
+ 59, 414, 0, 414, 414, 381, 38, 36, 60, 46,
+ 51, 75, 69, 354, 82, 76, 362, 85, 56, 352,
+ 357, 414, 100, 414, 414, 414, 383, 414, 414, 414,
+ 414, 414, 414, 414, 390, 127, 414, 414, 414, 414,
+ 414, 129, 414, 395, 414, 132, 95, 414, 165, 414,
+ 0, 373, 414, 414, 414, 109, 0, 414, 343, 342,
+ 344, 352, 338, 101, 354, 353, 340, 346, 332, 333,
+
+ 331, 337, 334, 332, 329, 0, 329, 110, 330, 324,
+ 320, 329, 336, 93, 336, 319, 322, 89, 320, 325,
+ 320, 114, 131, 120, 323, 414, 414, 414, 414, 358,
+ 170, 357, 362, 414, 173, 157, 176, 150, 414, 414,
+ 340, 309, 321, 314, 323, 318, 317, 318, 304, 302,
+ 300, 316, 314, 310, 309, 296, 311, 310, 0, 153,
+ 292, 304, 301, 298, 0, 295, 295, 284, 285, 291,
+ 282, 284, 281, 289, 292, 278, 292, 277, 279, 279,
+ 286, 0, 286, 288, 277, 189, 314, 414, 414, 270,
+ 269, 279, 273, 0, 0, 274, 0, 264, 271, 260,
+
+ 267, 0, 264, 271, 264, 256, 268, 256, 270, 254,
+ 0, 249, 0, 267, 266, 261, 256, 248, 245, 253,
+ 258, 244, 256, 250, 0, 236, 239, 0, 0, 237,
+ 249, 252, 234, 250, 0, 0, 0, 237, 238, 243,
+ 243, 235, 0, 233, 226, 230, 236, 236, 233, 221,
+ 235, 234, 223, 0, 232, 216, 0, 225, 216, 214,
+ 221, 220, 0, 225, 0, 214, 207, 207, 0, 207,
+ 200, 217, 0, 218, 219, 0, 214, 213, 199, 0,
+ 0, 0, 210, 0, 201, 0, 209, 202, 194, 0,
+ 206, 0, 0, 0, 197, 204, 205, 0, 0, 202,
+
+ 191, 192, 191, 198, 0, 0, 163, 162, 170, 170,
+ 0, 164, 152, 0, 152, 157, 0, 0, 127, 0,
+ 0, 0, 115, 95, 0, 414, 218, 222, 226, 228,
+ 232, 96, 235
+ } ;
+
+static yyconst flex_int16_t yy_def[334] =
+ { 0,
+ 326, 1, 327, 327, 328, 328, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 329, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 25, 326, 326, 326, 326,
+ 326, 326, 330, 326, 326, 326, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 329, 326, 326, 326, 326,
+ 326, 326, 326, 331, 326, 326, 25, 326, 326, 326,
+ 332, 326, 326, 326, 326, 326, 330, 326, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 326, 326, 326, 326, 326,
+ 326, 333, 331, 326, 326, 326, 326, 332, 326, 326,
+ 326, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 326, 333, 326, 326, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 0, 326, 326, 326, 326,
+ 326, 326, 326
+ } ;
+
+static yyconst flex_int16_t yy_nxt[479] =
+ { 0,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 26,
+ 27, 28, 29, 30, 31, 32, 33, 33, 33, 33,
+ 33, 33, 34, 8, 35, 36, 37, 38, 39, 40,
+ 41, 42, 33, 33, 43, 33, 44, 33, 45, 33,
+ 46, 47, 48, 49, 33, 50, 51, 33, 33, 33,
+ 52, 53, 54, 55, 59, 59, 60, 60, 63, 68,
+ 70, 72, 72, 72, 326, 89, 73, 82, 83, 71,
+ 69, 74, 85, 86, 64, 91, 98, 92, 75, 76,
+ 90, 77, 77, 77, 93, 99, 94, 100, 138, 122,
+
+ 326, 78, 79, 95, 80, 81, 96, 123, 101, 97,
+ 106, 102, 113, 78, 79, 78, 107, 108, 110, 103,
+ 80, 104, 111, 126, 105, 173, 326, 114, 117, 326,
+ 115, 81, 140, 141, 325, 130, 112, 168, 118, 119,
+ 174, 120, 169, 121, 131, 131, 72, 72, 72, 135,
+ 135, 135, 326, 147, 148, 324, 78, 79, 178, 78,
+ 79, 127, 161, 162, 183, 179, 184, 180, 78, 79,
+ 78, 78, 79, 78, 137, 137, 137, 136, 129, 136,
+ 188, 132, 137, 137, 137, 181, 323, 186, 186, 182,
+ 135, 135, 135, 137, 137, 137, 188, 129, 322, 207,
+
+ 78, 79, 208, 78, 321, 320, 186, 186, 319, 318,
+ 317, 316, 78, 79, 78, 78, 315, 78, 56, 56,
+ 56, 56, 58, 58, 58, 58, 65, 65, 65, 65,
+ 87, 87, 133, 133, 133, 133, 187, 187, 314, 313,
+ 312, 311, 310, 309, 308, 307, 306, 305, 304, 303,
+ 302, 301, 300, 299, 298, 297, 296, 295, 294, 293,
+ 292, 291, 290, 289, 288, 287, 286, 285, 284, 283,
+ 282, 281, 280, 279, 278, 277, 276, 275, 274, 273,
+ 272, 271, 270, 269, 268, 267, 266, 265, 264, 263,
+ 262, 261, 260, 259, 258, 257, 256, 255, 254, 253,
+
+ 252, 251, 250, 249, 248, 247, 246, 245, 244, 243,
+ 242, 228, 241, 240, 239, 238, 237, 236, 235, 234,
+ 233, 232, 129, 231, 230, 229, 228, 227, 226, 225,
+ 224, 223, 222, 221, 220, 219, 218, 217, 216, 215,
+ 214, 213, 212, 211, 210, 209, 206, 205, 204, 203,
+ 202, 201, 200, 199, 198, 197, 196, 195, 194, 193,
+ 192, 191, 190, 189, 134, 129, 129, 185, 177, 176,
+ 175, 172, 171, 170, 167, 166, 165, 164, 163, 160,
+ 159, 158, 157, 156, 155, 154, 153, 152, 151, 150,
+ 149, 146, 145, 144, 143, 142, 139, 134, 129, 128,
+
+ 125, 124, 116, 109, 88, 84, 67, 66, 62, 61,
+ 326, 57, 57, 7, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326
+ } ;
+
+static yyconst flex_int16_t yy_chk[479] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 5, 6, 5, 6, 15, 20,
+ 22, 23, 23, 23, 26, 37, 24, 29, 29, 22,
+ 20, 24, 31, 31, 15, 38, 40, 38, 24, 25,
+ 37, 25, 25, 25, 38, 40, 39, 41, 332, 49,
+
+ 26, 25, 25, 39, 25, 25, 39, 49, 41, 39,
+ 43, 42, 46, 25, 25, 25, 43, 43, 45, 42,
+ 25, 42, 45, 53, 42, 118, 77, 46, 48, 66,
+ 46, 25, 86, 86, 324, 66, 45, 114, 48, 48,
+ 118, 48, 114, 48, 66, 66, 72, 72, 72, 76,
+ 76, 76, 77, 94, 94, 323, 72, 72, 122, 76,
+ 76, 53, 108, 108, 124, 122, 124, 123, 72, 72,
+ 72, 76, 76, 76, 136, 136, 136, 79, 131, 79,
+ 138, 66, 79, 79, 79, 123, 319, 131, 131, 123,
+ 135, 135, 135, 137, 137, 137, 138, 186, 316, 160,
+
+ 135, 135, 160, 137, 315, 313, 186, 186, 312, 310,
+ 309, 308, 135, 135, 135, 137, 307, 137, 327, 327,
+ 327, 327, 328, 328, 328, 328, 329, 329, 329, 329,
+ 330, 330, 331, 331, 331, 331, 333, 333, 304, 303,
+ 302, 301, 300, 297, 296, 295, 291, 289, 288, 287,
+ 285, 283, 279, 278, 277, 275, 274, 272, 271, 270,
+ 268, 267, 266, 264, 262, 261, 260, 259, 258, 256,
+ 255, 253, 252, 251, 250, 249, 248, 247, 246, 245,
+ 244, 242, 241, 240, 239, 238, 234, 233, 232, 231,
+ 230, 227, 226, 224, 223, 222, 221, 220, 219, 218,
+
+ 217, 216, 215, 214, 212, 210, 209, 208, 207, 206,
+ 205, 204, 203, 201, 200, 199, 198, 196, 193, 192,
+ 191, 190, 187, 185, 184, 183, 181, 180, 179, 178,
+ 177, 176, 175, 174, 173, 172, 171, 170, 169, 168,
+ 167, 166, 164, 163, 162, 161, 158, 157, 156, 155,
+ 154, 153, 152, 151, 150, 149, 148, 147, 146, 145,
+ 144, 143, 142, 141, 133, 132, 130, 125, 121, 120,
+ 119, 117, 116, 115, 113, 112, 111, 110, 109, 107,
+ 105, 104, 103, 102, 101, 100, 99, 98, 97, 96,
+ 95, 93, 92, 91, 90, 89, 82, 74, 65, 57,
+
+ 51, 50, 47, 44, 36, 30, 19, 16, 14, 11,
+ 7, 4, 3, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326
+ } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "cmDependsJavaLexer.in.l"
+#line 2 "cmDependsJavaLexer.in.l"
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run flex like this:
+
+ flex --prefix=cmDependsJava_yy --header-file=cmDependsJavaLexer.h -ocmDependsJavaLexer.cxx cmDependsJavaLexer.in.l
+
+Modify cmDependsJavaLexer.c:
+ - remove TABs
+ - remove "yyscanner" argument from these methods:
+ yy_fatal_error, cmDependsJava_yyalloc, cmDependsJava_yyrealloc, cmDependsJava_yyfree
+ - remove all YY_BREAK lines occurring right after return statements
+ - change while ( 1 ) to for(;;)
+
+Modify cmDependsJavaLexer.h:
+ - remove TABs
+ - remove the yy_init_globals function
+ - remove the block that includes unistd.h
+ - remove #line directives (avoids bogus warning on old Sun)
+
+*/
+
+#include "cmStandardLexer.h"
+
+#include "cmDependsJavaParserHelper.h"
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ { result = yyextra->LexInput(buf, max_size); }
+
+/* Include the set of tokens from the parser. */
+#include "cmDependsJavaParserTokens.h"
+
+#define KEYWORD yylvalp->str = 0
+#define SYMBOL yylvalp->str = 0
+#define PRIMITIVE yylvalp->str = 0
+
+/*--------------------------------------------------------------------------*/
+
+
+#line 721 "cmDependsJavaLexer.cxx"
+
+#define INITIAL 0
+#define comment 1
+#define string 2
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ }; /* end struct yyguts_t */
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int cmDependsJava_yylex_destroy (yyscan_t yyscanner );
+
+int cmDependsJava_yyget_debug (yyscan_t yyscanner );
+
+void cmDependsJava_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE cmDependsJava_yyget_extra (yyscan_t yyscanner );
+
+void cmDependsJava_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *cmDependsJava_yyget_in (yyscan_t yyscanner );
+
+void cmDependsJava_yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *cmDependsJava_yyget_out (yyscan_t yyscanner );
+
+void cmDependsJava_yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+int cmDependsJava_yyget_leng (yyscan_t yyscanner );
+
+char *cmDependsJava_yyget_text (yyscan_t yyscanner );
+
+int cmDependsJava_yyget_lineno (yyscan_t yyscanner );
+
+void cmDependsJava_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int cmDependsJava_yywrap (yyscan_t yyscanner );
+#else
+extern int cmDependsJava_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int cmDependsJava_yylex (yyscan_t yyscanner);
+
+#define YY_DECL int cmDependsJava_yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+#line 88 "cmDependsJavaLexer.in.l"
+
+#line 940 "cmDependsJavaLexer.cxx"
+
+ if ( yyg->yy_init )
+ {
+ yyg->yy_init = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ cmDependsJava_yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ cmDependsJava_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ cmDependsJava_yy_load_buffer_state(yyscanner );
+ }
+
+ for(;;) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 327 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 414 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 89 "cmDependsJavaLexer.in.l"
+{ BEGIN(comment); }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 90 "cmDependsJavaLexer.in.l"
+{ BEGIN(INITIAL); }
+ YY_BREAK
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+#line 91 "cmDependsJavaLexer.in.l"
+{}
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 93 "cmDependsJavaLexer.in.l"
+{ BEGIN(string); }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 94 "cmDependsJavaLexer.in.l"
+{ BEGIN(INITIAL); return jp_STRINGLITERAL; }
+case 6:
+YY_RULE_SETUP
+#line 95 "cmDependsJavaLexer.in.l"
+{}
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 97 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_ABSTRACT; }
+case 8:
+YY_RULE_SETUP
+#line 98 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_ASSERT; }
+case 9:
+YY_RULE_SETUP
+#line 99 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_BOOLEAN_TYPE; }
+case 10:
+YY_RULE_SETUP
+#line 100 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_BREAK; }
+case 11:
+YY_RULE_SETUP
+#line 101 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_BYTE_TYPE; }
+case 12:
+YY_RULE_SETUP
+#line 102 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_CASE; }
+case 13:
+YY_RULE_SETUP
+#line 103 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_CATCH; }
+case 14:
+YY_RULE_SETUP
+#line 104 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_CHAR_TYPE; }
+case 15:
+YY_RULE_SETUP
+#line 105 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_CLASS; }
+case 16:
+YY_RULE_SETUP
+#line 106 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_CONTINUE; }
+case 17:
+YY_RULE_SETUP
+#line 107 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_DEFAULT; }
+case 18:
+YY_RULE_SETUP
+#line 108 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_DO; }
+case 19:
+YY_RULE_SETUP
+#line 109 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_DOUBLE_TYPE; }
+case 20:
+YY_RULE_SETUP
+#line 110 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_ELSE; }
+case 21:
+YY_RULE_SETUP
+#line 111 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_EXTENDS; }
+case 22:
+YY_RULE_SETUP
+#line 112 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_FINAL; }
+case 23:
+YY_RULE_SETUP
+#line 113 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_FINALLY; }
+case 24:
+YY_RULE_SETUP
+#line 114 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_FLOAT_TYPE; }
+case 25:
+YY_RULE_SETUP
+#line 115 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_FOR; }
+case 26:
+YY_RULE_SETUP
+#line 116 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_IF; }
+case 27:
+YY_RULE_SETUP
+#line 117 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_IMPLEMENTS; }
+case 28:
+YY_RULE_SETUP
+#line 118 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_IMPORT; }
+case 29:
+YY_RULE_SETUP
+#line 119 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_INSTANCEOF; }
+case 30:
+YY_RULE_SETUP
+#line 120 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_INT_TYPE; }
+case 31:
+YY_RULE_SETUP
+#line 121 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_INTERFACE; }
+case 32:
+YY_RULE_SETUP
+#line 122 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_LONG_TYPE; }
+case 33:
+YY_RULE_SETUP
+#line 123 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_NATIVE; }
+case 34:
+YY_RULE_SETUP
+#line 124 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_NEW; }
+case 35:
+YY_RULE_SETUP
+#line 125 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_PACKAGE; }
+case 36:
+YY_RULE_SETUP
+#line 126 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_PRIVATE; }
+case 37:
+YY_RULE_SETUP
+#line 127 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_PROTECTED; }
+case 38:
+YY_RULE_SETUP
+#line 128 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_PUBLIC; }
+case 39:
+YY_RULE_SETUP
+#line 129 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_RETURN; }
+case 40:
+YY_RULE_SETUP
+#line 130 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_SHORT_TYPE; }
+case 41:
+YY_RULE_SETUP
+#line 131 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_STATIC; }
+case 42:
+YY_RULE_SETUP
+#line 132 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_STRICTFP; }
+case 43:
+YY_RULE_SETUP
+#line 133 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_SUPER; }
+case 44:
+YY_RULE_SETUP
+#line 134 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_SWITCH; }
+case 45:
+YY_RULE_SETUP
+#line 135 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_SYNCHRONIZED; }
+case 46:
+YY_RULE_SETUP
+#line 136 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_THIS; }
+case 47:
+YY_RULE_SETUP
+#line 137 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_THROW; }
+case 48:
+YY_RULE_SETUP
+#line 138 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_THROWS; }
+case 49:
+YY_RULE_SETUP
+#line 139 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_TRANSIENT; }
+case 50:
+YY_RULE_SETUP
+#line 140 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_TRY; }
+case 51:
+YY_RULE_SETUP
+#line 141 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_VOID; }
+case 52:
+YY_RULE_SETUP
+#line 142 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_VOLATILE; }
+case 53:
+YY_RULE_SETUP
+#line 143 "cmDependsJavaLexer.in.l"
+{ KEYWORD; return jp_WHILE; }
+case 54:
+YY_RULE_SETUP
+#line 145 "cmDependsJavaLexer.in.l"
+{ PRIMITIVE; return jp_BOOLEANLITERAL; }
+case 55:
+/* rule 55 can match eol */
+YY_RULE_SETUP
+#line 146 "cmDependsJavaLexer.in.l"
+{ PRIMITIVE; return jp_CHARACTERLITERAL; }
+case 56:
+YY_RULE_SETUP
+#line 147 "cmDependsJavaLexer.in.l"
+{ PRIMITIVE; return jp_DECIMALINTEGERLITERAL; }
+case 57:
+YY_RULE_SETUP
+#line 148 "cmDependsJavaLexer.in.l"
+{ PRIMITIVE; return jp_FLOATINGPOINTLITERAL; }
+case 58:
+YY_RULE_SETUP
+#line 149 "cmDependsJavaLexer.in.l"
+{ PRIMITIVE; return jp_HEXINTEGERLITERAL; }
+case 59:
+YY_RULE_SETUP
+#line 150 "cmDependsJavaLexer.in.l"
+{ PRIMITIVE; return jp_NULLLITERAL; }
+case 60:
+YY_RULE_SETUP
+#line 152 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_AND; }
+case 61:
+YY_RULE_SETUP
+#line 153 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_ANDAND; }
+case 62:
+YY_RULE_SETUP
+#line 154 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_ANDEQUALS; }
+case 63:
+YY_RULE_SETUP
+#line 155 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_BRACKETEND; }
+case 64:
+YY_RULE_SETUP
+#line 156 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_BRACKETSTART; }
+case 65:
+YY_RULE_SETUP
+#line 157 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_CARROT; }
+case 66:
+YY_RULE_SETUP
+#line 158 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_CARROTEQUALS; }
+case 67:
+YY_RULE_SETUP
+#line 159 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_COLON; }
+case 68:
+YY_RULE_SETUP
+#line 160 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_COMMA; }
+case 69:
+YY_RULE_SETUP
+#line 161 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_CURLYEND; }
+case 70:
+YY_RULE_SETUP
+#line 162 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_CURLYSTART; }
+case 71:
+YY_RULE_SETUP
+#line 163 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_DIVIDE; }
+case 72:
+YY_RULE_SETUP
+#line 164 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_DIVIDEEQUALS; }
+case 73:
+YY_RULE_SETUP
+#line 165 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_DOLLAR; }
+case 74:
+YY_RULE_SETUP
+#line 166 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_DOT; }
+case 75:
+YY_RULE_SETUP
+#line 167 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_EQUALS; }
+case 76:
+YY_RULE_SETUP
+#line 168 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_EQUALSEQUALS; }
+case 77:
+YY_RULE_SETUP
+#line 169 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_EXCLAMATION; }
+case 78:
+YY_RULE_SETUP
+#line 170 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_EXCLAMATIONEQUALS; }
+case 79:
+YY_RULE_SETUP
+#line 171 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_GREATER; }
+case 80:
+YY_RULE_SETUP
+#line 172 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_GTEQUALS; }
+case 81:
+YY_RULE_SETUP
+#line 173 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_GTGT; }
+case 82:
+YY_RULE_SETUP
+#line 174 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_GTGTEQUALS; }
+case 83:
+YY_RULE_SETUP
+#line 175 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_GTGTGT; }
+case 84:
+YY_RULE_SETUP
+#line 176 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_GTGTGTEQUALS; }
+case 85:
+YY_RULE_SETUP
+#line 177 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_LESLESEQUALS; }
+case 86:
+YY_RULE_SETUP
+#line 178 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_LESSTHAN; }
+case 87:
+YY_RULE_SETUP
+#line 179 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_LTEQUALS; }
+case 88:
+YY_RULE_SETUP
+#line 180 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_LTLT; }
+case 89:
+YY_RULE_SETUP
+#line 181 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_MINUS; }
+case 90:
+YY_RULE_SETUP
+#line 182 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_MINUSEQUALS; }
+case 91:
+YY_RULE_SETUP
+#line 183 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_MINUSMINUS; }
+case 92:
+YY_RULE_SETUP
+#line 184 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_PAREEND; }
+case 93:
+YY_RULE_SETUP
+#line 185 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_PARESTART; }
+case 94:
+YY_RULE_SETUP
+#line 186 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_PERCENT; }
+case 95:
+YY_RULE_SETUP
+#line 187 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_PERCENTEQUALS; }
+case 96:
+YY_RULE_SETUP
+#line 188 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_PIPE; }
+case 97:
+YY_RULE_SETUP
+#line 189 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_PIPEEQUALS; }
+case 98:
+YY_RULE_SETUP
+#line 190 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_PIPEPIPE; }
+case 99:
+YY_RULE_SETUP
+#line 191 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_PLUS; }
+case 100:
+YY_RULE_SETUP
+#line 192 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_PLUSEQUALS; }
+case 101:
+YY_RULE_SETUP
+#line 193 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_PLUSPLUS; }
+case 102:
+YY_RULE_SETUP
+#line 194 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_QUESTION; }
+case 103:
+YY_RULE_SETUP
+#line 195 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_SEMICOL; }
+case 104:
+YY_RULE_SETUP
+#line 196 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_TILDE; }
+case 105:
+YY_RULE_SETUP
+#line 197 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_TIMES; }
+case 106:
+YY_RULE_SETUP
+#line 198 "cmDependsJavaLexer.in.l"
+{ SYMBOL; return jp_TIMESEQUALS; }
+case 107:
+YY_RULE_SETUP
+#line 200 "cmDependsJavaLexer.in.l"
+{
+ yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ return jp_NAME;
+}
+case 108:
+/* rule 108 can match eol */
+YY_RULE_SETUP
+#line 205 "cmDependsJavaLexer.in.l"
+{ }
+ YY_BREAK
+case 109:
+/* rule 109 can match eol */
+YY_RULE_SETUP
+#line 206 "cmDependsJavaLexer.in.l"
+{ }
+ YY_BREAK
+case 110:
+YY_RULE_SETUP
+#line 207 "cmDependsJavaLexer.in.l"
+{
+ std::cerr << "Unknown character: " << yytext[0]
+ << " (" << (int)yytext[0] << ")" << std::endl;
+ yyextra->Error("Unknown character");
+ return jp_ERROR;
+}
+case 111:
+YY_RULE_SETUP
+#line 214 "cmDependsJavaLexer.in.l"
+ECHO;
+ YY_BREAK
+#line 1590 "cmDependsJavaLexer.cxx"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(comment):
+case YY_STATE_EOF(string):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * cmDependsJava_yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( cmDependsJava_yywrap(yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+return 0; /* this should not happen but it quiets some compilers */
+} /* end of cmDependsJava_yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ size_t nuto_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( nuto_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ cmDependsJava_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ nuto_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( nuto_read > YY_READ_BUF_SIZE )
+ nuto_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, nuto_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ cmDependsJava_yyrestart(yyin ,yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 327 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 327 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 326);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ cmDependsJava_yyrestart(yyin ,yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( cmDependsJava_yywrap(yyscanner ) )
+ return EOF;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void cmDependsJava_yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ cmDependsJava_yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ cmDependsJava_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ cmDependsJava_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+ cmDependsJava_yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void cmDependsJava_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * cmDependsJava_yypop_buffer_state();
+ * cmDependsJava_yypush_buffer_state(new_buffer);
+ */
+ cmDependsJava_yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ cmDependsJava_yy_load_buffer_state(yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (cmDependsJava_yywrap()) processing, but the only time this flag
+ * is looked at is after cmDependsJava_yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void cmDependsJava_yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE cmDependsJava_yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) cmDependsJava_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in cmDependsJava_yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) cmDependsJava_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in cmDependsJava_yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ cmDependsJava_yy_init_buffer(b,file ,yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with cmDependsJava_yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void cmDependsJava_yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ cmDependsJava_yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+ cmDependsJava_yyfree((void *) b ,yyscanner );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a cmDependsJava_yyrestart() or at EOF.
+ */
+ static void cmDependsJava_yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ cmDependsJava_yy_flush_buffer(b ,yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then cmDependsJava_yy_init_buffer was _probably_
+ * called from cmDependsJava_yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void cmDependsJava_yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ cmDependsJava_yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void cmDependsJava_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ cmDependsJava_yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from cmDependsJava_yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from cmDependsJava_yy_switch_to_buffer. */
+ cmDependsJava_yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void cmDependsJava_yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ cmDependsJava_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ cmDependsJava_yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void cmDependsJava_yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ int nuto_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ nuto_alloc = 1;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)cmDependsJava_yyalloc
+ (nuto_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+
+ memset(yyg->yy_buffer_stack, 0, nuto_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = nuto_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ nuto_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)cmDependsJava_yyrealloc
+ (yyg->yy_buffer_stack,
+ nuto_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = nuto_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cmDependsJava_yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) cmDependsJava_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in cmDependsJava_yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ cmDependsJava_yy_switch_to_buffer(b ,yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to cmDependsJava_yylex() will
+ * scan from a @e copy of @a yy_str.
+ * @param yy_str a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * cmDependsJava_yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE cmDependsJava_yy_scan_string (yyconst char * yy_str , yyscan_t yyscanner)
+{
+
+ return cmDependsJava_yy_scan_bytes(yy_str,strlen(yy_str) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to cmDependsJava_yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cmDependsJava_yy_scan_bytes (yyconst char * bytes, int len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) cmDependsJava_yyalloc(n ,yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in cmDependsJava_yy_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = cmDependsJava_yy_scan_buffer(buf,n ,yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in cmDependsJava_yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t)
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE cmDependsJava_yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int cmDependsJava_yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int cmDependsJava_yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *cmDependsJava_yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *cmDependsJava_yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int cmDependsJava_yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *cmDependsJava_yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void cmDependsJava_yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number The line number to set.
+ * @param yyscanner The scanner object.
+ */
+void cmDependsJava_yyset_lineno (int line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "cmDependsJava_yyset_lineno called with no buffer" , yyscanner);
+
+ yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param column_no The column number to set.
+ * @param yyscanner The scanner object.
+ */
+void cmDependsJava_yyset_column (int column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "cmDependsJava_yyset_column called with no buffer" , yyscanner);
+
+ yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see cmDependsJava_yy_switch_to_buffer
+ */
+void cmDependsJava_yyset_in (FILE * in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = in_str ;
+}
+
+void cmDependsJava_yyset_out (FILE * out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = out_str ;
+}
+
+int cmDependsJava_yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void cmDependsJava_yyset_debug (int bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ This function is called once per scanner lifetime. */
+
+ yyg->yy_buffer_stack = 0;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = (char *) 0;
+ yyg->yy_init = 1;
+ yyg->yy_start = 0;
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = (int *) 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * cmDependsJava_yylex_init()
+ */
+ return 0;
+}
+
+/* User-visible API */
+
+/* cmDependsJava_yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int cmDependsJava_yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) cmDependsJava_yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ memset(*ptr_yy_globals,0,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* cmDependsJava_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int cmDependsJava_yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ cmDependsJava_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ cmDependsJava_yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ cmDependsJava_yyfree(yyg->yy_buffer_stack ,yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ cmDependsJava_yyfree(yyg->yy_start_stack ,yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Destroy the main struct (reentrant only). */
+ cmDependsJava_yyfree ( yyscanner , yyscanner );
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+ int i;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+ int n;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *cmDependsJava_yyalloc (yy_size_t size , yyscan_t)
+{
+ return (void *) malloc( size );
+}
+
+void *cmDependsJava_yyrealloc (void * ptr, yy_size_t size , yyscan_t)
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void cmDependsJava_yyfree (void * ptr , yyscan_t)
+{
+ free( (char *) ptr ); /* see cmDependsJava_yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef yytext_ptr
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+#line 214 "cmDependsJavaLexer.in.l"
+
+
+
diff --git a/Source/cmDependsJavaLexer.h b/Source/cmDependsJavaLexer.h
new file mode 100644
index 0000000..61aa66d
--- /dev/null
+++ b/Source/cmDependsJavaLexer.h
@@ -0,0 +1,334 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmDependsJava_yyHEADER_H
+#define cmDependsJava_yyHEADER_H 1
+#define cmDependsJava_yyIN_HEADER 1
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 31
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#if defined(__BEOS__) || defined(__HAIKU__)
+#include <unistd.h> /* prevents a conflict with a #define later on... */
+#endif
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+int cmDependsJava_yylex_init (yyscan_t* scanner);
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void cmDependsJava_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void cmDependsJava_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,
+ yyscan_t yyscanner );
+YY_BUFFER_STATE cmDependsJava_yy_create_buffer (FILE *file,int size ,
+ yyscan_t yyscanner );
+void cmDependsJava_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmDependsJava_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmDependsJava_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,
+ yyscan_t yyscanner );
+void cmDependsJava_yypop_buffer_state (yyscan_t yyscanner );
+
+YY_BUFFER_STATE cmDependsJava_yy_scan_buffer (char *base,yy_size_t size ,
+ yyscan_t yyscanner );
+YY_BUFFER_STATE cmDependsJava_yy_scan_string (yyconst char *yy_str ,
+ yyscan_t yyscanner );
+YY_BUFFER_STATE cmDependsJava_yy_scan_bytes (yyconst char *bytes,int len ,
+ yyscan_t yyscanner );
+
+void *cmDependsJava_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *cmDependsJava_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void cmDependsJava_yyfree (void * ,yyscan_t yyscanner );
+
+/* Begin user sect3 */
+
+#define cmDependsJava_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+#define comment 1
+#define string 2
+
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int cmDependsJava_yylex_destroy (yyscan_t yyscanner );
+
+int cmDependsJava_yyget_debug (yyscan_t yyscanner );
+
+void cmDependsJava_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE cmDependsJava_yyget_extra (yyscan_t yyscanner );
+
+void cmDependsJava_yyset_extra (YY_EXTRA_TYPE user_defined ,
+ yyscan_t yyscanner );
+
+FILE *cmDependsJava_yyget_in (yyscan_t yyscanner );
+
+void cmDependsJava_yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *cmDependsJava_yyget_out (yyscan_t yyscanner );
+
+void cmDependsJava_yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+int cmDependsJava_yyget_leng (yyscan_t yyscanner );
+
+char *cmDependsJava_yyget_text (yyscan_t yyscanner );
+
+int cmDependsJava_yyget_lineno (yyscan_t yyscanner );
+
+void cmDependsJava_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int cmDependsJava_yywrap (yyscan_t yyscanner );
+#else
+extern int cmDependsJava_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int cmDependsJava_yylex (yyscan_t yyscanner);
+
+#define YY_DECL int cmDependsJava_yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the
+ EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef yytext_ptr
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#undef cmDependsJava_yyIN_HEADER
+#endif /* cmDependsJava_yyHEADER_H */
diff --git a/Source/cmDependsJavaLexer.in.l b/Source/cmDependsJavaLexer.in.l
new file mode 100644
index 0000000..aa2f8a5
--- /dev/null
+++ b/Source/cmDependsJavaLexer.in.l
@@ -0,0 +1,189 @@
+%{
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run flex like this:
+
+ flex --prefix=cmDependsJava_yy --header-file=cmDependsJavaLexer.h -ocmDependsJavaLexer.cxx cmDependsJavaLexer.in.l
+
+Modify cmDependsJavaLexer.c:
+ - remove TABs
+ - remove use of the 'register' storage class specifier
+ - remove "yyscanner" argument from these methods:
+ yy_fatal_error, cmDependsJava_yyalloc, cmDependsJava_yyrealloc, cmDependsJava_yyfree
+ - remove all YY_BREAK lines occurring right after return statements
+ - change while ( 1 ) to for(;;)
+
+Modify cmDependsJavaLexer.h:
+ - remove TABs
+ - remove the yy_init_globals function
+ - remove the block that includes unistd.h
+ - remove #line directives (avoids bogus warning on old Sun)
+
+*/
+
+#include "cmStandardLexer.h"
+
+#include "cmDependsJavaParserHelper.h"
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ { result = yyextra->LexInput(buf, max_size); }
+
+/* Include the set of tokens from the parser. */
+#include "cmDependsJavaParserTokens.h"
+
+#define KEYWORD yylvalp->str = 0
+#define SYMBOL yylvalp->str = 0
+#define PRIMITIVE yylvalp->str = 0
+
+/*--------------------------------------------------------------------------*/
+%}
+
+%option reentrant
+%option noyywrap
+%pointer
+
+%x comment
+%x string
+
+%%
+"/*" { BEGIN(comment); }
+<comment>"*/" { BEGIN(INITIAL); }
+<comment>.|\n {}
+
+\" { BEGIN(string); }
+<string>\" { BEGIN(INITIAL); return jp_STRINGLITERAL; }
+<string>. {}
+
+abstract { KEYWORD; return jp_ABSTRACT; }
+assert { KEYWORD; return jp_ASSERT; }
+boolean { KEYWORD; return jp_BOOLEAN_TYPE; }
+break { KEYWORD; return jp_BREAK; }
+byte { KEYWORD; return jp_BYTE_TYPE; }
+case { KEYWORD; return jp_CASE; }
+catch { KEYWORD; return jp_CATCH; }
+char { KEYWORD; return jp_CHAR_TYPE; }
+class { KEYWORD; return jp_CLASS; }
+continue { KEYWORD; return jp_CONTINUE; }
+default { KEYWORD; return jp_DEFAULT; }
+do { KEYWORD; return jp_DO; }
+double { KEYWORD; return jp_DOUBLE_TYPE; }
+else { KEYWORD; return jp_ELSE; }
+extends { KEYWORD; return jp_EXTENDS; }
+final { KEYWORD; return jp_FINAL; }
+finally { KEYWORD; return jp_FINALLY; }
+float { KEYWORD; return jp_FLOAT_TYPE; }
+for { KEYWORD; return jp_FOR; }
+if { KEYWORD; return jp_IF; }
+implements { KEYWORD; return jp_IMPLEMENTS; }
+import { KEYWORD; return jp_IMPORT; }
+instanceof { KEYWORD; return jp_INSTANCEOF; }
+int { KEYWORD; return jp_INT_TYPE; }
+interface { KEYWORD; return jp_INTERFACE; }
+long { KEYWORD; return jp_LONG_TYPE; }
+native { KEYWORD; return jp_NATIVE; }
+new { KEYWORD; return jp_NEW; }
+package { KEYWORD; return jp_PACKAGE; }
+private { KEYWORD; return jp_PRIVATE; }
+protected { KEYWORD; return jp_PROTECTED; }
+public { KEYWORD; return jp_PUBLIC; }
+return { KEYWORD; return jp_RETURN; }
+short { KEYWORD; return jp_SHORT_TYPE; }
+static { KEYWORD; return jp_STATIC; }
+strictfp { KEYWORD; return jp_STRICTFP; }
+super { KEYWORD; return jp_SUPER; }
+switch { KEYWORD; return jp_SWITCH; }
+synchronized { KEYWORD; return jp_SYNCHRONIZED; }
+this { KEYWORD; return jp_THIS; }
+throw { KEYWORD; return jp_THROW; }
+throws { KEYWORD; return jp_THROWS; }
+transient { KEYWORD; return jp_TRANSIENT; }
+try { KEYWORD; return jp_TRY; }
+void { KEYWORD; return jp_VOID; }
+volatile { KEYWORD; return jp_VOLATILE; }
+while { KEYWORD; return jp_WHILE; }
+
+(true|false) { PRIMITIVE; return jp_BOOLEANLITERAL; }
+\'([^\\]|\\.|\\u[0-9a-fA-F]*|\\[0-7]*)\' { PRIMITIVE; return jp_CHARACTERLITERAL; }
+(0|[0-9]+)[lL]? { PRIMITIVE; return jp_DECIMALINTEGERLITERAL; }
+([0-9]+\.[0-9]*|\.[0-9]+|[0-9]+)([eE][+\-]?[0-9]+)?[fFdD]? { PRIMITIVE; return jp_FLOATINGPOINTLITERAL; }
+0[xX][0-9a-fA-F]+[lL]? { PRIMITIVE; return jp_HEXINTEGERLITERAL; }
+null { PRIMITIVE; return jp_NULLLITERAL; }
+
+"&" { SYMBOL; return jp_AND; }
+"&&" { SYMBOL; return jp_ANDAND; }
+"&=" { SYMBOL; return jp_ANDEQUALS; }
+"\]" { SYMBOL; return jp_BRACKETEND; }
+"\[" { SYMBOL; return jp_BRACKETSTART; }
+"\^" { SYMBOL; return jp_CARROT; }
+"\^=" { SYMBOL; return jp_CARROTEQUALS; }
+":" { SYMBOL; return jp_COLON; }
+"," { SYMBOL; return jp_COMMA; }
+"}" { SYMBOL; return jp_CURLYEND; }
+"{" { SYMBOL; return jp_CURLYSTART; }
+"/" { SYMBOL; return jp_DIVIDE; }
+"/=" { SYMBOL; return jp_DIVIDEEQUALS; }
+"\$" { SYMBOL; return jp_DOLLAR; }
+"\." { SYMBOL; return jp_DOT; }
+"=" { SYMBOL; return jp_EQUALS; }
+"==" { SYMBOL; return jp_EQUALSEQUALS; }
+"\!" { SYMBOL; return jp_EXCLAMATION; }
+"\!=" { SYMBOL; return jp_EXCLAMATIONEQUALS; }
+">" { SYMBOL; return jp_GREATER; }
+">=" { SYMBOL; return jp_GTEQUALS; }
+">>" { SYMBOL; return jp_GTGT; }
+">>=" { SYMBOL; return jp_GTGTEQUALS; }
+">>>" { SYMBOL; return jp_GTGTGT; }
+">>>=" { SYMBOL; return jp_GTGTGTEQUALS; }
+"<<=" { SYMBOL; return jp_LESLESEQUALS; }
+"<" { SYMBOL; return jp_LESSTHAN; }
+"<=" { SYMBOL; return jp_LTEQUALS; }
+"<<" { SYMBOL; return jp_LTLT; }
+"-" { SYMBOL; return jp_MINUS; }
+"-=" { SYMBOL; return jp_MINUSEQUALS; }
+"--" { SYMBOL; return jp_MINUSMINUS; }
+"\)" { SYMBOL; return jp_PAREEND; }
+"\(" { SYMBOL; return jp_PARESTART; }
+"%" { SYMBOL; return jp_PERCENT; }
+"%=" { SYMBOL; return jp_PERCENTEQUALS; }
+"\|" { SYMBOL; return jp_PIPE; }
+"\|=" { SYMBOL; return jp_PIPEEQUALS; }
+"\|\|" { SYMBOL; return jp_PIPEPIPE; }
+"\+" { SYMBOL; return jp_PLUS; }
+"\+=" { SYMBOL; return jp_PLUSEQUALS; }
+"\+\+" { SYMBOL; return jp_PLUSPLUS; }
+"\?" { SYMBOL; return jp_QUESTION; }
+";" { SYMBOL; return jp_SEMICOL; }
+"\~" { SYMBOL; return jp_TILDE; }
+"\*" { SYMBOL; return jp_TIMES; }
+"\*=" { SYMBOL; return jp_TIMESEQUALS; }
+
+[a-z_A-Z][a-z_0-9A-Z]* {
+ yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ return jp_NAME;
+}
+
+\/\/.*\n { }
+[ \f\t\n\r] { }
+. {
+ std::cerr << "Unknown character: " << yytext[0]
+ << " (" << (int)yytext[0] << ")" << std::endl;
+ yyextra->Error("Unknown character");
+ return jp_ERROR;
+}
+
+%%
diff --git a/Source/cmDependsJavaParser.cxx b/Source/cmDependsJavaParser.cxx
new file mode 100644
index 0000000..899f4d2
--- /dev/null
+++ b/Source/cmDependsJavaParser.cxx
@@ -0,0 +1,6015 @@
+/* A Bison parser, made by GNU Bison 1.875d. */
+
+/* Skeleton parser for Yacc-like parsing with Bison, Copyright (C) 1984,
+ 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* turn off some warning as this is generated code */
+#if defined(_MSC_VER)
+# pragma warning ( disable : 4702 ) /* unreachable code */
+#endif
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+/* If NAME_PREFIX is specified substitute the variables and functions
+ names. */
+#define yyparse cmDependsJava_yyparse
+#define yylex cmDependsJava_yylex
+#define yyerror cmDependsJava_yyerror
+#define yylval cmDependsJava_yylval
+#define yychar cmDependsJava_yychar
+#define yydebug cmDependsJava_yydebug
+#define yynerrs cmDependsJava_yynerrs
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ jp_ABSTRACT = 258,
+ jp_ASSERT = 259,
+ jp_BOOLEAN_TYPE = 260,
+ jp_BREAK = 261,
+ jp_BYTE_TYPE = 262,
+ jp_CASE = 263,
+ jp_CATCH = 264,
+ jp_CHAR_TYPE = 265,
+ jp_CLASS = 266,
+ jp_CONTINUE = 267,
+ jp_DEFAULT = 268,
+ jp_DO = 269,
+ jp_DOUBLE_TYPE = 270,
+ jp_ELSE = 271,
+ jp_EXTENDS = 272,
+ jp_FINAL = 273,
+ jp_FINALLY = 274,
+ jp_FLOAT_TYPE = 275,
+ jp_FOR = 276,
+ jp_IF = 277,
+ jp_IMPLEMENTS = 278,
+ jp_IMPORT = 279,
+ jp_INSTANCEOF = 280,
+ jp_INT_TYPE = 281,
+ jp_INTERFACE = 282,
+ jp_LONG_TYPE = 283,
+ jp_NATIVE = 284,
+ jp_NEW = 285,
+ jp_PACKAGE = 286,
+ jp_PRIVATE = 287,
+ jp_PROTECTED = 288,
+ jp_PUBLIC = 289,
+ jp_RETURN = 290,
+ jp_SHORT_TYPE = 291,
+ jp_STATIC = 292,
+ jp_STRICTFP = 293,
+ jp_SUPER = 294,
+ jp_SWITCH = 295,
+ jp_SYNCHRONIZED = 296,
+ jp_THIS = 297,
+ jp_THROW = 298,
+ jp_THROWS = 299,
+ jp_TRANSIENT = 300,
+ jp_TRY = 301,
+ jp_VOID = 302,
+ jp_VOLATILE = 303,
+ jp_WHILE = 304,
+ jp_BOOLEANLITERAL = 305,
+ jp_CHARACTERLITERAL = 306,
+ jp_DECIMALINTEGERLITERAL = 307,
+ jp_FLOATINGPOINTLITERAL = 308,
+ jp_HEXINTEGERLITERAL = 309,
+ jp_NULLLITERAL = 310,
+ jp_STRINGLITERAL = 311,
+ jp_NAME = 312,
+ jp_AND = 313,
+ jp_ANDAND = 314,
+ jp_ANDEQUALS = 315,
+ jp_BRACKETEND = 316,
+ jp_BRACKETSTART = 317,
+ jp_CARROT = 318,
+ jp_CARROTEQUALS = 319,
+ jp_COLON = 320,
+ jp_COMMA = 321,
+ jp_CURLYEND = 322,
+ jp_CURLYSTART = 323,
+ jp_DIVIDE = 324,
+ jp_DIVIDEEQUALS = 325,
+ jp_DOLLAR = 326,
+ jp_DOT = 327,
+ jp_EQUALS = 328,
+ jp_EQUALSEQUALS = 329,
+ jp_EXCLAMATION = 330,
+ jp_EXCLAMATIONEQUALS = 331,
+ jp_GREATER = 332,
+ jp_GTEQUALS = 333,
+ jp_GTGT = 334,
+ jp_GTGTEQUALS = 335,
+ jp_GTGTGT = 336,
+ jp_GTGTGTEQUALS = 337,
+ jp_LESLESEQUALS = 338,
+ jp_LESSTHAN = 339,
+ jp_LTEQUALS = 340,
+ jp_LTLT = 341,
+ jp_MINUS = 342,
+ jp_MINUSEQUALS = 343,
+ jp_MINUSMINUS = 344,
+ jp_PAREEND = 345,
+ jp_PARESTART = 346,
+ jp_PERCENT = 347,
+ jp_PERCENTEQUALS = 348,
+ jp_PIPE = 349,
+ jp_PIPEEQUALS = 350,
+ jp_PIPEPIPE = 351,
+ jp_PLUS = 352,
+ jp_PLUSEQUALS = 353,
+ jp_PLUSPLUS = 354,
+ jp_QUESTION = 355,
+ jp_SEMICOL = 356,
+ jp_TILDE = 357,
+ jp_TIMES = 358,
+ jp_TIMESEQUALS = 359,
+ jp_ERROR = 360
+ };
+#endif
+#define jp_ABSTRACT 258
+#define jp_ASSERT 259
+#define jp_BOOLEAN_TYPE 260
+#define jp_BREAK 261
+#define jp_BYTE_TYPE 262
+#define jp_CASE 263
+#define jp_CATCH 264
+#define jp_CHAR_TYPE 265
+#define jp_CLASS 266
+#define jp_CONTINUE 267
+#define jp_DEFAULT 268
+#define jp_DO 269
+#define jp_DOUBLE_TYPE 270
+#define jp_ELSE 271
+#define jp_EXTENDS 272
+#define jp_FINAL 273
+#define jp_FINALLY 274
+#define jp_FLOAT_TYPE 275
+#define jp_FOR 276
+#define jp_IF 277
+#define jp_IMPLEMENTS 278
+#define jp_IMPORT 279
+#define jp_INSTANCEOF 280
+#define jp_INT_TYPE 281
+#define jp_INTERFACE 282
+#define jp_LONG_TYPE 283
+#define jp_NATIVE 284
+#define jp_NEW 285
+#define jp_PACKAGE 286
+#define jp_PRIVATE 287
+#define jp_PROTECTED 288
+#define jp_PUBLIC 289
+#define jp_RETURN 290
+#define jp_SHORT_TYPE 291
+#define jp_STATIC 292
+#define jp_STRICTFP 293
+#define jp_SUPER 294
+#define jp_SWITCH 295
+#define jp_SYNCHRONIZED 296
+#define jp_THIS 297
+#define jp_THROW 298
+#define jp_THROWS 299
+#define jp_TRANSIENT 300
+#define jp_TRY 301
+#define jp_VOID 302
+#define jp_VOLATILE 303
+#define jp_WHILE 304
+#define jp_BOOLEANLITERAL 305
+#define jp_CHARACTERLITERAL 306
+#define jp_DECIMALINTEGERLITERAL 307
+#define jp_FLOATINGPOINTLITERAL 308
+#define jp_HEXINTEGERLITERAL 309
+#define jp_NULLLITERAL 310
+#define jp_STRINGLITERAL 311
+#define jp_NAME 312
+#define jp_AND 313
+#define jp_ANDAND 314
+#define jp_ANDEQUALS 315
+#define jp_BRACKETEND 316
+#define jp_BRACKETSTART 317
+#define jp_CARROT 318
+#define jp_CARROTEQUALS 319
+#define jp_COLON 320
+#define jp_COMMA 321
+#define jp_CURLYEND 322
+#define jp_CURLYSTART 323
+#define jp_DIVIDE 324
+#define jp_DIVIDEEQUALS 325
+#define jp_DOLLAR 326
+#define jp_DOT 327
+#define jp_EQUALS 328
+#define jp_EQUALSEQUALS 329
+#define jp_EXCLAMATION 330
+#define jp_EXCLAMATIONEQUALS 331
+#define jp_GREATER 332
+#define jp_GTEQUALS 333
+#define jp_GTGT 334
+#define jp_GTGTEQUALS 335
+#define jp_GTGTGT 336
+#define jp_GTGTGTEQUALS 337
+#define jp_LESLESEQUALS 338
+#define jp_LESSTHAN 339
+#define jp_LTEQUALS 340
+#define jp_LTLT 341
+#define jp_MINUS 342
+#define jp_MINUSEQUALS 343
+#define jp_MINUSMINUS 344
+#define jp_PAREEND 345
+#define jp_PARESTART 346
+#define jp_PERCENT 347
+#define jp_PERCENTEQUALS 348
+#define jp_PIPE 349
+#define jp_PIPEEQUALS 350
+#define jp_PIPEPIPE 351
+#define jp_PLUS 352
+#define jp_PLUSEQUALS 353
+#define jp_PLUSPLUS 354
+#define jp_QUESTION 355
+#define jp_SEMICOL 356
+#define jp_TILDE 357
+#define jp_TIMES 358
+#define jp_TIMESEQUALS 359
+#define jp_ERROR 360
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 1 "cmDependsJavaParser.y"
+
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --yacc --name-prefix=cmDependsJava_yy
+ --defines=cmDependsJavaParserTokens.h -ocmDependsJavaParser.cxx
+ cmDependsJavaParser.y
+
+Modify cmDependsJavaParser.c:
+ - remove TABs
+
+*/
+
+/* Configure the parser to use a lexer object. */
+#define YYPARSE_PARAM yyscanner
+#define YYLEX_PARAM yyscanner
+#define YYERROR_VERBOSE 1
+#define cmDependsJava_yyerror(x) \
+ cmDependsJavaError(yyscanner, x)
+#define yyGetParser (cmDependsJava_yyget_extra(yyscanner))
+
+/*-------------------------------------------------------------------------*/
+#include "cmDependsJavaParserHelper.h" /* Interface to parser object. */
+#include "cmDependsJavaLexer.h" /* Interface to lexer object. */
+#include "cmDependsJavaParserTokens.h" /* Need YYSTYPE for YY_DECL. */
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Internal utility functions. */
+static void cmDependsJavaError(yyscan_t yyscanner, const char* message);
+
+#define YYDEBUG 1
+#define YYMAXDEPTH 1000000
+
+
+#define jpCheckEmpty(cnt) yyGetParser->CheckEmpty(__LINE__, cnt, yyvsp);
+#define jpElementStart(cnt) yyGetParser->PrepareElement(&yyval)
+#define jpStoreClass(str) \
+yyGetParser->AddClassFound(str); yyGetParser->DeallocateParserType(&(str))
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch statement contains default but
+ no case. */
+#endif
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+typedef int YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 214 of yacc.c. */
+#line 372 "cmDependsJavaParser.cxx"
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+# ifndef YYFREE
+# define YYFREE free
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# endif
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# endif
+# else
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short int yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined (__GNUC__) && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short int yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 23
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 2215
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 106
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 158
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 351
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 575
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 360
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned char yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned short int yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 9, 11, 13, 15, 17,
+ 19, 21, 23, 25, 27, 29, 31, 33, 35, 37,
+ 39, 41, 43, 45, 47, 49, 51, 54, 57, 59,
+ 61, 63, 65, 68, 72, 76, 80, 84, 86, 88,
+ 92, 93, 95, 96, 99, 100, 103, 107, 109, 111,
+ 115, 121, 123, 125, 127, 129, 132, 134, 136, 138,
+ 140, 142, 144, 146, 148, 150, 152, 154, 158, 161,
+ 165, 169, 174, 175, 177, 180, 183, 185, 189, 193,
+ 194, 197, 199, 201, 203, 205, 207, 209, 214, 216,
+ 220, 222, 226, 228, 232, 234, 236, 239, 242, 246,
+ 251, 256, 257, 259, 264, 268, 269, 271, 273, 277,
+ 281, 284, 286, 290, 292, 295, 300, 306, 311, 316,
+ 317, 320, 326, 332, 336, 340, 341, 343, 346, 350,
+ 354, 355, 358, 360, 362, 364, 367, 369, 372, 374,
+ 377, 379, 382, 386, 387, 389, 392, 394, 398, 402,
+ 403, 405, 407, 410, 412, 414, 416, 419, 423, 426,
+ 428, 430, 432, 434, 436, 438, 440, 442, 444, 446,
+ 448, 450, 452, 454, 456, 458, 460, 462, 464, 466,
+ 468, 470, 472, 474, 478, 482, 485, 487, 489, 491,
+ 493, 495, 497, 499, 505, 513, 521, 527, 532, 533,
+ 535, 536, 539, 542, 544, 547, 551, 554, 560, 566,
+ 574, 584, 585, 587, 588, 590, 600, 601, 603, 605,
+ 607, 609, 611, 615, 619, 625, 629, 630, 632, 636,
+ 640, 644, 650, 654, 659, 660, 662, 664, 667, 673,
+ 676, 678, 680, 682, 684, 688, 690, 692, 694, 696,
+ 703, 704, 706, 707, 709, 711, 715, 720, 725, 730,
+ 735, 736, 738, 740, 743, 747, 750, 754, 758, 762,
+ 766, 770, 775, 782, 789, 796, 801, 806, 808, 810,
+ 814, 816, 818, 821, 824, 826, 828, 831, 834, 836,
+ 839, 842, 844, 847, 850, 852, 858, 863, 869, 871,
+ 875, 879, 883, 885, 889, 893, 895, 899, 903, 907,
+ 909, 913, 917, 921, 925, 929, 931, 935, 939, 941,
+ 945, 947, 951, 953, 957, 959, 963, 965, 969, 971,
+ 977, 979, 981, 985, 987, 989, 991, 993, 995, 997,
+ 999, 1001, 1003, 1005, 1007, 1009, 1011, 1013, 1015, 1017,
+ 1019, 1021
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const short int yyrhs[] =
+{
+ 107, 0, -1, 122, -1, 109, -1, 53, -1, 50,
+ -1, 51, -1, 56, -1, 55, -1, 52, -1, 54,
+ -1, 111, -1, 112, -1, 7, -1, 36, -1, 26,
+ -1, 28, -1, 10, -1, 20, -1, 15, -1, 5,
+ -1, 113, -1, 116, -1, 117, -1, 113, -1, 113,
+ -1, 111, 234, -1, 117, 234, -1, 118, -1, 120,
+ -1, 119, -1, 57, -1, 71, 57, -1, 117, 72,
+ 119, -1, 117, 72, 11, -1, 117, 72, 42, -1,
+ 121, 72, 11, -1, 111, -1, 47, -1, 123, 124,
+ 125, -1, -1, 126, -1, -1, 124, 127, -1, -1,
+ 125, 130, -1, 31, 117, 101, -1, 128, -1, 129,
+ -1, 24, 117, 101, -1, 24, 117, 72, 103, 101,
+ -1, 134, -1, 165, -1, 101, -1, 132, -1, 131,
+ 132, -1, 34, -1, 33, -1, 32, -1, 37, -1,
+ 3, -1, 18, -1, 29, -1, 41, -1, 45, -1,
+ 48, -1, 38, -1, 135, 11, 119, -1, 133, 139,
+ -1, 133, 137, 139, -1, 133, 136, 139, -1, 133,
+ 136, 137, 139, -1, -1, 131, -1, 17, 114, -1,
+ 23, 138, -1, 115, -1, 138, 66, 115, -1, 68,
+ 140, 67, -1, -1, 140, 141, -1, 142, -1, 158,
+ -1, 159, -1, 130, -1, 143, -1, 148, -1, 135,
+ 110, 144, 101, -1, 145, -1, 144, 66, 145, -1,
+ 146, -1, 146, 73, 147, -1, 119, -1, 146, 62,
+ 61, -1, 261, -1, 174, -1, 149, 101, -1, 149,
+ 157, -1, 149, 157, 101, -1, 135, 110, 151, 150,
+ -1, 135, 47, 151, 150, -1, -1, 155, -1, 119,
+ 91, 152, 90, -1, 151, 62, 61, -1, -1, 153,
+ -1, 154, -1, 153, 66, 154, -1, 135, 110, 146,
+ -1, 44, 156, -1, 114, -1, 156, 66, 114, -1,
+ 177, -1, 37, 177, -1, 135, 160, 150, 161, -1,
+ 135, 160, 150, 161, 101, -1, 118, 91, 152, 90,
+ -1, 68, 162, 178, 67, -1, -1, 162, 163, -1,
+ 42, 91, 228, 90, 101, -1, 39, 91, 228, 90,
+ 101, -1, 135, 27, 119, -1, 164, 166, 168, -1,
+ -1, 167, -1, 17, 115, -1, 167, 66, 115, -1,
+ 68, 169, 67, -1, -1, 169, 170, -1, 171, -1,
+ 172, -1, 134, -1, 134, 101, -1, 165, -1, 165,
+ 101, -1, 143, -1, 149, 173, -1, 101, -1, 173,
+ 101, -1, 68, 175, 67, -1, -1, 176, -1, 176,
+ 66, -1, 147, -1, 176, 66, 147, -1, 68, 178,
+ 67, -1, -1, 179, -1, 180, -1, 179, 180, -1,
+ 181, -1, 183, -1, 134, -1, 182, 101, -1, 131,
+ 110, 144, -1, 110, 144, -1, 185, -1, 187, -1,
+ 191, -1, 192, -1, 201, -1, 204, -1, 185, -1,
+ 188, -1, 193, -1, 202, -1, 207, -1, 177, -1,
+ 186, -1, 189, -1, 194, -1, 203, -1, 213, -1,
+ 215, -1, 216, -1, 218, -1, 217, -1, 219, -1,
+ 212, -1, 101, -1, 119, 65, 183, -1, 119, 65,
+ 184, -1, 190, 101, -1, 258, -1, 242, -1, 243,
+ -1, 239, -1, 240, -1, 236, -1, 226, -1, 22,
+ 91, 261, 90, 183, -1, 22, 91, 261, 90, 184,
+ 16, 183, -1, 22, 91, 261, 90, 184, 16, 184,
+ -1, 40, 91, 261, 90, 195, -1, 68, 197, 196,
+ 67, -1, -1, 199, -1, -1, 197, 198, -1, 199,
+ 179, -1, 200, -1, 199, 200, -1, 8, 262, 65,
+ -1, 13, 65, -1, 49, 91, 261, 90, 183, -1,
+ 49, 91, 261, 90, 184, -1, 14, 183, 49, 91,
+ 261, 90, 101, -1, 21, 91, 206, 101, 208, 101,
+ 205, 90, 183, -1, -1, 210, -1, -1, 209, -1,
+ 21, 91, 206, 101, 208, 101, 205, 90, 184, -1,
+ -1, 261, -1, 211, -1, 182, -1, 211, -1, 190,
+ -1, 211, 66, 190, -1, 4, 261, 101, -1, 4,
+ 261, 65, 261, 101, -1, 6, 214, 101, -1, -1,
+ 119, -1, 12, 214, 101, -1, 35, 208, 101, -1,
+ 43, 261, 101, -1, 41, 91, 261, 90, 177, -1,
+ 46, 177, 221, -1, 46, 177, 220, 223, -1, -1,
+ 221, -1, 222, -1, 221, 222, -1, 9, 91, 154,
+ 90, 177, -1, 19, 177, -1, 225, -1, 230, -1,
+ 108, -1, 42, -1, 91, 261, 90, -1, 226, -1,
+ 235, -1, 236, -1, 237, -1, 263, 114, 91, 228,
+ 90, 227, -1, -1, 139, -1, -1, 229, -1, 261,
+ -1, 229, 66, 261, -1, 263, 111, 232, 231, -1,
+ 263, 113, 232, 231, -1, 263, 111, 234, 174, -1,
+ 263, 113, 234, 174, -1, -1, 234, -1, 233, -1,
+ 232, 233, -1, 62, 261, 61, -1, 62, 61, -1,
+ 234, 62, 61, -1, 224, 72, 119, -1, 39, 72,
+ 119, -1, 42, 72, 119, -1, 224, 72, 42, -1,
+ 117, 91, 228, 90, -1, 224, 72, 119, 91, 228,
+ 90, -1, 39, 72, 119, 91, 228, 90, -1, 42,
+ 72, 119, 91, 228, 90, -1, 117, 62, 261, 61,
+ -1, 225, 62, 261, 61, -1, 224, -1, 117, -1,
+ 116, 72, 11, -1, 239, -1, 240, -1, 238, 99,
+ -1, 238, 89, -1, 242, -1, 243, -1, 97, 241,
+ -1, 87, 241, -1, 244, -1, 99, 241, -1, 89,
+ 241, -1, 238, -1, 102, 241, -1, 75, 241, -1,
+ 245, -1, 91, 111, 231, 90, 241, -1, 91, 261,
+ 90, 244, -1, 91, 117, 234, 90, 244, -1, 241,
+ -1, 246, 103, 241, -1, 246, 69, 241, -1, 246,
+ 92, 241, -1, 246, -1, 247, 97, 246, -1, 247,
+ 87, 246, -1, 247, -1, 248, 86, 247, -1, 248,
+ 79, 247, -1, 248, 81, 247, -1, 248, -1, 249,
+ 84, 248, -1, 249, 77, 248, -1, 249, 85, 248,
+ -1, 249, 78, 248, -1, 249, 25, 112, -1, 249,
+ -1, 250, 74, 249, -1, 250, 76, 249, -1, 250,
+ -1, 251, 58, 250, -1, 251, -1, 252, 63, 251,
+ -1, 252, -1, 253, 94, 252, -1, 253, -1, 254,
+ 59, 253, -1, 254, -1, 255, 96, 254, -1, 255,
+ -1, 255, 100, 261, 65, 256, -1, 256, -1, 258,
+ -1, 259, 260, 257, -1, 117, -1, 235, -1, 237,
+ -1, 73, -1, 104, -1, 70, -1, 93, -1, 98,
+ -1, 88, -1, 83, -1, 80, -1, 82, -1, 60,
+ -1, 64, -1, 95, -1, 257, -1, 261, -1, 30,
+ -1, 117, 72, 30, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short int yyrline[] =
+{
+ 0, 191, 191, 200, 208, 216, 224, 232, 240, 249,
+ 257, 266, 274, 283, 288, 293, 298, 303, 308, 313,
+ 318, 324, 332, 341, 351, 360, 369, 377, 387, 393,
+ 400, 407, 413, 420, 429, 439, 449, 458, 466, 475,
+ 484, 490, 499, 505, 514, 520, 529, 541, 549, 558,
+ 570, 583, 591, 599, 608, 616, 625, 625, 625, 626,
+ 627, 627, 627, 627, 627, 627, 628, 631, 641, 650,
+ 659, 668, 678, 684, 693, 702, 711, 719, 728, 737,
+ 743, 752, 760, 768, 776, 785, 793, 802, 808, 816,
+ 825, 833, 842, 851, 860, 868, 877, 885, 893, 902,
+ 911, 921, 928, 938, 948, 955, 962, 965, 971, 981,
+ 991, 1001, 1007, 1017, 1027, 1037, 1046, 1056, 1067, 1077,
+ 1084, 1094, 1103, 1113, 1122, 1132, 1138, 1148, 1157, 1167,
+ 1177, 1184, 1193, 1202, 1211, 1220, 1228, 1237, 1246, 1256,
+ 1266, 1275, 1285, 1295, 1302, 1311, 1321, 1330, 1340, 1349,
+ 1356, 1366, 1375, 1385, 1394, 1403, 1413, 1423, 1432, 1442,
+ 1451, 1460, 1469, 1478, 1487, 1497, 1506, 1515, 1524, 1533,
+ 1543, 1552, 1561, 1570, 1579, 1588, 1597, 1606, 1615, 1624,
+ 1633, 1642, 1652, 1662, 1673, 1683, 1693, 1702, 1711, 1720,
+ 1729, 1738, 1747, 1757, 1767, 1777, 1787, 1794, 1801, 1808,
+ 1818, 1825, 1835, 1845, 1854, 1864, 1873, 1883, 1890, 1897,
+ 1904, 1912, 1919, 1929, 1936, 1946, 1956, 1963, 1973, 1982,
+ 1992, 2002, 2011, 2021, 2030, 2040, 2051, 2058, 2065, 2076,
+ 2086, 2096, 2106, 2115, 2125, 2132, 2142, 2151, 2161, 2168,
+ 2178, 2187, 2197, 2206, 2212, 2221, 2230, 2239, 2248, 2258,
+ 2268, 2275, 2285, 2292, 2302, 2311, 2321, 2330, 2339, 2348,
+ 2358, 2365, 2375, 2384, 2394, 2404, 2410, 2417, 2427, 2437,
+ 2447, 2458, 2468, 2479, 2489, 2500, 2510, 2520, 2529, 2538,
+ 2547, 2556, 2566, 2576, 2586, 2595, 2604, 2613, 2622, 2632,
+ 2642, 2652, 2661, 2670, 2679, 2689, 2698, 2707, 2714, 2723,
+ 2732, 2741, 2751, 2760, 2769, 2779, 2788, 2797, 2806, 2816,
+ 2825, 2834, 2843, 2852, 2861, 2871, 2880, 2889, 2899, 2908,
+ 2918, 2927, 2937, 2946, 2956, 2965, 2975, 2984, 2994, 3003,
+ 3013, 3022, 3032, 3042, 3052, 3061, 3071, 3080, 3089, 3098,
+ 3107, 3116, 3125, 3134, 3143, 3152, 3161, 3170, 3180, 3190,
+ 3200, 3209
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "jp_ABSTRACT", "jp_ASSERT",
+ "jp_BOOLEAN_TYPE", "jp_BREAK", "jp_BYTE_TYPE", "jp_CASE", "jp_CATCH",
+ "jp_CHAR_TYPE", "jp_CLASS", "jp_CONTINUE", "jp_DEFAULT", "jp_DO",
+ "jp_DOUBLE_TYPE", "jp_ELSE", "jp_EXTENDS", "jp_FINAL", "jp_FINALLY",
+ "jp_FLOAT_TYPE", "jp_FOR", "jp_IF", "jp_IMPLEMENTS", "jp_IMPORT",
+ "jp_INSTANCEOF", "jp_INT_TYPE", "jp_INTERFACE", "jp_LONG_TYPE",
+ "jp_NATIVE", "jp_NEW", "jp_PACKAGE", "jp_PRIVATE", "jp_PROTECTED",
+ "jp_PUBLIC", "jp_RETURN", "jp_SHORT_TYPE", "jp_STATIC", "jp_STRICTFP",
+ "jp_SUPER", "jp_SWITCH", "jp_SYNCHRONIZED", "jp_THIS", "jp_THROW",
+ "jp_THROWS", "jp_TRANSIENT", "jp_TRY", "jp_VOID", "jp_VOLATILE",
+ "jp_WHILE", "jp_BOOLEANLITERAL", "jp_CHARACTERLITERAL",
+ "jp_DECIMALINTEGERLITERAL", "jp_FLOATINGPOINTLITERAL",
+ "jp_HEXINTEGERLITERAL", "jp_NULLLITERAL", "jp_STRINGLITERAL", "jp_NAME",
+ "jp_AND", "jp_ANDAND", "jp_ANDEQUALS", "jp_BRACKETEND",
+ "jp_BRACKETSTART", "jp_CARROT", "jp_CARROTEQUALS", "jp_COLON",
+ "jp_COMMA", "jp_CURLYEND", "jp_CURLYSTART", "jp_DIVIDE",
+ "jp_DIVIDEEQUALS", "jp_DOLLAR", "jp_DOT", "jp_EQUALS", "jp_EQUALSEQUALS",
+ "jp_EXCLAMATION", "jp_EXCLAMATIONEQUALS", "jp_GREATER", "jp_GTEQUALS",
+ "jp_GTGT", "jp_GTGTEQUALS", "jp_GTGTGT", "jp_GTGTGTEQUALS",
+ "jp_LESLESEQUALS", "jp_LESSTHAN", "jp_LTEQUALS", "jp_LTLT", "jp_MINUS",
+ "jp_MINUSEQUALS", "jp_MINUSMINUS", "jp_PAREEND", "jp_PARESTART",
+ "jp_PERCENT", "jp_PERCENTEQUALS", "jp_PIPE", "jp_PIPEEQUALS",
+ "jp_PIPEPIPE", "jp_PLUS", "jp_PLUSEQUALS", "jp_PLUSPLUS", "jp_QUESTION",
+ "jp_SEMICOL", "jp_TILDE", "jp_TIMES", "jp_TIMESEQUALS", "jp_ERROR",
+ "$accept", "Goal", "Literal", "IntegerLiteral", "Type", "PrimitiveType",
+ "ReferenceType", "ClassOrInterfaceType", "ClassType", "InterfaceType",
+ "ArrayType", "Name", "SimpleName", "Identifier", "QualifiedName",
+ "SimpleType", "CompilationUnit", "PackageDeclarationopt",
+ "ImportDeclarations", "TypeDeclarations", "PackageDeclaration",
+ "ImportDeclaration", "SingleTypeImportDeclaration",
+ "TypeImportOnDemandDeclaration", "TypeDeclaration", "Modifiers",
+ "Modifier", "ClassHeader", "ClassDeclaration", "Modifiersopt", "Super",
+ "Interfaces", "InterfaceTypeList", "ClassBody", "ClassBodyDeclarations",
+ "ClassBodyDeclaration", "ClassMemberDeclaration", "FieldDeclaration",
+ "VariableDeclarators", "VariableDeclarator", "VariableDeclaratorId",
+ "VariableInitializer", "MethodDeclaration", "MethodHeader", "Throwsopt",
+ "MethodDeclarator", "FormalParameterListopt", "FormalParameterList",
+ "FormalParameter", "Throws", "ClassTypeList", "MethodBody",
+ "StaticInitializer", "ConstructorDeclaration", "ConstructorDeclarator",
+ "ConstructorBody", "ExplicitConstructorInvocationopt",
+ "ExplicitConstructorInvocation", "InterfaceHeader",
+ "InterfaceDeclaration", "ExtendsInterfacesopt", "ExtendsInterfaces",
+ "InterfaceBody", "InterfaceMemberDeclarations",
+ "InterfaceMemberDeclaration", "ConstantDeclaration",
+ "AbstractMethodDeclaration", "Semicols", "ArrayInitializer",
+ "VariableInitializersOptional", "VariableInitializers", "Block",
+ "BlockStatementsopt", "BlockStatements", "BlockStatement",
+ "LocalVariableDeclarationStatement", "LocalVariableDeclaration",
+ "Statement", "StatementNoShortIf",
+ "StatementWithoutTrailingSubstatement", "EmptyStatement",
+ "LabeledStatement", "LabeledStatementNoShortIf", "ExpressionStatement",
+ "StatementExpression", "IfThenStatement", "IfThenElseStatement",
+ "IfThenElseStatementNoShortIf", "SwitchStatement", "SwitchBlock",
+ "SwitchLabelsopt", "SwitchBlockStatementGroups",
+ "SwitchBlockStatementGroup", "SwitchLabels", "SwitchLabel",
+ "WhileStatement", "WhileStatementNoShortIf", "DoStatement",
+ "ForStatement", "ForUpdateopt", "ForInitopt", "ForStatementNoShortIf",
+ "Expressionopt", "ForInit", "ForUpdate", "StatementExpressionList",
+ "AssertStatement", "BreakStatement", "Identifieropt",
+ "ContinueStatement", "ReturnStatement", "ThrowStatement",
+ "SynchronizedStatement", "TryStatement", "Catchesopt", "Catches",
+ "CatchClause", "Finally", "Primary", "PrimaryNoNewArray",
+ "ClassInstanceCreationExpression", "ClassBodyOpt", "ArgumentListopt",
+ "ArgumentList", "ArrayCreationExpression", "Dimsopt", "DimExprs",
+ "DimExpr", "Dims", "FieldAccess", "MethodInvocation", "ArrayAccess",
+ "PostfixExpression", "PostIncrementExpression",
+ "PostDecrementExpression", "UnaryExpression", "PreIncrementExpression",
+ "PreDecrementExpression", "UnaryExpressionNotPlusMinus",
+ "CastExpression", "MultiplicativeExpression", "AdditiveExpression",
+ "ShiftExpression", "RelationalExpression", "EqualityExpression",
+ "AndExpression", "ExclusiveOrExpression", "InclusiveOrExpression",
+ "ConditionalAndExpression", "ConditionalOrExpression",
+ "ConditionalExpression", "AssignmentExpression", "Assignment",
+ "LeftHandSide", "AssignmentOperator", "Expression", "ConstantExpression",
+ "New", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short int yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+ 345, 346, 347, 348, 349, 350, 351, 352, 353, 354,
+ 355, 356, 357, 358, 359, 360
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned short int yyr1[] =
+{
+ 0, 106, 107, 108, 108, 108, 108, 108, 108, 109,
+ 109, 110, 110, 111, 111, 111, 111, 111, 111, 111,
+ 111, 112, 112, 113, 114, 115, 116, 116, 117, 117,
+ 118, 119, 119, 120, 120, 120, 120, 121, 121, 122,
+ 123, 123, 124, 124, 125, 125, 126, 127, 127, 128,
+ 129, 130, 130, 130, 131, 131, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 133, 134, 134,
+ 134, 134, 135, 135, 136, 137, 138, 138, 139, 140,
+ 140, 141, 141, 141, 141, 142, 142, 143, 144, 144,
+ 145, 145, 146, 146, 147, 147, 148, 148, 148, 149,
+ 149, 150, 150, 151, 151, 152, 152, 153, 153, 154,
+ 155, 156, 156, 157, 158, 159, 159, 160, 161, 162,
+ 162, 163, 163, 164, 165, 166, 166, 167, 167, 168,
+ 169, 169, 170, 170, 170, 170, 170, 170, 171, 172,
+ 173, 173, 174, 175, 175, 175, 176, 176, 177, 178,
+ 178, 179, 179, 180, 180, 180, 181, 182, 182, 183,
+ 183, 183, 183, 183, 183, 184, 184, 184, 184, 184,
+ 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
+ 185, 185, 186, 187, 188, 189, 190, 190, 190, 190,
+ 190, 190, 190, 191, 192, 193, 194, 195, 196, 196,
+ 197, 197, 198, 199, 199, 200, 200, 201, 202, 203,
+ 204, 205, 205, 206, 206, 207, 208, 208, 209, 209,
+ 210, 211, 211, 212, 212, 213, 214, 214, 215, 216,
+ 217, 218, 219, 219, 220, 220, 221, 221, 222, 223,
+ 224, 224, 225, 225, 225, 225, 225, 225, 225, 226,
+ 227, 227, 228, 228, 229, 229, 230, 230, 230, 230,
+ 231, 231, 232, 232, 233, 234, 234, 235, 235, 235,
+ 235, 236, 236, 236, 236, 237, 237, 238, 238, 238,
+ 238, 238, 239, 240, 241, 241, 241, 241, 241, 242,
+ 243, 244, 244, 244, 244, 245, 245, 245, 246, 246,
+ 246, 246, 247, 247, 247, 248, 248, 248, 248, 249,
+ 249, 249, 249, 249, 249, 250, 250, 250, 251, 251,
+ 252, 252, 253, 253, 254, 254, 255, 255, 256, 256,
+ 257, 257, 258, 259, 259, 259, 260, 260, 260, 260,
+ 260, 260, 260, 260, 260, 260, 260, 260, 261, 262,
+ 263, 263
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2, 1, 1,
+ 1, 1, 2, 3, 3, 3, 3, 1, 1, 3,
+ 0, 1, 0, 2, 0, 2, 3, 1, 1, 3,
+ 5, 1, 1, 1, 1, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 3, 2, 3,
+ 3, 4, 0, 1, 2, 2, 1, 3, 3, 0,
+ 2, 1, 1, 1, 1, 1, 1, 4, 1, 3,
+ 1, 3, 1, 3, 1, 1, 2, 2, 3, 4,
+ 4, 0, 1, 4, 3, 0, 1, 1, 3, 3,
+ 2, 1, 3, 1, 2, 4, 5, 4, 4, 0,
+ 2, 5, 5, 3, 3, 0, 1, 2, 3, 3,
+ 0, 2, 1, 1, 1, 2, 1, 2, 1, 2,
+ 1, 2, 3, 0, 1, 2, 1, 3, 3, 0,
+ 1, 1, 2, 1, 1, 1, 2, 3, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 3, 3, 2, 1, 1, 1, 1,
+ 1, 1, 1, 5, 7, 7, 5, 4, 0, 1,
+ 0, 2, 2, 1, 2, 3, 2, 5, 5, 7,
+ 9, 0, 1, 0, 1, 9, 0, 1, 1, 1,
+ 1, 1, 3, 3, 5, 3, 0, 1, 3, 3,
+ 3, 5, 3, 4, 0, 1, 1, 2, 5, 2,
+ 1, 1, 1, 1, 3, 1, 1, 1, 1, 6,
+ 0, 1, 0, 1, 1, 3, 4, 4, 4, 4,
+ 0, 1, 1, 2, 3, 2, 3, 3, 3, 3,
+ 3, 4, 6, 6, 6, 4, 4, 1, 1, 3,
+ 1, 1, 2, 2, 1, 1, 2, 2, 1, 2,
+ 2, 1, 2, 2, 1, 5, 4, 5, 1, 3,
+ 3, 3, 1, 3, 3, 1, 3, 3, 3, 1,
+ 3, 3, 3, 3, 3, 1, 3, 3, 1, 3,
+ 1, 3, 1, 3, 1, 3, 1, 3, 1, 5,
+ 1, 1, 3, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned short int yydefact[] =
+{
+ 40, 0, 0, 2, 42, 41, 20, 13, 17, 19,
+ 18, 15, 16, 14, 38, 31, 0, 37, 0, 28,
+ 30, 29, 0, 1, 44, 32, 0, 46, 0, 0,
+ 72, 43, 47, 48, 34, 35, 33, 36, 0, 60,
+ 61, 62, 58, 57, 56, 59, 66, 63, 64, 65,
+ 53, 45, 73, 54, 0, 51, 0, 125, 52, 0,
+ 49, 55, 0, 0, 79, 0, 0, 68, 0, 0,
+ 0, 0, 126, 0, 24, 74, 23, 25, 76, 75,
+ 72, 0, 70, 69, 67, 123, 127, 130, 124, 0,
+ 50, 0, 59, 78, 84, 0, 80, 81, 85, 86,
+ 0, 82, 83, 71, 72, 128, 77, 72, 114, 38,
+ 0, 11, 12, 21, 22, 23, 28, 101, 96, 97,
+ 113, 129, 134, 0, 138, 0, 136, 131, 132, 133,
+ 0, 226, 226, 0, 0, 0, 350, 216, 0, 0,
+ 63, 243, 0, 0, 0, 5, 6, 9, 4, 10,
+ 8, 7, 0, 0, 0, 182, 242, 3, 0, 22,
+ 333, 30, 73, 155, 0, 170, 0, 72, 151, 153,
+ 0, 154, 159, 171, 160, 172, 0, 161, 162, 173,
+ 163, 174, 164, 181, 175, 176, 177, 179, 178, 180,
+ 277, 240, 245, 241, 246, 247, 248, 0, 189, 190,
+ 187, 188, 186, 0, 0, 0, 101, 92, 0, 88,
+ 90, 101, 0, 26, 27, 72, 0, 0, 102, 98,
+ 135, 140, 139, 137, 0, 0, 0, 0, 0, 37,
+ 0, 278, 245, 247, 291, 280, 281, 298, 284, 285,
+ 288, 294, 302, 305, 309, 315, 318, 320, 322, 324,
+ 326, 328, 330, 348, 331, 0, 227, 0, 0, 0,
+ 0, 213, 0, 0, 217, 0, 0, 0, 0, 0,
+ 234, 0, 278, 246, 248, 290, 0, 289, 92, 158,
+ 0, 0, 0, 252, 0, 0, 148, 152, 156, 185,
+ 0, 0, 283, 282, 345, 346, 338, 336, 343, 344,
+ 342, 341, 339, 347, 340, 337, 0, 37, 24, 0,
+ 72, 0, 100, 0, 87, 0, 0, 99, 265, 0,
+ 0, 0, 106, 107, 111, 110, 119, 115, 141, 293,
+ 287, 37, 278, 0, 286, 292, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 223, 225,
+ 228, 0, 0, 219, 221, 0, 214, 218, 0, 229,
+ 268, 0, 0, 269, 230, 0, 0, 232, 236, 0,
+ 244, 279, 0, 351, 0, 253, 254, 183, 157, 270,
+ 267, 0, 332, 0, 260, 262, 0, 260, 0, 252,
+ 0, 104, 89, 93, 143, 91, 95, 94, 266, 0,
+ 117, 72, 0, 72, 116, 0, 26, 27, 244, 300,
+ 301, 299, 304, 303, 307, 308, 306, 314, 311, 313,
+ 310, 312, 316, 317, 319, 321, 323, 325, 327, 0,
+ 0, 0, 216, 0, 0, 252, 0, 0, 252, 72,
+ 0, 233, 237, 0, 275, 271, 0, 252, 276, 0,
+ 256, 263, 261, 258, 257, 259, 0, 103, 146, 0,
+ 144, 109, 108, 112, 0, 243, 120, 0, 0, 0,
+ 296, 0, 224, 0, 0, 222, 0, 0, 0, 30,
+ 193, 0, 159, 166, 167, 168, 169, 0, 200, 196,
+ 231, 0, 0, 239, 207, 255, 0, 264, 250, 142,
+ 145, 252, 252, 118, 295, 297, 329, 0, 211, 213,
+ 0, 0, 0, 0, 273, 198, 274, 0, 272, 251,
+ 249, 147, 0, 0, 209, 0, 212, 220, 0, 0,
+ 0, 184, 194, 0, 0, 0, 201, 72, 203, 238,
+ 0, 0, 0, 216, 0, 0, 349, 0, 206, 197,
+ 202, 204, 122, 121, 210, 0, 0, 208, 205, 211,
+ 0, 0, 195, 0, 215
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short int yydefgoto[] =
+{
+ -1, 2, 156, 157, 158, 229, 112, 113, 75, 78,
+ 230, 231, 19, 20, 21, 22, 3, 4, 24, 30,
+ 5, 31, 32, 33, 51, 52, 53, 54, 163, 164,
+ 65, 66, 79, 67, 80, 96, 97, 98, 208, 209,
+ 210, 405, 99, 100, 217, 206, 321, 322, 323, 218,
+ 325, 119, 101, 102, 117, 327, 413, 476, 57, 58,
+ 71, 72, 88, 104, 127, 128, 129, 222, 406, 469,
+ 470, 165, 166, 167, 168, 169, 170, 171, 491, 172,
+ 173, 174, 493, 175, 176, 177, 178, 494, 179, 499,
+ 545, 525, 546, 547, 548, 180, 495, 181, 182, 535,
+ 365, 496, 263, 366, 536, 367, 183, 184, 257, 185,
+ 186, 187, 188, 189, 376, 377, 378, 451, 190, 191,
+ 232, 530, 384, 385, 193, 415, 394, 395, 214, 194,
+ 233, 196, 234, 235, 236, 237, 238, 239, 240, 241,
+ 242, 243, 244, 245, 246, 247, 248, 249, 250, 251,
+ 252, 253, 254, 203, 306, 386, 557, 204
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -503
+static const short int yypact[] =
+{
+ 159, 1039, 236, -503, -503, -503, -503, -503, -503, -503,
+ -503, -503, -503, -503, -503, -503, 186, -503, 56, -503,
+ -503, -503, 178, -503, 35, -503, 21, -503, 248, 1039,
+ 273, -503, -503, -503, -503, -503, -503, -503, 78, -503,
+ -503, -503, -503, -503, -503, -503, -503, -503, -503, -503,
+ -503, -503, 2088, -503, 32, -503, 16, 245, -503, 28,
+ -503, -503, 1039, 1039, -503, 80, 206, -503, 129, 129,
+ 1039, 221, 228, 194, -503, -503, 225, -503, -503, 234,
+ 164, 206, -503, -503, -503, -503, -503, -503, -503, 1039,
+ -503, 1039, 233, -503, -503, 739, -503, -503, -503, -503,
+ -49, -503, -503, -503, 1116, -503, -503, 1276, -503, 129,
+ 129, 40, -503, -503, -503, 122, 212, 265, -503, 215,
+ -503, -503, 219, 739, -503, 222, 224, -503, -503, -503,
+ 1820, 129, 129, 1627, 237, 238, -503, 1820, 241, 239,
+ 242, 283, 1820, 233, 266, -503, -503, -503, -503, -503,
+ -503, -503, 1820, 1820, 1820, -503, -503, -503, 129, 284,
+ 476, 293, 2067, -503, 349, -503, 296, 1366, -503, -503,
+ 264, -503, -503, -503, -503, -503, 268, -503, -503, -503,
+ -503, -503, -503, -503, -503, -503, -503, -503, -503, -503,
+ 294, 305, 72, -503, 2070, 88, 2084, 121, 130, 148,
+ -503, -503, -503, 2111, 1039, 281, 133, 281, -25, -503,
+ 126, 133, 314, 315, 315, 921, 1039, 308, -503, -503,
+ -503, -503, 277, -503, 1820, 1820, 1820, 1820, 1820, 317,
+ 284, 545, -503, -503, 121, -503, -503, -503, -503, -503,
+ -503, -503, 73, 124, 163, 59, 196, 323, 319, 290,
+ 324, 18, -503, -503, -503, -30, -503, 285, 286, 242,
+ 342, 1941, 1820, 291, -503, 129, 1820, 1820, 129, 292,
+ 385, 1820, 96, -503, -503, -503, 310, -503, -503, 329,
+ 387, 1085, 3, 1820, 1627, 129, -503, -503, -503, -503,
+ 175, 1820, -503, -503, -503, -503, -503, -503, -503, -503,
+ -503, -503, -503, -503, -503, -503, 1820, 339, 339, 311,
+ 921, 343, -503, 129, -503, 344, 1766, -503, -503, 346,
+ 1039, 313, 347, -503, -503, 353, -503, 307, -503, -503,
+ -503, 6, 545, 326, -503, -503, 1820, 1820, 1820, 1820,
+ 1820, 1820, 1820, 1820, 1039, 1820, 1820, 1820, 1820, 1820,
+ 1820, 1820, 1820, 1820, 1820, 1820, 1820, 1820, -503, -503,
+ -503, 330, 2067, -503, -503, 327, -503, 354, 334, -503,
+ 345, 335, 340, 348, -503, 351, 416, 232, -503, 356,
+ -503, -503, 376, -503, 357, 377, -503, -503, 329, -503,
+ 358, 390, -503, 1085, 339, -503, 154, 339, 154, 1820,
+ 362, -503, -503, -503, 1766, -503, -503, -503, -503, 129,
+ -503, 2088, 1039, 1456, -503, 363, 70, 93, 1874, -503,
+ -503, -503, 73, 73, 124, 124, 124, -503, 163, 163,
+ 163, 163, 59, 59, 196, 323, 319, 290, 324, 383,
+ 360, 1820, 1820, 1995, 1699, 1820, 386, 233, 1820, 2088,
+ 233, -503, -503, 1627, -503, -503, 1820, 1820, -503, 394,
+ -503, -503, 315, -503, -503, -503, 369, -503, -503, 396,
+ 404, 410, -503, -503, 26, 113, -503, 407, 1820, 1874,
+ -503, 1820, -503, 391, 374, -503, 393, 395, 397, 411,
+ -503, 466, 471, -503, -503, -503, -503, 399, -503, -503,
+ -503, 400, 401, -503, -503, -503, 402, -503, 206, -503,
+ 1766, 1820, 1820, -503, -503, -503, -503, 403, 1995, 1941,
+ 1820, 1820, 1699, 1627, -503, 34, -503, 233, -503, -503,
+ -503, -503, 405, 412, -503, 413, -503, 354, 406, 418,
+ 421, -503, -503, 1820, 429, 430, -503, 1186, -503, -503,
+ 419, 422, 1627, 1820, 1699, 1699, -503, 447, -503, -503,
+ 1555, -503, -503, -503, -503, 423, 497, -503, -503, 1995,
+ 1699, 432, -503, 1699, -503
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const short int yypgoto[] =
+{
+ -503, -503, -503, -503, -85, 2, 181, -41, -198, -45,
+ -87, -1, 431, 14, -503, -503, -503, -503, -503, -503,
+ -503, -503, -503, -503, 448, -81, -47, -503, 7, -23,
+ -503, 462, -503, -64, -503, -503, -503, 425, -146, 217,
+ 123, -391, -503, 427, -101, 424, 230, -503, -360, -503,
+ -503, -503, -503, -503, -503, -503, -503, -503, -503, 439,
+ -503, -503, -503, -503, -503, -503, -503, -503, -110, -503,
+ -503, -77, 138, -12, -163, -503, -250, -13, -421, -414,
+ -503, -503, -503, -503, -252, -503, -503, -503, -503, -503,
+ -503, -503, -503, -503, 5, -503, -503, -503, -503, -16,
+ 36, -503, -418, -503, -503, -502, -503, -503, 440, -503,
+ -503, -503, -503, -503, -503, -503, 179, -503, -503, -503,
+ -54, -503, -341, -503, -503, -149, 255, -136, 102, 652,
+ 101, 688, 145, 157, 201, -98, 289, 338, -384, -503,
+ -59, -58, -92, -57, 213, 226, 218, 223, 227, -503,
+ 95, 274, 350, -503, -503, 660, -503, -503
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -336
+static const short int yytable[] =
+{
+ 18, 82, 83, 17, 287, 61, 309, 56, 114, 364,
+ 110, 363, 279, 468, 34, 108, 537, 103, 324, 107,
+ 159, 74, 77, 120, 484, 86, 162, 68, 38, 77,
+ 492, 17, 34, 383, 480, 357, 114, 55, 110, 34,
+ 36, 313, 543, 69, 105, 35, 106, 544, 77, 62,
+ 77, 472, 118, 192, 275, 63, 277, 95, 466, 29,
+ 15, 76, 76, 35, 17, 17, 270, 537, 212, 76,
+ 35, 358, 17, 36, 16, 114, 314, 285, 15, 192,
+ 159, 123, 84, 85, 344, 15, 162, 55, 76, 502,
+ 76, 17, 16, 17, 115, 515, -260, 111, 265, 16,
+ 64, 541, 212, 63, 497, 312, 160, 501, 492, 111,
+ 317, 122, -37, 192, 355, 61, 506, 511, 356, 531,
+ 260, 161, 115, 205, 207, 111, 329, 330, 26, 334,
+ 335, 73, 319, 566, 567, 565, 345, 346, -192, 388,
+ 492, 492, 336, 347, 348, 256, 256, 161, 64, 572,
+ 59, 272, 574, 272, -191, 319, 492, 27, 281, 492,
+ -261, 115, -192, 308, 111, 337, 160, 39, 282, 111,
+ 532, 533, 278, -192, 159, 74, 338, 216, -191, 60,
+ 362, 161, 40, 479, 212, 268, 15, 283, 315, -191,
+ 1, 485, 320, 41, 26, 311, 42, 43, 44, 316,
+ 16, 92, 46, 76, 512, 47, 307, 192, 195, 48,
+ 292, 339, 49, 213, 473, 76, 319, 389, 17, -280,
+ 293, 340, 404, 272, 272, 332, 272, 272, 331, -280,
+ 192, 93, 15, 114, 195, 409, 23, -281, 419, 420,
+ 421, 375, 341, 25, 342, 460, 16, -281, 464, 343,
+ 28, -235, 197, 428, 429, 430, 431, 114, 461, 37,
+ 160, 461, 70, 111, 198, 50, 364, 364, 195, 363,
+ 349, 387, 350, -39, 64, 114, 39, 285, 197, 370,
+ 422, 423, 373, 424, 425, 426, 463, 320, 465, 87,
+ 198, 40, 432, 433, 89, 90, 36, 26, 161, 278,
+ 91, 107, 41, 215, 390, 42, 43, 44, 199, 216,
+ 45, 46, 197, 265, 47, 61, 219, 364, 48, 115,
+ 220, 49, 111, 221, 198, 223, 159, 278, 261, 262,
+ 266, 213, 162, 267, 199, 272, 272, 272, 272, 272,
+ 272, 272, 272, 115, 272, 272, 272, 272, 272, 272,
+ 272, 272, 272, 272, 272, 268, 280, 271, 284, 192,
+ 68, 115, 195, 286, 111, 288, 290, 291, 199, 289,
+ 500, 74, 310, 503, 50, 318, 326, 319, 328, 212,
+ 514, 351, 352, 354, 353, 195, 359, 360, 320, 192,
+ 192, 361, 369, 374, 375, 313, 200, 287, 381, 192,
+ 380, 393, 399, 410, 401, 403, 197, 408, 414, 396,
+ 398, 76, 160, 411, 17, 111, 418, 272, 198, 412,
+ 443, 441, 200, 278, 444, 446, 320, 161, 442, 197,
+ 447, 490, 159, 416, 417, 450, 445, 454, 362, 448,
+ 504, 198, 449, 456, 529, 201, 453, 455, 481, 457,
+ 549, 458, 467, 478, 498, 507, 200, 202, 489, 508,
+ 159, 482, 199, 509, 192, 192, 162, 161, 192, 192,
+ 510, 201, 315, 159, 513, 518, 522, 272, 272, 162,
+ 272, 517, 523, 202, 519, 199, 520, -165, 521, 524,
+ 526, 527, 528, 192, 558, 550, 462, 559, 192, 462,
+ 192, 192, 551, 552, 534, 201, 192, 553, 554, 387,
+ 542, 555, 568, 570, 195, 192, 192, 202, 160, 192,
+ 562, 111, 573, 563, 569, 427, 116, 81, 94, 124,
+ 402, 125, 471, -23, 211, 560, 489, 161, 281, 564,
+ 400, 490, 504, 126, 195, 195, 160, -23, 282, 111,
+ 200, 477, 561, 571, 195, 538, 452, 542, 197, 160,
+ 564, 161, 111, 397, 434, -278, 161, 283, 489, 489,
+ 198, 436, 258, 200, 161, -278, 516, 437, 435, 0,
+ 392, 0, 438, 0, 489, 0, 0, 489, 197, 197,
+ 0, 0, 0, 0, 0, 0, 0, 0, 197, 201,
+ 198, 198, 0, 0, 0, -333, 0, 281, 0, -333,
+ 198, 202, 0, 0, 199, -333, 0, 282, -333, 195,
+ 195, 0, 201, 195, 195, -333, 0, -333, -333, 0,
+ 0, 0, 0, -333, 202, 0, 283, 0, -333, 0,
+ -333, 0, 0, -333, 199, 199, 0, 0, 195, -333,
+ 0, 0, 0, 195, 199, 195, 195, 0, 0, 0,
+ 0, 195, 0, 197, 197, 0, 0, 197, 197, 0,
+ 195, 195, 0, 0, 195, 198, 198, 0, 0, 198,
+ 198, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 197, 0, 0, 0, 0, 197, 0, 197,
+ 197, 0, 200, 0, 198, 197, 0, 0, 0, 198,
+ 0, 198, 198, 0, 197, 197, 0, 198, 197, 199,
+ 199, 0, 0, 199, 199, 0, 198, 198, 0, 0,
+ 198, 0, 200, 200, 0, 0, 0, 0, 0, 0,
+ 0, 0, 200, 0, 6, 0, 7, 0, 199, 8,
+ 68, 201, 0, 199, 9, 199, 199, 0, 0, 10,
+ 0, 199, 0, 202, 0, 11, 69, 12, 0, 0,
+ 199, 199, 0, 0, 199, 13, 0, 0, 0, 0,
+ 0, 201, 201, 0, 0, 0, 109, 0, 0, 0,
+ 255, 201, 0, 202, 202, 0, 15, 264, 0, 0,
+ 0, 0, 269, 202, 273, 0, 273, 200, 200, 0,
+ 16, 200, 200, 276, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 200, 0, 0, 0,
+ 274, 200, 274, 200, 200, 0, 0, 0, 0, 200,
+ 0, 0, 0, 0, 0, 0, 201, 201, 200, 200,
+ 201, 201, 200, 0, 0, 0, 0, 0, 202, 202,
+ 0, 0, 202, 202, 0, 0, 273, 273, 0, 273,
+ 273, 0, 0, 0, 0, 201, 333, 0, 0, 0,
+ 201, 0, 201, 201, 0, 0, 0, 202, 201, 0,
+ 0, 0, 202, 0, 202, 202, 0, 201, 201, 0,
+ 202, 201, 274, 274, 0, 274, 274, 0, 0, 202,
+ 202, 0, 368, 202, 39, 0, 371, 372, 0, 0,
+ 0, 379, 0, 0, 0, 0, 0, 0, 0, 40,
+ 0, 382, 0, 0, 0, 0, 0, 0, 0, 0,
+ 41, 391, 0, 42, 43, 44, 0, 0, 45, 46,
+ 0, 0, 47, 0, 0, 0, 48, 0, 0, 49,
+ 0, 0, 0, 0, 0, 0, 407, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 273, 273,
+ 273, 273, 273, 273, 273, 273, 0, 273, 273, 273,
+ 273, 273, 273, 273, 273, 273, 273, 273, 0, 0,
+ 0, -105, 0, 0, 0, 0, 439, 440, 0, 0,
+ 0, 0, 0, 0, 274, 274, 274, 274, 274, 274,
+ 274, 274, 0, 274, 274, 274, 274, 274, 274, 274,
+ 274, 274, 274, 274, 6, 0, 7, 0, 0, 8,
+ 0, 0, 0, 459, 9, 0, 0, 0, 0, 10,
+ 0, 0, 0, 0, 407, 11, 0, 12, 0, 0,
+ 273, 0, 0, 0, 0, 13, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 14, 0, 0, 0,
+ 6, 0, 7, 0, 0, 8, 15, 0, 0, 0,
+ 9, 483, 264, 0, 0, 10, 274, 0, 0, 0,
+ 16, 11, 0, 12, 0, 136, 505, 0, 0, 39,
+ 0, 13, 0, 0, 138, 0, 0, 141, 0, 0,
+ 273, 273, 14, 273, 40, 145, 146, 147, 148, 149,
+ 150, 151, 15, 0, 0, 41, 318, 0, 42, 43,
+ 44, 0, 0, 45, 46, 0, 16, 47, 0, 0,
+ 224, 48, 0, 0, 49, 0, 274, 274, 0, 274,
+ 407, 0, 225, 0, 152, 0, 226, 0, 0, 0,
+ 539, 540, 227, 121, 154, 0, 0, 228, 0, 39,
+ 130, 6, 131, 7, 543, 0, 8, 0, 132, 544,
+ 133, 9, 0, 556, 40, 0, 10, 134, 135, 0,
+ 0, 0, 11, 264, 12, 41, 136, 0, 42, 43,
+ 44, 137, 13, 45, 46, 138, 139, 140, 141, 142,
+ 0, 48, 143, 14, 49, 144, 145, 146, 147, 148,
+ 149, 150, 151, 15, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, -199, 107, 0, 0, 16, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 152, 0, 153, 0, 39,
+ 130, 6, 131, 7, 0, 154, 8, 155, 132, 0,
+ 133, 9, 0, 0, 40, 0, 10, 134, 135, 0,
+ 0, 0, 11, 0, 12, 41, 136, 0, 42, 43,
+ 44, 137, 13, 45, 46, 138, 139, 140, 141, 142,
+ 0, 48, 143, 14, 49, 144, 145, 146, 147, 148,
+ 149, 150, 151, 15, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, -149, 107, 0, 0, 16, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 152, 0, 153, 0, 39,
+ 130, 6, 131, 7, 0, 154, 8, 155, 132, 0,
+ 133, 9, 0, 0, 40, 0, 10, 134, 135, 0,
+ 0, 0, 11, 0, 12, 41, 136, 0, 42, 43,
+ 44, 137, 13, 45, 46, 138, 139, 140, 141, 142,
+ 0, 48, 143, 14, 49, 144, 145, 146, 147, 148,
+ 149, 150, 151, 15, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, -150, 107, 0, 0, 16, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 152, 0, 153, 0, 39,
+ 130, 6, 131, 7, 0, 154, 8, 155, 132, 0,
+ 133, 9, 0, 0, 40, 0, 10, 134, 135, 0,
+ 0, 0, 11, 0, 12, 41, 136, 0, 42, 43,
+ 44, 137, 13, 45, 46, 474, 139, 140, 475, 142,
+ 0, 48, 143, 14, 49, 144, 145, 146, 147, 148,
+ 149, 150, 151, 15, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, -149, 107, 0, 0, 16, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 152, 0, 153, 0, 0,
+ 0, 0, 0, 0, 0, 154, 0, 155, 39, 130,
+ 6, 131, 7, 0, 0, 8, -72, 132, 0, 133,
+ 9, 0, 0, 40, 0, 10, 134, 135, 0, 0,
+ 0, 11, 0, 12, 41, 136, 0, 42, 43, 44,
+ 137, 13, 45, 46, 138, 139, 140, 141, 142, 0,
+ 48, 143, 14, 49, 144, 145, 146, 147, 148, 149,
+ 150, 151, 15, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 107, 0, 0, 16, 0, 0, 0,
+ 0, 130, 6, 131, 7, 0, 0, 8, 0, 132,
+ 0, 133, 9, 0, 152, 0, 153, 10, 134, 135,
+ 0, 0, 0, 11, 154, 12, 155, 136, 0, 0,
+ 0, 0, 137, 13, 0, 0, 138, 139, 259, 141,
+ 142, 0, 0, 143, 14, 0, 144, 145, 146, 147,
+ 148, 149, 150, 151, 15, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 107, 0, 0, 16, 0,
+ 0, 0, 0, 130, 6, 131, 7, 0, 0, 8,
+ 0, 132, 0, 133, 9, 0, 152, 0, 153, 10,
+ 486, 487, 0, 0, 0, 11, 154, 12, 155, 136,
+ 0, 0, 0, 0, 137, 13, 0, 0, 138, 139,
+ 259, 141, 142, 0, 0, 143, 14, 0, 488, 145,
+ 146, 147, 148, 149, 150, 151, 15, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 107, 0, 0,
+ 16, 6, 0, 7, 0, 0, 8, 0, 0, 0,
+ 0, 9, 0, 0, 0, 0, 10, 0, 152, 0,
+ 153, 0, 11, 0, 12, 0, 136, 0, 154, 0,
+ 155, 0, 13, 0, 0, 138, 0, 0, 141, 0,
+ 0, 0, 0, 14, 0, 0, 145, 146, 147, 148,
+ 149, 150, 151, 15, 0, 6, 0, 7, 0, 0,
+ 8, 0, 0, 0, 404, 9, 0, 16, 0, 0,
+ 10, 224, 0, 0, 0, 0, 11, 0, 12, 0,
+ 136, 0, 0, 225, 0, 152, 13, 226, 0, 138,
+ 0, 0, 141, 227, 0, 154, 0, 14, 228, 0,
+ 145, 146, 147, 148, 149, 150, 151, 15, 0, 6,
+ 0, 7, 0, 0, 8, 0, 0, 0, 0, 9,
+ 0, 16, 0, 0, 10, 224, 0, 0, 0, 0,
+ 11, 0, 12, 0, 136, 0, 0, 225, 0, 152,
+ 13, 226, 0, 138, 0, 0, 141, 227, 0, 154,
+ 0, 14, 228, 0, 145, 146, 147, 148, 149, 150,
+ 151, 15, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 39, 16, 6, 0, 7, 224,
+ 0, 8, 0, 0, 0, 0, 9, 0, 0, 40,
+ 0, 10, 0, 0, 0, 226, 0, 11, 0, 12,
+ 41, 136, 0, 42, 43, 44, 228, 13, 45, 46,
+ 138, 0, 47, 141, 0, 0, 48, 0, 14, 49,
+ 0, 145, 146, 147, 148, 149, 150, 151, 15, 0,
+ 6, 0, 7, 0, 0, 8, 0, 0, 0, 0,
+ 9, 0, 16, 0, 0, 10, 0, 0, 0, 0,
+ 0, 11, 0, 12, 0, 136, 0, 0, 0, 0,
+ 152, 13, 153, 0, 138, 0, 0, 141, 0, 0,
+ 154, 0, 14, 0, 0, 145, 146, 147, 148, 149,
+ 150, 151, 15, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 16, 0, 0, 0,
+ 39, 0, 6, 0, 7, 0, 0, 8, 0, 0,
+ 0, 0, 9, 0, 152, 40, 153, 10, 0, 0,
+ 0, 39, 0, 11, 154, 12, 41, 0, 0, 42,
+ 43, 44, 0, 13, 45, 46, 40, 0, 47, 0,
+ 0, 0, 48, 0, 14, 49, 0, 41, 0, 0,
+ 42, 43, 44, 0, 15, 45, 46, 0, 0, 47,
+ -334, 0, 0, 48, -334, 0, 49, 0, 16, 0,
+ -334, 0, 0, -334, -335, 0, 0, 0, -335, 0,
+ -334, 0, -334, -334, -335, 0, 0, -335, -334, 0,
+ 0, 0, 0, -334, -335, -334, -335, -335, -334, 0,
+ 0, 294, -335, 0, -334, 295, 0, -335, 0, -335,
+ 0, 296, -335, 0, 297, 0, 0, 0, -335, 0,
+ 0, 298, 0, 299, 300, 0, 0, 0, 0, 301,
+ 0, 0, 0, 0, 302, 0, 303, 0, 0, 304,
+ 0, 0, 0, 0, 0, 305
+};
+
+static const short int yycheck[] =
+{
+ 1, 65, 66, 1, 167, 52, 204, 30, 95, 261,
+ 95, 261, 158, 404, 11, 92, 518, 81, 216, 68,
+ 107, 62, 63, 100, 442, 70, 107, 11, 29, 70,
+ 444, 29, 11, 30, 418, 65, 123, 30, 123, 11,
+ 26, 66, 8, 27, 89, 42, 91, 13, 89, 17,
+ 91, 411, 101, 107, 152, 23, 154, 80, 399, 24,
+ 57, 62, 63, 42, 62, 63, 143, 569, 62, 70,
+ 42, 101, 70, 59, 71, 162, 101, 162, 57, 133,
+ 167, 104, 68, 69, 25, 57, 167, 80, 89, 449,
+ 91, 89, 71, 91, 95, 479, 90, 95, 72, 71,
+ 68, 522, 62, 23, 445, 206, 107, 448, 522, 107,
+ 211, 104, 72, 167, 96, 162, 457, 91, 100, 510,
+ 133, 107, 123, 109, 110, 123, 224, 225, 72, 227,
+ 228, 103, 62, 554, 555, 553, 77, 78, 66, 285,
+ 554, 555, 69, 84, 85, 131, 132, 133, 68, 570,
+ 72, 152, 573, 154, 66, 62, 570, 101, 62, 573,
+ 90, 162, 90, 204, 162, 92, 167, 3, 72, 167,
+ 511, 512, 158, 101, 261, 216, 103, 44, 90, 101,
+ 261, 167, 18, 90, 62, 72, 57, 91, 62, 101,
+ 31, 443, 215, 29, 72, 62, 32, 33, 34, 73,
+ 71, 37, 38, 204, 91, 41, 204, 261, 107, 45,
+ 89, 87, 48, 111, 412, 216, 62, 42, 216, 89,
+ 99, 97, 68, 224, 225, 226, 227, 228, 226, 99,
+ 284, 67, 57, 320, 133, 320, 0, 89, 336, 337,
+ 338, 9, 79, 57, 81, 394, 71, 99, 397, 86,
+ 72, 19, 107, 345, 346, 347, 348, 344, 394, 11,
+ 261, 397, 17, 261, 107, 101, 518, 519, 167, 519,
+ 74, 284, 76, 0, 68, 362, 3, 362, 133, 265,
+ 339, 340, 268, 341, 342, 343, 396, 310, 398, 68,
+ 133, 18, 349, 350, 66, 101, 282, 72, 284, 285,
+ 66, 68, 29, 91, 290, 32, 33, 34, 107, 44,
+ 37, 38, 167, 72, 41, 362, 101, 569, 45, 320,
+ 101, 48, 320, 101, 167, 101, 413, 313, 91, 91,
+ 91, 229, 413, 91, 133, 336, 337, 338, 339, 340,
+ 341, 342, 343, 344, 345, 346, 347, 348, 349, 350,
+ 351, 352, 353, 354, 355, 72, 72, 91, 65, 413,
+ 11, 362, 261, 67, 362, 101, 72, 62, 167, 101,
+ 447, 412, 91, 450, 101, 61, 68, 62, 101, 62,
+ 478, 58, 63, 59, 94, 284, 101, 101, 411, 443,
+ 444, 49, 101, 101, 9, 66, 107, 560, 11, 453,
+ 90, 62, 91, 90, 61, 61, 261, 61, 101, 307,
+ 308, 412, 413, 66, 412, 413, 90, 418, 261, 66,
+ 66, 91, 133, 409, 90, 90, 449, 413, 101, 284,
+ 90, 444, 519, 331, 332, 19, 91, 61, 519, 91,
+ 453, 284, 91, 66, 508, 107, 90, 90, 65, 91,
+ 527, 61, 90, 90, 68, 61, 167, 107, 444, 90,
+ 547, 101, 261, 67, 518, 519, 547, 453, 522, 523,
+ 66, 133, 62, 560, 67, 101, 65, 478, 479, 560,
+ 481, 90, 16, 133, 91, 284, 91, 16, 91, 90,
+ 90, 90, 90, 547, 65, 90, 394, 67, 552, 397,
+ 554, 555, 90, 90, 101, 167, 560, 101, 90, 522,
+ 523, 90, 65, 16, 413, 569, 570, 167, 519, 573,
+ 101, 519, 90, 101, 101, 344, 95, 65, 80, 104,
+ 313, 104, 409, 57, 110, 547, 522, 523, 62, 552,
+ 310, 554, 555, 104, 443, 444, 547, 71, 72, 547,
+ 261, 413, 547, 569, 453, 519, 377, 570, 413, 560,
+ 573, 547, 560, 308, 351, 89, 552, 91, 554, 555,
+ 413, 353, 132, 284, 560, 99, 481, 354, 352, -1,
+ 306, -1, 355, -1, 570, -1, -1, 573, 443, 444,
+ -1, -1, -1, -1, -1, -1, -1, -1, 453, 261,
+ 443, 444, -1, -1, -1, 60, -1, 62, -1, 64,
+ 453, 261, -1, -1, 413, 70, -1, 72, 73, 518,
+ 519, -1, 284, 522, 523, 80, -1, 82, 83, -1,
+ -1, -1, -1, 88, 284, -1, 91, -1, 93, -1,
+ 95, -1, -1, 98, 443, 444, -1, -1, 547, 104,
+ -1, -1, -1, 552, 453, 554, 555, -1, -1, -1,
+ -1, 560, -1, 518, 519, -1, -1, 522, 523, -1,
+ 569, 570, -1, -1, 573, 518, 519, -1, -1, 522,
+ 523, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 547, -1, -1, -1, -1, 552, -1, 554,
+ 555, -1, 413, -1, 547, 560, -1, -1, -1, 552,
+ -1, 554, 555, -1, 569, 570, -1, 560, 573, 518,
+ 519, -1, -1, 522, 523, -1, 569, 570, -1, -1,
+ 573, -1, 443, 444, -1, -1, -1, -1, -1, -1,
+ -1, -1, 453, -1, 5, -1, 7, -1, 547, 10,
+ 11, 413, -1, 552, 15, 554, 555, -1, -1, 20,
+ -1, 560, -1, 413, -1, 26, 27, 28, -1, -1,
+ 569, 570, -1, -1, 573, 36, -1, -1, -1, -1,
+ -1, 443, 444, -1, -1, -1, 47, -1, -1, -1,
+ 130, 453, -1, 443, 444, -1, 57, 137, -1, -1,
+ -1, -1, 142, 453, 152, -1, 154, 518, 519, -1,
+ 71, 522, 523, 153, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 547, -1, -1, -1,
+ 152, 552, 154, 554, 555, -1, -1, -1, -1, 560,
+ -1, -1, -1, -1, -1, -1, 518, 519, 569, 570,
+ 522, 523, 573, -1, -1, -1, -1, -1, 518, 519,
+ -1, -1, 522, 523, -1, -1, 224, 225, -1, 227,
+ 228, -1, -1, -1, -1, 547, 226, -1, -1, -1,
+ 552, -1, 554, 555, -1, -1, -1, 547, 560, -1,
+ -1, -1, 552, -1, 554, 555, -1, 569, 570, -1,
+ 560, 573, 224, 225, -1, 227, 228, -1, -1, 569,
+ 570, -1, 262, 573, 3, -1, 266, 267, -1, -1,
+ -1, 271, -1, -1, -1, -1, -1, -1, -1, 18,
+ -1, 281, -1, -1, -1, -1, -1, -1, -1, -1,
+ 29, 291, -1, 32, 33, 34, -1, -1, 37, 38,
+ -1, -1, 41, -1, -1, -1, 45, -1, -1, 48,
+ -1, -1, -1, -1, -1, -1, 316, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 336, 337,
+ 338, 339, 340, 341, 342, 343, -1, 345, 346, 347,
+ 348, 349, 350, 351, 352, 353, 354, 355, -1, -1,
+ -1, 90, -1, -1, -1, -1, 356, 357, -1, -1,
+ -1, -1, -1, -1, 336, 337, 338, 339, 340, 341,
+ 342, 343, -1, 345, 346, 347, 348, 349, 350, 351,
+ 352, 353, 354, 355, 5, -1, 7, -1, -1, 10,
+ -1, -1, -1, 393, 15, -1, -1, -1, -1, 20,
+ -1, -1, -1, -1, 404, 26, -1, 28, -1, -1,
+ 418, -1, -1, -1, -1, 36, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 47, -1, -1, -1,
+ 5, -1, 7, -1, -1, 10, 57, -1, -1, -1,
+ 15, 441, 442, -1, -1, 20, 418, -1, -1, -1,
+ 71, 26, -1, 28, -1, 30, 456, -1, -1, 3,
+ -1, 36, -1, -1, 39, -1, -1, 42, -1, -1,
+ 478, 479, 47, 481, 18, 50, 51, 52, 53, 54,
+ 55, 56, 57, -1, -1, 29, 61, -1, 32, 33,
+ 34, -1, -1, 37, 38, -1, 71, 41, -1, -1,
+ 75, 45, -1, -1, 48, -1, 478, 479, -1, 481,
+ 510, -1, 87, -1, 89, -1, 91, -1, -1, -1,
+ 520, 521, 97, 67, 99, -1, -1, 102, -1, 3,
+ 4, 5, 6, 7, 8, -1, 10, -1, 12, 13,
+ 14, 15, -1, 543, 18, -1, 20, 21, 22, -1,
+ -1, -1, 26, 553, 28, 29, 30, -1, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ -1, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 67, 68, -1, -1, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 89, -1, 91, -1, 3,
+ 4, 5, 6, 7, -1, 99, 10, 101, 12, -1,
+ 14, 15, -1, -1, 18, -1, 20, 21, 22, -1,
+ -1, -1, 26, -1, 28, 29, 30, -1, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ -1, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 67, 68, -1, -1, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 89, -1, 91, -1, 3,
+ 4, 5, 6, 7, -1, 99, 10, 101, 12, -1,
+ 14, 15, -1, -1, 18, -1, 20, 21, 22, -1,
+ -1, -1, 26, -1, 28, 29, 30, -1, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ -1, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 67, 68, -1, -1, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 89, -1, 91, -1, 3,
+ 4, 5, 6, 7, -1, 99, 10, 101, 12, -1,
+ 14, 15, -1, -1, 18, -1, 20, 21, 22, -1,
+ -1, -1, 26, -1, 28, 29, 30, -1, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ -1, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 67, 68, -1, -1, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 89, -1, 91, -1, -1,
+ -1, -1, -1, -1, -1, 99, -1, 101, 3, 4,
+ 5, 6, 7, -1, -1, 10, 11, 12, -1, 14,
+ 15, -1, -1, 18, -1, 20, 21, 22, -1, -1,
+ -1, 26, -1, 28, 29, 30, -1, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, -1,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 68, -1, -1, 71, -1, -1, -1,
+ -1, 4, 5, 6, 7, -1, -1, 10, -1, 12,
+ -1, 14, 15, -1, 89, -1, 91, 20, 21, 22,
+ -1, -1, -1, 26, 99, 28, 101, 30, -1, -1,
+ -1, -1, 35, 36, -1, -1, 39, 40, 41, 42,
+ 43, -1, -1, 46, 47, -1, 49, 50, 51, 52,
+ 53, 54, 55, 56, 57, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 68, -1, -1, 71, -1,
+ -1, -1, -1, 4, 5, 6, 7, -1, -1, 10,
+ -1, 12, -1, 14, 15, -1, 89, -1, 91, 20,
+ 21, 22, -1, -1, -1, 26, 99, 28, 101, 30,
+ -1, -1, -1, -1, 35, 36, -1, -1, 39, 40,
+ 41, 42, 43, -1, -1, 46, 47, -1, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 68, -1, -1,
+ 71, 5, -1, 7, -1, -1, 10, -1, -1, -1,
+ -1, 15, -1, -1, -1, -1, 20, -1, 89, -1,
+ 91, -1, 26, -1, 28, -1, 30, -1, 99, -1,
+ 101, -1, 36, -1, -1, 39, -1, -1, 42, -1,
+ -1, -1, -1, 47, -1, -1, 50, 51, 52, 53,
+ 54, 55, 56, 57, -1, 5, -1, 7, -1, -1,
+ 10, -1, -1, -1, 68, 15, -1, 71, -1, -1,
+ 20, 75, -1, -1, -1, -1, 26, -1, 28, -1,
+ 30, -1, -1, 87, -1, 89, 36, 91, -1, 39,
+ -1, -1, 42, 97, -1, 99, -1, 47, 102, -1,
+ 50, 51, 52, 53, 54, 55, 56, 57, -1, 5,
+ -1, 7, -1, -1, 10, -1, -1, -1, -1, 15,
+ -1, 71, -1, -1, 20, 75, -1, -1, -1, -1,
+ 26, -1, 28, -1, 30, -1, -1, 87, -1, 89,
+ 36, 91, -1, 39, -1, -1, 42, 97, -1, 99,
+ -1, 47, 102, -1, 50, 51, 52, 53, 54, 55,
+ 56, 57, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 3, 71, 5, -1, 7, 75,
+ -1, 10, -1, -1, -1, -1, 15, -1, -1, 18,
+ -1, 20, -1, -1, -1, 91, -1, 26, -1, 28,
+ 29, 30, -1, 32, 33, 34, 102, 36, 37, 38,
+ 39, -1, 41, 42, -1, -1, 45, -1, 47, 48,
+ -1, 50, 51, 52, 53, 54, 55, 56, 57, -1,
+ 5, -1, 7, -1, -1, 10, -1, -1, -1, -1,
+ 15, -1, 71, -1, -1, 20, -1, -1, -1, -1,
+ -1, 26, -1, 28, -1, 30, -1, -1, -1, -1,
+ 89, 36, 91, -1, 39, -1, -1, 42, -1, -1,
+ 99, -1, 47, -1, -1, 50, 51, 52, 53, 54,
+ 55, 56, 57, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 71, -1, -1, -1,
+ 3, -1, 5, -1, 7, -1, -1, 10, -1, -1,
+ -1, -1, 15, -1, 89, 18, 91, 20, -1, -1,
+ -1, 3, -1, 26, 99, 28, 29, -1, -1, 32,
+ 33, 34, -1, 36, 37, 38, 18, -1, 41, -1,
+ -1, -1, 45, -1, 47, 48, -1, 29, -1, -1,
+ 32, 33, 34, -1, 57, 37, 38, -1, -1, 41,
+ 60, -1, -1, 45, 64, -1, 48, -1, 71, -1,
+ 70, -1, -1, 73, 60, -1, -1, -1, 64, -1,
+ 80, -1, 82, 83, 70, -1, -1, 73, 88, -1,
+ -1, -1, -1, 93, 80, 95, 82, 83, 98, -1,
+ -1, 60, 88, -1, 104, 64, -1, 93, -1, 95,
+ -1, 70, 98, -1, 73, -1, -1, -1, 104, -1,
+ -1, 80, -1, 82, 83, -1, -1, -1, -1, 88,
+ -1, -1, -1, -1, 93, -1, 95, -1, -1, 98,
+ -1, -1, -1, -1, -1, 104
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned short int yystos[] =
+{
+ 0, 31, 107, 122, 123, 126, 5, 7, 10, 15,
+ 20, 26, 28, 36, 47, 57, 71, 111, 117, 118,
+ 119, 120, 121, 0, 124, 57, 72, 101, 72, 24,
+ 125, 127, 128, 129, 11, 42, 119, 11, 117, 3,
+ 18, 29, 32, 33, 34, 37, 38, 41, 45, 48,
+ 101, 130, 131, 132, 133, 134, 135, 164, 165, 72,
+ 101, 132, 17, 23, 68, 136, 137, 139, 11, 27,
+ 17, 166, 167, 103, 113, 114, 117, 113, 115, 138,
+ 140, 137, 139, 139, 119, 119, 115, 68, 168, 66,
+ 101, 66, 37, 67, 130, 135, 141, 142, 143, 148,
+ 149, 158, 159, 139, 169, 115, 115, 68, 177, 47,
+ 110, 111, 112, 113, 116, 117, 118, 160, 101, 157,
+ 177, 67, 134, 135, 143, 149, 165, 170, 171, 172,
+ 4, 6, 12, 14, 21, 22, 30, 35, 39, 40,
+ 41, 42, 43, 46, 49, 50, 51, 52, 53, 54,
+ 55, 56, 89, 91, 99, 101, 108, 109, 110, 116,
+ 117, 119, 131, 134, 135, 177, 178, 179, 180, 181,
+ 182, 183, 185, 186, 187, 189, 190, 191, 192, 194,
+ 201, 203, 204, 212, 213, 215, 216, 217, 218, 219,
+ 224, 225, 226, 230, 235, 236, 237, 238, 239, 240,
+ 242, 243, 258, 259, 263, 119, 151, 119, 144, 145,
+ 146, 151, 62, 234, 234, 91, 44, 150, 155, 101,
+ 101, 101, 173, 101, 75, 87, 91, 97, 102, 111,
+ 116, 117, 226, 236, 238, 239, 240, 241, 242, 243,
+ 244, 245, 246, 247, 248, 249, 250, 251, 252, 253,
+ 254, 255, 256, 257, 258, 261, 119, 214, 214, 41,
+ 183, 91, 91, 208, 261, 72, 91, 91, 72, 261,
+ 177, 91, 117, 235, 237, 241, 261, 241, 119, 144,
+ 72, 62, 72, 91, 65, 110, 67, 180, 101, 101,
+ 72, 62, 89, 99, 60, 64, 70, 73, 80, 82,
+ 83, 88, 93, 95, 98, 104, 260, 111, 113, 114,
+ 91, 62, 150, 66, 101, 62, 73, 150, 61, 62,
+ 135, 152, 153, 154, 114, 156, 68, 161, 101, 241,
+ 241, 111, 117, 261, 241, 241, 69, 92, 103, 87,
+ 97, 79, 81, 86, 25, 77, 78, 84, 85, 74,
+ 76, 58, 63, 94, 59, 96, 100, 65, 101, 101,
+ 101, 49, 131, 182, 190, 206, 209, 211, 261, 101,
+ 119, 261, 261, 119, 101, 9, 220, 221, 222, 261,
+ 90, 11, 261, 30, 228, 229, 261, 183, 144, 42,
+ 119, 261, 257, 62, 232, 233, 234, 232, 234, 91,
+ 152, 61, 145, 61, 68, 147, 174, 261, 61, 110,
+ 90, 66, 66, 162, 101, 231, 234, 234, 90, 241,
+ 241, 241, 246, 246, 247, 247, 247, 112, 248, 248,
+ 248, 248, 249, 249, 250, 251, 252, 253, 254, 261,
+ 261, 91, 101, 66, 90, 91, 90, 90, 91, 91,
+ 19, 223, 222, 90, 61, 90, 66, 91, 61, 261,
+ 231, 233, 234, 174, 231, 174, 228, 90, 147, 175,
+ 176, 146, 154, 114, 39, 42, 163, 178, 90, 90,
+ 244, 65, 101, 261, 208, 190, 21, 22, 49, 119,
+ 183, 184, 185, 188, 193, 202, 207, 228, 68, 195,
+ 177, 228, 154, 177, 183, 261, 228, 61, 90, 67,
+ 66, 91, 91, 67, 241, 244, 256, 90, 101, 91,
+ 91, 91, 65, 16, 90, 197, 90, 90, 90, 139,
+ 227, 147, 228, 228, 101, 205, 210, 211, 206, 261,
+ 261, 184, 183, 8, 13, 196, 198, 199, 200, 177,
+ 90, 90, 90, 101, 90, 90, 261, 262, 65, 67,
+ 179, 200, 101, 101, 183, 208, 184, 184, 65, 101,
+ 16, 205, 184, 90, 184
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ ((Current).first_line = (Rhs)[1].first_line, \
+ (Current).first_column = (Rhs)[1].first_column, \
+ (Current).last_line = (Rhs)[N].last_line, \
+ (Current).last_column = (Rhs)[N].last_column)
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval)
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short int *bottom, short int *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short int *bottom;
+ short int *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if defined (YYMAXDEPTH) && YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ /* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ short int yyssa[YYINITDEPTH];
+ short int *yyss = yyssa;
+ short int *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short int *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short int *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+#line 192 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 3:
+#line 201 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 4:
+#line 209 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 5:
+#line 217 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 6:
+#line 225 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 7:
+#line 233 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 8:
+#line 241 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 9:
+#line 250 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 10:
+#line 258 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 11:
+#line 267 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 12:
+#line 275 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 13:
+#line 284 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+}
+ break;
+
+ case 14:
+#line 289 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+}
+ break;
+
+ case 15:
+#line 294 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+}
+ break;
+
+ case 16:
+#line 299 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+}
+ break;
+
+ case 17:
+#line 304 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+}
+ break;
+
+ case 18:
+#line 309 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+}
+ break;
+
+ case 19:
+#line 314 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+}
+ break;
+
+ case 20:
+#line 319 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+}
+ break;
+
+ case 21:
+#line 325 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 22:
+#line 333 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 23:
+#line 342 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpStoreClass(yyvsp[0].str);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 24:
+#line 352 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 25:
+#line 361 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 26:
+#line 370 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 27:
+#line 378 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpStoreClass(yyvsp[-1].str);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 28:
+#line 388 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ yyval.str = yyvsp[0].str;
+}
+ break;
+
+ case 29:
+#line 394 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ yyval.str = yyvsp[0].str;
+}
+ break;
+
+ case 30:
+#line 401 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ yyval.str = yyvsp[0].str;
+}
+ break;
+
+ case 31:
+#line 408 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ yyval.str = yyvsp[0].str;
+}
+ break;
+
+ case 32:
+#line 414 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ yyval.str = yyvsp[0].str;
+}
+ break;
+
+ case 33:
+#line 421 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ yyGetParser->AddClassFound(yyvsp[-2].str);
+ yyGetParser->UpdateCombine(yyvsp[-2].str, yyvsp[0].str);
+ yyGetParser->DeallocateParserType(&(yyvsp[-2].str));
+ yyval.str = const_cast<char*>(yyGetParser->GetCurrentCombine());
+}
+ break;
+
+ case 34:
+#line 430 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpStoreClass(yyvsp[-2].str);
+ jpCheckEmpty(3);
+ yyGetParser->SetCurrentCombine("");
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 35:
+#line 440 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpStoreClass(yyvsp[-2].str);
+ yyGetParser->SetCurrentCombine("");
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 36:
+#line 450 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 37:
+#line 459 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 38:
+#line 467 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 39:
+#line 476 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 40:
+#line 484 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 41:
+#line 491 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 42:
+#line 499 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 43:
+#line 506 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 44:
+#line 514 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 45:
+#line 521 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 46:
+#line 530 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ yyGetParser->SetCurrentPackage(yyvsp[-1].str);
+ yyGetParser->DeallocateParserType(&(yyvsp[-1].str));
+ yyGetParser->SetCurrentCombine("");
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 47:
+#line 542 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 48:
+#line 550 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 49:
+#line 559 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ yyGetParser->AddPackagesImport(yyvsp[-1].str);
+ yyGetParser->DeallocateParserType(&(yyvsp[-1].str));
+ yyGetParser->SetCurrentCombine("");
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 50:
+#line 571 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+ std::string str = yyvsp[-3].str;
+ str += ".*";
+ yyGetParser->AddPackagesImport(str.c_str());
+ yyGetParser->DeallocateParserType(&(yyvsp[-3].str));
+ yyGetParser->SetCurrentCombine("");
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 51:
+#line 584 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 52:
+#line 592 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 53:
+#line 600 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 54:
+#line 609 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 55:
+#line 617 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 67:
+#line 632 "cmDependsJavaParser.y"
+ {
+ yyGetParser->StartClass(yyvsp[0].str);
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&(yyvsp[0].str));
+ jpCheckEmpty(3);
+}
+ break;
+
+ case 68:
+#line 642 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+ break;
+
+ case 69:
+#line 651 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+ break;
+
+ case 70:
+#line 660 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+ break;
+
+ case 71:
+#line 669 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+ break;
+
+ case 72:
+#line 678 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 73:
+#line 685 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 74:
+#line 694 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 75:
+#line 703 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 76:
+#line 712 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 77:
+#line 720 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 78:
+#line 729 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 79:
+#line 737 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 80:
+#line 744 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 81:
+#line 753 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 82:
+#line 761 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 83:
+#line 769 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 84:
+#line 777 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 85:
+#line 786 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 86:
+#line 794 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 87:
+#line 803 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+}
+ break;
+
+ case 88:
+#line 809 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 89:
+#line 817 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 90:
+#line 826 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 91:
+#line 834 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 92:
+#line 843 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ yyGetParser->DeallocateParserType(&(yyvsp[0].str));
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 93:
+#line 852 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 94:
+#line 861 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 95:
+#line 869 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 96:
+#line 878 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 97:
+#line 886 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 98:
+#line 894 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 99:
+#line 903 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 100:
+#line 912 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 101:
+#line 921 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 102:
+#line 929 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 103:
+#line 939 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&(yyvsp[-3].str));
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 104:
+#line 949 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+
+}
+ break;
+
+ case 105:
+#line 955 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 107:
+#line 966 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+
+}
+ break;
+
+ case 108:
+#line 972 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 109:
+#line 982 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 110:
+#line 992 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 111:
+#line 1002 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+
+}
+ break;
+
+ case 112:
+#line 1008 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 113:
+#line 1018 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 114:
+#line 1028 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 115:
+#line 1038 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 116:
+#line 1047 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 117:
+#line 1057 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&(yyvsp[-3].str));
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 118:
+#line 1068 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 119:
+#line 1077 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 120:
+#line 1085 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 121:
+#line 1095 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 122:
+#line 1104 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 123:
+#line 1114 "cmDependsJavaParser.y"
+ {
+ yyGetParser->StartClass(yyvsp[0].str);
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&(yyvsp[0].str));
+ jpCheckEmpty(3);
+}
+ break;
+
+ case 124:
+#line 1123 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+ break;
+
+ case 125:
+#line 1132 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+ break;
+
+ case 126:
+#line 1139 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 127:
+#line 1149 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 128:
+#line 1158 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 129:
+#line 1168 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 130:
+#line 1177 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 131:
+#line 1185 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 132:
+#line 1194 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 133:
+#line 1203 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 134:
+#line 1212 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 135:
+#line 1221 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 136:
+#line 1229 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 137:
+#line 1238 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 138:
+#line 1247 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 139:
+#line 1257 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 140:
+#line 1267 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 141:
+#line 1276 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 142:
+#line 1286 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 143:
+#line 1295 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 144:
+#line 1303 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 145:
+#line 1312 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 146:
+#line 1322 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 147:
+#line 1331 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 148:
+#line 1341 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 149:
+#line 1349 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 150:
+#line 1357 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 151:
+#line 1367 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 152:
+#line 1376 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 153:
+#line 1386 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 154:
+#line 1395 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 155:
+#line 1404 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 156:
+#line 1414 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 157:
+#line 1424 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 158:
+#line 1433 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 159:
+#line 1443 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 160:
+#line 1452 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 161:
+#line 1461 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 162:
+#line 1470 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 163:
+#line 1479 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 164:
+#line 1488 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 165:
+#line 1498 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 166:
+#line 1507 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 167:
+#line 1516 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 168:
+#line 1525 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 169:
+#line 1534 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 170:
+#line 1544 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 171:
+#line 1553 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 172:
+#line 1562 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 173:
+#line 1571 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 174:
+#line 1580 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 175:
+#line 1589 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 176:
+#line 1598 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 177:
+#line 1607 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 178:
+#line 1616 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 179:
+#line 1625 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 180:
+#line 1634 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 181:
+#line 1643 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 182:
+#line 1653 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 183:
+#line 1663 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&(yyvsp[-2].str));
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 184:
+#line 1674 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 185:
+#line 1684 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 186:
+#line 1694 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 187:
+#line 1703 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 188:
+#line 1712 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 189:
+#line 1721 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 190:
+#line 1730 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 191:
+#line 1739 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 192:
+#line 1748 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 193:
+#line 1758 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 194:
+#line 1768 "cmDependsJavaParser.y"
+ {
+ jpElementStart(7);
+ jpCheckEmpty(7);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 195:
+#line 1778 "cmDependsJavaParser.y"
+ {
+ jpElementStart(7);
+ jpCheckEmpty(7);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 196:
+#line 1788 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+
+}
+ break;
+
+ case 197:
+#line 1795 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+
+}
+ break;
+
+ case 198:
+#line 1801 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 199:
+#line 1809 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 200:
+#line 1818 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 201:
+#line 1826 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 202:
+#line 1836 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 203:
+#line 1846 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 204:
+#line 1855 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 205:
+#line 1865 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 206:
+#line 1874 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 207:
+#line 1884 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+
+}
+ break;
+
+ case 208:
+#line 1891 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+
+}
+ break;
+
+ case 209:
+#line 1898 "cmDependsJavaParser.y"
+ {
+ jpElementStart(7);
+
+}
+ break;
+
+ case 210:
+#line 1906 "cmDependsJavaParser.y"
+ {
+ jpElementStart(9);
+
+}
+ break;
+
+ case 211:
+#line 1912 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 212:
+#line 1920 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 213:
+#line 1929 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 214:
+#line 1937 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 215:
+#line 1948 "cmDependsJavaParser.y"
+ {
+ jpElementStart(9);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 216:
+#line 1956 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 217:
+#line 1964 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 218:
+#line 1974 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 219:
+#line 1983 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 220:
+#line 1993 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 221:
+#line 2003 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 222:
+#line 2012 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 223:
+#line 2022 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 224:
+#line 2031 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 225:
+#line 2041 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&(yyvsp[-1].str));
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 226:
+#line 2051 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 227:
+#line 2059 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+
+}
+ break;
+
+ case 228:
+#line 2066 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&(yyvsp[-1].str));
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 229:
+#line 2077 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 230:
+#line 2087 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 231:
+#line 2097 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 232:
+#line 2107 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 233:
+#line 2116 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 234:
+#line 2125 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 235:
+#line 2133 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 236:
+#line 2143 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 237:
+#line 2152 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 238:
+#line 2162 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+
+}
+ break;
+
+ case 239:
+#line 2169 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 240:
+#line 2179 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 241:
+#line 2188 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 242:
+#line 2198 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 243:
+#line 2207 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+
+}
+ break;
+
+ case 244:
+#line 2213 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 245:
+#line 2222 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 246:
+#line 2231 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 247:
+#line 2240 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 248:
+#line 2249 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 249:
+#line 2259 "cmDependsJavaParser.y"
+ {
+ jpElementStart(6);
+ jpCheckEmpty(6);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 250:
+#line 2268 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 251:
+#line 2276 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 252:
+#line 2285 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 253:
+#line 2293 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 254:
+#line 2303 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 255:
+#line 2312 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 256:
+#line 2322 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 257:
+#line 2331 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 258:
+#line 2340 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 259:
+#line 2349 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 260:
+#line 2358 "cmDependsJavaParser.y"
+ {
+ jpElementStart(0);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 261:
+#line 2366 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 262:
+#line 2376 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 263:
+#line 2385 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 264:
+#line 2395 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 265:
+#line 2405 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+
+}
+ break;
+
+ case 266:
+#line 2411 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+
+}
+ break;
+
+ case 267:
+#line 2418 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&(yyvsp[0].str));
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 268:
+#line 2428 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&(yyvsp[0].str));
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 269:
+#line 2438 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&(yyvsp[0].str));
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 270:
+#line 2448 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&(yyvsp[0].str));
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 271:
+#line 2459 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&(yyvsp[-3].str));
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 272:
+#line 2469 "cmDependsJavaParser.y"
+ {
+ jpElementStart(6);
+ yyGetParser->DeallocateParserType(&(yyvsp[-5].str));
+ yyGetParser->DeallocateParserType(&(yyvsp[-3].str));
+ jpCheckEmpty(6);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 273:
+#line 2480 "cmDependsJavaParser.y"
+ {
+ jpElementStart(6);
+ yyGetParser->DeallocateParserType(&(yyvsp[-3].str));
+ jpCheckEmpty(6);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 274:
+#line 2490 "cmDependsJavaParser.y"
+ {
+ jpElementStart(6);
+ yyGetParser->DeallocateParserType(&(yyvsp[-3].str));
+ jpCheckEmpty(6);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 275:
+#line 2501 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&(yyvsp[-3].str));
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 276:
+#line 2511 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 277:
+#line 2521 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 278:
+#line 2530 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ yyGetParser->DeallocateParserType(&(yyvsp[0].str));
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 279:
+#line 2539 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 280:
+#line 2548 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 281:
+#line 2557 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 282:
+#line 2567 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 283:
+#line 2577 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 284:
+#line 2587 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 285:
+#line 2596 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 286:
+#line 2605 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 287:
+#line 2614 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 288:
+#line 2623 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 289:
+#line 2633 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 290:
+#line 2643 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 291:
+#line 2653 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 292:
+#line 2662 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 293:
+#line 2671 "cmDependsJavaParser.y"
+ {
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 294:
+#line 2680 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 295:
+#line 2690 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 296:
+#line 2699 "cmDependsJavaParser.y"
+ {
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 297:
+#line 2708 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+
+}
+ break;
+
+ case 298:
+#line 2715 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 299:
+#line 2724 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 300:
+#line 2733 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 301:
+#line 2742 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 302:
+#line 2752 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 303:
+#line 2761 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 304:
+#line 2770 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 305:
+#line 2780 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 306:
+#line 2789 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 307:
+#line 2798 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 308:
+#line 2807 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 309:
+#line 2817 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 310:
+#line 2826 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 311:
+#line 2835 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 312:
+#line 2844 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 313:
+#line 2853 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 314:
+#line 2862 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 315:
+#line 2872 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 316:
+#line 2881 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 317:
+#line 2890 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 318:
+#line 2900 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 319:
+#line 2909 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 320:
+#line 2919 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 321:
+#line 2928 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 322:
+#line 2938 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 323:
+#line 2947 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 324:
+#line 2957 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 325:
+#line 2966 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 326:
+#line 2976 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 327:
+#line 2985 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 328:
+#line 2995 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 329:
+#line 3004 "cmDependsJavaParser.y"
+ {
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 330:
+#line 3014 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 331:
+#line 3023 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 332:
+#line 3033 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 333:
+#line 3043 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ yyGetParser->DeallocateParserType(&(yyvsp[0].str));
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 334:
+#line 3053 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 335:
+#line 3062 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 336:
+#line 3072 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 337:
+#line 3081 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 338:
+#line 3090 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 339:
+#line 3099 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 340:
+#line 3108 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 341:
+#line 3117 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 342:
+#line 3126 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 343:
+#line 3135 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 344:
+#line 3144 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 345:
+#line 3153 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 346:
+#line 3162 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 347:
+#line 3171 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 348:
+#line 3181 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 349:
+#line 3191 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 350:
+#line 3201 "cmDependsJavaParser.y"
+ {
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+ case 351:
+#line 3210 "cmDependsJavaParser.y"
+ {
+ jpElementStart(3);
+ jpStoreClass(yyvsp[-2].str);
+ jpCheckEmpty(3);
+ yyval.str = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+ break;
+
+
+ }
+
+/* Line 1010 of yacc.c. */
+#line 5780 "cmDependsJavaParser.cxx"
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ const char* yyprefix;
+ char *yymsg;
+ int yyx;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 0;
+
+ yyprefix = ", expecting ";
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
+ yycount += 1;
+ if (yycount == 5)
+ {
+ yysize = 0;
+ break;
+ }
+ }
+ yysize += (sizeof ("syntax error, unexpected ")
+ + yystrlen (yytname[yytype]));
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yyprefix = ", expecting ";
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ yyp = yystpcpy (yyp, yyprefix);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yyprefix = " or ";
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* If at end of input, pop the error token,
+ then the rest of the stack, then return failure. */
+ if (yychar == YYEOF)
+ for (;;)
+ {
+ YYPOPSTACK;
+ if (yyssp == yyss)
+ YYABORT;
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ }
+ }
+ else
+ {
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
+ yychar = YYEMPTY;
+
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+#if defined(__GNUC__) || defined(__HP_aCC)
+ /* Pacify GCC when the user code never invokes YYERROR and the label
+ yyerrorlab therefore never appears in user code. */
+ if (0)
+ goto yyerrorlab;
+#endif
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ YYPOPSTACK;
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 3219 "cmDependsJavaParser.y"
+
+/* End of grammar */
+
+/*--------------------------------------------------------------------------*/
+void cmDependsJavaError(yyscan_t yyscanner, const char* message)
+{
+ yyGetParser->Error(message);
+}
+
+
diff --git a/Source/cmDependsJavaParser.y b/Source/cmDependsJavaParser.y
new file mode 100644
index 0000000..b66dc6d
--- /dev/null
+++ b/Source/cmDependsJavaParser.y
@@ -0,0 +1,3221 @@
+%{
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --yacc --name-prefix=cmDependsJava_yy --defines=cmDependsJavaParserTokens.h -ocmDependsJavaParser.cxx cmDependsJavaParser.y
+
+Modify cmDependsJavaParser.cxx:
+ - remove TABs
+ - remove use of the 'register' storage class specifier
+ - add __HP_aCC to the #if test for yyerrorlab warning suppression
+
+*/
+
+/* Configure the parser to use a lexer object. */
+#define YYPARSE_PARAM yyscanner
+#define YYLEX_PARAM yyscanner
+#define YYERROR_VERBOSE 1
+#define cmDependsJava_yyerror(x) \
+ cmDependsJavaError(yyscanner, x)
+#define yyGetParser (cmDependsJava_yyget_extra(yyscanner))
+
+/*-------------------------------------------------------------------------*/
+#include "cmDependsJavaParserHelper.h" /* Interface to parser object. */
+#include "cmDependsJavaLexer.h" /* Interface to lexer object. */
+#include "cmDependsJavaParserTokens.h" /* Need YYSTYPE for YY_DECL. */
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Internal utility functions. */
+static void cmDependsJavaError(yyscan_t yyscanner, const char* message);
+
+#define YYDEBUG 1
+#define YYMAXDEPTH 1000000
+
+
+#define jpCheckEmpty(cnt) yyGetParser->CheckEmpty(__LINE__, cnt, yyvsp);
+#define jpElementStart(cnt) yyGetParser->PrepareElement(&yyval)
+#define jpStoreClass(str) yyGetParser->AddClassFound(str); yyGetParser->DeallocateParserType(&(str))
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch statement contains default but no case. */
+#endif
+%}
+
+/* Generate a reentrant parser object. */
+%pure_parser
+
+/*
+%union {
+ char* string;
+}
+*/
+
+/*-------------------------------------------------------------------------*/
+/* Tokens */
+%token jp_ABSTRACT
+%token jp_ASSERT
+%token jp_BOOLEAN_TYPE
+%token jp_BREAK
+%token jp_BYTE_TYPE
+%token jp_CASE
+%token jp_CATCH
+%token jp_CHAR_TYPE
+%token jp_CLASS
+%token jp_CONTINUE
+%token jp_DEFAULT
+%token jp_DO
+%token jp_DOUBLE_TYPE
+%token jp_ELSE
+%token jp_EXTENDS
+%token jp_FINAL
+%token jp_FINALLY
+%token jp_FLOAT_TYPE
+%token jp_FOR
+%token jp_IF
+%token jp_IMPLEMENTS
+%token jp_IMPORT
+%token jp_INSTANCEOF
+%token jp_INT_TYPE
+%token jp_INTERFACE
+%token jp_LONG_TYPE
+%token jp_NATIVE
+%token jp_NEW
+%token jp_PACKAGE
+%token jp_PRIVATE
+%token jp_PROTECTED
+%token jp_PUBLIC
+%token jp_RETURN
+%token jp_SHORT_TYPE
+%token jp_STATIC
+%token jp_STRICTFP
+%token jp_SUPER
+%token jp_SWITCH
+%token jp_SYNCHRONIZED
+%token jp_THIS
+%token jp_THROW
+%token jp_THROWS
+%token jp_TRANSIENT
+%token jp_TRY
+%token jp_VOID
+%token jp_VOLATILE
+%token jp_WHILE
+
+%token jp_BOOLEANLITERAL
+%token jp_CHARACTERLITERAL
+%token jp_DECIMALINTEGERLITERAL
+%token jp_FLOATINGPOINTLITERAL
+%token jp_HEXINTEGERLITERAL
+%token jp_NULLLITERAL
+%token jp_STRINGLITERAL
+
+%token jp_NAME
+
+%token jp_AND
+%token jp_ANDAND
+%token jp_ANDEQUALS
+%token jp_BRACKETEND
+%token jp_BRACKETSTART
+%token jp_CARROT
+%token jp_CARROTEQUALS
+%token jp_COLON
+%token jp_COMMA
+%token jp_CURLYEND
+%token jp_CURLYSTART
+%token jp_DIVIDE
+%token jp_DIVIDEEQUALS
+%token jp_DOLLAR
+%token jp_DOT
+%token jp_EQUALS
+%token jp_EQUALSEQUALS
+%token jp_EXCLAMATION
+%token jp_EXCLAMATIONEQUALS
+%token jp_GREATER
+%token jp_GTEQUALS
+%token jp_GTGT
+%token jp_GTGTEQUALS
+%token jp_GTGTGT
+%token jp_GTGTGTEQUALS
+%token jp_LESLESEQUALS
+%token jp_LESSTHAN
+%token jp_LTEQUALS
+%token jp_LTLT
+%token jp_MINUS
+%token jp_MINUSEQUALS
+%token jp_MINUSMINUS
+%token jp_PAREEND
+%token jp_PARESTART
+%token jp_PERCENT
+%token jp_PERCENTEQUALS
+%token jp_PIPE
+%token jp_PIPEEQUALS
+%token jp_PIPEPIPE
+%token jp_PLUS
+%token jp_PLUSEQUALS
+%token jp_PLUSPLUS
+%token jp_QUESTION
+%token jp_SEMICOL
+%token jp_TILDE
+%token jp_TIMES
+%token jp_TIMESEQUALS
+
+%token jp_ERROR
+
+/*-------------------------------------------------------------------------*/
+/* grammar */
+%%
+
+Goal:
+CompilationUnit
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Literal:
+IntegerLiteral
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_FLOATINGPOINTLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_BOOLEANLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_CHARACTERLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_STRINGLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_NULLLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+IntegerLiteral:
+jp_DECIMALINTEGERLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_HEXINTEGERLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Type:
+PrimitiveType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ReferenceType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+PrimitiveType:
+jp_BYTE_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_SHORT_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_INT_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_LONG_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_CHAR_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_FLOAT_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_DOUBLE_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_BOOLEAN_TYPE
+{
+ jpElementStart(0);
+}
+
+ReferenceType:
+ClassOrInterfaceType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ArrayType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ClassOrInterfaceType:
+Name
+{
+ jpElementStart(1);
+ jpStoreClass($<str>1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ClassType:
+ClassOrInterfaceType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+InterfaceType:
+ClassOrInterfaceType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ArrayType:
+PrimitiveType Dims
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+Name Dims
+{
+ jpElementStart(2);
+ jpStoreClass($<str>1);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Name:
+SimpleName
+{
+ jpElementStart(1);
+ $<str>$ = $<str>1;
+}
+|
+QualifiedName
+{
+ jpElementStart(1);
+ $<str>$ = $<str>1;
+}
+
+SimpleName:
+Identifier
+{
+ jpElementStart(1);
+ $<str>$ = $<str>1;
+}
+
+Identifier:
+jp_NAME
+{
+ jpElementStart(1);
+ $<str>$ = $<str>1;
+}
+|
+jp_DOLLAR jp_NAME
+{
+ jpElementStart(2);
+ $<str>$ = $<str>2;
+}
+
+QualifiedName:
+Name jp_DOT Identifier
+{
+ jpElementStart(3);
+ yyGetParser->AddClassFound($<str>1);
+ yyGetParser->UpdateCombine($<str>1, $<str>3);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ $<str>$ = const_cast<char*>(yyGetParser->GetCurrentCombine());
+}
+|
+Name jp_DOT jp_CLASS
+{
+ jpElementStart(3);
+ jpStoreClass($<str>1);
+ jpCheckEmpty(3);
+ yyGetParser->SetCurrentCombine("");
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+Name jp_DOT jp_THIS
+{
+ jpElementStart(3);
+ jpStoreClass($<str>1);
+ yyGetParser->SetCurrentCombine("");
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+SimpleType jp_DOT jp_CLASS
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+SimpleType:
+PrimitiveType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_VOID
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+CompilationUnit:
+PackageDeclarationopt ImportDeclarations TypeDeclarations
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+PackageDeclarationopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+PackageDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ImportDeclarations:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ImportDeclarations ImportDeclaration
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+TypeDeclarations:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+TypeDeclarations TypeDeclaration
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+PackageDeclaration:
+jp_PACKAGE Name jp_SEMICOL
+{
+ jpElementStart(3);
+ yyGetParser->SetCurrentPackage($<str>2);
+ yyGetParser->DeallocateParserType(&($<str>2));
+ yyGetParser->SetCurrentCombine("");
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ImportDeclaration:
+SingleTypeImportDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+TypeImportOnDemandDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+SingleTypeImportDeclaration:
+jp_IMPORT Name jp_SEMICOL
+{
+ jpElementStart(3);
+ yyGetParser->AddPackagesImport($<str>2);
+ yyGetParser->DeallocateParserType(&($<str>2));
+ yyGetParser->SetCurrentCombine("");
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+TypeImportOnDemandDeclaration:
+jp_IMPORT Name jp_DOT jp_TIMES jp_SEMICOL
+{
+ jpElementStart(5);
+ std::string str = $<str>2;
+ str += ".*";
+ yyGetParser->AddPackagesImport(str.c_str());
+ yyGetParser->DeallocateParserType(&($<str>2));
+ yyGetParser->SetCurrentCombine("");
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+TypeDeclaration:
+ClassDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+InterfaceDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_SEMICOL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Modifiers:
+Modifier
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+Modifiers Modifier
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Modifier:
+jp_PUBLIC | jp_PROTECTED | jp_PRIVATE |
+jp_STATIC |
+jp_ABSTRACT | jp_FINAL | jp_NATIVE | jp_SYNCHRONIZED | jp_TRANSIENT | jp_VOLATILE |
+jp_STRICTFP
+
+ClassHeader:
+Modifiersopt jp_CLASS Identifier
+{
+ yyGetParser->StartClass($<str>3);
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(3);
+}
+
+
+ClassDeclaration:
+ClassHeader ClassBody
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+|
+ClassHeader Interfaces ClassBody
+{
+ jpElementStart(3);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+|
+ClassHeader Super ClassBody
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+|
+ClassHeader Super Interfaces ClassBody
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+
+Modifiersopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+Modifiers
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Super:
+jp_EXTENDS ClassType
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Interfaces:
+jp_IMPLEMENTS InterfaceTypeList
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+InterfaceTypeList:
+InterfaceType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+InterfaceTypeList jp_COMMA InterfaceType
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ClassBody:
+jp_CURLYSTART ClassBodyDeclarations jp_CURLYEND
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ClassBodyDeclarations:
+{
+ jpElementStart(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ClassBodyDeclarations ClassBodyDeclaration
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ClassBodyDeclaration:
+ClassMemberDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+StaticInitializer
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ConstructorDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+TypeDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ClassMemberDeclaration:
+FieldDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+MethodDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+FieldDeclaration:
+Modifiersopt Type VariableDeclarators jp_SEMICOL
+{
+ jpElementStart(4);
+}
+
+VariableDeclarators:
+VariableDeclarator
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+VariableDeclarators jp_COMMA VariableDeclarator
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+VariableDeclarator:
+VariableDeclaratorId
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+VariableDeclaratorId jp_EQUALS VariableInitializer
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+VariableDeclaratorId:
+Identifier
+{
+ jpElementStart(1);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+VariableDeclaratorId jp_BRACKETSTART jp_BRACKETEND
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+VariableInitializer:
+Expression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ArrayInitializer
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+MethodDeclaration:
+MethodHeader jp_SEMICOL
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+MethodHeader MethodBody
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+MethodHeader MethodBody jp_SEMICOL
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+MethodHeader:
+Modifiersopt Type MethodDeclarator Throwsopt
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Modifiersopt jp_VOID MethodDeclarator Throwsopt
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Throwsopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Throws
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+MethodDeclarator:
+Identifier jp_PARESTART FormalParameterListopt jp_PAREEND
+{
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+MethodDeclarator jp_BRACKETSTART jp_BRACKETEND
+{
+ jpElementStart(3);
+
+}
+
+FormalParameterListopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+FormalParameterList
+
+FormalParameterList:
+FormalParameter
+{
+ jpElementStart(1);
+
+}
+|
+FormalParameterList jp_COMMA FormalParameter
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+FormalParameter:
+Modifiersopt Type VariableDeclaratorId
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Throws:
+jp_THROWS ClassTypeList
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ClassTypeList:
+ClassType
+{
+ jpElementStart(1);
+
+}
+|
+ClassTypeList jp_COMMA ClassType
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+MethodBody:
+Block
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+StaticInitializer:
+jp_STATIC Block
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConstructorDeclaration:
+Modifiersopt ConstructorDeclarator Throwsopt ConstructorBody
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Modifiersopt ConstructorDeclarator Throwsopt ConstructorBody jp_SEMICOL
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConstructorDeclarator:
+SimpleName jp_PARESTART FormalParameterListopt jp_PAREEND
+{
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConstructorBody:
+jp_CURLYSTART ExplicitConstructorInvocationopt BlockStatementsopt jp_CURLYEND
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ExplicitConstructorInvocationopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ExplicitConstructorInvocationopt ExplicitConstructorInvocation
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ExplicitConstructorInvocation:
+jp_THIS jp_PARESTART ArgumentListopt jp_PAREEND jp_SEMICOL
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_SUPER jp_PARESTART ArgumentListopt jp_PAREEND jp_SEMICOL
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+InterfaceHeader:
+Modifiersopt jp_INTERFACE Identifier
+{
+ yyGetParser->StartClass($<str>3);
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(3);
+}
+
+InterfaceDeclaration:
+InterfaceHeader ExtendsInterfacesopt InterfaceBody
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+
+ExtendsInterfacesopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ExtendsInterfaces
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ExtendsInterfaces:
+jp_EXTENDS InterfaceType
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ExtendsInterfaces jp_COMMA InterfaceType
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+InterfaceBody:
+jp_CURLYSTART InterfaceMemberDeclarations jp_CURLYEND
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+InterfaceMemberDeclarations:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+InterfaceMemberDeclarations InterfaceMemberDeclaration
+{
+ jpElementStart(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+InterfaceMemberDeclaration:
+ConstantDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+AbstractMethodDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ClassDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ClassDeclaration jp_SEMICOL
+{
+ jpElementStart(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+InterfaceDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+InterfaceDeclaration jp_SEMICOL
+{
+ jpElementStart(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConstantDeclaration:
+FieldDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+AbstractMethodDeclaration:
+MethodHeader Semicols
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Semicols:
+jp_SEMICOL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Semicols jp_SEMICOL
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ArrayInitializer:
+jp_CURLYSTART VariableInitializersOptional jp_CURLYEND
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+VariableInitializersOptional:
+{
+ jpElementStart(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+VariableInitializers
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+VariableInitializers jp_COMMA
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+VariableInitializers:
+VariableInitializer
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+VariableInitializers jp_COMMA VariableInitializer
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Block:
+jp_CURLYSTART BlockStatementsopt jp_CURLYEND
+{
+ jpElementStart(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+BlockStatementsopt:
+{
+ jpElementStart(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+BlockStatements
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+BlockStatements:
+BlockStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+BlockStatements BlockStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+BlockStatement:
+LocalVariableDeclarationStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Statement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ClassDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+LocalVariableDeclarationStatement:
+LocalVariableDeclaration jp_SEMICOL
+{
+ jpElementStart(1);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+LocalVariableDeclaration:
+Modifiers Type VariableDeclarators
+{
+ jpElementStart(1);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Type VariableDeclarators
+{
+ jpElementStart(1);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Statement:
+StatementWithoutTrailingSubstatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+LabeledStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+IfThenStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+IfThenElseStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+WhileStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ForStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+StatementNoShortIf:
+StatementWithoutTrailingSubstatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+LabeledStatementNoShortIf
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+IfThenElseStatementNoShortIf
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+WhileStatementNoShortIf
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ForStatementNoShortIf
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+StatementWithoutTrailingSubstatement:
+Block
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+EmptyStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ExpressionStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+SwitchStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+DoStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+BreakStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ContinueStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ReturnStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+SynchronizedStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ThrowStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+TryStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+AssertStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+EmptyStatement:
+jp_SEMICOL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+LabeledStatement:
+Identifier jp_COLON Statement
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+LabeledStatementNoShortIf:
+Identifier jp_COLON StatementNoShortIf
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ExpressionStatement:
+StatementExpression jp_SEMICOL
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+StatementExpression:
+Assignment
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PreIncrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PreDecrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PostIncrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PostDecrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+MethodInvocation
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ClassInstanceCreationExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+IfThenStatement:
+jp_IF jp_PARESTART Expression jp_PAREEND Statement
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+IfThenElseStatement:
+jp_IF jp_PARESTART Expression jp_PAREEND StatementNoShortIf jp_ELSE Statement
+{
+ jpElementStart(7);
+ jpCheckEmpty(7);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+IfThenElseStatementNoShortIf:
+jp_IF jp_PARESTART Expression jp_PAREEND StatementNoShortIf jp_ELSE StatementNoShortIf
+{
+ jpElementStart(7);
+ jpCheckEmpty(7);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+SwitchStatement:
+jp_SWITCH jp_PARESTART Expression jp_PAREEND SwitchBlock
+{
+ jpElementStart(5);
+
+}
+
+SwitchBlock:
+jp_CURLYSTART SwitchBlockStatementGroups SwitchLabelsopt jp_CURLYEND
+{
+ jpElementStart(4);
+
+}
+
+SwitchLabelsopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+SwitchLabels
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+SwitchBlockStatementGroups:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+SwitchBlockStatementGroups SwitchBlockStatementGroup
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+SwitchBlockStatementGroup:
+SwitchLabels BlockStatements
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+SwitchLabels:
+SwitchLabel
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+SwitchLabels SwitchLabel
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+SwitchLabel:
+jp_CASE ConstantExpression jp_COLON
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_DEFAULT jp_COLON
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+WhileStatement:
+jp_WHILE jp_PARESTART Expression jp_PAREEND Statement
+{
+ jpElementStart(5);
+
+}
+
+WhileStatementNoShortIf:
+jp_WHILE jp_PARESTART Expression jp_PAREEND StatementNoShortIf
+{
+ jpElementStart(5);
+
+}
+
+DoStatement:
+jp_DO Statement jp_WHILE jp_PARESTART Expression jp_PAREEND jp_SEMICOL
+{
+ jpElementStart(7);
+
+}
+
+ForStatement:
+jp_FOR jp_PARESTART ForInitopt jp_SEMICOL Expressionopt jp_SEMICOL ForUpdateopt jp_PAREEND
+Statement
+{
+ jpElementStart(9);
+
+}
+
+ForUpdateopt:
+{
+ jpElementStart(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ForUpdate
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ForInitopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ForInit
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ForStatementNoShortIf:
+jp_FOR jp_PARESTART ForInitopt jp_SEMICOL Expressionopt jp_SEMICOL ForUpdateopt jp_PAREEND
+StatementNoShortIf
+{
+ jpElementStart(9);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Expressionopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Expression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ForInit:
+StatementExpressionList
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+LocalVariableDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ForUpdate:
+StatementExpressionList
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+StatementExpressionList:
+StatementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+StatementExpressionList jp_COMMA StatementExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+AssertStatement:
+jp_ASSERT Expression jp_SEMICOL
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_ASSERT Expression jp_COLON Expression jp_SEMICOL
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+BreakStatement:
+jp_BREAK Identifieropt jp_SEMICOL
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>2));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Identifieropt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Identifier
+{
+ jpElementStart(1);
+
+}
+
+ContinueStatement:
+jp_CONTINUE Identifieropt jp_SEMICOL
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>2));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ReturnStatement:
+jp_RETURN Expressionopt jp_SEMICOL
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ThrowStatement:
+jp_THROW Expression jp_SEMICOL
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+SynchronizedStatement:
+jp_SYNCHRONIZED jp_PARESTART Expression jp_PAREEND Block
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+TryStatement:
+jp_TRY Block Catches
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_TRY Block Catchesopt Finally
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Catchesopt:
+{
+ jpElementStart(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Catches
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Catches:
+CatchClause
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Catches CatchClause
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+CatchClause:
+jp_CATCH jp_PARESTART FormalParameter jp_PAREEND Block
+{
+ jpElementStart(5);
+
+}
+
+Finally:
+jp_FINALLY Block
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Primary:
+PrimaryNoNewArray
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ArrayCreationExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+PrimaryNoNewArray:
+Literal
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_THIS
+{
+ jpElementStart(1);
+
+}
+|
+jp_PARESTART Expression jp_PAREEND
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ClassInstanceCreationExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+FieldAccess
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+MethodInvocation
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ArrayAccess
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ClassInstanceCreationExpression:
+New ClassType jp_PARESTART ArgumentListopt jp_PAREEND ClassBodyOpt
+{
+ jpElementStart(6);
+ jpCheckEmpty(6);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ClassBodyOpt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ClassBody
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ArgumentListopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ArgumentList
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ArgumentList:
+Expression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ArgumentList jp_COMMA Expression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ArrayCreationExpression:
+New PrimitiveType DimExprs Dimsopt
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+New ClassOrInterfaceType DimExprs Dimsopt
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+New PrimitiveType Dims ArrayInitializer
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+New ClassOrInterfaceType Dims ArrayInitializer
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Dimsopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Dims
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+DimExprs:
+DimExpr
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+DimExprs DimExpr
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+DimExpr:
+jp_BRACKETSTART Expression jp_BRACKETEND
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Dims:
+jp_BRACKETSTART jp_BRACKETEND
+{
+ jpElementStart(2);
+
+}
+|
+Dims jp_BRACKETSTART jp_BRACKETEND
+{
+ jpElementStart(3);
+
+}
+
+FieldAccess:
+Primary jp_DOT Identifier
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_SUPER jp_DOT Identifier
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_THIS jp_DOT Identifier
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Primary jp_DOT jp_THIS
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+MethodInvocation:
+Name jp_PARESTART ArgumentListopt jp_PAREEND
+{
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Primary jp_DOT Identifier jp_PARESTART ArgumentListopt jp_PAREEND
+{
+ jpElementStart(6);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(6);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_SUPER jp_DOT Identifier jp_PARESTART ArgumentListopt jp_PAREEND
+{
+ jpElementStart(6);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(6);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_THIS jp_DOT Identifier jp_PARESTART ArgumentListopt jp_PAREEND
+{
+ jpElementStart(6);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(6);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ArrayAccess:
+Name jp_BRACKETSTART Expression jp_BRACKETEND
+{
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PrimaryNoNewArray jp_BRACKETSTART Expression jp_BRACKETEND
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+PostfixExpression:
+Primary
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Name
+{
+ jpElementStart(1);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ArrayType jp_DOT jp_CLASS
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PostIncrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PostDecrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+PostIncrementExpression:
+PostfixExpression jp_PLUSPLUS
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+PostDecrementExpression:
+PostfixExpression jp_MINUSMINUS
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+UnaryExpression:
+PreIncrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PreDecrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_PLUS UnaryExpression
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_MINUS UnaryExpression
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+UnaryExpressionNotPlusMinus
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+PreIncrementExpression:
+jp_PLUSPLUS UnaryExpression
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+PreDecrementExpression:
+jp_MINUSMINUS UnaryExpression
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+UnaryExpressionNotPlusMinus:
+PostfixExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_TILDE UnaryExpression
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_EXCLAMATION UnaryExpression
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+CastExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+CastExpression:
+jp_PARESTART PrimitiveType Dimsopt jp_PAREEND UnaryExpression
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_PARESTART Expression jp_PAREEND UnaryExpressionNotPlusMinus
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_PARESTART Name Dims jp_PAREEND UnaryExpressionNotPlusMinus
+{
+ jpElementStart(5);
+
+}
+
+MultiplicativeExpression:
+UnaryExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+MultiplicativeExpression jp_TIMES UnaryExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+MultiplicativeExpression jp_DIVIDE UnaryExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+MultiplicativeExpression jp_PERCENT UnaryExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+AdditiveExpression:
+MultiplicativeExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+AdditiveExpression jp_PLUS MultiplicativeExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+AdditiveExpression jp_MINUS MultiplicativeExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ShiftExpression:
+AdditiveExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ShiftExpression jp_LTLT AdditiveExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ShiftExpression jp_GTGT AdditiveExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ShiftExpression jp_GTGTGT AdditiveExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+RelationalExpression:
+ShiftExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+RelationalExpression jp_LESSTHAN ShiftExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+RelationalExpression jp_GREATER ShiftExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+RelationalExpression jp_LTEQUALS ShiftExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+RelationalExpression jp_GTEQUALS ShiftExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+RelationalExpression jp_INSTANCEOF ReferenceType
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+EqualityExpression:
+RelationalExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+EqualityExpression jp_EQUALSEQUALS RelationalExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+EqualityExpression jp_EXCLAMATIONEQUALS RelationalExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+AndExpression:
+EqualityExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+AndExpression jp_AND EqualityExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ExclusiveOrExpression:
+AndExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ExclusiveOrExpression jp_CARROT AndExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+InclusiveOrExpression:
+ExclusiveOrExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+InclusiveOrExpression jp_PIPE ExclusiveOrExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConditionalAndExpression:
+InclusiveOrExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ConditionalAndExpression jp_ANDAND InclusiveOrExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConditionalOrExpression:
+ConditionalAndExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ConditionalOrExpression jp_PIPEPIPE ConditionalAndExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConditionalExpression:
+ConditionalOrExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ConditionalOrExpression jp_QUESTION Expression jp_COLON ConditionalExpression
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+AssignmentExpression:
+ConditionalExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Assignment
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Assignment:
+LeftHandSide AssignmentOperator AssignmentExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+LeftHandSide:
+Name
+{
+ jpElementStart(1);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+FieldAccess
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ArrayAccess
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+AssignmentOperator:
+jp_EQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_TIMESEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_DIVIDEEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_PERCENTEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_PLUSEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_MINUSEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_LESLESEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_GTGTEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_GTGTGTEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_ANDEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_CARROTEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_PIPEEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Expression:
+AssignmentExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConstantExpression:
+Expression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+New:
+jp_NEW
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Name jp_DOT jp_NEW
+{
+ jpElementStart(3);
+ jpStoreClass($<str>1);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+%%
+/* End of grammar */
+
+/*--------------------------------------------------------------------------*/
+void cmDependsJavaError(yyscan_t yyscanner, const char* message)
+{
+ yyGetParser->Error(message);
+}
+
diff --git a/Source/cmDependsJavaParserHelper.cxx b/Source/cmDependsJavaParserHelper.cxx
new file mode 100644
index 0000000..79c4669
--- /dev/null
+++ b/Source/cmDependsJavaParserHelper.cxx
@@ -0,0 +1,352 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmDependsJavaParserHelper.h"
+
+#include "cmDependsJavaLexer.h"
+#include "cmSystemTools.h"
+#include <cmsys/FStream.hxx>
+
+int cmDependsJava_yyparse(yyscan_t yyscanner);
+
+cmDependsJavaParserHelper::cmDependsJavaParserHelper()
+{
+ this->CurrentDepth = 0;
+
+ this->UnionsAvailable = 0;
+ this->LastClassId = 0;
+
+ CurrentClass tl;
+ tl.Name = "*";
+ this->ClassStack.push_back(tl);
+}
+
+cmDependsJavaParserHelper::~cmDependsJavaParserHelper()
+{
+ this->CleanupParser();
+}
+
+void cmDependsJavaParserHelper::CurrentClass::AddFileNamesForPrinting(
+ std::vector<std::string>* files, const char* prefix, const char* sep) const
+{
+ std::string rname = "";
+ if (prefix) {
+ rname += prefix;
+ rname += sep;
+ }
+ rname += this->Name;
+ files->push_back(rname);
+ std::vector<CurrentClass>::const_iterator it;
+ for (it = this->NestedClasses.begin(); it != this->NestedClasses.end();
+ ++it) {
+ it->AddFileNamesForPrinting(files, rname.c_str(), sep);
+ }
+}
+
+void cmDependsJavaParserHelper::DeallocateParserType(char** pt)
+{
+ if (!pt) {
+ return;
+ }
+ if (!*pt) {
+ return;
+ }
+ *pt = CM_NULLPTR;
+ this->UnionsAvailable--;
+}
+
+void cmDependsJavaParserHelper::AddClassFound(const char* sclass)
+{
+ if (!sclass) {
+ return;
+ }
+ std::vector<std::string>::iterator it;
+ for (it = this->ClassesFound.begin(); it != this->ClassesFound.end(); it++) {
+ if (*it == sclass) {
+ return;
+ }
+ }
+ this->ClassesFound.push_back(sclass);
+}
+
+void cmDependsJavaParserHelper::AddPackagesImport(const char* sclass)
+{
+ std::vector<std::string>::iterator it;
+ for (it = this->PackagesImport.begin(); it != this->PackagesImport.end();
+ it++) {
+ if (*it == sclass) {
+ return;
+ }
+ }
+ this->PackagesImport.push_back(sclass);
+}
+
+void cmDependsJavaParserHelper::SafePrintMissing(const char* str, int line,
+ int cnt)
+{
+ if (str) {
+ std::cout << line << " String " << cnt << " exists: ";
+ unsigned int cc;
+ for (cc = 0; cc < strlen(str); cc++) {
+ unsigned char ch = str[cc];
+ if (ch >= 32 && ch <= 126) {
+ std::cout << (char)ch;
+ } else {
+ std::cout << "<" << (int)ch << ">";
+ break;
+ }
+ }
+ std::cout << "- " << strlen(str) << std::endl;
+ }
+}
+void cmDependsJavaParserHelper::Print(const char* place, const char* str)
+{
+ if (this->Verbose) {
+ std::cout << "[" << place << "=" << str << "]" << std::endl;
+ }
+}
+
+void cmDependsJavaParserHelper::CombineUnions(char** out, const char* in1,
+ char** in2, const char* sep)
+{
+ size_t len = 1;
+ if (in1) {
+ len += strlen(in1);
+ }
+ if (*in2) {
+ len += strlen(*in2);
+ }
+ if (sep) {
+ len += strlen(sep);
+ }
+ *out = new char[len];
+ *out[0] = 0;
+ if (in1) {
+ strcat(*out, in1);
+ }
+ if (sep) {
+ strcat(*out, sep);
+ }
+ if (*in2) {
+ strcat(*out, *in2);
+ }
+ if (*in2) {
+ this->DeallocateParserType(in2);
+ }
+ this->UnionsAvailable++;
+}
+
+void cmDependsJavaParserHelper::CheckEmpty(
+ int line, int cnt, cmDependsJavaParserHelper::ParserType* pt)
+{
+ int cc;
+ int kk = -cnt + 1;
+ for (cc = 1; cc <= cnt; cc++) {
+ cmDependsJavaParserHelper::ParserType* cpt = pt + kk;
+ this->SafePrintMissing(cpt->str, line, cc);
+ kk++;
+ }
+}
+
+void cmDependsJavaParserHelper::PrepareElement(
+ cmDependsJavaParserHelper::ParserType* me)
+{
+ // Inititalize self
+ me->str = CM_NULLPTR;
+}
+
+void cmDependsJavaParserHelper::AllocateParserType(
+ cmDependsJavaParserHelper::ParserType* pt, const char* str, int len)
+{
+ pt->str = CM_NULLPTR;
+ if (len == 0) {
+ len = (int)strlen(str);
+ }
+ if (len == 0) {
+ return;
+ }
+ this->UnionsAvailable++;
+ pt->str = new char[len + 1];
+ strncpy(pt->str, str, len);
+ pt->str[len] = 0;
+ this->Allocates.push_back(pt->str);
+}
+
+void cmDependsJavaParserHelper::StartClass(const char* cls)
+{
+ CurrentClass cl;
+ cl.Name = cls;
+ this->ClassStack.push_back(cl);
+
+ this->CurrentDepth++;
+}
+
+void cmDependsJavaParserHelper::EndClass()
+{
+ if (this->ClassStack.empty()) {
+ std::cerr << "Error when parsing. Current class is null" << std::endl;
+ abort();
+ }
+ if (this->ClassStack.size() <= 1) {
+ std::cerr << "Error when parsing. Parent class is null" << std::endl;
+ abort();
+ }
+ CurrentClass& current = this->ClassStack.back();
+ CurrentClass& parent = this->ClassStack[this->ClassStack.size() - 2];
+ this->CurrentDepth--;
+ parent.NestedClasses.push_back(current);
+ this->ClassStack.pop_back();
+}
+
+void cmDependsJavaParserHelper::PrintClasses()
+{
+ if (this->ClassStack.empty()) {
+ std::cerr << "Error when parsing. No classes on class stack" << std::endl;
+ abort();
+ }
+ std::vector<std::string> files = this->GetFilesProduced();
+ std::vector<std::string>::iterator sit;
+ for (sit = files.begin(); sit != files.end(); ++sit) {
+ std::cout << " " << *sit << ".class" << std::endl;
+ }
+}
+
+std::vector<std::string> cmDependsJavaParserHelper::GetFilesProduced()
+{
+ std::vector<std::string> files;
+ CurrentClass const& toplevel = this->ClassStack.front();
+ std::vector<CurrentClass>::const_iterator it;
+ for (it = toplevel.NestedClasses.begin(); it != toplevel.NestedClasses.end();
+ ++it) {
+ it->AddFileNamesForPrinting(&files, CM_NULLPTR, "$");
+ }
+ return files;
+}
+
+int cmDependsJavaParserHelper::ParseString(const char* str, int verb)
+{
+ if (!str) {
+ return 0;
+ }
+ this->Verbose = verb;
+ this->InputBuffer = str;
+ this->InputBufferPos = 0;
+ this->CurrentLine = 0;
+
+ yyscan_t yyscanner;
+ cmDependsJava_yylex_init(&yyscanner);
+ cmDependsJava_yyset_extra(this, yyscanner);
+ int res = cmDependsJava_yyparse(yyscanner);
+ cmDependsJava_yylex_destroy(yyscanner);
+ if (res != 0) {
+ std::cout << "JP_Parse returned: " << res << std::endl;
+ return 0;
+ }
+
+ if (verb) {
+ if (!this->CurrentPackage.empty()) {
+ std::cout << "Current package is: " << this->CurrentPackage << std::endl;
+ }
+ std::cout << "Imports packages:";
+ if (!this->PackagesImport.empty()) {
+ std::vector<std::string>::iterator it;
+ for (it = this->PackagesImport.begin(); it != this->PackagesImport.end();
+ ++it) {
+ std::cout << " " << *it;
+ }
+ }
+ std::cout << std::endl;
+ std::cout << "Depends on:";
+ if (!this->ClassesFound.empty()) {
+ std::vector<std::string>::iterator it;
+ for (it = this->ClassesFound.begin(); it != this->ClassesFound.end();
+ ++it) {
+ std::cout << " " << *it;
+ }
+ }
+ std::cout << std::endl;
+ std::cout << "Generated files:" << std::endl;
+ this->PrintClasses();
+ if (this->UnionsAvailable != 0) {
+ std::cout << "There are still " << this->UnionsAvailable
+ << " unions available" << std::endl;
+ }
+ }
+ this->CleanupParser();
+ return 1;
+}
+
+void cmDependsJavaParserHelper::CleanupParser()
+{
+ std::vector<char*>::iterator it;
+ for (it = this->Allocates.begin(); it != this->Allocates.end(); ++it) {
+ delete[] * it;
+ }
+ this->Allocates.erase(this->Allocates.begin(), this->Allocates.end());
+}
+
+int cmDependsJavaParserHelper::LexInput(char* buf, int maxlen)
+{
+ if (maxlen < 1) {
+ return 0;
+ }
+ if (this->InputBufferPos < this->InputBuffer.size()) {
+ buf[0] = this->InputBuffer[this->InputBufferPos++];
+ if (buf[0] == '\n') {
+ this->CurrentLine++;
+ }
+ return 1;
+ }
+ buf[0] = '\n';
+ return 0;
+}
+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;
+}
+
+void cmDependsJavaParserHelper::UpdateCombine(const char* str1,
+ const char* str2)
+{
+ if (this->CurrentCombine == "" && str1 != CM_NULLPTR) {
+ this->CurrentCombine = str1;
+ }
+ this->CurrentCombine += ".";
+ this->CurrentCombine += str2;
+}
+
+int cmDependsJavaParserHelper::ParseFile(const char* file)
+{
+ if (!cmSystemTools::FileExists(file)) {
+ return 0;
+ }
+ cmsys::ifstream ifs(file);
+ if (!ifs) {
+ return 0;
+ }
+
+ std::string fullfile = "";
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ fullfile += line + "\n";
+ }
+ return this->ParseString(fullfile.c_str(), 0);
+}
diff --git a/Source/cmDependsJavaParserHelper.h b/Source/cmDependsJavaParserHelper.h
new file mode 100644
index 0000000..6ff0245
--- /dev/null
+++ b/Source/cmDependsJavaParserHelper.h
@@ -0,0 +1,103 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmDependsJavaParserHelper_h
+#define cmDependsJavaParserHelper_h
+
+#include "cmStandardIncludes.h"
+
+#define YYSTYPE cmDependsJavaParserHelper::ParserType
+#define YYSTYPE_IS_DECLARED
+#define YY_EXTRA_TYPE cmDependsJavaParserHelper*
+#define YY_DECL int cmDependsJava_yylex(YYSTYPE* yylvalp, yyscan_t yyscanner)
+
+/** \class cmDependsJavaParserHelper
+ * \brief Helper class for parsing java source files
+ *
+ * Finds dependencies for java file and list of outputs
+ */
+
+class cmDependsJavaParserHelper
+{
+public:
+ typedef struct
+ {
+ char* str;
+ } ParserType;
+
+ cmDependsJavaParserHelper();
+ ~cmDependsJavaParserHelper();
+
+ int ParseString(const char* str, int verb);
+ int ParseFile(const char* file);
+
+ // For the lexer:
+ void AllocateParserType(cmDependsJavaParserHelper::ParserType* pt,
+ const char* str, int len = 0);
+
+ int LexInput(char* buf, int maxlen);
+ void Error(const char* str);
+
+ // For yacc
+ void AddClassFound(const char* sclass);
+ void PrepareElement(ParserType* me);
+ void DeallocateParserType(char** pt);
+ void CheckEmpty(int line, int cnt, ParserType* pt);
+ void StartClass(const char* cls);
+ void EndClass();
+ void AddPackagesImport(const char* sclass);
+ void SetCurrentPackage(const char* pkg) { this->CurrentPackage = pkg; }
+ const char* GetCurrentPackage() { return this->CurrentPackage.c_str(); }
+ void SetCurrentCombine(const char* cmb) { this->CurrentCombine = cmb; }
+ const char* GetCurrentCombine() { return this->CurrentCombine.c_str(); }
+ void UpdateCombine(const char* str1, const char* str2);
+
+ std::vector<std::string>& GetClassesFound() { return this->ClassesFound; }
+
+ std::vector<std::string> GetFilesProduced();
+
+private:
+ class CurrentClass
+ {
+ public:
+ std::string Name;
+ std::vector<CurrentClass> NestedClasses;
+ void AddFileNamesForPrinting(std::vector<std::string>* files,
+ const char* prefix, const char* sep) const;
+ };
+ std::string CurrentPackage;
+ std::string::size_type InputBufferPos;
+ std::string InputBuffer;
+ std::vector<char> OutputBuffer;
+ std::vector<std::string> ClassesFound;
+ std::vector<std::string> PackagesImport;
+ std::string CurrentCombine;
+
+ std::vector<CurrentClass> ClassStack;
+
+ int CurrentLine;
+ int UnionsAvailable;
+ int LastClassId;
+ int CurrentDepth;
+ int Verbose;
+
+ std::vector<char*> Allocates;
+
+ void PrintClasses();
+
+ void Print(const char* place, const char* str);
+ void CombineUnions(char** out, const char* in1, char** in2, const char* sep);
+ void SafePrintMissing(const char* str, int line, int cnt);
+
+ void CleanupParser();
+};
+
+#endif
diff --git a/Source/cmDependsJavaParserTokens.h b/Source/cmDependsJavaParserTokens.h
new file mode 100644
index 0000000..c7a414f
--- /dev/null
+++ b/Source/cmDependsJavaParserTokens.h
@@ -0,0 +1,254 @@
+/* A Bison parser, made by GNU Bison 1.875d. */
+
+/* Skeleton parser for Yacc-like parsing with Bison, Copyright (C) 1984,
+ 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ jp_ABSTRACT = 258,
+ jp_ASSERT = 259,
+ jp_BOOLEAN_TYPE = 260,
+ jp_BREAK = 261,
+ jp_BYTE_TYPE = 262,
+ jp_CASE = 263,
+ jp_CATCH = 264,
+ jp_CHAR_TYPE = 265,
+ jp_CLASS = 266,
+ jp_CONTINUE = 267,
+ jp_DEFAULT = 268,
+ jp_DO = 269,
+ jp_DOUBLE_TYPE = 270,
+ jp_ELSE = 271,
+ jp_EXTENDS = 272,
+ jp_FINAL = 273,
+ jp_FINALLY = 274,
+ jp_FLOAT_TYPE = 275,
+ jp_FOR = 276,
+ jp_IF = 277,
+ jp_IMPLEMENTS = 278,
+ jp_IMPORT = 279,
+ jp_INSTANCEOF = 280,
+ jp_INT_TYPE = 281,
+ jp_INTERFACE = 282,
+ jp_LONG_TYPE = 283,
+ jp_NATIVE = 284,
+ jp_NEW = 285,
+ jp_PACKAGE = 286,
+ jp_PRIVATE = 287,
+ jp_PROTECTED = 288,
+ jp_PUBLIC = 289,
+ jp_RETURN = 290,
+ jp_SHORT_TYPE = 291,
+ jp_STATIC = 292,
+ jp_STRICTFP = 293,
+ jp_SUPER = 294,
+ jp_SWITCH = 295,
+ jp_SYNCHRONIZED = 296,
+ jp_THIS = 297,
+ jp_THROW = 298,
+ jp_THROWS = 299,
+ jp_TRANSIENT = 300,
+ jp_TRY = 301,
+ jp_VOID = 302,
+ jp_VOLATILE = 303,
+ jp_WHILE = 304,
+ jp_BOOLEANLITERAL = 305,
+ jp_CHARACTERLITERAL = 306,
+ jp_DECIMALINTEGERLITERAL = 307,
+ jp_FLOATINGPOINTLITERAL = 308,
+ jp_HEXINTEGERLITERAL = 309,
+ jp_NULLLITERAL = 310,
+ jp_STRINGLITERAL = 311,
+ jp_NAME = 312,
+ jp_AND = 313,
+ jp_ANDAND = 314,
+ jp_ANDEQUALS = 315,
+ jp_BRACKETEND = 316,
+ jp_BRACKETSTART = 317,
+ jp_CARROT = 318,
+ jp_CARROTEQUALS = 319,
+ jp_COLON = 320,
+ jp_COMMA = 321,
+ jp_CURLYEND = 322,
+ jp_CURLYSTART = 323,
+ jp_DIVIDE = 324,
+ jp_DIVIDEEQUALS = 325,
+ jp_DOLLAR = 326,
+ jp_DOT = 327,
+ jp_EQUALS = 328,
+ jp_EQUALSEQUALS = 329,
+ jp_EXCLAMATION = 330,
+ jp_EXCLAMATIONEQUALS = 331,
+ jp_GREATER = 332,
+ jp_GTEQUALS = 333,
+ jp_GTGT = 334,
+ jp_GTGTEQUALS = 335,
+ jp_GTGTGT = 336,
+ jp_GTGTGTEQUALS = 337,
+ jp_LESLESEQUALS = 338,
+ jp_LESSTHAN = 339,
+ jp_LTEQUALS = 340,
+ jp_LTLT = 341,
+ jp_MINUS = 342,
+ jp_MINUSEQUALS = 343,
+ jp_MINUSMINUS = 344,
+ jp_PAREEND = 345,
+ jp_PARESTART = 346,
+ jp_PERCENT = 347,
+ jp_PERCENTEQUALS = 348,
+ jp_PIPE = 349,
+ jp_PIPEEQUALS = 350,
+ jp_PIPEPIPE = 351,
+ jp_PLUS = 352,
+ jp_PLUSEQUALS = 353,
+ jp_PLUSPLUS = 354,
+ jp_QUESTION = 355,
+ jp_SEMICOL = 356,
+ jp_TILDE = 357,
+ jp_TIMES = 358,
+ jp_TIMESEQUALS = 359,
+ jp_ERROR = 360
+ };
+#endif
+#define jp_ABSTRACT 258
+#define jp_ASSERT 259
+#define jp_BOOLEAN_TYPE 260
+#define jp_BREAK 261
+#define jp_BYTE_TYPE 262
+#define jp_CASE 263
+#define jp_CATCH 264
+#define jp_CHAR_TYPE 265
+#define jp_CLASS 266
+#define jp_CONTINUE 267
+#define jp_DEFAULT 268
+#define jp_DO 269
+#define jp_DOUBLE_TYPE 270
+#define jp_ELSE 271
+#define jp_EXTENDS 272
+#define jp_FINAL 273
+#define jp_FINALLY 274
+#define jp_FLOAT_TYPE 275
+#define jp_FOR 276
+#define jp_IF 277
+#define jp_IMPLEMENTS 278
+#define jp_IMPORT 279
+#define jp_INSTANCEOF 280
+#define jp_INT_TYPE 281
+#define jp_INTERFACE 282
+#define jp_LONG_TYPE 283
+#define jp_NATIVE 284
+#define jp_NEW 285
+#define jp_PACKAGE 286
+#define jp_PRIVATE 287
+#define jp_PROTECTED 288
+#define jp_PUBLIC 289
+#define jp_RETURN 290
+#define jp_SHORT_TYPE 291
+#define jp_STATIC 292
+#define jp_STRICTFP 293
+#define jp_SUPER 294
+#define jp_SWITCH 295
+#define jp_SYNCHRONIZED 296
+#define jp_THIS 297
+#define jp_THROW 298
+#define jp_THROWS 299
+#define jp_TRANSIENT 300
+#define jp_TRY 301
+#define jp_VOID 302
+#define jp_VOLATILE 303
+#define jp_WHILE 304
+#define jp_BOOLEANLITERAL 305
+#define jp_CHARACTERLITERAL 306
+#define jp_DECIMALINTEGERLITERAL 307
+#define jp_FLOATINGPOINTLITERAL 308
+#define jp_HEXINTEGERLITERAL 309
+#define jp_NULLLITERAL 310
+#define jp_STRINGLITERAL 311
+#define jp_NAME 312
+#define jp_AND 313
+#define jp_ANDAND 314
+#define jp_ANDEQUALS 315
+#define jp_BRACKETEND 316
+#define jp_BRACKETSTART 317
+#define jp_CARROT 318
+#define jp_CARROTEQUALS 319
+#define jp_COLON 320
+#define jp_COMMA 321
+#define jp_CURLYEND 322
+#define jp_CURLYSTART 323
+#define jp_DIVIDE 324
+#define jp_DIVIDEEQUALS 325
+#define jp_DOLLAR 326
+#define jp_DOT 327
+#define jp_EQUALS 328
+#define jp_EQUALSEQUALS 329
+#define jp_EXCLAMATION 330
+#define jp_EXCLAMATIONEQUALS 331
+#define jp_GREATER 332
+#define jp_GTEQUALS 333
+#define jp_GTGT 334
+#define jp_GTGTEQUALS 335
+#define jp_GTGTGT 336
+#define jp_GTGTGTEQUALS 337
+#define jp_LESLESEQUALS 338
+#define jp_LESSTHAN 339
+#define jp_LTEQUALS 340
+#define jp_LTLT 341
+#define jp_MINUS 342
+#define jp_MINUSEQUALS 343
+#define jp_MINUSMINUS 344
+#define jp_PAREEND 345
+#define jp_PARESTART 346
+#define jp_PERCENT 347
+#define jp_PERCENTEQUALS 348
+#define jp_PIPE 349
+#define jp_PIPEEQUALS 350
+#define jp_PIPEPIPE 351
+#define jp_PLUS 352
+#define jp_PLUSEQUALS 353
+#define jp_PLUSPLUS 354
+#define jp_QUESTION 355
+#define jp_SEMICOL 356
+#define jp_TILDE 357
+#define jp_TIMES 358
+#define jp_TIMESEQUALS 359
+#define jp_ERROR 360
+
+
+
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+typedef int YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+
+
diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx
new file mode 100644
index 0000000..919a45e
--- /dev/null
+++ b/Source/cmDocumentation.cxx
@@ -0,0 +1,772 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmDocumentation.h"
+
+#include "cmAlgorithms.h"
+#include "cmRST.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+
+#include <ctype.h>
+
+#include <algorithm>
+
+static const char* cmDocumentationStandardOptions[][2] = {
+ { "--help,-help,-usage,-h,-H,/?", "Print usage information and exit." },
+ { "--version,-version,/V [<f>]", "Print version number and exit." },
+ { "--help-full [<f>]", "Print all help manuals and exit." },
+ { "--help-manual <man> [<f>]", "Print one help manual and exit." },
+ { "--help-manual-list [<f>]", "List help manuals available and exit." },
+ { "--help-command <cmd> [<f>]", "Print help for one command and exit." },
+ { "--help-command-list [<f>]",
+ "List commands with help available and exit." },
+ { "--help-commands [<f>]", "Print cmake-commands manual and exit." },
+ { "--help-module <mod> [<f>]", "Print help for one module and exit." },
+ { "--help-module-list [<f>]", "List modules with help available and exit." },
+ { "--help-modules [<f>]", "Print cmake-modules manual and exit." },
+ { "--help-policy <cmp> [<f>]", "Print help for one policy and exit." },
+ { "--help-policy-list [<f>]",
+ "List policies with help available and exit." },
+ { "--help-policies [<f>]", "Print cmake-policies manual and exit." },
+ { "--help-property <prop> [<f>]", "Print help for one property and exit." },
+ { "--help-property-list [<f>]",
+ "List properties with help available and exit." },
+ { "--help-properties [<f>]", "Print cmake-properties manual and exit." },
+ { "--help-variable var [<f>]", "Print help for one variable and exit." },
+ { "--help-variable-list [<f>]",
+ "List variables with help available and exit." },
+ { "--help-variables [<f>]", "Print cmake-variables manual and exit." },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+static const char* cmDocumentationGeneratorsHeader[][2] = {
+ { CM_NULLPTR, "The following generators are available on this platform:" },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+cmDocumentation::cmDocumentation()
+{
+ this->addCommonStandardDocSections();
+ this->ShowGenerators = true;
+}
+
+cmDocumentation::~cmDocumentation()
+{
+ cmDeleteAll(this->AllSections);
+}
+
+bool cmDocumentation::PrintVersion(std::ostream& os)
+{
+ /* clang-format off */
+ os <<
+ this->GetNameString() <<
+ " version " << cmVersion::GetCMakeVersion() << "\n"
+ "\n"
+ "CMake suite maintained and supported by Kitware (kitware.com/cmake).\n"
+ ;
+ /* clang-format on */
+ return true;
+}
+
+bool cmDocumentation::PrintDocumentation(Type ht, std::ostream& os)
+{
+ switch (ht) {
+ case cmDocumentation::Usage:
+ return this->PrintUsage(os);
+ case cmDocumentation::Help:
+ return this->PrintHelp(os);
+ case cmDocumentation::Full:
+ return this->PrintHelpFull(os);
+ case cmDocumentation::OneManual:
+ return this->PrintHelpOneManual(os);
+ case cmDocumentation::OneCommand:
+ return this->PrintHelpOneCommand(os);
+ case cmDocumentation::OneModule:
+ return this->PrintHelpOneModule(os);
+ case cmDocumentation::OnePolicy:
+ return this->PrintHelpOnePolicy(os);
+ case cmDocumentation::OneProperty:
+ return this->PrintHelpOneProperty(os);
+ case cmDocumentation::OneVariable:
+ return this->PrintHelpOneVariable(os);
+ case cmDocumentation::ListManuals:
+ return this->PrintHelpListManuals(os);
+ case cmDocumentation::ListCommands:
+ return this->PrintHelpListCommands(os);
+ case cmDocumentation::ListModules:
+ return this->PrintHelpListModules(os);
+ case cmDocumentation::ListProperties:
+ return this->PrintHelpListProperties(os);
+ case cmDocumentation::ListVariables:
+ return this->PrintHelpListVariables(os);
+ case cmDocumentation::ListPolicies:
+ return this->PrintHelpListPolicies(os);
+ case cmDocumentation::ListGenerators:
+ return this->PrintHelpListGenerators(os);
+ case cmDocumentation::Version:
+ return this->PrintVersion(os);
+ case cmDocumentation::OldCustomModules:
+ return this->PrintOldCustomModules(os);
+ default:
+ return false;
+ }
+}
+
+bool cmDocumentation::PrintRequestedDocumentation(std::ostream& os)
+{
+ int count = 0;
+ bool result = true;
+
+ // Loop over requested documentation types.
+ for (std::vector<RequestedHelpItem>::const_iterator i =
+ this->RequestedHelpItems.begin();
+ i != this->RequestedHelpItems.end(); ++i) {
+ this->CurrentArgument = i->Argument;
+ // If a file name was given, use it. Otherwise, default to the
+ // given stream.
+ cmsys::ofstream* fout = CM_NULLPTR;
+ std::ostream* s = &os;
+ if (!i->Filename.empty()) {
+ fout = new cmsys::ofstream(i->Filename.c_str());
+ if (fout) {
+ s = fout;
+ } else {
+ result = false;
+ }
+ } else if (++count > 1) {
+ os << "\n\n";
+ }
+
+ // Print this documentation type to the stream.
+ if (!this->PrintDocumentation(i->HelpType, *s) || !*s) {
+ result = false;
+ }
+
+ // Close the file if we wrote one.
+ if (fout) {
+ delete fout;
+ }
+ }
+ return result;
+}
+
+#define GET_OPT_ARGUMENT(target) \
+ if ((i + 1 < argc) && !this->IsOption(argv[i + 1])) { \
+ target = argv[i + 1]; \
+ i = i + 1; \
+ };
+
+void cmDocumentation::WarnFormFromFilename(
+ cmDocumentation::RequestedHelpItem& request, bool& result)
+{
+ std::string ext = cmSystemTools::GetFilenameLastExtension(request.Filename);
+ ext = cmSystemTools::UpperCase(ext);
+ if ((ext == ".HTM") || (ext == ".HTML")) {
+ request.HelpType = cmDocumentation::None;
+ result = true;
+ cmSystemTools::Message("Warning: HTML help format no longer supported");
+ } else if (ext == ".DOCBOOK") {
+ request.HelpType = cmDocumentation::None;
+ result = true;
+ cmSystemTools::Message("Warning: Docbook help format no longer supported");
+ }
+ // ".1" to ".9" should be manpages
+ else if ((ext.length() == 2) && (ext[1] >= '1') && (ext[1] <= '9')) {
+ request.HelpType = cmDocumentation::None;
+ result = true;
+ cmSystemTools::Message("Warning: Man help format no longer supported");
+ }
+}
+
+void cmDocumentation::addCommonStandardDocSections()
+{
+ cmDocumentationSection* sec;
+
+ sec = new cmDocumentationSection("Options", "OPTIONS");
+ sec->Append(cmDocumentationStandardOptions);
+ this->AllSections["Options"] = sec;
+}
+
+void cmDocumentation::addCMakeStandardDocSections()
+{
+ cmDocumentationSection* sec;
+
+ sec = new cmDocumentationSection("Generators", "GENERATORS");
+ sec->Append(cmDocumentationGeneratorsHeader);
+ this->AllSections["Generators"] = sec;
+}
+
+void cmDocumentation::addCTestStandardDocSections()
+{
+ // This is currently done for backward compatibility reason
+ // We may suppress some of these.
+ addCMakeStandardDocSections();
+}
+
+void cmDocumentation::addCPackStandardDocSections()
+{
+ cmDocumentationSection* sec;
+
+ sec = new cmDocumentationSection("Generators", "GENERATORS");
+ sec->Append(cmDocumentationGeneratorsHeader);
+ this->AllSections["Generators"] = sec;
+}
+
+bool cmDocumentation::CheckOptions(int argc, const char* const* argv,
+ const char* exitOpt)
+{
+ // Providing zero arguments gives usage information.
+ if (argc == 1) {
+ RequestedHelpItem help;
+ help.HelpType = cmDocumentation::Usage;
+ this->RequestedHelpItems.push_back(help);
+ return true;
+ }
+
+ // Search for supported help options.
+
+ bool result = false;
+ for (int i = 1; i < argc; ++i) {
+ if (exitOpt && strcmp(argv[i], exitOpt) == 0) {
+ return result;
+ }
+ RequestedHelpItem help;
+ // Check if this is a supported help option.
+ if ((strcmp(argv[i], "-help") == 0) || (strcmp(argv[i], "--help") == 0) ||
+ (strcmp(argv[i], "/?") == 0) || (strcmp(argv[i], "-usage") == 0) ||
+ (strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "-H") == 0)) {
+ help.HelpType = cmDocumentation::Help;
+ GET_OPT_ARGUMENT(help.Argument);
+ help.Argument = cmSystemTools::LowerCase(help.Argument);
+ // special case for single command
+ if (!help.Argument.empty()) {
+ help.HelpType = cmDocumentation::OneCommand;
+ }
+ } else if (strcmp(argv[i], "--help-properties") == 0) {
+ help.HelpType = cmDocumentation::OneManual;
+ help.Argument = "cmake-properties.7";
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-policies") == 0) {
+ help.HelpType = cmDocumentation::OneManual;
+ help.Argument = "cmake-policies.7";
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-variables") == 0) {
+ help.HelpType = cmDocumentation::OneManual;
+ help.Argument = "cmake-variables.7";
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-modules") == 0) {
+ help.HelpType = cmDocumentation::OneManual;
+ help.Argument = "cmake-modules.7";
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-custom-modules") == 0) {
+ GET_OPT_ARGUMENT(help.Filename);
+ cmSystemTools::Message(
+ "Warning: --help-custom-modules no longer supported");
+ if (help.Filename.empty()) {
+ return true;
+ }
+ // Avoid breaking old project builds completely by at least generating
+ // the output file. Abuse help.Argument to give the file name to
+ // PrintOldCustomModules without disrupting our internal API.
+ help.HelpType = cmDocumentation::OldCustomModules;
+ help.Argument = cmSystemTools::GetFilenameName(help.Filename);
+ } else if (strcmp(argv[i], "--help-commands") == 0) {
+ help.HelpType = cmDocumentation::OneManual;
+ help.Argument = "cmake-commands.7";
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-compatcommands") == 0) {
+ GET_OPT_ARGUMENT(help.Filename);
+ cmSystemTools::Message(
+ "Warning: --help-compatcommands no longer supported");
+ return true;
+ } else if (strcmp(argv[i], "--help-full") == 0) {
+ help.HelpType = cmDocumentation::Full;
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-html") == 0) {
+ GET_OPT_ARGUMENT(help.Filename);
+ cmSystemTools::Message("Warning: --help-html no longer supported");
+ return true;
+ } else if (strcmp(argv[i], "--help-man") == 0) {
+ GET_OPT_ARGUMENT(help.Filename);
+ cmSystemTools::Message("Warning: --help-man no longer supported");
+ return true;
+ } else if (strcmp(argv[i], "--help-command") == 0) {
+ help.HelpType = cmDocumentation::OneCommand;
+ GET_OPT_ARGUMENT(help.Argument);
+ GET_OPT_ARGUMENT(help.Filename);
+ help.Argument = cmSystemTools::LowerCase(help.Argument);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-module") == 0) {
+ help.HelpType = cmDocumentation::OneModule;
+ GET_OPT_ARGUMENT(help.Argument);
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-property") == 0) {
+ help.HelpType = cmDocumentation::OneProperty;
+ GET_OPT_ARGUMENT(help.Argument);
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-policy") == 0) {
+ help.HelpType = cmDocumentation::OnePolicy;
+ GET_OPT_ARGUMENT(help.Argument);
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-variable") == 0) {
+ help.HelpType = cmDocumentation::OneVariable;
+ GET_OPT_ARGUMENT(help.Argument);
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-manual") == 0) {
+ help.HelpType = cmDocumentation::OneManual;
+ GET_OPT_ARGUMENT(help.Argument);
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-command-list") == 0) {
+ help.HelpType = cmDocumentation::ListCommands;
+ GET_OPT_ARGUMENT(help.Filename);
+ } else if (strcmp(argv[i], "--help-module-list") == 0) {
+ help.HelpType = cmDocumentation::ListModules;
+ GET_OPT_ARGUMENT(help.Filename);
+ } else if (strcmp(argv[i], "--help-property-list") == 0) {
+ help.HelpType = cmDocumentation::ListProperties;
+ GET_OPT_ARGUMENT(help.Filename);
+ } else if (strcmp(argv[i], "--help-variable-list") == 0) {
+ help.HelpType = cmDocumentation::ListVariables;
+ GET_OPT_ARGUMENT(help.Filename);
+ } else if (strcmp(argv[i], "--help-policy-list") == 0) {
+ help.HelpType = cmDocumentation::ListPolicies;
+ GET_OPT_ARGUMENT(help.Filename);
+ } else if (strcmp(argv[i], "--help-manual-list") == 0) {
+ help.HelpType = cmDocumentation::ListManuals;
+ GET_OPT_ARGUMENT(help.Filename);
+ } else if (strcmp(argv[i], "--copyright") == 0) {
+ GET_OPT_ARGUMENT(help.Filename);
+ cmSystemTools::Message("Warning: --copyright no longer supported");
+ return true;
+ } else if ((strcmp(argv[i], "--version") == 0) ||
+ (strcmp(argv[i], "-version") == 0) ||
+ (strcmp(argv[i], "/V") == 0)) {
+ help.HelpType = cmDocumentation::Version;
+ GET_OPT_ARGUMENT(help.Filename);
+ }
+ if (help.HelpType != None) {
+ // This is a help option. See if there is a file name given.
+ result = true;
+ this->RequestedHelpItems.push_back(help);
+ }
+ }
+ return result;
+}
+
+void cmDocumentation::SetName(const std::string& name)
+{
+ this->NameString = name;
+}
+
+void cmDocumentation::SetSection(const char* name,
+ cmDocumentationSection* section)
+{
+ if (this->AllSections.find(name) != this->AllSections.end()) {
+ delete this->AllSections[name];
+ }
+ this->AllSections[name] = section;
+}
+
+void cmDocumentation::SetSection(const char* name,
+ std::vector<cmDocumentationEntry>& docs)
+{
+ cmDocumentationSection* sec =
+ new cmDocumentationSection(name, cmSystemTools::UpperCase(name).c_str());
+ sec->Append(docs);
+ this->SetSection(name, sec);
+}
+
+void cmDocumentation::SetSection(const char* name, const char* docs[][2])
+{
+ cmDocumentationSection* sec =
+ new cmDocumentationSection(name, cmSystemTools::UpperCase(name).c_str());
+ sec->Append(docs);
+ this->SetSection(name, sec);
+}
+
+void cmDocumentation::SetSections(
+ std::map<std::string, cmDocumentationSection*>& sections)
+{
+ for (std::map<std::string, cmDocumentationSection*>::const_iterator it =
+ sections.begin();
+ it != sections.end(); ++it) {
+ this->SetSection(it->first.c_str(), it->second);
+ }
+}
+
+void cmDocumentation::PrependSection(const char* name, const char* docs[][2])
+{
+ cmDocumentationSection* sec = CM_NULLPTR;
+ if (this->AllSections.find(name) == this->AllSections.end()) {
+ sec =
+ new cmDocumentationSection(name, cmSystemTools::UpperCase(name).c_str());
+ this->SetSection(name, sec);
+ } else {
+ sec = this->AllSections[name];
+ }
+ sec->Prepend(docs);
+}
+
+void cmDocumentation::PrependSection(const char* name,
+ std::vector<cmDocumentationEntry>& docs)
+{
+ cmDocumentationSection* sec = CM_NULLPTR;
+ if (this->AllSections.find(name) == this->AllSections.end()) {
+ sec =
+ new cmDocumentationSection(name, cmSystemTools::UpperCase(name).c_str());
+ this->SetSection(name, sec);
+ } else {
+ sec = this->AllSections[name];
+ }
+ sec->Prepend(docs);
+}
+
+void cmDocumentation::AppendSection(const char* name, const char* docs[][2])
+{
+ cmDocumentationSection* sec = CM_NULLPTR;
+ if (this->AllSections.find(name) == this->AllSections.end()) {
+ sec =
+ new cmDocumentationSection(name, cmSystemTools::UpperCase(name).c_str());
+ this->SetSection(name, sec);
+ } else {
+ sec = this->AllSections[name];
+ }
+ sec->Append(docs);
+}
+
+void cmDocumentation::AppendSection(const char* name,
+ std::vector<cmDocumentationEntry>& docs)
+{
+ cmDocumentationSection* sec = CM_NULLPTR;
+ if (this->AllSections.find(name) == this->AllSections.end()) {
+ sec =
+ new cmDocumentationSection(name, cmSystemTools::UpperCase(name).c_str());
+ this->SetSection(name, sec);
+ } else {
+ sec = this->AllSections[name];
+ }
+ sec->Append(docs);
+}
+
+void cmDocumentation::AppendSection(const char* name,
+ cmDocumentationEntry& docs)
+{
+
+ std::vector<cmDocumentationEntry> docsVec;
+ docsVec.push_back(docs);
+ this->AppendSection(name, docsVec);
+}
+
+void cmDocumentation::PrependSection(const char* name,
+ cmDocumentationEntry& docs)
+{
+
+ std::vector<cmDocumentationEntry> docsVec;
+ docsVec.push_back(docs);
+ this->PrependSection(name, docsVec);
+}
+
+void cmDocumentation::GlobHelp(std::vector<std::string>& files,
+ std::string const& pattern)
+{
+ cmsys::Glob gl;
+ std::string findExpr =
+ cmSystemTools::GetCMakeRoot() + "/Help/" + pattern + ".rst";
+ if (gl.FindFiles(findExpr)) {
+ files = gl.GetFiles();
+ }
+}
+
+void cmDocumentation::PrintNames(std::ostream& os, std::string const& pattern)
+{
+ std::vector<std::string> files;
+ this->GlobHelp(files, pattern);
+ std::vector<std::string> names;
+ for (std::vector<std::string>::const_iterator i = files.begin();
+ i != files.end(); ++i) {
+ std::string line;
+ cmsys::ifstream fin(i->c_str());
+ while (fin && cmSystemTools::GetLineFromStream(fin, line)) {
+ if (!line.empty() && (isalnum(line[0]) || line[0] == '<')) {
+ names.push_back(line);
+ break;
+ }
+ }
+ }
+ std::sort(names.begin(), names.end());
+ for (std::vector<std::string>::iterator i = names.begin(); i != names.end();
+ ++i) {
+ os << *i << "\n";
+ }
+}
+
+bool cmDocumentation::PrintFiles(std::ostream& os, std::string const& pattern)
+{
+ bool found = false;
+ std::vector<std::string> files;
+ this->GlobHelp(files, pattern);
+ std::sort(files.begin(), files.end());
+ cmRST r(os, cmSystemTools::GetCMakeRoot() + "/Help");
+ for (std::vector<std::string>::const_iterator i = files.begin();
+ i != files.end(); ++i) {
+ found = r.ProcessFile(*i) || found;
+ }
+ return found;
+}
+
+bool cmDocumentation::PrintHelpFull(std::ostream& os)
+{
+ return this->PrintFiles(os, "index");
+}
+
+bool cmDocumentation::PrintHelpOneManual(std::ostream& os)
+{
+ std::string mname = this->CurrentArgument;
+ std::string::size_type mlen = mname.length();
+ if (mlen > 3 && mname[mlen - 3] == '(' && mname[mlen - 1] == ')') {
+ mname = mname.substr(0, mlen - 3) + "." + mname[mlen - 2];
+ }
+ if (this->PrintFiles(os, "manual/" + mname) ||
+ this->PrintFiles(os, "manual/" + mname + ".[0-9]")) {
+ return true;
+ }
+ // Argument was not a manual. Complain.
+ os << "Argument \"" << this->CurrentArgument
+ << "\" to --help-manual is not an available manual. "
+ << "Use --help-manual-list to see all available manuals.\n";
+ return false;
+}
+
+bool cmDocumentation::PrintHelpListManuals(std::ostream& os)
+{
+ this->PrintNames(os, "manual/*");
+ return true;
+}
+
+bool cmDocumentation::PrintHelpOneCommand(std::ostream& os)
+{
+ std::string cname = cmSystemTools::LowerCase(this->CurrentArgument);
+ if (this->PrintFiles(os, "command/" + cname)) {
+ return true;
+ }
+ // Argument was not a command. Complain.
+ os << "Argument \"" << this->CurrentArgument
+ << "\" to --help-command is not a CMake command. "
+ << "Use --help-command-list to see all commands.\n";
+ return false;
+}
+
+bool cmDocumentation::PrintHelpListCommands(std::ostream& os)
+{
+ this->PrintNames(os, "command/*");
+ return true;
+}
+
+bool cmDocumentation::PrintHelpOneModule(std::ostream& os)
+{
+ std::string mname = this->CurrentArgument;
+ if (this->PrintFiles(os, "module/" + mname)) {
+ return true;
+ }
+ // Argument was not a module. Complain.
+ os << "Argument \"" << this->CurrentArgument
+ << "\" to --help-module is not a CMake module.\n";
+ return false;
+}
+
+bool cmDocumentation::PrintHelpListModules(std::ostream& os)
+{
+ std::vector<std::string> files;
+ this->GlobHelp(files, "module/*");
+ std::vector<std::string> modules;
+ for (std::vector<std::string>::iterator fi = files.begin();
+ fi != files.end(); ++fi) {
+ std::string module = cmSystemTools::GetFilenameName(*fi);
+ modules.push_back(module.substr(0, module.size() - 4));
+ }
+ std::sort(modules.begin(), modules.end());
+ for (std::vector<std::string>::iterator i = modules.begin();
+ i != modules.end(); ++i) {
+ os << *i << "\n";
+ }
+ return true;
+}
+
+bool cmDocumentation::PrintHelpOneProperty(std::ostream& os)
+{
+ std::string pname = cmSystemTools::HelpFileName(this->CurrentArgument);
+ if (this->PrintFiles(os, "prop_*/" + pname)) {
+ return true;
+ }
+ // Argument was not a property. Complain.
+ os << "Argument \"" << this->CurrentArgument
+ << "\" to --help-property is not a CMake property. "
+ << "Use --help-property-list to see all properties.\n";
+ return false;
+}
+
+bool cmDocumentation::PrintHelpListProperties(std::ostream& os)
+{
+ this->PrintNames(os, "prop_*/*");
+ return true;
+}
+
+bool cmDocumentation::PrintHelpOnePolicy(std::ostream& os)
+{
+ std::string pname = this->CurrentArgument;
+ std::vector<std::string> files;
+ if (this->PrintFiles(os, "policy/" + pname)) {
+ return true;
+ }
+
+ // Argument was not a policy. Complain.
+ os << "Argument \"" << this->CurrentArgument
+ << "\" to --help-policy is not a CMake policy.\n";
+ return false;
+}
+
+bool cmDocumentation::PrintHelpListPolicies(std::ostream& os)
+{
+ this->PrintNames(os, "policy/*");
+ return true;
+}
+
+bool cmDocumentation::PrintHelpListGenerators(std::ostream& os)
+{
+ std::map<std::string, cmDocumentationSection*>::iterator si;
+ si = this->AllSections.find("Generators");
+ if (si != this->AllSections.end()) {
+ this->Formatter.SetIndent(" ");
+ this->Formatter.PrintSection(os, *si->second);
+ }
+ return true;
+}
+
+bool cmDocumentation::PrintHelpOneVariable(std::ostream& os)
+{
+ std::string vname = cmSystemTools::HelpFileName(this->CurrentArgument);
+ if (this->PrintFiles(os, "variable/" + vname)) {
+ return true;
+ }
+ // Argument was not a variable. Complain.
+ os << "Argument \"" << this->CurrentArgument
+ << "\" to --help-variable is not a defined variable. "
+ << "Use --help-variable-list to see all defined variables.\n";
+ return false;
+}
+
+bool cmDocumentation::PrintHelpListVariables(std::ostream& os)
+{
+ this->PrintNames(os, "variable/*");
+ return true;
+}
+
+bool cmDocumentation::PrintUsage(std::ostream& os)
+{
+ std::map<std::string, cmDocumentationSection*>::iterator si;
+ si = this->AllSections.find("Usage");
+ if (si != this->AllSections.end()) {
+ this->Formatter.PrintSection(os, *si->second);
+ }
+ return true;
+}
+
+bool cmDocumentation::PrintHelp(std::ostream& os)
+{
+ std::map<std::string, cmDocumentationSection*>::iterator si;
+ si = this->AllSections.find("Usage");
+ if (si != this->AllSections.end()) {
+ this->Formatter.PrintSection(os, *si->second);
+ }
+ si = this->AllSections.find("Options");
+ if (si != this->AllSections.end()) {
+ this->Formatter.PrintSection(os, *si->second);
+ }
+ if (this->ShowGenerators) {
+ si = this->AllSections.find("Generators");
+ if (si != this->AllSections.end()) {
+ this->Formatter.PrintSection(os, *si->second);
+ }
+ }
+ return true;
+}
+
+const char* cmDocumentation::GetNameString() const
+{
+ if (!this->NameString.empty()) {
+ return this->NameString.c_str();
+ } else {
+ return "CMake";
+ }
+}
+
+bool cmDocumentation::IsOption(const char* arg) const
+{
+ return ((arg[0] == '-') || (strcmp(arg, "/V") == 0) ||
+ (strcmp(arg, "/?") == 0));
+}
+
+bool cmDocumentation::PrintOldCustomModules(std::ostream& os)
+{
+ // CheckOptions abuses the Argument field to give us the file name.
+ std::string filename = this->CurrentArgument;
+ std::string ext = cmSystemTools::UpperCase(
+ cmSystemTools::GetFilenameLastExtension(filename));
+ std::string name = cmSystemTools::GetFilenameWithoutLastExtension(filename);
+
+ const char* summary = "cmake --help-custom-modules no longer supported\n";
+ const char* detail =
+ "CMake versions prior to 3.0 exposed their internal module help page\n"
+ "generation functionality through the --help-custom-modules option.\n"
+ "CMake versions 3.0 and above use other means to generate their module\n"
+ "help pages so this functionality is no longer available to be exposed.\n"
+ "\n"
+ "This file was generated as a placeholder to provide this information.\n";
+ if ((ext == ".HTM") || (ext == ".HTML")) {
+ os << "<html><title>" << name << "</title><body>\n"
+ << summary << "<p/>\n"
+ << detail << "</body></html>\n";
+ } else if ((ext.length() == 2) && (ext[1] >= '1') && (ext[1] <= '9')) {
+ /* clang-format off */
+ os <<
+ ".TH " << name << " " << ext[1] << " \"" <<
+ cmSystemTools::GetCurrentDateTime("%B %d, %Y") <<
+ "\" \"cmake " << cmVersion::GetCMakeVersion() << "\"\n"
+ ".SH NAME\n"
+ ".PP\n" <<
+ name << " \\- " << summary <<
+ "\n"
+ ".SH DESCRIPTION\n"
+ ".PP\n" <<
+ detail
+ ;
+ /* clang-format on */
+ } else {
+ os << name << "\n\n" << summary << "\n" << detail;
+ }
+ return true;
+}
diff --git a/Source/cmDocumentation.h b/Source/cmDocumentation.h
new file mode 100644
index 0000000..ac36c8b
--- /dev/null
+++ b/Source/cmDocumentation.h
@@ -0,0 +1,141 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef _cmDocumentation_h
+#define _cmDocumentation_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmDocumentationFormatter.h"
+#include "cmDocumentationSection.h"
+#include "cmake.h"
+
+namespace cmsys {
+class Directory;
+}
+
+/** Class to generate documentation. */
+class cmDocumentation : public cmDocumentationEnums
+{
+public:
+ cmDocumentation();
+
+ ~cmDocumentation();
+
+ /**
+ * Check command line arguments for documentation options. Returns
+ * true if documentation options are found, and false otherwise.
+ * When true is returned, PrintRequestedDocumentation should be
+ * called. exitOpt can be used for things like cmake -E, so that
+ * all arguments after the -E are ignored and not searched for
+ * help arguments.
+ */
+ bool CheckOptions(int argc, const char* const* argv,
+ const char* exitOpt = CM_NULLPTR);
+
+ /**
+ * Print help requested on the command line. Call after
+ * CheckOptions returns true. Returns true on success, and false
+ * otherwise. Failure can occur when output files specified on the
+ * command line cannot be written.
+ */
+ bool PrintRequestedDocumentation(std::ostream& os);
+
+ /** Print help of the given type. */
+ bool PrintDocumentation(Type ht, std::ostream& os);
+
+ void SetShowGenerators(bool showGen) { this->ShowGenerators = showGen; }
+
+ /** Set the program name for standard document generation. */
+ void SetName(const std::string& name);
+
+ /** Set a section of the documentation. Typical sections include Name,
+ Usage, Description, Options */
+ void SetSection(const char* sectionName, cmDocumentationSection* section);
+ void SetSection(const char* sectionName,
+ std::vector<cmDocumentationEntry>& docs);
+ void SetSection(const char* sectionName, const char* docs[][2]);
+ void SetSections(std::map<std::string, cmDocumentationSection*>& sections);
+
+ /** Add the documentation to the beginning/end of the section */
+ void PrependSection(const char* sectionName, const char* docs[][2]);
+ void PrependSection(const char* sectionName,
+ std::vector<cmDocumentationEntry>& docs);
+ void PrependSection(const char* sectionName, cmDocumentationEntry& docs);
+ void AppendSection(const char* sectionName, const char* docs[][2]);
+ void AppendSection(const char* sectionName,
+ std::vector<cmDocumentationEntry>& docs);
+ void AppendSection(const char* sectionName, cmDocumentationEntry& docs);
+
+ /** Add common (to all tools) documentation section(s) */
+ void addCommonStandardDocSections();
+
+ /** Add the CMake standard documentation section(s) */
+ void addCMakeStandardDocSections();
+
+ /** Add the CTest standard documentation section(s) */
+ void addCTestStandardDocSections();
+
+ /** Add the CPack standard documentation section(s) */
+ void addCPackStandardDocSections();
+
+private:
+ void GlobHelp(std::vector<std::string>& files, std::string const& pattern);
+ void PrintNames(std::ostream& os, std::string const& pattern);
+ bool PrintFiles(std::ostream& os, std::string const& pattern);
+
+ bool PrintVersion(std::ostream& os);
+ bool PrintUsage(std::ostream& os);
+ bool PrintHelp(std::ostream& os);
+ bool PrintHelpFull(std::ostream& os);
+ bool PrintHelpOneManual(std::ostream& os);
+ bool PrintHelpOneCommand(std::ostream& os);
+ bool PrintHelpOneModule(std::ostream& os);
+ bool PrintHelpOnePolicy(std::ostream& os);
+ bool PrintHelpOneProperty(std::ostream& os);
+ bool PrintHelpOneVariable(std::ostream& os);
+ bool PrintHelpListManuals(std::ostream& os);
+ bool PrintHelpListCommands(std::ostream& os);
+ bool PrintHelpListModules(std::ostream& os);
+ bool PrintHelpListProperties(std::ostream& os);
+ bool PrintHelpListVariables(std::ostream& os);
+ bool PrintHelpListPolicies(std::ostream& os);
+ bool PrintHelpListGenerators(std::ostream& os);
+ bool PrintOldCustomModules(std::ostream& os);
+
+ const char* GetNameString() const;
+ bool IsOption(const char* arg) const;
+
+ bool ShowGenerators;
+
+ std::string NameString;
+ std::map<std::string, cmDocumentationSection*> AllSections;
+
+ std::string CurrentArgument;
+
+ struct RequestedHelpItem
+ {
+ RequestedHelpItem()
+ : HelpType(None)
+ {
+ }
+ cmDocumentationEnums::Type HelpType;
+ std::string Filename;
+ std::string Argument;
+ };
+
+ std::vector<RequestedHelpItem> RequestedHelpItems;
+ cmDocumentationFormatter Formatter;
+
+ static void WarnFormFromFilename(RequestedHelpItem& request, bool& result);
+};
+
+#endif
diff --git a/Source/cmDocumentationEntry.h b/Source/cmDocumentationEntry.h
new file mode 100644
index 0000000..f50839e
--- /dev/null
+++ b/Source/cmDocumentationEntry.h
@@ -0,0 +1,45 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmDocumentationEntry_h
+#define cmDocumentationEntry_h
+
+#include <cmConfigure.h> // IWYU pragma: keep
+
+#include <string>
+
+/** Standard documentation entry for cmDocumentation's formatting. */
+struct cmDocumentationEntry
+{
+ std::string Name;
+ std::string Brief;
+ cmDocumentationEntry() {}
+ cmDocumentationEntry(const char* doc[2])
+ {
+ if (doc[0]) {
+ this->Name = doc[0];
+ }
+ if (doc[1]) {
+ this->Brief = doc[1];
+ }
+ }
+ cmDocumentationEntry(const char* n, const char* b)
+ {
+ if (n) {
+ this->Name = n;
+ }
+ if (b) {
+ this->Brief = b;
+ }
+ }
+};
+
+#endif
diff --git a/Source/cmDocumentationFormatter.cxx b/Source/cmDocumentationFormatter.cxx
new file mode 100644
index 0000000..4816bb9
--- /dev/null
+++ b/Source/cmDocumentationFormatter.cxx
@@ -0,0 +1,197 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmDocumentationFormatter.h"
+
+#include "cmDocumentationSection.h"
+
+cmDocumentationFormatter::cmDocumentationFormatter()
+ : TextWidth(77)
+ , TextIndent("")
+{
+}
+
+cmDocumentationFormatter::~cmDocumentationFormatter()
+{
+}
+
+void cmDocumentationFormatter::PrintFormatted(std::ostream& os,
+ const char* text)
+{
+ if (!text) {
+ return;
+ }
+ const char* ptr = text;
+ while (*ptr) {
+ // Any ptrs starting in a space are treated as preformatted text.
+ std::string preformatted;
+ while (*ptr == ' ') {
+ for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) {
+ preformatted.append(1, ch);
+ }
+ if (*ptr) {
+ ++ptr;
+ preformatted.append(1, '\n');
+ }
+ }
+ if (!preformatted.empty()) {
+ this->PrintPreformatted(os, preformatted.c_str());
+ }
+
+ // Other ptrs are treated as paragraphs.
+ std::string paragraph;
+ for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) {
+ paragraph.append(1, ch);
+ }
+ if (*ptr) {
+ ++ptr;
+ paragraph.append(1, '\n');
+ }
+ if (!paragraph.empty()) {
+ this->PrintParagraph(os, paragraph.c_str());
+ }
+ }
+}
+
+void cmDocumentationFormatter::PrintPreformatted(std::ostream& os,
+ const char* text)
+{
+ bool newline = true;
+ for (const char* ptr = text; *ptr; ++ptr) {
+ if (newline && *ptr != '\n') {
+ os << this->TextIndent;
+ newline = false;
+ }
+ os << *ptr;
+ if (*ptr == '\n') {
+ newline = true;
+ }
+ }
+ os << "\n";
+}
+
+void cmDocumentationFormatter::PrintParagraph(std::ostream& os,
+ const char* text)
+{
+ os << this->TextIndent;
+ this->PrintColumn(os, text);
+ os << "\n";
+}
+
+void cmDocumentationFormatter::SetIndent(const char* indent)
+{
+ this->TextIndent = indent;
+}
+
+void cmDocumentationFormatter::PrintColumn(std::ostream& os, const char* text)
+{
+ // Print text arranged in an indented column of fixed witdh.
+ const char* l = text;
+ long column = 0;
+ bool newSentence = false;
+ bool firstLine = true;
+ int width = this->TextWidth - static_cast<int>(strlen(this->TextIndent));
+
+ // Loop until the end of the text.
+ while (*l) {
+ // Parse the next word.
+ const char* r = l;
+ while (*r && (*r != '\n') && (*r != ' ')) {
+ ++r;
+ }
+
+ // Does it fit on this line?
+ if (r - l < (width - column - (newSentence ? 1 : 0))) {
+ // Word fits on this line.
+ if (r > l) {
+ if (column) {
+ // Not first word on line. Separate from the previous word
+ // by a space, or two if this is a new sentence.
+ if (newSentence) {
+ os << " ";
+ column += 2;
+ } else {
+ os << " ";
+ column += 1;
+ }
+ } else {
+ // First word on line. Print indentation unless this is the
+ // first line.
+ os << (firstLine ? "" : this->TextIndent);
+ }
+
+ // Print the word.
+ os.write(l, static_cast<long>(r - l));
+ newSentence = (*(r - 1) == '.');
+ }
+
+ if (*r == '\n') {
+ // Text provided a newline. Start a new line.
+ os << "\n";
+ ++r;
+ column = 0;
+ firstLine = false;
+ } else {
+ // No provided newline. Continue this line.
+ column += static_cast<long>(r - l);
+ }
+ } else {
+ // Word does not fit on this line. Start a new line.
+ os << "\n";
+ firstLine = false;
+ if (r > l) {
+ os << this->TextIndent;
+ os.write(l, static_cast<long>(r - l));
+ column = static_cast<long>(r - l);
+ newSentence = (*(r - 1) == '.');
+ } else {
+ column = 0;
+ }
+ }
+
+ // Move to beginning of next word. Skip over whitespace.
+ l = r;
+ while (*l && (*l == ' ')) {
+ ++l;
+ }
+ }
+}
+
+void cmDocumentationFormatter::PrintSection(
+ std::ostream& os, cmDocumentationSection const& section)
+{
+ os << section.GetName() << "\n";
+
+ const std::vector<cmDocumentationEntry>& entries = section.GetEntries();
+ for (std::vector<cmDocumentationEntry>::const_iterator op = entries.begin();
+ op != entries.end(); ++op) {
+ if (!op->Name.empty()) {
+ os << " " << op->Name;
+ this->TextIndent = " ";
+ int align = static_cast<int>(strlen(this->TextIndent)) - 4;
+ for (int i = static_cast<int>(op->Name.size()); i < align; ++i) {
+ os << " ";
+ }
+ if (op->Name.size() > strlen(this->TextIndent) - 4) {
+ os << "\n";
+ os.write(this->TextIndent, strlen(this->TextIndent) - 2);
+ }
+ os << "= ";
+ this->PrintColumn(os, op->Brief.c_str());
+ os << "\n";
+ } else {
+ os << "\n";
+ this->TextIndent = "";
+ this->PrintFormatted(os, op->Brief.c_str());
+ }
+ }
+ os << "\n";
+}
diff --git a/Source/cmDocumentationFormatter.h b/Source/cmDocumentationFormatter.h
new file mode 100644
index 0000000..7c4c35b
--- /dev/null
+++ b/Source/cmDocumentationFormatter.h
@@ -0,0 +1,73 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef _cmDocumentationFormatter_h
+#define _cmDocumentationFormatter_h
+
+#include "cmStandardIncludes.h"
+
+/** This is just a helper class to make it build with MSVC 6.0.
+Actually the enums and internal classes could directly go into
+cmDocumentation, but then MSVC6 complains in RequestedHelpItem that
+cmDocumentation is an undefined type and so it doesn't know the enums.
+Moving the enums to a class which is then already completely parsed helps
+against this. */
+class cmDocumentationEnums
+{
+public:
+ /** Types of help provided. */
+ enum Type
+ {
+ None,
+ Version,
+ Usage,
+ Help,
+ Full,
+ ListManuals,
+ ListCommands,
+ ListModules,
+ ListProperties,
+ ListVariables,
+ ListPolicies,
+ ListGenerators,
+ OneManual,
+ OneCommand,
+ OneModule,
+ OneProperty,
+ OneVariable,
+ OnePolicy,
+ OldCustomModules
+ };
+};
+
+class cmDocumentationSection;
+
+/** Print documentation in a simple text format. */
+class cmDocumentationFormatter
+{
+public:
+ cmDocumentationFormatter();
+ virtual ~cmDocumentationFormatter();
+ void PrintFormatted(std::ostream& os, const char* text);
+
+ virtual void PrintSection(std::ostream& os,
+ cmDocumentationSection const& section);
+ virtual void PrintPreformatted(std::ostream& os, const char* text);
+ virtual void PrintParagraph(std::ostream& os, const char* text);
+ void PrintColumn(std::ostream& os, const char* text);
+ void SetIndent(const char* indent);
+
+private:
+ int TextWidth;
+ const char* TextIndent;
+};
+
+#endif
diff --git a/Source/cmDocumentationSection.cxx b/Source/cmDocumentationSection.cxx
new file mode 100644
index 0000000..c6c87f4
--- /dev/null
+++ b/Source/cmDocumentationSection.cxx
@@ -0,0 +1,37 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmDocumentationSection.h"
+
+void cmDocumentationSection::Append(const char* data[][2])
+{
+ int i = 0;
+ while (data[i][1]) {
+ this->Entries.push_back(cmDocumentationEntry(data[i][0], data[i][1]));
+ data += 1;
+ }
+}
+
+void cmDocumentationSection::Prepend(const char* data[][2])
+{
+ std::vector<cmDocumentationEntry> tmp;
+ int i = 0;
+ while (data[i][1]) {
+ tmp.push_back(cmDocumentationEntry(data[i][0], data[i][1]));
+ data += 1;
+ }
+ this->Entries.insert(this->Entries.begin(), tmp.begin(), tmp.end());
+}
+
+void cmDocumentationSection::Append(const char* n, const char* b)
+{
+ this->Entries.push_back(cmDocumentationEntry(n, b));
+}
diff --git a/Source/cmDocumentationSection.h b/Source/cmDocumentationSection.h
new file mode 100644
index 0000000..161a731
--- /dev/null
+++ b/Source/cmDocumentationSection.h
@@ -0,0 +1,73 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef _cmDocumentationSection_h
+#define _cmDocumentationSection_h
+
+#include "cmDocumentationFormatter.h"
+
+// Low-level interface for custom documents:
+/** Internal class representing a section of the documentation.
+ * Cares e.g. for the different section titles in the different
+ * output formats.
+ */
+class cmDocumentationSection
+{
+public:
+ /** Create a cmSection, with a special name for man-output mode. */
+ cmDocumentationSection(const char* name, const char*)
+ : Name(name)
+ {
+ }
+
+ /** Has any content been added to this section or is it empty ? */
+ bool IsEmpty() const { return this->Entries.empty(); }
+
+ /** Clear contents. */
+ void Clear() { this->Entries.clear(); }
+
+ /** Return the name of this section. */
+ std::string GetName() const { return this->Name; }
+
+ /** Return a pointer to the first entry of this section. */
+ const std::vector<cmDocumentationEntry>& GetEntries() const
+ {
+ return this->Entries;
+ }
+
+ /** Append an entry to this section. */
+ void Append(const cmDocumentationEntry& entry)
+ {
+ this->Entries.push_back(entry);
+ }
+ void Append(const std::vector<cmDocumentationEntry>& entries)
+ {
+ this->Entries.insert(this->Entries.end(), entries.begin(), entries.end());
+ }
+
+ /** Append an entry to this section using NULL terminated chars */
+ void Append(const char* [][2]);
+ void Append(const char* n, const char* b);
+
+ /** prepend some documentation to this section */
+ void Prepend(const char* [][2]);
+ void Prepend(const std::vector<cmDocumentationEntry>& entries)
+ {
+ this->Entries.insert(this->Entries.begin(), entries.begin(),
+ entries.end());
+ }
+
+private:
+ std::string Name;
+ std::vector<cmDocumentationEntry> Entries;
+};
+
+#endif
diff --git a/Source/cmDynamicLoader.cxx b/Source/cmDynamicLoader.cxx
new file mode 100644
index 0000000..4c31733f
--- /dev/null
+++ b/Source/cmDynamicLoader.cxx
@@ -0,0 +1,104 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmDynamicLoader.h"
+
+class cmDynamicLoaderCache
+{
+public:
+ ~cmDynamicLoaderCache();
+ void CacheFile(const char* path, const cmsys::DynamicLoader::LibraryHandle&);
+ bool GetCacheFile(const char* path, cmsys::DynamicLoader::LibraryHandle&);
+ bool FlushCache(const char* path);
+ void FlushCache();
+ static cmDynamicLoaderCache* GetInstance();
+
+private:
+ std::map<std::string, cmsys::DynamicLoader::LibraryHandle> CacheMap;
+ static cmDynamicLoaderCache* Instance;
+};
+
+cmDynamicLoaderCache* cmDynamicLoaderCache::Instance = CM_NULLPTR;
+
+cmDynamicLoaderCache::~cmDynamicLoaderCache()
+{
+}
+
+void cmDynamicLoaderCache::CacheFile(
+ const char* path, const cmsys::DynamicLoader::LibraryHandle& p)
+{
+ cmsys::DynamicLoader::LibraryHandle h;
+ if (this->GetCacheFile(path, h)) {
+ this->FlushCache(path);
+ }
+ this->CacheMap[path] = p;
+}
+
+bool cmDynamicLoaderCache::GetCacheFile(const char* path,
+ cmsys::DynamicLoader::LibraryHandle& p)
+{
+ std::map<std::string, cmsys::DynamicLoader::LibraryHandle>::iterator it =
+ this->CacheMap.find(path);
+ if (it != this->CacheMap.end()) {
+ p = it->second;
+ return true;
+ }
+ return false;
+}
+
+bool cmDynamicLoaderCache::FlushCache(const char* path)
+{
+ std::map<std::string, cmsys::DynamicLoader::LibraryHandle>::iterator it =
+ this->CacheMap.find(path);
+ bool ret = false;
+ if (it != this->CacheMap.end()) {
+ cmsys::DynamicLoader::CloseLibrary(it->second);
+ this->CacheMap.erase(it);
+ ret = true;
+ }
+ return ret;
+}
+
+void cmDynamicLoaderCache::FlushCache()
+{
+ for (std::map<std::string, cmsys::DynamicLoader::LibraryHandle>::iterator
+ it = this->CacheMap.begin();
+ it != this->CacheMap.end(); it++) {
+ cmsys::DynamicLoader::CloseLibrary(it->second);
+ }
+ delete cmDynamicLoaderCache::Instance;
+ cmDynamicLoaderCache::Instance = CM_NULLPTR;
+}
+
+cmDynamicLoaderCache* cmDynamicLoaderCache::GetInstance()
+{
+ if (!cmDynamicLoaderCache::Instance) {
+ cmDynamicLoaderCache::Instance = new cmDynamicLoaderCache;
+ }
+ return cmDynamicLoaderCache::Instance;
+}
+
+cmsys::DynamicLoader::LibraryHandle cmDynamicLoader::OpenLibrary(
+ const char* libname)
+{
+ cmsys::DynamicLoader::LibraryHandle lh;
+ if (cmDynamicLoaderCache::GetInstance()->GetCacheFile(libname, lh)) {
+ return lh;
+ }
+ lh = cmsys::DynamicLoader::OpenLibrary(libname);
+ cmDynamicLoaderCache::GetInstance()->CacheFile(libname, lh);
+ return lh;
+}
+
+void cmDynamicLoader::FlushCache()
+{
+ cmDynamicLoaderCache::GetInstance()->FlushCache();
+}
diff --git a/Source/cmDynamicLoader.h b/Source/cmDynamicLoader.h
new file mode 100644
index 0000000..58d9ae9
--- /dev/null
+++ b/Source/cmDynamicLoader.h
@@ -0,0 +1,46 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+// .NAME cmDynamicLoader - class interface to system dynamic libraries
+// .SECTION Description
+// cmDynamicLoader provides a portable interface to loading dynamic
+// libraries into a process.
+
+#ifndef cmDynamicLoader_h
+#define cmDynamicLoader_h
+
+#include "cmStandardIncludes.h"
+
+#include <cmsys/DynamicLoader.hxx>
+
+class cmDynamicLoader
+{
+public:
+ // Description:
+ // Load a dynamic library into the current process.
+ // The returned cmsys::DynamicLoader::LibraryHandle can be used to access
+ // the symbols in the library.
+ static cmsys::DynamicLoader::LibraryHandle OpenLibrary(const char*);
+
+ // Description:
+ // Flush the cache of dynamic loader.
+ static void FlushCache();
+
+protected:
+ cmDynamicLoader() {}
+ ~cmDynamicLoader() {}
+
+private:
+ cmDynamicLoader(const cmDynamicLoader&); // Not implemented.
+ void operator=(const cmDynamicLoader&); // Not implemented.
+};
+
+#endif
diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx
new file mode 100644
index 0000000..15755cb
--- /dev/null
+++ b/Source/cmELF.cxx
@@ -0,0 +1,916 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmStandardIncludes.h" // to get CMAKE_USE_ELF_PARSER first
+
+#include "cmELF.h"
+
+#include <cm_auto_ptr.hxx>
+#include <cmsys/FStream.hxx>
+
+// Include the ELF format information system header.
+#if defined(__OpenBSD__)
+#include <elf_abi.h>
+#include <stdint.h>
+#elif defined(__HAIKU__)
+#include <elf32.h>
+#include <elf64.h>
+typedef struct Elf32_Ehdr Elf32_Ehdr;
+typedef struct Elf32_Shdr Elf32_Shdr;
+typedef struct Elf32_Sym Elf32_Sym;
+typedef struct Elf32_Rel Elf32_Rel;
+typedef struct Elf32_Rela Elf32_Rela;
+#define ELFMAG0 0x7F
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+#define ET_NONE 0
+#define ET_REL 1
+#define ET_EXEC 2
+#define ET_DYN 3
+#define ET_CORE 4
+#define EM_386 3
+#define EM_SPARC 2
+#define EM_PPC 20
+#else
+#include <elf.h>
+#endif
+#if defined(__sun)
+#include <sys/link.h> // For dynamic section information
+#endif
+
+// Low-level byte swapping implementation.
+template <size_t s>
+struct cmELFByteSwapSize
+{
+};
+void cmELFByteSwap(char*, cmELFByteSwapSize<1> const&)
+{
+}
+void cmELFByteSwap(char* data, cmELFByteSwapSize<2> const&)
+{
+ char one_byte;
+ one_byte = data[0];
+ data[0] = data[1];
+ data[1] = one_byte;
+}
+void cmELFByteSwap(char* data, cmELFByteSwapSize<4> const&)
+{
+ char one_byte;
+ one_byte = data[0];
+ data[0] = data[3];
+ data[3] = one_byte;
+ one_byte = data[1];
+ data[1] = data[2];
+ data[2] = one_byte;
+}
+void cmELFByteSwap(char* data, cmELFByteSwapSize<8> const&)
+{
+ char one_byte;
+ one_byte = data[0];
+ data[0] = data[7];
+ data[7] = one_byte;
+ one_byte = data[1];
+ data[1] = data[6];
+ data[6] = one_byte;
+ one_byte = data[2];
+ data[2] = data[5];
+ data[5] = one_byte;
+ one_byte = data[3];
+ data[3] = data[4];
+ data[4] = one_byte;
+}
+
+// Low-level byte swapping interface.
+template <typename T>
+void cmELFByteSwap(T& x)
+{
+ cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
+}
+
+class cmELFInternal
+{
+public:
+ typedef cmELF::StringEntry StringEntry;
+ enum ByteOrderType
+ {
+ ByteOrderMSB,
+ ByteOrderLSB
+ };
+
+ // Construct and take ownership of the file stream object.
+ cmELFInternal(cmELF* external, CM_AUTO_PTR<cmsys::ifstream>& fin,
+ ByteOrderType order)
+ : External(external)
+ , Stream(*fin.release())
+ , ByteOrder(order)
+ , ELFType(cmELF::FileTypeInvalid)
+ {
+// In most cases the processor-specific byte order will match that
+// of the target execution environment. If we choose wrong here
+// it is fixed when the header is read.
+#if KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_LITTLE
+ this->NeedSwap = (this->ByteOrder == ByteOrderMSB);
+#elif KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_BIG
+ this->NeedSwap = (this->ByteOrder == ByteOrderLSB);
+#else
+ this->NeedSwap = false; // Final decision is at runtime anyway.
+#endif
+
+ // We have not yet loaded the section info.
+ this->DynamicSectionIndex = -1;
+ }
+
+ // Destruct and delete the file stream object.
+ virtual ~cmELFInternal() { delete &this->Stream; }
+
+ // Forward to the per-class implementation.
+ virtual unsigned int GetNumberOfSections() const = 0;
+ virtual unsigned int GetDynamicEntryCount() = 0;
+ virtual unsigned long GetDynamicEntryPosition(int j) = 0;
+ virtual StringEntry const* GetDynamicSectionString(unsigned int tag) = 0;
+ virtual void PrintInfo(std::ostream& os) const = 0;
+
+ bool ReadBytes(unsigned long pos, unsigned long size, char* buf)
+ {
+ this->Stream.seekg(pos);
+ this->Stream.read(buf, size);
+ return !this->Stream.fail();
+ }
+
+ // Lookup the SONAME in the DYNAMIC section.
+ StringEntry const* GetSOName()
+ {
+ return this->GetDynamicSectionString(DT_SONAME);
+ }
+
+ // Lookup the RPATH in the DYNAMIC section.
+ StringEntry const* GetRPath()
+ {
+ return this->GetDynamicSectionString(DT_RPATH);
+ }
+
+ // Lookup the RUNPATH in the DYNAMIC section.
+ StringEntry const* GetRunPath()
+ {
+#if defined(DT_RUNPATH)
+ return this->GetDynamicSectionString(DT_RUNPATH);
+#else
+ return 0;
+#endif
+ }
+
+ // Return the recorded ELF type.
+ cmELF::FileType GetFileType() const { return this->ELFType; }
+protected:
+ // Data common to all ELF class implementations.
+
+ // The external cmELF object.
+ cmELF* External;
+
+ // The stream from which to read.
+ std::istream& Stream;
+
+ // The byte order of the ELF file.
+ ByteOrderType ByteOrder;
+
+ // The ELF file type.
+ cmELF::FileType ELFType;
+
+ // Whether we need to byte-swap structures read from the stream.
+ bool NeedSwap;
+
+ // The section header index of the DYNAMIC section (-1 if none).
+ int DynamicSectionIndex;
+
+ // Helper methods for subclasses.
+ void SetErrorMessage(const char* msg)
+ {
+ this->External->ErrorMessage = msg;
+ this->ELFType = cmELF::FileTypeInvalid;
+ }
+
+ // Store string table entry states.
+ std::map<unsigned int, StringEntry> DynamicSectionStrings;
+};
+
+// Configure the implementation template for 32-bit ELF files.
+struct cmELFTypes32
+{
+ typedef Elf32_Ehdr ELF_Ehdr;
+ typedef Elf32_Shdr ELF_Shdr;
+ typedef Elf32_Dyn ELF_Dyn;
+ typedef Elf32_Half ELF_Half;
+ typedef KWIML_INT_uint32_t tagtype;
+ static const char* GetName() { return "32-bit"; }
+};
+
+// Configure the implementation template for 64-bit ELF files.
+struct cmELFTypes64
+{
+ typedef Elf64_Ehdr ELF_Ehdr;
+ typedef Elf64_Shdr ELF_Shdr;
+ typedef Elf64_Dyn ELF_Dyn;
+ typedef Elf64_Half ELF_Half;
+ typedef KWIML_INT_uint64_t tagtype;
+ static const char* GetName() { return "64-bit"; }
+};
+
+// Parser implementation template.
+template <class Types>
+class cmELFInternalImpl : public cmELFInternal
+{
+public:
+ // Copy the ELF file format types from our configuration parameter.
+ typedef typename Types::ELF_Ehdr ELF_Ehdr;
+ typedef typename Types::ELF_Shdr ELF_Shdr;
+ typedef typename Types::ELF_Dyn ELF_Dyn;
+ typedef typename Types::ELF_Half ELF_Half;
+ typedef typename Types::tagtype tagtype;
+
+ // Construct with a stream and byte swap indicator.
+ cmELFInternalImpl(cmELF* external, CM_AUTO_PTR<cmsys::ifstream>& fin,
+ ByteOrderType order);
+
+ // Return the number of sections as specified by the ELF header.
+ unsigned int GetNumberOfSections() const CM_OVERRIDE
+ {
+ return static_cast<unsigned int>(this->ELFHeader.e_shnum);
+ }
+
+ // Get the file position and size of a dynamic section entry.
+ unsigned int GetDynamicEntryCount() CM_OVERRIDE;
+ unsigned long GetDynamicEntryPosition(int j) CM_OVERRIDE;
+
+ // Lookup a string from the dynamic section with the given tag.
+ StringEntry const* GetDynamicSectionString(unsigned int tag) CM_OVERRIDE;
+
+ // Print information about the ELF file.
+ void PrintInfo(std::ostream& os) const CM_OVERRIDE
+ {
+ os << "ELF " << Types::GetName();
+ if (this->ByteOrder == ByteOrderMSB) {
+ os << " MSB";
+ } else if (this->ByteOrder == ByteOrderLSB) {
+ os << " LSB";
+ }
+ switch (this->ELFType) {
+ case cmELF::FileTypeInvalid:
+ os << " invalid file";
+ break;
+ case cmELF::FileTypeRelocatableObject:
+ os << " relocatable object";
+ break;
+ case cmELF::FileTypeExecutable:
+ os << " executable";
+ break;
+ case cmELF::FileTypeSharedLibrary:
+ os << " shared library";
+ break;
+ case cmELF::FileTypeCore:
+ os << " core file";
+ break;
+ case cmELF::FileTypeSpecificOS:
+ os << " os-specific type";
+ break;
+ case cmELF::FileTypeSpecificProc:
+ os << " processor-specific type";
+ break;
+ }
+ os << "\n";
+ }
+
+private:
+ void ByteSwap(ELF_Ehdr& elf_header)
+ {
+ cmELFByteSwap(elf_header.e_type);
+ cmELFByteSwap(elf_header.e_machine);
+ cmELFByteSwap(elf_header.e_version);
+ cmELFByteSwap(elf_header.e_entry);
+ cmELFByteSwap(elf_header.e_phoff);
+ cmELFByteSwap(elf_header.e_shoff);
+ cmELFByteSwap(elf_header.e_flags);
+ cmELFByteSwap(elf_header.e_ehsize);
+ cmELFByteSwap(elf_header.e_phentsize);
+ cmELFByteSwap(elf_header.e_phnum);
+ cmELFByteSwap(elf_header.e_shentsize);
+ cmELFByteSwap(elf_header.e_shnum);
+ cmELFByteSwap(elf_header.e_shstrndx);
+ }
+
+ void ByteSwap(ELF_Shdr& sec_header)
+ {
+ cmELFByteSwap(sec_header.sh_name);
+ cmELFByteSwap(sec_header.sh_type);
+ cmELFByteSwap(sec_header.sh_flags);
+ cmELFByteSwap(sec_header.sh_addr);
+ cmELFByteSwap(sec_header.sh_offset);
+ cmELFByteSwap(sec_header.sh_size);
+ cmELFByteSwap(sec_header.sh_link);
+ cmELFByteSwap(sec_header.sh_info);
+ cmELFByteSwap(sec_header.sh_addralign);
+ cmELFByteSwap(sec_header.sh_entsize);
+ }
+
+ void ByteSwap(ELF_Dyn& dyn)
+ {
+ cmELFByteSwap(dyn.d_tag);
+ switch (dyn.d_tag) {
+ case DT_NULL: /* dyn.d_un ignored */
+ break;
+ case DT_NEEDED:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+ case DT_PLTRELSZ:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+ case DT_PLTGOT:
+ cmELFByteSwap(dyn.d_un.d_ptr);
+ break;
+ case DT_HASH:
+ cmELFByteSwap(dyn.d_un.d_ptr);
+ break;
+ case DT_STRTAB:
+ cmELFByteSwap(dyn.d_un.d_ptr);
+ break;
+ case DT_SYMTAB:
+ cmELFByteSwap(dyn.d_un.d_ptr);
+ break;
+ case DT_RELA:
+ cmELFByteSwap(dyn.d_un.d_ptr);
+ break;
+ case DT_RELASZ:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+ case DT_RELAENT:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+ case DT_STRSZ:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+ case DT_SYMENT:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+ case DT_INIT:
+ cmELFByteSwap(dyn.d_un.d_ptr);
+ break;
+ case DT_FINI:
+ cmELFByteSwap(dyn.d_un.d_ptr);
+ break;
+ case DT_SONAME:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+ case DT_RPATH:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+ case DT_SYMBOLIC: /* dyn.d_un ignored */
+ break;
+ case DT_REL:
+ cmELFByteSwap(dyn.d_un.d_ptr);
+ break;
+ case DT_RELSZ:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+ case DT_RELENT:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+ case DT_PLTREL:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+ case DT_DEBUG:
+ cmELFByteSwap(dyn.d_un.d_ptr);
+ break;
+ case DT_TEXTREL: /* dyn.d_un ignored */
+ break;
+ case DT_JMPREL:
+ cmELFByteSwap(dyn.d_un.d_ptr);
+ break;
+#ifdef T_BIND_NOW
+ case T_BIND_NOW: /* dyn.d_un ignored */
+ break;
+#endif
+#ifdef DT_INIT_ARRAY
+ case DT_INIT_ARRAY:
+ cmELFByteSwap(dyn.d_un.d_ptr);
+ break;
+#endif
+#ifdef DT_FINI_ARRAY
+ case DT_FINI_ARRAY:
+ cmELFByteSwap(dyn.d_un.d_ptr);
+ break;
+#endif
+#ifdef DT_INIT_ARRAYSZ
+ case DT_INIT_ARRAYSZ:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+#endif
+#ifdef DT_FINI_ARRAYSZ
+ case DT_FINI_ARRAYSZ:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+#endif
+#ifdef DT_RUNPATH
+ case DT_RUNPATH:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+#endif
+#ifdef DT_FLAGS
+ case DT_FLAGS:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+#endif
+#ifdef DT_PREINIT_ARRAY
+ case DT_PREINIT_ARRAY:
+ cmELFByteSwap(dyn.d_un.d_ptr);
+ break;
+#endif
+#ifdef DT_PREINIT_ARRAYSZ
+ case DT_PREINIT_ARRAYSZ:
+ cmELFByteSwap(dyn.d_un.d_val);
+ break;
+#endif
+ }
+ }
+
+ bool FileTypeValid(ELF_Half et)
+ {
+ unsigned int eti = static_cast<unsigned int>(et);
+ if (eti == ET_NONE || eti == ET_REL || eti == ET_EXEC || eti == ET_DYN ||
+ eti == ET_CORE) {
+ return true;
+ }
+#if defined(ET_LOOS) && defined(ET_HIOS)
+ if (eti >= ET_LOOS && eti <= ET_HIOS) {
+ return true;
+ }
+#endif
+#if defined(ET_LOPROC) && defined(ET_HIPROC)
+ if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
+ return true;
+ }
+#endif
+ return false;
+ }
+
+ bool Read(ELF_Ehdr& x)
+ {
+ // Read the header from the file.
+ if (!this->Stream.read(reinterpret_cast<char*>(&x), sizeof(x))) {
+ return false;
+ }
+
+ // The byte order of ELF header fields may not match that of the
+ // processor-specific data. The header fields are ordered to
+ // match the target execution environment, so we may need to
+ // memorize the order of all platforms based on the e_machine
+ // value. As a heuristic, if the type is invalid but its
+ // swapped value is okay then flip our swap mode.
+ ELF_Half et = x.e_type;
+ if (this->NeedSwap) {
+ cmELFByteSwap(et);
+ }
+ if (!this->FileTypeValid(et)) {
+ cmELFByteSwap(et);
+ if (this->FileTypeValid(et)) {
+ // The previous byte order guess was wrong. Flip it.
+ this->NeedSwap = !this->NeedSwap;
+ }
+ }
+
+ // Fix the byte order of the header.
+ if (this->NeedSwap) {
+ ByteSwap(x);
+ }
+ return true;
+ }
+ bool Read(ELF_Shdr& x)
+ {
+ if (this->Stream.read(reinterpret_cast<char*>(&x), sizeof(x)) &&
+ this->NeedSwap) {
+ ByteSwap(x);
+ }
+ return !this->Stream.fail();
+ }
+ bool Read(ELF_Dyn& x)
+ {
+ if (this->Stream.read(reinterpret_cast<char*>(&x), sizeof(x)) &&
+ this->NeedSwap) {
+ ByteSwap(x);
+ }
+ return !this->Stream.fail();
+ }
+
+ bool LoadSectionHeader(ELF_Half i)
+ {
+ // Read the section header from the file.
+ this->Stream.seekg(this->ELFHeader.e_shoff +
+ this->ELFHeader.e_shentsize * i);
+ if (!this->Read(this->SectionHeaders[i])) {
+ return false;
+ }
+
+ // Identify some important sections.
+ if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) {
+ this->DynamicSectionIndex = i;
+ }
+ return true;
+ }
+
+ bool LoadDynamicSection();
+
+ // Store the main ELF header.
+ ELF_Ehdr ELFHeader;
+
+ // Store all the section headers.
+ std::vector<ELF_Shdr> SectionHeaders;
+
+ // Store all entries of the DYNAMIC section.
+ std::vector<ELF_Dyn> DynamicSectionEntries;
+};
+
+template <class Types>
+cmELFInternalImpl<Types>::cmELFInternalImpl(cmELF* external,
+ CM_AUTO_PTR<cmsys::ifstream>& fin,
+ ByteOrderType order)
+ : cmELFInternal(external, fin, order)
+{
+ // Read the main header.
+ if (!this->Read(this->ELFHeader)) {
+ this->SetErrorMessage("Failed to read main ELF header.");
+ return;
+ }
+
+ // Determine the ELF file type.
+ switch (this->ELFHeader.e_type) {
+ case ET_NONE:
+ this->SetErrorMessage("ELF file type is NONE.");
+ return;
+ case ET_REL:
+ this->ELFType = cmELF::FileTypeRelocatableObject;
+ break;
+ case ET_EXEC:
+ this->ELFType = cmELF::FileTypeExecutable;
+ break;
+ case ET_DYN:
+ this->ELFType = cmELF::FileTypeSharedLibrary;
+ break;
+ case ET_CORE:
+ this->ELFType = cmELF::FileTypeCore;
+ break;
+ default: {
+ unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type);
+#if defined(ET_LOOS) && defined(ET_HIOS)
+ if (eti >= ET_LOOS && eti <= ET_HIOS) {
+ this->ELFType = cmELF::FileTypeSpecificOS;
+ break;
+ }
+#endif
+#if defined(ET_LOPROC) && defined(ET_HIPROC)
+ if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
+ this->ELFType = cmELF::FileTypeSpecificProc;
+ break;
+ }
+#endif
+ std::ostringstream e;
+ e << "Unknown ELF file type " << eti;
+ this->SetErrorMessage(e.str().c_str());
+ return;
+ }
+ }
+
+ // Load the section headers.
+ this->SectionHeaders.resize(this->ELFHeader.e_shnum);
+ for (ELF_Half i = 0; i < this->ELFHeader.e_shnum; ++i) {
+ if (!this->LoadSectionHeader(i)) {
+ this->SetErrorMessage("Failed to load section headers.");
+ return;
+ }
+ }
+}
+
+template <class Types>
+bool cmELFInternalImpl<Types>::LoadDynamicSection()
+{
+ // If there is no dynamic section we are done.
+ if (this->DynamicSectionIndex < 0) {
+ return false;
+ }
+
+ // If the section was already loaded we are done.
+ if (!this->DynamicSectionEntries.empty()) {
+ return true;
+ }
+
+ // If there are no entries we are done.
+ ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
+ if (sec.sh_entsize == 0) {
+ return false;
+ }
+
+ // Allocate the dynamic section entries.
+ int n = static_cast<int>(sec.sh_size / sec.sh_entsize);
+ this->DynamicSectionEntries.resize(n);
+
+ // Read each entry.
+ for (int j = 0; j < n; ++j) {
+ // Seek to the beginning of the section entry.
+ this->Stream.seekg(sec.sh_offset + sec.sh_entsize * j);
+ ELF_Dyn& dyn = this->DynamicSectionEntries[j];
+
+ // Try reading the entry.
+ if (!this->Read(dyn)) {
+ this->SetErrorMessage("Error reading entry from DYNAMIC section.");
+ this->DynamicSectionIndex = -1;
+ return false;
+ }
+ }
+ return true;
+}
+
+template <class Types>
+unsigned int cmELFInternalImpl<Types>::GetDynamicEntryCount()
+{
+ if (!this->LoadDynamicSection()) {
+ return 0;
+ }
+ for (unsigned int i = 0; i < this->DynamicSectionEntries.size(); ++i) {
+ if (this->DynamicSectionEntries[i].d_tag == DT_NULL) {
+ return i;
+ }
+ }
+ return static_cast<unsigned int>(this->DynamicSectionEntries.size());
+}
+
+template <class Types>
+unsigned long cmELFInternalImpl<Types>::GetDynamicEntryPosition(int j)
+{
+ if (!this->LoadDynamicSection()) {
+ return 0;
+ }
+ if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) {
+ return 0;
+ }
+ ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
+ return static_cast<unsigned long>(sec.sh_offset + sec.sh_entsize * j);
+}
+
+template <class Types>
+cmELF::StringEntry const* cmELFInternalImpl<Types>::GetDynamicSectionString(
+ unsigned int tag)
+{
+ // Short-circuit if already checked.
+ std::map<unsigned int, StringEntry>::iterator dssi =
+ this->DynamicSectionStrings.find(tag);
+ if (dssi != this->DynamicSectionStrings.end()) {
+ if (dssi->second.Position > 0) {
+ return &dssi->second;
+ }
+ return CM_NULLPTR;
+ }
+
+ // Create an entry for this tag. Assume it is missing until found.
+ StringEntry& se = this->DynamicSectionStrings[tag];
+ se.Position = 0;
+ se.Size = 0;
+ se.IndexInSection = -1;
+
+ // Try reading the dynamic section.
+ if (!this->LoadDynamicSection()) {
+ return CM_NULLPTR;
+ }
+
+ // Get the string table referenced by the DYNAMIC section.
+ ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
+ if (sec.sh_link >= this->SectionHeaders.size()) {
+ this->SetErrorMessage("Section DYNAMIC has invalid string table index.");
+ return CM_NULLPTR;
+ }
+ ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link];
+
+ // Look for the requested entry.
+ for (typename std::vector<ELF_Dyn>::iterator di =
+ this->DynamicSectionEntries.begin();
+ di != this->DynamicSectionEntries.end(); ++di) {
+ ELF_Dyn& dyn = *di;
+ if (static_cast<tagtype>(dyn.d_tag) == static_cast<tagtype>(tag)) {
+ // We found the tag requested.
+ // Make sure the position given is within the string section.
+ if (dyn.d_un.d_val >= strtab.sh_size) {
+ this->SetErrorMessage("Section DYNAMIC references string beyond "
+ "the end of its string section.");
+ return CM_NULLPTR;
+ }
+
+ // Seek to the position reported by the entry.
+ unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val);
+ unsigned long last = first;
+ unsigned long end = static_cast<unsigned long>(strtab.sh_size);
+ this->Stream.seekg(strtab.sh_offset + first);
+
+ // Read the string. It may be followed by more than one NULL
+ // terminator. Count the total size of the region allocated to
+ // the string. This assumes that the next string in the table
+ // is non-empty, but the "chrpath" tool makes the same
+ // assumption.
+ bool terminated = false;
+ char c;
+ while (last != end && this->Stream.get(c) && !(terminated && c)) {
+ ++last;
+ if (c) {
+ se.Value += c;
+ } else {
+ terminated = true;
+ }
+ }
+
+ // Make sure the whole value was read.
+ if (!this->Stream) {
+ this->SetErrorMessage("Dynamic section specifies unreadable RPATH.");
+ se.Value = "";
+ return CM_NULLPTR;
+ }
+
+ // The value has been read successfully. Report it.
+ se.Position = static_cast<unsigned long>(strtab.sh_offset + first);
+ se.Size = last - first;
+ se.IndexInSection =
+ static_cast<int>(di - this->DynamicSectionEntries.begin());
+ return &se;
+ }
+ }
+ return CM_NULLPTR;
+}
+
+//============================================================================
+// External class implementation.
+
+cmELF::cmELF(const char* fname)
+ : Internal(CM_NULLPTR)
+{
+ // Try to open the file.
+ CM_AUTO_PTR<cmsys::ifstream> fin(new cmsys::ifstream(fname));
+
+ // Quit now if the file could not be opened.
+ if (!fin.get() || !*fin) {
+ this->ErrorMessage = "Error opening input file.";
+ return;
+ }
+
+ // Read the ELF identification block.
+ char ident[EI_NIDENT];
+ if (!fin->read(ident, EI_NIDENT)) {
+ this->ErrorMessage = "Error reading ELF identification.";
+ return;
+ }
+ if (!fin->seekg(0)) {
+ this->ErrorMessage = "Error seeking to beginning of file.";
+ return;
+ }
+
+ // Verify the ELF identification.
+ if (!(ident[EI_MAG0] == ELFMAG0 && ident[EI_MAG1] == ELFMAG1 &&
+ ident[EI_MAG2] == ELFMAG2 && ident[EI_MAG3] == ELFMAG3)) {
+ this->ErrorMessage = "File does not have a valid ELF identification.";
+ return;
+ }
+
+ // Check the byte order in which the rest of the file is encoded.
+ cmELFInternal::ByteOrderType order;
+ if (ident[EI_DATA] == ELFDATA2LSB) {
+ // File is LSB.
+ order = cmELFInternal::ByteOrderLSB;
+ } else if (ident[EI_DATA] == ELFDATA2MSB) {
+ // File is MSB.
+ order = cmELFInternal::ByteOrderMSB;
+ } else {
+ this->ErrorMessage = "ELF file is not LSB or MSB encoded.";
+ return;
+ }
+
+ // Check the class of the file and construct the corresponding
+ // parser implementation.
+ if (ident[EI_CLASS] == ELFCLASS32) {
+ // 32-bit ELF
+ this->Internal = new cmELFInternalImpl<cmELFTypes32>(this, fin, order);
+ } else if (ident[EI_CLASS] == ELFCLASS64) {
+ // 64-bit ELF
+ this->Internal = new cmELFInternalImpl<cmELFTypes64>(this, fin, order);
+ } else {
+ this->ErrorMessage = "ELF file class is not 32-bit or 64-bit.";
+ return;
+ }
+}
+
+cmELF::~cmELF()
+{
+ delete this->Internal;
+}
+
+bool cmELF::Valid() const
+{
+ return this->Internal && this->Internal->GetFileType() != FileTypeInvalid;
+}
+
+cmELF::FileType cmELF::GetFileType() const
+{
+ if (this->Valid()) {
+ return this->Internal->GetFileType();
+ } else {
+ return FileTypeInvalid;
+ }
+}
+
+unsigned int cmELF::GetNumberOfSections() const
+{
+ if (this->Valid()) {
+ return this->Internal->GetNumberOfSections();
+ } else {
+ return 0;
+ }
+}
+
+unsigned int cmELF::GetDynamicEntryCount() const
+{
+ if (this->Valid()) {
+ return this->Internal->GetDynamicEntryCount();
+ } else {
+ return 0;
+ }
+}
+
+unsigned long cmELF::GetDynamicEntryPosition(int index) const
+{
+ if (this->Valid()) {
+ return this->Internal->GetDynamicEntryPosition(index);
+ } else {
+ return 0;
+ }
+}
+
+bool cmELF::ReadBytes(unsigned long pos, unsigned long size, char* buf) const
+{
+ if (this->Valid()) {
+ return this->Internal->ReadBytes(pos, size, buf);
+ } else {
+ return false;
+ }
+}
+
+bool cmELF::GetSOName(std::string& soname)
+{
+ if (StringEntry const* se = this->GetSOName()) {
+ soname = se->Value;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+cmELF::StringEntry const* cmELF::GetSOName()
+{
+ if (this->Valid() &&
+ this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary) {
+ return this->Internal->GetSOName();
+ } else {
+ return CM_NULLPTR;
+ }
+}
+
+cmELF::StringEntry const* cmELF::GetRPath()
+{
+ if (this->Valid() &&
+ (this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
+ this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) {
+ return this->Internal->GetRPath();
+ } else {
+ return CM_NULLPTR;
+ }
+}
+
+cmELF::StringEntry const* cmELF::GetRunPath()
+{
+ if (this->Valid() &&
+ (this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
+ this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) {
+ return this->Internal->GetRunPath();
+ } else {
+ return CM_NULLPTR;
+ }
+}
+
+void cmELF::PrintInfo(std::ostream& os) const
+{
+ if (this->Valid()) {
+ this->Internal->PrintInfo(os);
+ } else {
+ os << "Not a valid ELF file.\n";
+ }
+}
diff --git a/Source/cmELF.h b/Source/cmELF.h
new file mode 100644
index 0000000..80832ad
--- /dev/null
+++ b/Source/cmELF.h
@@ -0,0 +1,105 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmELF_h
+#define cmELF_h
+
+#if !defined(CMAKE_USE_ELF_PARSER)
+#error "This file may be included only if CMAKE_USE_ELF_PARSER is enabled."
+#endif
+
+class cmELFInternal;
+
+/** \class cmELF
+ * \brief Executable and Link Format (ELF) parser.
+ */
+class cmELF
+{
+public:
+ /** Construct with the name of the ELF input file to parse. */
+ cmELF(const char* fname);
+
+ /** Destruct. */
+ ~cmELF();
+
+ /** Get the error message if any. */
+ std::string const& GetErrorMessage() const { return this->ErrorMessage; }
+
+ /** Boolean conversion. True if the ELF file is valid. */
+ operator bool() const { return this->Valid(); }
+
+ /** Enumeration of ELF file types. */
+ enum FileType
+ {
+ FileTypeInvalid,
+ FileTypeRelocatableObject,
+ FileTypeExecutable,
+ FileTypeSharedLibrary,
+ FileTypeCore,
+ FileTypeSpecificOS,
+ FileTypeSpecificProc
+ };
+
+ /** Represent string table entries. */
+ struct StringEntry
+ {
+ // The string value itself.
+ std::string Value;
+
+ // The position in the file at which the string appears.
+ unsigned long Position;
+
+ // The size of the string table entry. This includes the space
+ // allocated for one or more null terminators.
+ unsigned long Size;
+
+ // The index of the section entry referencing the string.
+ int IndexInSection;
+ };
+
+ /** Get the type of the file opened. */
+ FileType GetFileType() const;
+
+ /** Get the number of ELF sections present. */
+ unsigned int GetNumberOfSections() const;
+
+ /** Get the number of DYNAMIC section entries before the first
+ DT_NULL. Returns zero on error. */
+ unsigned int GetDynamicEntryCount() const;
+
+ /** Get the position of a DYNAMIC section header entry. Returns
+ zero on error. */
+ unsigned long GetDynamicEntryPosition(int index) const;
+
+ /** Read bytes from the file. */
+ bool ReadBytes(unsigned long pos, unsigned long size, char* buf) const;
+
+ /** Get the SONAME field if any. */
+ bool GetSOName(std::string& soname);
+ StringEntry const* GetSOName();
+
+ /** Get the RPATH field if any. */
+ StringEntry const* GetRPath();
+
+ /** Get the RUNPATH field if any. */
+ StringEntry const* GetRunPath();
+
+ /** Print human-readable information about the ELF file. */
+ void PrintInfo(std::ostream& os) const;
+
+private:
+ friend class cmELFInternal;
+ bool Valid() const;
+ cmELFInternal* Internal;
+ std::string ErrorMessage;
+};
+
+#endif
diff --git a/Source/cmElseCommand.cxx b/Source/cmElseCommand.cxx
new file mode 100644
index 0000000..6db6f8d
--- /dev/null
+++ b/Source/cmElseCommand.cxx
@@ -0,0 +1,21 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmElseCommand.h"
+
+bool cmElseCommand::InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&)
+{
+ this->SetError("An ELSE command was found outside of a proper "
+ "IF ENDIF structure. Or its arguments did not match "
+ "the opening IF command.");
+ return false;
+}
diff --git a/Source/cmElseCommand.h b/Source/cmElseCommand.h
new file mode 100644
index 0000000..9acf4d8
--- /dev/null
+++ b/Source/cmElseCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmElseCommand_h
+#define cmElseCommand_h
+
+#include "cmIfCommand.h"
+
+/** \class cmElseCommand
+ * \brief ends an if block
+ *
+ * cmElseCommand ends an if block
+ */
+class cmElseCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmElseCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "else"; }
+
+ cmTypeMacro(cmElseCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmElseIfCommand.cxx b/Source/cmElseIfCommand.cxx
new file mode 100644
index 0000000..dc89e24
--- /dev/null
+++ b/Source/cmElseIfCommand.cxx
@@ -0,0 +1,20 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmElseIfCommand.h"
+
+bool cmElseIfCommand::InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&)
+{
+ this->SetError("An ELSEIF command was found outside of a proper "
+ "IF ENDIF structure.");
+ return false;
+}
diff --git a/Source/cmElseIfCommand.h b/Source/cmElseIfCommand.h
new file mode 100644
index 0000000..19c1885
--- /dev/null
+++ b/Source/cmElseIfCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmElseIfCommand_h
+#define cmElseIfCommand_h
+
+#include "cmIfCommand.h"
+
+/** \class cmElseIfCommand
+ * \brief ends an if block
+ *
+ * cmElseIfCommand ends an if block
+ */
+class cmElseIfCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmElseIfCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "elseif"; }
+
+ cmTypeMacro(cmElseIfCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmEnableLanguageCommand.cxx b/Source/cmEnableLanguageCommand.cxx
new file mode 100644
index 0000000..0ebe778
--- /dev/null
+++ b/Source/cmEnableLanguageCommand.cxx
@@ -0,0 +1,35 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmEnableLanguageCommand.h"
+
+// cmEnableLanguageCommand
+bool cmEnableLanguageCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ bool optional = false;
+ std::vector<std::string> languages;
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ for (std::vector<std::string>::const_iterator it = args.begin();
+ it != args.end(); ++it) {
+ if ((*it) == "OPTIONAL") {
+ optional = true;
+ } else {
+ languages.push_back(*it);
+ }
+ }
+
+ this->Makefile->EnableLanguage(languages, optional);
+ return true;
+}
diff --git a/Source/cmEnableLanguageCommand.h b/Source/cmEnableLanguageCommand.h
new file mode 100644
index 0000000..31b6095
--- /dev/null
+++ b/Source/cmEnableLanguageCommand.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmEnableLanguageCommand_h
+#define cmEnableLanguageCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmEnableLanguageCommand
+ * \brief Specify the name for this build project.
+ *
+ * cmEnableLanguageCommand is used to specify a name for this build project.
+ * It is defined once per set of CMakeList.txt files (including
+ * all subdirectories). Currently it just sets the name of the workspace
+ * file for Microsoft Visual C++
+ */
+class cmEnableLanguageCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmEnableLanguageCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "enable_language"; }
+
+ cmTypeMacro(cmEnableLanguageCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmEnableTestingCommand.cxx b/Source/cmEnableTestingCommand.cxx
new file mode 100644
index 0000000..a9c60a8
--- /dev/null
+++ b/Source/cmEnableTestingCommand.cxx
@@ -0,0 +1,21 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmEnableTestingCommand.h"
+
+// we do this in the final pass so that we now the subdirs have all
+// been defined
+bool cmEnableTestingCommand::InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&)
+{
+ this->Makefile->AddDefinition("CMAKE_TESTING_ENABLED", "1");
+ return true;
+}
diff --git a/Source/cmEnableTestingCommand.h b/Source/cmEnableTestingCommand.h
new file mode 100644
index 0000000..8c8ffbf
--- /dev/null
+++ b/Source/cmEnableTestingCommand.h
@@ -0,0 +1,53 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmEnableTestingCommand_h
+#define cmEnableTestingCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmEnableTestingCommand
+ * \brief Enable testing for this directory and below.
+ *
+ * Produce the output testfile. This produces a file in the build directory
+ * called CMakeTestfile with a syntax similar to CMakeLists.txt. It contains
+ * the SUBDIRS() and ADD_TEST() commands from the source CMakeLists.txt
+ * file with CMake variables expanded. Only the subdirs and tests
+ * within the valid control structures are replicated in Testfile
+ * (i.e. SUBDIRS() and ADD_TEST() commands within IF() commands that are
+ * not entered by CMake are not replicated in Testfile).
+ * Note that CTest expects to find this file in the build directory root;
+ * therefore, this command should be in the source directory root too.
+ */
+class cmEnableTestingCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmEnableTestingCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "enable_testing"; }
+
+ cmTypeMacro(cmEnableTestingCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmEndForEachCommand.cxx b/Source/cmEndForEachCommand.cxx
new file mode 100644
index 0000000..104b39a
--- /dev/null
+++ b/Source/cmEndForEachCommand.cxx
@@ -0,0 +1,21 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmEndForEachCommand.h"
+
+bool cmEndForEachCommand::InvokeInitialPass(
+ std::vector<cmListFileArgument> const&, cmExecutionStatus&)
+{
+ this->SetError("An ENDFOREACH command was found outside of a proper "
+ "FOREACH ENDFOREACH structure. Or its arguments did "
+ "not match the opening FOREACH command.");
+ return false;
+}
diff --git a/Source/cmEndForEachCommand.h b/Source/cmEndForEachCommand.h
new file mode 100644
index 0000000..b2c47b2
--- /dev/null
+++ b/Source/cmEndForEachCommand.h
@@ -0,0 +1,60 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmEndForEachCommand_h
+#define cmEndForEachCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmEndForEachCommand
+ * \brief ends an if block
+ *
+ * cmEndForEachCommand ends an if block
+ */
+class cmEndForEachCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmEndForEachCommand; }
+
+ /**
+ * Override cmCommand::InvokeInitialPass to get arguments before
+ * expansion.
+ */
+ bool InvokeInitialPass(std::vector<cmListFileArgument> const&,
+ cmExecutionStatus&) CM_OVERRIDE;
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&) CM_OVERRIDE
+ {
+ return false;
+ }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "endforeach"; }
+
+ cmTypeMacro(cmEndForEachCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmEndFunctionCommand.cxx b/Source/cmEndFunctionCommand.cxx
new file mode 100644
index 0000000..b4bfa2d
--- /dev/null
+++ b/Source/cmEndFunctionCommand.cxx
@@ -0,0 +1,21 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmEndFunctionCommand.h"
+
+bool cmEndFunctionCommand::InvokeInitialPass(
+ std::vector<cmListFileArgument> const&, cmExecutionStatus&)
+{
+ this->SetError("An ENDFUNCTION command was found outside of a proper "
+ "FUNCTION ENDFUNCTION structure. Or its arguments did not "
+ "match the opening FUNCTION command.");
+ return false;
+}
diff --git a/Source/cmEndFunctionCommand.h b/Source/cmEndFunctionCommand.h
new file mode 100644
index 0000000..856fdc5
--- /dev/null
+++ b/Source/cmEndFunctionCommand.h
@@ -0,0 +1,60 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmEndFunctionCommand_h
+#define cmEndFunctionCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmEndFunctionCommand
+ * \brief ends an if block
+ *
+ * cmEndFunctionCommand ends an if block
+ */
+class cmEndFunctionCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmEndFunctionCommand; }
+
+ /**
+ * Override cmCommand::InvokeInitialPass to get arguments before
+ * expansion.
+ */
+ bool InvokeInitialPass(std::vector<cmListFileArgument> const&,
+ cmExecutionStatus&) CM_OVERRIDE;
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&) CM_OVERRIDE
+ {
+ return false;
+ }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "endfunction"; }
+
+ cmTypeMacro(cmEndFunctionCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmEndIfCommand.cxx b/Source/cmEndIfCommand.cxx
new file mode 100644
index 0000000..1ae3a78
--- /dev/null
+++ b/Source/cmEndIfCommand.cxx
@@ -0,0 +1,28 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmEndIfCommand.h"
+
+#include <stdlib.h> // required for atof
+bool cmEndIfCommand::InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&)
+{
+ const char* versionValue =
+ this->Makefile->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION");
+ if (!versionValue || (atof(versionValue) <= 1.4)) {
+ return true;
+ }
+
+ this->SetError("An ENDIF command was found outside of a proper "
+ "IF ENDIF structure. Or its arguments did not match "
+ "the opening IF command.");
+ return false;
+}
diff --git a/Source/cmEndIfCommand.h b/Source/cmEndIfCommand.h
new file mode 100644
index 0000000..13cf6f6
--- /dev/null
+++ b/Source/cmEndIfCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmEndIfCommand_h
+#define cmEndIfCommand_h
+
+#include "cmIfCommand.h"
+
+/** \class cmEndIfCommand
+ * \brief ends an if block
+ *
+ * cmEndIfCommand ends an if block
+ */
+class cmEndIfCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmEndIfCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "endif"; }
+
+ cmTypeMacro(cmEndIfCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmEndMacroCommand.cxx b/Source/cmEndMacroCommand.cxx
new file mode 100644
index 0000000..435c05f
--- /dev/null
+++ b/Source/cmEndMacroCommand.cxx
@@ -0,0 +1,21 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmEndMacroCommand.h"
+
+bool cmEndMacroCommand::InvokeInitialPass(
+ std::vector<cmListFileArgument> const&, cmExecutionStatus&)
+{
+ this->SetError("An ENDMACRO command was found outside of a proper "
+ "MACRO ENDMACRO structure. Or its arguments did not "
+ "match the opening MACRO command.");
+ return false;
+}
diff --git a/Source/cmEndMacroCommand.h b/Source/cmEndMacroCommand.h
new file mode 100644
index 0000000..e176eaf
--- /dev/null
+++ b/Source/cmEndMacroCommand.h
@@ -0,0 +1,60 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmEndMacroCommand_h
+#define cmEndMacroCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmEndMacroCommand
+ * \brief ends an if block
+ *
+ * cmEndMacroCommand ends an if block
+ */
+class cmEndMacroCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmEndMacroCommand; }
+
+ /**
+ * Override cmCommand::InvokeInitialPass to get arguments before
+ * expansion.
+ */
+ bool InvokeInitialPass(std::vector<cmListFileArgument> const&,
+ cmExecutionStatus&) CM_OVERRIDE;
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&) CM_OVERRIDE
+ {
+ return false;
+ }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "endmacro"; }
+
+ cmTypeMacro(cmEndMacroCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmEndWhileCommand.cxx b/Source/cmEndWhileCommand.cxx
new file mode 100644
index 0000000..33507de
--- /dev/null
+++ b/Source/cmEndWhileCommand.cxx
@@ -0,0 +1,27 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmEndWhileCommand.h"
+
+bool cmEndWhileCommand::InvokeInitialPass(
+ std::vector<cmListFileArgument> const& args, cmExecutionStatus&)
+{
+ if (args.empty()) {
+ this->SetError("An ENDWHILE command was found outside of a proper "
+ "WHILE ENDWHILE structure.");
+ } else {
+ this->SetError("An ENDWHILE command was found outside of a proper "
+ "WHILE ENDWHILE structure. Or its arguments did not "
+ "match the opening WHILE command.");
+ }
+
+ return false;
+}
diff --git a/Source/cmEndWhileCommand.h b/Source/cmEndWhileCommand.h
new file mode 100644
index 0000000..6b72514
--- /dev/null
+++ b/Source/cmEndWhileCommand.h
@@ -0,0 +1,60 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmEndWhileCommand_h
+#define cmEndWhileCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmEndWhileCommand
+ * \brief ends a while loop
+ *
+ * cmEndWhileCommand ends a while loop
+ */
+class cmEndWhileCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmEndWhileCommand; }
+
+ /**
+ * Override cmCommand::InvokeInitialPass to get arguments before
+ * expansion.
+ */
+ bool InvokeInitialPass(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&) CM_OVERRIDE
+ {
+ return false;
+ }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "endwhile"; }
+
+ cmTypeMacro(cmEndWhileCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx
new file mode 100644
index 0000000..58bbc31
--- /dev/null
+++ b/Source/cmExecProgramCommand.cxx
@@ -0,0 +1,279 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmExecProgramCommand.h"
+
+#include "cmSystemTools.h"
+
+#include <cmsys/Process.h>
+
+// cmExecProgramCommand
+bool cmExecProgramCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ std::string arguments;
+ bool doingargs = false;
+ int count = 0;
+ std::string output_variable;
+ bool haveoutput_variable = false;
+ std::string return_variable;
+ bool havereturn_variable = false;
+ for (size_t i = 0; i < args.size(); ++i) {
+ if (args[i] == "OUTPUT_VARIABLE") {
+ count++;
+ doingargs = false;
+ havereturn_variable = false;
+ haveoutput_variable = true;
+ } else if (haveoutput_variable) {
+ if (!output_variable.empty()) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ output_variable = args[i];
+ haveoutput_variable = false;
+ count++;
+ } else if (args[i] == "RETURN_VALUE") {
+ count++;
+ doingargs = false;
+ haveoutput_variable = false;
+ havereturn_variable = true;
+ } else if (havereturn_variable) {
+ if (!return_variable.empty()) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ return_variable = args[i];
+ havereturn_variable = false;
+ count++;
+ } else if (args[i] == "ARGS") {
+ count++;
+ havereturn_variable = false;
+ haveoutput_variable = false;
+ doingargs = true;
+ } else if (doingargs) {
+ arguments += args[i];
+ arguments += " ";
+ count++;
+ }
+ }
+
+ std::string command;
+ if (!arguments.empty()) {
+ command = cmSystemTools::ConvertToRunCommandPath(args[0].c_str());
+ command += " ";
+ command += arguments;
+ } else {
+ command = args[0];
+ }
+ bool verbose = true;
+ if (!output_variable.empty()) {
+ verbose = false;
+ }
+ int retVal = 0;
+ std::string output;
+ bool result = true;
+ if (args.size() - count == 2) {
+ cmSystemTools::MakeDirectory(args[1].c_str());
+ result = cmExecProgramCommand::RunCommand(command.c_str(), output, retVal,
+ args[1].c_str(), verbose);
+ } else {
+ result = cmExecProgramCommand::RunCommand(command.c_str(), output, retVal,
+ CM_NULLPTR, verbose);
+ }
+ if (!result) {
+ retVal = -1;
+ }
+
+ if (!output_variable.empty()) {
+ std::string::size_type first = output.find_first_not_of(" \n\t\r");
+ std::string::size_type last = output.find_last_not_of(" \n\t\r");
+ if (first == std::string::npos) {
+ first = 0;
+ }
+ if (last == std::string::npos) {
+ last = output.size() - 1;
+ }
+
+ std::string coutput = std::string(output, first, last - first + 1);
+ this->Makefile->AddDefinition(output_variable, coutput.c_str());
+ }
+
+ if (!return_variable.empty()) {
+ char buffer[100];
+ sprintf(buffer, "%d", retVal);
+ this->Makefile->AddDefinition(return_variable, buffer);
+ }
+
+ return true;
+}
+
+bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
+ int& retVal, const char* dir,
+ bool verbose)
+{
+ if (cmSystemTools::GetRunCommandOutput()) {
+ verbose = false;
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // if the command does not start with a quote, then
+ // 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] == '\"') {
+ // count the number of quotes
+ for (const char* s = command; *s != 0; ++s) {
+ if (*s == '\"') {
+ count++;
+ if (count > 2) {
+ break;
+ }
+ }
+ }
+ // if there are more than two double quotes use
+ // GetShortPathName, the cmd.exe program in windows which
+ // is used by system fails to execute if there are more than
+ // one set of quotes in the arguments
+ if (count > 2) {
+ cmsys::RegularExpression quoted("^\"([^\"]*)\"[ \t](.*)");
+ if (quoted.find(command)) {
+ std::string cmd = quoted.match(1);
+ std::string args = quoted.match(2);
+ if (!cmSystemTools::FileExists(cmd.c_str())) {
+ shortCmd = cmd;
+ } else if (!cmSystemTools::GetShortPath(cmd.c_str(), shortCmd)) {
+ cmSystemTools::Error("GetShortPath failed for ", cmd.c_str());
+ return false;
+ }
+ shortCmd += " ";
+ shortCmd += args;
+
+ command = shortCmd.c_str();
+ } else {
+ cmSystemTools::Error("Could not parse command line with quotes ",
+ command);
+ }
+ }
+ }
+#endif
+
+ // Allocate a process instance.
+ cmsysProcess* cp = cmsysProcess_New();
+ if (!cp) {
+ cmSystemTools::Error("Error allocating process instance.");
+ return false;
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (dir) {
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ }
+ if (cmSystemTools::GetRunCommandHideConsole()) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ }
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
+ const char* cmd[] = { command, 0 };
+ cmsysProcess_SetCommand(cp, cmd);
+#else
+ std::string commandInDir;
+ if (dir) {
+ commandInDir = "cd \"";
+ commandInDir += dir;
+ commandInDir += "\" && ";
+ commandInDir += command;
+ } else {
+ commandInDir = command;
+ }
+#ifndef __VMS
+ commandInDir += " 2>&1";
+#endif
+ command = commandInDir.c_str();
+ if (verbose) {
+ cmSystemTools::Stdout("running ");
+ cmSystemTools::Stdout(command);
+ cmSystemTools::Stdout("\n");
+ }
+ fflush(stdout);
+ fflush(stderr);
+ const char* cmd[] = { "/bin/sh", "-c", command, CM_NULLPTR };
+ cmsysProcess_SetCommand(cp, cmd);
+#endif
+
+ cmsysProcess_Execute(cp);
+
+ // Read the process output.
+ int length;
+ char* data;
+ int p;
+ while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) {
+ if (p == cmsysProcess_Pipe_STDOUT || p == cmsysProcess_Pipe_STDERR) {
+ if (verbose) {
+ cmSystemTools::Stdout(data, length);
+ }
+ output.append(data, length);
+ }
+ }
+
+ // All output has been read. Wait for the process to exit.
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+
+ // Check the result of running the process.
+ std::string msg;
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited:
+ retVal = cmsysProcess_GetExitValue(cp);
+ break;
+ case cmsysProcess_State_Exception:
+ retVal = -1;
+ msg += "\nProcess terminated due to: ";
+ msg += cmsysProcess_GetExceptionString(cp);
+ break;
+ case cmsysProcess_State_Error:
+ retVal = -1;
+ msg += "\nProcess failed because: ";
+ msg += cmsysProcess_GetErrorString(cp);
+ break;
+ case cmsysProcess_State_Expired:
+ retVal = -1;
+ msg += "\nProcess terminated due to timeout.";
+ break;
+ }
+ if (!msg.empty()) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // Old Windows process execution printed this info.
+ msg += "\n\nfor command: ";
+ msg += command;
+ if (dir) {
+ msg += "\nin dir: ";
+ msg += dir;
+ }
+ msg += "\n";
+ if (verbose) {
+ cmSystemTools::Stdout(msg.c_str());
+ }
+ output += msg;
+#else
+ // Old UNIX process execution only put message in output.
+ output += msg;
+#endif
+ }
+
+ // Delete the process instance.
+ cmsysProcess_Delete(cp);
+
+ return true;
+}
diff --git a/Source/cmExecProgramCommand.h b/Source/cmExecProgramCommand.h
new file mode 100644
index 0000000..7cd4f9f
--- /dev/null
+++ b/Source/cmExecProgramCommand.h
@@ -0,0 +1,57 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExecProgramCommand_h
+#define cmExecProgramCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmExecProgramCommand
+ * \brief Command that adds a target to the build system.
+ *
+ * cmExecProgramCommand adds an extra target to the build system.
+ * This is useful when you would like to add special
+ * targets like "install,", "clean," and so on.
+ */
+class cmExecProgramCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmExecProgramCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "exec_program"; }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ cmTypeMacro(cmExecProgramCommand, cmCommand);
+
+private:
+ static bool RunCommand(const char* command, std::string& output, int& retVal,
+ const char* directory = CM_NULLPTR,
+ bool verbose = true);
+};
+
+#endif
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
new file mode 100644
index 0000000..d97b25f
--- /dev/null
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -0,0 +1,337 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmExecuteProcessCommand.h"
+
+#include "cmSystemTools.h"
+
+#include <cmsys/Process.h>
+
+#include <ctype.h> /* isspace */
+
+static bool cmExecuteProcessCommandIsWhitespace(char c)
+{
+ return (isspace((int)c) || c == '\n' || c == '\r');
+}
+
+void cmExecuteProcessCommandFixText(std::vector<char>& output,
+ bool strip_trailing_whitespace);
+void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data,
+ int length);
+
+// cmExecuteProcessCommand
+bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ 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 working_directory;
+ for (size_t i = 0; i < args.size(); ++i) {
+ if (args[i] == "COMMAND") {
+ doing_command = true;
+ command_index = cmds.size();
+ cmds.push_back(std::vector<const char*>());
+ } 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] == "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 (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;
+ }
+ }
+
+ if (!this->Makefile->CanIWriteThisFile(output_file.c_str())) {
+ std::string e = "attempted to output into a file: " + output_file +
+ " into a source directory.";
+ this->SetError(e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ // Check for commands given.
+ if (cmds.empty()) {
+ this->SetError(" called with no COMMAND argument.");
+ return false;
+ }
+ for (unsigned int i = 0; i < cmds.size(); ++i) {
+ if (cmds[i].empty()) {
+ this->SetError(" given COMMAND argument with no value.");
+ return false;
+ } else {
+ // Add the null terminating pointer to the command argument list.
+ cmds[i].push_back(CM_NULLPTR);
+ }
+ }
+
+ // Parse the timeout string.
+ double timeout = -1;
+ if (!timeout_string.empty()) {
+ if (sscanf(timeout_string.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();
+
+ // Set the command sequence.
+ for (unsigned int i = 0; i < cmds.size(); ++i) {
+ cmsysProcess_AddCommand(cp, &*cmds[i].begin());
+ }
+
+ // Set the process working directory.
+ if (!working_directory.empty()) {
+ cmsysProcess_SetWorkingDirectory(cp, working_directory.c_str());
+ }
+
+ // Always hide the process window.
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+
+ // Check the output variables.
+ bool merge_output = false;
+ if (!input_file.empty()) {
+ cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN, input_file.c_str());
+ }
+ if (!output_file.empty()) {
+ cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT,
+ output_file.c_str());
+ }
+ if (!error_file.empty()) {
+ if (error_file == output_file) {
+ merge_output = true;
+ } else {
+ cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR,
+ error_file.c_str());
+ }
+ }
+ if (!output_variable.empty() && output_variable == error_variable) {
+ merge_output = true;
+ }
+ if (merge_output) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1);
+ }
+
+ // Set the timeout if any.
+ if (timeout >= 0) {
+ cmsysProcess_SetTimeout(cp, timeout);
+ }
+
+ // Start the process.
+ cmsysProcess_Execute(cp);
+
+ // Read the process output.
+ std::vector<char> tempOutput;
+ std::vector<char> tempError;
+ int length;
+ char* data;
+ int p;
+ while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) {
+ // Put the output in the right place.
+ if (p == cmsysProcess_Pipe_STDOUT && !output_quiet) {
+ if (output_variable.empty()) {
+ cmSystemTools::Stdout(data, length);
+ } else {
+ cmExecuteProcessCommandAppend(tempOutput, data, length);
+ }
+ } else if (p == cmsysProcess_Pipe_STDERR && !error_quiet) {
+ if (error_variable.empty()) {
+ cmSystemTools::Stderr(data, length);
+ } else {
+ cmExecuteProcessCommandAppend(tempError, data, length);
+ }
+ }
+ }
+
+ // All output has been read. Wait for the process to exit.
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+
+ // Fix the text in the output strings.
+ cmExecuteProcessCommandFixText(tempOutput, output_strip_trailing_whitespace);
+ cmExecuteProcessCommandFixText(tempError, error_strip_trailing_whitespace);
+
+ // Store the output obtained.
+ if (!output_variable.empty() && !tempOutput.empty()) {
+ this->Makefile->AddDefinition(output_variable, &*tempOutput.begin());
+ }
+ if (!merge_output && !error_variable.empty() && !tempError.empty()) {
+ this->Makefile->AddDefinition(error_variable, &*tempError.begin());
+ }
+
+ // Store the result of running the process.
+ if (!result_variable.empty()) {
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited: {
+ int v = cmsysProcess_GetExitValue(cp);
+ char buf[100];
+ sprintf(buf, "%d", v);
+ this->Makefile->AddDefinition(result_variable, buf);
+ } break;
+ case cmsysProcess_State_Exception:
+ this->Makefile->AddDefinition(result_variable,
+ cmsysProcess_GetExceptionString(cp));
+ break;
+ case cmsysProcess_State_Error:
+ this->Makefile->AddDefinition(result_variable,
+ cmsysProcess_GetErrorString(cp));
+ break;
+ case cmsysProcess_State_Expired:
+ this->Makefile->AddDefinition(result_variable,
+ "Process terminated due to timeout");
+ break;
+ }
+ }
+
+ // Delete the process instance.
+ cmsysProcess_Delete(cp);
+
+ return true;
+}
+
+void cmExecuteProcessCommandFixText(std::vector<char>& output,
+ bool strip_trailing_whitespace)
+{
+ // Remove \0 characters and the \r part of \r\n pairs.
+ unsigned int in_index = 0;
+ unsigned int out_index = 0;
+ while (in_index < output.size()) {
+ char c = output[in_index++];
+ if ((c != '\r' ||
+ !(in_index < output.size() && output[in_index] == '\n')) &&
+ c != '\0') {
+ output[out_index++] = c;
+ }
+ }
+
+ // Remove trailing whitespace if requested.
+ if (strip_trailing_whitespace) {
+ while (out_index > 0 &&
+ cmExecuteProcessCommandIsWhitespace(output[out_index - 1])) {
+ --out_index;
+ }
+ }
+
+ // Shrink the vector to the size needed.
+ output.resize(out_index);
+
+ // Put a terminator on the text string.
+ output.push_back('\0');
+}
+
+void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data,
+ int length)
+{
+#if defined(__APPLE__)
+ // HACK on Apple to work around bug with inserting at the
+ // end of an empty vector. This resulted in random failures
+ // that were hard to reproduce.
+ if (output.empty() && length > 0) {
+ output.push_back(data[0]);
+ ++data;
+ --length;
+ }
+#endif
+ output.insert(output.end(), data, data + length);
+}
diff --git a/Source/cmExecuteProcessCommand.h b/Source/cmExecuteProcessCommand.h
new file mode 100644
index 0000000..61687ef
--- /dev/null
+++ b/Source/cmExecuteProcessCommand.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExecuteProcessCommand_h
+#define cmExecuteProcessCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmExecuteProcessCommand
+ * \brief Command that adds a target to the build system.
+ *
+ * cmExecuteProcessCommand is a CMake language interface to the KWSys
+ * Process Execution implementation.
+ */
+class cmExecuteProcessCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmExecuteProcessCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "execute_process"; }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ cmTypeMacro(cmExecuteProcessCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmExecutionStatus.h b/Source/cmExecutionStatus.h
new file mode 100644
index 0000000..508c6bd
--- /dev/null
+++ b/Source/cmExecutionStatus.h
@@ -0,0 +1,53 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExecutionStatus_h
+#define cmExecutionStatus_h
+
+#include "cmStandardIncludes.h"
+
+/** \class cmExecutionStatus
+ * \brief Superclass for all command status classes
+ *
+ * when a command is involked it may set values on a command status instance
+ */
+class cmExecutionStatus
+{
+public:
+ cmExecutionStatus() { this->Clear(); }
+
+ void SetReturnInvoked(bool val) { this->ReturnInvoked = val; }
+ bool GetReturnInvoked() { return this->ReturnInvoked; }
+
+ void SetBreakInvoked(bool val) { this->BreakInvoked = val; }
+ bool GetBreakInvoked() { return this->BreakInvoked; }
+
+ void SetContinueInvoked(bool val) { this->ContinueInvoked = val; }
+ bool GetContinueInvoked() { return this->ContinueInvoked; }
+
+ void Clear()
+ {
+ this->ReturnInvoked = false;
+ this->BreakInvoked = false;
+ this->ContinueInvoked = false;
+ this->NestedError = false;
+ }
+ void SetNestedError(bool val) { this->NestedError = val; }
+ bool GetNestedError() { return this->NestedError; }
+
+private:
+ bool ReturnInvoked;
+ bool BreakInvoked;
+ bool ContinueInvoked;
+ bool NestedError;
+};
+
+#endif
diff --git a/Source/cmExpandedCommandArgument.cxx b/Source/cmExpandedCommandArgument.cxx
new file mode 100644
index 0000000..df7fba1
--- /dev/null
+++ b/Source/cmExpandedCommandArgument.cxx
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmExpandedCommandArgument.h"
+
+cmExpandedCommandArgument::cmExpandedCommandArgument()
+ : Quoted(false)
+{
+}
+
+cmExpandedCommandArgument::cmExpandedCommandArgument(std::string const& value,
+ bool quoted)
+ : Value(value)
+ , Quoted(quoted)
+{
+}
+
+std::string const& cmExpandedCommandArgument::GetValue() const
+{
+ return this->Value;
+}
+
+bool cmExpandedCommandArgument::WasQuoted() const
+{
+ return this->Quoted;
+}
+
+bool cmExpandedCommandArgument::operator==(std::string const& value) const
+{
+ return this->Value == value;
+}
+
+bool cmExpandedCommandArgument::empty() const
+{
+ return this->Value.empty();
+}
+
+const char* cmExpandedCommandArgument::c_str() const
+{
+ return this->Value.c_str();
+}
diff --git a/Source/cmExpandedCommandArgument.h b/Source/cmExpandedCommandArgument.h
new file mode 100644
index 0000000..1f8e405
--- /dev/null
+++ b/Source/cmExpandedCommandArgument.h
@@ -0,0 +1,45 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExpandedCommandArgument_h
+#define cmExpandedCommandArgument_h
+
+#include "cmStandardIncludes.h"
+
+/** \class cmExpandedCommandArgument
+ * \brief Represents an expanded command argument
+ *
+ * cmCommandArgument stores a string representing an expanded
+ * command argument and context information.
+ */
+
+class cmExpandedCommandArgument
+{
+public:
+ cmExpandedCommandArgument();
+ cmExpandedCommandArgument(std::string const& value, bool quoted);
+
+ std::string const& GetValue() const;
+
+ bool WasQuoted() const;
+
+ bool operator==(std::string const& value) const;
+
+ bool empty() const;
+
+ const char* c_str() const;
+
+private:
+ std::string Value;
+ bool Quoted;
+};
+
+#endif
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
new file mode 100644
index 0000000..a53d285
--- /dev/null
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -0,0 +1,296 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmExportBuildFileGenerator.h"
+
+#include "cmExportSet.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmTargetExport.h"
+
+cmExportBuildFileGenerator::cmExportBuildFileGenerator()
+{
+ this->LG = CM_NULLPTR;
+ this->ExportSet = CM_NULLPTR;
+}
+
+void cmExportBuildFileGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LG = lg;
+ if (this->ExportSet) {
+ this->ExportSet->Compute(lg);
+ }
+}
+
+bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
+{
+ {
+ std::string expectedTargets;
+ std::string sep;
+ std::vector<std::string> targets;
+ this->GetTargets(targets);
+ for (std::vector<std::string>::const_iterator tei = targets.begin();
+ tei != targets.end(); ++tei) {
+ cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(*tei);
+ expectedTargets += sep + this->Namespace + te->GetExportName();
+ sep = " ";
+ if (this->ExportedTargets.insert(te).second) {
+ this->Exports.push_back(te);
+ } else {
+ std::ostringstream e;
+ e << "given target \"" << te->GetName() << "\" more than once.";
+ this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
+ cmake::FATAL_ERROR, e.str(),
+ this->LG->GetMakefile()->GetBacktrace());
+ return false;
+ }
+ if (te->GetType() == cmState::INTERFACE_LIBRARY) {
+ this->GenerateRequiredCMakeVersion(os, "3.0.0");
+ }
+ }
+
+ this->GenerateExpectedTargetsCode(os, expectedTargets);
+ }
+
+ std::vector<std::string> missingTargets;
+
+ // Create all the imported targets.
+ for (std::vector<cmGeneratorTarget*>::const_iterator tei =
+ this->Exports.begin();
+ tei != this->Exports.end(); ++tei) {
+ cmGeneratorTarget* gte = *tei;
+ this->GenerateImportTargetCode(os, gte);
+
+ gte->Target->AppendBuildInterfaceIncludes();
+
+ ImportPropertyMap properties;
+
+ this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_SOURCES", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte,
+ properties);
+ const bool newCMP0022Behavior =
+ gte->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
+ gte->GetPolicyStatusCMP0022() != cmPolicies::OLD;
+ if (newCMP0022Behavior) {
+ this->PopulateInterfaceLinkLibrariesProperty(
+ gte, cmGeneratorExpression::BuildInterface, properties,
+ missingTargets);
+ }
+ this->PopulateCompatibleInterfaceProperties(gte, properties);
+
+ this->GenerateInterfaceProperties(gte, os, properties);
+ }
+
+ // Generate import file content for each configuration.
+ for (std::vector<std::string>::const_iterator ci =
+ this->Configurations.begin();
+ ci != this->Configurations.end(); ++ci) {
+ this->GenerateImportConfig(os, *ci, missingTargets);
+ }
+
+ this->GenerateMissingTargetsCheckCode(os, missingTargets);
+
+ return true;
+}
+
+void cmExportBuildFileGenerator::GenerateImportTargetsConfig(
+ std::ostream& os, const std::string& config, std::string const& suffix,
+ std::vector<std::string>& missingTargets)
+{
+ for (std::vector<cmGeneratorTarget*>::const_iterator tei =
+ this->Exports.begin();
+ tei != this->Exports.end(); ++tei) {
+ // Collect import properties for this target.
+ cmGeneratorTarget* target = *tei;
+ ImportPropertyMap properties;
+
+ if (target->GetType() != cmState::INTERFACE_LIBRARY) {
+ this->SetImportLocationProperty(config, suffix, target, properties);
+ }
+ if (!properties.empty()) {
+ // Get the rest of the target details.
+ if (target->GetType() != cmState::INTERFACE_LIBRARY) {
+ this->SetImportDetailProperties(config, suffix, target, properties,
+ missingTargets);
+ this->SetImportLinkInterface(config, suffix,
+ cmGeneratorExpression::BuildInterface,
+ target, properties, missingTargets);
+ }
+
+ // TOOD: PUBLIC_HEADER_LOCATION
+ // This should wait until the build feature propagation stuff
+ // is done. Then this can be a propagated include directory.
+ // this->GenerateImportProperty(config, te->HeaderGenerator,
+ // properties);
+
+ // Generate code in the export file.
+ this->GenerateImportPropertyCode(os, config, target, properties);
+ }
+ }
+}
+
+void cmExportBuildFileGenerator::SetExportSet(cmExportSet* exportSet)
+{
+ this->ExportSet = exportSet;
+}
+
+void cmExportBuildFileGenerator::SetImportLocationProperty(
+ const std::string& config, std::string const& suffix,
+ cmGeneratorTarget* target, ImportPropertyMap& properties)
+{
+ // Get the makefile in which to lookup target information.
+ cmMakefile* mf = target->Makefile;
+
+ // Add the main target file.
+ {
+ std::string prop = "IMPORTED_LOCATION";
+ prop += suffix;
+ std::string value;
+ if (target->IsAppBundleOnApple()) {
+ value = target->GetFullPath(config, false);
+ } else {
+ value = target->GetFullPath(config, false, true);
+ }
+ properties[prop] = value;
+ }
+
+ // Add the import library for windows DLLs.
+ if (target->IsDLLPlatform() &&
+ (target->GetType() == cmState::SHARED_LIBRARY ||
+ target->IsExecutableWithExports()) &&
+ mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
+ std::string prop = "IMPORTED_IMPLIB";
+ prop += suffix;
+ std::string value = target->GetFullPath(config, true);
+ target->GetImplibGNUtoMS(value, value, "${CMAKE_IMPORT_LIBRARY_SUFFIX}");
+ properties[prop] = value;
+ }
+}
+
+void cmExportBuildFileGenerator::HandleMissingTarget(
+ std::string& link_libs, std::vector<std::string>& missingTargets,
+ cmGeneratorTarget* depender, cmGeneratorTarget* dependee)
+{
+ // The target is not in the export.
+ if (!this->AppendMode) {
+ const std::string name = dependee->GetName();
+ cmGlobalGenerator* gg =
+ dependee->GetLocalGenerator()->GetGlobalGenerator();
+ std::vector<std::string> namespaces = this->FindNamespaces(gg, name);
+
+ int targetOccurrences = (int)namespaces.size();
+ if (targetOccurrences == 1) {
+ std::string missingTarget = namespaces[0];
+
+ missingTarget += dependee->GetExportName();
+ link_libs += missingTarget;
+ missingTargets.push_back(missingTarget);
+ return;
+ } else {
+ // We are not appending, so all exported targets should be
+ // known here. This is probably user-error.
+ this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences);
+ }
+ }
+ // Assume the target will be exported by another command.
+ // Append it with the export namespace.
+ link_libs += this->Namespace;
+ link_libs += dependee->GetExportName();
+}
+
+void cmExportBuildFileGenerator::GetTargets(
+ std::vector<std::string>& targets) const
+{
+ if (this->ExportSet) {
+ for (std::vector<cmTargetExport*>::const_iterator tei =
+ this->ExportSet->GetTargetExports()->begin();
+ tei != this->ExportSet->GetTargetExports()->end(); ++tei) {
+ targets.push_back((*tei)->TargetName);
+ }
+ return;
+ }
+ targets = this->Targets;
+}
+
+std::vector<std::string> cmExportBuildFileGenerator::FindNamespaces(
+ cmGlobalGenerator* gg, const std::string& name)
+{
+ std::vector<std::string> namespaces;
+
+ std::map<std::string, cmExportBuildFileGenerator*>& exportSets =
+ gg->GetBuildExportSets();
+
+ for (std::map<std::string, cmExportBuildFileGenerator*>::const_iterator
+ expIt = exportSets.begin();
+ expIt != exportSets.end(); ++expIt) {
+ const cmExportBuildFileGenerator* exportSet = expIt->second;
+ std::vector<std::string> targets;
+ exportSet->GetTargets(targets);
+ if (std::find(targets.begin(), targets.end(), name) != targets.end()) {
+ namespaces.push_back(exportSet->GetNamespace());
+ }
+ }
+
+ return namespaces;
+}
+
+void cmExportBuildFileGenerator::ComplainAboutMissingTarget(
+ cmGeneratorTarget* depender, cmGeneratorTarget* dependee, int occurrences)
+{
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+
+ std::ostringstream e;
+ e << "export called with target \"" << depender->GetName()
+ << "\" which requires target \"" << dependee->GetName() << "\" ";
+ if (occurrences == 0) {
+ e << "that is not in the export set.\n";
+ } else {
+ e << "that is not in this export set, but " << occurrences
+ << " times in others.\n";
+ }
+ e << "If the required target is not easy to reference in this call, "
+ << "consider using the APPEND option with multiple separate calls.";
+
+ this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
+ cmake::FATAL_ERROR, e.str(), this->LG->GetMakefile()->GetBacktrace());
+}
+
+std::string cmExportBuildFileGenerator::InstallNameDir(
+ cmGeneratorTarget* target, const std::string& config)
+{
+ std::string install_name_dir;
+
+ cmMakefile* mf = target->Target->GetMakefile();
+ if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ install_name_dir = target->GetInstallNameDirForBuildTree(config);
+ }
+
+ return install_name_dir;
+}
diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h
new file mode 100644
index 0000000..417e8c9
--- /dev/null
+++ b/Source/cmExportBuildFileGenerator.h
@@ -0,0 +1,84 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExportBuildFileGenerator_h
+#define cmExportBuildFileGenerator_h
+
+#include "cmExportFileGenerator.h"
+#include "cmListFileCache.h"
+
+class cmExportSet;
+
+/** \class cmExportBuildFileGenerator
+ * \brief Generate a file exporting targets from a build tree.
+ *
+ * cmExportBuildFileGenerator generates a file exporting targets from
+ * a build tree. A single file exports information for all
+ * configurations built.
+ *
+ * This is used to implement the EXPORT() command.
+ */
+class cmExportBuildFileGenerator : public cmExportFileGenerator
+{
+public:
+ cmExportBuildFileGenerator();
+
+ /** Set the list of targets to export. */
+ void SetTargets(std::vector<std::string> const& targets)
+ {
+ this->Targets = targets;
+ }
+ 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());
+ }
+ void SetExportSet(cmExportSet*);
+
+ /** Set whether to append generated code to the output file. */
+ void SetAppendMode(bool append) { this->AppendMode = append; }
+
+ void Compute(cmLocalGenerator* lg);
+
+protected:
+ // Implement virtual methods from the superclass.
+ bool GenerateMainFile(std::ostream& os) CM_OVERRIDE;
+ void GenerateImportTargetsConfig(
+ std::ostream& os, const std::string& config, std::string const& suffix,
+ std::vector<std::string>& missingTargets) CM_OVERRIDE;
+ void HandleMissingTarget(std::string& link_libs,
+ std::vector<std::string>& missingTargets,
+ cmGeneratorTarget* depender,
+ cmGeneratorTarget* dependee) CM_OVERRIDE;
+
+ void ComplainAboutMissingTarget(cmGeneratorTarget* depender,
+ cmGeneratorTarget* dependee,
+ int occurrences);
+
+ /** Fill in properties indicating built file locations. */
+ void SetImportLocationProperty(const std::string& config,
+ std::string const& suffix,
+ cmGeneratorTarget* target,
+ ImportPropertyMap& properties);
+
+ std::string InstallNameDir(cmGeneratorTarget* target,
+ const std::string& config) CM_OVERRIDE;
+
+ std::vector<std::string> FindNamespaces(cmGlobalGenerator* gg,
+ const std::string& name);
+
+ std::vector<std::string> Targets;
+ cmExportSet* ExportSet;
+ std::vector<cmGeneratorTarget*> Exports;
+ cmLocalGenerator* LG;
+};
+
+#endif
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
new file mode 100644
index 0000000..3cb575e
--- /dev/null
+++ b/Source/cmExportCommand.cxx
@@ -0,0 +1,357 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmExportCommand.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmake.h"
+
+#include <cmsys/Encoding.hxx>
+#include <cmsys/RegularExpression.hxx>
+
+#include "cmExportBuildFileGenerator.h"
+
+#if defined(__HAIKU__)
+#include <FindDirectory.h>
+#include <StorageDefs.h>
+#endif
+
+cmExportCommand::cmExportCommand()
+ : cmCommand()
+ , ArgumentGroup()
+ , 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)
+{
+ this->ExportSet = CM_NULLPTR;
+}
+
+// cmExportCommand
+bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with too few arguments");
+ return false;
+ }
+
+ if (args[0] == "PACKAGE") {
+ return this->HandlePackage(args);
+ } else if (args[0] == "EXPORT") {
+ this->ExportSetName.Follows(CM_NULLPTR);
+ this->ArgumentGroup.Follows(&this->ExportSetName);
+ } else {
+ this->Targets.Follows(CM_NULLPTR);
+ this->ArgumentGroup.Follows(&this->Targets);
+ }
+
+ std::vector<std::string> unknownArgs;
+ this->Helper.Parse(&args, &unknownArgs);
+
+ if (!unknownArgs.empty()) {
+ this->SetError("Unknown arguments.");
+ return false;
+ }
+
+ std::string fname;
+ if (!this->Filename.WasFound()) {
+ if (args[0] != "EXPORT") {
+ this->SetError("FILE <filename> option missing.");
+ return false;
+ }
+ fname = this->ExportSetName.GetString() + ".cmake";
+ } else {
+ // Make sure the file has a .cmake extension.
+ if (cmSystemTools::GetFilenameLastExtension(this->Filename.GetCString()) !=
+ ".cmake") {
+ std::ostringstream e;
+ e << "FILE option given filename \"" << this->Filename.GetString()
+ << "\" which does not have an extension of \".cmake\".\n";
+ this->SetError(e.str());
+ return false;
+ }
+ fname = this->Filename.GetString();
+ }
+
+ // Get the file to write.
+ if (cmSystemTools::FileIsFullPath(fname.c_str())) {
+ if (!this->Makefile->CanIWriteThisFile(fname.c_str())) {
+ std::ostringstream e;
+ e << "FILE option given filename \"" << fname
+ << "\" which is in the source tree.\n";
+ this->SetError(e.str());
+ return false;
+ }
+ } else {
+ // Interpret relative paths with respect to the current build dir.
+ std::string dir = this->Makefile->GetCurrentBinaryDirectory();
+ fname = dir + "/" + fname;
+ }
+
+ std::vector<std::string> targets;
+
+ cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+
+ 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()) {
+ std::ostringstream e;
+ e << "Export set \"" << setName << "\" not found.";
+ this->SetError(e.str());
+ return false;
+ }
+ this->ExportSet = setMap[setName];
+ } else if (this->Targets.WasFound()) {
+ for (std::vector<std::string>::const_iterator currentTarget =
+ this->Targets.GetVector().begin();
+ currentTarget != this->Targets.GetVector().end(); ++currentTarget) {
+ if (this->Makefile->IsAlias(*currentTarget)) {
+ std::ostringstream e;
+ e << "given ALIAS target \"" << *currentTarget
+ << "\" which may not be exported.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ if (cmTarget* target = gg->FindTarget(*currentTarget)) {
+ if (target->GetType() == cmState::OBJECT_LIBRARY) {
+ std::ostringstream e;
+ e << "given OBJECT library \"" << *currentTarget
+ << "\" which may not be exported.";
+ this->SetError(e.str());
+ return false;
+ }
+ if (target->GetType() == cmState::UTILITY) {
+ this->SetError("given custom target \"" + *currentTarget +
+ "\" which may not be exported.");
+ return false;
+ }
+ } else {
+ std::ostringstream e;
+ e << "given target \"" << *currentTarget
+ << "\" which is not built by this project.";
+ this->SetError(e.str());
+ return false;
+ }
+ targets.push_back(*currentTarget);
+ }
+ if (this->Append.IsEnabled()) {
+ if (cmExportBuildFileGenerator* ebfg =
+ gg->GetExportedTargetsFile(fname)) {
+ ebfg->AppendTargets(targets);
+ return true;
+ }
+ }
+ } else {
+ this->SetError("EXPORT or TARGETS specifier missing.");
+ return false;
+ }
+
+ // Setup export file generation.
+ cmExportBuildFileGenerator* 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);
+ } else {
+ ebfg->SetTargets(targets);
+ }
+ this->Makefile->AddExportBuildFileGenerator(ebfg);
+ ebfg->SetExportOld(this->ExportOld.IsEnabled());
+
+ // Compute the set of configurations exported.
+ std::vector<std::string> configurationTypes;
+ this->Makefile->GetConfigurations(configurationTypes);
+ if (configurationTypes.empty()) {
+ configurationTypes.push_back("");
+ }
+ for (std::vector<std::string>::const_iterator ci =
+ configurationTypes.begin();
+ ci != configurationTypes.end(); ++ci) {
+ ebfg->AddConfiguration(*ci);
+ }
+ if (this->ExportSet) {
+ gg->AddBuildExportExportSet(ebfg);
+ } else {
+ gg->AddBuildExportSet(ebfg);
+ }
+
+ return true;
+}
+
+bool cmExportCommand::HandlePackage(std::vector<std::string> const& args)
+{
+ // Parse PACKAGE mode arguments.
+ enum Doing
+ {
+ DoingNone,
+ DoingPackage
+ };
+ Doing doing = DoingPackage;
+ std::string package;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (doing == DoingPackage) {
+ package = args[i];
+ doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << "PACKAGE given unknown argument: " << args[i];
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ // Verify the package name.
+ if (package.empty()) {
+ this->SetError("PACKAGE must be given a package name.");
+ return false;
+ }
+ const char* packageExpr = "^[A-Za-z0-9_.-]+$";
+ cmsys::RegularExpression packageRegex(packageExpr);
+ if (!packageRegex.find(package.c_str())) {
+ std::ostringstream e;
+ e << "PACKAGE given invalid package name \"" << package << "\". "
+ << "Package names must match \"" << packageExpr << "\".";
+ this->SetError(e.str());
+ 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;
+ }
+
+ // We store the current build directory in the registry as a value
+ // named by a hash of its own content. This is deterministic and is
+ // unique with high probability.
+ const char* outDir = this->Makefile->GetCurrentBinaryDirectory();
+ std::string hash = cmSystemTools::ComputeStringMD5(outDir);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ this->StorePackageRegistryWin(package, outDir, hash.c_str());
+#else
+ this->StorePackageRegistryDir(package, outDir, hash.c_str());
+#endif
+
+ return true;
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <windows.h>
+#undef GetCurrentDirectory
+void cmExportCommand::ReportRegistryError(std::string const& msg,
+ std::string const& key, long err)
+{
+ std::ostringstream e;
+ e << msg << "\n"
+ << " HKEY_CURRENT_USER\\" << key << "\n";
+ wchar_t winmsg[1024];
+ if (FormatMessageW(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), winmsg, 1024, 0) > 0) {
+ e << "Windows reported:\n"
+ << " " << cmsys::Encoding::ToNarrow(winmsg);
+ }
+ this->Makefile->IssueMessage(cmake::WARNING, e.str());
+}
+
+void cmExportCommand::StorePackageRegistryWin(std::string const& package,
+ const char* content,
+ const char* hash)
+{
+ std::string key = "Software\\Kitware\\CMake\\Packages\\";
+ key += package;
+ HKEY hKey;
+ LONG err =
+ RegCreateKeyExW(HKEY_CURRENT_USER, cmsys::Encoding::ToWide(key).c_str(), 0,
+ 0, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, 0, &hKey, 0);
+ if (err != ERROR_SUCCESS) {
+ this->ReportRegistryError("Cannot create/open registry key", key, err);
+ return;
+ }
+
+ std::wstring wcontent = cmsys::Encoding::ToWide(content);
+ err =
+ RegSetValueExW(hKey, cmsys::Encoding::ToWide(hash).c_str(), 0, REG_SZ,
+ (BYTE const*)wcontent.c_str(),
+ static_cast<DWORD>(wcontent.size() + 1) * sizeof(wchar_t));
+ RegCloseKey(hKey);
+ if (err != ERROR_SUCCESS) {
+ std::ostringstream msg;
+ msg << "Cannot set registry value \"" << hash << "\" under key";
+ this->ReportRegistryError(msg.str(), key, err);
+ return;
+ }
+}
+#else
+void cmExportCommand::StorePackageRegistryDir(std::string const& package,
+ const char* content,
+ const char* hash)
+{
+#if defined(__HAIKU__)
+ char dir[B_PATH_NAME_LENGTH];
+ if (find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, dir, sizeof(dir)) !=
+ B_OK) {
+ return;
+ }
+ std::string fname = dir;
+ fname += "/cmake/packages/";
+ fname += package;
+#else
+ const char* home = cmSystemTools::GetEnv("HOME");
+ if (!home) {
+ return;
+ }
+ std::string fname = home;
+ cmSystemTools::ConvertToUnixSlashes(fname);
+ fname += "/.cmake/packages/";
+ fname += package;
+#endif
+ cmSystemTools::MakeDirectory(fname.c_str());
+ fname += "/";
+ fname += hash;
+ if (!cmSystemTools::FileExists(fname.c_str())) {
+ cmGeneratedFileStream entry(fname.c_str(), true);
+ if (entry) {
+ entry << content << "\n";
+ } else {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "Cannot create package registry file:\n"
+ << " " << fname << "\n"
+ << cmSystemTools::GetLastSystemError() << "\n";
+ /* clang-format on */
+ this->Makefile->IssueMessage(cmake::WARNING, e.str());
+ }
+ }
+}
+#endif
diff --git a/Source/cmExportCommand.h b/Source/cmExportCommand.h
new file mode 100644
index 0000000..0a149af
--- /dev/null
+++ b/Source/cmExportCommand.h
@@ -0,0 +1,72 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExportCommand_h
+#define cmExportCommand_h
+
+#include "cmCommand.h"
+
+class cmExportBuildFileGenerator;
+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.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmExportCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "export"; }
+
+ cmTypeMacro(cmExportCommand, cmCommand);
+
+private:
+ cmCommandArgumentGroup ArgumentGroup;
+ cmCAStringVector Targets;
+ cmCAEnabler Append;
+ cmCAString ExportSetName;
+ cmCAString Namespace;
+ cmCAString Filename;
+ cmCAEnabler ExportOld;
+
+ 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);
+ void StorePackageRegistryDir(std::string const& package, const char* content,
+ const char* hash);
+ void ReportRegistryError(std::string const& msg, std::string const& key,
+ long err);
+};
+
+#endif
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
new file mode 100644
index 0000000..d93e406
--- /dev/null
+++ b/Source/cmExportFileGenerator.cxx
@@ -0,0 +1,1091 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmExportFileGenerator.h"
+
+#include "cmAlgorithms.h"
+#include "cmComputeLinkInformation.h"
+#include "cmExportSet.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallExportGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmSystemTools.h"
+#include "cmTargetExport.h"
+#include "cmVersion.h"
+
+#include <assert.h>
+#include <cm_auto_ptr.hxx>
+#include <cmsys/FStream.hxx>
+
+static std::string cmExportFileGeneratorEscape(std::string const& str)
+{
+ // Escape a property value for writing into a .cmake file.
+ std::string result = cmOutputConverter::EscapeForCMake(str);
+ // Un-escape variable references generated by our own export code.
+ cmSystemTools::ReplaceString(result, "\\${_IMPORT_PREFIX}",
+ "${_IMPORT_PREFIX}");
+ cmSystemTools::ReplaceString(result, "\\${CMAKE_IMPORT_LIBRARY_SUFFIX}",
+ "${CMAKE_IMPORT_LIBRARY_SUFFIX}");
+ return result;
+}
+
+cmExportFileGenerator::cmExportFileGenerator()
+{
+ this->AppendMode = false;
+ this->ExportOld = false;
+}
+
+void cmExportFileGenerator::AddConfiguration(const std::string& config)
+{
+ this->Configurations.push_back(config);
+}
+
+void cmExportFileGenerator::SetExportFile(const char* mainFile)
+{
+ this->MainImportFile = mainFile;
+ this->FileDir = cmSystemTools::GetFilenamePath(this->MainImportFile);
+ this->FileBase =
+ cmSystemTools::GetFilenameWithoutLastExtension(this->MainImportFile);
+ this->FileExt =
+ cmSystemTools::GetFilenameLastExtension(this->MainImportFile);
+}
+
+const char* cmExportFileGenerator::GetMainExportFileName() const
+{
+ return this->MainImportFile.c_str();
+}
+
+bool cmExportFileGenerator::GenerateImportFile()
+{
+ // Open the output file to generate it.
+ CM_AUTO_PTR<cmsys::ofstream> foutPtr;
+ if (this->AppendMode) {
+ // Open for append.
+ CM_AUTO_PTR<cmsys::ofstream> ap(
+ new cmsys::ofstream(this->MainImportFile.c_str(), std::ios::app));
+ foutPtr = ap;
+ } else {
+ // Generate atomically and with copy-if-different.
+ CM_AUTO_PTR<cmGeneratedFileStream> ap(
+ new cmGeneratedFileStream(this->MainImportFile.c_str(), true));
+ ap->SetCopyIfDifferent(true);
+ foutPtr = ap;
+ }
+ if (!foutPtr.get() || !*foutPtr) {
+ std::string se = cmSystemTools::GetLastSystemError();
+ std::ostringstream e;
+ e << "cannot write to file \"" << this->MainImportFile << "\": " << se;
+ cmSystemTools::Error(e.str().c_str());
+ return false;
+ }
+ std::ostream& os = *foutPtr;
+
+ // Protect that file against use with older CMake versions.
+ /* clang-format off */
+ os << "# Generated by CMake " << cmVersion::GetCMakeVersion() << "\n\n";
+ os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.5)\n"
+ << " message(FATAL_ERROR \"CMake >= 2.6.0 required\")\n"
+ << "endif()\n";
+ /* clang-format on */
+
+ // Isolate the file policy level.
+ // We use 2.6 here instead of the current version because newer
+ // versions of CMake should be able to export files imported by 2.6
+ // until the import format changes.
+ /* clang-format off */
+ os << "cmake_policy(PUSH)\n"
+ << "cmake_policy(VERSION 2.6)\n";
+ /* clang-format on */
+
+ // Start with the import file header.
+ this->GenerateImportHeaderCode(os);
+
+ // Create all the imported targets.
+ bool result = this->GenerateMainFile(os);
+
+ // End with the import file footer.
+ this->GenerateImportFooterCode(os);
+ os << "cmake_policy(POP)\n";
+
+ return result;
+}
+
+void cmExportFileGenerator::GenerateImportConfig(
+ std::ostream& os, const std::string& config,
+ std::vector<std::string>& missingTargets)
+{
+ // Construct the property configuration suffix.
+ std::string suffix = "_";
+ if (!config.empty()) {
+ suffix += cmSystemTools::UpperCase(config);
+ } else {
+ suffix += "NOCONFIG";
+ }
+
+ // Generate the per-config target information.
+ this->GenerateImportTargetsConfig(os, config, suffix, missingTargets);
+}
+
+void cmExportFileGenerator::PopulateInterfaceProperty(
+ const std::string& propName, cmGeneratorTarget* target,
+ ImportPropertyMap& properties)
+{
+ const char* input = target->GetProperty(propName);
+ if (input) {
+ properties[propName] = input;
+ }
+}
+
+void cmExportFileGenerator::PopulateInterfaceProperty(
+ const std::string& propName, const std::string& outputName,
+ cmGeneratorTarget* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ const char* input = target->GetProperty(propName);
+ if (input) {
+ if (!*input) {
+ // Set to empty
+ properties[outputName] = "";
+ return;
+ }
+
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(input, preprocessRule);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(prepro, target,
+ missingTargets);
+ properties[outputName] = prepro;
+ }
+ }
+}
+
+void cmExportFileGenerator::GenerateRequiredCMakeVersion(
+ std::ostream& os, const char* versionString)
+{
+ /* clang-format off */
+ os << "if(CMAKE_VERSION VERSION_LESS " << versionString << ")\n"
+ " message(FATAL_ERROR \"This file relies on consumers using "
+ "CMake " << versionString << " or greater.\")\n"
+ "endif()\n\n";
+ /* clang-format on */
+}
+
+bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty(
+ cmGeneratorTarget* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ if (!target->IsLinkable()) {
+ return false;
+ }
+ const char* input = target->GetProperty("INTERFACE_LINK_LIBRARIES");
+ if (input) {
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(input, preprocessRule);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(
+ prepro, target, missingTargets, ReplaceFreeTargets);
+ properties["INTERFACE_LINK_LIBRARIES"] = prepro;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool isSubDirectory(const char* a, const char* b)
+{
+ return (cmSystemTools::ComparePath(a, b) ||
+ cmSystemTools::IsSubDirectory(a, b));
+}
+
+static bool checkInterfaceDirs(const std::string& prepro,
+ cmGeneratorTarget* target,
+ const std::string& prop)
+{
+ const char* installDir =
+ target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
+ const char* topSourceDir = target->GetLocalGenerator()->GetSourceDirectory();
+ const char* topBinaryDir = target->GetLocalGenerator()->GetBinaryDirectory();
+
+ std::vector<std::string> parts;
+ cmGeneratorExpression::Split(prepro, parts);
+
+ const bool inSourceBuild = strcmp(topSourceDir, topBinaryDir) == 0;
+
+ bool hadFatalError = false;
+
+ for (std::vector<std::string>::iterator li = parts.begin();
+ li != parts.end(); ++li) {
+ size_t genexPos = cmGeneratorExpression::Find(*li);
+ if (genexPos == 0) {
+ continue;
+ }
+ cmake::MessageType messageType = cmake::FATAL_ERROR;
+ std::ostringstream e;
+ if (genexPos != std::string::npos) {
+ if (prop == "INTERFACE_INCLUDE_DIRECTORIES") {
+ switch (target->GetPolicyStatusCMP0041()) {
+ case cmPolicies::WARN:
+ messageType = cmake::WARNING;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0041) << "\n";
+ break;
+ case cmPolicies::OLD:
+ continue;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ hadFatalError = true;
+ break; // Issue fatal message.
+ }
+ } else {
+ hadFatalError = true;
+ }
+ }
+ if (cmHasLiteralPrefix(li->c_str(), "${_IMPORT_PREFIX}")) {
+ continue;
+ }
+ if (!cmSystemTools::FileIsFullPath(li->c_str())) {
+ /* clang-format off */
+ e << "Target \"" << target->GetName() << "\" " << prop <<
+ " property contains relative path:\n"
+ " \"" << *li << "\"";
+ /* clang-format on */
+ target->GetLocalGenerator()->IssueMessage(messageType, e.str());
+ }
+ bool inBinary = isSubDirectory(li->c_str(), topBinaryDir);
+ bool inSource = isSubDirectory(li->c_str(), topSourceDir);
+ if (isSubDirectory(li->c_str(), installDir)) {
+ // The include directory is inside the install tree. If the
+ // install tree is not inside the source tree or build tree then
+ // fall through to the checks below that the include directory is not
+ // also inside the source tree or build tree.
+ bool shouldContinue =
+ (!inBinary || isSubDirectory(installDir, topBinaryDir)) &&
+ (!inSource || isSubDirectory(installDir, topSourceDir));
+
+ if (prop == "INTERFACE_INCLUDE_DIRECTORIES") {
+ if (!shouldContinue) {
+ switch (target->GetPolicyStatusCMP0052()) {
+ case cmPolicies::WARN: {
+ std::ostringstream s;
+ s << cmPolicies::GetPolicyWarning(cmPolicies::CMP0052) << "\n";
+ s << "Directory:\n \"" << *li
+ << "\"\nin "
+ "INTERFACE_INCLUDE_DIRECTORIES of target \""
+ << target->GetName() << "\" is a subdirectory of the install "
+ "directory:\n \""
+ << installDir << "\"\nhowever it is also "
+ "a subdirectory of the "
+ << (inBinary ? "build" : "source") << " tree:\n \""
+ << (inBinary ? topBinaryDir : topSourceDir) << "\""
+ << std::endl;
+ target->GetLocalGenerator()->IssueMessage(cmake::AUTHOR_WARNING,
+ s.str());
+ }
+ case cmPolicies::OLD:
+ shouldContinue = true;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ break;
+ }
+ }
+ }
+ if (shouldContinue) {
+ continue;
+ }
+ }
+ if (inBinary) {
+ /* clang-format off */
+ e << "Target \"" << target->GetName() << "\" " << prop <<
+ " property contains path:\n"
+ " \"" << *li << "\"\nwhich is prefixed in the build directory.";
+ /* clang-format on */
+ target->GetLocalGenerator()->IssueMessage(messageType, e.str());
+ }
+ if (!inSourceBuild) {
+ if (inSource) {
+ e << "Target \"" << target->GetName() << "\" " << prop
+ << " property contains path:\n"
+ " \""
+ << *li << "\"\nwhich is prefixed in the source directory.";
+ target->GetLocalGenerator()->IssueMessage(messageType, e.str());
+ }
+ }
+ }
+ return !hadFatalError;
+}
+
+static void prefixItems(std::string& exportDirs)
+{
+ std::vector<std::string> entries;
+ cmGeneratorExpression::Split(exportDirs, entries);
+ exportDirs = "";
+ const char* sep = "";
+ for (std::vector<std::string>::const_iterator ei = entries.begin();
+ ei != entries.end(); ++ei) {
+ exportDirs += sep;
+ sep = ";";
+ if (!cmSystemTools::FileIsFullPath(ei->c_str()) &&
+ ei->find("${_IMPORT_PREFIX}") == std::string::npos) {
+ exportDirs += "${_IMPORT_PREFIX}/";
+ }
+ exportDirs += *ei;
+ }
+}
+
+void cmExportFileGenerator::PopulateSourcesInterface(
+ cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ cmGeneratorTarget* gt = tei->Target;
+ assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+ const char* propName = "INTERFACE_SOURCES";
+ const char* input = gt->GetProperty(propName);
+
+ if (!input) {
+ return;
+ }
+
+ if (!*input) {
+ properties[propName] = "";
+ return;
+ }
+
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(input, preprocessRule, true);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets);
+
+ if (!checkInterfaceDirs(prepro, gt, propName)) {
+ return;
+ }
+ properties[propName] = prepro;
+ }
+}
+
+void cmExportFileGenerator::PopulateIncludeDirectoriesInterface(
+ cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ cmGeneratorTarget* target = tei->Target;
+ assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+ const char* propName = "INTERFACE_INCLUDE_DIRECTORIES";
+ const char* input = target->GetProperty(propName);
+
+ cmGeneratorExpression ge;
+
+ std::string dirs = cmGeneratorExpression::Preprocess(
+ tei->InterfaceIncludeDirectories, preprocessRule, true);
+ this->ReplaceInstallPrefix(dirs);
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(dirs);
+ std::string exportDirs =
+ cge->Evaluate(target->GetLocalGenerator(), "", false, target);
+
+ if (cge->GetHadContextSensitiveCondition()) {
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ std::ostringstream e;
+ e << "Target \"" << target->GetName()
+ << "\" is installed with "
+ "INCLUDES DESTINATION set to a context sensitive path. Paths which "
+ "depend on the configuration, policy values or the link interface "
+ "are "
+ "not supported. Consider using target_include_directories instead.";
+ lg->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+
+ if (!input && exportDirs.empty()) {
+ return;
+ }
+ if ((input && !*input) && exportDirs.empty()) {
+ // Set to empty
+ properties[propName] = "";
+ return;
+ }
+
+ prefixItems(exportDirs);
+
+ std::string includes = (input ? input : "");
+ const char* sep = input ? ";" : "";
+ includes += sep + exportDirs;
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(includes, preprocessRule, true);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(prepro, target, missingTargets);
+
+ if (!checkInterfaceDirs(prepro, target, propName)) {
+ return;
+ }
+ properties[propName] = prepro;
+ }
+}
+
+void cmExportFileGenerator::PopulateInterfaceProperty(
+ const std::string& propName, cmGeneratorTarget* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ this->PopulateInterfaceProperty(propName, propName, target, preprocessRule,
+ properties, missingTargets);
+}
+
+void getPropertyContents(cmGeneratorTarget const* tgt, const std::string& prop,
+ std::set<std::string>& ifaceProperties)
+{
+ const char* p = tgt->GetProperty(prop);
+ if (!p) {
+ return;
+ }
+ std::vector<std::string> content;
+ cmSystemTools::ExpandListArgument(p, content);
+ ifaceProperties.insert(content.begin(), content.end());
+}
+
+void getCompatibleInterfaceProperties(cmGeneratorTarget* target,
+ std::set<std::string>& ifaceProperties,
+ const std::string& config)
+{
+ cmComputeLinkInformation* info = target->GetLinkInformation(config);
+
+ if (!info) {
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ std::ostringstream e;
+ e << "Exporting the target \"" << target->GetName()
+ << "\" is not "
+ "allowed since its linker language cannot be determined";
+ lg->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+
+ const cmComputeLinkInformation::ItemVector& deps = info->GetItems();
+
+ for (cmComputeLinkInformation::ItemVector::const_iterator li = deps.begin();
+ li != deps.end(); ++li) {
+ if (!li->Target) {
+ continue;
+ }
+ getPropertyContents(li->Target, "COMPATIBLE_INTERFACE_BOOL",
+ ifaceProperties);
+ getPropertyContents(li->Target, "COMPATIBLE_INTERFACE_STRING",
+ ifaceProperties);
+ getPropertyContents(li->Target, "COMPATIBLE_INTERFACE_NUMBER_MIN",
+ ifaceProperties);
+ getPropertyContents(li->Target, "COMPATIBLE_INTERFACE_NUMBER_MAX",
+ ifaceProperties);
+ }
+}
+
+void cmExportFileGenerator::PopulateCompatibleInterfaceProperties(
+ cmGeneratorTarget* gtarget, ImportPropertyMap& properties)
+{
+ this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_BOOL", gtarget,
+ properties);
+ this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_STRING", gtarget,
+ properties);
+ this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_NUMBER_MIN", gtarget,
+ properties);
+ this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_NUMBER_MAX", gtarget,
+ properties);
+
+ std::set<std::string> ifaceProperties;
+
+ getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_BOOL", ifaceProperties);
+ getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_STRING", ifaceProperties);
+ getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_NUMBER_MIN",
+ ifaceProperties);
+ getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_NUMBER_MAX",
+ ifaceProperties);
+
+ if (gtarget->GetType() != cmState::INTERFACE_LIBRARY) {
+ getCompatibleInterfaceProperties(gtarget, ifaceProperties, "");
+
+ std::vector<std::string> configNames;
+ gtarget->Target->GetMakefile()->GetConfigurations(configNames);
+
+ for (std::vector<std::string>::const_iterator ci = configNames.begin();
+ ci != configNames.end(); ++ci) {
+ getCompatibleInterfaceProperties(gtarget, ifaceProperties, *ci);
+ }
+ }
+
+ for (std::set<std::string>::const_iterator it = ifaceProperties.begin();
+ it != ifaceProperties.end(); ++it) {
+ this->PopulateInterfaceProperty("INTERFACE_" + *it, gtarget, properties);
+ }
+}
+
+void cmExportFileGenerator::GenerateInterfaceProperties(
+ const cmGeneratorTarget* target, std::ostream& os,
+ const ImportPropertyMap& properties)
+{
+ if (!properties.empty()) {
+ std::string targetName = this->Namespace;
+ targetName += target->GetExportName();
+ os << "set_target_properties(" << targetName << " PROPERTIES\n";
+ for (ImportPropertyMap::const_iterator pi = properties.begin();
+ pi != properties.end(); ++pi) {
+ os << " " << pi->first << " " << cmExportFileGeneratorEscape(pi->second)
+ << "\n";
+ }
+ os << ")\n\n";
+ }
+}
+
+bool cmExportFileGenerator::AddTargetNamespace(
+ std::string& input, cmGeneratorTarget* target,
+ std::vector<std::string>& missingTargets)
+{
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+
+ cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(input);
+ if (!tgt) {
+ return false;
+ }
+
+ if (tgt->IsImported()) {
+ return true;
+ }
+ if (this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) {
+ input = this->Namespace + tgt->GetExportName();
+ } else {
+ std::string namespacedTarget;
+ this->HandleMissingTarget(namespacedTarget, missingTargets, target, tgt);
+ if (!namespacedTarget.empty()) {
+ input = namespacedTarget;
+ }
+ }
+ return true;
+}
+
+void cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
+ std::string& input, cmGeneratorTarget* target,
+ std::vector<std::string>& missingTargets, FreeTargetsReplace replace)
+{
+ if (replace == NoReplaceFreeTargets) {
+ this->ResolveTargetsInGeneratorExpression(input, target, missingTargets);
+ return;
+ }
+ std::vector<std::string> parts;
+ cmGeneratorExpression::Split(input, parts);
+
+ std::string sep;
+ input = "";
+ for (std::vector<std::string>::iterator li = parts.begin();
+ li != parts.end(); ++li) {
+ if (cmGeneratorExpression::Find(*li) == std::string::npos) {
+ this->AddTargetNamespace(*li, target, missingTargets);
+ } else {
+ this->ResolveTargetsInGeneratorExpression(*li, target, missingTargets);
+ }
+ input += sep + *li;
+ sep = ";";
+ }
+}
+
+void cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
+ std::string& input, cmGeneratorTarget* target,
+ std::vector<std::string>& missingTargets)
+{
+ std::string::size_type pos = 0;
+ std::string::size_type lastPos = pos;
+
+ while ((pos = input.find("$<TARGET_PROPERTY:", lastPos)) != input.npos) {
+ std::string::size_type nameStartPos =
+ pos + sizeof("$<TARGET_PROPERTY:") - 1;
+ std::string::size_type closePos = input.find('>', nameStartPos);
+ std::string::size_type commaPos = input.find(',', nameStartPos);
+ std::string::size_type nextOpenPos = input.find("$<", nameStartPos);
+ if (commaPos == input.npos // Implied 'this' target
+ || closePos == input.npos // Imcomplete expression.
+ || closePos < commaPos // Implied 'this' target
+ || nextOpenPos < commaPos) // Non-literal
+ {
+ lastPos = nameStartPos;
+ continue;
+ }
+
+ std::string targetName =
+ input.substr(nameStartPos, commaPos - nameStartPos);
+
+ if (this->AddTargetNamespace(targetName, target, missingTargets)) {
+ input.replace(nameStartPos, commaPos - nameStartPos, targetName);
+ }
+ lastPos = nameStartPos + targetName.size() + 1;
+ }
+
+ std::string errorString;
+ pos = 0;
+ lastPos = pos;
+ while ((pos = input.find("$<TARGET_NAME:", lastPos)) != input.npos) {
+ std::string::size_type nameStartPos = pos + sizeof("$<TARGET_NAME:") - 1;
+ std::string::size_type endPos = input.find('>', nameStartPos);
+ if (endPos == input.npos) {
+ errorString = "$<TARGET_NAME:...> expression incomplete";
+ break;
+ }
+ std::string targetName = input.substr(nameStartPos, endPos - nameStartPos);
+ if (targetName.find("$<") != input.npos) {
+ errorString = "$<TARGET_NAME:...> requires its parameter to be a "
+ "literal.";
+ break;
+ }
+ if (!this->AddTargetNamespace(targetName, target, missingTargets)) {
+ errorString = "$<TARGET_NAME:...> requires its parameter to be a "
+ "reachable target.";
+ break;
+ }
+ input.replace(pos, endPos - pos + 1, targetName);
+ lastPos = endPos;
+ }
+
+ pos = 0;
+ lastPos = pos;
+ while (errorString.empty() &&
+ (pos = input.find("$<LINK_ONLY:", lastPos)) != input.npos) {
+ std::string::size_type nameStartPos = pos + sizeof("$<LINK_ONLY:") - 1;
+ std::string::size_type endPos = input.find('>', nameStartPos);
+ if (endPos == input.npos) {
+ errorString = "$<LINK_ONLY:...> expression incomplete";
+ break;
+ }
+ std::string libName = input.substr(nameStartPos, endPos - nameStartPos);
+ if (cmGeneratorExpression::IsValidTargetName(libName) &&
+ this->AddTargetNamespace(libName, target, missingTargets)) {
+ input.replace(nameStartPos, endPos - nameStartPos, libName);
+ }
+ lastPos = nameStartPos + libName.size() + 1;
+ }
+
+ this->ReplaceInstallPrefix(input);
+
+ if (!errorString.empty()) {
+ target->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, errorString);
+ }
+}
+
+void cmExportFileGenerator::ReplaceInstallPrefix(std::string&)
+{
+ // Do nothing
+}
+
+void cmExportFileGenerator::SetImportLinkInterface(
+ const std::string& config, std::string const& suffix,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ cmGeneratorTarget* target, ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets)
+{
+ // Add the transitive link dependencies for this configuration.
+ cmLinkInterface const* iface = target->GetLinkInterface(config, target);
+ if (!iface) {
+ return;
+ }
+
+ if (iface->ImplementationIsInterface) {
+ // Policy CMP0022 must not be NEW.
+ this->SetImportLinkProperty(suffix, target,
+ "IMPORTED_LINK_INTERFACE_LIBRARIES",
+ iface->Libraries, properties, missingTargets);
+ return;
+ }
+
+ const char* propContent;
+
+ if (const char* prop_suffixed =
+ target->GetProperty("LINK_INTERFACE_LIBRARIES" + suffix)) {
+ propContent = prop_suffixed;
+ } else if (const char* prop =
+ target->GetProperty("LINK_INTERFACE_LIBRARIES")) {
+ propContent = prop;
+ } else {
+ return;
+ }
+
+ const bool newCMP0022Behavior =
+ target->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
+ target->GetPolicyStatusCMP0022() != cmPolicies::OLD;
+
+ if (newCMP0022Behavior && !this->ExportOld) {
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ std::ostringstream e;
+ e << "Target \"" << target->GetName()
+ << "\" has policy CMP0022 enabled, "
+ "but also has old-style LINK_INTERFACE_LIBRARIES properties "
+ "populated, but it was exported without the "
+ "EXPORT_LINK_INTERFACE_LIBRARIES to export the old-style properties";
+ lg->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+
+ if (!*propContent) {
+ properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = "";
+ return;
+ }
+
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(propContent, preprocessRule);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(prepro, target, missingTargets,
+ ReplaceFreeTargets);
+ properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro;
+ }
+}
+
+void cmExportFileGenerator::SetImportDetailProperties(
+ const std::string& config, std::string const& suffix,
+ cmGeneratorTarget* target, ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets)
+{
+ // Get the makefile in which to lookup target information.
+ cmMakefile* mf = target->Makefile;
+
+ // Add the soname for unix shared libraries.
+ if (target->GetType() == cmState::SHARED_LIBRARY ||
+ target->GetType() == cmState::MODULE_LIBRARY) {
+ if (!target->IsDLLPlatform()) {
+ std::string prop;
+ std::string value;
+ if (target->HasSOName(config)) {
+ if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ value = this->InstallNameDir(target, config);
+ }
+ prop = "IMPORTED_SONAME";
+ value += target->GetSOName(config);
+ } else {
+ prop = "IMPORTED_NO_SONAME";
+ value = "TRUE";
+ }
+ prop += suffix;
+ properties[prop] = value;
+ }
+ }
+
+ // Add the transitive link dependencies for this configuration.
+ if (cmLinkInterface const* iface =
+ target->GetLinkInterface(config, target)) {
+ this->SetImportLinkProperty(suffix, target,
+ "IMPORTED_LINK_INTERFACE_LANGUAGES",
+ iface->Languages, properties, missingTargets);
+
+ std::vector<std::string> dummy;
+ this->SetImportLinkProperty(suffix, target,
+ "IMPORTED_LINK_DEPENDENT_LIBRARIES",
+ iface->SharedDeps, properties, dummy);
+ if (iface->Multiplicity > 0) {
+ std::string prop = "IMPORTED_LINK_INTERFACE_MULTIPLICITY";
+ prop += suffix;
+ std::ostringstream m;
+ m << iface->Multiplicity;
+ properties[prop] = m.str();
+ }
+ }
+}
+
+template <typename T>
+void cmExportFileGenerator::SetImportLinkProperty(
+ std::string const& suffix, cmGeneratorTarget* target,
+ const std::string& propName, std::vector<T> const& entries,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ // Skip the property if there are no entries.
+ if (entries.empty()) {
+ return;
+ }
+
+ // Construct the property value.
+ std::string link_entries;
+ const char* sep = "";
+ for (typename std::vector<T>::const_iterator li = entries.begin();
+ li != entries.end(); ++li) {
+ // Separate this from the previous entry.
+ link_entries += sep;
+ sep = ";";
+
+ std::string temp = *li;
+ this->AddTargetNamespace(temp, target, missingTargets);
+ link_entries += temp;
+ }
+
+ // Store the property.
+ std::string prop = propName;
+ prop += suffix;
+ properties[prop] = link_entries;
+}
+
+void cmExportFileGenerator::GenerateImportHeaderCode(std::ostream& os,
+ const std::string& config)
+{
+ os << "#----------------------------------------------------------------\n"
+ << "# Generated CMake target import file";
+ if (!config.empty()) {
+ os << " for configuration \"" << config << "\".\n";
+ } else {
+ os << ".\n";
+ }
+ os << "#----------------------------------------------------------------\n"
+ << "\n";
+ this->GenerateImportVersionCode(os);
+}
+
+void cmExportFileGenerator::GenerateImportFooterCode(std::ostream& os)
+{
+ os << "# Commands beyond this point should not need to know the version.\n"
+ << "set(CMAKE_IMPORT_FILE_VERSION)\n";
+}
+
+void cmExportFileGenerator::GenerateImportVersionCode(std::ostream& os)
+{
+ // Store an import file format version. This will let us change the
+ // format later while still allowing old import files to work.
+ /* clang-format off */
+ os << "# Commands may need to know the format version.\n"
+ << "set(CMAKE_IMPORT_FILE_VERSION 1)\n"
+ << "\n";
+ /* clang-format on */
+}
+
+void cmExportFileGenerator::GenerateExpectedTargetsCode(
+ std::ostream& os, const std::string& expectedTargets)
+{
+ /* clang-format off */
+ os << "# Protect against multiple inclusion, which would fail when already "
+ "imported targets are added once more.\n"
+ "set(_targetsDefined)\n"
+ "set(_targetsNotDefined)\n"
+ "set(_expectedTargets)\n"
+ "foreach(_expectedTarget " << expectedTargets << ")\n"
+ " list(APPEND _expectedTargets ${_expectedTarget})\n"
+ " if(NOT TARGET ${_expectedTarget})\n"
+ " list(APPEND _targetsNotDefined ${_expectedTarget})\n"
+ " endif()\n"
+ " if(TARGET ${_expectedTarget})\n"
+ " list(APPEND _targetsDefined ${_expectedTarget})\n"
+ " endif()\n"
+ "endforeach()\n"
+ "if(\"${_targetsDefined}\" STREQUAL \"${_expectedTargets}\")\n"
+ " unset(_targetsDefined)\n"
+ " unset(_targetsNotDefined)\n"
+ " unset(_expectedTargets)\n"
+ " set(CMAKE_IMPORT_FILE_VERSION)\n"
+ " cmake_policy(POP)\n"
+ " return()\n"
+ "endif()\n"
+ "if(NOT \"${_targetsDefined}\" STREQUAL \"\")\n"
+ " message(FATAL_ERROR \"Some (but not all) targets in this export "
+ "set were already defined.\\nTargets Defined: ${_targetsDefined}\\n"
+ "Targets not yet defined: ${_targetsNotDefined}\\n\")\n"
+ "endif()\n"
+ "unset(_targetsDefined)\n"
+ "unset(_targetsNotDefined)\n"
+ "unset(_expectedTargets)\n"
+ "\n\n";
+ /* clang-format on */
+}
+void cmExportFileGenerator::GenerateImportTargetCode(
+ std::ostream& os, const cmGeneratorTarget* target)
+{
+ // Construct the imported target name.
+ std::string targetName = this->Namespace;
+
+ targetName += target->GetExportName();
+
+ // Create the imported target.
+ os << "# Create imported target " << targetName << "\n";
+ switch (target->GetType()) {
+ case cmState::EXECUTABLE:
+ os << "add_executable(" << targetName << " IMPORTED)\n";
+ break;
+ case cmState::STATIC_LIBRARY:
+ os << "add_library(" << targetName << " STATIC IMPORTED)\n";
+ break;
+ case cmState::SHARED_LIBRARY:
+ os << "add_library(" << targetName << " SHARED IMPORTED)\n";
+ break;
+ case cmState::MODULE_LIBRARY:
+ os << "add_library(" << targetName << " MODULE IMPORTED)\n";
+ break;
+ case cmState::UNKNOWN_LIBRARY:
+ os << "add_library(" << targetName << " UNKNOWN IMPORTED)\n";
+ break;
+ case cmState::INTERFACE_LIBRARY:
+ os << "add_library(" << targetName << " INTERFACE IMPORTED)\n";
+ break;
+ default: // should never happen
+ break;
+ }
+
+ // Mark the imported executable if it has exports.
+ if (target->IsExecutableWithExports()) {
+ os << "set_property(TARGET " << targetName
+ << " PROPERTY ENABLE_EXPORTS 1)\n";
+ }
+
+ // Mark the imported library if it is a framework.
+ if (target->IsFrameworkOnApple()) {
+ os << "set_property(TARGET " << targetName << " PROPERTY FRAMEWORK 1)\n";
+ }
+
+ // Mark the imported executable if it is an application bundle.
+ if (target->IsAppBundleOnApple()) {
+ os << "set_property(TARGET " << targetName
+ << " PROPERTY MACOSX_BUNDLE 1)\n";
+ }
+
+ if (target->IsCFBundleOnApple()) {
+ os << "set_property(TARGET " << targetName << " PROPERTY BUNDLE 1)\n";
+ }
+ os << "\n";
+}
+
+void cmExportFileGenerator::GenerateImportPropertyCode(
+ std::ostream& os, const std::string& config, cmGeneratorTarget const* target,
+ ImportPropertyMap const& properties)
+{
+ // Construct the imported target name.
+ std::string targetName = this->Namespace;
+
+ targetName += target->GetExportName();
+
+ // Set the import properties.
+ os << "# Import target \"" << targetName << "\" for configuration \""
+ << config << "\"\n";
+ os << "set_property(TARGET " << targetName
+ << " APPEND PROPERTY IMPORTED_CONFIGURATIONS ";
+ if (!config.empty()) {
+ os << cmSystemTools::UpperCase(config);
+ } else {
+ os << "NOCONFIG";
+ }
+ os << ")\n";
+ os << "set_target_properties(" << targetName << " PROPERTIES\n";
+ for (ImportPropertyMap::const_iterator pi = properties.begin();
+ pi != properties.end(); ++pi) {
+ os << " " << pi->first << " " << cmExportFileGeneratorEscape(pi->second)
+ << "\n";
+ }
+ os << " )\n"
+ << "\n";
+}
+
+void cmExportFileGenerator::GenerateMissingTargetsCheckCode(
+ std::ostream& os, const std::vector<std::string>& missingTargets)
+{
+ if (missingTargets.empty()) {
+ /* clang-format off */
+ os << "# This file does not depend on other imported targets which have\n"
+ "# been exported from the same project but in a separate "
+ "export set.\n\n";
+ /* clang-format on */
+ return;
+ }
+ /* clang-format off */
+ os << "# Make sure the targets which have been exported in some other \n"
+ "# export set exist.\n"
+ "unset(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)\n"
+ "foreach(_target ";
+ /* clang-format on */
+ std::set<std::string> emitted;
+ for (unsigned int i = 0; i < missingTargets.size(); ++i) {
+ if (emitted.insert(missingTargets[i]).second) {
+ os << "\"" << missingTargets[i] << "\" ";
+ }
+ }
+ /* clang-format off */
+ os << ")\n"
+ " if(NOT TARGET \"${_target}\" )\n"
+ " set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets \""
+ "${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets} ${_target}\")"
+ "\n"
+ " endif()\n"
+ "endforeach()\n"
+ "\n"
+ "if(DEFINED ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)\n"
+ " if(CMAKE_FIND_PACKAGE_NAME)\n"
+ " set( ${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)\n"
+ " set( ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "
+ "\"The following imported targets are "
+ "referenced, but are missing: "
+ "${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets}\")\n"
+ " else()\n"
+ " message(FATAL_ERROR \"The following imported targets are "
+ "referenced, but are missing: "
+ "${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets}\")\n"
+ " endif()\n"
+ "endif()\n"
+ "unset(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)\n"
+ "\n";
+ /* clang-format on */
+}
+
+void cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os)
+{
+ // Add code which verifies at cmake time that the file which is being
+ // imported actually exists on disk. This should in theory always be theory
+ // case, but still when packages are split into normal and development
+ // packages this might get broken (e.g. the Config.cmake could be part of
+ // the non-development package, something similar happened to me without
+ // on SUSE with a mysql pkg-config file, which claimed everything is fine,
+ // but the development package was not installed.).
+ /* clang-format off */
+ os << "# Loop over all imported files and verify that they actually exist\n"
+ "foreach(target ${_IMPORT_CHECK_TARGETS} )\n"
+ " foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )\n"
+ " if(NOT EXISTS \"${file}\" )\n"
+ " message(FATAL_ERROR \"The imported target \\\"${target}\\\""
+ " references the file\n"
+ " \\\"${file}\\\"\n"
+ "but this file does not exist. Possible reasons include:\n"
+ "* The file was deleted, renamed, or moved to another location.\n"
+ "* An install or uninstall procedure did not complete successfully.\n"
+ "* The installation package was faulty and contained\n"
+ " \\\"${CMAKE_CURRENT_LIST_FILE}\\\"\n"
+ "but not all the files it references.\n"
+ "\")\n"
+ " endif()\n"
+ " endforeach()\n"
+ " unset(_IMPORT_CHECK_FILES_FOR_${target})\n"
+ "endforeach()\n"
+ "unset(_IMPORT_CHECK_TARGETS)\n"
+ "\n";
+ /* clang-format on */
+}
+
+void cmExportFileGenerator::GenerateImportedFileChecksCode(
+ std::ostream& os, cmGeneratorTarget* target,
+ ImportPropertyMap const& properties,
+ const std::set<std::string>& importedLocations)
+{
+ // Construct the imported target name.
+ std::string targetName = this->Namespace;
+ targetName += target->GetExportName();
+
+ os << "list(APPEND _IMPORT_CHECK_TARGETS " << targetName
+ << " )\n"
+ "list(APPEND _IMPORT_CHECK_FILES_FOR_"
+ << targetName << " ";
+
+ for (std::set<std::string>::const_iterator li = importedLocations.begin();
+ li != importedLocations.end(); ++li) {
+ ImportPropertyMap::const_iterator pi = properties.find(*li);
+ if (pi != properties.end()) {
+ os << cmExportFileGeneratorEscape(pi->second) << " ";
+ }
+ }
+
+ os << ")\n\n";
+}
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
new file mode 100644
index 0000000..9c96015
--- /dev/null
+++ b/Source/cmExportFileGenerator.h
@@ -0,0 +1,205 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExportFileGenerator_h
+#define cmExportFileGenerator_h
+
+#include "cmCommand.h"
+#include "cmGeneratorExpression.h"
+
+#include "cmVersion.h"
+#include "cmVersionMacros.h"
+
+#define STRINGIFY_HELPER(X) #X
+#define STRINGIFY(X) STRINGIFY_HELPER(X)
+
+#define DEVEL_CMAKE_VERSION(major, minor) \
+ (CMake_VERSION_ENCODE(major, minor, 0) > \
+ CMake_VERSION_ENCODE(CMake_VERSION_MAJOR, CMake_VERSION_MINOR, 0) \
+ ? STRINGIFY(CMake_VERSION_MAJOR) "." STRINGIFY( \
+ CMake_VERSION_MINOR) "." STRINGIFY(CMake_VERSION_PATCH) \
+ : #major "." #minor ".0")
+
+class cmTargetExport;
+
+/** \class cmExportFileGenerator
+ * \brief Generate a file exporting targets from a build or install tree.
+ *
+ * cmExportFileGenerator is the superclass for
+ * cmExportBuildFileGenerator and cmExportInstallFileGenerator. It
+ * contains common code generation routines for the two kinds of
+ * export implementations.
+ */
+class cmExportFileGenerator
+{
+public:
+ cmExportFileGenerator();
+ virtual ~cmExportFileGenerator() {}
+
+ /** Set the full path to the export file to generate. */
+ void SetExportFile(const char* mainFile);
+ const char* GetMainExportFileName() const;
+
+ /** Set the namespace in which to place exported target names. */
+ void SetNamespace(const std::string& ns) { this->Namespace = ns; }
+ std::string GetNamespace() const { return this->Namespace; }
+
+ void SetExportOld(bool exportOld) { this->ExportOld = exportOld; }
+
+ /** Add a configuration to be exported. */
+ void AddConfiguration(const std::string& config);
+
+ /** Actually generate the export file. Returns whether there was an
+ error. */
+ bool GenerateImportFile();
+
+protected:
+ typedef std::map<std::string, std::string> ImportPropertyMap;
+
+ // Generate per-configuration target information to the given output
+ // stream.
+ void GenerateImportConfig(std::ostream& os, const std::string& config,
+ std::vector<std::string>& missingTargets);
+
+ // Methods to implement export file code generation.
+ void GenerateImportHeaderCode(std::ostream& os,
+ const std::string& config = "");
+ void GenerateImportFooterCode(std::ostream& os);
+ void GenerateImportVersionCode(std::ostream& os);
+ void GenerateImportTargetCode(std::ostream& os,
+ cmGeneratorTarget const* target);
+ void GenerateImportPropertyCode(std::ostream& os, const std::string& config,
+ cmGeneratorTarget const* target,
+ ImportPropertyMap const& properties);
+ void GenerateImportedFileChecksCode(
+ std::ostream& os, cmGeneratorTarget* target,
+ ImportPropertyMap const& properties,
+ const std::set<std::string>& importedLocations);
+ void GenerateImportedFileCheckLoop(std::ostream& os);
+ void GenerateMissingTargetsCheckCode(
+ std::ostream& os, const std::vector<std::string>& missingTargets);
+
+ void GenerateExpectedTargetsCode(std::ostream& os,
+ const std::string& expectedTargets);
+
+ // Collect properties with detailed information about targets beyond
+ // their location on disk.
+ void SetImportDetailProperties(const std::string& config,
+ std::string const& suffix,
+ cmGeneratorTarget* target,
+ ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets);
+
+ template <typename T>
+ void SetImportLinkProperty(std::string const& suffix,
+ cmGeneratorTarget* target,
+ const std::string& propName,
+ std::vector<T> const& entries,
+ ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets);
+
+ /** Each subclass knows how to generate its kind of export file. */
+ virtual bool GenerateMainFile(std::ostream& os) = 0;
+
+ /** Each subclass knows where the target files are located. */
+ virtual void GenerateImportTargetsConfig(
+ std::ostream& os, const std::string& config, std::string const& suffix,
+ std::vector<std::string>& missingTargets) = 0;
+
+ /** Each subclass knows how to deal with a target that is missing from an
+ * export set. */
+ virtual void HandleMissingTarget(std::string& link_libs,
+ std::vector<std::string>& missingTargets,
+ cmGeneratorTarget* depender,
+ cmGeneratorTarget* dependee) = 0;
+ void PopulateInterfaceProperty(const std::string&, cmGeneratorTarget* target,
+ cmGeneratorExpression::PreprocessContext,
+ ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets);
+ bool PopulateInterfaceLinkLibrariesProperty(
+ cmGeneratorTarget* target, cmGeneratorExpression::PreprocessContext,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
+ void PopulateInterfaceProperty(const std::string& propName,
+ cmGeneratorTarget* target,
+ ImportPropertyMap& properties);
+ void PopulateCompatibleInterfaceProperties(cmGeneratorTarget* target,
+ ImportPropertyMap& properties);
+ void GenerateInterfaceProperties(cmGeneratorTarget const* target,
+ std::ostream& os,
+ const ImportPropertyMap& properties);
+ void PopulateIncludeDirectoriesInterface(
+ cmTargetExport* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
+ void PopulateSourcesInterface(
+ cmTargetExport* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
+
+ void SetImportLinkInterface(
+ const std::string& config, std::string const& suffix,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ cmGeneratorTarget* target, ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets);
+
+ enum FreeTargetsReplace
+ {
+ ReplaceFreeTargets,
+ NoReplaceFreeTargets
+ };
+
+ void ResolveTargetsInGeneratorExpressions(
+ std::string& input, cmGeneratorTarget* target,
+ std::vector<std::string>& missingTargets,
+ FreeTargetsReplace replace = NoReplaceFreeTargets);
+
+ void GenerateRequiredCMakeVersion(std::ostream& os,
+ const char* versionString);
+
+ // The namespace in which the exports are placed in the generated file.
+ std::string Namespace;
+
+ bool ExportOld;
+
+ // The set of configurations to export.
+ std::vector<std::string> Configurations;
+
+ // The file to generate.
+ std::string MainImportFile;
+ std::string FileDir;
+ std::string FileBase;
+ std::string FileExt;
+ bool AppendMode;
+
+ // The set of targets included in the export.
+ std::set<cmGeneratorTarget*> ExportedTargets;
+
+private:
+ void PopulateInterfaceProperty(const std::string&, const std::string&,
+ cmGeneratorTarget* target,
+ cmGeneratorExpression::PreprocessContext,
+ ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets);
+
+ bool AddTargetNamespace(std::string& input, cmGeneratorTarget* target,
+ std::vector<std::string>& missingTargets);
+
+ void ResolveTargetsInGeneratorExpression(
+ std::string& input, cmGeneratorTarget* target,
+ std::vector<std::string>& missingTargets);
+
+ virtual void ReplaceInstallPrefix(std::string& input);
+
+ virtual std::string InstallNameDir(cmGeneratorTarget* target,
+ const std::string& config) = 0;
+};
+
+#endif
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
new file mode 100644
index 0000000..38b08f0
--- /dev/null
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -0,0 +1,481 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmExportInstallFileGenerator.h"
+
+#include "cmAlgorithms.h"
+#include "cmExportSet.h"
+#include "cmExportSetMap.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallTargetGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmTargetExport.h"
+
+cmExportInstallFileGenerator::cmExportInstallFileGenerator(
+ cmInstallExportGenerator* iegen)
+ : IEGen(iegen)
+{
+}
+
+std::string cmExportInstallFileGenerator::GetConfigImportFileGlob()
+{
+ std::string glob = this->FileBase;
+ glob += "-*";
+ glob += this->FileExt;
+ return glob;
+}
+
+bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
+{
+ std::vector<cmTargetExport*> allTargets;
+ {
+ std::string expectedTargets;
+ std::string sep;
+ for (std::vector<cmTargetExport*>::const_iterator tei =
+ this->IEGen->GetExportSet()->GetTargetExports()->begin();
+ tei != this->IEGen->GetExportSet()->GetTargetExports()->end();
+ ++tei) {
+ expectedTargets +=
+ sep + this->Namespace + (*tei)->Target->GetExportName();
+ sep = " ";
+ cmTargetExport* te = *tei;
+ if (this->ExportedTargets.insert(te->Target).second) {
+ allTargets.push_back(te);
+ } else {
+ std::ostringstream e;
+ e << "install(EXPORT \"" << this->IEGen->GetExportSet()->GetName()
+ << "\" ...) "
+ << "includes target \"" << te->Target->GetName()
+ << "\" more than once in the export set.";
+ cmSystemTools::Error(e.str().c_str());
+ return false;
+ }
+ }
+
+ this->GenerateExpectedTargetsCode(os, expectedTargets);
+ }
+
+ // Set an _IMPORT_PREFIX variable for import location properties
+ // to reference if they are relative to the install prefix.
+ std::string installPrefix =
+ this->IEGen->GetLocalGenerator()->GetMakefile()->GetSafeDefinition(
+ "CMAKE_INSTALL_PREFIX");
+ std::string const& expDest = this->IEGen->GetDestination();
+ if (cmSystemTools::FileIsFullPath(expDest)) {
+ // The export file is being installed to an absolute path so the
+ // package is not relocatable. Use the configured install prefix.
+ /* clang-format off */
+ os <<
+ "# The installation prefix configured by this project.\n"
+ "set(_IMPORT_PREFIX \"" << installPrefix << "\")\n"
+ "\n";
+ /* clang-format on */
+ } else {
+ // Add code to compute the installation prefix relative to the
+ // import file location.
+ std::string absDest = installPrefix + "/" + expDest;
+ std::string absDestS = absDest + "/";
+ os << "# Compute the installation prefix relative to this file.\n"
+ << "get_filename_component(_IMPORT_PREFIX"
+ << " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
+ if (cmHasLiteralPrefix(absDestS.c_str(), "/lib/") ||
+ cmHasLiteralPrefix(absDestS.c_str(), "/lib64/") ||
+ cmHasLiteralPrefix(absDestS.c_str(), "/usr/lib/") ||
+ cmHasLiteralPrefix(absDestS.c_str(), "/usr/lib64/")) {
+ // Handle "/usr move" symlinks created by some Linux distros.
+ /* clang-format off */
+ os <<
+ "# Use original install prefix when loaded through a\n"
+ "# cross-prefix symbolic link such as /lib -> /usr/lib.\n"
+ "get_filename_component(_realCurr \"${_IMPORT_PREFIX}\" REALPATH)\n"
+ "get_filename_component(_realOrig \"" << absDest << "\" REALPATH)\n"
+ "if(_realCurr STREQUAL _realOrig)\n"
+ " set(_IMPORT_PREFIX \"" << absDest << "\")\n"
+ "endif()\n"
+ "unset(_realOrig)\n"
+ "unset(_realCurr)\n";
+ /* clang-format on */
+ }
+ std::string dest = expDest;
+ while (!dest.empty()) {
+ os << "get_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" "
+ "PATH)\n";
+ dest = cmSystemTools::GetFilenamePath(dest);
+ }
+ os << "\n";
+ }
+
+ std::vector<std::string> missingTargets;
+
+ bool require2_8_12 = false;
+ bool require3_0_0 = false;
+ bool require3_1_0 = false;
+ bool requiresConfigFiles = false;
+ // Create all the imported targets.
+ for (std::vector<cmTargetExport*>::const_iterator tei = allTargets.begin();
+ tei != allTargets.end(); ++tei) {
+ cmGeneratorTarget* gt = (*tei)->Target;
+
+ requiresConfigFiles =
+ requiresConfigFiles || gt->GetType() != cmState::INTERFACE_LIBRARY;
+
+ this->GenerateImportTargetCode(os, gt);
+
+ ImportPropertyMap properties;
+
+ this->PopulateIncludeDirectoriesInterface(
+ *tei, cmGeneratorExpression::InstallInterface, properties,
+ missingTargets);
+ this->PopulateSourcesInterface(*tei,
+ cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt,
+ cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gt,
+ cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gt,
+ cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gt,
+ cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt,
+ cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+
+ const bool newCMP0022Behavior =
+ gt->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
+ gt->GetPolicyStatusCMP0022() != cmPolicies::OLD;
+ if (newCMP0022Behavior) {
+ if (this->PopulateInterfaceLinkLibrariesProperty(
+ gt, cmGeneratorExpression::InstallInterface, properties,
+ missingTargets) &&
+ !this->ExportOld) {
+ require2_8_12 = true;
+ }
+ }
+ if (gt->GetType() == cmState::INTERFACE_LIBRARY) {
+ require3_0_0 = true;
+ }
+ if (gt->GetProperty("INTERFACE_SOURCES")) {
+ // We can only generate INTERFACE_SOURCES in CMake 3.3, but CMake 3.1
+ // can consume them.
+ require3_1_0 = true;
+ }
+
+ this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gt,
+ properties);
+
+ this->PopulateCompatibleInterfaceProperties(gt, properties);
+
+ this->GenerateInterfaceProperties(gt, os, properties);
+ }
+
+ if (require3_1_0) {
+ this->GenerateRequiredCMakeVersion(os, "3.1.0");
+ } else if (require3_0_0) {
+ this->GenerateRequiredCMakeVersion(os, "3.0.0");
+ } else if (require2_8_12) {
+ this->GenerateRequiredCMakeVersion(os, "2.8.12");
+ }
+
+ // Now load per-configuration properties for them.
+ /* clang-format off */
+ os << "# Load information for each installed configuration.\n"
+ << "get_filename_component(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"
+ << "file(GLOB CONFIG_FILES \"${_DIR}/"
+ << this->GetConfigImportFileGlob() << "\")\n"
+ << "foreach(f ${CONFIG_FILES})\n"
+ << " include(${f})\n"
+ << "endforeach()\n"
+ << "\n";
+ /* clang-format on */
+
+ // Cleanup the import prefix variable.
+ /* clang-format off */
+ os << "# Cleanup temporary variables.\n"
+ << "set(_IMPORT_PREFIX)\n"
+ << "\n";
+ /* clang-format on */
+ this->GenerateImportedFileCheckLoop(os);
+
+ bool result = true;
+ // Generate an import file for each configuration.
+ // Don't do this if we only export INTERFACE_LIBRARY targets.
+ if (requiresConfigFiles) {
+ for (std::vector<std::string>::const_iterator ci =
+ this->Configurations.begin();
+ ci != this->Configurations.end(); ++ci) {
+ if (!this->GenerateImportFileConfig(*ci, missingTargets)) {
+ result = false;
+ }
+ }
+ }
+
+ this->GenerateMissingTargetsCheckCode(os, missingTargets);
+
+ return result;
+}
+
+void cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string& input)
+{
+ std::string::size_type pos = 0;
+ std::string::size_type lastPos = pos;
+
+ while ((pos = input.find("$<INSTALL_PREFIX>", lastPos)) != input.npos) {
+ std::string::size_type endPos = pos + sizeof("$<INSTALL_PREFIX>") - 1;
+ input.replace(pos, endPos - pos, "${_IMPORT_PREFIX}");
+ lastPos = endPos;
+ }
+}
+
+bool cmExportInstallFileGenerator::GenerateImportFileConfig(
+ const std::string& config, std::vector<std::string>& missingTargets)
+{
+ // Skip configurations not enabled for this export.
+ if (!this->IEGen->InstallsForConfig(config)) {
+ return true;
+ }
+
+ // Construct the name of the file to generate.
+ std::string fileName = this->FileDir;
+ fileName += "/";
+ fileName += this->FileBase;
+ fileName += "-";
+ if (!config.empty()) {
+ fileName += cmSystemTools::LowerCase(config);
+ } else {
+ fileName += "noconfig";
+ }
+ fileName += this->FileExt;
+
+ // Open the output file to generate it.
+ cmGeneratedFileStream exportFileStream(fileName.c_str(), true);
+ if (!exportFileStream) {
+ std::string se = cmSystemTools::GetLastSystemError();
+ std::ostringstream e;
+ e << "cannot write to file \"" << fileName << "\": " << se;
+ cmSystemTools::Error(e.str().c_str());
+ return false;
+ }
+ std::ostream& os = exportFileStream;
+
+ // Start with the import file header.
+ this->GenerateImportHeaderCode(os, config);
+
+ // Generate the per-config target information.
+ this->GenerateImportConfig(os, config, missingTargets);
+
+ // End with the import file footer.
+ this->GenerateImportFooterCode(os);
+
+ // Record this per-config import file.
+ this->ConfigImportFiles[config] = fileName;
+
+ return true;
+}
+
+void cmExportInstallFileGenerator::GenerateImportTargetsConfig(
+ std::ostream& os, const std::string& config, std::string const& suffix,
+ std::vector<std::string>& missingTargets)
+{
+ // Add each target in the set to the export.
+ for (std::vector<cmTargetExport*>::const_iterator tei =
+ this->IEGen->GetExportSet()->GetTargetExports()->begin();
+ tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei) {
+ // Collect import properties for this target.
+ cmTargetExport const* te = *tei;
+ if (te->Target->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+
+ ImportPropertyMap properties;
+ std::set<std::string> importedLocations;
+
+ this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator,
+ properties, importedLocations);
+ this->SetImportLocationProperty(config, suffix, te->LibraryGenerator,
+ properties, importedLocations);
+ this->SetImportLocationProperty(config, suffix, te->RuntimeGenerator,
+ properties, importedLocations);
+ this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator,
+ properties, importedLocations);
+ this->SetImportLocationProperty(config, suffix, te->BundleGenerator,
+ properties, importedLocations);
+
+ // If any file location was set for the target add it to the
+ // import file.
+ if (!properties.empty()) {
+ // Get the rest of the target details.
+ cmGeneratorTarget* gtgt = te->Target;
+ this->SetImportDetailProperties(config, suffix, gtgt, properties,
+ missingTargets);
+
+ this->SetImportLinkInterface(config, suffix,
+ cmGeneratorExpression::InstallInterface,
+ gtgt, properties, missingTargets);
+
+ // TOOD: PUBLIC_HEADER_LOCATION
+ // This should wait until the build feature propagation stuff
+ // is done. Then this can be a propagated include directory.
+ // this->GenerateImportProperty(config, te->HeaderGenerator,
+ // properties);
+
+ // Generate code in the export file.
+ this->GenerateImportPropertyCode(os, config, gtgt, properties);
+ this->GenerateImportedFileChecksCode(os, gtgt, properties,
+ importedLocations);
+ }
+ }
+}
+
+void cmExportInstallFileGenerator::SetImportLocationProperty(
+ const std::string& config, std::string const& suffix,
+ cmInstallTargetGenerator* itgen, ImportPropertyMap& properties,
+ std::set<std::string>& importedLocations)
+{
+ // Skip rules that do not match this configuration.
+ if (!(itgen && itgen->InstallsForConfig(config))) {
+ return;
+ }
+
+ // Get the target to be installed.
+ cmGeneratorTarget* target = itgen->GetTarget();
+
+ // Construct the installed location of the target.
+ std::string dest = itgen->GetDestination(config);
+ std::string value;
+ if (!cmSystemTools::FileIsFullPath(dest.c_str())) {
+ // The target is installed relative to the installation prefix.
+ value = "${_IMPORT_PREFIX}/";
+ }
+ value += dest;
+ value += "/";
+
+ if (itgen->IsImportLibrary()) {
+ // Construct the property name.
+ std::string prop = "IMPORTED_IMPLIB";
+ prop += suffix;
+
+ // Append the installed file name.
+ value += itgen->GetInstallFilename(target, config,
+ cmInstallTargetGenerator::NameImplib);
+
+ // Store the property.
+ properties[prop] = value;
+ importedLocations.insert(prop);
+ } else {
+ // Construct the property name.
+ std::string prop = "IMPORTED_LOCATION";
+ prop += suffix;
+
+ // Append the installed file name.
+ if (target->IsAppBundleOnApple()) {
+ value += itgen->GetInstallFilename(target, config);
+ value += ".app/Contents/MacOS/";
+ value += itgen->GetInstallFilename(target, config);
+ } else {
+ value += itgen->GetInstallFilename(target, config,
+ cmInstallTargetGenerator::NameReal);
+ }
+
+ // Store the property.
+ properties[prop] = value;
+ importedLocations.insert(prop);
+ }
+}
+
+void cmExportInstallFileGenerator::HandleMissingTarget(
+ std::string& link_libs, std::vector<std::string>& missingTargets,
+ cmGeneratorTarget* depender, cmGeneratorTarget* dependee)
+{
+ const std::string name = dependee->GetName();
+ cmGlobalGenerator* gg = dependee->GetLocalGenerator()->GetGlobalGenerator();
+ std::vector<std::string> namespaces = this->FindNamespaces(gg, name);
+ int targetOccurrences = (int)namespaces.size();
+ if (targetOccurrences == 1) {
+ std::string missingTarget = namespaces[0];
+
+ missingTarget += dependee->GetExportName();
+ link_libs += missingTarget;
+ missingTargets.push_back(missingTarget);
+ } else {
+ // All exported targets should be known here and should be unique.
+ // This is probably user-error.
+ this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences);
+ }
+}
+
+std::vector<std::string> cmExportInstallFileGenerator::FindNamespaces(
+ cmGlobalGenerator* gg, const std::string& name)
+{
+ std::vector<std::string> namespaces;
+ const cmExportSetMap& exportSets = gg->GetExportSets();
+
+ for (cmExportSetMap::const_iterator expIt = exportSets.begin();
+ expIt != exportSets.end(); ++expIt) {
+ const cmExportSet* exportSet = expIt->second;
+ std::vector<cmTargetExport*> const* targets =
+ exportSet->GetTargetExports();
+
+ bool containsTarget = false;
+ for (unsigned int i = 0; i < targets->size(); i++) {
+ if (name == (*targets)[i]->TargetName) {
+ containsTarget = true;
+ break;
+ }
+ }
+
+ if (containsTarget) {
+ std::vector<cmInstallExportGenerator const*> const* installs =
+ exportSet->GetInstallations();
+ for (unsigned int i = 0; i < installs->size(); i++) {
+ namespaces.push_back((*installs)[i]->GetNamespace());
+ }
+ }
+ }
+
+ return namespaces;
+}
+
+void cmExportInstallFileGenerator::ComplainAboutMissingTarget(
+ cmGeneratorTarget* depender, cmGeneratorTarget* dependee, int occurrences)
+{
+ std::ostringstream e;
+ e << "install(EXPORT \"" << this->IEGen->GetExportSet()->GetName()
+ << "\" ...) "
+ << "includes target \"" << depender->GetName()
+ << "\" which requires target \"" << dependee->GetName() << "\" ";
+ if (occurrences == 0) {
+ e << "that is not in the export set.";
+ } else {
+ e << "that is not in this export set, but " << occurrences
+ << " times in others.";
+ }
+ cmSystemTools::Error(e.str().c_str());
+}
+
+std::string cmExportInstallFileGenerator::InstallNameDir(
+ cmGeneratorTarget* target, const std::string&)
+{
+ std::string install_name_dir;
+
+ cmMakefile* mf = target->Target->GetMakefile();
+ if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ install_name_dir = target->GetInstallNameDirForInstallTree();
+ }
+
+ return install_name_dir;
+}
diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h
new file mode 100644
index 0000000..68960db
--- /dev/null
+++ b/Source/cmExportInstallFileGenerator.h
@@ -0,0 +1,93 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExportInstallFileGenerator_h
+#define cmExportInstallFileGenerator_h
+
+#include "cmExportFileGenerator.h"
+
+class cmInstallExportGenerator;
+class cmInstallTargetGenerator;
+
+/** \class cmExportInstallFileGenerator
+ * \brief Generate a file exporting targets from an install tree.
+ *
+ * cmExportInstallFileGenerator generates files exporting targets from
+ * install an installation tree. The files are placed in a temporary
+ * location for installation by cmInstallExportGenerator. One main
+ * file is generated that creates the imported targets and loads
+ * per-configuration files. Target locations and settings for each
+ * configuration are written to these per-configuration files. After
+ * installation the main file loads the configurations that have been
+ * installed.
+ *
+ * This is used to implement the INSTALL(EXPORT) command.
+ */
+class cmExportInstallFileGenerator : public cmExportFileGenerator
+{
+public:
+ /** Construct with the export installer that will install the
+ files. */
+ cmExportInstallFileGenerator(cmInstallExportGenerator* iegen);
+
+ /** Get the per-config file generated for each configuraiton. This
+ maps from the configuration name to the file temporary location
+ for installation. */
+ std::map<std::string, std::string> const& GetConfigImportFiles()
+ {
+ return this->ConfigImportFiles;
+ }
+
+ /** Compute the globbing expression used to load per-config import
+ files from the main file. */
+ std::string GetConfigImportFileGlob();
+
+protected:
+ // Implement virtual methods from the superclass.
+ bool GenerateMainFile(std::ostream& os) CM_OVERRIDE;
+ void GenerateImportTargetsConfig(
+ std::ostream& os, const std::string& config, std::string const& suffix,
+ std::vector<std::string>& missingTargets) CM_OVERRIDE;
+ void HandleMissingTarget(std::string& link_libs,
+ std::vector<std::string>& missingTargets,
+ cmGeneratorTarget* depender,
+ cmGeneratorTarget* dependee) CM_OVERRIDE;
+
+ void ReplaceInstallPrefix(std::string& input) CM_OVERRIDE;
+
+ void ComplainAboutMissingTarget(cmGeneratorTarget* depender,
+ cmGeneratorTarget* dependee,
+ int occurrences);
+
+ std::vector<std::string> FindNamespaces(cmGlobalGenerator* gg,
+ const std::string& name);
+
+ /** Generate a per-configuration file for the targets. */
+ bool GenerateImportFileConfig(const std::string& config,
+ std::vector<std::string>& missingTargets);
+
+ /** Fill in properties indicating installed file locations. */
+ void SetImportLocationProperty(const std::string& config,
+ std::string const& suffix,
+ cmInstallTargetGenerator* itgen,
+ ImportPropertyMap& properties,
+ std::set<std::string>& importedLocations);
+
+ std::string InstallNameDir(cmGeneratorTarget* target,
+ const std::string& config) CM_OVERRIDE;
+
+ cmInstallExportGenerator* IEGen;
+
+ // The import file generated for each configuration.
+ std::map<std::string, std::string> ConfigImportFiles;
+};
+
+#endif
diff --git a/Source/cmExportLibraryDependenciesCommand.cxx b/Source/cmExportLibraryDependenciesCommand.cxx
new file mode 100644
index 0000000..c8272cb
--- /dev/null
+++ b/Source/cmExportLibraryDependenciesCommand.cxx
@@ -0,0 +1,182 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmExportLibraryDependenciesCommand.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmVersion.h"
+#include "cmake.h"
+
+#include <cm_auto_ptr.hxx>
+
+bool cmExportLibraryDependenciesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (this->Disallowed(
+ cmPolicies::CMP0033,
+ "The export_library_dependencies command should not be called; "
+ "see CMP0033.")) {
+ return true;
+ }
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // store the arguments for the final pass
+ this->Filename = args[0];
+ this->Append = false;
+ if (args.size() > 1) {
+ if (args[1] == "APPEND") {
+ this->Append = true;
+ }
+ }
+ return true;
+}
+
+void cmExportLibraryDependenciesCommand::FinalPass()
+{
+ // export_library_dependencies() shouldn't modify anything
+ // ensure this by calling a const method
+ this->ConstFinalPass();
+}
+
+void cmExportLibraryDependenciesCommand::ConstFinalPass() const
+{
+ // Use copy-if-different if not appending.
+ CM_AUTO_PTR<cmsys::ofstream> foutPtr;
+ if (this->Append) {
+ CM_AUTO_PTR<cmsys::ofstream> ap(
+ new cmsys::ofstream(this->Filename.c_str(), std::ios::app));
+ foutPtr = ap;
+ } else {
+ CM_AUTO_PTR<cmGeneratedFileStream> ap(
+ new cmGeneratedFileStream(this->Filename.c_str(), true));
+ ap->SetCopyIfDifferent(true);
+ foutPtr = ap;
+ }
+ std::ostream& fout = *foutPtr.get();
+
+ if (!fout) {
+ cmSystemTools::Error("Error Writing ", this->Filename.c_str());
+ cmSystemTools::ReportLastSystemError("");
+ return;
+ }
+
+ // Collect dependency information about all library targets built in
+ // the project.
+ cmake* cm = this->Makefile->GetCMakeInstance();
+ cmGlobalGenerator* global = cm->GetGlobalGenerator();
+ const std::vector<cmMakefile*>& locals = global->GetMakefiles();
+ std::map<std::string, std::string> libDepsOld;
+ std::map<std::string, std::string> libDepsNew;
+ std::map<std::string, std::string> libTypes;
+ for (std::vector<cmMakefile*>::const_iterator i = locals.begin();
+ i != locals.end(); ++i) {
+ const cmTargets& tgts = (*i)->GetTargets();
+ for (cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); ++l) {
+ // Get the current target.
+ cmTarget const& target = l->second;
+
+ // Skip non-library targets.
+ if (target.GetType() < cmState::STATIC_LIBRARY ||
+ target.GetType() > cmState::MODULE_LIBRARY) {
+ continue;
+ }
+
+ // Construct the dependency variable name.
+ std::string targetEntry = target.GetName();
+ targetEntry += "_LIB_DEPENDS";
+
+ // Construct the dependency variable value with the direct link
+ // dependencies.
+ std::string valueOld;
+ std::string valueNew;
+ cmTarget::LinkLibraryVectorType const& libs =
+ target.GetOriginalLinkLibraries();
+ for (cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
+ li != libs.end(); ++li) {
+ std::string ltVar = li->first;
+ ltVar += "_LINK_TYPE";
+ std::string ltValue;
+ switch (li->second) {
+ case GENERAL_LibraryType:
+ valueNew += "general;";
+ ltValue = "general";
+ break;
+ case DEBUG_LibraryType:
+ valueNew += "debug;";
+ ltValue = "debug";
+ break;
+ case OPTIMIZED_LibraryType:
+ valueNew += "optimized;";
+ ltValue = "optimized";
+ break;
+ }
+ std::string lib = li->first;
+ if (cmTarget* libtgt = global->FindTarget(lib)) {
+ // Handle simple output name changes. This command is
+ // deprecated so we do not support full target name
+ // translation (which requires per-configuration info).
+ if (const char* outname = libtgt->GetProperty("OUTPUT_NAME")) {
+ lib = outname;
+ }
+ }
+ valueOld += lib;
+ valueOld += ";";
+ valueNew += lib;
+ valueNew += ";";
+
+ std::string& ltEntry = libTypes[ltVar];
+ if (ltEntry.empty()) {
+ ltEntry = ltValue;
+ } else if (ltEntry != ltValue) {
+ ltEntry = "general";
+ }
+ }
+ libDepsNew[targetEntry] = valueNew;
+ libDepsOld[targetEntry] = valueOld;
+ }
+ }
+
+ // Generate dependency information for both old and new style CMake
+ // versions.
+ const char* vertest =
+ "\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" GREATER 2.4";
+ fout << "# Generated by CMake " << cmVersion::GetCMakeVersion() << "\n\n";
+ fout << "if(" << vertest << ")\n";
+ fout << " # Information for CMake 2.6 and above.\n";
+ for (std::map<std::string, std::string>::const_iterator i =
+ libDepsNew.begin();
+ i != libDepsNew.end(); ++i) {
+ if (!i->second.empty()) {
+ fout << " set(\"" << i->first << "\" \"" << i->second << "\")\n";
+ }
+ }
+ fout << "else()\n";
+ fout << " # Information for CMake 2.4 and lower.\n";
+ for (std::map<std::string, std::string>::const_iterator i =
+ libDepsOld.begin();
+ i != libDepsOld.end(); ++i) {
+ if (!i->second.empty()) {
+ fout << " set(\"" << i->first << "\" \"" << i->second << "\")\n";
+ }
+ }
+ for (std::map<std::string, std::string>::const_iterator i = libTypes.begin();
+ i != libTypes.end(); ++i) {
+ if (i->second != "general") {
+ fout << " set(\"" << i->first << "\" \"" << i->second << "\")\n";
+ }
+ }
+ fout << "endif()\n";
+ return;
+}
diff --git a/Source/cmExportLibraryDependenciesCommand.h b/Source/cmExportLibraryDependenciesCommand.h
new file mode 100644
index 0000000..4b3dc92
--- /dev/null
+++ b/Source/cmExportLibraryDependenciesCommand.h
@@ -0,0 +1,41 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExportLibraryDependenciesCommand_h
+#define cmExportLibraryDependenciesCommand_h
+
+#include "cmCommand.h"
+
+class cmExportLibraryDependenciesCommand : public cmCommand
+{
+public:
+ cmTypeMacro(cmExportLibraryDependenciesCommand, cmCommand);
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ return new cmExportLibraryDependenciesCommand;
+ }
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+ std::string GetName() const CM_OVERRIDE
+ {
+ return "export_library_dependencies";
+ }
+
+ void FinalPass() CM_OVERRIDE;
+ bool HasFinalPass() const CM_OVERRIDE { return true; }
+
+private:
+ std::string Filename;
+ bool Append;
+ void ConstFinalPass() const;
+};
+
+#endif
diff --git a/Source/cmExportSet.cxx b/Source/cmExportSet.cxx
new file mode 100644
index 0000000..c468e3e
--- /dev/null
+++ b/Source/cmExportSet.cxx
@@ -0,0 +1,40 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmExportSet.h"
+
+#include "cmAlgorithms.h"
+#include "cmLocalGenerator.h"
+#include "cmTargetExport.h"
+
+cmExportSet::~cmExportSet()
+{
+ cmDeleteAll(this->TargetExports);
+}
+
+void cmExportSet::Compute(cmLocalGenerator* lg)
+{
+ for (std::vector<cmTargetExport*>::iterator it = this->TargetExports.begin();
+ it != this->TargetExports.end(); ++it) {
+ (*it)->Target = lg->FindGeneratorTargetToUse((*it)->TargetName);
+ }
+}
+
+void cmExportSet::AddTargetExport(cmTargetExport* te)
+{
+ this->TargetExports.push_back(te);
+}
+
+void cmExportSet::AddInstallation(cmInstallExportGenerator const* installation)
+{
+ this->Installations.push_back(installation);
+}
diff --git a/Source/cmExportSet.h b/Source/cmExportSet.h
new file mode 100644
index 0000000..49f2cac
--- /dev/null
+++ b/Source/cmExportSet.h
@@ -0,0 +1,57 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExportSet_h
+#define cmExportSet_h
+
+#include "cmSystemTools.h"
+
+class cmTargetExport;
+class cmInstallExportGenerator;
+class cmLocalGenerator;
+
+/// A set of targets that were installed with the same EXPORT parameter.
+class cmExportSet
+{
+public:
+ /// Construct an empty export set named \a name
+ cmExportSet(const std::string& name)
+ : Name(name)
+ {
+ }
+ /// Destructor
+ ~cmExportSet();
+
+ void Compute(cmLocalGenerator* lg);
+
+ void AddTargetExport(cmTargetExport* tgt);
+
+ void AddInstallation(cmInstallExportGenerator const* installation);
+
+ std::string const& GetName() const { return this->Name; }
+
+ std::vector<cmTargetExport*> const* GetTargetExports() const
+ {
+ return &this->TargetExports;
+ }
+
+ std::vector<cmInstallExportGenerator const*> const* GetInstallations() const
+ {
+ return &this->Installations;
+ }
+
+private:
+ std::vector<cmTargetExport*> TargetExports;
+ std::string Name;
+ std::vector<cmInstallExportGenerator const*> Installations;
+};
+
+#endif
diff --git a/Source/cmExportSetMap.cxx b/Source/cmExportSetMap.cxx
new file mode 100644
index 0000000..ac1c66e
--- /dev/null
+++ b/Source/cmExportSetMap.cxx
@@ -0,0 +1,37 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmExportSetMap.h"
+
+#include "cmAlgorithms.h"
+#include "cmExportSet.h"
+
+cmExportSet* cmExportSetMap::operator[](const std::string& name)
+{
+ std::map<std::string, cmExportSet*>::iterator it = this->find(name);
+ if (it == this->end()) // Export set not found
+ {
+ it = this->insert(std::make_pair(name, new cmExportSet(name))).first;
+ }
+ return it->second;
+}
+
+void cmExportSetMap::clear()
+{
+ cmDeleteAll(*this);
+ this->derived::clear();
+}
+
+cmExportSetMap::~cmExportSetMap()
+{
+ this->clear();
+}
diff --git a/Source/cmExportSetMap.h b/Source/cmExportSetMap.h
new file mode 100644
index 0000000..d2954e3
--- /dev/null
+++ b/Source/cmExportSetMap.h
@@ -0,0 +1,38 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExportSetMap_h
+#define cmExportSetMap_h
+
+#include "cmSystemTools.h"
+
+class cmExportSet;
+
+/// A name -> cmExportSet map with overloaded operator[].
+class cmExportSetMap : public std::map<std::string, cmExportSet*>
+{
+ typedef std::map<std::string, cmExportSet*> derived;
+
+public:
+ /** \brief Overloaded operator[].
+ *
+ * The operator is overloaded because cmExportSet has no default constructor:
+ * we do not want unnamed export sets.
+ */
+ cmExportSet* operator[](const std::string& name);
+
+ void clear();
+
+ /// Overloaded destructor deletes all member export sets.
+ ~cmExportSetMap();
+};
+
+#endif
diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
new file mode 100644
index 0000000..2916e6b
--- /dev/null
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -0,0 +1,132 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmExportTryCompileFileGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+
+cmExportTryCompileFileGenerator::cmExportTryCompileFileGenerator(
+ cmGlobalGenerator* gg, const std::vector<std::string>& targets,
+ cmMakefile* mf)
+{
+ gg->CreateImportedGenerationObjects(mf, targets, this->Exports);
+}
+
+bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os)
+{
+ std::set<cmGeneratorTarget const*> emitted;
+ std::set<cmGeneratorTarget const*> emittedDeps;
+ while (!this->Exports.empty()) {
+ cmGeneratorTarget const* te = this->Exports.back();
+ this->Exports.pop_back();
+ if (emitted.insert(te).second) {
+ emittedDeps.insert(te);
+ this->GenerateImportTargetCode(os, te);
+
+ ImportPropertyMap properties;
+
+#define FIND_TARGETS(PROPERTY) \
+ this->FindTargets("INTERFACE_" #PROPERTY, te, emittedDeps);
+
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(FIND_TARGETS)
+
+#undef FIND_TARGETS
+
+ this->PopulateProperties(te, properties, emittedDeps);
+
+ this->GenerateInterfaceProperties(te, os, properties);
+ }
+ }
+ return true;
+}
+
+std::string cmExportTryCompileFileGenerator::FindTargets(
+ const std::string& propName, cmGeneratorTarget const* tgt,
+ std::set<cmGeneratorTarget const*>& emitted)
+{
+ const char* prop = tgt->GetProperty(propName);
+ if (!prop) {
+ return std::string();
+ }
+
+ cmGeneratorExpression ge;
+
+ cmGeneratorExpressionDAGChecker dagChecker(tgt->GetName(), propName,
+ CM_NULLPTR, CM_NULLPTR);
+
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
+
+ cmTarget dummyHead;
+ dummyHead.SetType(cmState::EXECUTABLE, "try_compile_dummy_exe");
+ dummyHead.SetMakefile(tgt->Target->GetMakefile());
+
+ cmGeneratorTarget gDummyHead(&dummyHead, tgt->GetLocalGenerator());
+
+ std::string result = cge->Evaluate(tgt->GetLocalGenerator(), this->Config,
+ false, &gDummyHead, tgt, &dagChecker);
+
+ const std::set<cmGeneratorTarget const*>& allTargets =
+ cge->GetAllTargetsSeen();
+ for (std::set<cmGeneratorTarget const*>::const_iterator li =
+ allTargets.begin();
+ li != allTargets.end(); ++li) {
+ if (emitted.insert(*li).second) {
+ this->Exports.push_back(*li);
+ }
+ }
+ return result;
+}
+
+void cmExportTryCompileFileGenerator::PopulateProperties(
+ const cmGeneratorTarget* target, ImportPropertyMap& properties,
+ std::set<cmGeneratorTarget const*>& emitted)
+{
+ std::vector<std::string> props = target->GetPropertyKeys();
+ for (std::vector<std::string>::const_iterator i = props.begin();
+ i != props.end(); ++i) {
+
+ properties[*i] = target->GetProperty(*i);
+
+ if (i->find("IMPORTED_LINK_INTERFACE_LIBRARIES") == 0 ||
+ i->find("IMPORTED_LINK_DEPENDENT_LIBRARIES") == 0 ||
+ i->find("INTERFACE_LINK_LIBRARIES") == 0) {
+ std::string evalResult = this->FindTargets(*i, target, emitted);
+
+ std::vector<std::string> depends;
+ cmSystemTools::ExpandListArgument(evalResult, depends);
+ for (std::vector<std::string>::const_iterator li = depends.begin();
+ li != depends.end(); ++li) {
+ cmGeneratorTarget* tgt =
+ target->GetLocalGenerator()->FindGeneratorTargetToUse(*li);
+ if (tgt && emitted.insert(tgt).second) {
+ this->Exports.push_back(tgt);
+ }
+ }
+ }
+ }
+}
+
+std::string cmExportTryCompileFileGenerator::InstallNameDir(
+ cmGeneratorTarget* target, const std::string& config)
+{
+ std::string install_name_dir;
+
+ cmMakefile* mf = target->Target->GetMakefile();
+ if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ install_name_dir = target->GetInstallNameDirForBuildTree(config);
+ }
+
+ return install_name_dir;
+}
diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h
new file mode 100644
index 0000000..1d13711
--- /dev/null
+++ b/Source/cmExportTryCompileFileGenerator.h
@@ -0,0 +1,59 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExportTryCompileFileGenerator_h
+#define cmExportTryCompileFileGenerator_h
+
+#include "cmExportFileGenerator.h"
+
+class cmInstallExportGenerator;
+class cmInstallTargetGenerator;
+
+class cmExportTryCompileFileGenerator : public cmExportFileGenerator
+{
+public:
+ cmExportTryCompileFileGenerator(cmGlobalGenerator* gg,
+ std::vector<std::string> const& targets,
+ cmMakefile* mf);
+
+ /** Set the list of targets to export. */
+ void SetConfig(const std::string& config) { this->Config = config; }
+protected:
+ // Implement virtual methods from the superclass.
+ bool GenerateMainFile(std::ostream& os) CM_OVERRIDE;
+
+ void GenerateImportTargetsConfig(std::ostream&, const std::string&,
+ std::string const&,
+ std::vector<std::string>&) CM_OVERRIDE
+ {
+ }
+ void HandleMissingTarget(std::string&, std::vector<std::string>&,
+ cmGeneratorTarget*, cmGeneratorTarget*) CM_OVERRIDE
+ {
+ }
+
+ void PopulateProperties(cmGeneratorTarget const* target,
+ ImportPropertyMap& properties,
+ std::set<const cmGeneratorTarget*>& emitted);
+
+ std::string InstallNameDir(cmGeneratorTarget* target,
+ const std::string& config) CM_OVERRIDE;
+
+private:
+ std::string FindTargets(const std::string& prop,
+ const cmGeneratorTarget* tgt,
+ std::set<const cmGeneratorTarget*>& emitted);
+
+ std::vector<cmGeneratorTarget const*> Exports;
+ std::string Config;
+};
+
+#endif
diff --git a/Source/cmExprLexer.cxx b/Source/cmExprLexer.cxx
new file mode 100644
index 0000000..4704f03
--- /dev/null
+++ b/Source/cmExprLexer.cxx
@@ -0,0 +1,1928 @@
+#include "cmStandardIncludes.h"
+#line 2 "/home/andy/vtk/CMake-bin/Source/cmExprLexer.cxx"
+
+#line 4 "/home/andy/vtk/CMake-bin/Source/cmExprLexer.cxx"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 31
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+int cmExpr_yylex_init (yyscan_t* scanner);
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE cmExpr_yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input
+ stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via cmExpr_yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is
+ * not NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void cmExpr_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void cmExpr_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmExpr_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void cmExpr_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmExpr_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmExpr_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void cmExpr_yypop_buffer_state (yyscan_t yyscanner );
+
+static void cmExpr_yyensure_buffer_stack (yyscan_t yyscanner );
+static void cmExpr_yy_load_buffer_state (yyscan_t yyscanner );
+static void cmExpr_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER cmExpr_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE cmExpr_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmExpr_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmExpr_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *cmExpr_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *cmExpr_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void cmExpr_yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer cmExpr_yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ cmExpr_yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ cmExpr_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ cmExpr_yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ cmExpr_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cmExpr_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,
+ yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 15
+#define YY_END_OF_BUFFER 16
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[23] =
+ { 0,
+ 0, 0, 16, 15, 6, 8, 13, 14, 4, 2,
+ 3, 5, 1, 15, 15, 9, 7, 10, 1, 11,
+ 12, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 3, 1, 4,
+ 5, 6, 7, 1, 8, 1, 9, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 1, 1, 11,
+ 1, 12, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 13, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 14, 1, 15, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[16] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[23] =
+ { 0,
+ 0, 0, 20, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 9, 7, 5, 21, 21, 21, 6, 21,
+ 21, 21
+ } ;
+
+static yyconst flex_int16_t yy_def[23] =
+ { 0,
+ 22, 1, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 0
+ } ;
+
+static yyconst flex_int16_t yy_nxt[37] =
+ { 0,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 21, 20, 19, 22,
+ 3, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22
+ } ;
+
+static yyconst flex_int16_t yy_chk[37] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 19, 15, 14, 13, 3,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22
+ } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+#line 2 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run flex like this:
+
+ flex --prefix=cmExpr_yy --header-file=cmExprLexer.h -ocmExprLexer.cxx cmExprLexer.in.l
+
+Modify cmExprLexer.cxx:
+ - remove TABs
+ - remove "yyscanner" argument from these methods:
+ yy_fatal_error, cmExpr_yyalloc, cmExpr_yyrealloc, cmExpr_yyfree
+ - remove all YY_BREAK lines occurring right after return statements
+ - change while ( 1 ) to for(;;)
+
+Modify cmExprLexer.h:
+ - remove TABs
+ - remove the yy_init_globals function
+ - remove the block that includes unistd.h
+ - remove #line directives (avoids bogus warning on old Sun)
+
+*/
+
+#include "cmStandardLexer.h"
+
+#include "cmExprParserHelper.h"
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ { result = yyextra->LexInput(buf, max_size); }
+
+/* Include the set of tokens from the parser. */
+#include "cmExprParserTokens.h"
+
+/*--------------------------------------------------------------------------*/
+#line 518 "/home/andy/vtk/CMake-bin/Source/cmExprLexer.cxx"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant
+ scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ }; /* end struct yyguts_t */
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int cmExpr_yylex_destroy (yyscan_t yyscanner );
+
+int cmExpr_yyget_debug (yyscan_t yyscanner );
+
+void cmExpr_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE cmExpr_yyget_extra (yyscan_t yyscanner );
+
+void cmExpr_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *cmExpr_yyget_in (yyscan_t yyscanner );
+
+void cmExpr_yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *cmExpr_yyget_out (yyscan_t yyscanner );
+
+void cmExpr_yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+int cmExpr_yyget_leng (yyscan_t yyscanner );
+
+char *cmExpr_yyget_text (yyscan_t yyscanner );
+
+int cmExpr_yyget_lineno (yyscan_t yyscanner );
+
+void cmExpr_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int cmExpr_yywrap (yyscan_t yyscanner );
+#else
+extern int cmExpr_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int cmExpr_yylex (yyscan_t yyscanner);
+
+#define YY_DECL int cmExpr_yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+#line 86 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+
+
+#line 736 "/home/andy/vtk/CMake-bin/Source/cmExprLexer.cxx"
+
+ if ( yyg->yy_init )
+ {
+ yyg->yy_init = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ cmExpr_yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ cmExpr_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ cmExpr_yy_load_buffer_state(yyscanner );
+ }
+
+ for(;;) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 23 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 21 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 88 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ yylvalp->Number = atoi(yytext); return exp_NUMBER; }
+case 2:
+YY_RULE_SETUP
+#line 90 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ return exp_PLUS; }
+case 3:
+YY_RULE_SETUP
+#line 91 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ return exp_MINUS; }
+case 4:
+YY_RULE_SETUP
+#line 92 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ return exp_TIMES; }
+case 5:
+YY_RULE_SETUP
+#line 93 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ return exp_DIVIDE; }
+case 6:
+YY_RULE_SETUP
+#line 94 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ return exp_MOD; }
+case 7:
+YY_RULE_SETUP
+#line 95 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ return exp_OR; }
+case 8:
+YY_RULE_SETUP
+#line 96 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ return exp_AND; }
+case 9:
+YY_RULE_SETUP
+#line 97 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ return exp_XOR; }
+case 10:
+YY_RULE_SETUP
+#line 98 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ return exp_NOT; }
+case 11:
+YY_RULE_SETUP
+#line 99 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ return exp_SHIFTLEFT; }
+case 12:
+YY_RULE_SETUP
+#line 100 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ return exp_SHIFTRIGHT; }
+case 13:
+YY_RULE_SETUP
+#line 101 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ return exp_OPENPARENT; }
+case 14:
+YY_RULE_SETUP
+#line 102 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+{ return exp_CLOSEPARENT; }
+case 15:
+YY_RULE_SETUP
+#line 104 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+ECHO;
+ YY_BREAK
+#line 894 "/home/andy/vtk/CMake-bin/Source/cmExprLexer.cxx"
+case YY_STATE_EOF(INITIAL):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * cmExpr_yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( cmExpr_yywrap(yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+return 0; /* this should not happen but it quiets some compilers */
+} /* end of cmExpr_yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ size_t nuto_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( nuto_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ cmExpr_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ nuto_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( nuto_read > YY_READ_BUF_SIZE )
+ nuto_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, nuto_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ cmExpr_yyrestart(yyin ,yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was
+ reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 23 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 23 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 22);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ cmExpr_yyrestart(yyin ,yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( cmExpr_yywrap(yyscanner ) )
+ return EOF;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void cmExpr_yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ cmExpr_yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ cmExpr_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ cmExpr_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+ cmExpr_yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void cmExpr_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * cmExpr_yypop_buffer_state();
+ * cmExpr_yypush_buffer_state(new_buffer);
+ */
+ cmExpr_yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ cmExpr_yy_load_buffer_state(yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (cmExpr_yywrap()) processing, but the only time this flag
+ * is looked at is after cmExpr_yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void cmExpr_yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE cmExpr_yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) cmExpr_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in cmExpr_yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) cmExpr_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in cmExpr_yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ cmExpr_yy_init_buffer(b,file ,yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with cmExpr_yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void cmExpr_yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ cmExpr_yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+ cmExpr_yyfree((void *) b ,yyscanner );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a cmExpr_yyrestart() or at EOF.
+ */
+ static void cmExpr_yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ cmExpr_yy_flush_buffer(b ,yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then cmExpr_yy_init_buffer was _probably_
+ * called from cmExpr_yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void cmExpr_yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ cmExpr_yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void cmExpr_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ cmExpr_yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from cmExpr_yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from cmExpr_yy_switch_to_buffer. */
+ cmExpr_yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void cmExpr_yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ cmExpr_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ cmExpr_yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void cmExpr_yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ int nuto_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ nuto_alloc = 1;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)cmExpr_yyalloc
+ (nuto_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+
+ memset(yyg->yy_buffer_stack, 0, nuto_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = nuto_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ nuto_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)cmExpr_yyrealloc
+ (yyg->yy_buffer_stack,
+ nuto_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = nuto_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cmExpr_yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) cmExpr_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in cmExpr_yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ cmExpr_yy_switch_to_buffer(b ,yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to cmExpr_yylex() will
+ * scan from a @e copy of @a yy_str.
+ * @param yy_str a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * cmExpr_yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE cmExpr_yy_scan_string (yyconst char * yy_str , yyscan_t yyscanner)
+{
+
+ return cmExpr_yy_scan_bytes(yy_str,strlen(yy_str) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to cmExpr_yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cmExpr_yy_scan_bytes (yyconst char * bytes, int len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) cmExpr_yyalloc(n ,yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in cmExpr_yy_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = cmExpr_yy_scan_buffer(buf,n ,yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in cmExpr_yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t)
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE cmExpr_yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int cmExpr_yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int cmExpr_yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *cmExpr_yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *cmExpr_yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int cmExpr_yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *cmExpr_yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void cmExpr_yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number The line number to set.
+ * @param yyscanner The scanner object.
+ */
+void cmExpr_yyset_lineno (int line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "cmExpr_yyset_lineno called with no buffer" , yyscanner);
+
+ yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param column_no The column number to set.
+ * @param yyscanner The scanner object.
+ */
+void cmExpr_yyset_column (int column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "cmExpr_yyset_column called with no buffer" , yyscanner);
+
+ yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see cmExpr_yy_switch_to_buffer
+ */
+void cmExpr_yyset_in (FILE * in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = in_str ;
+}
+
+void cmExpr_yyset_out (FILE * out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = out_str ;
+}
+
+int cmExpr_yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void cmExpr_yyset_debug (int bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ This function is called once per scanner lifetime. */
+
+ yyg->yy_buffer_stack = 0;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = (char *) 0;
+ yyg->yy_init = 1;
+ yyg->yy_start = 0;
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = (int *) 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * cmExpr_yylex_init()
+ */
+ return 0;
+}
+
+/* User-visible API */
+
+/* cmExpr_yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int cmExpr_yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) cmExpr_yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ memset(*ptr_yy_globals,0,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* cmExpr_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int cmExpr_yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ cmExpr_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ cmExpr_yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ cmExpr_yyfree(yyg->yy_buffer_stack ,yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ cmExpr_yyfree(yyg->yy_start_stack ,yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Destroy the main struct (reentrant only). */
+ cmExpr_yyfree ( yyscanner , yyscanner );
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+ int i;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+ int n;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *cmExpr_yyalloc (yy_size_t size , yyscan_t)
+{
+ return (void *) malloc( size );
+}
+
+void *cmExpr_yyrealloc (void * ptr, yy_size_t size , yyscan_t)
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void cmExpr_yyfree (void * ptr , yyscan_t)
+{
+ free( (char *) ptr ); /* see cmExpr_yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef yytext_ptr
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+#line 104 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l"
+
+
+
diff --git a/Source/cmExprLexer.h b/Source/cmExprLexer.h
new file mode 100644
index 0000000..03b36ce
--- /dev/null
+++ b/Source/cmExprLexer.h
@@ -0,0 +1,334 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExpr_yyHEADER_H
+#define cmExpr_yyHEADER_H 1
+#define cmExpr_yyIN_HEADER 1
+
+
+
+
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 31
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+int cmExpr_yylex_init (yyscan_t* scanner);
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void cmExpr_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void cmExpr_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,
+ yyscan_t yyscanner );
+YY_BUFFER_STATE cmExpr_yy_create_buffer (FILE *file,int size ,
+ yyscan_t yyscanner );
+void cmExpr_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmExpr_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmExpr_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,
+ yyscan_t yyscanner );
+void cmExpr_yypop_buffer_state (yyscan_t yyscanner );
+
+YY_BUFFER_STATE cmExpr_yy_scan_buffer (char *base,yy_size_t size ,
+ yyscan_t yyscanner );
+YY_BUFFER_STATE cmExpr_yy_scan_string (yyconst char *yy_str ,
+ yyscan_t yyscanner );
+YY_BUFFER_STATE cmExpr_yy_scan_bytes (yyconst char *bytes,int len ,
+ yyscan_t yyscanner );
+
+void *cmExpr_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *cmExpr_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void cmExpr_yyfree (void * ,yyscan_t yyscanner );
+
+/* Begin user sect3 */
+
+#define cmExpr_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int cmExpr_yylex_destroy (yyscan_t yyscanner );
+
+int cmExpr_yyget_debug (yyscan_t yyscanner );
+
+void cmExpr_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE cmExpr_yyget_extra (yyscan_t yyscanner );
+
+void cmExpr_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *cmExpr_yyget_in (yyscan_t yyscanner );
+
+void cmExpr_yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *cmExpr_yyget_out (yyscan_t yyscanner );
+
+void cmExpr_yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+int cmExpr_yyget_leng (yyscan_t yyscanner );
+
+char *cmExpr_yyget_text (yyscan_t yyscanner );
+
+int cmExpr_yyget_lineno (yyscan_t yyscanner );
+
+void cmExpr_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int cmExpr_yywrap (yyscan_t yyscanner );
+#else
+extern int cmExpr_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int cmExpr_yylex (yyscan_t yyscanner);
+
+#define YY_DECL int cmExpr_yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was
+ reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef yytext_ptr
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+
+
+
+#undef cmExpr_yyIN_HEADER
+#endif /* cmExpr_yyHEADER_H */
diff --git a/Source/cmExprLexer.in.l b/Source/cmExprLexer.in.l
new file mode 100644
index 0000000..febd244
--- /dev/null
+++ b/Source/cmExprLexer.in.l
@@ -0,0 +1,74 @@
+%{
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run flex like this:
+
+ flex --prefix=cmExpr_yy --header-file=cmExprLexer.h -ocmExprLexer.cxx cmExprLexer.in.l
+
+Modify cmExprLexer.cxx:
+ - remove TABs
+ - remove use of the 'register' storage class specifier
+ - remove "yyscanner" argument from these methods:
+ yy_fatal_error, cmExpr_yyalloc, cmExpr_yyrealloc, cmExpr_yyfree
+ - remove all YY_BREAK lines occurring right after return statements
+ - change while ( 1 ) to for(;;)
+
+Modify cmExprLexer.h:
+ - remove TABs
+ - remove the yy_init_globals function
+ - remove the block that includes unistd.h
+ - remove #line directives (avoids bogus warning on old Sun)
+
+*/
+
+#include "cmStandardLexer.h"
+
+#include "cmExprParserHelper.h"
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ { result = yyextra->LexInput(buf, max_size); }
+
+/* Include the set of tokens from the parser. */
+#include "cmExprParserTokens.h"
+
+/*--------------------------------------------------------------------------*/
+%}
+
+%option reentrant
+%option noyywrap
+%pointer
+
+%%
+
+[0-9][0-9]* { yylvalp->Number = atoi(yytext); return exp_NUMBER; }
+
+"+" { return exp_PLUS; }
+"-" { return exp_MINUS; }
+"*" { return exp_TIMES; }
+"/" { return exp_DIVIDE; }
+"%" { return exp_MOD; }
+"\|" { return exp_OR; }
+"&" { return exp_AND; }
+"^" { return exp_XOR; }
+"~" { return exp_NOT; }
+"<<" { return exp_SHIFTLEFT; }
+">>" { return exp_SHIFTRIGHT; }
+"(" { return exp_OPENPARENT; }
+")" { return exp_CLOSEPARENT; }
+
+%%
diff --git a/Source/cmExprParser.cxx b/Source/cmExprParser.cxx
new file mode 100644
index 0000000..c12b42e
--- /dev/null
+++ b/Source/cmExprParser.cxx
@@ -0,0 +1,1427 @@
+/* A Bison parser, made by GNU Bison 1.875d. */
+
+/* Skeleton parser for Yacc-like parsing with Bison, Copyright (C) 1984,
+ 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* turn off some warning as this is generated code */
+#if defined(_MSC_VER)
+# pragma warning ( disable : 4702 ) /* unreachable code */
+#endif
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+/* If NAME_PREFIX is specified substitute the variables and functions
+ names. */
+#define yyparse cmExpr_yyparse
+#define yylex cmExpr_yylex
+#define yyerror cmExpr_yyerror
+#define yylval cmExpr_yylval
+#define yychar cmExpr_yychar
+#define yydebug cmExpr_yydebug
+#define yynerrs cmExpr_yynerrs
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ exp_PLUS = 258,
+ exp_MINUS = 259,
+ exp_TIMES = 260,
+ exp_DIVIDE = 261,
+ exp_MOD = 262,
+ exp_SHIFTLEFT = 263,
+ exp_SHIFTRIGHT = 264,
+ exp_OPENPARENT = 265,
+ exp_CLOSEPARENT = 266,
+ exp_OR = 267,
+ exp_AND = 268,
+ exp_XOR = 269,
+ exp_NOT = 270,
+ exp_NUMBER = 271
+ };
+#endif
+#define exp_PLUS 258
+#define exp_MINUS 259
+#define exp_TIMES 260
+#define exp_DIVIDE 261
+#define exp_MOD 262
+#define exp_SHIFTLEFT 263
+#define exp_SHIFTRIGHT 264
+#define exp_OPENPARENT 265
+#define exp_CLOSEPARENT 266
+#define exp_OR 267
+#define exp_AND 268
+#define exp_XOR 269
+#define exp_NOT 270
+#define exp_NUMBER 271
+
+
+
+
+/* Copy the first part of user declarations. */
+
+
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --yacc --name-prefix=cmExpr_yy --defines=cmExprParserTokens.h
+ -ocmExprParser.cxx cmExprParser.y
+
+Modify cmExprParser.cxx:
+ - remove TABs
+ - add __HP_aCC to the #if test for yyerrorlab warning suppression
+
+*/
+
+/* Configure the parser to use a lexer object. */
+#define YYPARSE_PARAM yyscanner
+#define YYLEX_PARAM yyscanner
+#define YYERROR_VERBOSE 1
+#define cmExpr_yyerror(x) \
+ cmExprError(yyscanner, x)
+#define yyGetParser (cmExpr_yyget_extra(yyscanner))
+
+/*-------------------------------------------------------------------------*/
+#include "cmExprParserHelper.h" /* Interface to parser object. */
+#include "cmExprLexer.h" /* Interface to lexer object. */
+#include "cmExprParserTokens.h" /* Need YYSTYPE for YY_DECL. */
+
+#include <math.h>
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Internal utility functions. */
+static void cmExprError(yyscan_t yyscanner, const char* message);
+
+#define YYDEBUG 1
+//#define YYMAXDEPTH 100000
+//#define YYINITDEPTH 10000
+
+
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch statement contains default but
+ no case. */
+#endif
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+typedef int YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 214 of yacc.c. */
+
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+# ifndef YYFREE
+# define YYFREE free
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# endif
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# endif
+# else
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short int yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined (__GNUC__) && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short int yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 12
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 25
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 17
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 9
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 20
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 34
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 271
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned char yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned char yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 11, 13, 17, 19, 23,
+ 25, 29, 33, 35, 39, 43, 45, 49, 53, 57,
+ 59
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 18, 0, -1, 19, -1, 20, -1, 19, 12, 20,
+ -1, 21, -1, 20, 14, 21, -1, 22, -1, 21,
+ 13, 22, -1, 23, -1, 22, 8, 23, -1, 22,
+ 9, 23, -1, 24, -1, 23, 3, 24, -1, 23,
+ 4, 24, -1, 25, -1, 24, 5, 25, -1, 24,
+ 6, 25, -1, 24, 7, 25, -1, 16, -1, 10,
+ 19, 11, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned char yyrline[] =
+{
+ 0, 94, 94, 100, 103, 107, 110, 114, 117, 121,
+ 124, 127, 132, 135, 138, 142, 145, 148, 151, 155,
+ 158
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "exp_PLUS", "exp_MINUS", "exp_TIMES",
+ "exp_DIVIDE", "exp_MOD", "exp_SHIFTLEFT", "exp_SHIFTRIGHT",
+ "exp_OPENPARENT", "exp_CLOSEPARENT", "exp_OR", "exp_AND", "exp_XOR",
+ "exp_NOT", "exp_NUMBER", "$accept", "Start", "exp", "bitwiseor",
+ "bitwisexor", "bitwiseand", "shift", "term", "factor", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short int yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 17, 18, 19, 19, 20, 20, 21, 21, 22,
+ 22, 22, 23, 23, 23, 24, 24, 24, 24, 25,
+ 25
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 1, 1, 3, 1, 3, 1, 3, 1,
+ 3, 3, 1, 3, 3, 1, 3, 3, 3, 1,
+ 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 0, 0, 19, 0, 2, 3, 5, 7, 9, 12,
+ 15, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 20, 4, 6, 8, 10, 11, 13,
+ 14, 16, 17, 18
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+ -1, 3, 4, 5, 6, 7, 8, 9, 10
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -14
+static const yysigned_char yypact[] =
+{
+ -10, -10, -14, 18, 7, 6, 8, 2, 1, -4,
+ -14, 3, -14, -10, -10, -10, -10, -10, -10, -10,
+ -10, -10, -10, -14, 6, 8, 2, 1, 1, -4,
+ -4, -14, -14, -14
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yysigned_char yypgoto[] =
+{
+ -14, -14, 21, 10, 11, 9, 0, -6, -13
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const unsigned char yytable[] =
+{
+ 1, 20, 21, 22, 18, 19, 2, 31, 32, 33,
+ 16, 17, 29, 30, 23, 13, 27, 28, 12, 13,
+ 14, 15, 11, 24, 26, 25
+};
+
+static const unsigned char yycheck[] =
+{
+ 10, 5, 6, 7, 3, 4, 16, 20, 21, 22,
+ 8, 9, 18, 19, 11, 12, 16, 17, 0, 12,
+ 14, 13, 1, 13, 15, 14
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 10, 16, 18, 19, 20, 21, 22, 23, 24,
+ 25, 19, 0, 12, 14, 13, 8, 9, 3, 4,
+ 5, 6, 7, 11, 20, 21, 22, 23, 23, 24,
+ 24, 25, 25, 25
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ ((Current).first_line = (Rhs)[1].first_line, \
+ (Current).first_column = (Rhs)[1].first_column, \
+ (Current).last_line = (Rhs)[N].last_line, \
+ (Current).last_column = (Rhs)[N].last_column)
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval)
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short int *bottom, short int *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short int *bottom;
+ short int *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if defined (YYMAXDEPTH) && YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ /* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ short int yyssa[YYINITDEPTH];
+ short int *yyss = yyssa;
+ short int *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short int *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short int *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+
+ {
+ yyGetParser->SetResult(yyvsp[0].Number);
+}
+ break;
+
+ case 3:
+
+ {yyval.Number = yyvsp[0].Number;}
+ break;
+
+ case 4:
+
+ {yyval.Number = yyvsp[-2].Number | yyvsp[0].Number;}
+ break;
+
+ case 5:
+
+ {yyval.Number = yyvsp[0].Number;}
+ break;
+
+ case 6:
+
+ {yyval.Number = yyvsp[-2].Number ^ yyvsp[0].Number;}
+ break;
+
+ case 7:
+
+ {yyval.Number = yyvsp[0].Number;}
+ break;
+
+ case 8:
+
+ {yyval.Number = yyvsp[-2].Number & yyvsp[0].Number;}
+ break;
+
+ case 9:
+
+ {yyval.Number = yyvsp[0].Number;}
+ break;
+
+ case 10:
+
+ {yyval.Number = yyvsp[-2].Number << yyvsp[0].Number;}
+ break;
+
+ case 11:
+
+ {yyval.Number = yyvsp[-2].Number >> yyvsp[0].Number;}
+ break;
+
+ case 12:
+
+ {yyval.Number = yyvsp[0].Number;}
+ break;
+
+ case 13:
+
+ {yyval.Number = yyvsp[-2].Number + yyvsp[0].Number;}
+ break;
+
+ case 14:
+
+ {yyval.Number = yyvsp[-2].Number - yyvsp[0].Number;}
+ break;
+
+ case 15:
+
+ {yyval.Number = yyvsp[0].Number;}
+ break;
+
+ case 16:
+
+ {yyval.Number = yyvsp[-2].Number * yyvsp[0].Number;}
+ break;
+
+ case 17:
+
+ {yyval.Number = yyvsp[-2].Number / yyvsp[0].Number;}
+ break;
+
+ case 18:
+
+ {yyval.Number = yyvsp[-2].Number % yyvsp[0].Number;}
+ break;
+
+ case 19:
+
+ {yyval.Number = yyvsp[0].Number;}
+ break;
+
+ case 20:
+
+ {yyval.Number = yyvsp[-1].Number;}
+ break;
+
+
+ }
+
+/* Line 1010 of yacc.c. */
+
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ const char* yyprefix;
+ char *yymsg;
+ int yyx;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 0;
+
+ yyprefix = ", expecting ";
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
+ yycount += 1;
+ if (yycount == 5)
+ {
+ yysize = 0;
+ break;
+ }
+ }
+ yysize += (sizeof ("syntax error, unexpected ")
+ + yystrlen (yytname[yytype]));
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yyprefix = ", expecting ";
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ yyp = yystpcpy (yyp, yyprefix);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yyprefix = " or ";
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* If at end of input, pop the error token,
+ then the rest of the stack, then return failure. */
+ if (yychar == YYEOF)
+ for (;;)
+ {
+ YYPOPSTACK;
+ if (yyssp == yyss)
+ YYABORT;
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ }
+ }
+ else
+ {
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
+ yychar = YYEMPTY;
+
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+#if defined( __GNUC__ ) || defined(__HP_aCC)
+ /* Pacify GCC when the user code never invokes YYERROR and the label
+ yyerrorlab therefore never appears in user code. */
+ if (0)
+ goto yyerrorlab;
+#endif
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ YYPOPSTACK;
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+
+
+/* End of grammar */
+
+/*--------------------------------------------------------------------------*/
+void cmExprError(yyscan_t yyscanner, const char* message)
+{
+ yyGetParser->Error(message);
+}
+
+
diff --git a/Source/cmExprParser.y b/Source/cmExprParser.y
new file mode 100644
index 0000000..f2c85d0
--- /dev/null
+++ b/Source/cmExprParser.y
@@ -0,0 +1,164 @@
+%{
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --yacc --name-prefix=cmExpr_yy --defines=cmExprParserTokens.h -ocmExprParser.cxx cmExprParser.y
+
+Modify cmExprParser.cxx:
+ - remove TABs
+ - remove use of the 'register' storage class specifier
+ - add __HP_aCC to the #if test for yyerrorlab warning suppression
+
+*/
+
+/* Configure the parser to use a lexer object. */
+#define YYPARSE_PARAM yyscanner
+#define YYLEX_PARAM yyscanner
+#define YYERROR_VERBOSE 1
+#define cmExpr_yyerror(x) \
+ cmExprError(yyscanner, x)
+#define yyGetParser (cmExpr_yyget_extra(yyscanner))
+
+/*-------------------------------------------------------------------------*/
+#include "cmExprParserHelper.h" /* Interface to parser object. */
+#include "cmExprLexer.h" /* Interface to lexer object. */
+#include "cmExprParserTokens.h" /* Need YYSTYPE for YY_DECL. */
+
+#include <math.h>
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Internal utility functions. */
+static void cmExprError(yyscan_t yyscanner, const char* message);
+
+#define YYDEBUG 1
+//#define YYMAXDEPTH 100000
+//#define YYINITDEPTH 10000
+
+
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch statement contains default but no case. */
+#endif
+%}
+
+/* Generate a reentrant parser object. */
+%pure_parser
+
+/*-------------------------------------------------------------------------*/
+/* Tokens */
+%token exp_PLUS
+%token exp_MINUS
+%token exp_TIMES
+%token exp_DIVIDE
+%token exp_MOD
+%token exp_SHIFTLEFT
+%token exp_SHIFTRIGHT
+%token exp_OPENPARENT
+%token exp_CLOSEPARENT
+%token exp_OR;
+%token exp_AND;
+%token exp_XOR;
+%token exp_NOT;
+%token exp_NUMBER;
+
+/*-------------------------------------------------------------------------*/
+/* grammar */
+%%
+
+
+Start:
+exp
+{
+ yyGetParser->SetResult($<Number>1);
+}
+
+exp:
+bitwiseor
+{$<Number>$ = $<Number>1;}
+|
+exp exp_OR bitwiseor
+{$<Number>$ = $<Number>1 | $<Number>3;}
+
+bitwiseor:
+bitwisexor
+{$<Number>$ = $<Number>1;}
+|
+bitwiseor exp_XOR bitwisexor
+{$<Number>$ = $<Number>1 ^ $<Number>3;}
+
+bitwisexor:
+bitwiseand
+{$<Number>$ = $<Number>1;}
+|
+bitwisexor exp_AND bitwiseand
+{$<Number>$ = $<Number>1 & $<Number>3;}
+
+bitwiseand:
+shift
+{$<Number>$ = $<Number>1;}
+|
+bitwiseand exp_SHIFTLEFT shift
+{$<Number>$ = $<Number>1 << $<Number>3;}
+|
+bitwiseand exp_SHIFTRIGHT shift
+{$<Number>$ = $<Number>1 >> $<Number>3;}
+
+
+shift:
+term
+{$<Number>$ = $<Number>1;}
+|
+shift exp_PLUS term
+{$<Number>$ = $<Number>1 + $<Number>3;}
+|
+shift exp_MINUS term
+{$<Number>$ = $<Number>1 - $<Number>3;}
+
+term:
+factor
+{$<Number>$ = $<Number>1;}
+|
+term exp_TIMES factor
+{$<Number>$ = $<Number>1 * $<Number>3;}
+|
+term exp_DIVIDE factor
+{$<Number>$ = $<Number>1 / $<Number>3;}
+|
+term exp_MOD factor
+{$<Number>$ = $<Number>1 % $<Number>3;}
+
+factor:
+exp_NUMBER
+{$<Number>$ = $<Number>1;}
+|
+exp_OPENPARENT exp exp_CLOSEPARENT
+{$<Number>$ = $<Number>2;}
+;
+
+
+%%
+/* End of grammar */
+
+/*--------------------------------------------------------------------------*/
+void cmExprError(yyscan_t yyscanner, const char* message)
+{
+ yyGetParser->Error(message);
+}
+
diff --git a/Source/cmExprParserHelper.cxx b/Source/cmExprParserHelper.cxx
new file mode 100644
index 0000000..0771a4e
--- /dev/null
+++ b/Source/cmExprParserHelper.cxx
@@ -0,0 +1,101 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmExprParserHelper.h"
+
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include "cmExprLexer.h"
+
+int cmExpr_yyparse(yyscan_t yyscanner);
+//
+cmExprParserHelper::cmExprParserHelper()
+{
+ this->FileLine = -1;
+ this->FileName = CM_NULLPTR;
+}
+
+cmExprParserHelper::~cmExprParserHelper()
+{
+ this->CleanupParser();
+}
+
+int cmExprParserHelper::ParseString(const char* str, int verb)
+{
+ if (!str) {
+ return 0;
+ }
+ // printf("Do some parsing: %s\n", str);
+
+ this->Verbose = verb;
+ this->InputBuffer = str;
+ this->InputBufferPos = 0;
+ this->CurrentLine = 0;
+
+ this->Result = 0;
+
+ yyscan_t yyscanner;
+ cmExpr_yylex_init(&yyscanner);
+ cmExpr_yyset_extra(this, yyscanner);
+ int res = cmExpr_yyparse(yyscanner);
+ cmExpr_yylex_destroy(yyscanner);
+ if (res != 0) {
+ // str << "CAL_Parser returned: " << res << std::endl;
+ // std::cerr << "When parsing: [" << str << "]" << std::endl;
+ return 0;
+ }
+
+ this->CleanupParser();
+
+ if (Verbose) {
+ std::cerr << "Expanding [" << str << "] produced: [" << this->Result << "]"
+ << std::endl;
+ }
+ return 1;
+}
+
+void cmExprParserHelper::CleanupParser()
+{
+}
+
+int cmExprParserHelper::LexInput(char* buf, int maxlen)
+{
+ // std::cout << "JPLexInput ";
+ // std::cout.write(buf, maxlen);
+ // std::cout << std::endl;
+ if (maxlen < 1) {
+ return 0;
+ }
+ if (this->InputBufferPos < this->InputBuffer.size()) {
+ buf[0] = this->InputBuffer[this->InputBufferPos++];
+ if (buf[0] == '\n') {
+ this->CurrentLine++;
+ }
+ return (1);
+ } else {
+ buf[0] = '\n';
+ return (0);
+ }
+}
+
+void cmExprParserHelper::Error(const char* str)
+{
+ unsigned long pos = static_cast<unsigned long>(this->InputBufferPos);
+ std::ostringstream ostr;
+ ostr << str << " (" << pos << ")";
+ this->ErrorString = ostr.str();
+}
+
+void cmExprParserHelper::SetResult(int value)
+{
+ this->Result = value;
+}
diff --git a/Source/cmExprParserHelper.h b/Source/cmExprParserHelper.h
new file mode 100644
index 0000000..af0b916
--- /dev/null
+++ b/Source/cmExprParserHelper.h
@@ -0,0 +1,69 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExprParserHelper_h
+#define cmExprParserHelper_h
+
+#include "cmStandardIncludes.h"
+
+#define YYSTYPE cmExprParserHelper::ParserType
+#define YYSTYPE_IS_DECLARED
+#define YY_EXTRA_TYPE cmExprParserHelper*
+#define YY_DECL int cmExpr_yylex(YYSTYPE* yylvalp, yyscan_t yyscanner)
+
+/** \class cmExprParserHelper
+ * \brief Helper class for parsing java source files
+ *
+ * Finds dependencies for java file and list of outputs
+ */
+
+class cmMakefile;
+
+class cmExprParserHelper
+{
+public:
+ typedef struct
+ {
+ int Number;
+ } ParserType;
+
+ cmExprParserHelper();
+ ~cmExprParserHelper();
+
+ int ParseString(const char* str, int verb);
+
+ int LexInput(char* buf, int maxlen);
+ void Error(const char* str);
+
+ void SetResult(int value);
+
+ int GetResult() { return this->Result; }
+
+ const char* GetError() { return this->ErrorString.c_str(); }
+
+private:
+ std::string::size_type InputBufferPos;
+ std::string InputBuffer;
+ std::vector<char> OutputBuffer;
+ int CurrentLine;
+ int Verbose;
+
+ void Print(const char* place, const char* str);
+
+ void CleanupParser();
+
+ int Result;
+ const char* FileName;
+ long FileLine;
+ std::string ErrorString;
+};
+
+#endif
diff --git a/Source/cmExprParserTokens.h b/Source/cmExprParserTokens.h
new file mode 100644
index 0000000..0309c09
--- /dev/null
+++ b/Source/cmExprParserTokens.h
@@ -0,0 +1,76 @@
+/* A Bison parser, made by GNU Bison 1.875d. */
+
+/* Skeleton parser for Yacc-like parsing with Bison, Copyright (C) 1984,
+ 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ exp_PLUS = 258,
+ exp_MINUS = 259,
+ exp_TIMES = 260,
+ exp_DIVIDE = 261,
+ exp_MOD = 262,
+ exp_SHIFTLEFT = 263,
+ exp_SHIFTRIGHT = 264,
+ exp_OPENPARENT = 265,
+ exp_CLOSEPARENT = 266,
+ exp_OR = 267,
+ exp_AND = 268,
+ exp_XOR = 269,
+ exp_NOT = 270,
+ exp_NUMBER = 271
+ };
+#endif
+#define exp_PLUS 258
+#define exp_MINUS 259
+#define exp_TIMES 260
+#define exp_DIVIDE 261
+#define exp_MOD 262
+#define exp_SHIFTLEFT 263
+#define exp_SHIFTRIGHT 264
+#define exp_OPENPARENT 265
+#define exp_CLOSEPARENT 266
+#define exp_OR 267
+#define exp_AND 268
+#define exp_XOR 269
+#define exp_NOT 270
+#define exp_NUMBER 271
+
+
+
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+typedef int YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+
+
diff --git a/Source/cmExternalMakefileProjectGenerator.cxx b/Source/cmExternalMakefileProjectGenerator.cxx
new file mode 100644
index 0000000..0e42d75
--- /dev/null
+++ b/Source/cmExternalMakefileProjectGenerator.cxx
@@ -0,0 +1,60 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmExternalMakefileProjectGenerator.h"
+
+#include <assert.h>
+
+void cmExternalMakefileProjectGenerator::EnableLanguage(
+ std::vector<std::string> const&, cmMakefile*, bool)
+{
+}
+
+std::string cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
+ const std::string& globalGenerator, const std::string& extraGenerator)
+{
+ std::string fullName;
+ if (!globalGenerator.empty()) {
+ if (!extraGenerator.empty()) {
+ fullName = extraGenerator;
+ fullName += " - ";
+ }
+ fullName += globalGenerator;
+ }
+ return fullName;
+}
+
+std::string cmExternalMakefileProjectGenerator::GetGlobalGeneratorName(
+ const std::string& fullName)
+{
+ // at least one global generator must be supported
+ assert(!this->SupportedGlobalGenerators.empty());
+
+ if (fullName.empty()) {
+ return "";
+ }
+
+ // if we get only the short name, take the first global generator as default
+ if (fullName == this->GetName()) {
+ return this->SupportedGlobalGenerators[0];
+ }
+
+ // otherwise search for the matching global generator
+ for (std::vector<std::string>::const_iterator it =
+ this->SupportedGlobalGenerators.begin();
+ it != this->SupportedGlobalGenerators.end(); ++it) {
+ if (this->CreateFullGeneratorName(*it, this->GetName()) == fullName) {
+ return *it;
+ }
+ }
+ return "";
+}
diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h
new file mode 100644
index 0000000..5d4d54d
--- /dev/null
+++ b/Source/cmExternalMakefileProjectGenerator.h
@@ -0,0 +1,76 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExternalMakefileProjectGenerator_h
+#define cmExternalMakefileProjectGenerator_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmDocumentation.h"
+
+class cmGlobalGenerator;
+
+/** \class cmExternalMakefileProjectGenerator
+ * \brief Base class for generators for "External Makefile based IDE projects".
+ *
+ * cmExternalMakefileProjectGenerator is a base class for generators
+ * for "external makefile based projects", i.e. IDE projects which work
+ * an already existing makefiles.
+ * See cmGlobalKdevelopGenerator as an example.
+ * After the makefiles have been generated by one of the Makefile
+ * generators, the Generate() method is called and this generator
+ * can iterate over the local generators and/or projects to produce the
+ * project files for the IDE.
+ */
+class cmExternalMakefileProjectGenerator
+{
+public:
+ virtual ~cmExternalMakefileProjectGenerator() {}
+
+ ///! Get the name for this generator.
+ virtual std::string GetName() const = 0;
+ /** Get the documentation entry for this generator. */
+ virtual void GetDocumentation(cmDocumentationEntry& entry,
+ const std::string& fullName) const = 0;
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+
+ ///! 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
+ const std::vector<std::string>& GetSupportedGlobalGenerators() const
+ {
+ return this->SupportedGlobalGenerators;
+ }
+
+ ///! Get the name of the global generator for the given full name
+ std::string GetGlobalGeneratorName(const std::string& fullName);
+ /** Create a full name from the given global generator name and the
+ * extra generator name
+ */
+ static std::string CreateFullGeneratorName(
+ const std::string& globalGenerator, const std::string& extraGenerator);
+
+ ///! Generate the project files, the Makefiles have already been generated
+ virtual void Generate() = 0;
+
+protected:
+ ///! Contains the names of the global generators support by this generator.
+ std::vector<std::string> SupportedGlobalGenerators;
+ ///! the global generator which creates the makefiles
+ const cmGlobalGenerator* GlobalGenerator;
+};
+
+#endif
diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx
new file mode 100644
index 0000000..fbfbccc
--- /dev/null
+++ b/Source/cmExtraCodeBlocksGenerator.cxx
@@ -0,0 +1,774 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2009 Kitware, Inc.
+ Copyright 2004 Alexander Neundorf (neundorf@kde.org)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmExtraCodeBlocksGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+#include <cmsys/SystemTools.hxx>
+
+/* Some useful URLs:
+Homepage:
+http://www.codeblocks.org
+
+File format docs:
+http://wiki.codeblocks.org/index.php?title=File_formats_description
+http://wiki.codeblocks.org/index.php?title=Workspace_file
+http://wiki.codeblocks.org/index.php?title=Project_file
+
+Discussion:
+http://forums.codeblocks.org/index.php/topic,6789.0.html
+*/
+
+void cmExtraCodeBlocksGenerator::GetDocumentation(cmDocumentationEntry& entry,
+ const std::string&) const
+{
+ entry.Name = this->GetName();
+ entry.Brief = "Generates CodeBlocks project files.";
+}
+
+cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator()
+ : cmExternalMakefileProjectGenerator()
+{
+#if defined(_WIN32)
+ this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
+ this->SupportedGlobalGenerators.push_back("NMake Makefiles");
+// disable until somebody actually tests it:
+// this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
+#endif
+ this->SupportedGlobalGenerators.push_back("Ninja");
+ this->SupportedGlobalGenerators.push_back("Unix Makefiles");
+}
+
+void cmExtraCodeBlocksGenerator::Generate()
+{
+ // for each sub project in the project create a codeblocks project
+ for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
+ it = this->GlobalGenerator->GetProjectMap().begin();
+ it != this->GlobalGenerator->GetProjectMap().end(); ++it) {
+ // create a project file
+ this->CreateProjectFile(it->second);
+ }
+}
+
+/* create the project file */
+void cmExtraCodeBlocksGenerator::CreateProjectFile(
+ const std::vector<cmLocalGenerator*>& lgs)
+{
+ std::string outputDir = lgs[0]->GetCurrentBinaryDirectory();
+ std::string projectName = lgs[0]->GetProjectName();
+
+ std::string filename = outputDir + "/";
+ filename += projectName + ".cbp";
+ std::string sessionFilename = outputDir + "/";
+ sessionFilename += projectName + ".layout";
+
+ this->CreateNewProjectFile(lgs, filename);
+}
+
+/* Tree is used to create a "Virtual Folder" in CodeBlocks, in which all
+ CMake files this project depends on will be put. This means additionally
+ to the "Sources" and "Headers" virtual folders of CodeBlocks, there will
+ now also be a "CMake Files" virtual folder.
+ Patch by Daniel Teske <daniel.teske AT nokia.com> (which use C::B project
+ files in QtCreator).*/
+struct Tree
+{
+ std::string path; // only one component of the path
+ std::vector<Tree> folders;
+ std::vector<std::string> files;
+ void InsertPath(const std::vector<std::string>& splitted,
+ std::vector<std::string>::size_type start,
+ const std::string& fileName);
+ void BuildVirtualFolder(cmXMLWriter& xml) const;
+ void BuildVirtualFolderImpl(std::string& virtualFolders,
+ const std::string& prefix) const;
+ void BuildUnit(cmXMLWriter& xml, const std::string& fsPath) const;
+ void BuildUnitImpl(cmXMLWriter& xml, const std::string& virtualFolderPath,
+ const std::string& fsPath) const;
+};
+
+void Tree::InsertPath(const std::vector<std::string>& splitted,
+ std::vector<std::string>::size_type start,
+ const std::string& fileName)
+{
+ if (start == splitted.size()) {
+ files.push_back(fileName);
+ return;
+ }
+ for (std::vector<Tree>::iterator it = folders.begin(); it != folders.end();
+ ++it) {
+ if ((*it).path == splitted[start]) {
+ if (start + 1 < splitted.size()) {
+ it->InsertPath(splitted, start + 1, fileName);
+ return;
+ } else {
+ // last part of splitted
+ it->files.push_back(fileName);
+ return;
+ }
+ }
+ }
+ // Not found in folders, thus insert
+ Tree newFolder;
+ newFolder.path = splitted[start];
+ if (start + 1 < splitted.size()) {
+ newFolder.InsertPath(splitted, start + 1, fileName);
+ folders.push_back(newFolder);
+ return;
+ } else {
+ // last part of splitted
+ newFolder.files.push_back(fileName);
+ folders.push_back(newFolder);
+ return;
+ }
+}
+
+void Tree::BuildVirtualFolder(cmXMLWriter& xml) const
+{
+ xml.StartElement("Option");
+ std::string virtualFolders = "CMake Files\\;";
+ for (std::vector<Tree>::const_iterator it = folders.begin();
+ it != folders.end(); ++it) {
+ it->BuildVirtualFolderImpl(virtualFolders, "");
+ }
+ xml.Attribute("virtualFolders", virtualFolders);
+ xml.EndElement();
+}
+
+void Tree::BuildVirtualFolderImpl(std::string& virtualFolders,
+ const std::string& prefix) const
+{
+ virtualFolders += "CMake Files\\" + prefix + path + "\\;";
+ for (std::vector<Tree>::const_iterator it = folders.begin();
+ it != folders.end(); ++it) {
+ it->BuildVirtualFolderImpl(virtualFolders, prefix + path + "\\");
+ }
+}
+
+void Tree::BuildUnit(cmXMLWriter& xml, const std::string& fsPath) const
+{
+ for (std::vector<std::string>::const_iterator it = files.begin();
+ it != files.end(); ++it) {
+ xml.StartElement("Unit");
+ xml.Attribute("filename", fsPath + *it);
+
+ xml.StartElement("Option");
+ xml.Attribute("virtualFolder", "CMake Files\\");
+ xml.EndElement();
+
+ xml.EndElement();
+ }
+ for (std::vector<Tree>::const_iterator it = folders.begin();
+ it != folders.end(); ++it) {
+ it->BuildUnitImpl(xml, "", fsPath);
+ }
+}
+
+void Tree::BuildUnitImpl(cmXMLWriter& xml,
+ const std::string& virtualFolderPath,
+ const std::string& fsPath) const
+{
+ for (std::vector<std::string>::const_iterator it = files.begin();
+ it != files.end(); ++it) {
+ xml.StartElement("Unit");
+ xml.Attribute("filename", fsPath + path + "/" + *it);
+
+ xml.StartElement("Option");
+ xml.Attribute("virtualFolder",
+ "CMake Files\\" + virtualFolderPath + path + "\\");
+ xml.EndElement();
+
+ xml.EndElement();
+ }
+ for (std::vector<Tree>::const_iterator it = folders.begin();
+ it != folders.end(); ++it) {
+ it->BuildUnitImpl(xml, virtualFolderPath + path + "\\",
+ fsPath + path + "/");
+ }
+}
+
+void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
+ const std::vector<cmLocalGenerator*>& lgs, const std::string& filename)
+{
+ const cmMakefile* mf = lgs[0]->GetMakefile();
+ cmGeneratedFileStream fout(filename.c_str());
+ if (!fout) {
+ return;
+ }
+
+ Tree tree;
+
+ // build tree of virtual folders
+ for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
+ it = this->GlobalGenerator->GetProjectMap().begin();
+ it != this->GlobalGenerator->GetProjectMap().end(); ++it) {
+ // Collect all files
+ std::vector<std::string> listFiles;
+ for (std::vector<cmLocalGenerator*>::const_iterator jt =
+ it->second.begin();
+ jt != it->second.end(); ++jt) {
+ const std::vector<std::string>& files =
+ (*jt)->GetMakefile()->GetListFiles();
+ listFiles.insert(listFiles.end(), files.begin(), files.end());
+ }
+
+ // Convert
+ for (std::vector<std::string>::const_iterator jt = listFiles.begin();
+ jt != listFiles.end(); ++jt) {
+ // don't put cmake's own files into the project (#12110):
+ if (jt->find(cmSystemTools::GetCMakeRoot()) == 0) {
+ continue;
+ }
+
+ const std::string& relative = cmSystemTools::RelativePath(
+ it->second[0]->GetSourceDirectory(), jt->c_str());
+ std::vector<std::string> splitted;
+ cmSystemTools::SplitPath(relative, splitted, false);
+ // Split filename from path
+ std::string fileName = *(splitted.end() - 1);
+ splitted.erase(splitted.end() - 1, splitted.end());
+
+ // We don't want paths with CMakeFiles in them
+ // or do we?
+ // In speedcrunch those where purely internal
+ if (!splitted.empty() &&
+ relative.find("CMakeFiles") == std::string::npos) {
+ tree.InsertPath(splitted, 1, fileName);
+ }
+ }
+ }
+
+ // figure out the compiler
+ std::string compiler = this->GetCBCompilerId(mf);
+ std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string makeArgs =
+ mf->GetSafeDefinition("CMAKE_CODEBLOCKS_MAKE_ARGUMENTS");
+
+ cmXMLWriter xml(fout);
+ xml.StartDocument();
+ xml.StartElement("CodeBlocks_project_file");
+
+ xml.StartElement("FileVersion");
+ xml.Attribute("major", 1);
+ xml.Attribute("minor", 6);
+ xml.EndElement();
+
+ xml.StartElement("Project");
+
+ xml.StartElement("Option");
+ xml.Attribute("title", lgs[0]->GetProjectName());
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("makefile_is_custom", 1);
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("compiler", compiler);
+ xml.EndElement();
+
+ // Now build a virtual tree
+ tree.BuildVirtualFolder(xml);
+
+ xml.StartElement("Build");
+
+ this->AppendTarget(xml, "all", CM_NULLPTR, make.c_str(), lgs[0],
+ compiler.c_str(), makeArgs);
+
+ // add all executable and library targets and some of the GLOBAL
+ // and UTILITY targets
+ for (std::vector<cmLocalGenerator*>::const_iterator lg = lgs.begin();
+ lg != lgs.end(); lg++) {
+ std::vector<cmGeneratorTarget*> targets = (*lg)->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator ti = targets.begin();
+ ti != targets.end(); ti++) {
+ std::string targetName = (*ti)->GetName();
+ switch ((*ti)->GetType()) {
+ case cmState::GLOBAL_TARGET: {
+ // Only add the global targets from CMAKE_BINARY_DIR,
+ // not from the subdirs
+ if (strcmp((*lg)->GetCurrentBinaryDirectory(),
+ (*lg)->GetBinaryDirectory()) == 0) {
+ this->AppendTarget(xml, targetName, CM_NULLPTR, make.c_str(), *lg,
+ compiler.c_str(), makeArgs);
+ }
+ } break;
+ case cmState::UTILITY:
+ // Add all utility targets, except the Nightly/Continuous/
+ // Experimental-"sub"targets as e.g. NightlyStart
+ if (((targetName.find("Nightly") == 0) &&
+ (targetName != "Nightly")) ||
+ ((targetName.find("Continuous") == 0) &&
+ (targetName != "Continuous")) ||
+ ((targetName.find("Experimental") == 0) &&
+ (targetName != "Experimental"))) {
+ break;
+ }
+
+ this->AppendTarget(xml, targetName, CM_NULLPTR, make.c_str(), *lg,
+ compiler.c_str(), makeArgs);
+ break;
+ case cmState::EXECUTABLE:
+ case cmState::STATIC_LIBRARY:
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ case cmState::OBJECT_LIBRARY: {
+ cmGeneratorTarget* gt = *ti;
+ this->AppendTarget(xml, targetName, gt, make.c_str(), *lg,
+ compiler.c_str(), makeArgs);
+ std::string fastTarget = targetName;
+ fastTarget += "/fast";
+ this->AppendTarget(xml, fastTarget, gt, make.c_str(), *lg,
+ compiler.c_str(), makeArgs);
+ } break;
+ default:
+ break;
+ }
+ }
+ }
+
+ xml.EndElement(); // Build
+
+ // Collect all used source files in the project.
+ // Keep a list of C/C++ source files which might have an acompanying header
+ // that should be looked for.
+ typedef std::map<std::string, CbpUnit> all_files_map_t;
+ all_files_map_t allFiles;
+ std::vector<std::string> cFiles;
+
+ std::vector<std::string> srcExts =
+ this->GlobalGenerator->GetCMakeInstance()->GetSourceExtensions();
+
+ for (std::vector<cmLocalGenerator*>::const_iterator lg = lgs.begin();
+ lg != lgs.end(); lg++) {
+ cmMakefile* makefile = (*lg)->GetMakefile();
+ std::vector<cmGeneratorTarget*> targets = (*lg)->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator ti = targets.begin();
+ ti != targets.end(); ti++) {
+ switch ((*ti)->GetType()) {
+ case cmState::EXECUTABLE:
+ case cmState::STATIC_LIBRARY:
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ case cmState::OBJECT_LIBRARY:
+ case cmState::UTILITY: // can have sources since 2.6.3
+ {
+ std::vector<cmSourceFile*> sources;
+ cmGeneratorTarget* gt = *ti;
+ gt->GetSourceFiles(sources,
+ makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ for (std::vector<cmSourceFile*>::const_iterator si = sources.begin();
+ si != sources.end(); si++) {
+ // don't add source files from UTILITY target which have the
+ // GENERATED property set:
+ if (gt->GetType() == cmState::UTILITY &&
+ (*si)->GetPropertyAsBool("GENERATED")) {
+ continue;
+ }
+
+ // check whether it is a C/C++ implementation file
+ bool isCFile = false;
+ std::string lang = (*si)->GetLanguage();
+ if (lang == "C" || lang == "CXX") {
+ std::string srcext = (*si)->GetExtension();
+ for (std::vector<std::string>::const_iterator ext =
+ srcExts.begin();
+ ext != srcExts.end(); ++ext) {
+ if (srcext == *ext) {
+ isCFile = true;
+ break;
+ }
+ }
+ }
+
+ std::string fullPath = (*si)->GetFullPath();
+
+ if (isCFile) {
+ cFiles.push_back(fullPath);
+ }
+
+ CbpUnit& cbpUnit = allFiles[fullPath];
+ cbpUnit.Targets.push_back(*ti);
+ }
+ }
+ default: // intended fallthrough
+ break;
+ }
+ }
+ }
+
+ std::vector<std::string> headerExts =
+ this->GlobalGenerator->GetCMakeInstance()->GetHeaderExtensions();
+
+ // The following loop tries to add header files matching to implementation
+ // files to the project. It does that by iterating over all
+ // C/C++ source files,
+ // replacing the file name extension with ".h" and checks whether such a
+ // file exists. If it does, it is inserted into the map of files.
+ // A very similar version of that code exists also in the kdevelop
+ // project generator.
+ for (std::vector<std::string>::const_iterator sit = cFiles.begin();
+ sit != cFiles.end(); ++sit) {
+ std::string const& fileName = *sit;
+ std::string headerBasename = cmSystemTools::GetFilenamePath(fileName);
+ headerBasename += "/";
+ headerBasename += cmSystemTools::GetFilenameWithoutExtension(fileName);
+
+ // check if there's a matching header around
+ for (std::vector<std::string>::const_iterator ext = headerExts.begin();
+ ext != headerExts.end(); ++ext) {
+ std::string hname = headerBasename;
+ hname += ".";
+ hname += *ext;
+ // if it's already in the set, don't check if it exists on disk
+ if (allFiles.find(hname) != allFiles.end()) {
+ break;
+ }
+
+ if (cmSystemTools::FileExists(hname.c_str())) {
+ allFiles[hname].Targets = allFiles[fileName].Targets;
+ break;
+ }
+ }
+ }
+
+ // insert all source files in the CodeBlocks project
+ for (all_files_map_t::const_iterator sit = allFiles.begin();
+ sit != allFiles.end(); ++sit) {
+ std::string const& unitFilename = sit->first;
+ CbpUnit const& unit = sit->second;
+
+ xml.StartElement("Unit");
+ xml.Attribute("filename", unitFilename);
+
+ for (std::vector<const cmGeneratorTarget*>::const_iterator ti =
+ unit.Targets.begin();
+ ti != unit.Targets.end(); ++ti) {
+ xml.StartElement("Option");
+ xml.Attribute("target", (*ti)->GetName());
+ xml.EndElement();
+ }
+
+ xml.EndElement();
+ }
+
+ // Add CMakeLists.txt
+ tree.BuildUnit(xml, std::string(mf->GetHomeDirectory()) + "/");
+
+ xml.EndElement(); // Project
+ xml.EndElement(); // CodeBlocks_project_file
+ xml.EndDocument();
+}
+
+// Write a dummy file for OBJECT libraries, so C::B can reference some file
+std::string cmExtraCodeBlocksGenerator::CreateDummyTargetFile(
+ cmLocalGenerator* lg, cmGeneratorTarget* target) const
+{
+ // this file doesn't seem to be used by C::B in custom makefile mode,
+ // but we generate a unique file for each OBJECT library so in case
+ // C::B uses it in some way, the targets don't interfere with each other.
+ std::string filename = lg->GetCurrentBinaryDirectory();
+ filename += "/";
+ filename += lg->GetTargetDirectory(target);
+ filename += "/";
+ filename += target->GetName();
+ filename += ".objlib";
+ cmGeneratedFileStream fout(filename.c_str());
+ if (fout) {
+ /* clang-format off */
+ fout << "# This is a dummy file for the OBJECT library "
+ << target->GetName()
+ << " for the CMake CodeBlocks project generator.\n"
+ << "# Don't edit, this file will be overwritten.\n";
+ /* clang-format on */
+ }
+ return filename;
+}
+
+// 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)
+{
+ cmMakefile const* makefile = lg->GetMakefile();
+ std::string makefileName = lg->GetCurrentBinaryDirectory();
+ makefileName += "/Makefile";
+
+ xml.StartElement("Target");
+ xml.Attribute("title", targetName);
+
+ if (target != CM_NULLPTR) {
+ int cbTargetType = this->GetCBTargetType(target);
+ std::string workingDir = lg->GetCurrentBinaryDirectory();
+ if (target->GetType() == cmState::EXECUTABLE) {
+ // Determine the directory where the executable target is created, and
+ // set the working directory to this dir.
+ const char* runtimeOutputDir =
+ makefile->GetDefinition("CMAKE_RUNTIME_OUTPUT_DIRECTORY");
+ if (runtimeOutputDir != CM_NULLPTR) {
+ workingDir = runtimeOutputDir;
+ } else {
+ const char* executableOutputDir =
+ makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
+ if (executableOutputDir != CM_NULLPTR) {
+ workingDir = executableOutputDir;
+ }
+ }
+ }
+
+ std::string buildType = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ std::string location;
+ if (target->GetType() == cmState::OBJECT_LIBRARY) {
+ location =
+ this->CreateDummyTargetFile(const_cast<cmLocalGenerator*>(lg), target);
+ } else {
+ location = target->GetLocation(buildType);
+ }
+
+ xml.StartElement("Option");
+ xml.Attribute("output", location);
+ xml.Attribute("prefix_auto", 0);
+ xml.Attribute("extension_auto", 0);
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("working_dir", workingDir);
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("object_output", "./");
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("type", cbTargetType);
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("compiler", compiler);
+ xml.EndElement();
+
+ xml.StartElement("Compiler");
+
+ // the compilerdefines for this target
+ std::vector<std::string> cdefs;
+ target->GetCompileDefinitions(cdefs, buildType, "C");
+
+ // Expand the list.
+ for (std::vector<std::string>::const_iterator di = cdefs.begin();
+ di != cdefs.end(); ++di) {
+ xml.StartElement("Add");
+ xml.Attribute("option", "-D" + *di);
+ xml.EndElement();
+ }
+
+ // 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::string 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());
+ }
+
+ 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());
+ }
+
+ std::vector<std::string>::const_iterator end =
+ cmRemoveDuplicates(allIncludeDirs);
+
+ for (std::vector<std::string>::const_iterator i = allIncludeDirs.begin();
+ i != end; ++i) {
+ xml.StartElement("Add");
+ xml.Attribute("directory", *i);
+ xml.EndElement();
+ }
+
+ xml.EndElement(); // Compiler
+ } else // e.g. all and the GLOBAL and UTILITY targets
+ {
+ xml.StartElement("Option");
+ xml.Attribute("working_dir", lg->GetCurrentBinaryDirectory());
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("type", 4);
+ xml.EndElement();
+ }
+
+ xml.StartElement("MakeCommands");
+
+ xml.StartElement("Build");
+ xml.Attribute("command", this->BuildMakeCommand(make, makefileName.c_str(),
+ targetName, makeFlags));
+ xml.EndElement();
+
+ xml.StartElement("CompileFile");
+ xml.Attribute("command", this->BuildMakeCommand(make, makefileName.c_str(),
+ "\"$file\"", makeFlags));
+ xml.EndElement();
+
+ xml.StartElement("Clean");
+ xml.Attribute("command", this->BuildMakeCommand(make, makefileName.c_str(),
+ "clean", makeFlags));
+ xml.EndElement();
+
+ xml.StartElement("DistClean");
+ xml.Attribute("command", this->BuildMakeCommand(make, makefileName.c_str(),
+ "clean", makeFlags));
+ xml.EndElement();
+
+ xml.EndElement(); // MakeCommands
+ xml.EndElement(); // Target
+}
+
+// Translate the cmake compiler id into the CodeBlocks compiler id
+std::string cmExtraCodeBlocksGenerator::GetCBCompilerId(const cmMakefile* mf)
+{
+ // figure out which language to use
+ // for now care only for C, C++, and Fortran
+
+ // projects with C/C++ and Fortran are handled as C/C++ projects
+ bool pureFortran = false;
+ std::string compilerIdVar;
+ if (this->GlobalGenerator->GetLanguageEnabled("CXX")) {
+ compilerIdVar = "CMAKE_CXX_COMPILER_ID";
+ } else if (this->GlobalGenerator->GetLanguageEnabled("C")) {
+ compilerIdVar = "CMAKE_C_COMPILER_ID";
+ } else if (this->GlobalGenerator->GetLanguageEnabled("Fortran")) {
+ compilerIdVar = "CMAKE_Fortran_COMPILER_ID";
+ pureFortran = true;
+ }
+
+ std::string compilerId = mf->GetSafeDefinition(compilerIdVar);
+ std::string compiler = "gcc"; // default to gcc
+ if (compilerId == "MSVC") {
+ if (mf->IsDefinitionSet("MSVC10")) {
+ compiler = "msvc10";
+ } else {
+ compiler = "msvc8";
+ }
+ } else if (compilerId == "Borland") {
+ compiler = "bcc";
+ } else if (compilerId == "SDCC") {
+ compiler = "sdcc";
+ } else if (compilerId == "Intel") {
+ if (pureFortran && mf->IsDefinitionSet("WIN32")) {
+ compiler = "ifcwin"; // Intel Fortran for Windows (known by cbFortran)
+ } else {
+ compiler = "icc";
+ }
+ } else if (compilerId == "Watcom" || compilerId == "OpenWatcom") {
+ compiler = "ow";
+ } else if (compilerId == "Clang") {
+ compiler = "clang";
+ } else if (compilerId == "PGI") {
+ if (pureFortran) {
+ compiler = "pgifortran";
+ } else {
+ compiler = "pgi"; // does not exist as default in CodeBlocks 16.01
+ }
+ } else if (compilerId == "GNU") {
+ if (pureFortran) {
+ compiler = "gfortran";
+ } else {
+ compiler = "gcc";
+ }
+ }
+ return compiler;
+}
+
+// Translate the cmake target type into the CodeBlocks target type id
+int cmExtraCodeBlocksGenerator::GetCBTargetType(cmGeneratorTarget* target)
+{
+ if (target->GetType() == cmState::EXECUTABLE) {
+ if ((target->GetPropertyAsBool("WIN32_EXECUTABLE")) ||
+ (target->GetPropertyAsBool("MACOSX_BUNDLE"))) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else if ((target->GetType() == cmState::STATIC_LIBRARY) ||
+ (target->GetType() == cmState::OBJECT_LIBRARY)) {
+ return 2;
+ } else if ((target->GetType() == cmState::SHARED_LIBRARY) ||
+ (target->GetType() == cmState::MODULE_LIBRARY)) {
+ return 3;
+ }
+ return 4;
+}
+
+// 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)
+{
+ std::string command = make;
+ if (!makeFlags.empty()) {
+ command += " ";
+ command += makeFlags;
+ }
+
+ std::string generator = this->GlobalGenerator->GetName();
+ if (generator == "NMake Makefiles") {
+ // For Windows ConvertToOutputPath already adds quotes when required.
+ // These need to be escaped, see
+ // http://public.kitware.com/Bug/view.php?id=13952
+ std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
+ command += " /NOLOGO /f ";
+ command += makefileName;
+ command += " VERBOSE=1 ";
+ command += target;
+ } else if (generator == "MinGW Makefiles") {
+ // no escaping of spaces in this case, see
+ // http://public.kitware.com/Bug/view.php?id=10014
+ std::string makefileName = makefile;
+ command += " -f \"";
+ command += makefileName;
+ command += "\" ";
+ command += " VERBOSE=1 ";
+ command += target;
+ } else if (generator == "Ninja") {
+ command += " -v ";
+ command += target;
+ } else {
+ std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
+ command += " -f \"";
+ command += makefileName;
+ command += "\" ";
+ command += " VERBOSE=1 ";
+ command += target;
+ }
+ return command;
+}
diff --git a/Source/cmExtraCodeBlocksGenerator.h b/Source/cmExtraCodeBlocksGenerator.h
new file mode 100644
index 0000000..31ea500
--- /dev/null
+++ b/Source/cmExtraCodeBlocksGenerator.h
@@ -0,0 +1,70 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2009 Kitware, Inc.
+ Copyright 2004 Alexander Neundorf (neundorf@kde.org)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExtraCodeBlocksGenerator_h
+#define cmExtraCodeBlocksGenerator_h
+
+#include "cmExternalMakefileProjectGenerator.h"
+
+class cmLocalGenerator;
+class cmMakefile;
+class cmGeneratorTarget;
+class cmXMLWriter;
+
+/** \class cmExtraCodeBlocksGenerator
+ * \brief Write CodeBlocks project files for Makefile based projects
+ */
+class cmExtraCodeBlocksGenerator : public cmExternalMakefileProjectGenerator
+{
+public:
+ cmExtraCodeBlocksGenerator();
+
+ std::string GetName() const CM_OVERRIDE
+ {
+ return cmExtraCodeBlocksGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "CodeBlocks"; }
+ static cmExternalMakefileProjectGenerator* New()
+ {
+ return new cmExtraCodeBlocksGenerator;
+ }
+ /** Get the documentation entry for this generator. */
+ void GetDocumentation(cmDocumentationEntry& entry,
+ const std::string& fullName) const CM_OVERRIDE;
+
+ void Generate() CM_OVERRIDE;
+
+private:
+ struct CbpUnit
+ {
+ std::vector<const cmGeneratorTarget*> Targets;
+ };
+
+ void CreateProjectFile(const std::vector<cmLocalGenerator*>& lgs);
+
+ void CreateNewProjectFile(const std::vector<cmLocalGenerator*>& lgs,
+ const std::string& filename);
+ std::string CreateDummyTargetFile(cmLocalGenerator* lg,
+ cmGeneratorTarget* target) const;
+
+ std::string GetCBCompilerId(const cmMakefile* mf);
+ int GetCBTargetType(cmGeneratorTarget* target);
+ std::string BuildMakeCommand(const std::string& make, const char* 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,
+ const std::string& makeFlags);
+};
+
+#endif
diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx
new file mode 100644
index 0000000..dd10b65
--- /dev/null
+++ b/Source/cmExtraCodeLiteGenerator.cxx
@@ -0,0 +1,483 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2009 Kitware, Inc.
+ Copyright 2004 Alexander Neundorf (neundorf@kde.org)
+ Copyright 2013 Eran Ifrah (eran.ifrah@gmail.com)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmExtraCodeLiteGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include "cmStandardIncludes.h"
+#include "cmXMLWriter.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/SystemInformation.hxx>
+#include <cmsys/SystemTools.hxx>
+
+void cmExtraCodeLiteGenerator::GetDocumentation(cmDocumentationEntry& entry,
+ const std::string&) const
+{
+ entry.Name = this->GetName();
+ entry.Brief = "Generates CodeLite project files.";
+}
+
+cmExtraCodeLiteGenerator::cmExtraCodeLiteGenerator()
+ : cmExternalMakefileProjectGenerator()
+ , ConfigName("NoConfig")
+ , CpuCount(2)
+{
+#if defined(_WIN32)
+ this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
+ this->SupportedGlobalGenerators.push_back("NMake Makefiles");
+#endif
+ this->SupportedGlobalGenerators.push_back("Ninja");
+ this->SupportedGlobalGenerators.push_back("Unix Makefiles");
+}
+
+void cmExtraCodeLiteGenerator::Generate()
+{
+ // Hold root tree information for creating the workspace
+ std::string workspaceProjectName;
+ std::string workspaceOutputDir;
+ std::string workspaceFileName;
+ std::string workspaceSourcePath;
+
+ const std::map<std::string, std::vector<cmLocalGenerator*> >& projectMap =
+ this->GlobalGenerator->GetProjectMap();
+
+ // loop projects and locate the root project.
+ // and extract the information for creating the worspace
+ for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
+ it = projectMap.begin();
+ it != projectMap.end(); ++it) {
+ const cmMakefile* mf = it->second[0]->GetMakefile();
+ this->ConfigName = GetConfigurationName(mf);
+
+ if (strcmp(it->second[0]->GetCurrentBinaryDirectory(),
+ it->second[0]->GetBinaryDirectory()) == 0) {
+ workspaceOutputDir = it->second[0]->GetCurrentBinaryDirectory();
+ workspaceProjectName = it->second[0]->GetProjectName();
+ workspaceSourcePath = it->second[0]->GetSourceDirectory();
+ workspaceFileName = workspaceOutputDir + "/";
+ workspaceFileName += workspaceProjectName + ".workspace";
+ this->WorkspacePath = it->second[0]->GetCurrentBinaryDirectory();
+ ;
+ break;
+ }
+ }
+
+ cmGeneratedFileStream fout(workspaceFileName.c_str());
+ cmXMLWriter xml(fout);
+
+ xml.StartDocument("utf-8");
+ xml.StartElement("CodeLite_Workspace");
+ xml.Attribute("Name", workspaceProjectName);
+
+ // for each sub project in the workspace create a codelite project
+ for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
+ it = projectMap.begin();
+ it != projectMap.end(); ++it) {
+ // retrive project information
+ std::string outputDir = it->second[0]->GetCurrentBinaryDirectory();
+ std::string projectName = it->second[0]->GetProjectName();
+ std::string filename = outputDir + "/" + projectName + ".project";
+
+ // Make the project file relative to the workspace
+ filename = cmSystemTools::RelativePath(this->WorkspacePath.c_str(),
+ filename.c_str());
+
+ // create a project file
+ this->CreateProjectFile(it->second);
+ xml.StartElement("Project");
+ xml.Attribute("Name", projectName);
+ xml.Attribute("Path", filename);
+ xml.Attribute("Active", "No");
+ xml.EndElement();
+ }
+
+ xml.StartElement("BuildMatrix");
+ xml.StartElement("WorkspaceConfiguration");
+ xml.Attribute("Name", this->ConfigName);
+ xml.Attribute("Selected", "yes");
+
+ for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
+ it = projectMap.begin();
+ it != projectMap.end(); ++it) {
+ // retrive project information
+ std::string projectName = it->second[0]->GetProjectName();
+
+ xml.StartElement("Project");
+ xml.Attribute("Name", projectName);
+ xml.Attribute("ConfigName", this->ConfigName);
+ xml.EndElement();
+ }
+
+ xml.EndElement(); // WorkspaceConfiguration
+ xml.EndElement(); // BuildMatrix
+ xml.EndElement(); // CodeLite_Workspace
+}
+
+/* create the project file */
+void cmExtraCodeLiteGenerator::CreateProjectFile(
+ const std::vector<cmLocalGenerator*>& lgs)
+{
+ std::string outputDir = lgs[0]->GetCurrentBinaryDirectory();
+ std::string projectName = lgs[0]->GetProjectName();
+ std::string filename = outputDir + "/";
+
+ filename += projectName + ".project";
+ this->CreateNewProjectFile(lgs, filename);
+}
+
+void cmExtraCodeLiteGenerator::CreateNewProjectFile(
+ const std::vector<cmLocalGenerator*>& lgs, const std::string& filename)
+{
+ const cmMakefile* mf = lgs[0]->GetMakefile();
+ cmGeneratedFileStream fout(filename.c_str());
+ if (!fout) {
+ return;
+ }
+ cmXMLWriter xml(fout);
+
+ ////////////////////////////////////
+ xml.StartDocument("utf-8");
+ xml.StartElement("CodeLite_Project");
+ xml.Attribute("Name", lgs[0]->GetProjectName());
+ xml.Attribute("InternalType", "");
+
+ // Collect all used source files in the project
+ // Sort them into two containers, one for C/C++ implementation files
+ // which may have an acompanying header, one for all other files
+ std::string projectType;
+
+ std::vector<std::string> srcExts =
+ this->GlobalGenerator->GetCMakeInstance()->GetSourceExtensions();
+ std::vector<std::string> headerExts =
+ this->GlobalGenerator->GetCMakeInstance()->GetHeaderExtensions();
+
+ std::map<std::string, cmSourceFile*> cFiles;
+ std::set<std::string> otherFiles;
+ for (std::vector<cmLocalGenerator*>::const_iterator lg = lgs.begin();
+ lg != lgs.end(); lg++) {
+ cmMakefile* makefile = (*lg)->GetMakefile();
+ std::vector<cmGeneratorTarget*> targets = (*lg)->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator ti = targets.begin();
+ ti != targets.end(); ti++) {
+
+ switch ((*ti)->GetType()) {
+ case cmState::EXECUTABLE: {
+ projectType = "Executable";
+ } break;
+ case cmState::STATIC_LIBRARY: {
+ projectType = "Static Library";
+ } break;
+ case cmState::SHARED_LIBRARY: {
+ projectType = "Dynamic Library";
+ } break;
+ case cmState::MODULE_LIBRARY: {
+ projectType = "Dynamic Library";
+ } break;
+ default: // intended fallthrough
+ break;
+ }
+
+ switch ((*ti)->GetType()) {
+ case cmState::EXECUTABLE:
+ case cmState::STATIC_LIBRARY:
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY: {
+ std::vector<cmSourceFile*> sources;
+ cmGeneratorTarget* gt = *ti;
+ gt->GetSourceFiles(sources,
+ makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ for (std::vector<cmSourceFile*>::const_iterator si = sources.begin();
+ si != sources.end(); si++) {
+ // check whether it is a C/C++ implementation file
+ bool isCFile = false;
+ std::string lang = (*si)->GetLanguage();
+ if (lang == "C" || lang == "CXX") {
+ std::string srcext = (*si)->GetExtension();
+ for (std::vector<std::string>::const_iterator ext =
+ srcExts.begin();
+ ext != srcExts.end(); ++ext) {
+ if (srcext == *ext) {
+ isCFile = true;
+ break;
+ }
+ }
+ }
+
+ // then put it accordingly into one of the two containers
+ if (isCFile) {
+ cFiles[(*si)->GetFullPath()] = *si;
+ } else {
+ otherFiles.insert((*si)->GetFullPath());
+ }
+ }
+ }
+ default: // intended fallthrough
+ break;
+ }
+ }
+ }
+
+ // The following loop tries to add header files matching to implementation
+ // files to the project. It does that by iterating over all source files,
+ // replacing the file name extension with ".h" and checks whether such a
+ // file exists. If it does, it is inserted into the map of files.
+ // A very similar version of that code exists also in the kdevelop
+ // project generator.
+ for (std::map<std::string, cmSourceFile*>::const_iterator sit =
+ cFiles.begin();
+ sit != cFiles.end(); ++sit) {
+ std::string headerBasename = cmSystemTools::GetFilenamePath(sit->first);
+ headerBasename += "/";
+ headerBasename += cmSystemTools::GetFilenameWithoutExtension(sit->first);
+
+ // check if there's a matching header around
+ for (std::vector<std::string>::const_iterator ext = headerExts.begin();
+ ext != headerExts.end(); ++ext) {
+ std::string hname = headerBasename;
+ hname += ".";
+ hname += *ext;
+ // if it's already in the set, don't check if it exists on disk
+ std::set<std::string>::const_iterator headerIt = otherFiles.find(hname);
+ if (headerIt != otherFiles.end()) {
+ break;
+ }
+
+ if (cmSystemTools::FileExists(hname.c_str())) {
+ otherFiles.insert(hname);
+ break;
+ }
+ }
+ }
+
+ // Get the project path ( we need it later to convert files to
+ // their relative path)
+ std::string projectPath = cmSystemTools::GetFilenamePath(filename);
+
+ // Create 2 virtual folders: src and include
+ // and place all the implementation files into the src
+ // folder, the rest goes to the include folder
+ xml.StartElement("VirtualDirectory");
+ xml.Attribute("Name", "src");
+
+ // insert all source files in the codelite project
+ // first the C/C++ implementation files, then all others
+ for (std::map<std::string, cmSourceFile*>::const_iterator sit =
+ cFiles.begin();
+ sit != cFiles.end(); ++sit) {
+ xml.StartElement("File");
+ xml.Attribute("Name", cmSystemTools::RelativePath(projectPath.c_str(),
+ sit->first.c_str()));
+ xml.EndElement();
+ }
+ xml.EndElement(); // VirtualDirectory
+ xml.StartElement("VirtualDirectory");
+ xml.Attribute("Name", "include");
+ for (std::set<std::string>::const_iterator sit = otherFiles.begin();
+ sit != otherFiles.end(); ++sit) {
+ xml.StartElement("File");
+ xml.Attribute(
+ "Name", cmSystemTools::RelativePath(projectPath.c_str(), sit->c_str()));
+ xml.EndElement();
+ }
+ xml.EndElement(); // VirtualDirectory
+
+ // Get the number of CPUs. We use this information for the make -jN
+ // command
+ cmsys::SystemInformation info;
+ info.RunCPUCheck();
+
+ this->CpuCount =
+ info.GetNumberOfLogicalCPU() * info.GetNumberOfPhysicalCPU();
+
+ std::string codeliteCompilerName = this->GetCodeLiteCompilerName(mf);
+
+ xml.StartElement("Settings");
+ xml.Attribute("Type", projectType);
+
+ xml.StartElement("Configuration");
+ xml.Attribute("Name", this->ConfigName);
+ xml.Attribute("CompilerType", this->GetCodeLiteCompilerName(mf));
+ xml.Attribute("DebuggerType", "GNU gdb debugger");
+ xml.Attribute("Type", projectType);
+ xml.Attribute("BuildCmpWithGlobalSettings", "append");
+ xml.Attribute("BuildLnkWithGlobalSettings", "append");
+ xml.Attribute("BuildResWithGlobalSettings", "append");
+
+ xml.StartElement("Compiler");
+ xml.Attribute("Options", "-g");
+ xml.Attribute("Required", "yes");
+ xml.Attribute("PreCompiledHeader", "");
+ xml.StartElement("IncludePath");
+ xml.Attribute("Value", ".");
+ xml.EndElement(); // IncludePath
+ xml.EndElement(); // Compiler
+
+ xml.StartElement("Linker");
+ xml.Attribute("Options", "");
+ xml.Attribute("Required", "yes");
+ xml.EndElement(); // Linker
+
+ xml.StartElement("ResourceCompiler");
+ xml.Attribute("Options", "");
+ xml.Attribute("Required", "no");
+ xml.EndElement(); // ResourceCompiler
+
+ xml.StartElement("General");
+ xml.Attribute("OutputFile", "$(IntermediateDirectory)/$(ProjectName)");
+ xml.Attribute("IntermediateDirectory", "./");
+ xml.Attribute("Command", "./$(ProjectName)");
+ xml.Attribute("CommandArguments", "");
+ xml.Attribute("WorkingDirectory", "$(IntermediateDirectory)");
+ xml.Attribute("PauseExecWhenProcTerminates", "yes");
+ xml.EndElement(); // General
+
+ xml.StartElement("Debugger");
+ xml.Attribute("IsRemote", "no");
+ xml.Attribute("RemoteHostName", "");
+ xml.Attribute("RemoteHostPort", "");
+ xml.Attribute("DebuggerPath", "");
+ xml.Element("PostConnectCommands");
+ xml.Element("StartupCommands");
+ xml.EndElement(); // Debugger
+
+ xml.Element("PreBuild");
+ xml.Element("PostBuild");
+
+ xml.StartElement("CustomBuild");
+ xml.Attribute("Enabled", "yes");
+ xml.Element("RebuildCommand", GetRebuildCommand(mf));
+ xml.Element("CleanCommand", GetCleanCommand(mf));
+ xml.Element("BuildCommand", GetBuildCommand(mf));
+ xml.Element("SingleFileCommand", GetSingleFileBuildCommand(mf));
+ xml.Element("PreprocessFileCommand");
+ xml.Element("WorkingDirectory", "$(WorkspacePath)");
+ xml.EndElement(); // CustomBuild
+
+ xml.StartElement("AdditionalRules");
+ xml.Element("CustomPostBuild");
+ xml.Element("CustomPreBuild");
+ xml.EndElement(); // AdditionalRules
+
+ xml.EndElement(); // Configuration
+ xml.StartElement("GlobalSettings");
+
+ xml.StartElement("Compiler");
+ xml.Attribute("Options", "");
+ xml.StartElement("IncludePath");
+ xml.Attribute("Value", ".");
+ xml.EndElement(); // IncludePath
+ xml.EndElement(); // Compiler
+
+ xml.StartElement("Linker");
+ xml.Attribute("Options", "");
+ xml.StartElement("LibraryPath");
+ xml.Attribute("Value", ".");
+ xml.EndElement(); // LibraryPath
+ xml.EndElement(); // Linker
+
+ xml.StartElement("ResourceCompiler");
+ xml.Attribute("Options", "");
+ xml.EndElement(); // ResourceCompiler
+
+ xml.EndElement(); // GlobalSettings
+ xml.EndElement(); // Settings
+ xml.EndElement(); // CodeLite_Project
+}
+
+std::string cmExtraCodeLiteGenerator::GetCodeLiteCompilerName(
+ const cmMakefile* mf) const
+{
+ // figure out which language to use
+ // for now care only for C and C++
+ std::string compilerIdVar = "CMAKE_CXX_COMPILER_ID";
+ if (!this->GlobalGenerator->GetLanguageEnabled("CXX")) {
+ compilerIdVar = "CMAKE_C_COMPILER_ID";
+ }
+
+ std::string compilerId = mf->GetSafeDefinition(compilerIdVar);
+ std::string compiler = "gnu g++"; // default to g++
+
+ // Since we need the compiler for parsing purposes only
+ // it does not matter if we use clang or clang++, same as
+ // "gnu gcc" vs "gnu g++"
+ if (compilerId == "MSVC") {
+ compiler = "VC++";
+ } else if (compilerId == "Clang") {
+ compiler = "clang++";
+ } else if (compilerId == "GNU") {
+ compiler = "gnu g++";
+ }
+ return compiler;
+}
+
+std::string cmExtraCodeLiteGenerator::GetConfigurationName(
+ const cmMakefile* mf) const
+{
+ std::string confName = mf->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ // Trim the configuration name from whitespaces (left and right)
+ confName.erase(0, confName.find_first_not_of(" \t\r\v\n"));
+ confName.erase(confName.find_last_not_of(" \t\r\v\n") + 1);
+ if (confName.empty()) {
+ confName = "NoConfig";
+ }
+ return confName;
+}
+
+std::string cmExtraCodeLiteGenerator::GetBuildCommand(
+ const cmMakefile* mf) const
+{
+ std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
+ std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ std::string buildCommand = make; // Default
+ if (generator == "NMake Makefiles" || generator == "Ninja") {
+ buildCommand = make;
+ } else if (generator == "MinGW Makefiles" || generator == "Unix Makefiles") {
+ std::ostringstream ss;
+ ss << make << " -j " << this->CpuCount;
+ buildCommand = ss.str();
+ }
+ return buildCommand;
+}
+
+std::string cmExtraCodeLiteGenerator::GetCleanCommand(
+ const cmMakefile* mf) const
+{
+ return GetBuildCommand(mf) + " clean";
+}
+
+std::string cmExtraCodeLiteGenerator::GetRebuildCommand(
+ const cmMakefile* mf) const
+{
+ return GetCleanCommand(mf) + " && " + GetBuildCommand(mf);
+}
+
+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");
+ if (generator == "Unix Makefiles" || generator == "MinGW Makefiles") {
+ std::ostringstream ss;
+ ss << make << " -f$(ProjectPath)/Makefile $(CurrentFileName).cpp.o";
+ buildCommand = ss.str();
+ }
+ return buildCommand;
+}
diff --git a/Source/cmExtraCodeLiteGenerator.h b/Source/cmExtraCodeLiteGenerator.h
new file mode 100644
index 0000000..f2ee85c
--- /dev/null
+++ b/Source/cmExtraCodeLiteGenerator.h
@@ -0,0 +1,59 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2009 Kitware, Inc.
+ Copyright 2004 Alexander Neundorf (neundorf@kde.org)
+ Copyright 2013 Eran Ifrah (eran.ifrah@gmail.com)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalCodeLiteGenerator_h
+#define cmGlobalCodeLiteGenerator_h
+
+#include "cmExternalMakefileProjectGenerator.h"
+
+class cmLocalGenerator;
+
+class cmExtraCodeLiteGenerator : public cmExternalMakefileProjectGenerator
+{
+protected:
+ std::string ConfigName;
+ std::string WorkspacePath;
+ unsigned int CpuCount;
+
+protected:
+ std::string GetCodeLiteCompilerName(const cmMakefile* mf) const;
+ std::string GetConfigurationName(const cmMakefile* mf) const;
+ std::string GetBuildCommand(const cmMakefile* mf) const;
+ std::string GetCleanCommand(const cmMakefile* mf) const;
+ std::string GetRebuildCommand(const cmMakefile* mf) const;
+ std::string GetSingleFileBuildCommand(const cmMakefile* mf) const;
+
+public:
+ cmExtraCodeLiteGenerator();
+
+ std::string GetName() const CM_OVERRIDE
+ {
+ return cmExtraCodeLiteGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "CodeLite"; }
+ static cmExternalMakefileProjectGenerator* New()
+ {
+ return new cmExtraCodeLiteGenerator;
+ }
+ /** Get the documentation entry for this generator. */
+ void GetDocumentation(cmDocumentationEntry& entry,
+ const std::string& fullName) const CM_OVERRIDE;
+
+ void Generate() CM_OVERRIDE;
+ void CreateProjectFile(const std::vector<cmLocalGenerator*>& lgs);
+
+ void CreateNewProjectFile(const std::vector<cmLocalGenerator*>& lgs,
+ const std::string& filename);
+};
+
+#endif
diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx
new file mode 100644
index 0000000..16cb082
--- /dev/null
+++ b/Source/cmExtraEclipseCDT4Generator.cxx
@@ -0,0 +1,1184 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2009 Kitware, Inc.
+ Copyright 2004 Alexander Neundorf (neundorf@kde.org)
+ Copyright 2007 Miguel A. Figueroa-Villanueva
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmExtraEclipseCDT4Generator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmTarget.h"
+#include "cmXMLWriter.h"
+
+#include "cmSystemTools.h"
+#include <assert.h>
+#include <stdlib.h>
+
+static void AppendAttribute(cmXMLWriter& xml, const char* keyval)
+{
+ xml.StartElement("attribute");
+ xml.Attribute("key", keyval);
+ xml.Attribute("value", keyval);
+ xml.EndElement();
+}
+
+template <typename T>
+void AppendDictionary(cmXMLWriter& xml, const char* key, T const& value)
+{
+ xml.StartElement("dictionary");
+ xml.Element("key", key);
+ xml.Element("value", value);
+ xml.EndElement();
+}
+
+cmExtraEclipseCDT4Generator::cmExtraEclipseCDT4Generator()
+ : cmExternalMakefileProjectGenerator()
+{
+// TODO: Verify if __CYGWIN__ should be checked.
+//#if defined(_WIN32) && !defined(__CYGWIN__)
+#if defined(_WIN32)
+ this->SupportedGlobalGenerators.push_back("NMake Makefiles");
+ this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
+// this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
+#endif
+ this->SupportedGlobalGenerators.push_back("Ninja");
+ this->SupportedGlobalGenerators.push_back("Unix Makefiles");
+
+ this->SupportsVirtualFolders = true;
+ this->GenerateLinkedResources = true;
+ this->SupportsGmakeErrorParser = true;
+ this->SupportsMachO64Parser = true;
+ this->CEnabled = false;
+ this->CXXEnabled = false;
+}
+
+void cmExtraEclipseCDT4Generator::GetDocumentation(cmDocumentationEntry& entry,
+ const std::string&) const
+{
+ entry.Name = this->GetName();
+ entry.Brief = "Generates Eclipse CDT 4.0 project files.";
+}
+
+void cmExtraEclipseCDT4Generator::EnableLanguage(
+ std::vector<std::string> const& languages, cmMakefile*, bool)
+{
+ for (std::vector<std::string>::const_iterator lit = languages.begin();
+ lit != languages.end(); ++lit) {
+ if (*lit == "CXX") {
+ this->Natures.insert("org.eclipse.cdt.core.ccnature");
+ this->Natures.insert("org.eclipse.cdt.core.cnature");
+ this->CXXEnabled = true;
+ } else if (*lit == "C") {
+ this->Natures.insert("org.eclipse.cdt.core.cnature");
+ this->CEnabled = true;
+ } else if (*lit == "Java") {
+ this->Natures.insert("org.eclipse.jdt.core.javanature");
+ }
+ }
+}
+
+void cmExtraEclipseCDT4Generator::Generate()
+{
+ cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0];
+ const cmMakefile* mf = lg->GetMakefile();
+
+ std::string eclipseVersion = mf->GetSafeDefinition("CMAKE_ECLIPSE_VERSION");
+ cmsys::RegularExpression regex(".*([0-9]+\\.[0-9]+).*");
+ if (regex.find(eclipseVersion.c_str())) {
+ unsigned int majorVersion = 0;
+ unsigned int minorVersion = 0;
+ int res =
+ sscanf(regex.match(1).c_str(), "%u.%u", &majorVersion, &minorVersion);
+ if (res == 2) {
+ int version = majorVersion * 1000 + minorVersion;
+ if (version < 3006) // 3.6 is Helios
+ {
+ this->SupportsVirtualFolders = false;
+ this->SupportsMachO64Parser = false;
+ }
+ if (version < 3007) // 3.7 is Indigo
+ {
+ this->SupportsGmakeErrorParser = false;
+ }
+ }
+ }
+
+ // TODO: Decide if these are local or member variables
+ this->HomeDirectory = lg->GetSourceDirectory();
+ this->HomeOutputDirectory = lg->GetBinaryDirectory();
+
+ this->GenerateLinkedResources =
+ mf->IsOn("CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES");
+
+ this->IsOutOfSourceBuild =
+ (this->HomeDirectory != this->HomeOutputDirectory);
+
+ this->GenerateSourceProject =
+ (this->IsOutOfSourceBuild &&
+ mf->IsOn("CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT"));
+
+ if (!this->GenerateSourceProject &&
+ (mf->IsOn("ECLIPSE_CDT4_GENERATE_SOURCE_PROJECT"))) {
+ mf->IssueMessage(
+ cmake::WARNING,
+ "ECLIPSE_CDT4_GENERATE_SOURCE_PROJECT is set to TRUE, "
+ "but this variable is not supported anymore since CMake 2.8.7.\n"
+ "Enable CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT instead.");
+ }
+
+ if (cmSystemTools::IsSubDirectory(this->HomeOutputDirectory,
+ this->HomeDirectory)) {
+ mf->IssueMessage(cmake::WARNING,
+ "The build directory is a subdirectory "
+ "of the source directory.\n"
+ "This is not supported well by Eclipse. It is strongly "
+ "recommended to use a build directory which is a "
+ "sibling of the source directory.");
+ }
+
+ // NOTE: This is not good, since it pollutes the source tree. However,
+ // Eclipse doesn't allow CVS/SVN to work when the .project is not in
+ // the cvs/svn root directory. Hence, this is provided as an option.
+ if (this->GenerateSourceProject) {
+ // create .project file in the source tree
+ this->CreateSourceProjectFile();
+ }
+
+ // create a .project file
+ this->CreateProjectFile();
+
+ // create a .cproject file
+ this->CreateCProjectFile();
+}
+
+void cmExtraEclipseCDT4Generator::CreateSourceProjectFile()
+{
+ assert(this->HomeDirectory != this->HomeOutputDirectory);
+
+ // set up the project name: <project>-Source@<baseSourcePathName>
+ cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0];
+ std::string name =
+ this->GenerateProjectName(lg->GetProjectName(), "Source",
+ this->GetPathBasename(this->HomeDirectory));
+
+ const std::string filename = this->HomeDirectory + "/.project";
+ cmGeneratedFileStream fout(filename.c_str());
+ if (!fout) {
+ return;
+ }
+
+ cmXMLWriter xml(fout);
+ xml.StartDocument("UTF-8");
+ xml.StartElement("projectDescription");
+ xml.Element("name", name);
+ xml.Element("comment", "");
+ xml.Element("projects", "");
+ xml.Element("buildSpec", "");
+ xml.Element("natures", "");
+ xml.StartElement("linkedResources");
+
+ if (this->SupportsVirtualFolders) {
+ this->CreateLinksToSubprojects(xml, this->HomeDirectory);
+ this->SrcLinkedResources.clear();
+ }
+
+ xml.EndElement(); // linkedResources
+ xml.EndElement(); // projectDescription
+ xml.EndDocument();
+}
+
+void cmExtraEclipseCDT4Generator::AddEnvVar(std::ostream& out,
+ const char* envVar,
+ cmLocalGenerator* lg)
+{
+ cmMakefile* mf = lg->GetMakefile();
+
+ // get the variables from the environment and from the cache and then
+ // figure out which one to use:
+
+ const char* envVarValue = getenv(envVar);
+
+ std::string cacheEntryName = "CMAKE_ECLIPSE_ENVVAR_";
+ cacheEntryName += envVar;
+ const char* cacheValue =
+ lg->GetState()->GetInitializedCacheValue(cacheEntryName);
+
+ // now we have both, decide which one to use
+ std::string valueToUse;
+ if (envVarValue == CM_NULLPTR && cacheValue == CM_NULLPTR) {
+ // nothing known, do nothing
+ valueToUse = "";
+ } else if (envVarValue != CM_NULLPTR && cacheValue == CM_NULLPTR) {
+ // The variable is in the env, but not in the cache. Use it and put it
+ // in the cache
+ valueToUse = envVarValue;
+ mf->AddCacheDefinition(cacheEntryName, valueToUse.c_str(),
+ cacheEntryName.c_str(), cmState::STRING, true);
+ mf->GetCMakeInstance()->SaveCache(lg->GetBinaryDirectory());
+ } else if (envVarValue == CM_NULLPTR && cacheValue != CM_NULLPTR) {
+ // It is already in the cache, but not in the env, so use it from the cache
+ valueToUse = cacheValue;
+ } else {
+ // It is both in the cache and in the env.
+ // Use the version from the env. except if the value from the env is
+ // completely contained in the value from the cache (for the case that we
+ // now have a PATH without MSVC dirs in the env. but had the full PATH with
+ // all MSVC dirs during the cmake run which stored the var in the cache:
+ valueToUse = cacheValue;
+ if (valueToUse.find(envVarValue) == std::string::npos) {
+ valueToUse = envVarValue;
+ mf->AddCacheDefinition(cacheEntryName, valueToUse.c_str(),
+ cacheEntryName.c_str(), cmState::STRING, true);
+ mf->GetCMakeInstance()->SaveCache(lg->GetBinaryDirectory());
+ }
+ }
+
+ if (!valueToUse.empty()) {
+ out << envVar << "=" << valueToUse << "|";
+ }
+}
+
+void cmExtraEclipseCDT4Generator::CreateProjectFile()
+{
+ cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0];
+ cmMakefile* mf = lg->GetMakefile();
+
+ const std::string filename = this->HomeOutputDirectory + "/.project";
+
+ cmGeneratedFileStream fout(filename.c_str());
+ if (!fout) {
+ return;
+ }
+
+ std::string compilerId = mf->GetSafeDefinition("CMAKE_C_COMPILER_ID");
+ if (compilerId.empty()) // no C compiler, try the C++ compiler:
+ {
+ compilerId = mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID");
+ }
+
+ cmXMLWriter xml(fout);
+
+ xml.StartDocument("UTF-8");
+ xml.StartElement("projectDescription");
+
+ xml.Element("name", this->GenerateProjectName(
+ lg->GetProjectName(),
+ mf->GetSafeDefinition("CMAKE_BUILD_TYPE"),
+ this->GetPathBasename(this->HomeOutputDirectory)));
+
+ xml.Element("comment", "");
+ xml.Element("projects", "");
+
+ xml.StartElement("buildSpec");
+ xml.StartElement("buildCommand");
+ xml.Element("name", "org.eclipse.cdt.make.core.makeBuilder");
+ xml.Element("triggers", "clean,full,incremental,");
+ xml.StartElement("arguments");
+
+ // use clean target
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.cleanBuildTarget", "clean");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.enableCleanBuild", "true");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.append_environment",
+ "true");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.stopOnError", "true");
+
+ // set the make command
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.enabledIncrementalBuild",
+ "true");
+ AppendDictionary(
+ xml, "org.eclipse.cdt.make.core.build.command",
+ this->GetEclipsePath(mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM")));
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.contents",
+ "org.eclipse.cdt.make.core.activeConfigSettings");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.build.target.inc", "all");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.build.arguments",
+ mf->GetSafeDefinition("CMAKE_ECLIPSE_MAKE_ARGUMENTS"));
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.buildLocation",
+ this->GetEclipsePath(this->HomeOutputDirectory));
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.useDefaultBuildCmd",
+ "false");
+
+ // set project specific environment
+ std::ostringstream environment;
+ environment << "VERBOSE=1|CMAKE_NO_VERBOSE=1|"; // verbose Makefile output
+ // set vsvars32.bat environment available at CMake time,
+ // but not necessarily when eclipse is open
+ if (compilerId == "MSVC") {
+ AddEnvVar(environment, "PATH", lg);
+ AddEnvVar(environment, "INCLUDE", lg);
+ AddEnvVar(environment, "LIB", lg);
+ AddEnvVar(environment, "LIBPATH", lg);
+ } else if (compilerId == "Intel") {
+ // if the env.var is set, use this one and put it in the cache
+ // if the env.var is not set, but the value is in the cache,
+ // use it from the cache:
+ AddEnvVar(environment, "INTEL_LICENSE_FILE", lg);
+ }
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.environment",
+ environment.str());
+
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.enableFullBuild", "true");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.build.target.auto", "all");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.enableAutoBuild", "false");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.build.target.clean",
+ "clean");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.fullBuildTarget", "all");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.buildArguments", "");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.build.location",
+ this->GetEclipsePath(this->HomeOutputDirectory));
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.autoBuildTarget", "all");
+
+ // set error parsers
+ std::ostringstream errorOutputParser;
+
+ if (compilerId == "MSVC") {
+ errorOutputParser << "org.eclipse.cdt.core.VCErrorParser;";
+ } else if (compilerId == "Intel") {
+ errorOutputParser << "org.eclipse.cdt.core.ICCErrorParser;";
+ }
+
+ if (this->SupportsGmakeErrorParser) {
+ errorOutputParser << "org.eclipse.cdt.core.GmakeErrorParser;";
+ } else {
+ errorOutputParser << "org.eclipse.cdt.core.MakeErrorParser;";
+ }
+
+ errorOutputParser << "org.eclipse.cdt.core.GCCErrorParser;"
+ "org.eclipse.cdt.core.GASErrorParser;"
+ "org.eclipse.cdt.core.GLDErrorParser;";
+ AppendDictionary(xml, "org.eclipse.cdt.core.errorOutputParser",
+ errorOutputParser.str());
+
+ xml.EndElement(); // arguments
+ xml.EndElement(); // buildCommand
+ xml.StartElement("buildCommand");
+ xml.Element("name", "org.eclipse.cdt.make.core.ScannerConfigBuilder");
+ xml.StartElement("arguments");
+ xml.EndElement(); // arguments
+ xml.EndElement(); // buildCommand
+ xml.EndElement(); // buildSpec
+
+ // set natures for c/c++ projects
+ xml.StartElement("natures");
+ xml.Element("nature", "org.eclipse.cdt.make.core.makeNature");
+ xml.Element("nature", "org.eclipse.cdt.make.core.ScannerConfigNature");
+ ;
+
+ for (std::set<std::string>::const_iterator nit = this->Natures.begin();
+ nit != this->Natures.end(); ++nit) {
+ xml.Element("nature", *nit);
+ }
+
+ if (const char* extraNaturesProp =
+ mf->GetState()->GetGlobalProperty("ECLIPSE_EXTRA_NATURES")) {
+ std::vector<std::string> extraNatures;
+ cmSystemTools::ExpandListArgument(extraNaturesProp, extraNatures);
+ for (std::vector<std::string>::const_iterator nit = extraNatures.begin();
+ nit != extraNatures.end(); ++nit) {
+ xml.Element("nature", *nit);
+ }
+ }
+
+ xml.EndElement(); // natures
+
+ xml.StartElement("linkedResources");
+ // create linked resources
+ if (this->IsOutOfSourceBuild) {
+ // create a linked resource to CMAKE_SOURCE_DIR
+ // (this is not done anymore for each project because of
+ // http://public.kitware.com/Bug/view.php?id=9978 and because I found it
+ // actually quite confusing in bigger projects with many directories and
+ // projects, Alex
+
+ std::string sourceLinkedResourceName = "[Source directory]";
+ std::string linkSourceDirectory =
+ this->GetEclipsePath(lg->GetCurrentSourceDirectory());
+ // .project dir can't be subdir of a linked resource dir
+ if (!cmSystemTools::IsSubDirectory(this->HomeOutputDirectory,
+ linkSourceDirectory)) {
+ this->AppendLinkedResource(xml, sourceLinkedResourceName,
+ this->GetEclipsePath(linkSourceDirectory),
+ LinkToFolder);
+ this->SrcLinkedResources.push_back(sourceLinkedResourceName);
+ }
+ }
+
+ if (this->SupportsVirtualFolders) {
+ this->CreateLinksToSubprojects(xml, this->HomeOutputDirectory);
+
+ this->CreateLinksForTargets(xml);
+ }
+
+ xml.EndElement(); // linkedResources
+ xml.EndElement(); // projectDescription
+}
+
+void cmExtraEclipseCDT4Generator::WriteGroups(
+ std::vector<cmSourceGroup> const& sourceGroups, std::string& linkName,
+ cmXMLWriter& xml)
+{
+ for (std::vector<cmSourceGroup>::const_iterator sgIt = sourceGroups.begin();
+ sgIt != sourceGroups.end(); ++sgIt) {
+ std::string linkName3 = linkName;
+ linkName3 += "/";
+ linkName3 += sgIt->GetFullName();
+
+ std::replace(linkName3.begin(), linkName3.end(), '\\', '/');
+
+ this->AppendLinkedResource(xml, linkName3, "virtual:/virtual",
+ VirtualFolder);
+ std::vector<cmSourceGroup> const& children = sgIt->GetGroupChildren();
+ if (!children.empty()) {
+ this->WriteGroups(children, linkName, xml);
+ }
+ std::vector<const cmSourceFile*> sFiles = sgIt->GetSourceFiles();
+ for (std::vector<const cmSourceFile*>::const_iterator fileIt =
+ sFiles.begin();
+ fileIt != sFiles.end(); ++fileIt) {
+ std::string fullPath = (*fileIt)->GetFullPath();
+
+ if (!cmSystemTools::FileIsDirectory(fullPath)) {
+ std::string linkName4 = linkName3;
+ linkName4 += "/";
+ linkName4 += cmSystemTools::GetFilenameName(fullPath);
+ this->AppendLinkedResource(xml, linkName4,
+ this->GetEclipsePath(fullPath), LinkToFile);
+ }
+ }
+ }
+}
+
+void cmExtraEclipseCDT4Generator::CreateLinksForTargets(cmXMLWriter& xml)
+{
+ std::string linkName = "[Targets]";
+ this->AppendLinkedResource(xml, linkName, "virtual:/virtual", VirtualFolder);
+
+ for (std::vector<cmLocalGenerator*>::const_iterator lgIt =
+ this->GlobalGenerator->GetLocalGenerators().begin();
+ lgIt != this->GlobalGenerator->GetLocalGenerators().end(); ++lgIt) {
+ cmMakefile* makefile = (*lgIt)->GetMakefile();
+ const std::vector<cmGeneratorTarget*> targets =
+ (*lgIt)->GetGeneratorTargets();
+
+ for (std::vector<cmGeneratorTarget*>::const_iterator ti = targets.begin();
+ ti != targets.end(); ++ti) {
+ std::string linkName2 = linkName;
+ linkName2 += "/";
+ switch ((*ti)->GetType()) {
+ case cmState::EXECUTABLE:
+ case cmState::STATIC_LIBRARY:
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ case cmState::OBJECT_LIBRARY: {
+ const char* prefix =
+ ((*ti)->GetType() == cmState::EXECUTABLE ? "[exe] " : "[lib] ");
+ linkName2 += prefix;
+ linkName2 += (*ti)->GetName();
+ this->AppendLinkedResource(xml, linkName2, "virtual:/virtual",
+ VirtualFolder);
+ if (!this->GenerateLinkedResources) {
+ break; // skip generating the linked resources to the source files
+ }
+ std::vector<cmSourceGroup> sourceGroups =
+ makefile->GetSourceGroups();
+ // get the files from the source lists then add them to the groups
+ cmGeneratorTarget* gt = const_cast<cmGeneratorTarget*>(*ti);
+ std::vector<cmSourceFile*> files;
+ gt->GetSourceFiles(files,
+ makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ for (std::vector<cmSourceFile*>::const_iterator sfIt = files.begin();
+ sfIt != files.end(); sfIt++) {
+ // Add the file to the list of sources.
+ std::string source = (*sfIt)->GetFullPath();
+ cmSourceGroup* sourceGroup =
+ makefile->FindSourceGroup(source.c_str(), sourceGroups);
+ sourceGroup->AssignSource(*sfIt);
+ }
+
+ this->WriteGroups(sourceGroups, linkName2, xml);
+ } break;
+ // ignore all others:
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void cmExtraEclipseCDT4Generator::CreateLinksToSubprojects(
+ cmXMLWriter& xml, const std::string& baseDir)
+{
+ if (!this->GenerateLinkedResources) {
+ return;
+ }
+
+ // for each sub project create a linked resource to the source dir
+ // - only if it is an out-of-source build
+ this->AppendLinkedResource(xml, "[Subprojects]", "virtual:/virtual",
+ VirtualFolder);
+
+ for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
+ it = this->GlobalGenerator->GetProjectMap().begin();
+ it != this->GlobalGenerator->GetProjectMap().end(); ++it) {
+ std::string linkSourceDirectory =
+ this->GetEclipsePath(it->second[0]->GetCurrentSourceDirectory());
+ // a linked resource must not point to a parent directory of .project or
+ // .project itself
+ if ((baseDir != linkSourceDirectory) &&
+ !cmSystemTools::IsSubDirectory(baseDir, linkSourceDirectory)) {
+ std::string linkName = "[Subprojects]/";
+ linkName += it->first;
+ this->AppendLinkedResource(xml, linkName,
+ this->GetEclipsePath(linkSourceDirectory),
+ LinkToFolder);
+ // Don't add it to the srcLinkedResources, because listing multiple
+ // directories confuses the Eclipse indexer (#13596).
+ }
+ }
+}
+
+void cmExtraEclipseCDT4Generator::AppendIncludeDirectories(
+ cmXMLWriter& xml, const std::vector<std::string>& includeDirs,
+ std::set<std::string>& emittedDirs)
+{
+ for (std::vector<std::string>::const_iterator inc = includeDirs.begin();
+ inc != includeDirs.end(); ++inc) {
+ if (!inc->empty()) {
+ std::string dir = cmSystemTools::CollapseFullPath(*inc);
+
+ // handle framework include dirs on OSX, the remainder after the
+ // Frameworks/ part has to be stripped
+ // /System/Library/Frameworks/GLUT.framework/Headers
+ cmsys::RegularExpression frameworkRx("(.+/Frameworks)/.+\\.framework/");
+ if (frameworkRx.find(dir.c_str())) {
+ dir = frameworkRx.match(1);
+ }
+
+ if (emittedDirs.find(dir) == emittedDirs.end()) {
+ emittedDirs.insert(dir);
+ xml.StartElement("pathentry");
+ xml.Attribute("include",
+ cmExtraEclipseCDT4Generator::GetEclipsePath(dir));
+ xml.Attribute("kind", "inc");
+ xml.Attribute("path", "");
+ xml.Attribute("system", "true");
+ xml.EndElement();
+ }
+ }
+ }
+}
+
+void cmExtraEclipseCDT4Generator::CreateCProjectFile() const
+{
+ std::set<std::string> emmited;
+
+ cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0];
+ const cmMakefile* mf = lg->GetMakefile();
+
+ const std::string filename = this->HomeOutputDirectory + "/.cproject";
+
+ cmGeneratedFileStream fout(filename.c_str());
+ if (!fout) {
+ return;
+ }
+
+ cmXMLWriter xml(fout);
+
+ // add header
+ xml.StartDocument("UTF-8");
+ xml.ProcessingInstruction("fileVersion", "4.0.0");
+ xml.StartElement("cproject");
+ xml.StartElement("storageModule");
+ xml.Attribute("moduleId", "org.eclipse.cdt.core.settings");
+
+ xml.StartElement("cconfiguration");
+ xml.Attribute("id", "org.eclipse.cdt.core.default.config.1");
+
+ // Configuration settings...
+ xml.StartElement("storageModule");
+ xml.Attribute("buildSystemId",
+ "org.eclipse.cdt.core.defaultConfigDataProvider");
+ xml.Attribute("id", "org.eclipse.cdt.core.default.config.1");
+ xml.Attribute("moduleId", "org.eclipse.cdt.core.settings");
+ xml.Attribute("name", "Configuration");
+ xml.Element("externalSettings");
+ xml.StartElement("extensions");
+
+ // TODO: refactor this out...
+ std::string executableFormat =
+ mf->GetSafeDefinition("CMAKE_EXECUTABLE_FORMAT");
+ if (executableFormat == "ELF") {
+ xml.StartElement("extension");
+ xml.Attribute("id", "org.eclipse.cdt.core.ELF");
+ xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
+ xml.EndElement(); // extension
+
+ xml.StartElement("extension");
+ xml.Attribute("id", "org.eclipse.cdt.core.GNU_ELF");
+ xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
+ AppendAttribute(xml, "addr2line");
+ AppendAttribute(xml, "c++filt");
+ xml.EndElement(); // extension
+ } else {
+ std::string systemName = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME");
+ if (systemName == "CYGWIN") {
+ xml.StartElement("extension");
+ xml.Attribute("id", "org.eclipse.cdt.core.Cygwin_PE");
+ xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
+ AppendAttribute(xml, "addr2line");
+ AppendAttribute(xml, "c++filt");
+ AppendAttribute(xml, "cygpath");
+ AppendAttribute(xml, "nm");
+ xml.EndElement(); // extension
+ } else if (systemName == "Windows") {
+ xml.StartElement("extension");
+ xml.Attribute("id", "org.eclipse.cdt.core.PE");
+ xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
+ xml.EndElement(); // extension
+ } else if (systemName == "Darwin") {
+ xml.StartElement("extension");
+ xml.Attribute("id", this->SupportsMachO64Parser
+ ? "org.eclipse.cdt.core.MachO64"
+ : "org.eclipse.cdt.core.MachO");
+ xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
+ AppendAttribute(xml, "c++filt");
+ xml.EndElement(); // extension
+ } else {
+ // *** Should never get here ***
+ xml.Element("error_toolchain_type");
+ }
+ }
+
+ xml.EndElement(); // extensions
+ xml.EndElement(); // storageModule
+
+ // ???
+ xml.StartElement("storageModule");
+ xml.Attribute("moduleId", "org.eclipse.cdt.core.language.mapping");
+ xml.Element("project-mappings");
+ xml.EndElement(); // storageModule
+
+ // ???
+ xml.StartElement("storageModule");
+ xml.Attribute("moduleId", "org.eclipse.cdt.core.externalSettings");
+ xml.EndElement(); // storageModule
+
+ // set the path entries (includes, libs, source dirs, etc.)
+ xml.StartElement("storageModule");
+ xml.Attribute("moduleId", "org.eclipse.cdt.core.pathentry");
+
+ // for each sub project with a linked resource to the source dir:
+ // - make it type 'src'
+ // - and exclude it from type 'out'
+ std::string excludeFromOut;
+ /* I don't know what the pathentry kind="src" are good for, e.g.
+ * autocompletion
+ * works also without them. Done wrong, the indexer complains, see #12417
+ * and #12213.
+ * According to #13596, this entry at least limits the directories the
+ * indexer is searching for files. So now the "src" entry contains only
+ * the linked resource to CMAKE_SOURCE_DIR.
+ * The CDT documentation is very terse on that:
+ * "CDT_SOURCE: Entry kind constant describing a path entry identifying a
+ * folder containing source code to be compiled."
+ * Also on the cdt-dev list didn't bring any information:
+ * http://web.archiveorange.com/archive/v/B4NlJDNIpYoOS1SbxFNy
+ * Alex */
+
+ for (std::vector<std::string>::const_iterator it =
+ this->SrcLinkedResources.begin();
+ it != this->SrcLinkedResources.end(); ++it) {
+ xml.StartElement("pathentry");
+ xml.Attribute("kind", "src");
+ xml.Attribute("path", *it);
+ xml.EndElement();
+
+ // exlude source directory from output search path
+ // - only if not named the same as an output directory
+ if (!cmSystemTools::FileIsDirectory(
+ std::string(this->HomeOutputDirectory + "/" + *it))) {
+ excludeFromOut += *it + "/|";
+ }
+ }
+
+ excludeFromOut += "**/CMakeFiles/";
+
+ xml.StartElement("pathentry");
+ xml.Attribute("excluding", excludeFromOut);
+ xml.Attribute("kind", "out");
+ xml.Attribute("path", "");
+ xml.EndElement();
+
+ // add pre-processor definitions to allow eclipse to gray out sections
+ emmited.clear();
+ for (std::vector<cmLocalGenerator*>::const_iterator it =
+ this->GlobalGenerator->GetLocalGenerators().begin();
+ it != this->GlobalGenerator->GetLocalGenerators().end(); ++it) {
+
+ if (const char* cdefs =
+ (*it)->GetMakefile()->GetProperty("COMPILE_DEFINITIONS")) {
+ // Expand the list.
+ std::vector<std::string> defs;
+ cmGeneratorExpression::Split(cdefs, defs);
+
+ for (std::vector<std::string>::const_iterator di = defs.begin();
+ di != defs.end(); ++di) {
+ if (cmGeneratorExpression::Find(*di) != std::string::npos) {
+ continue;
+ }
+
+ std::string::size_type equals = di->find('=', 0);
+ std::string::size_type enddef = di->length();
+
+ std::string def;
+ std::string val;
+ if (equals != std::string::npos && equals < enddef) {
+ // we have -DFOO=BAR
+ def = di->substr(0, equals);
+ val = di->substr(equals + 1, enddef - equals + 1);
+ } else {
+ // we have -DFOO
+ def = *di;
+ }
+
+ // insert the definition if not already added.
+ if (emmited.find(def) == emmited.end()) {
+ emmited.insert(def);
+ xml.StartElement("pathentry");
+ xml.Attribute("kind", "mac");
+ xml.Attribute("name", def);
+ xml.Attribute("path", "");
+ xml.Attribute("value", val);
+ xml.EndElement();
+ }
+ }
+ }
+ }
+ // add system defined c macros
+ const char* cDefs =
+ mf->GetDefinition("CMAKE_EXTRA_GENERATOR_C_SYSTEM_DEFINED_MACROS");
+ if (this->CEnabled && cDefs) {
+ // Expand the list.
+ std::vector<std::string> defs;
+ cmSystemTools::ExpandListArgument(cDefs, defs, true);
+
+ // the list must contain only definition-value pairs:
+ if ((defs.size() % 2) == 0) {
+ std::vector<std::string>::const_iterator di = defs.begin();
+ while (di != defs.end()) {
+ std::string def = *di;
+ ++di;
+ std::string val;
+ if (di != defs.end()) {
+ val = *di;
+ ++di;
+ }
+
+ // insert the definition if not already added.
+ if (emmited.find(def) == emmited.end()) {
+ emmited.insert(def);
+ xml.StartElement("pathentry");
+ xml.Attribute("kind", "mac");
+ xml.Attribute("name", def);
+ xml.Attribute("path", "");
+ xml.Attribute("value", val);
+ xml.EndElement();
+ }
+ }
+ }
+ }
+ // add system defined c++ macros
+ const char* cxxDefs =
+ mf->GetDefinition("CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_DEFINED_MACROS");
+ if (this->CXXEnabled && cxxDefs) {
+ // Expand the list.
+ std::vector<std::string> defs;
+ cmSystemTools::ExpandListArgument(cxxDefs, defs, true);
+
+ // the list must contain only definition-value pairs:
+ if ((defs.size() % 2) == 0) {
+ std::vector<std::string>::const_iterator di = defs.begin();
+ while (di != defs.end()) {
+ std::string def = *di;
+ ++di;
+ std::string val;
+ if (di != defs.end()) {
+ val = *di;
+ ++di;
+ }
+
+ // insert the definition if not already added.
+ if (emmited.find(def) == emmited.end()) {
+ emmited.insert(def);
+ xml.StartElement("pathentry");
+ xml.Attribute("kind", "mac");
+ xml.Attribute("name", def);
+ xml.Attribute("path", "");
+ xml.Attribute("value", val);
+ xml.EndElement();
+ }
+ }
+ }
+ }
+
+ // include dirs
+ emmited.clear();
+ for (std::vector<cmLocalGenerator*>::const_iterator it =
+ this->GlobalGenerator->GetLocalGenerators().begin();
+ it != this->GlobalGenerator->GetLocalGenerators().end(); ++it) {
+ std::vector<cmGeneratorTarget*> targets = (*it)->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator l = targets.begin();
+ l != targets.end(); ++l) {
+ std::vector<std::string> includeDirs;
+ std::string config = mf->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ (*it)->GetIncludeDirectories(includeDirs, *l, "C", config);
+ this->AppendIncludeDirectories(xml, includeDirs, emmited);
+ }
+ }
+ // now also the system include directories, in case we found them in
+ // CMakeSystemSpecificInformation.cmake. This makes Eclipse find the
+ // standard headers.
+ std::string compiler = mf->GetSafeDefinition("CMAKE_C_COMPILER");
+ if (this->CEnabled && !compiler.empty()) {
+ std::string systemIncludeDirs =
+ mf->GetSafeDefinition("CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
+ std::vector<std::string> dirs;
+ cmSystemTools::ExpandListArgument(systemIncludeDirs, dirs);
+ this->AppendIncludeDirectories(xml, dirs, emmited);
+ }
+ compiler = mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
+ if (this->CXXEnabled && !compiler.empty()) {
+ std::string systemIncludeDirs =
+ mf->GetSafeDefinition("CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
+ std::vector<std::string> dirs;
+ cmSystemTools::ExpandListArgument(systemIncludeDirs, dirs);
+ this->AppendIncludeDirectories(xml, dirs, emmited);
+ }
+
+ xml.EndElement(); // storageModule
+
+ // add build targets
+ xml.StartElement("storageModule");
+ 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 =
+ mf->GetSafeDefinition("CMAKE_ECLIPSE_MAKE_ARGUMENTS");
+
+ cmGlobalGenerator* generator =
+ const_cast<cmGlobalGenerator*>(this->GlobalGenerator);
+
+ std::string allTarget;
+ std::string cleanTarget;
+ if (generator->GetAllTargetName()) {
+ allTarget = generator->GetAllTargetName();
+ }
+ if (generator->GetCleanTargetName()) {
+ cleanTarget = generator->GetCleanTargetName();
+ }
+
+ // add all executable and library targets and some of the GLOBAL
+ // and UTILITY targets
+ for (std::vector<cmLocalGenerator*>::const_iterator it =
+ this->GlobalGenerator->GetLocalGenerators().begin();
+ it != this->GlobalGenerator->GetLocalGenerators().end(); ++it) {
+ const std::vector<cmGeneratorTarget*> targets =
+ (*it)->GetGeneratorTargets();
+ std::string subdir = (*it)->Convert((*it)->GetCurrentBinaryDirectory(),
+ cmOutputConverter::HOME_OUTPUT);
+ if (subdir == ".") {
+ subdir = "";
+ }
+
+ for (std::vector<cmGeneratorTarget*>::const_iterator ti = targets.begin();
+ ti != targets.end(); ++ti) {
+ std::string targetName = (*ti)->GetName();
+ switch ((*ti)->GetType()) {
+ case cmState::GLOBAL_TARGET: {
+ // Only add the global targets from CMAKE_BINARY_DIR,
+ // not from the subdirs
+ if (subdir.empty()) {
+ this->AppendTarget(xml, targetName, make, makeArgs, subdir, ": ");
+ }
+ } break;
+ case cmState::UTILITY:
+ // Add all utility targets, except the Nightly/Continuous/
+ // Experimental-"sub"targets as e.g. NightlyStart
+ if (((targetName.find("Nightly") == 0) &&
+ (targetName != "Nightly")) ||
+ ((targetName.find("Continuous") == 0) &&
+ (targetName != "Continuous")) ||
+ ((targetName.find("Experimental") == 0) &&
+ (targetName != "Experimental"))) {
+ break;
+ }
+
+ this->AppendTarget(xml, targetName, make, makeArgs, subdir, ": ");
+ break;
+ case cmState::EXECUTABLE:
+ case cmState::STATIC_LIBRARY:
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ case cmState::OBJECT_LIBRARY: {
+ const char* prefix =
+ ((*ti)->GetType() == cmState::EXECUTABLE ? "[exe] " : "[lib] ");
+ this->AppendTarget(xml, targetName, make, makeArgs, subdir, prefix);
+ std::string fastTarget = targetName;
+ fastTarget += "/fast";
+ this->AppendTarget(xml, fastTarget, make, makeArgs, subdir, prefix);
+
+ // Add Build and Clean targets in the virtual folder of targets:
+ if (this->SupportsVirtualFolders) {
+ std::string virtDir = "[Targets]/";
+ virtDir += prefix;
+ virtDir += targetName;
+ std::string buildArgs = "-C \"";
+ buildArgs += (*it)->GetBinaryDirectory();
+ buildArgs += "\" ";
+ buildArgs += makeArgs;
+ this->AppendTarget(xml, "Build", make, buildArgs, virtDir, "",
+ targetName.c_str());
+
+ std::string cleanArgs = "-E chdir \"";
+ cleanArgs += (*it)->GetCurrentBinaryDirectory();
+ cleanArgs += "\" \"";
+ cleanArgs += cmSystemTools::GetCMakeCommand();
+ cleanArgs += "\" -P \"";
+ cmGeneratorTarget* gt = *ti;
+ cleanArgs += (*it)->GetTargetDirectory(gt);
+ cleanArgs += "/cmake_clean.cmake\"";
+ this->AppendTarget(xml, "Clean", cmSystemTools::GetCMakeCommand(),
+ cleanArgs, virtDir, "", "");
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+
+ // insert the all and clean targets in every subdir
+ if (!allTarget.empty()) {
+ this->AppendTarget(xml, allTarget, make, makeArgs, subdir, ": ");
+ }
+ if (!cleanTarget.empty()) {
+ this->AppendTarget(xml, cleanTarget, make, makeArgs, subdir, ": ");
+ }
+
+ // insert rules for compiling, preprocessing and assembling individual
+ // files
+ std::vector<std::string> objectFileTargets;
+ (*it)->GetIndividualFileTargets(objectFileTargets);
+ for (std::vector<std::string>::const_iterator fit =
+ objectFileTargets.begin();
+ fit != objectFileTargets.end(); ++fit) {
+ const char* prefix = "[obj] ";
+ if ((*fit)[fit->length() - 1] == 's') {
+ prefix = "[to asm] ";
+ } else if ((*fit)[fit->length() - 1] == 'i') {
+ prefix = "[pre] ";
+ }
+ this->AppendTarget(xml, *fit, make, makeArgs, subdir, prefix);
+ }
+ }
+
+ xml.EndElement(); // buildTargets
+ xml.EndElement(); // storageModule
+
+ this->AppendStorageScanners(xml, *mf);
+
+ xml.EndElement(); // cconfiguration
+ xml.EndElement(); // storageModule
+
+ xml.StartElement("storageModule");
+ xml.Attribute("moduleId", "cdtBuildSystem");
+ xml.Attribute("version", "4.0.0");
+
+ xml.StartElement("project");
+ xml.Attribute("id", std::string(lg->GetProjectName()) + ".null.1");
+ xml.Attribute("name", lg->GetProjectName());
+ xml.EndElement(); // project
+
+ xml.EndElement(); // storageModule
+ xml.EndElement(); // cproject
+}
+
+std::string cmExtraEclipseCDT4Generator::GetEclipsePath(
+ const std::string& path)
+{
+#if defined(__CYGWIN__)
+ std::string cmd = "cygpath -m " + path;
+ std::string out;
+ if (!cmSystemTools::RunSingleCommand(cmd.c_str(), &out, &out)) {
+ return path;
+ } else {
+ out.erase(out.find_last_of('\n'));
+ return out;
+ }
+#else
+ return path;
+#endif
+}
+
+std::string cmExtraEclipseCDT4Generator::GetPathBasename(
+ const std::string& path)
+{
+ std::string outputBasename = path;
+ while (!outputBasename.empty() &&
+ (outputBasename[outputBasename.size() - 1] == '/' ||
+ outputBasename[outputBasename.size() - 1] == '\\')) {
+ outputBasename.resize(outputBasename.size() - 1);
+ }
+ std::string::size_type loc = outputBasename.find_last_of("/\\");
+ if (loc != std::string::npos) {
+ outputBasename = outputBasename.substr(loc + 1);
+ }
+
+ return outputBasename;
+}
+
+std::string cmExtraEclipseCDT4Generator::GenerateProjectName(
+ const std::string& name, const std::string& type, const std::string& path)
+{
+ return name + (type.empty() ? "" : "-") + type + "@" + path;
+}
+
+// Helper functions
+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");
+ std::string compiler = makefile.GetSafeDefinition("CMAKE_C_COMPILER");
+ std::string arg1 = makefile.GetSafeDefinition("CMAKE_C_COMPILER_ARG1");
+ if (compiler.empty()) {
+ compiler = makefile.GetSafeDefinition("CMAKE_CXX_COMPILER");
+ arg1 = makefile.GetSafeDefinition("CMAKE_CXX_COMPILER_ARG1");
+ }
+ if (compiler.empty()) // Hmm, what to do now ?
+ {
+ compiler = "gcc";
+ }
+
+ // the following right now hardcodes gcc behaviour :-/
+ std::string compilerArgs =
+ "-E -P -v -dD ${plugin_state_location}/${specs_file}";
+ if (!arg1.empty()) {
+ arg1 += " ";
+ compilerArgs = arg1 + compilerArgs;
+ }
+
+ xml.StartElement("storageModule");
+ xml.Attribute("moduleId", "scannerConfiguration");
+
+ xml.StartElement("autodiscovery");
+ xml.Attribute("enabled", "true");
+ xml.Attribute("problemReportingEnabled", "true");
+ xml.Attribute("selectedProfileId",
+ "org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile");
+ xml.EndElement(); // autodiscovery
+
+ cmExtraEclipseCDT4Generator::AppendScannerProfile(
+ xml, "org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile", true,
+ "", true, "specsFile", compilerArgs, compiler, true, true);
+ cmExtraEclipseCDT4Generator::AppendScannerProfile(
+ xml, "org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile", true, "",
+ true, "makefileGenerator", "-f ${project_name}_scd.mk", make, true, true);
+
+ xml.EndElement(); // storageModule
+}
+
+// The prefix is prepended before the actual name of the target. The purpose
+// of that is to sort the targets in the view of Eclipse, so that at first
+// the global/utility/all/clean targets appear ": ", then the executable
+// targets "[exe] ", then the libraries "[lib]", then the rules for the
+// object files "[obj]", then for preprocessing only "[pre] " and
+// finally the assembly files "[to asm] ". Note the "to" in "to asm",
+// without it, "asm" would be the first targets in the list, with the "to"
+// they are the last targets, which makes more sense.
+void cmExtraEclipseCDT4Generator::AppendTarget(
+ cmXMLWriter& xml, const std::string& target, const std::string& make,
+ const std::string& makeArgs, const std::string& path, const char* prefix,
+ const char* makeTarget)
+{
+ xml.StartElement("target");
+ xml.Attribute("name", prefix + target);
+ xml.Attribute("path", path);
+ xml.Attribute("targetID", "org.eclipse.cdt.make.MakeTargetBuilder");
+ xml.Element("buildCommand",
+ cmExtraEclipseCDT4Generator::GetEclipsePath(make));
+ xml.Element("buildArguments", makeArgs);
+ xml.Element("buildTarget", makeTarget ? makeTarget : target.c_str());
+ xml.Element("stopOnError", "true");
+ xml.Element("useDefaultCommand", "false");
+ xml.EndElement();
+}
+
+void cmExtraEclipseCDT4Generator::AppendScannerProfile(
+ cmXMLWriter& xml, const std::string& profileID, bool openActionEnabled,
+ const std::string& openActionFilePath, bool pParserEnabled,
+ const std::string& scannerInfoProviderID,
+ const std::string& runActionArguments, const std::string& runActionCommand,
+ bool runActionUseDefault, bool sipParserEnabled)
+{
+ xml.StartElement("profile");
+ xml.Attribute("id", profileID);
+
+ xml.StartElement("buildOutputProvider");
+ xml.StartElement("openAction");
+ xml.Attribute("enabled", openActionEnabled ? "true" : "false");
+ xml.Attribute("filePath", openActionFilePath);
+ xml.EndElement(); // openAction
+ xml.StartElement("parser");
+ xml.Attribute("enabled", pParserEnabled ? "true" : "false");
+ xml.EndElement(); // parser
+ xml.EndElement(); // buildOutputProvider
+
+ xml.StartElement("scannerInfoProvider");
+ xml.Attribute("id", scannerInfoProviderID);
+ xml.StartElement("runAction");
+ xml.Attribute("arguments", runActionArguments);
+ xml.Attribute("command", runActionCommand);
+ xml.Attribute("useDefault", runActionUseDefault ? "true" : "false");
+ xml.EndElement(); // runAction
+ xml.StartElement("parser");
+ xml.Attribute("enabled", sipParserEnabled ? "true" : "false");
+ xml.EndElement(); // parser
+ xml.EndElement(); // scannerInfoProvider
+
+ xml.EndElement(); // profile
+}
+
+void cmExtraEclipseCDT4Generator::AppendLinkedResource(cmXMLWriter& xml,
+ const std::string& name,
+ const std::string& path,
+ LinkType linkType)
+{
+ const char* locationTag = "location";
+ int typeTag = 2;
+ if (linkType == VirtualFolder) // ... and not a linked folder
+ {
+ locationTag = "locationURI";
+ }
+ if (linkType == LinkToFile) {
+ typeTag = 1;
+ }
+
+ xml.StartElement("link");
+ xml.Element("name", name);
+ xml.Element("type", typeTag);
+ xml.Element(locationTag, path);
+ xml.EndElement();
+}
diff --git a/Source/cmExtraEclipseCDT4Generator.h b/Source/cmExtraEclipseCDT4Generator.h
new file mode 100644
index 0000000..0400ad5
--- /dev/null
+++ b/Source/cmExtraEclipseCDT4Generator.h
@@ -0,0 +1,122 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2009 Kitware, Inc.
+ Copyright 2004 Alexander Neundorf (neundorf@kde.org)
+ Copyright 2007 Miguel A. Figueroa-Villanueva
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExtraEclipseCDT4Generator_h
+#define cmExtraEclipseCDT4Generator_h
+
+#include "cmExternalMakefileProjectGenerator.h"
+
+class cmMakefile;
+class cmXMLWriter;
+class cmSourceGroup;
+
+/** \class cmExtraEclipseCDT4Generator
+ * \brief Write Eclipse project files for Makefile based projects
+ */
+class cmExtraEclipseCDT4Generator : public cmExternalMakefileProjectGenerator
+{
+public:
+ enum LinkType
+ {
+ VirtualFolder,
+ LinkToFolder,
+ LinkToFile
+ };
+
+ cmExtraEclipseCDT4Generator();
+
+ static cmExternalMakefileProjectGenerator* New()
+ {
+ return new cmExtraEclipseCDT4Generator;
+ }
+
+ std::string GetName() const CM_OVERRIDE
+ {
+ return cmExtraEclipseCDT4Generator::GetActualName();
+ }
+
+ static std::string GetActualName() { return "Eclipse CDT4"; }
+
+ void GetDocumentation(cmDocumentationEntry& entry,
+ const std::string& fullName) const CM_OVERRIDE;
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) CM_OVERRIDE;
+
+ void Generate() CM_OVERRIDE;
+
+private:
+ // create .project file in the source tree
+ void CreateSourceProjectFile();
+
+ // create .project file
+ void CreateProjectFile();
+
+ // create .cproject file
+ void CreateCProjectFile() const;
+
+ // If built with cygwin cmake, convert posix to windows path.
+ static std::string GetEclipsePath(const std::string& path);
+
+ // Extract basename.
+ static std::string GetPathBasename(const std::string& path);
+
+ // Generate the project name as: <name>-<type>@<path>
+ static std::string GenerateProjectName(const std::string& name,
+ const std::string& type,
+ const std::string& path);
+
+ // Helper functions
+ static void AppendStorageScanners(cmXMLWriter& xml,
+ const cmMakefile& makefile);
+ static void AppendTarget(cmXMLWriter& xml, const std::string& target,
+ const std::string& make,
+ const std::string& makeArguments,
+ const std::string& path, const char* prefix = "",
+ const char* makeTarget = CM_NULLPTR);
+ static void AppendScannerProfile(
+ cmXMLWriter& xml, const std::string& profileID, bool openActionEnabled,
+ const std::string& openActionFilePath, bool pParserEnabled,
+ const std::string& scannerInfoProviderID,
+ const std::string& runActionArguments, const std::string& runActionCommand,
+ bool runActionUseDefault, bool sipParserEnabled);
+
+ static void AppendLinkedResource(cmXMLWriter& xml, const std::string& name,
+ const std::string& path, LinkType linkType);
+
+ static void AppendIncludeDirectories(
+ cmXMLWriter& xml, const std::vector<std::string>& includeDirs,
+ std::set<std::string>& emittedDirs);
+
+ static void AddEnvVar(std::ostream& out, const char* envVar,
+ cmLocalGenerator* lg);
+
+ void WriteGroups(std::vector<cmSourceGroup> const& sourceGroups,
+ std::string& linkName, cmXMLWriter& xml);
+ void CreateLinksToSubprojects(cmXMLWriter& xml, const std::string& baseDir);
+ void CreateLinksForTargets(cmXMLWriter& xml);
+
+ std::vector<std::string> SrcLinkedResources;
+ std::set<std::string> Natures;
+ std::string HomeDirectory;
+ std::string HomeOutputDirectory;
+ bool IsOutOfSourceBuild;
+ bool GenerateSourceProject;
+ bool GenerateLinkedResources;
+ bool SupportsVirtualFolders;
+ bool SupportsGmakeErrorParser;
+ bool SupportsMachO64Parser;
+ bool CEnabled;
+ bool CXXEnabled;
+};
+
+#endif
diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx
new file mode 100644
index 0000000..b757a49
--- /dev/null
+++ b/Source/cmExtraKateGenerator.cxx
@@ -0,0 +1,318 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2009 Kitware, Inc.
+ Copyright 2004 Alexander Neundorf (neundorf@kde.org)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmExtraKateGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cmsys/SystemTools.hxx>
+
+void cmExtraKateGenerator::GetDocumentation(cmDocumentationEntry& entry,
+ const std::string&) const
+{
+ entry.Name = this->GetName();
+ entry.Brief = "Generates Kate project files.";
+}
+
+cmExtraKateGenerator::cmExtraKateGenerator()
+ : cmExternalMakefileProjectGenerator()
+{
+#if defined(_WIN32)
+ this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
+ this->SupportedGlobalGenerators.push_back("NMake Makefiles");
+// disable until somebody actually tests it:
+// this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
+#endif
+ this->SupportedGlobalGenerators.push_back("Ninja");
+ this->SupportedGlobalGenerators.push_back("Unix Makefiles");
+}
+
+void cmExtraKateGenerator::Generate()
+{
+ cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0];
+ const cmMakefile* mf = lg->GetMakefile();
+ this->ProjectName = this->GenerateProjectName(
+ lg->GetProjectName(), mf->GetSafeDefinition("CMAKE_BUILD_TYPE"),
+ this->GetPathBasename(lg->GetBinaryDirectory()));
+ this->UseNinja = (this->GlobalGenerator->GetName() == "Ninja");
+
+ this->CreateKateProjectFile(lg);
+ this->CreateDummyKateProjectFile(lg);
+}
+
+void cmExtraKateGenerator::CreateKateProjectFile(
+ const cmLocalGenerator* lg) const
+{
+ std::string filename = lg->GetBinaryDirectory();
+ filename += "/.kateproject";
+ cmGeneratedFileStream fout(filename.c_str());
+ if (!fout) {
+ return;
+ }
+
+ /* clang-format off */
+ fout <<
+ "{\n"
+ "\t\"name\": \"" << this->ProjectName << "\",\n"
+ "\t\"directory\": \"" << lg->GetSourceDirectory() << "\",\n"
+ "\t\"files\": [ { " << this->GenerateFilesString(lg) << "} ],\n";
+ /* clang-format on */
+ this->WriteTargets(lg, fout);
+ fout << "}\n";
+}
+
+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 =
+ mf->GetSafeDefinition("CMAKE_KATE_MAKE_ARGUMENTS");
+ const char* homeOutputDir = lg->GetBinaryDirectory();
+
+ /* clang-format off */
+ fout <<
+ "\t\"build\": {\n"
+ "\t\t\"directory\": \"" << lg->GetBinaryDirectory() << "\",\n"
+ "\t\t\"default_target\": \"all\",\n"
+ "\t\t\"clean_target\": \"clean\",\n";
+ /* clang-format on */
+
+ // build, clean and quick are for the build plugin kate <= 4.12:
+ fout << "\t\t\"build\": \"" << make << " -C \\\"" << homeOutputDir << "\\\" "
+ << makeArgs << " "
+ << "all\",\n";
+ fout << "\t\t\"clean\": \"" << make << " -C \\\"" << homeOutputDir << "\\\" "
+ << makeArgs << " "
+ << "clean\",\n";
+ fout << "\t\t\"quick\": \"" << make << " -C \\\"" << homeOutputDir << "\\\" "
+ << makeArgs << " "
+ << "install\",\n";
+
+ // this is for kate >= 4.13:
+ fout << "\t\t\"targets\":[\n";
+
+ this->AppendTarget(fout, "all", make, makeArgs, homeOutputDir,
+ homeOutputDir);
+ this->AppendTarget(fout, "clean", make, makeArgs, homeOutputDir,
+ homeOutputDir);
+
+ // add all executable and library targets and some of the GLOBAL
+ // and UTILITY targets
+ for (std::vector<cmLocalGenerator*>::const_iterator it =
+ this->GlobalGenerator->GetLocalGenerators().begin();
+ it != this->GlobalGenerator->GetLocalGenerators().end(); ++it) {
+ const std::vector<cmGeneratorTarget*> targets =
+ (*it)->GetGeneratorTargets();
+ std::string currentDir = (*it)->GetCurrentBinaryDirectory();
+ bool topLevel = (currentDir == (*it)->GetBinaryDirectory());
+
+ for (std::vector<cmGeneratorTarget*>::const_iterator ti = targets.begin();
+ ti != targets.end(); ++ti) {
+ std::string targetName = (*ti)->GetName();
+ switch ((*ti)->GetType()) {
+ case cmState::GLOBAL_TARGET: {
+ bool insertTarget = false;
+ // Only add the global targets from CMAKE_BINARY_DIR,
+ // not from the subdirs
+ if (topLevel) {
+ insertTarget = true;
+ // only add the "edit_cache" target if it's not ccmake, because
+ // this will not work within the IDE
+ if (targetName == "edit_cache") {
+ const char* editCommand =
+ (*it)->GetMakefile()->GetDefinition("CMAKE_EDIT_COMMAND");
+ if (editCommand == CM_NULLPTR) {
+ insertTarget = false;
+ } else if (strstr(editCommand, "ccmake") != CM_NULLPTR) {
+ insertTarget = false;
+ }
+ }
+ }
+ if (insertTarget) {
+ this->AppendTarget(fout, targetName, make, makeArgs, currentDir,
+ homeOutputDir);
+ }
+ } break;
+ case cmState::UTILITY:
+ // Add all utility targets, except the Nightly/Continuous/
+ // Experimental-"sub"targets as e.g. NightlyStart
+ if (((targetName.find("Nightly") == 0) &&
+ (targetName != "Nightly")) ||
+ ((targetName.find("Continuous") == 0) &&
+ (targetName != "Continuous")) ||
+ ((targetName.find("Experimental") == 0) &&
+ (targetName != "Experimental"))) {
+ break;
+ }
+
+ this->AppendTarget(fout, targetName, make, makeArgs, currentDir,
+ homeOutputDir);
+ break;
+ case cmState::EXECUTABLE:
+ case cmState::STATIC_LIBRARY:
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ case cmState::OBJECT_LIBRARY: {
+ this->AppendTarget(fout, targetName, make, makeArgs, currentDir,
+ homeOutputDir);
+ std::string fastTarget = targetName;
+ fastTarget += "/fast";
+ this->AppendTarget(fout, fastTarget, make, makeArgs, currentDir,
+ homeOutputDir);
+
+ } break;
+ default:
+ break;
+ }
+ }
+
+ // insert rules for compiling, preprocessing and assembling individual
+ // files
+ std::vector<std::string> objectFileTargets;
+ (*it)->GetIndividualFileTargets(objectFileTargets);
+ for (std::vector<std::string>::const_iterator fit =
+ objectFileTargets.begin();
+ fit != objectFileTargets.end(); ++fit) {
+ this->AppendTarget(fout, *fit, make, makeArgs, currentDir,
+ homeOutputDir);
+ }
+ }
+
+ fout << "\t] }\n";
+}
+
+void cmExtraKateGenerator::AppendTarget(cmGeneratedFileStream& fout,
+ const std::string& target,
+ const std::string& make,
+ const std::string& makeArgs,
+ const std::string& path,
+ const char* homeOutputDir) const
+{
+ static char JsonSep = ' ';
+
+ fout << "\t\t\t" << JsonSep << "{\"name\":\"" << target << "\", "
+ "\"build_cmd\":\""
+ << make << " -C \\\"" << (this->UseNinja ? homeOutputDir : path.c_str())
+ << "\\\" " << makeArgs << " " << target << "\"}\n";
+
+ JsonSep = ',';
+}
+
+void cmExtraKateGenerator::CreateDummyKateProjectFile(
+ const cmLocalGenerator* lg) const
+{
+ std::string filename = lg->GetBinaryDirectory();
+ filename += "/";
+ filename += this->ProjectName;
+ filename += ".kateproject";
+ cmGeneratedFileStream fout(filename.c_str());
+ if (!fout) {
+ return;
+ }
+
+ fout << "#Generated by " << cmSystemTools::GetCMakeCommand()
+ << ", do not edit.\n";
+}
+
+std::string cmExtraKateGenerator::GenerateFilesString(
+ const cmLocalGenerator* lg) const
+{
+ std::string s = lg->GetSourceDirectory();
+ s += "/.git";
+ if (cmSystemTools::FileExists(s.c_str())) {
+ return std::string("\"git\": 1 ");
+ }
+
+ s = lg->GetSourceDirectory();
+ s += "/.svn";
+ if (cmSystemTools::FileExists(s.c_str())) {
+ return std::string("\"svn\": 1 ");
+ }
+
+ s = lg->GetSourceDirectory();
+ s += "/";
+
+ std::set<std::string> files;
+ std::string tmp;
+ const std::vector<cmLocalGenerator*>& lgs =
+ this->GlobalGenerator->GetLocalGenerators();
+
+ for (std::vector<cmLocalGenerator*>::const_iterator it = lgs.begin();
+ it != lgs.end(); it++) {
+ cmMakefile* makefile = (*it)->GetMakefile();
+ const std::vector<std::string>& listFiles = makefile->GetListFiles();
+ for (std::vector<std::string>::const_iterator lt = listFiles.begin();
+ lt != listFiles.end(); lt++) {
+ tmp = *lt;
+ {
+ files.insert(tmp);
+ }
+ }
+
+ const std::vector<cmSourceFile*>& sources = makefile->GetSourceFiles();
+ for (std::vector<cmSourceFile*>::const_iterator sfIt = sources.begin();
+ sfIt != sources.end(); sfIt++) {
+ cmSourceFile* sf = *sfIt;
+ if (sf->GetPropertyAsBool("GENERATED")) {
+ continue;
+ }
+
+ tmp = sf->GetFullPath();
+ files.insert(tmp);
+ }
+ }
+
+ const char* sep = "";
+ tmp = "\"list\": [";
+ for (std::set<std::string>::const_iterator it = files.begin();
+ it != files.end(); ++it) {
+ tmp += sep;
+ tmp += " \"";
+ tmp += *it;
+ tmp += "\"";
+ sep = ",";
+ }
+ tmp += "] ";
+
+ return tmp;
+}
+
+std::string cmExtraKateGenerator::GenerateProjectName(
+ const std::string& name, const std::string& type,
+ const std::string& path) const
+{
+ return name + (type.empty() ? "" : "-") + type + "@" + path;
+}
+
+std::string cmExtraKateGenerator::GetPathBasename(
+ const std::string& path) const
+{
+ std::string outputBasename = path;
+ while (!outputBasename.empty() &&
+ (outputBasename[outputBasename.size() - 1] == '/' ||
+ outputBasename[outputBasename.size() - 1] == '\\')) {
+ outputBasename.resize(outputBasename.size() - 1);
+ }
+ std::string::size_type loc = outputBasename.find_last_of("/\\");
+ if (loc != std::string::npos) {
+ outputBasename = outputBasename.substr(loc + 1);
+ }
+
+ return outputBasename;
+}
diff --git a/Source/cmExtraKateGenerator.h b/Source/cmExtraKateGenerator.h
new file mode 100644
index 0000000..410d552
--- /dev/null
+++ b/Source/cmExtraKateGenerator.h
@@ -0,0 +1,63 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2009 Kitware, Inc.
+ Copyright 2013 Alexander Neundorf (neundorf@kde.org)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExtraKateGenerator_h
+#define cmExtraKateGenerator_h
+
+#include "cmExternalMakefileProjectGenerator.h"
+
+class cmLocalGenerator;
+class cmGeneratedFileStream;
+
+/** \class cmExtraKateGenerator
+ * \brief Write Kate project files for Makefile or ninja based projects
+ */
+class cmExtraKateGenerator : public cmExternalMakefileProjectGenerator
+{
+public:
+ cmExtraKateGenerator();
+
+ std::string GetName() const CM_OVERRIDE
+ {
+ return cmExtraKateGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "Kate"; }
+ static cmExternalMakefileProjectGenerator* New()
+ {
+ return new cmExtraKateGenerator;
+ }
+ /** Get the documentation entry for this generator. */
+ void GetDocumentation(cmDocumentationEntry& entry,
+ const std::string& fullName) const CM_OVERRIDE;
+
+ void Generate() CM_OVERRIDE;
+
+private:
+ void CreateKateProjectFile(const cmLocalGenerator* lg) const;
+ void CreateDummyKateProjectFile(const cmLocalGenerator* lg) const;
+ void WriteTargets(const cmLocalGenerator* lg,
+ cmGeneratedFileStream& fout) const;
+ void AppendTarget(cmGeneratedFileStream& fout, const std::string& target,
+ const std::string& make, const std::string& makeArgs,
+ const std::string& path, const char* homeOutputDir) const;
+
+ std::string GenerateFilesString(const cmLocalGenerator* lg) const;
+ std::string GetPathBasename(const std::string& path) const;
+ std::string GenerateProjectName(const std::string& name,
+ const std::string& type,
+ const std::string& path) const;
+
+ std::string ProjectName;
+ bool UseNinja;
+};
+
+#endif
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
new file mode 100644
index 0000000..c166e26
--- /dev/null
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -0,0 +1,371 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2009 Kitware, Inc.
+ Copyright 2004 Alexander Neundorf (neundorf@kde.org)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmExtraSublimeTextGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalGenerator.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cmsys/SystemTools.hxx>
+
+/*
+Sublime Text 2 Generator
+Author: Morné Chamberlain
+This generator was initially based off of the CodeBlocks generator.
+
+Some useful URLs:
+Homepage:
+http://www.sublimetext.com/
+
+File format docs:
+http://www.sublimetext.com/docs/2/projects.html
+http://sublimetext.info/docs/en/reference/build_systems.html
+*/
+
+void cmExtraSublimeTextGenerator::GetDocumentation(cmDocumentationEntry& entry,
+ const std::string&) const
+{
+ entry.Name = this->GetName();
+ entry.Brief = "Generates Sublime Text 2 project files.";
+}
+
+cmExtraSublimeTextGenerator::cmExtraSublimeTextGenerator()
+ : cmExternalMakefileProjectGenerator()
+{
+#if defined(_WIN32)
+ this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
+ this->SupportedGlobalGenerators.push_back("NMake Makefiles");
+// disable until somebody actually tests it:
+// this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
+#endif
+ this->SupportedGlobalGenerators.push_back("Ninja");
+ this->SupportedGlobalGenerators.push_back("Unix Makefiles");
+}
+
+void cmExtraSublimeTextGenerator::Generate()
+{
+ // for each sub project in the project create a sublime text 2 project
+ for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
+ it = this->GlobalGenerator->GetProjectMap().begin();
+ it != this->GlobalGenerator->GetProjectMap().end(); ++it) {
+ // create a project file
+ this->CreateProjectFile(it->second);
+ }
+}
+
+void cmExtraSublimeTextGenerator::CreateProjectFile(
+ const std::vector<cmLocalGenerator*>& lgs)
+{
+ std::string outputDir = lgs[0]->GetCurrentBinaryDirectory();
+ std::string projectName = lgs[0]->GetProjectName();
+
+ const std::string filename =
+ outputDir + "/" + projectName + ".sublime-project";
+
+ this->CreateNewProjectFile(lgs, filename);
+}
+
+void cmExtraSublimeTextGenerator::CreateNewProjectFile(
+ const std::vector<cmLocalGenerator*>& lgs, const std::string& filename)
+{
+ const cmMakefile* mf = lgs[0]->GetMakefile();
+ cmGeneratedFileStream fout(filename.c_str());
+ if (!fout) {
+ return;
+ }
+
+ const std::string& sourceRootRelativeToOutput = cmSystemTools::RelativePath(
+ lgs[0]->GetBinaryDirectory(), lgs[0]->GetSourceDirectory());
+ // Write the folder entries to the project file
+ fout << "{\n";
+ fout << "\t\"folders\":\n\t[\n\t";
+ if (!sourceRootRelativeToOutput.empty()) {
+ fout << "\t{\n\t\t\t\"path\": \"" << sourceRootRelativeToOutput << "\"";
+ const std::string& outputRelativeToSourceRoot =
+ cmSystemTools::RelativePath(lgs[0]->GetSourceDirectory(),
+ lgs[0]->GetBinaryDirectory());
+ if ((!outputRelativeToSourceRoot.empty()) &&
+ ((outputRelativeToSourceRoot.length() < 3) ||
+ (outputRelativeToSourceRoot.substr(0, 3) != "../"))) {
+ fout << ",\n\t\t\t\"folder_exclude_patterns\": [\""
+ << outputRelativeToSourceRoot << "\"]";
+ }
+ } else {
+ fout << "\t{\n\t\t\t\"path\": \"./\"";
+ }
+ fout << "\n\t\t}";
+ // End of the folders section
+ fout << "\n\t]";
+
+ // Write the beginning of the build systems section to the project file
+ fout << ",\n\t\"build_systems\":\n\t[\n\t";
+
+ // Set of include directories over all targets (sublime text/sublimeclang
+ // doesn't currently support these settings per build system, only project
+ // wide
+ MapSourceFileFlags sourceFileFlags;
+ AppendAllTargets(lgs, mf, fout, sourceFileFlags);
+
+ // End of build_systems
+ fout << "\n\t]";
+ fout << "\n\t}";
+}
+
+void cmExtraSublimeTextGenerator::AppendAllTargets(
+ const std::vector<cmLocalGenerator*>& lgs, const cmMakefile* mf,
+ cmGeneratedFileStream& fout, MapSourceFileFlags& sourceFileFlags)
+{
+ std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ std::string compiler = "";
+ if (!lgs.empty()) {
+ this->AppendTarget(fout, "all", lgs[0], CM_NULLPTR, make.c_str(), mf,
+ compiler.c_str(), sourceFileFlags, true);
+ this->AppendTarget(fout, "clean", lgs[0], CM_NULLPTR, make.c_str(), mf,
+ compiler.c_str(), sourceFileFlags, false);
+ }
+
+ // add all executable and library targets and some of the GLOBAL
+ // and UTILITY targets
+ for (std::vector<cmLocalGenerator*>::const_iterator lg = lgs.begin();
+ lg != lgs.end(); lg++) {
+ cmMakefile* makefile = (*lg)->GetMakefile();
+ std::vector<cmGeneratorTarget*> targets = (*lg)->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator ti = targets.begin();
+ ti != targets.end(); ti++) {
+ std::string targetName = (*ti)->GetName();
+ switch ((*ti)->GetType()) {
+ case cmState::GLOBAL_TARGET: {
+ // Only add the global targets from CMAKE_BINARY_DIR,
+ // not from the subdirs
+ if (strcmp((*lg)->GetCurrentBinaryDirectory(),
+ (*lg)->GetBinaryDirectory()) == 0) {
+ this->AppendTarget(fout, targetName, *lg, CM_NULLPTR, make.c_str(),
+ makefile, compiler.c_str(), sourceFileFlags,
+ false);
+ }
+ } break;
+ case cmState::UTILITY:
+ // Add all utility targets, except the Nightly/Continuous/
+ // Experimental-"sub"targets as e.g. NightlyStart
+ if (((targetName.find("Nightly") == 0) &&
+ (targetName != "Nightly")) ||
+ ((targetName.find("Continuous") == 0) &&
+ (targetName != "Continuous")) ||
+ ((targetName.find("Experimental") == 0) &&
+ (targetName != "Experimental"))) {
+ break;
+ }
+
+ this->AppendTarget(fout, targetName, *lg, CM_NULLPTR, make.c_str(),
+ makefile, compiler.c_str(), sourceFileFlags,
+ false);
+ break;
+ case cmState::EXECUTABLE:
+ case cmState::STATIC_LIBRARY:
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ case cmState::OBJECT_LIBRARY: {
+ this->AppendTarget(fout, targetName, *lg, *ti, make.c_str(),
+ makefile, compiler.c_str(), sourceFileFlags,
+ false);
+ std::string fastTarget = targetName;
+ fastTarget += "/fast";
+ this->AppendTarget(fout, fastTarget, *lg, *ti, make.c_str(),
+ makefile, compiler.c_str(), sourceFileFlags,
+ false);
+ } break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void cmExtraSublimeTextGenerator::AppendTarget(
+ cmGeneratedFileStream& fout, const std::string& targetName,
+ cmLocalGenerator* lg, cmGeneratorTarget* target, const char* make,
+ const cmMakefile* makefile,
+ const char*, // compiler
+ MapSourceFileFlags& sourceFileFlags, bool firstTarget)
+{
+
+ if (target != CM_NULLPTR) {
+ std::vector<cmSourceFile*> sourceFiles;
+ target->GetSourceFiles(sourceFiles,
+ makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ std::vector<cmSourceFile*>::const_iterator sourceFilesEnd =
+ sourceFiles.end();
+ for (std::vector<cmSourceFile*>::const_iterator iter = sourceFiles.begin();
+ iter != sourceFilesEnd; ++iter) {
+ cmSourceFile* sourceFile = *iter;
+ MapSourceFileFlags::iterator sourceFileFlagsIter =
+ sourceFileFlags.find(sourceFile->GetFullPath());
+ if (sourceFileFlagsIter == sourceFileFlags.end()) {
+ sourceFileFlagsIter =
+ sourceFileFlags
+ .insert(MapSourceFileFlags::value_type(sourceFile->GetFullPath(),
+ std::vector<std::string>()))
+ .first;
+ }
+ std::vector<std::string>& flags = sourceFileFlagsIter->second;
+ std::string flagsString = this->ComputeFlagsForObject(*iter, lg, target);
+ std::string definesString = this->ComputeDefines(*iter, lg, target);
+ flags.clear();
+ cmsys::RegularExpression flagRegex;
+ // Regular expression to extract compiler flags from a string
+ // https://gist.github.com/3944250
+ const char* regexString =
+ "(^|[ ])-[DIOUWfgs][^= ]+(=\\\"[^\"]+\\\"|=[^\"][^ ]+)?";
+ flagRegex.compile(regexString);
+ std::string workString = flagsString + " " + definesString;
+ while (flagRegex.find(workString)) {
+ std::string::size_type start = flagRegex.start();
+ if (workString[start] == ' ') {
+ start++;
+ }
+ flags.push_back(workString.substr(start, flagRegex.end() - start));
+ if (flagRegex.end() < workString.size()) {
+ workString = workString.substr(flagRegex.end());
+ } else {
+ workString = "";
+ }
+ }
+ }
+ }
+
+ // Ninja uses ninja.build files (look for a way to get the output file name
+ // from cmMakefile or something)
+ std::string makefileName;
+ if (this->GlobalGenerator->GetName() == "Ninja") {
+ makefileName = "build.ninja";
+ } else {
+ makefileName = "Makefile";
+ }
+ if (!firstTarget) {
+ fout << ",\n\t";
+ }
+ fout << "\t{\n\t\t\t\"name\": \"" << lg->GetProjectName() << " - "
+ << targetName << "\",\n";
+ fout << "\t\t\t\"cmd\": ["
+ << this->BuildMakeCommand(make, makefileName.c_str(), targetName)
+ << "],\n";
+ fout << "\t\t\t\"working_dir\": \"${project_path}\",\n";
+ fout << "\t\t\t\"file_regex\": \"^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$\"\n";
+ fout << "\t\t}";
+}
+
+// Create the command line for building the given target using the selected
+// make
+std::string cmExtraSublimeTextGenerator::BuildMakeCommand(
+ const std::string& make, const char* makefile, const std::string& target)
+{
+ std::string command = "\"";
+ command += make + "\"";
+ std::string generator = this->GlobalGenerator->GetName();
+ if (generator == "NMake Makefiles") {
+ std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
+ command += ", \"/NOLOGO\", \"/f\", \"";
+ command += makefileName + "\"";
+ command += ", \"VERBOSE=1\", \"";
+ command += target;
+ command += "\"";
+ } else if (generator == "Ninja") {
+ std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
+ command += ", \"-f\", \"";
+ command += makefileName + "\"";
+ command += ", \"-v\", \"";
+ command += target;
+ command += "\"";
+ } else {
+ std::string makefileName;
+ if (generator == "MinGW Makefiles") {
+ // no escaping of spaces in this case, see
+ // http://public.kitware.com/Bug/view.php?id=10014
+ makefileName = makefile;
+ } else {
+ makefileName = cmSystemTools::ConvertToOutputPath(makefile);
+ }
+ command += ", \"-f\", \"";
+ command += makefileName + "\"";
+ command += ", \"VERBOSE=1\", \"";
+ command += target;
+ command += "\"";
+ }
+ return command;
+}
+
+// TODO: Most of the code is picked up from the Ninja generator, refactor it.
+std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject(
+ cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* gtgt)
+{
+ std::string flags;
+ std::string language = source->GetLanguage();
+ if (language.empty()) {
+ language = "C";
+ }
+ std::string const& config =
+ lg->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
+
+ lg->GetTargetCompileFlags(gtgt, config, language, flags);
+
+ // Add include directory flags.
+ {
+ std::vector<std::string> includes;
+ lg->GetIncludeDirectories(includes, gtgt, language, config);
+ std::string includeFlags = lg->GetIncludeFlags(includes, gtgt, language,
+ true); // full include paths
+ lg->AppendFlags(flags, includeFlags);
+ }
+
+ // Add source file specific flags.
+ lg->AppendFlags(flags, source->GetProperty("COMPILE_FLAGS"));
+
+ return flags;
+}
+
+// TODO: Refactor with
+// void cmMakefileTargetGenerator::WriteTargetLanguageFlags().
+std::string cmExtraSublimeTextGenerator::ComputeDefines(
+ cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* target)
+
+{
+ std::set<std::string> defines;
+ cmMakefile* makefile = lg->GetMakefile();
+ const std::string& language = source->GetLanguage();
+ const std::string& config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+
+ // Add the export symbol definition for shared library objects.
+ if (const char* exportMacro = target->GetExportMacro()) {
+ lg->AppendDefines(defines, exportMacro);
+ }
+
+ // Add preprocessor definitions for this target and configuration.
+ lg->AddCompileDefinitions(defines, target, config, language);
+ lg->AppendDefines(defines, source->GetProperty("COMPILE_DEFINITIONS"));
+ {
+ std::string defPropName = "COMPILE_DEFINITIONS_";
+ defPropName += cmSystemTools::UpperCase(config);
+ lg->AppendDefines(defines, source->GetProperty(defPropName));
+ }
+
+ std::string definesString;
+ lg->JoinDefines(defines, definesString, language);
+
+ return definesString;
+}
diff --git a/Source/cmExtraSublimeTextGenerator.h b/Source/cmExtraSublimeTextGenerator.h
new file mode 100644
index 0000000..26dd138
--- /dev/null
+++ b/Source/cmExtraSublimeTextGenerator.h
@@ -0,0 +1,85 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2009 Kitware, Inc.
+ Copyright 2004 Alexander Neundorf (neundorf@kde.org)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmExtraSublimeTextGenerator_h
+#define cmExtraSublimeTextGenerator_h
+
+#include "cmExternalMakefileProjectGenerator.h"
+#include "cmSourceFile.h"
+
+class cmLocalGenerator;
+class cmMakefile;
+class cmGeneratedFileStream;
+class cmGeneratorTarget;
+
+/** \class cmExtraSublimeTextGenerator
+ * \brief Write Sublime Text 2 project files for Makefile based projects
+ */
+class cmExtraSublimeTextGenerator : public cmExternalMakefileProjectGenerator
+{
+public:
+ typedef std::map<std::string, std::vector<std::string> > MapSourceFileFlags;
+ cmExtraSublimeTextGenerator();
+
+ std::string GetName() const CM_OVERRIDE
+ {
+ return cmExtraSublimeTextGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "Sublime Text 2"; }
+ static cmExternalMakefileProjectGenerator* New()
+ {
+ return new cmExtraSublimeTextGenerator;
+ }
+ /** Get the documentation entry for this generator. */
+ void GetDocumentation(cmDocumentationEntry& entry,
+ const std::string& fullName) const CM_OVERRIDE;
+
+ void Generate() CM_OVERRIDE;
+
+private:
+ void CreateProjectFile(const std::vector<cmLocalGenerator*>& lgs);
+
+ void CreateNewProjectFile(const std::vector<cmLocalGenerator*>& lgs,
+ const std::string& filename);
+
+ /** Appends all targets as build systems to the project file and get all
+ * include directories and compiler definitions used.
+ */
+ void AppendAllTargets(const std::vector<cmLocalGenerator*>& lgs,
+ const cmMakefile* mf, cmGeneratedFileStream& fout,
+ MapSourceFileFlags& sourceFileFlags);
+ /** Returns the build command that needs to be executed to build the
+ * specified target.
+ */
+ std::string BuildMakeCommand(const std::string& make, const char* makefile,
+ const std::string& target);
+ /** Appends the specified target to the generated project file as a Sublime
+ * Text build system.
+ */
+ void AppendTarget(cmGeneratedFileStream& fout, const std::string& targetName,
+ cmLocalGenerator* lg, cmGeneratorTarget* target,
+ const char* make, const cmMakefile* makefile,
+ const char* compiler, MapSourceFileFlags& sourceFileFlags,
+ bool firstTarget);
+ /**
+ * Compute the flags for compilation of object files for a given @a language.
+ * @note Generally it is the value of the variable whose name is computed
+ * by LanguageFlagsVarName().
+ */
+ std::string ComputeFlagsForObject(cmSourceFile* source, cmLocalGenerator* lg,
+ cmGeneratorTarget* gtgt);
+
+ std::string ComputeDefines(cmSourceFile* source, cmLocalGenerator* lg,
+ cmGeneratorTarget* gtgt);
+};
+
+#endif
diff --git a/Source/cmFLTKWrapUICommand.cxx b/Source/cmFLTKWrapUICommand.cxx
new file mode 100644
index 0000000..03ee31e
--- /dev/null
+++ b/Source/cmFLTKWrapUICommand.cxx
@@ -0,0 +1,124 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmFLTKWrapUICommand.h"
+
+#include "cmSourceFile.h"
+
+// cmFLTKWrapUICommand
+bool cmFLTKWrapUICommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // what is the current source dir
+ std::string cdir = this->Makefile->GetCurrentSourceDirectory();
+ const char* fluid_exe =
+ this->Makefile->GetRequiredDefinition("FLTK_FLUID_EXECUTABLE");
+
+ // get parameter for the command
+ this->Target = args[0]; // Target that will use the generated files
+
+ // get the list of GUI files from which .cxx and .h will be generated
+ std::string outputDirectory = this->Makefile->GetCurrentBinaryDirectory();
+
+ {
+ // Some of the generated files are *.h so the directory "GUI"
+ // where they are created have to be added to the include path
+ std::vector<std::string> outputDirectories;
+ outputDirectories.push_back(outputDirectory);
+ 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);
+ // 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);
+ std::string hname = outName;
+ hname += ".h";
+ std::string origname = cdir + "/" + *i;
+ // add starting depends
+ std::vector<std::string> depends;
+ depends.push_back(origname);
+ depends.push_back(fluid_exe);
+ std::string cxxres = outName;
+ cxxres += ".cxx";
+
+ cmCustomCommandLine commandLine;
+ commandLine.push_back(fluid_exe);
+ commandLine.push_back("-c"); // instructs Fluid to run in command line
+ commandLine.push_back("-h"); // optionally rename .h files
+ commandLine.push_back(hname);
+ commandLine.push_back("-o"); // optionally rename .cxx files
+ commandLine.push_back(cxxres);
+ commandLine.push_back(origname); // name of the GUI fluid file
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(commandLine);
+
+ // Add command for generating the .h and .cxx files
+ std::string no_main_dependency = "";
+ const char* no_comment = CM_NULLPTR;
+ const char* no_working_dir = CM_NULLPTR;
+ this->Makefile->AddCustomCommandToOutput(
+ cxxres, depends, no_main_dependency, commandLines, no_comment,
+ no_working_dir);
+ this->Makefile->AddCustomCommandToOutput(
+ hname, depends, no_main_dependency, commandLines, no_comment,
+ no_working_dir);
+
+ cmSourceFile* sf = this->Makefile->GetSource(cxxres);
+ sf->AddDepend(hname.c_str());
+ sf->AddDepend(origname.c_str());
+ this->GeneratedSourcesClasses.push_back(sf);
+ }
+ }
+
+ // create the variable with the list of sources in it
+ size_t lastHeadersClass = this->GeneratedSourcesClasses.size();
+ std::string sourceListValue;
+ for (size_t classNum = 0; classNum < lastHeadersClass; classNum++) {
+ if (classNum) {
+ sourceListValue += ";";
+ }
+ sourceListValue += this->GeneratedSourcesClasses[classNum]->GetFullPath();
+ }
+ std::string varName = this->Target;
+ varName += "_FLTK_UI_SRCS";
+ this->Makefile->AddDefinition(varName, sourceListValue.c_str());
+
+ return true;
+}
+
+void cmFLTKWrapUICommand::FinalPass()
+{
+ // people should add the srcs to the target themselves, but the old command
+ // didn't support that, so check and see if they added the files in and if
+ // they didn;t then print a warning and add then anyhow
+ cmTarget* target = this->Makefile->FindLocalNonAliasTarget(this->Target);
+ if (!target) {
+ std::string msg =
+ "FLTK_WRAP_UI was called with a target that was never created: ";
+ msg += this->Target;
+ msg += ". The problem was found while processing the source directory: ";
+ msg += this->Makefile->GetCurrentSourceDirectory();
+ msg += ". This FLTK_WRAP_UI call will be ignored.";
+ cmSystemTools::Message(msg.c_str(), "Warning");
+ return;
+ }
+}
diff --git a/Source/cmFLTKWrapUICommand.h b/Source/cmFLTKWrapUICommand.h
new file mode 100644
index 0000000..72b468e
--- /dev/null
+++ b/Source/cmFLTKWrapUICommand.h
@@ -0,0 +1,67 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFLTKWrapUICommand_h
+#define cmFLTKWrapUICommand_h
+
+#include "cmCommand.h"
+
+/** \class cmFLTKWrapUICommand
+ * \brief Create .h and .cxx files rules for FLTK user interfaces files
+ *
+ * cmFLTKWrapUICommand is used to create wrappers for FLTK classes into
+ * normal C++
+ */
+class cmFLTKWrapUICommand : public cmCommand
+{
+public:
+ cmTypeMacro(cmFLTKWrapUICommand, cmCommand);
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmFLTKWrapUICommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This is called at the end after all the information
+ * specified by the command is accumulated. Most commands do
+ * not implement this method. At this point, reading and
+ * writing to the cache can be done.
+ */
+ void FinalPass() CM_OVERRIDE;
+ bool HasFinalPass() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "fltk_wrap_ui"; }
+
+private:
+ /**
+ * List of produced files.
+ */
+ std::vector<cmSourceFile*> GeneratedSourcesClasses;
+
+ /**
+ * List of Fluid files that provide the source
+ * generating .cxx and .h files
+ */
+ std::string Target;
+};
+
+#endif
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
new file mode 100644
index 0000000..5a1238b
--- /dev/null
+++ b/Source/cmFileCommand.cxx
@@ -0,0 +1,3223 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmFileCommand.h"
+
+#include "cmAlgorithms.h"
+#include "cmCryptoHash.h"
+#include "cmCryptoHash.h"
+#include "cmFileTimeComparison.h"
+#include "cmGlobalGenerator.h"
+#include "cmHexFileConverter.h"
+#include "cmInstallType.h"
+#include "cmake.h"
+
+#include "cmTimestamp.h"
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmCurl.h"
+#include "cmFileLockResult.h"
+#endif
+
+#undef GetCurrentDirectory
+#include <assert.h>
+
+#include <sys/types.h>
+// include sys/stat.h after sys/types.h
+#include <sys/stat.h>
+
+#include <cm_auto_ptr.hxx>
+#include <cmsys/Directory.hxx>
+#include <cmsys/Encoding.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/RegularExpression.hxx>
+
+// Table of permissions flags.
+#if defined(_WIN32) && !defined(__CYGWIN__)
+static mode_t mode_owner_read = S_IREAD;
+static mode_t mode_owner_write = S_IWRITE;
+static mode_t mode_owner_execute = S_IEXEC;
+static mode_t mode_group_read = 0;
+static mode_t mode_group_write = 0;
+static mode_t mode_group_execute = 0;
+static mode_t mode_world_read = 0;
+static mode_t mode_world_write = 0;
+static mode_t mode_world_execute = 0;
+static mode_t mode_setuid = 0;
+static mode_t mode_setgid = 0;
+#else
+static mode_t mode_owner_read = S_IRUSR;
+static mode_t mode_owner_write = S_IWUSR;
+static mode_t mode_owner_execute = S_IXUSR;
+static mode_t mode_group_read = S_IRGRP;
+static mode_t mode_group_write = S_IWGRP;
+static mode_t mode_group_execute = S_IXGRP;
+static mode_t mode_world_read = S_IROTH;
+static mode_t mode_world_write = S_IWOTH;
+static mode_t mode_world_execute = S_IXOTH;
+static mode_t mode_setuid = S_ISUID;
+static mode_t mode_setgid = S_ISGID;
+#endif
+
+#if defined(_WIN32) && defined(CMAKE_ENCODING_UTF8)
+// libcurl doesn't support file:// urls for unicode filenames on Windows.
+// Convert string from UTF-8 to ACP if this is a file:// URL.
+static std::string fix_file_url_windows(const std::string& url)
+{
+ std::string ret = url;
+ if (strncmp(url.c_str(), "file://", 7) == 0) {
+ std::wstring wurl = cmsys::Encoding::ToWide(url);
+ if (!wurl.empty()) {
+ int mblen =
+ WideCharToMultiByte(CP_ACP, 0, wurl.c_str(), -1, NULL, 0, NULL, NULL);
+ if (mblen > 0) {
+ std::vector<char> chars(mblen);
+ mblen = WideCharToMultiByte(CP_ACP, 0, wurl.c_str(), -1, &chars[0],
+ mblen, NULL, NULL);
+ if (mblen > 0) {
+ ret = &chars[0];
+ }
+ }
+ }
+ }
+ return ret;
+}
+#endif
+
+// cmLibraryCommand
+bool cmFileCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("must be called with at least two arguments.");
+ return false;
+ }
+ std::string subCommand = args[0];
+ if (subCommand == "WRITE") {
+ return this->HandleWriteCommand(args, false);
+ } else if (subCommand == "APPEND") {
+ return this->HandleWriteCommand(args, true);
+ } else if (subCommand == "DOWNLOAD") {
+ return this->HandleDownloadCommand(args);
+ } else if (subCommand == "UPLOAD") {
+ return this->HandleUploadCommand(args);
+ } else if (subCommand == "READ") {
+ return this->HandleReadCommand(args);
+ } else if (subCommand == "MD5" || subCommand == "SHA1" ||
+ subCommand == "SHA224" || subCommand == "SHA256" ||
+ subCommand == "SHA384" || subCommand == "SHA512") {
+ return this->HandleHashCommand(args);
+ } else if (subCommand == "STRINGS") {
+ return this->HandleStringsCommand(args);
+ } else if (subCommand == "GLOB") {
+ return this->HandleGlobCommand(args, false);
+ } else if (subCommand == "GLOB_RECURSE") {
+ return this->HandleGlobCommand(args, true);
+ } else if (subCommand == "MAKE_DIRECTORY") {
+ return this->HandleMakeDirectoryCommand(args);
+ } else if (subCommand == "RENAME") {
+ return this->HandleRename(args);
+ } else if (subCommand == "REMOVE") {
+ return this->HandleRemove(args, false);
+ } else if (subCommand == "REMOVE_RECURSE") {
+ return this->HandleRemove(args, true);
+ } else if (subCommand == "COPY") {
+ return this->HandleCopyCommand(args);
+ } else if (subCommand == "INSTALL") {
+ return this->HandleInstallCommand(args);
+ } else if (subCommand == "DIFFERENT") {
+ return this->HandleDifferentCommand(args);
+ } else if (subCommand == "RPATH_CHANGE" || subCommand == "CHRPATH") {
+ return this->HandleRPathChangeCommand(args);
+ } else if (subCommand == "RPATH_CHECK") {
+ return this->HandleRPathCheckCommand(args);
+ } else if (subCommand == "RPATH_REMOVE") {
+ return this->HandleRPathRemoveCommand(args);
+ } else if (subCommand == "RELATIVE_PATH") {
+ return this->HandleRelativePathCommand(args);
+ } else if (subCommand == "TO_CMAKE_PATH") {
+ return this->HandleCMakePathCommand(args, false);
+ } else if (subCommand == "TO_NATIVE_PATH") {
+ return this->HandleCMakePathCommand(args, true);
+ } else if (subCommand == "TIMESTAMP") {
+ return this->HandleTimestampCommand(args);
+ } else if (subCommand == "GENERATE") {
+ return this->HandleGenerateCommand(args);
+ } else if (subCommand == "LOCK") {
+ return this->HandleLockCommand(args);
+ }
+
+ std::string e = "does not recognize sub-command " + subCommand;
+ this->SetError(e);
+ return false;
+}
+
+bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
+ bool append)
+{
+ std::vector<std::string>::const_iterator i = args.begin();
+
+ i++; // Get rid of subcommand
+
+ std::string fileName = *i;
+ if (!cmsys::SystemTools::FileIsFullPath(i->c_str())) {
+ fileName = this->Makefile->GetCurrentSourceDirectory();
+ fileName += "/" + *i;
+ }
+
+ i++;
+
+ if (!this->Makefile->CanIWriteThisFile(fileName.c_str())) {
+ std::string e =
+ "attempted to write a file: " + fileName + " into a source directory.";
+ this->SetError(e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ std::string dir = cmSystemTools::GetFilenamePath(fileName);
+ cmSystemTools::MakeDirectory(dir.c_str());
+
+ mode_t mode = 0;
+
+ // Set permissions to writable
+ if (cmSystemTools::GetPermissions(fileName.c_str(), mode)) {
+ cmSystemTools::SetPermissions(fileName.c_str(),
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ mode | S_IWRITE
+#else
+ mode | S_IWUSR | S_IWGRP
+#endif
+ );
+ }
+ // If GetPermissions fails, pretend like it is ok. File open will fail if
+ // the file is not writable
+ cmsys::ofstream file(fileName.c_str(),
+ append ? std::ios::app : std::ios::out);
+ if (!file) {
+ std::string error = "failed to open for writing (";
+ error += cmSystemTools::GetLastSystemError();
+ error += "):\n ";
+ error += fileName;
+ this->SetError(error);
+ return false;
+ }
+ std::string message = cmJoin(cmMakeRange(i, args.end()), std::string());
+ file << message;
+ file.close();
+ if (mode) {
+ cmSystemTools::SetPermissions(fileName.c_str(), mode);
+ }
+ return true;
+}
+
+bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args)
+{
+ if (args.size() < 3) {
+ this->SetError("READ must be called with at least two additional "
+ "arguments");
+ return false;
+ }
+
+ cmCommandArgumentsHelper argHelper;
+ cmCommandArgumentGroup group;
+
+ cmCAString readArg(&argHelper, "READ");
+ cmCAString fileNameArg(&argHelper, CM_NULLPTR);
+ cmCAString resultArg(&argHelper, CM_NULLPTR);
+
+ cmCAString offsetArg(&argHelper, "OFFSET", &group);
+ cmCAString limitArg(&argHelper, "LIMIT", &group);
+ cmCAEnabler hexOutputArg(&argHelper, "HEX", &group);
+ readArg.Follows(CM_NULLPTR);
+ fileNameArg.Follows(&readArg);
+ resultArg.Follows(&fileNameArg);
+ group.Follows(&resultArg);
+ argHelper.Parse(&args, CM_NULLPTR);
+
+ std::string fileName = fileNameArg.GetString();
+ if (!cmsys::SystemTools::FileIsFullPath(fileName.c_str())) {
+ fileName = this->Makefile->GetCurrentSourceDirectory();
+ fileName += "/" + fileNameArg.GetString();
+ }
+
+ 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));
+#else
+ cmsys::ifstream file(fileName.c_str());
+#endif
+
+ if (!file) {
+ std::string error = "failed to open for reading (";
+ error += cmSystemTools::GetLastSystemError();
+ error += "):\n ";
+ error += fileName;
+ this->SetError(error);
+ return false;
+ }
+
+ // is there a limit?
+ long sizeLimit = -1;
+ if (!limitArg.GetString().empty()) {
+ sizeLimit = atoi(limitArg.GetCString());
+ }
+
+ // is there an offset?
+ long offset = 0;
+ if (!offsetArg.GetString().empty()) {
+ offset = atoi(offsetArg.GetCString());
+ }
+
+ file.seekg(offset, std::ios::beg); // explicit ios::beg for IBM VisualAge 6
+
+ std::string output;
+
+ if (hexOutputArg.IsEnabled()) {
+ // Convert part of the file into hex code
+ char c;
+ while ((sizeLimit != 0) && (file.get(c))) {
+ char hex[4];
+ sprintf(hex, "%.2x", c & 0xff);
+ output += hex;
+ if (sizeLimit > 0) {
+ sizeLimit--;
+ }
+ }
+ } else {
+ std::string line;
+ bool has_newline = false;
+ while (sizeLimit != 0 && cmSystemTools::GetLineFromStream(
+ file, line, &has_newline, sizeLimit)) {
+ if (sizeLimit > 0) {
+ sizeLimit = sizeLimit - static_cast<long>(line.size());
+ if (has_newline) {
+ sizeLimit--;
+ }
+ if (sizeLimit < 0) {
+ sizeLimit = 0;
+ }
+ }
+ output += line;
+ if (has_newline) {
+ output += "\n";
+ }
+ }
+ }
+ this->Makefile->AddDefinition(variable, output.c_str());
+ return true;
+}
+
+bool cmFileCommand::HandleHashCommand(std::vector<std::string> const& args)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ if (args.size() != 3) {
+ std::ostringstream e;
+ e << args[0] << " requires a file name and output variable";
+ this->SetError(e.str());
+ return false;
+ }
+
+ CM_AUTO_PTR<cmCryptoHash> hash(cmCryptoHash::New(args[0].c_str()));
+ if (hash.get()) {
+ std::string out = hash->HashFile(args[1]);
+ if (!out.empty()) {
+ this->Makefile->AddDefinition(args[2], out.c_str());
+ return true;
+ }
+ std::ostringstream e;
+ e << args[0] << " failed to read file \"" << args[1]
+ << "\": " << cmSystemTools::GetLastSystemError();
+ this->SetError(e.str());
+ }
+ return false;
+#else
+ std::ostringstream e;
+ e << args[0] << " not available during bootstrap";
+ this->SetError(e.str().c_str());
+ return false;
+#endif
+}
+
+bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args)
+{
+ if (args.size() < 3) {
+ this->SetError("STRINGS requires a file name and output variable");
+ return false;
+ }
+
+ // Get the file to read.
+ std::string fileName = args[1];
+ if (!cmsys::SystemTools::FileIsFullPath(fileName.c_str())) {
+ fileName = this->Makefile->GetCurrentSourceDirectory();
+ fileName += "/" + args[1];
+ }
+
+ // Get the variable in which to store the results.
+ std::string outVar = args[2];
+
+ // Parse the options.
+ enum
+ {
+ arg_none,
+ arg_limit_input,
+ arg_limit_output,
+ arg_limit_count,
+ arg_length_minimum,
+ arg_length_maximum,
+ arg__maximum,
+ arg_regex,
+ arg_encoding
+ };
+ unsigned int minlen = 0;
+ unsigned int maxlen = 0;
+ int limit_input = -1;
+ int limit_output = -1;
+ unsigned int limit_count = 0;
+ cmsys::RegularExpression regex;
+ bool have_regex = false;
+ bool newline_consume = false;
+ bool hex_conversion_enabled = true;
+ enum
+ {
+ encoding_none = cmsys::FStream::BOM_None,
+ encoding_utf8 = cmsys::FStream::BOM_UTF8,
+ encoding_utf16le = cmsys::FStream::BOM_UTF16LE,
+ encoding_utf16be = cmsys::FStream::BOM_UTF16BE,
+ encoding_utf32le = cmsys::FStream::BOM_UTF32LE,
+ encoding_utf32be = cmsys::FStream::BOM_UTF32BE
+ };
+ int encoding = encoding_none;
+ int arg_mode = arg_none;
+ for (unsigned int i = 3; i < args.size(); ++i) {
+ if (args[i] == "LIMIT_INPUT") {
+ arg_mode = arg_limit_input;
+ } else if (args[i] == "LIMIT_OUTPUT") {
+ arg_mode = arg_limit_output;
+ } else if (args[i] == "LIMIT_COUNT") {
+ arg_mode = arg_limit_count;
+ } else if (args[i] == "LENGTH_MINIMUM") {
+ arg_mode = arg_length_minimum;
+ } else if (args[i] == "LENGTH_MAXIMUM") {
+ arg_mode = arg_length_maximum;
+ } else if (args[i] == "REGEX") {
+ arg_mode = arg_regex;
+ } else if (args[i] == "NEWLINE_CONSUME") {
+ newline_consume = true;
+ arg_mode = arg_none;
+ } else if (args[i] == "NO_HEX_CONVERSION") {
+ hex_conversion_enabled = false;
+ arg_mode = arg_none;
+ } else if (args[i] == "ENCODING") {
+ arg_mode = arg_encoding;
+ } else if (arg_mode == arg_limit_input) {
+ if (sscanf(args[i].c_str(), "%d", &limit_input) != 1 ||
+ limit_input < 0) {
+ std::ostringstream e;
+ e << "STRINGS option LIMIT_INPUT value \"" << args[i]
+ << "\" is not an unsigned integer.";
+ this->SetError(e.str());
+ return false;
+ }
+ arg_mode = arg_none;
+ } else if (arg_mode == arg_limit_output) {
+ if (sscanf(args[i].c_str(), "%d", &limit_output) != 1 ||
+ limit_output < 0) {
+ std::ostringstream e;
+ e << "STRINGS option LIMIT_OUTPUT value \"" << args[i]
+ << "\" is not an unsigned integer.";
+ this->SetError(e.str());
+ return false;
+ }
+ arg_mode = arg_none;
+ } else if (arg_mode == arg_limit_count) {
+ int count;
+ if (sscanf(args[i].c_str(), "%d", &count) != 1 || count < 0) {
+ std::ostringstream e;
+ e << "STRINGS option LIMIT_COUNT value \"" << args[i]
+ << "\" is not an unsigned integer.";
+ this->SetError(e.str());
+ return false;
+ }
+ limit_count = count;
+ arg_mode = arg_none;
+ } else if (arg_mode == arg_length_minimum) {
+ int len;
+ if (sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0) {
+ std::ostringstream e;
+ e << "STRINGS option LENGTH_MINIMUM value \"" << args[i]
+ << "\" is not an unsigned integer.";
+ this->SetError(e.str());
+ return false;
+ }
+ minlen = len;
+ arg_mode = arg_none;
+ } else if (arg_mode == arg_length_maximum) {
+ int len;
+ if (sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0) {
+ std::ostringstream e;
+ e << "STRINGS option LENGTH_MAXIMUM value \"" << args[i]
+ << "\" is not an unsigned integer.";
+ this->SetError(e.str());
+ return false;
+ }
+ maxlen = len;
+ arg_mode = arg_none;
+ } else if (arg_mode == arg_regex) {
+ if (!regex.compile(args[i].c_str())) {
+ std::ostringstream e;
+ e << "STRINGS option REGEX value \"" << args[i]
+ << "\" could not be compiled.";
+ this->SetError(e.str());
+ return false;
+ }
+ have_regex = true;
+ arg_mode = arg_none;
+ } else if (arg_mode == arg_encoding) {
+ if (args[i] == "UTF-8") {
+ encoding = encoding_utf8;
+ } else if (args[i] == "UTF-16LE") {
+ encoding = encoding_utf16le;
+ } else if (args[i] == "UTF-16BE") {
+ encoding = encoding_utf16be;
+ } else if (args[i] == "UTF-32LE") {
+ encoding = encoding_utf32le;
+ } else if (args[i] == "UTF-32BE") {
+ encoding = encoding_utf32be;
+ } else {
+ std::ostringstream e;
+ e << "STRINGS option ENCODING \"" << args[i] << "\" not recognized.";
+ this->SetError(e.str());
+ return false;
+ }
+ arg_mode = arg_none;
+ } else {
+ std::ostringstream e;
+ e << "STRINGS given unknown argument \"" << args[i] << "\"";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ if (hex_conversion_enabled) {
+ // TODO: should work without temp file, but just on a memory buffer
+ std::string binaryFileName = this->Makefile->GetCurrentBinaryDirectory();
+ binaryFileName += cmake::GetCMakeFilesDirectory();
+ binaryFileName += "/FileCommandStringsBinaryFile";
+ if (cmHexFileConverter::TryConvert(fileName.c_str(),
+ binaryFileName.c_str())) {
+ fileName = binaryFileName;
+ }
+ }
+
+// Open the specified file.
+#if defined(_WIN32) || defined(__CYGWIN__)
+ cmsys::ifstream fin(fileName.c_str(), std::ios::in | std::ios::binary);
+#else
+ cmsys::ifstream fin(fileName.c_str());
+#endif
+ if (!fin) {
+ std::ostringstream e;
+ e << "STRINGS file \"" << fileName << "\" cannot be read.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // If BOM is found and encoding was not specified, use the BOM
+ int bom_found = cmsys::FStream::ReadBOM(fin);
+ if (encoding == encoding_none && bom_found != cmsys::FStream::BOM_None) {
+ encoding = bom_found;
+ }
+
+ unsigned int bytes_rem = 0;
+ if (encoding == encoding_utf16le || encoding == encoding_utf16be) {
+ bytes_rem = 1;
+ }
+ if (encoding == encoding_utf32le || encoding == encoding_utf32be) {
+ bytes_rem = 3;
+ }
+
+ // Parse strings out of the file.
+ int output_size = 0;
+ std::vector<std::string> strings;
+ std::string s;
+ while ((!limit_count || strings.size() < limit_count) &&
+ (limit_input < 0 || static_cast<int>(fin.tellg()) < limit_input) &&
+ fin) {
+ std::string current_str;
+
+ int c = fin.get();
+ for (unsigned int i = 0; i < bytes_rem; ++i) {
+ int c1 = fin.get();
+ if (!fin) {
+ fin.putback(static_cast<char>(c1));
+ break;
+ }
+ c = (c << 8) | c1;
+ }
+ if (encoding == encoding_utf16le) {
+ c = ((c & 0xFF) << 8) | ((c & 0xFF00) >> 8);
+ } else if (encoding == encoding_utf32le) {
+ c = (((c & 0xFF) << 24) | ((c & 0xFF00) << 8) | ((c & 0xFF0000) >> 8) |
+ ((c & 0xFF000000) >> 24));
+ }
+
+ if (c == '\r') {
+ // Ignore CR character to make output always have UNIX newlines.
+ continue;
+ }
+
+ else if ((c >= 0x20 && c < 0x7F) || c == '\t' ||
+ (c == '\n' && newline_consume)) {
+ // This is an ASCII character that may be part of a string.
+ // Cast added to avoid compiler warning. Cast is ok because
+ // c is guaranteed to fit in char by the above if...
+ current_str += static_cast<char>(c);
+ } else if (encoding == encoding_utf8) {
+ // Check for UTF-8 encoded string (up to 4 octets)
+ static const unsigned char utf8_check_table[3][2] = {
+ { 0xE0, 0xC0 }, { 0xF0, 0xE0 }, { 0xF8, 0xF0 },
+ };
+
+ // how many octets are there?
+ unsigned int num_utf8_bytes = 0;
+ for (unsigned int j = 0; num_utf8_bytes == 0 && j < 3; j++) {
+ if ((c & utf8_check_table[j][0]) == utf8_check_table[j][1])
+ num_utf8_bytes = j + 2;
+ }
+
+ // get subsequent octets and check that they are valid
+ for (unsigned int j = 0; j < num_utf8_bytes; j++) {
+ if (j != 0) {
+ c = fin.get();
+ if (!fin || (c & 0xC0) != 0x80) {
+ fin.putback(static_cast<char>(c));
+ break;
+ }
+ }
+ current_str += static_cast<char>(c);
+ }
+
+ // if this was an invalid utf8 sequence, discard the data, and put
+ // back subsequent characters
+ if ((current_str.length() != num_utf8_bytes)) {
+ for (unsigned int j = 0; j < current_str.size() - 1; j++) {
+ c = current_str[current_str.size() - 1 - j];
+ fin.putback(static_cast<char>(c));
+ }
+ current_str = "";
+ }
+ }
+
+ if (c == '\n' && !newline_consume) {
+ // The current line has been terminated. Check if the current
+ // string matches the requirements. The length may now be as
+ // low as zero since blank lines are allowed.
+ if (s.length() >= minlen && (!have_regex || regex.find(s.c_str()))) {
+ output_size += static_cast<int>(s.size()) + 1;
+ if (limit_output >= 0 && output_size >= limit_output) {
+ s = "";
+ break;
+ }
+ strings.push_back(s);
+ }
+
+ // Reset the string to empty.
+ s = "";
+ } else if (current_str.empty()) {
+ // A non-string character has been found. Check if the current
+ // string matches the requirements. We require that the length
+ // be at least one no matter what the user specified.
+ if (s.length() >= minlen && !s.empty() &&
+ (!have_regex || regex.find(s.c_str()))) {
+ output_size += static_cast<int>(s.size()) + 1;
+ if (limit_output >= 0 && output_size >= limit_output) {
+ s = "";
+ break;
+ }
+ strings.push_back(s);
+ }
+
+ // Reset the string to empty.
+ s = "";
+ } else {
+ s += current_str;
+ }
+
+ if (maxlen > 0 && s.size() == maxlen) {
+ // Terminate a string if the maximum length is reached.
+ if (s.length() >= minlen && (!have_regex || regex.find(s.c_str()))) {
+ output_size += static_cast<int>(s.size()) + 1;
+ if (limit_output >= 0 && output_size >= limit_output) {
+ s = "";
+ break;
+ }
+ strings.push_back(s);
+ }
+ s = "";
+ }
+ }
+
+ // If there is a non-empty current string we have hit the end of the
+ // input file or the input size limit. Check if the current string
+ // matches the requirements.
+ if ((!limit_count || strings.size() < limit_count) && !s.empty() &&
+ s.length() >= minlen && (!have_regex || regex.find(s.c_str()))) {
+ output_size += static_cast<int>(s.size()) + 1;
+ if (limit_output < 0 || output_size < limit_output) {
+ strings.push_back(s);
+ }
+ }
+
+ // Encode the result in a CMake list.
+ const char* sep = "";
+ std::string output;
+ for (std::vector<std::string>::const_iterator si = strings.begin();
+ si != strings.end(); ++si) {
+ // Separate the strings in the output to make it a list.
+ output += sep;
+ sep = ";";
+
+ // Store the string in the output, but escape semicolons to
+ // make sure it is a list.
+ std::string const& sr = *si;
+ for (unsigned int i = 0; i < sr.size(); ++i) {
+ if (sr[i] == ';') {
+ output += '\\';
+ }
+ output += sr[i];
+ }
+ }
+
+ // Save the output in a makefile variable.
+ this->Makefile->AddDefinition(outVar, output.c_str());
+ return true;
+}
+
+bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
+ bool recurse)
+{
+ // File commands 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 variable = *i;
+ i++;
+ cmsys::Glob g;
+ g.SetRecurse(recurse);
+
+ bool explicitFollowSymlinks = false;
+ cmPolicies::PolicyStatus status =
+ this->Makefile->GetPolicyStatus(cmPolicies::CMP0009);
+ if (recurse) {
+ switch (status) {
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ g.RecurseThroughSymlinksOff();
+ break;
+ case cmPolicies::OLD:
+ case cmPolicies::WARN:
+ g.RecurseThroughSymlinksOn();
+ break;
+ }
+ }
+
+ std::string output = "";
+ bool first = true;
+ for (; i != args.end(); ++i) {
+ if (*i == "LIST_DIRECTORIES") {
+ ++i;
+ if (i != args.end()) {
+ if (cmSystemTools::IsOn(i->c_str())) {
+ g.SetListDirs(true);
+ g.SetRecurseListDirs(true);
+ } else if (cmSystemTools::IsOff(i->c_str())) {
+ g.SetListDirs(false);
+ g.SetRecurseListDirs(false);
+ } else {
+ this->SetError("LIST_DIRECTORIES missing bool value.");
+ return false;
+ }
+ } else {
+ this->SetError("LIST_DIRECTORIES missing bool value.");
+ return false;
+ }
+ ++i;
+ }
+
+ if (recurse && (*i == "FOLLOW_SYMLINKS")) {
+ explicitFollowSymlinks = true;
+ g.RecurseThroughSymlinksOn();
+ ++i;
+ if (i == args.end()) {
+ this->SetError(
+ "GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS");
+ return false;
+ }
+ }
+
+ if (*i == "RELATIVE") {
+ ++i; // skip RELATIVE
+ if (i == args.end()) {
+ this->SetError("GLOB requires a directory after the RELATIVE tag");
+ return false;
+ }
+ g.SetRelative(i->c_str());
+ ++i;
+ if (i == args.end()) {
+ this->SetError("GLOB requires a glob expression after the directory");
+ return false;
+ }
+ }
+
+ cmsys::Glob::GlobMessages globMessages;
+ if (!cmsys::SystemTools::FileIsFullPath(i->c_str())) {
+ std::string expr = this->Makefile->GetCurrentSourceDirectory();
+ // Handle script mode
+ if (!expr.empty()) {
+ expr += "/" + *i;
+ g.FindFiles(expr, &globMessages);
+ } else {
+ g.FindFiles(*i, &globMessages);
+ }
+ } else {
+ g.FindFiles(*i, &globMessages);
+ }
+
+ if (!globMessages.empty()) {
+ bool shouldExit = false;
+ for (cmsys::Glob::GlobMessagesIterator it = globMessages.begin();
+ it != globMessages.end(); ++it) {
+ if (it->type == cmsys::Glob::cyclicRecursion) {
+ this->Makefile->IssueMessage(
+ cmake::AUTHOR_WARNING,
+ "Cyclic recursion detected while globbing for '" + *i + "':\n" +
+ it->content);
+ } else {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR, "Error has occurred while globbing for '" +
+ *i + "' - " + it->content);
+ shouldExit = true;
+ }
+ }
+ if (shouldExit) {
+ return false;
+ }
+ }
+
+ std::vector<std::string>::size_type cc;
+ std::vector<std::string>& files = g.GetFiles();
+ std::sort(files.begin(), files.end());
+ for (cc = 0; cc < files.size(); cc++) {
+ if (!first) {
+ output += ";";
+ }
+ output += files[cc];
+ first = false;
+ }
+ }
+
+ if (recurse && !explicitFollowSymlinks) {
+ switch (status) {
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Correct behavior, yay!
+ break;
+ case cmPolicies::OLD:
+ // Probably not really the expected behavior, but the author explicitly
+ // asked for the old behavior... no warning.
+ case cmPolicies::WARN:
+ // Possibly unexpected old behavior *and* we actually traversed
+ // symlinks without being explicitly asked to: warn the author.
+ if (g.GetFollowedSymlinkCount() != 0) {
+ this->Makefile->IssueMessage(
+ cmake::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0009));
+ }
+ break;
+ }
+ }
+
+ this->Makefile->AddDefinition(variable, output.c_str());
+ return true;
+}
+
+bool cmFileCommand::HandleMakeDirectoryCommand(
+ 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
+
+ std::string expr;
+ for (; i != args.end(); ++i) {
+ const std::string* cdir = &(*i);
+ if (!cmsys::SystemTools::FileIsFullPath(i->c_str())) {
+ expr = this->Makefile->GetCurrentSourceDirectory();
+ expr += "/" + *i;
+ cdir = &expr;
+ }
+ if (!this->Makefile->CanIWriteThisFile(cdir->c_str())) {
+ std::string e = "attempted to create a directory: " + *cdir +
+ " into a source directory.";
+ this->SetError(e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ if (!cmSystemTools::MakeDirectory(cdir->c_str())) {
+ std::string error = "problem creating directory: " + *cdir;
+ this->SetError(error);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmFileCommand::HandleDifferentCommand(
+ std::vector<std::string> const& args)
+{
+ /*
+ FILE(DIFFERENT <variable> FILES <lhs> <rhs>)
+ */
+
+ // Evaluate arguments.
+ const char* file_lhs = CM_NULLPTR;
+ const char* file_rhs = CM_NULLPTR;
+ const char* var = CM_NULLPTR;
+ enum Doing
+ {
+ DoingNone,
+ DoingVar,
+ DoingFileLHS,
+ DoingFileRHS
+ };
+ Doing doing = DoingVar;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "FILES") {
+ doing = DoingFileLHS;
+ } else if (doing == DoingVar) {
+ var = args[i].c_str();
+ doing = DoingNone;
+ } else if (doing == DoingFileLHS) {
+ file_lhs = args[i].c_str();
+ doing = DoingFileRHS;
+ } else if (doing == DoingFileRHS) {
+ file_rhs = args[i].c_str();
+ doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << "DIFFERENT given unknown argument " << args[i];
+ this->SetError(e.str());
+ return false;
+ }
+ }
+ if (!var) {
+ this->SetError("DIFFERENT not given result variable name.");
+ return false;
+ }
+ if (!file_lhs || !file_rhs) {
+ this->SetError("DIFFERENT not given FILES option with two file names.");
+ return false;
+ }
+
+ // Compare the files.
+ const char* result =
+ cmSystemTools::FilesDiffer(file_lhs, file_rhs) ? "1" : "0";
+ this->Makefile->AddDefinition(var, result);
+ 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(CM_NULLPTR)
+ , UseGivenPermissionsFile(false)
+ , UseGivenPermissionsDir(false)
+ , UseSourcePermissions(true)
+ , Doing(DoingNone)
+ {
+ }
+ virtual ~cmFileCopier() {}
+
+ 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;
+ mode_t Permissions;
+ MatchProperties()
+ : Exclude(false)
+ , Permissions(0)
+ {
+ }
+ };
+ struct MatchRule;
+ friend struct MatchRule;
+ 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 (std::vector<MatchRule>::iterator mr = this->MatchRules.begin();
+ mr != this->MatchRules.end(); ++mr) {
+ 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 && !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 (arg == "OWNER_READ") {
+ permissions |= mode_owner_read;
+ } else if (arg == "OWNER_WRITE") {
+ permissions |= mode_owner_write;
+ } else if (arg == "OWNER_EXECUTE") {
+ permissions |= mode_owner_execute;
+ } else if (arg == "GROUP_READ") {
+ permissions |= mode_group_read;
+ } else if (arg == "GROUP_WRITE") {
+ permissions |= mode_group_write;
+ } else if (arg == "GROUP_EXECUTE") {
+ permissions |= mode_group_execute;
+ } else if (arg == "WORLD_READ") {
+ permissions |= mode_world_read;
+ } else if (arg == "WORLD_WRITE") {
+ permissions |= mode_world_write;
+ } else if (arg == "WORLD_EXECUTE") {
+ permissions |= mode_world_execute;
+ } else if (arg == "SETUID") {
+ permissions |= mode_setuid;
+ } else if (arg == "SETGID") {
+ permissions |= mode_setgid;
+ } else {
+ 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 const& match_properties);
+ bool InstallDirectory(const char* source, const char* destination,
+ MatchProperties const& 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::vector<std::string> Files;
+ int Doing;
+
+ virtual bool Parse(std::vector<std::string> const& args);
+ enum
+ {
+ DoingNone,
+ DoingError,
+ DoingDestination,
+ 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 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 == "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:
+ if (arg.empty() || cmSystemTools::FileIsFullPath(arg.c_str())) {
+ this->Files.push_back(arg);
+ } else {
+ std::string file = this->Makefile->GetCurrentSourceDirectory();
+ file += "/" + arg;
+ this->Files.push_back(file);
+ }
+ break;
+ case DoingDestination:
+ if (arg.empty() || cmSystemTools::FileIsFullPath(arg.c_str())) {
+ this->Destination = arg;
+ } else {
+ this->Destination = this->Makefile->GetCurrentBinaryDirectory();
+ this->Destination += "/" + arg;
+ }
+ 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.push_back(MatchRule(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.push_back(MatchRule(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;
+ }
+
+ std::vector<std::string> const& files = this->Files;
+ for (std::vector<std::string>::size_type i = 0; i < files.size(); ++i) {
+ // Split the input file into its directory and name components.
+ std::vector<std::string> fromPathComponents;
+ cmSystemTools::SplitPath(files[i], 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;
+ 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;
+ } else if (cmSystemTools::FileIsSymlink(fromFile)) {
+ return this->InstallSymlink(fromFile, toFile);
+ } else if (cmSystemTools::FileIsDirectory(fromFile)) {
+ return this->InstallDirectory(fromFile, toFile, match_properties);
+ } else 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 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 const& 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 const& match_properties)
+{
+ // Inform the user about this directory installation.
+ this->ReportCopy(destination, TypeDir,
+ !cmSystemTools::FileIsDirectory(destination));
+
+ // Make sure the destination directory exists.
+ if (!cmSystemTools::MakeDirectory(destination)) {
+ 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.
+ this->Always =
+ cmSystemTools::IsOn(cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS"));
+ // Get the current manifest.
+ this->Manifest =
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
+ }
+ ~cmFileInstaller() CM_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) CM_OVERRIDE
+ {
+ return this->Rename.empty() ? fromName : this->Rename;
+ }
+
+ void ReportCopy(const char* toFile, Type type, bool copy) CM_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) CM_OVERRIDE
+ {
+ return (this->Optional || this->cmFileCopier::ReportMissing(fromFile));
+ }
+ bool Install(const char* fromFile, const char* toFile) CM_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) CM_OVERRIDE;
+ enum
+ {
+ DoingType = DoingLast1,
+ DoingRename,
+ DoingLast2
+ };
+ bool CheckKeyword(std::string const& arg) CM_OVERRIDE;
+ bool CheckValue(std::string const& arg) CM_OVERRIDE;
+ void DefaultFilePermissions() CM_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;
+ }
+ 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->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;
+ }
+
+ const char* destdir = cmSystemTools::GetEnv("DESTDIR");
+ if (destdir && *destdir) {
+ std::string sdestdir = destdir;
+ 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());
+ }
+
+ if (this->InstallType != cmInstallType_DIRECTORY) {
+ if (!cmSystemTools::FileExists(destination.c_str())) {
+ if (!cmSystemTools::MakeDirectory(destination.c_str())) {
+ 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 = CM_NULLPTR;
+ const char* oldRPath = CM_NULLPTR;
+ const char* newRPath = CM_NULLPTR;
+ enum Doing
+ {
+ DoingNone,
+ DoingFile,
+ DoingOld,
+ DoingNew
+ };
+ Doing doing = DoingNone;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "OLD_RPATH") {
+ doing = DoingOld;
+ } else if (args[i] == "NEW_RPATH") {
+ doing = DoingNew;
+ } else if (args[i] == "FILE") {
+ doing = DoingFile;
+ } else if (doing == DoingFile) {
+ file = args[i].c_str();
+ doing = DoingNone;
+ } else if (doing == DoingOld) {
+ oldRPath = args[i].c_str();
+ doing = DoingNone;
+ } else if (doing == DoingNew) {
+ newRPath = args[i].c_str();
+ doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << "RPATH_CHANGE given unknown argument " << args[i];
+ this->SetError(e.str());
+ return false;
+ }
+ }
+ if (!file) {
+ this->SetError("RPATH_CHANGE not given FILE option.");
+ return false;
+ }
+ if (!oldRPath) {
+ this->SetError("RPATH_CHANGE not given OLD_RPATH option.");
+ return false;
+ }
+ if (!newRPath) {
+ this->SetError("RPATH_CHANGE not given NEW_RPATH option.");
+ return false;
+ }
+ if (!cmSystemTools::FileExists(file, true)) {
+ std::ostringstream e;
+ e << "RPATH_CHANGE given FILE \"" << file << "\" that does not exist.";
+ this->SetError(e.str());
+ return false;
+ }
+ bool success = true;
+ cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
+ bool have_ft = cmSystemTools::FileTimeGet(file, ft);
+ std::string emsg;
+ bool changed;
+ if (!cmSystemTools::ChangeRPath(file, oldRPath, newRPath, &emsg, &changed)) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "RPATH_CHANGE could not write new RPATH:\n"
+ << " " << newRPath << "\n"
+ << "to the file:\n"
+ << " " << file << "\n"
+ << emsg;
+ /* clang-format on */
+ this->SetError(e.str());
+ success = false;
+ }
+ if (success) {
+ if (changed) {
+ std::string message = "Set runtime path of \"";
+ message += file;
+ message += "\" to \"";
+ message += newRPath;
+ message += "\"";
+ this->Makefile->DisplayStatus(message.c_str(), -1);
+ }
+ if (have_ft) {
+ cmSystemTools::FileTimeSet(file, ft);
+ }
+ }
+ cmSystemTools::FileTimeDelete(ft);
+ return success;
+}
+
+bool cmFileCommand::HandleRPathRemoveCommand(
+ std::vector<std::string> const& args)
+{
+ // Evaluate arguments.
+ const char* file = CM_NULLPTR;
+ enum Doing
+ {
+ DoingNone,
+ DoingFile
+ };
+ Doing doing = DoingNone;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "FILE") {
+ doing = DoingFile;
+ } else if (doing == DoingFile) {
+ file = args[i].c_str();
+ doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << "RPATH_REMOVE given unknown argument " << args[i];
+ this->SetError(e.str());
+ return false;
+ }
+ }
+ if (!file) {
+ this->SetError("RPATH_REMOVE not given FILE option.");
+ return false;
+ }
+ if (!cmSystemTools::FileExists(file, true)) {
+ std::ostringstream e;
+ e << "RPATH_REMOVE given FILE \"" << file << "\" that does not exist.";
+ this->SetError(e.str());
+ return false;
+ }
+ bool success = true;
+ cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
+ bool have_ft = cmSystemTools::FileTimeGet(file, ft);
+ std::string emsg;
+ bool removed;
+ if (!cmSystemTools::RemoveRPath(file, &emsg, &removed)) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "RPATH_REMOVE could not remove RPATH from file:\n"
+ << " " << file << "\n"
+ << emsg;
+ /* clang-format on */
+ this->SetError(e.str());
+ success = false;
+ }
+ if (success) {
+ if (removed) {
+ std::string message = "Removed runtime path from \"";
+ message += file;
+ message += "\"";
+ this->Makefile->DisplayStatus(message.c_str(), -1);
+ }
+ if (have_ft) {
+ cmSystemTools::FileTimeSet(file, ft);
+ }
+ }
+ cmSystemTools::FileTimeDelete(ft);
+ return success;
+}
+
+bool cmFileCommand::HandleRPathCheckCommand(
+ std::vector<std::string> const& args)
+{
+ // Evaluate arguments.
+ const char* file = CM_NULLPTR;
+ const char* rpath = CM_NULLPTR;
+ enum Doing
+ {
+ DoingNone,
+ DoingFile,
+ DoingRPath
+ };
+ Doing doing = DoingNone;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "RPATH") {
+ doing = DoingRPath;
+ } else if (args[i] == "FILE") {
+ doing = DoingFile;
+ } else if (doing == DoingFile) {
+ file = args[i].c_str();
+ doing = DoingNone;
+ } else if (doing == DoingRPath) {
+ rpath = args[i].c_str();
+ doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << "RPATH_CHECK given unknown argument " << args[i];
+ this->SetError(e.str());
+ return false;
+ }
+ }
+ if (!file) {
+ this->SetError("RPATH_CHECK not given FILE option.");
+ return false;
+ }
+ if (!rpath) {
+ this->SetError("RPATH_CHECK not given RPATH option.");
+ return false;
+ }
+
+ // If the file exists but does not have the desired RPath then
+ // delete it. This is used during installation to re-install a file
+ // if its RPath will change.
+ if (cmSystemTools::FileExists(file, true) &&
+ !cmSystemTools::CheckRPath(file, rpath)) {
+ cmSystemTools::RemoveFile(file);
+ }
+
+ return true;
+}
+
+bool cmFileCommand::HandleInstallCommand(std::vector<std::string> const& args)
+{
+ cmFileInstaller installer(this);
+ return installer.Run(args);
+}
+
+bool cmFileCommand::HandleRelativePathCommand(
+ std::vector<std::string> const& args)
+{
+ if (args.size() != 4) {
+ this->SetError("RELATIVE_PATH called with incorrect number of arguments");
+ return false;
+ }
+
+ const std::string& outVar = args[1];
+ const std::string& directoryName = args[2];
+ const std::string& fileName = args[3];
+
+ if (!cmSystemTools::FileIsFullPath(directoryName.c_str())) {
+ std::string errstring =
+ "RELATIVE_PATH must be passed a full path to the directory: " +
+ directoryName;
+ this->SetError(errstring);
+ return false;
+ }
+ if (!cmSystemTools::FileIsFullPath(fileName.c_str())) {
+ std::string errstring =
+ "RELATIVE_PATH must be passed a full path to the file: " + fileName;
+ this->SetError(errstring);
+ return false;
+ }
+
+ std::string res =
+ cmSystemTools::RelativePath(directoryName.c_str(), fileName.c_str());
+ this->Makefile->AddDefinition(outVar, res.c_str());
+ return true;
+}
+
+bool cmFileCommand::HandleRename(std::vector<std::string> const& args)
+{
+ if (args.size() != 3) {
+ this->SetError("RENAME given incorrect number of arguments.");
+ return false;
+ }
+
+ // Compute full path for old and new names.
+ std::string oldname = args[1];
+ if (!cmsys::SystemTools::FileIsFullPath(oldname.c_str())) {
+ oldname = this->Makefile->GetCurrentSourceDirectory();
+ oldname += "/" + args[1];
+ }
+ std::string newname = args[2];
+ if (!cmsys::SystemTools::FileIsFullPath(newname.c_str())) {
+ newname = this->Makefile->GetCurrentSourceDirectory();
+ newname += "/" + args[2];
+ }
+
+ if (!cmSystemTools::RenameFile(oldname.c_str(), newname.c_str())) {
+ std::string err = cmSystemTools::GetLastSystemError();
+ std::ostringstream e;
+ /* clang-format off */
+ e << "RENAME failed to rename\n"
+ << " " << oldname << "\n"
+ << "to\n"
+ << " " << newname << "\n"
+ << "because: " << err << "\n";
+ /* clang-format on */
+ this->SetError(e.str());
+ return false;
+ }
+ return true;
+}
+
+bool cmFileCommand::HandleRemove(std::vector<std::string> const& args,
+ bool recurse)
+{
+
+ 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;
+ if (!cmsys::SystemTools::FileIsFullPath(fileName.c_str())) {
+ fileName = this->Makefile->GetCurrentSourceDirectory();
+ fileName += "/" + *i;
+ }
+
+ if (cmSystemTools::FileIsDirectory(fileName) &&
+ !cmSystemTools::FileIsSymlink(fileName) && recurse) {
+ cmSystemTools::RemoveADirectory(fileName);
+ } else {
+ cmSystemTools::RemoveFile(fileName);
+ }
+ }
+ return true;
+}
+
+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<cmsys::String> path = cmSystemTools::SplitString(*i, pathSep);
+ i++;
+ const char* var = i->c_str();
+ std::string value;
+ for (std::vector<cmsys::String>::iterator j = path.begin(); j != path.end();
+ ++j) {
+ if (j != path.begin()) {
+ value += ";";
+ }
+ if (!nativePath) {
+ cmSystemTools::ConvertToUnixSlashes(*j);
+ } else {
+ *j = cmSystemTools::ConvertToOutputPath(j->c_str());
+ // remove double quotes in the path
+ cmsys::String& s = *j;
+
+ if (s.size() > 1 && s[0] == '\"' && s[s.size() - 1] == '\"') {
+ s = s.substr(1, s.size() - 2);
+ }
+ }
+ value += *j;
+ }
+ this->Makefile->AddDefinition(var, value.c_str());
+ return true;
+}
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+
+// Stuff for curl download/upload
+typedef std::vector<char> cmFileCommandVectorOfChar;
+
+namespace {
+
+size_t cmWriteToFileCallback(void* ptr, size_t size, size_t nmemb, void* data)
+{
+ int realsize = (int)(size * nmemb);
+ cmsys::ofstream* fout = static_cast<cmsys::ofstream*>(data);
+ const char* chPtr = static_cast<char*>(ptr);
+ fout->write(chPtr, realsize);
+ return realsize;
+}
+
+size_t cmWriteToMemoryCallback(void* ptr, size_t size, size_t nmemb,
+ void* data)
+{
+ int realsize = (int)(size * nmemb);
+ cmFileCommandVectorOfChar* vec =
+ static_cast<cmFileCommandVectorOfChar*>(data);
+ const char* chPtr = static_cast<char*>(ptr);
+ vec->insert(vec->end(), chPtr, chPtr + realsize);
+ return realsize;
+}
+
+static size_t cmFileCommandCurlDebugCallback(CURL*, curl_infotype type,
+ char* chPtr, size_t size,
+ void* 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);
+ break;
+ case CURLINFO_DATA_IN:
+ case CURLINFO_DATA_OUT:
+ case CURLINFO_SSL_DATA_IN:
+ case CURLINFO_SSL_DATA_OUT: {
+ char buf[128];
+ 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);
+ }
+ } break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+class cURLProgressHelper
+{
+public:
+ cURLProgressHelper(cmFileCommand* fc, const char* text)
+ {
+ this->CurrentPercentage = -1;
+ this->FileCommand = fc;
+ this->Text = text;
+ }
+
+ bool UpdatePercentage(double value, double total, std::string& status)
+ {
+ int OldPercentage = this->CurrentPercentage;
+
+ if (total > 0.0) {
+ this->CurrentPercentage = static_cast<int>(value / total * 100.0 + 0.5);
+ if (this->CurrentPercentage > 100) {
+ // Avoid extra progress reports for unexpected data beyond total.
+ this->CurrentPercentage = 100;
+ }
+ }
+
+ bool updated = (OldPercentage != this->CurrentPercentage);
+
+ if (updated) {
+ std::ostringstream oss;
+ oss << "[" << this->Text << " " << this->CurrentPercentage
+ << "% complete]";
+ status = oss.str();
+ }
+
+ return updated;
+ }
+
+ cmFileCommand* GetFileCommand() { return this->FileCommand; }
+
+private:
+ int CurrentPercentage;
+ cmFileCommand* FileCommand;
+ std::string Text;
+};
+
+static int cmFileDownloadProgressCallback(void* clientp, double dltotal,
+ double dlnow, double ultotal,
+ double ulnow)
+{
+ cURLProgressHelper* helper = reinterpret_cast<cURLProgressHelper*>(clientp);
+
+ static_cast<void>(ultotal);
+ static_cast<void>(ulnow);
+
+ std::string status;
+ if (helper->UpdatePercentage(dlnow, dltotal, status)) {
+ cmFileCommand* fc = helper->GetFileCommand();
+ cmMakefile* mf = fc->GetMakefile();
+ mf->DisplayStatus(status.c_str(), -1);
+ }
+
+ return 0;
+}
+
+static int cmFileUploadProgressCallback(void* clientp, double dltotal,
+ double dlnow, double ultotal,
+ double ulnow)
+{
+ cURLProgressHelper* helper = reinterpret_cast<cURLProgressHelper*>(clientp);
+
+ static_cast<void>(dltotal);
+ static_cast<void>(dlnow);
+
+ std::string status;
+ if (helper->UpdatePercentage(ulnow, ultotal, status)) {
+ cmFileCommand* fc = helper->GetFileCommand();
+ cmMakefile* mf = fc->GetMakefile();
+ mf->DisplayStatus(status.c_str(), -1);
+ }
+
+ return 0;
+}
+}
+
+namespace {
+
+class cURLEasyGuard
+{
+public:
+ cURLEasyGuard(CURL* easy)
+ : Easy(easy)
+ {
+ }
+
+ ~cURLEasyGuard(void)
+ {
+ if (this->Easy) {
+ ::curl_easy_cleanup(this->Easy);
+ }
+ }
+
+ inline void release(void)
+ {
+ this->Easy = CM_NULLPTR;
+ return;
+ }
+
+private:
+ ::CURL* Easy;
+};
+}
+#endif
+
+#define check_curl_result(result, errstr) \
+ if (result != CURLE_OK) { \
+ std::string e(errstr); \
+ e += ::curl_easy_strerror(result); \
+ this->SetError(e); \
+ return false; \
+ }
+
+bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ std::vector<std::string>::const_iterator i = args.begin();
+ if (args.size() < 3) {
+ this->SetError("DOWNLOAD must be called with at least three arguments.");
+ return false;
+ }
+ ++i; // Get rid of subcommand
+ std::string url = *i;
+ ++i;
+ std::string file = *i;
+ ++i;
+
+ long timeout = 0;
+ long inactivity_timeout = 0;
+ std::string logVar;
+ std::string statusVar;
+ bool tls_verify = this->Makefile->IsOn("CMAKE_TLS_VERIFY");
+ const char* cainfo = this->Makefile->GetDefinition("CMAKE_TLS_CAINFO");
+ std::string expectedHash;
+ std::string hashMatchMSG;
+ CM_AUTO_PTR<cmCryptoHash> hash;
+ bool showProgress = false;
+
+ while (i != args.end()) {
+ if (*i == "TIMEOUT") {
+ ++i;
+ if (i != args.end()) {
+ timeout = atol(i->c_str());
+ } else {
+ this->SetError("DOWNLOAD missing time for TIMEOUT.");
+ return false;
+ }
+ } else if (*i == "INACTIVITY_TIMEOUT") {
+ ++i;
+ if (i != args.end()) {
+ inactivity_timeout = atol(i->c_str());
+ } else {
+ this->SetError("DOWNLOAD missing time for INACTIVITY_TIMEOUT.");
+ return false;
+ }
+ } else if (*i == "LOG") {
+ ++i;
+ if (i == args.end()) {
+ this->SetError("DOWNLOAD missing VAR for LOG.");
+ return false;
+ }
+ logVar = *i;
+ } else if (*i == "STATUS") {
+ ++i;
+ if (i == args.end()) {
+ this->SetError("DOWNLOAD missing VAR for STATUS.");
+ return false;
+ }
+ statusVar = *i;
+ } else if (*i == "TLS_VERIFY") {
+ ++i;
+ if (i != args.end()) {
+ tls_verify = cmSystemTools::IsOn(i->c_str());
+ } else {
+ this->SetError("TLS_VERIFY missing bool value.");
+ return false;
+ }
+ } else if (*i == "TLS_CAINFO") {
+ ++i;
+ if (i != args.end()) {
+ cainfo = i->c_str();
+ } else {
+ this->SetError("TLS_CAFILE missing file value.");
+ return false;
+ }
+ } else if (*i == "EXPECTED_MD5") {
+ ++i;
+ if (i == args.end()) {
+ this->SetError("DOWNLOAD missing sum value for EXPECTED_MD5.");
+ return false;
+ }
+ hash = CM_AUTO_PTR<cmCryptoHash>(cmCryptoHash::New("MD5"));
+ hashMatchMSG = "MD5 sum";
+ expectedHash = cmSystemTools::LowerCase(*i);
+ } else if (*i == "SHOW_PROGRESS") {
+ showProgress = true;
+ } else if (*i == "EXPECTED_HASH") {
+ ++i;
+ if (i == args.end()) {
+ this->SetError("DOWNLOAD missing ALGO=value for EXPECTED_HASH.");
+ return false;
+ }
+ std::string::size_type pos = i->find("=");
+ if (pos == std::string::npos) {
+ std::string err =
+ "DOWNLOAD EXPECTED_HASH expects ALGO=value but got: ";
+ err += *i;
+ this->SetError(err);
+ return false;
+ }
+ std::string algo = i->substr(0, pos);
+ expectedHash = cmSystemTools::LowerCase(i->substr(pos + 1));
+ hash = CM_AUTO_PTR<cmCryptoHash>(cmCryptoHash::New(algo.c_str()));
+ if (!hash.get()) {
+ std::string err = "DOWNLOAD EXPECTED_HASH given unknown ALGO: ";
+ err += algo;
+ this->SetError(err);
+ return false;
+ }
+ hashMatchMSG = algo + " hash";
+ }
+ ++i;
+ }
+ // If file exists already, and caller specified an expected md5 or sha,
+ // and the existing file already has the expected hash, then simply
+ // return.
+ //
+ if (cmSystemTools::FileExists(file.c_str()) && hash.get()) {
+ std::string msg;
+ std::string actualHash = hash->HashFile(file);
+ if (actualHash == expectedHash) {
+ msg = "returning early; file already exists with expected ";
+ msg += hashMatchMSG;
+ msg += "\"";
+ if (!statusVar.empty()) {
+ std::ostringstream result;
+ result << (int)0 << ";\"" << msg;
+ this->Makefile->AddDefinition(statusVar, result.str().c_str());
+ }
+ return true;
+ }
+ }
+ // Make sure parent directory exists so we can write to the file
+ // as we receive downloaded bits from curl...
+ //
+ std::string dir = cmSystemTools::GetFilenamePath(file);
+ if (!cmSystemTools::FileExists(dir.c_str()) &&
+ !cmSystemTools::MakeDirectory(dir.c_str())) {
+ std::string errstring = "DOWNLOAD error: cannot create directory '" + dir +
+ "' - Specify file by full path name and verify that you "
+ "have directory creation and file write privileges.";
+ this->SetError(errstring);
+ return false;
+ }
+
+ cmsys::ofstream fout(file.c_str(), std::ios::binary);
+ if (!fout) {
+ this->SetError("DOWNLOAD cannot open file for write.");
+ return false;
+ }
+
+#if defined(_WIN32) && defined(CMAKE_ENCODING_UTF8)
+ url = fix_file_url_windows(url);
+#endif
+
+ ::CURL* curl;
+ ::curl_global_init(CURL_GLOBAL_DEFAULT);
+ curl = ::curl_easy_init();
+ if (!curl) {
+ this->SetError("DOWNLOAD error initializing curl.");
+ return false;
+ }
+
+ cURLEasyGuard g_curl(curl);
+ ::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+ check_curl_result(res, "DOWNLOAD cannot set url: ");
+
+ // enable HTTP ERROR parsing
+ res = ::curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
+ check_curl_result(res, "DOWNLOAD cannot set http failure option: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/" LIBCURL_VERSION);
+ check_curl_result(res, "DOWNLOAD cannot set user agent option: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cmWriteToFileCallback);
+ check_curl_result(res, "DOWNLOAD cannot set write function: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
+ cmFileCommandCurlDebugCallback);
+ check_curl_result(res, "DOWNLOAD cannot set debug function: ");
+
+ // check to see if TLS verification is requested
+ if (tls_verify) {
+ res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
+ check_curl_result(res, "Unable to set TLS/SSL Verify on: ");
+ } else {
+ res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
+ check_curl_result(res, "Unable to set TLS/SSL Verify off: ");
+ }
+ // check to see if a CAINFO file has been specified
+ // command arg comes first
+ std::string const& cainfo_err = cmCurlSetCAInfo(curl, cainfo);
+ if (!cainfo_err.empty()) {
+ this->SetError(cainfo_err);
+ return false;
+ }
+
+ cmFileCommandVectorOfChar chunkDebug;
+
+ res = ::curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&fout);
+ check_curl_result(res, "DOWNLOAD cannot set write data: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void*)&chunkDebug);
+ check_curl_result(res, "DOWNLOAD cannot set debug data: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+ check_curl_result(res, "DOWNLOAD cannot set follow-redirect option: ");
+
+ if (!logVar.empty()) {
+ res = ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+ check_curl_result(res, "DOWNLOAD cannot set verbose: ");
+ }
+
+ if (timeout > 0) {
+ res = ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
+ check_curl_result(res, "DOWNLOAD cannot set timeout: ");
+ }
+
+ if (inactivity_timeout > 0) {
+ // Give up if there is no progress for a long time.
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, inactivity_timeout);
+ }
+
+ // Need the progress helper's scope to last through the duration of
+ // the curl_easy_perform call... so this object is declared at function
+ // scope intentionally, rather than inside the "if(showProgress)"
+ // block...
+ //
+ cURLProgressHelper helper(this, "download");
+
+ if (showProgress) {
+ res = ::curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
+ check_curl_result(res, "DOWNLOAD cannot set noprogress value: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,
+ cmFileDownloadProgressCallback);
+ check_curl_result(res, "DOWNLOAD cannot set progress function: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_PROGRESSDATA,
+ reinterpret_cast<void*>(&helper));
+ check_curl_result(res, "DOWNLOAD cannot set progress data: ");
+ }
+
+ res = ::curl_easy_perform(curl);
+
+ /* always cleanup */
+ g_curl.release();
+ ::curl_easy_cleanup(curl);
+
+ if (!statusVar.empty()) {
+ std::ostringstream result;
+ result << (int)res << ";\"" << ::curl_easy_strerror(res) << "\"";
+ this->Makefile->AddDefinition(statusVar, result.str().c_str());
+ }
+
+ ::curl_global_cleanup();
+
+ // Explicitly flush/close so we can measure the md5 accurately.
+ //
+ fout.flush();
+ fout.close();
+
+ // Verify MD5 sum if requested:
+ //
+ if (hash.get()) {
+ std::string actualHash = hash->HashFile(file);
+ if (actualHash.empty()) {
+ this->SetError("DOWNLOAD cannot compute hash on downloaded file");
+ return false;
+ }
+
+ if (expectedHash != actualHash) {
+ std::ostringstream oss;
+ oss << "DOWNLOAD HASH mismatch" << std::endl
+ << " for file: [" << file << "]" << std::endl
+ << " expected hash: [" << expectedHash << "]" << std::endl
+ << " actual hash: [" << actualHash << "]" << std::endl
+ << " status: [" << (int)res << ";\""
+ << ::curl_easy_strerror(res) << "\"]" << std::endl;
+
+ if (!statusVar.empty() && res == 0) {
+ std::string status = "1;HASH mismatch: "
+ "expected: " +
+ expectedHash + " actual: " + actualHash;
+ this->Makefile->AddDefinition(statusVar, status.c_str());
+ }
+
+ this->SetError(oss.str());
+ return false;
+ }
+ }
+
+ if (!logVar.empty()) {
+ chunkDebug.push_back(0);
+ this->Makefile->AddDefinition(logVar, &*chunkDebug.begin());
+ }
+
+ return true;
+#else
+ this->SetError("DOWNLOAD not supported by bootstrap cmake.");
+ return false;
+#endif
+}
+
+bool cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ if (args.size() < 3) {
+ this->SetError("UPLOAD must be called with at least three arguments.");
+ return false;
+ }
+ std::vector<std::string>::const_iterator i = args.begin();
+ ++i;
+ std::string filename = *i;
+ ++i;
+ std::string url = *i;
+ ++i;
+
+ long timeout = 0;
+ long inactivity_timeout = 0;
+ std::string logVar;
+ std::string statusVar;
+ bool showProgress = false;
+
+ while (i != args.end()) {
+ if (*i == "TIMEOUT") {
+ ++i;
+ if (i != args.end()) {
+ timeout = atol(i->c_str());
+ } else {
+ this->SetError("UPLOAD missing time for TIMEOUT.");
+ return false;
+ }
+ } else if (*i == "INACTIVITY_TIMEOUT") {
+ ++i;
+ if (i != args.end()) {
+ inactivity_timeout = atol(i->c_str());
+ } else {
+ this->SetError("UPLOAD missing time for INACTIVITY_TIMEOUT.");
+ return false;
+ }
+ } else if (*i == "LOG") {
+ ++i;
+ if (i == args.end()) {
+ this->SetError("UPLOAD missing VAR for LOG.");
+ return false;
+ }
+ logVar = *i;
+ } else if (*i == "STATUS") {
+ ++i;
+ if (i == args.end()) {
+ this->SetError("UPLOAD missing VAR for STATUS.");
+ return false;
+ }
+ statusVar = *i;
+ } else if (*i == "SHOW_PROGRESS") {
+ showProgress = true;
+ }
+
+ ++i;
+ }
+
+ // Open file for reading:
+ //
+ FILE* fin = cmsys::SystemTools::Fopen(filename, "rb");
+ if (!fin) {
+ std::string errStr = "UPLOAD cannot open file '";
+ errStr += filename + "' for reading.";
+ this->SetError(errStr);
+ return false;
+ }
+
+ unsigned long file_size = cmsys::SystemTools::FileLength(filename);
+
+#if defined(_WIN32) && defined(CMAKE_ENCODING_UTF8)
+ url = fix_file_url_windows(url);
+#endif
+
+ ::CURL* curl;
+ ::curl_global_init(CURL_GLOBAL_DEFAULT);
+ curl = ::curl_easy_init();
+ if (!curl) {
+ this->SetError("UPLOAD error initializing curl.");
+ fclose(fin);
+ return false;
+ }
+
+ cURLEasyGuard g_curl(curl);
+
+ // enable HTTP ERROR parsing
+ ::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
+ check_curl_result(res, "UPLOAD cannot set fail on error flag: ");
+
+ // enable uploading
+ res = ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
+ check_curl_result(res, "UPLOAD cannot set upload flag: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+ check_curl_result(res, "UPLOAD cannot set url: ");
+
+ res =
+ ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cmWriteToMemoryCallback);
+ check_curl_result(res, "UPLOAD cannot set write function: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
+ cmFileCommandCurlDebugCallback);
+ check_curl_result(res, "UPLOAD cannot set debug function: ");
+
+ cmFileCommandVectorOfChar chunkResponse;
+ cmFileCommandVectorOfChar chunkDebug;
+
+ res = ::curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&chunkResponse);
+ check_curl_result(res, "UPLOAD cannot set write data: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void*)&chunkDebug);
+ check_curl_result(res, "UPLOAD cannot set debug data: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+ check_curl_result(res, "UPLOAD cannot set follow-redirect option: ");
+
+ if (!logVar.empty()) {
+ res = ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+ check_curl_result(res, "UPLOAD cannot set verbose: ");
+ }
+
+ if (timeout > 0) {
+ res = ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
+ check_curl_result(res, "UPLOAD cannot set timeout: ");
+ }
+
+ if (inactivity_timeout > 0) {
+ // Give up if there is no progress for a long time.
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, inactivity_timeout);
+ }
+
+ // Need the progress helper's scope to last through the duration of
+ // the curl_easy_perform call... so this object is declared at function
+ // scope intentionally, rather than inside the "if(showProgress)"
+ // block...
+ //
+ cURLProgressHelper helper(this, "upload");
+
+ if (showProgress) {
+ res = ::curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
+ check_curl_result(res, "UPLOAD cannot set noprogress value: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,
+ cmFileUploadProgressCallback);
+ check_curl_result(res, "UPLOAD cannot set progress function: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_PROGRESSDATA,
+ reinterpret_cast<void*>(&helper));
+ check_curl_result(res, "UPLOAD cannot set progress data: ");
+ }
+
+ // now specify which file to upload
+ res = ::curl_easy_setopt(curl, CURLOPT_INFILE, fin);
+ check_curl_result(res, "UPLOAD cannot set input file: ");
+
+ // and give the size of the upload (optional)
+ res =
+ ::curl_easy_setopt(curl, CURLOPT_INFILESIZE, static_cast<long>(file_size));
+ check_curl_result(res, "UPLOAD cannot set input file size: ");
+
+ res = ::curl_easy_perform(curl);
+
+ /* always cleanup */
+ g_curl.release();
+ ::curl_easy_cleanup(curl);
+
+ if (!statusVar.empty()) {
+ std::ostringstream result;
+ result << (int)res << ";\"" << ::curl_easy_strerror(res) << "\"";
+ this->Makefile->AddDefinition(statusVar, result.str().c_str());
+ }
+
+ ::curl_global_cleanup();
+
+ fclose(fin);
+ fin = CM_NULLPTR;
+
+ if (!logVar.empty()) {
+ std::string log;
+
+ if (!chunkResponse.empty()) {
+ chunkResponse.push_back(0);
+ log += "Response:\n";
+ log += &*chunkResponse.begin();
+ log += "\n";
+ }
+
+ if (!chunkDebug.empty()) {
+ chunkDebug.push_back(0);
+ log += "Debug:\n";
+ log += &*chunkDebug.begin();
+ log += "\n";
+ }
+
+ this->Makefile->AddDefinition(logVar, log.c_str());
+ }
+
+ return true;
+#else
+ this->SetError("UPLOAD not supported by bootstrap cmake.");
+ return false;
+#endif
+}
+
+void cmFileCommand::AddEvaluationFile(const std::string& inputName,
+ const std::string& outputExpr,
+ const std::string& condition,
+ bool inputIsContent)
+{
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+
+ cmGeneratorExpression outputGe(lfbt);
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> outputCge =
+ outputGe.Parse(outputExpr);
+
+ cmGeneratorExpression conditionGe(lfbt);
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> conditionCge =
+ conditionGe.Parse(condition);
+
+ this->Makefile->AddEvaluationFile(inputName, outputCge, conditionCge,
+ inputIsContent);
+}
+
+bool cmFileCommand::HandleGenerateCommand(std::vector<std::string> const& args)
+{
+ if (args.size() < 5) {
+ this->SetError("Incorrect arguments to GENERATE subcommand.");
+ return false;
+ }
+ if (args[1] != "OUTPUT") {
+ this->SetError("Incorrect arguments to GENERATE subcommand.");
+ return false;
+ }
+ std::string condition;
+ if (args.size() > 5) {
+ if (args[5] != "CONDITION") {
+ this->SetError("Incorrect arguments to GENERATE subcommand.");
+ return false;
+ }
+ if (args.size() != 7) {
+ this->SetError("Incorrect arguments to GENERATE subcommand.");
+ return false;
+ }
+ condition = args[6];
+ if (condition.empty()) {
+ this->SetError("CONDITION of sub-command GENERATE must not be empty if "
+ "specified.");
+ return false;
+ }
+ }
+ std::string output = args[2];
+ const bool inputIsContent = args[3] != "INPUT";
+ if (inputIsContent && args[3] != "CONTENT") {
+ this->SetError("Incorrect arguments to GENERATE subcommand.");
+ return false;
+ }
+ std::string input = args[4];
+
+ this->AddEvaluationFile(input, output, condition, inputIsContent);
+ return true;
+}
+
+bool cmFileCommand::HandleLockCommand(std::vector<std::string> const& args)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ // Default values
+ bool directory = false;
+ bool release = false;
+ enum Guard
+ {
+ GUARD_FUNCTION,
+ GUARD_FILE,
+ GUARD_PROCESS
+ };
+ Guard guard = GUARD_PROCESS;
+ std::string resultVariable;
+ unsigned long timeout = static_cast<unsigned long>(-1);
+
+ // Parse arguments
+ if (args.size() < 2) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR, "sub-command LOCK requires at least two arguments.");
+ return false;
+ }
+
+ std::string path = args[1];
+ for (unsigned i = 2; i < args.size(); ++i) {
+ if (args[i] == "DIRECTORY") {
+ directory = true;
+ } else if (args[i] == "RELEASE") {
+ release = true;
+ } else if (args[i] == "GUARD") {
+ ++i;
+ const char* merr = "expected FUNCTION, FILE or PROCESS after GUARD";
+ if (i >= args.size()) {
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, merr);
+ return false;
+ } else {
+ if (args[i] == "FUNCTION") {
+ guard = GUARD_FUNCTION;
+ } else if (args[i] == "FILE") {
+ guard = GUARD_FILE;
+ } else if (args[i] == "PROCESS") {
+ guard = GUARD_PROCESS;
+ } else {
+ std::ostringstream e;
+ e << merr << ", but got:\n \"" << args[i] << "\".";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ }
+ } else if (args[i] == "RESULT_VARIABLE") {
+ ++i;
+ if (i >= args.size()) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR, "expected variable name after RESULT_VARIABLE");
+ return false;
+ }
+ resultVariable = args[i];
+ } else if (args[i] == "TIMEOUT") {
+ ++i;
+ if (i >= args.size()) {
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR,
+ "expected timeout value after TIMEOUT");
+ return false;
+ }
+ long scanned;
+ if (!cmSystemTools::StringToLong(args[i].c_str(), &scanned) ||
+ scanned < 0) {
+ std::ostringstream e;
+ e << "TIMEOUT value \"" << args[i] << "\" is not an unsigned integer.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ timeout = static_cast<unsigned long>(scanned);
+ } else {
+ std::ostringstream e;
+ e << "expected DIRECTORY, RELEASE, GUARD, RESULT_VARIABLE or TIMEOUT\n";
+ e << "but got: \"" << args[i] << "\".";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ }
+
+ if (directory) {
+ path += "/cmake.lock";
+ }
+
+ if (!cmsys::SystemTools::FileIsFullPath(path)) {
+ path = this->Makefile->GetCurrentSourceDirectory() + ("/" + path);
+ }
+
+ // Unify path (remove '//', '/../', ...)
+ path = cmSystemTools::CollapseFullPath(path);
+
+ // Create file and directories if needed
+ std::string parentDir = cmSystemTools::GetParentDirectory(path);
+ if (!cmSystemTools::MakeDirectory(parentDir)) {
+ std::ostringstream e;
+ e << "directory\n \"" << parentDir << "\"\ncreation failed ";
+ e << "(check permissions).";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ FILE* file = cmsys::SystemTools::Fopen(path, "w");
+ if (!file) {
+ std::ostringstream e;
+ e << "file\n \"" << path << "\"\ncreation failed (check permissions).";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ fclose(file);
+
+ // Actual lock/unlock
+ cmFileLockPool& lockPool =
+ this->Makefile->GetGlobalGenerator()->GetFileLockPool();
+
+ cmFileLockResult fileLockResult(cmFileLockResult::MakeOk());
+ if (release) {
+ fileLockResult = lockPool.Release(path);
+ } else {
+ switch (guard) {
+ case GUARD_FUNCTION:
+ fileLockResult = lockPool.LockFunctionScope(path, timeout);
+ break;
+ case GUARD_FILE:
+ fileLockResult = lockPool.LockFileScope(path, timeout);
+ break;
+ case GUARD_PROCESS:
+ fileLockResult = lockPool.LockProcessScope(path, timeout);
+ break;
+ default:
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+
+ const std::string result = fileLockResult.GetOutputMessage();
+
+ if (resultVariable.empty() && !fileLockResult.IsOk()) {
+ std::ostringstream e;
+ e << "error locking file\n \"" << path << "\"\n" << result << ".";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!resultVariable.empty()) {
+ this->Makefile->AddDefinition(resultVariable, result.c_str());
+ }
+
+ return true;
+#else
+ static_cast<void>(args);
+ this->SetError("sub-command LOCK not implemented in bootstrap cmake");
+ return false;
+#endif
+}
+
+bool cmFileCommand::HandleTimestampCommand(
+ std::vector<std::string> const& args)
+{
+ if (args.size() < 3) {
+ this->SetError("sub-command TIMESTAMP requires at least two arguments.");
+ return false;
+ } else if (args.size() > 5) {
+ this->SetError("sub-command TIMESTAMP takes at most four arguments.");
+ return false;
+ }
+
+ unsigned int argsIndex = 1;
+
+ const std::string& filename = args[argsIndex++];
+
+ const std::string& outputVariable = args[argsIndex++];
+
+ std::string formatString;
+ if (args.size() > argsIndex && args[argsIndex] != "UTC") {
+ formatString = args[argsIndex++];
+ }
+
+ bool utcFlag = false;
+ if (args.size() > argsIndex) {
+ if (args[argsIndex] == "UTC") {
+ utcFlag = true;
+ } else {
+ std::string e = " TIMESTAMP sub-command does not recognize option " +
+ args[argsIndex] + ".";
+ this->SetError(e);
+ return false;
+ }
+ }
+
+ cmTimestamp timestamp;
+ std::string result =
+ timestamp.FileModificationTime(filename.c_str(), formatString, utcFlag);
+ this->Makefile->AddDefinition(outputVariable, result.c_str());
+
+ return true;
+}
diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h
new file mode 100644
index 0000000..9121d3c
--- /dev/null
+++ b/Source/cmFileCommand.h
@@ -0,0 +1,83 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFileCommand_h
+#define cmFileCommand_h
+
+#include "cmCommand.h"
+
+struct cmFileInstaller;
+
+/** \class cmFileCommand
+ * \brief Command for manipulation of files
+ *
+ */
+class cmFileCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmFileCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "file"; }
+
+ cmTypeMacro(cmFileCommand, cmCommand);
+
+protected:
+ bool HandleRename(std::vector<std::string> const& args);
+ bool HandleRemove(std::vector<std::string> const& args, bool recurse);
+ bool HandleWriteCommand(std::vector<std::string> const& args, bool append);
+ bool HandleReadCommand(std::vector<std::string> const& args);
+ bool HandleHashCommand(std::vector<std::string> const& args);
+ bool HandleStringsCommand(std::vector<std::string> const& args);
+ bool HandleGlobCommand(std::vector<std::string> const& args, bool recurse);
+ bool HandleMakeDirectoryCommand(std::vector<std::string> const& args);
+
+ bool HandleRelativePathCommand(std::vector<std::string> const& args);
+ bool HandleCMakePathCommand(std::vector<std::string> const& args,
+ bool nativePath);
+ bool HandleRPathChangeCommand(std::vector<std::string> const& args);
+ bool HandleRPathCheckCommand(std::vector<std::string> const& args);
+ bool HandleRPathRemoveCommand(std::vector<std::string> const& args);
+ bool HandleDifferentCommand(std::vector<std::string> const& args);
+
+ bool HandleCopyCommand(std::vector<std::string> const& args);
+ bool HandleInstallCommand(std::vector<std::string> const& args);
+ bool HandleDownloadCommand(std::vector<std::string> const& args);
+ bool HandleUploadCommand(std::vector<std::string> const& args);
+
+ bool HandleTimestampCommand(std::vector<std::string> const& args);
+ bool HandleGenerateCommand(std::vector<std::string> const& args);
+ bool HandleLockCommand(std::vector<std::string> const& args);
+
+private:
+ void AddEvaluationFile(const std::string& inputName,
+ const std::string& outputExpr,
+ const std::string& condition, bool inputIsContent);
+};
+
+#endif
diff --git a/Source/cmFileLock.cxx b/Source/cmFileLock.cxx
new file mode 100644
index 0000000..828511f
--- /dev/null
+++ b/Source/cmFileLock.cxx
@@ -0,0 +1,70 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Ruslan Baratov
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmFileLock.h"
+
+#include "cmFileLockResult.h"
+#include <assert.h>
+
+// Common implementation
+
+cmFileLock::~cmFileLock()
+{
+ if (!this->Filename.empty()) {
+ const cmFileLockResult result = this->Release();
+ static_cast<void>(result);
+ assert(result.IsOk());
+ }
+}
+
+cmFileLockResult cmFileLock::Lock(const std::string& filename,
+ unsigned long timeout)
+{
+ if (filename.empty()) {
+ // Error is internal since all the directories and file must be created
+ // before actual lock called.
+ return cmFileLockResult::MakeInternal();
+ }
+
+ if (!this->Filename.empty()) {
+ // Error is internal since double-lock must be checked in class
+ // cmFileLockPool by the cmFileLock::IsLocked method.
+ return cmFileLockResult::MakeInternal();
+ }
+
+ this->Filename = filename;
+ cmFileLockResult result = this->OpenFile();
+ if (result.IsOk()) {
+ if (timeout == static_cast<unsigned long>(-1)) {
+ result = this->LockWithoutTimeout();
+ } else {
+ result = this->LockWithTimeout(timeout);
+ }
+ }
+
+ if (!result.IsOk()) {
+ this->Filename = "";
+ }
+
+ return result;
+}
+
+bool cmFileLock::IsLocked(const std::string& filename) const
+{
+ return filename == this->Filename;
+}
+
+#if defined(_WIN32)
+#include "cmFileLockWin32.cxx"
+#else
+#include "cmFileLockUnix.cxx"
+#endif
diff --git a/Source/cmFileLock.h b/Source/cmFileLock.h
new file mode 100644
index 0000000..538b716
--- /dev/null
+++ b/Source/cmFileLock.h
@@ -0,0 +1,74 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Ruslan Baratov
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmFileLock_h
+#define cmFileLock_h
+
+#include "cmStandardIncludes.h"
+
+#if defined(_WIN32)
+#include <windows.h> // HANDLE
+#endif
+
+class cmFileLockResult;
+
+/**
+ * @brief Cross-platform file locking.
+ * @details Under the hood this class use 'fcntl' for Unix-like platforms and
+ * 'LockFileEx'/'UnlockFileEx' for Win32 platform. Locks are exclusive and
+ * advisory.
+ */
+class cmFileLock
+{
+public:
+ cmFileLock();
+ ~cmFileLock();
+
+ /**
+ * @brief Lock the file.
+ * @param timeoutSec Lock timeout. If -1 try until success or fatal error.
+ */
+ cmFileLockResult Lock(const std::string& filename, unsigned long timeoutSec);
+
+ /**
+ * @brief Unlock the file.
+ */
+ cmFileLockResult Release();
+
+ /**
+ * @brief Check file is locked by this class.
+ * @details This function helps to find double locks (deadlocks) and to do
+ * explicit unlocks.
+ */
+ bool IsLocked(const std::string& filename) const;
+
+private:
+ cmFileLock(const cmFileLock&);
+ cmFileLock& operator=(const cmFileLock&);
+
+ cmFileLockResult OpenFile();
+ cmFileLockResult LockWithoutTimeout();
+ cmFileLockResult LockWithTimeout(unsigned long timeoutSec);
+
+#if defined(_WIN32)
+ typedef HANDLE FileId;
+ BOOL LockFile(DWORD flags);
+#else
+ typedef int FileId;
+ int LockFile(int cmd, int type);
+#endif
+
+ FileId File;
+ std::string Filename;
+};
+
+#endif // cmFileLock_h
diff --git a/Source/cmFileLockPool.cxx b/Source/cmFileLockPool.cxx
new file mode 100644
index 0000000..7c51459
--- /dev/null
+++ b/Source/cmFileLockPool.cxx
@@ -0,0 +1,169 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Ruslan Baratov
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmFileLockPool.h"
+
+#include <assert.h>
+
+#include "cmAlgorithms.h"
+#include "cmFileLock.h"
+#include "cmFileLockResult.h"
+
+cmFileLockPool::cmFileLockPool()
+{
+}
+
+cmFileLockPool::~cmFileLockPool()
+{
+ cmDeleteAll(this->FunctionScopes);
+ cmDeleteAll(this->FileScopes);
+}
+
+void cmFileLockPool::PushFunctionScope()
+{
+ this->FunctionScopes.push_back(new ScopePool());
+}
+
+void cmFileLockPool::PopFunctionScope()
+{
+ assert(!this->FunctionScopes.empty());
+ delete this->FunctionScopes.back();
+ this->FunctionScopes.pop_back();
+}
+
+void cmFileLockPool::PushFileScope()
+{
+ this->FileScopes.push_back(new ScopePool());
+}
+
+void cmFileLockPool::PopFileScope()
+{
+ assert(!this->FileScopes.empty());
+ delete this->FileScopes.back();
+ this->FileScopes.pop_back();
+}
+
+cmFileLockResult cmFileLockPool::LockFunctionScope(const std::string& filename,
+ unsigned long timeoutSec)
+{
+ if (this->IsAlreadyLocked(filename)) {
+ return cmFileLockResult::MakeAlreadyLocked();
+ }
+ if (this->FunctionScopes.empty()) {
+ return cmFileLockResult::MakeNoFunction();
+ }
+ return this->FunctionScopes.back()->Lock(filename, timeoutSec);
+}
+
+cmFileLockResult cmFileLockPool::LockFileScope(const std::string& filename,
+ unsigned long timeoutSec)
+{
+ if (this->IsAlreadyLocked(filename)) {
+ return cmFileLockResult::MakeAlreadyLocked();
+ }
+ assert(!this->FileScopes.empty());
+ return this->FileScopes.back()->Lock(filename, timeoutSec);
+}
+
+cmFileLockResult cmFileLockPool::LockProcessScope(const std::string& filename,
+ unsigned long timeoutSec)
+{
+ if (this->IsAlreadyLocked(filename)) {
+ return cmFileLockResult::MakeAlreadyLocked();
+ }
+ return this->ProcessScope.Lock(filename, timeoutSec);
+}
+
+cmFileLockResult cmFileLockPool::Release(const std::string& filename)
+{
+ for (It i = this->FunctionScopes.begin(); i != this->FunctionScopes.end();
+ ++i) {
+ const cmFileLockResult result = (*i)->Release(filename);
+ if (!result.IsOk()) {
+ return result;
+ }
+ }
+
+ for (It i = this->FileScopes.begin(); i != this->FileScopes.end(); ++i) {
+ const cmFileLockResult result = (*i)->Release(filename);
+ if (!result.IsOk()) {
+ return result;
+ }
+ }
+
+ return this->ProcessScope.Release(filename);
+}
+
+bool cmFileLockPool::IsAlreadyLocked(const std::string& filename) const
+{
+ for (CIt i = this->FunctionScopes.begin(); i != this->FunctionScopes.end();
+ ++i) {
+ const bool result = (*i)->IsAlreadyLocked(filename);
+ if (result) {
+ return true;
+ }
+ }
+
+ for (CIt i = this->FileScopes.begin(); i != this->FileScopes.end(); ++i) {
+ const bool result = (*i)->IsAlreadyLocked(filename);
+ if (result) {
+ return true;
+ }
+ }
+
+ return this->ProcessScope.IsAlreadyLocked(filename);
+}
+
+cmFileLockPool::ScopePool::ScopePool()
+{
+}
+
+cmFileLockPool::ScopePool::~ScopePool()
+{
+ cmDeleteAll(this->Locks);
+}
+
+cmFileLockResult cmFileLockPool::ScopePool::Lock(const std::string& filename,
+ unsigned long timeoutSec)
+{
+ cmFileLock* lock = new cmFileLock();
+ const cmFileLockResult result = lock->Lock(filename, timeoutSec);
+ if (result.IsOk()) {
+ this->Locks.push_back(lock);
+ return cmFileLockResult::MakeOk();
+ } else {
+ delete lock;
+ return result;
+ }
+}
+
+cmFileLockResult cmFileLockPool::ScopePool::Release(
+ const std::string& filename)
+{
+ for (It i = this->Locks.begin(); i != this->Locks.end(); ++i) {
+ if ((*i)->IsLocked(filename)) {
+ return (*i)->Release();
+ }
+ }
+ return cmFileLockResult::MakeOk();
+}
+
+bool cmFileLockPool::ScopePool::IsAlreadyLocked(
+ const std::string& filename) const
+{
+ for (CIt i = this->Locks.begin(); i != this->Locks.end(); ++i) {
+ if ((*i)->IsLocked(filename)) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/Source/cmFileLockPool.h b/Source/cmFileLockPool.h
new file mode 100644
index 0000000..dc42e6f
--- /dev/null
+++ b/Source/cmFileLockPool.h
@@ -0,0 +1,100 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Ruslan Baratov
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFileLockPool_h
+#define cmFileLockPool_h
+
+#include "cmStandardIncludes.h"
+
+#include <list>
+
+class cmFileLockResult;
+class cmFileLock;
+
+class cmFileLockPool
+{
+public:
+ cmFileLockPool();
+ ~cmFileLockPool();
+
+ //@{
+ /**
+ * @brief Function scope control.
+ */
+ void PushFunctionScope();
+ void PopFunctionScope();
+ //@}
+
+ //@{
+ /**
+ * @brief File scope control.
+ */
+ void PushFileScope();
+ void PopFileScope();
+ //@}
+
+ //@{
+ /**
+ * @brief Lock the file in given scope.
+ * @param timeoutSec Lock timeout. If -1 try until success or fatal error.
+ */
+ cmFileLockResult LockFunctionScope(const std::string& filename,
+ unsigned long timeoutSec);
+ cmFileLockResult LockFileScope(const std::string& filename,
+ unsigned long timeoutSec);
+ cmFileLockResult LockProcessScope(const std::string& filename,
+ unsigned long timeoutSec);
+ //@}
+
+ /**
+ * @brief Unlock the file explicitly.
+ */
+ cmFileLockResult Release(const std::string& filename);
+
+private:
+ cmFileLockPool(const cmFileLockPool&);
+ cmFileLockPool& operator=(const cmFileLockPool&);
+
+ bool IsAlreadyLocked(const std::string& filename) const;
+
+ class ScopePool
+ {
+ public:
+ ScopePool();
+ ~ScopePool();
+
+ cmFileLockResult Lock(const std::string& filename,
+ unsigned long timeoutSec);
+ cmFileLockResult Release(const std::string& filename);
+ bool IsAlreadyLocked(const std::string& filename) const;
+
+ private:
+ ScopePool(const ScopePool&);
+ ScopePool& operator=(const ScopePool&);
+
+ typedef std::list<cmFileLock*> List;
+ typedef List::iterator It;
+ typedef List::const_iterator CIt;
+
+ List Locks;
+ };
+
+ typedef std::list<ScopePool*> List;
+
+ typedef List::iterator It;
+ typedef List::const_iterator CIt;
+
+ List FunctionScopes;
+ List FileScopes;
+ ScopePool ProcessScope;
+};
+
+#endif // cmFileLockPool_h
diff --git a/Source/cmFileLockResult.cxx b/Source/cmFileLockResult.cxx
new file mode 100644
index 0000000..090fe60
--- /dev/null
+++ b/Source/cmFileLockResult.cxx
@@ -0,0 +1,101 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Ruslan Baratov
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmFileLockResult.h"
+
+#include <errno.h>
+
+cmFileLockResult cmFileLockResult::MakeOk()
+{
+ return cmFileLockResult(OK, 0);
+}
+
+cmFileLockResult cmFileLockResult::MakeSystem()
+{
+#if defined(_WIN32)
+ const Error lastError = GetLastError();
+#else
+ const Error lastError = errno;
+#endif
+ return cmFileLockResult(SYSTEM, lastError);
+}
+
+cmFileLockResult cmFileLockResult::MakeTimeout()
+{
+ return cmFileLockResult(TIMEOUT, 0);
+}
+
+cmFileLockResult cmFileLockResult::MakeAlreadyLocked()
+{
+ return cmFileLockResult(ALREADY_LOCKED, 0);
+}
+
+cmFileLockResult cmFileLockResult::MakeInternal()
+{
+ return cmFileLockResult(INTERNAL, 0);
+}
+
+cmFileLockResult cmFileLockResult::MakeNoFunction()
+{
+ return cmFileLockResult(NO_FUNCTION, 0);
+}
+
+bool cmFileLockResult::IsOk() const
+{
+ return this->Type == OK;
+}
+
+std::string cmFileLockResult::GetOutputMessage() const
+{
+ switch (this->Type) {
+ case OK:
+ return "0";
+ case SYSTEM:
+#if defined(_WIN32)
+ {
+ char* errorText = NULL;
+
+ // http://stackoverflow.com/a/455533/2288008
+ DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS;
+ ::FormatMessageA(flags, NULL, this->ErrorValue,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&errorText, 0, NULL);
+
+ if (errorText != NULL) {
+ const std::string message = errorText;
+ ::LocalFree(errorText);
+ return message;
+ } else {
+ return "Internal error (FormatMessageA failed)";
+ }
+ }
+#else
+ return strerror(this->ErrorValue);
+#endif
+ case TIMEOUT:
+ return "Timeout reached";
+ case ALREADY_LOCKED:
+ return "File already locked";
+ case NO_FUNCTION:
+ return "'GUARD FUNCTION' not used in function definition";
+ case INTERNAL:
+ default:
+ return "Internal error";
+ }
+}
+
+cmFileLockResult::cmFileLockResult(ErrorType typeValue, Error errorValue)
+ : Type(typeValue)
+ , ErrorValue(errorValue)
+{
+}
diff --git a/Source/cmFileLockResult.h b/Source/cmFileLockResult.h
new file mode 100644
index 0000000..d5ac354
--- /dev/null
+++ b/Source/cmFileLockResult.h
@@ -0,0 +1,85 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Ruslan Baratov
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmFileLockResult_h
+#define cmFileLockResult_h
+
+#include "cmStandardIncludes.h"
+
+#if defined(_WIN32)
+#include <windows.h> // DWORD
+#endif
+
+/**
+ * @brief Result of the locking/unlocking file.
+ * @note See @c cmFileLock
+ */
+class cmFileLockResult
+{
+public:
+#if defined(_WIN32)
+ typedef DWORD Error;
+#else
+ typedef int Error;
+#endif
+
+ /**
+ * @brief Successful lock/unlock.
+ */
+ static cmFileLockResult MakeOk();
+
+ /**
+ * @brief Lock/Unlock failed. Read error/GetLastError.
+ */
+ static cmFileLockResult MakeSystem();
+
+ /**
+ * @brief Lock/Unlock failed. Timeout reached.
+ */
+ static cmFileLockResult MakeTimeout();
+
+ /**
+ * @brief File already locked.
+ */
+ static cmFileLockResult MakeAlreadyLocked();
+
+ /**
+ * @brief Internal error.
+ */
+ static cmFileLockResult MakeInternal();
+
+ /**
+ * @brief Try to lock with function guard outside of the function
+ */
+ static cmFileLockResult MakeNoFunction();
+
+ bool IsOk() const;
+ std::string GetOutputMessage() const;
+
+private:
+ enum ErrorType
+ {
+ OK,
+ SYSTEM,
+ TIMEOUT,
+ ALREADY_LOCKED,
+ INTERNAL,
+ NO_FUNCTION
+ };
+
+ cmFileLockResult(ErrorType type, Error errorValue);
+
+ ErrorType Type;
+ Error ErrorValue;
+};
+
+#endif // cmFileLockResult_h
diff --git a/Source/cmFileLockUnix.cxx b/Source/cmFileLockUnix.cxx
new file mode 100644
index 0000000..6be6abc
--- /dev/null
+++ b/Source/cmFileLockUnix.cxx
@@ -0,0 +1,91 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Ruslan Baratov
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmFileLock.h"
+
+#include "cmSystemTools.h"
+#include <errno.h> // errno
+#include <fcntl.h>
+#include <stdio.h> // SEEK_SET
+#include <unistd.h>
+
+cmFileLock::cmFileLock()
+ : File(-1)
+{
+}
+
+cmFileLockResult cmFileLock::Release()
+{
+ if (this->Filename.empty()) {
+ return cmFileLockResult::MakeOk();
+ }
+ const int lockResult = this->LockFile(F_SETLK, F_UNLCK);
+
+ this->Filename = "";
+
+ ::close(this->File);
+ this->File = -1;
+
+ if (lockResult == 0) {
+ return cmFileLockResult::MakeOk();
+ } else {
+ return cmFileLockResult::MakeSystem();
+ }
+}
+
+cmFileLockResult cmFileLock::OpenFile()
+{
+ this->File = ::open(this->Filename.c_str(), O_RDWR);
+ if (this->File == -1) {
+ return cmFileLockResult::MakeSystem();
+ } else {
+ return cmFileLockResult::MakeOk();
+ }
+}
+
+cmFileLockResult cmFileLock::LockWithoutTimeout()
+{
+ if (this->LockFile(F_SETLKW, F_WRLCK) == -1) {
+ return cmFileLockResult::MakeSystem();
+ } else {
+ return cmFileLockResult::MakeOk();
+ }
+}
+
+cmFileLockResult cmFileLock::LockWithTimeout(unsigned long seconds)
+{
+ while (true) {
+ if (this->LockFile(F_SETLK, F_WRLCK) == -1) {
+ if (errno != EACCES && errno != EAGAIN) {
+ return cmFileLockResult::MakeSystem();
+ }
+ } else {
+ return cmFileLockResult::MakeOk();
+ }
+ if (seconds == 0) {
+ return cmFileLockResult::MakeTimeout();
+ }
+ --seconds;
+ cmSystemTools::Delay(1000);
+ }
+}
+
+int cmFileLock::LockFile(int cmd, int type)
+{
+ struct ::flock lock;
+ lock.l_start = 0;
+ lock.l_len = 0; // lock all bytes
+ lock.l_pid = 0; // unused (for F_GETLK only)
+ lock.l_type = static_cast<short>(type); // exclusive lock
+ lock.l_whence = SEEK_SET;
+ return ::fcntl(this->File, cmd, &lock);
+}
diff --git a/Source/cmFileLockWin32.cxx b/Source/cmFileLockWin32.cxx
new file mode 100644
index 0000000..0ba1e9a
--- /dev/null
+++ b/Source/cmFileLockWin32.cxx
@@ -0,0 +1,98 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Ruslan Baratov
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmFileLock.h"
+
+#include "cmSystemTools.h"
+#include <windows.h> // CreateFileW
+
+cmFileLock::cmFileLock()
+ : File(INVALID_HANDLE_VALUE)
+{
+}
+
+cmFileLockResult cmFileLock::Release()
+{
+ if (this->Filename.empty()) {
+ return cmFileLockResult::MakeOk();
+ }
+ const unsigned long len = static_cast<unsigned long>(-1);
+ static OVERLAPPED overlapped;
+ const DWORD reserved = 0;
+ const BOOL unlockResult =
+ UnlockFileEx(File, reserved, len, len, &overlapped);
+
+ this->Filename = "";
+
+ CloseHandle(this->File);
+ this->File = INVALID_HANDLE_VALUE;
+
+ if (unlockResult) {
+ return cmFileLockResult::MakeOk();
+ } else {
+ return cmFileLockResult::MakeSystem();
+ }
+}
+
+cmFileLockResult cmFileLock::OpenFile()
+{
+ const DWORD access = GENERIC_READ | GENERIC_WRITE;
+ const DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ const PSECURITY_ATTRIBUTES security = NULL;
+ const DWORD attr = 0;
+ const HANDLE templ = NULL;
+ this->File = CreateFileW(
+ cmSystemTools::ConvertToWindowsExtendedPath(this->Filename).c_str(),
+ access, shareMode, security, OPEN_EXISTING, attr, templ);
+ if (this->File == INVALID_HANDLE_VALUE) {
+ return cmFileLockResult::MakeSystem();
+ } else {
+ return cmFileLockResult::MakeOk();
+ }
+}
+
+cmFileLockResult cmFileLock::LockWithoutTimeout()
+{
+ if (!this->LockFile(LOCKFILE_EXCLUSIVE_LOCK)) {
+ return cmFileLockResult::MakeSystem();
+ } else {
+ return cmFileLockResult::MakeOk();
+ }
+}
+
+cmFileLockResult cmFileLock::LockWithTimeout(unsigned long seconds)
+{
+ const DWORD flags = LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY;
+ while (true) {
+ const BOOL result = this->LockFile(flags);
+ if (result) {
+ return cmFileLockResult::MakeOk();
+ }
+ const DWORD error = GetLastError();
+ if (error != ERROR_LOCK_VIOLATION) {
+ return cmFileLockResult::MakeSystem();
+ }
+ if (seconds == 0) {
+ return cmFileLockResult::MakeTimeout();
+ }
+ --seconds;
+ cmSystemTools::Delay(1000);
+ }
+}
+
+BOOL cmFileLock::LockFile(DWORD flags)
+{
+ const DWORD reserved = 0;
+ const unsigned long len = static_cast<unsigned long>(-1);
+ static OVERLAPPED overlapped;
+ return LockFileEx(this->File, flags, reserved, len, len, &overlapped);
+}
diff --git a/Source/cmFileTimeComparison.cxx b/Source/cmFileTimeComparison.cxx
new file mode 100644
index 0000000..9d63505
--- /dev/null
+++ b/Source/cmFileTimeComparison.cxx
@@ -0,0 +1,263 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmFileTimeComparison.h"
+
+// Use a hash table to avoid duplicate file time checks from disk.
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+#include <unordered_map>
+#else
+#include <cmsys/hash_map.hxx>
+#endif
+#endif
+
+#include <cmsys/Encoding.hxx>
+
+// Use a platform-specific API to get file times efficiently.
+#if !defined(_WIN32) || defined(__CYGWIN__)
+#define cmFileTimeComparison_Type struct stat
+#include <ctype.h>
+#include <sys/stat.h>
+#else
+#define cmFileTimeComparison_Type FILETIME
+#include <windows.h>
+#endif
+
+class cmFileTimeComparisonInternal
+{
+public:
+ // Internal comparison method.
+ inline bool FileTimeCompare(const char* f1, const char* f2, int* result);
+
+ bool FileTimesDiffer(const char* f1, const char* f2);
+
+private:
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ // Use a hash table to efficiently map from file name to modification time.
+ class HashString
+ {
+ public:
+ size_t operator()(const std::string& s) const { return h(s.c_str()); }
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+ std::hash<const char*> h;
+#else
+ cmsys::hash<const char*> h;
+#endif
+ };
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+ typedef std::unordered_map<std::string,
+#else
+ typedef cmsys::hash_map<std::string,
+#endif
+ cmFileTimeComparison_Type, HashString>
+ FileStatsMap;
+ FileStatsMap Files;
+#endif
+
+ // Internal methods to lookup and compare modification times.
+ inline bool Stat(const char* 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 char* fname,
+ cmFileTimeComparison_Type* st)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ // Use the stored time if available.
+ cmFileTimeComparisonInternal::FileStatsMap::iterator fit =
+ this->Files.find(fname);
+ if (fit != this->Files.end()) {
+ *st = fit->second;
+ return true;
+ }
+#endif
+
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ // POSIX version. Use the stat function.
+ int res = ::stat(fname, 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
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ // Store the time for future use.
+ this->Files[fname] = *st;
+#endif
+
+ return true;
+}
+
+cmFileTimeComparison::cmFileTimeComparison()
+{
+ this->Internals = new cmFileTimeComparisonInternal;
+}
+
+cmFileTimeComparison::~cmFileTimeComparison()
+{
+ delete this->Internals;
+}
+
+bool cmFileTimeComparison::FileTimeCompare(const char* f1, const char* f2,
+ int* result)
+{
+ return this->Internals->FileTimeCompare(f1, f2, result);
+}
+
+bool cmFileTimeComparison::FileTimesDiffer(const char* f1, const char* 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;
+ } else if (s1->st_mtim.tv_sec > s2->st_mtim.tv_sec) {
+ return 1;
+ } else if (s1->st_mtim.tv_nsec < s2->st_mtim.tv_nsec) {
+ return -1;
+ } else 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;
+ } else if (s1->st_mtimespec.tv_sec > s2->st_mtimespec.tv_sec) {
+ return 1;
+ } else if (s1->st_mtimespec.tv_nsec < s2->st_mtimespec.tv_nsec) {
+ return -1;
+ } else 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;
+ } else 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;
+ } else if (t2 < t1) {
+ return (t1 - t2) >= bil;
+ } else {
+ 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;
+ } else if (t2 < t1) {
+ return (t1 - t2) >= bil;
+ } else {
+ 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;
+ } else if (s1->st_mtime > s2->st_mtime) {
+ return (s1->st_mtime - s2->st_mtime) >= 1;
+ } else {
+ 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 char* f1,
+ const char* 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;
+ } else {
+ // No comparison available. Default to the same time.
+ *result = 0;
+ return false;
+ }
+}
+
+bool cmFileTimeComparisonInternal::FileTimesDiffer(const char* f1,
+ const char* 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);
+ } else {
+ // No comparison available. Default to different times.
+ return true;
+ }
+}
diff --git a/Source/cmFileTimeComparison.h b/Source/cmFileTimeComparison.h
new file mode 100644
index 0000000..409bd64
--- /dev/null
+++ b/Source/cmFileTimeComparison.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFileTimeComparison_h
+#define cmFileTimeComparison_h
+
+#include "cmStandardIncludes.h"
+
+class cmFileTimeComparisonInternal;
+
+/** \class cmFileTimeComparison
+ * \brief Helper class for performing globbing searches.
+ *
+ * Finds all files that match a given globbing expression.
+ */
+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 char* f1, const char* 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 char* f1, const char* f2);
+
+protected:
+ cmFileTimeComparisonInternal* Internals;
+};
+
+#endif
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
new file mode 100644
index 0000000..082bbf0
--- /dev/null
+++ b/Source/cmFindBase.cxx
@@ -0,0 +1,333 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmFindBase.h"
+
+#include "cmAlgorithms.h"
+#include "cmState.h"
+
+cmFindBase::cmFindBase()
+{
+ this->AlreadyInCache = false;
+ this->AlreadyInCacheWithoutMetaInfo = false;
+ this->NamesPerDir = false;
+ this->NamesPerDirAllowed = false;
+}
+
+bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
+{
+ if (argsIn.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // copy argsIn into args so it can be modified,
+ // in the process extract the DOC "documentation"
+ size_t size = argsIn.size();
+ std::vector<std::string> args;
+ bool foundDoc = false;
+ for (unsigned int j = 0; j < size; ++j) {
+ if (foundDoc || argsIn[j] != "DOC") {
+ if (argsIn[j] == "ENV") {
+ if (j + 1 < size) {
+ j++;
+ cmSystemTools::GetPath(args, argsIn[j].c_str());
+ }
+ } else {
+ args.push_back(argsIn[j]);
+ }
+ } else {
+ if (j + 1 < size) {
+ foundDoc = true;
+ this->VariableDocumentation = argsIn[j + 1];
+ j++;
+ if (j >= size) {
+ break;
+ }
+ }
+ }
+ }
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ this->VariableName = args[0];
+ if (this->CheckForVariableInCache()) {
+ this->AlreadyInCache = true;
+ return true;
+ }
+ this->AlreadyInCache = false;
+
+ // Find the current root path mode.
+ this->SelectDefaultRootPathMode();
+
+ // Find the current bundle/framework search policy.
+ this->SelectDefaultMacMode();
+
+ bool newStyle = false;
+ enum Doing
+ {
+ DoingNone,
+ DoingNames,
+ DoingPaths,
+ DoingPathSuffixes,
+ DoingHints
+ };
+ Doing doing = DoingNames; // assume it starts with a name
+ for (unsigned int j = 1; j < args.size(); ++j) {
+ if (args[j] == "NAMES") {
+ doing = DoingNames;
+ newStyle = true;
+ } else if (args[j] == "PATHS") {
+ doing = DoingPaths;
+ newStyle = true;
+ } else if (args[j] == "HINTS") {
+ doing = DoingHints;
+ newStyle = true;
+ } else if (args[j] == "PATH_SUFFIXES") {
+ doing = DoingPathSuffixes;
+ newStyle = true;
+ } else if (args[j] == "NAMES_PER_DIR") {
+ doing = DoingNone;
+ if (this->NamesPerDirAllowed) {
+ this->NamesPerDir = true;
+ } else {
+ this->SetError("does not support NAMES_PER_DIR");
+ return false;
+ }
+ } else if (args[j] == "NO_SYSTEM_PATH") {
+ doing = DoingNone;
+ this->NoDefaultPath = true;
+ } else if (this->CheckCommonArgument(args[j])) {
+ doing = DoingNone;
+ // Some common arguments were accidentally supported by CMake
+ // 2.4 and 2.6.0 in the short-hand form of the command, so we
+ // must support it even though it is not documented.
+ } else if (doing == DoingNames) {
+ this->Names.push_back(args[j]);
+ } else if (doing == DoingPaths) {
+ this->UserGuessArgs.push_back(args[j]);
+ } else if (doing == DoingHints) {
+ this->UserHintsArgs.push_back(args[j]);
+ } else if (doing == DoingPathSuffixes) {
+ this->AddPathSuffix(args[j]);
+ }
+ }
+
+ if (this->VariableDocumentation.empty()) {
+ this->VariableDocumentation = "Where can ";
+ if (this->Names.empty()) {
+ this->VariableDocumentation += "the (unknown) library be found";
+ } else if (this->Names.size() == 1) {
+ this->VariableDocumentation +=
+ "the " + this->Names[0] + " library be found";
+ } else {
+ this->VariableDocumentation += "one of the ";
+ this->VariableDocumentation +=
+ cmJoin(cmMakeRange(this->Names).retreat(1), ", ");
+ this->VariableDocumentation +=
+ " or " + this->Names[this->Names.size() - 1] + " libraries be found";
+ }
+ }
+
+ // look for old style
+ // FIND_*(VAR name path1 path2 ...)
+ if (!newStyle) {
+ // All the short-hand arguments have been recorded as names.
+ 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());
+ }
+ this->ExpandPaths();
+
+ this->ComputeFinalPaths();
+
+ return true;
+}
+
+void cmFindBase::ExpandPaths()
+{
+ if (!this->NoDefaultPath) {
+ if (!this->NoCMakePath) {
+ this->FillCMakeVariablePath();
+ }
+ if (!this->NoCMakeEnvironmentPath) {
+ this->FillCMakeEnvironmentPath();
+ }
+ }
+ this->FillUserHintsPath();
+ if (!this->NoDefaultPath) {
+ if (!this->NoSystemEnvironmentPath) {
+ this->FillSystemEnvironmentPath();
+ }
+ if (!this->NoCMakeSystemPath) {
+ this->FillCMakeSystemVariablePath();
+ }
+ }
+ this->FillUserGuessPath();
+}
+
+void cmFindBase::FillCMakeEnvironmentPath()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::CMakeEnvironment];
+
+ // Add CMAKE_*_PATH environment variables
+ std::string var = "CMAKE_";
+ var += this->CMakePathName;
+ var += "_PATH";
+ paths.AddEnvPrefixPath("CMAKE_PREFIX_PATH");
+ paths.AddEnvPath(var);
+
+ if (this->CMakePathName == "PROGRAM") {
+ paths.AddEnvPath("CMAKE_APPBUNDLE_PATH");
+ } else {
+ paths.AddEnvPath("CMAKE_FRAMEWORK_PATH");
+ }
+ paths.AddSuffixes(this->SearchPathSuffixes);
+}
+
+void cmFindBase::FillCMakeVariablePath()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::CMake];
+
+ // Add CMake varibles of the same name as the previous environment
+ // varibles CMAKE_*_PATH to be used most of the time with -D
+ // command line options
+ std::string var = "CMAKE_";
+ var += this->CMakePathName;
+ var += "_PATH";
+ paths.AddCMakePrefixPath("CMAKE_PREFIX_PATH");
+ paths.AddCMakePath(var);
+
+ if (this->CMakePathName == "PROGRAM") {
+ paths.AddCMakePath("CMAKE_APPBUNDLE_PATH");
+ } else {
+ paths.AddCMakePath("CMAKE_FRAMEWORK_PATH");
+ }
+ paths.AddSuffixes(this->SearchPathSuffixes);
+}
+
+void cmFindBase::FillSystemEnvironmentPath()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::SystemEnvironment];
+
+ // Add LIB or INCLUDE
+ if (!this->EnvironmentPath.empty()) {
+ paths.AddEnvPath(this->EnvironmentPath);
+#if defined(_WIN32) || defined(__CYGWIN__)
+ paths.AddEnvPrefixPath("PATH", true);
+ paths.AddEnvPath("PATH");
+#endif
+ } else {
+ // Add PATH
+ paths.AddEnvPath("PATH");
+ }
+ paths.AddSuffixes(this->SearchPathSuffixes);
+}
+
+void cmFindBase::FillCMakeSystemVariablePath()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::CMakeSystem];
+
+ std::string var = "CMAKE_SYSTEM_";
+ var += this->CMakePathName;
+ var += "_PATH";
+ paths.AddCMakePrefixPath("CMAKE_SYSTEM_PREFIX_PATH");
+ paths.AddCMakePath(var);
+
+ if (this->CMakePathName == "PROGRAM") {
+ paths.AddCMakePath("CMAKE_SYSTEM_APPBUNDLE_PATH");
+ } else {
+ paths.AddCMakePath("CMAKE_SYSTEM_FRAMEWORK_PATH");
+ }
+ paths.AddSuffixes(this->SearchPathSuffixes);
+}
+
+void cmFindBase::FillUserHintsPath()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::Hints];
+
+ for (std::vector<std::string>::const_iterator p =
+ this->UserHintsArgs.begin();
+ p != this->UserHintsArgs.end(); ++p) {
+ paths.AddUserPath(*p);
+ }
+ paths.AddSuffixes(this->SearchPathSuffixes);
+}
+
+void cmFindBase::FillUserGuessPath()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::Guess];
+
+ for (std::vector<std::string>::const_iterator p =
+ this->UserGuessArgs.begin();
+ p != this->UserGuessArgs.end(); ++p) {
+ paths.AddUserPath(*p);
+ }
+ paths.AddSuffixes(this->SearchPathSuffixes);
+}
+
+void cmFindBase::PrintFindStuff()
+{
+ std::cerr << "SearchFrameworkLast: " << this->SearchFrameworkLast << "\n";
+ std::cerr << "SearchFrameworkOnly: " << this->SearchFrameworkOnly << "\n";
+ std::cerr << "SearchFrameworkFirst: " << this->SearchFrameworkFirst << "\n";
+ std::cerr << "SearchAppBundleLast: " << this->SearchAppBundleLast << "\n";
+ std::cerr << "SearchAppBundleOnly: " << this->SearchAppBundleOnly << "\n";
+ std::cerr << "SearchAppBundleFirst: " << this->SearchAppBundleFirst << "\n";
+ std::cerr << "VariableName " << this->VariableName << "\n";
+ std::cerr << "VariableDocumentation " << this->VariableDocumentation << "\n";
+ std::cerr << "NoDefaultPath " << this->NoDefaultPath << "\n";
+ std::cerr << "NoCMakeEnvironmentPath " << this->NoCMakeEnvironmentPath
+ << "\n";
+ std::cerr << "NoCMakePath " << this->NoCMakePath << "\n";
+ std::cerr << "NoSystemEnvironmentPath " << this->NoSystemEnvironmentPath
+ << "\n";
+ std::cerr << "NoCMakeSystemPath " << this->NoCMakeSystemPath << "\n";
+ std::cerr << "EnvironmentPath " << this->EnvironmentPath << "\n";
+ std::cerr << "CMakePathName " << this->CMakePathName << "\n";
+ std::cerr << "Names " << cmJoin(this->Names, " ") << "\n";
+ std::cerr << "\n";
+ std::cerr << "SearchPathSuffixes ";
+ std::cerr << cmJoin(this->SearchPathSuffixes, "\n") << "\n";
+ std::cerr << "SearchPaths\n";
+ std::cerr << cmWrap("[", this->SearchPaths, "]", "\n") << "\n";
+}
+
+bool cmFindBase::CheckForVariableInCache()
+{
+ if (const char* cacheValue =
+ this->Makefile->GetDefinition(this->VariableName)) {
+ cmState* state = this->Makefile->GetState();
+ const char* cacheEntry = state->GetCacheEntryValue(this->VariableName);
+ bool found = !cmSystemTools::IsNOTFOUND(cacheValue);
+ bool cached = cacheEntry ? true : false;
+ if (found) {
+ // If the user specifies the entry on the command line without a
+ // type we should add the type and docstring but keep the
+ // original value. Tell the subclass implementations to do
+ // this.
+ if (cached &&
+ state->GetCacheEntryType(this->VariableName) ==
+ cmState::UNINITIALIZED) {
+ this->AlreadyInCacheWithoutMetaInfo = true;
+ }
+ return true;
+ } else if (cached) {
+ const char* hs =
+ state->GetCacheEntryProperty(this->VariableName, "HELPSTRING");
+ this->VariableDocumentation = hs ? hs : "(none)";
+ }
+ }
+ return false;
+}
diff --git a/Source/cmFindBase.h b/Source/cmFindBase.h
new file mode 100644
index 0000000..054c33b
--- /dev/null
+++ b/Source/cmFindBase.h
@@ -0,0 +1,66 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFindBase_h
+#define cmFindBase_h
+
+#include "cmFindCommon.h"
+
+/** \class cmFindBase
+ * \brief Base class for most FIND_XXX commands.
+ *
+ * cmFindBase is a parent class for cmFindProgramCommand, cmFindPathCommand,
+ * and cmFindLibraryCommand, cmFindFileCommand
+ */
+class cmFindBase : public cmFindCommon
+{
+public:
+ cmFindBase();
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ virtual bool ParseArguments(std::vector<std::string> const& args);
+ cmTypeMacro(cmFindBase, cmFindCommon);
+
+protected:
+ void PrintFindStuff();
+ void ExpandPaths();
+
+ // see if the VariableName is already set in the cache,
+ // also copy the documentation from the cache to VariableDocumentation
+ // if it has documentation in the cache
+ bool CheckForVariableInCache();
+
+ // use by command during find
+ std::string VariableDocumentation;
+ std::string VariableName;
+ std::vector<std::string> Names;
+ bool NamesPerDir;
+ bool NamesPerDirAllowed;
+
+ // CMAKE_*_PATH CMAKE_SYSTEM_*_PATH FRAMEWORK|LIBRARY|INCLUDE|PROGRAM
+ std::string EnvironmentPath; // LIB,INCLUDE
+
+ bool AlreadyInCache;
+ bool AlreadyInCacheWithoutMetaInfo;
+
+private:
+ // Add pieces of the search.
+ void FillCMakeVariablePath();
+ void FillCMakeEnvironmentPath();
+ void FillUserHintsPath();
+ void FillSystemEnvironmentPath();
+ void FillCMakeSystemVariablePath();
+ void FillUserGuessPath();
+};
+
+#endif
diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx
new file mode 100644
index 0000000..d255ceb
--- /dev/null
+++ b/Source/cmFindCommon.cxx
@@ -0,0 +1,353 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmFindCommon.h"
+
+#include <algorithm>
+#include <functional>
+
+cmFindCommon::PathGroup cmFindCommon::PathGroup::All("ALL");
+cmFindCommon::PathLabel cmFindCommon::PathLabel::CMake("CMAKE");
+cmFindCommon::PathLabel cmFindCommon::PathLabel::CMakeEnvironment(
+ "CMAKE_ENVIRONMENT");
+cmFindCommon::PathLabel cmFindCommon::PathLabel::Hints("HINTS");
+cmFindCommon::PathLabel cmFindCommon::PathLabel::SystemEnvironment(
+ "SYSTM_ENVIRONMENT");
+cmFindCommon::PathLabel cmFindCommon::PathLabel::CMakeSystem("CMAKE_SYSTEM");
+cmFindCommon::PathLabel cmFindCommon::PathLabel::Guess("GUESS");
+
+cmFindCommon::cmFindCommon()
+{
+ this->FindRootPathMode = RootPathModeBoth;
+ this->NoDefaultPath = false;
+ this->NoCMakePath = false;
+ this->NoCMakeEnvironmentPath = false;
+ this->NoSystemEnvironmentPath = false;
+ this->NoCMakeSystemPath = false;
+
+// OS X Bundle and Framework search policy. The default is to
+// search frameworks first on apple.
+#if defined(__APPLE__)
+ this->SearchFrameworkFirst = true;
+ this->SearchAppBundleFirst = true;
+#else
+ this->SearchFrameworkFirst = false;
+ this->SearchAppBundleFirst = false;
+#endif
+ this->SearchFrameworkOnly = false;
+ this->SearchFrameworkLast = false;
+ this->SearchAppBundleOnly = false;
+ this->SearchAppBundleLast = false;
+
+ this->InitializeSearchPathGroups();
+}
+
+cmFindCommon::~cmFindCommon()
+{
+}
+
+void cmFindCommon::InitializeSearchPathGroups()
+{
+ std::vector<PathLabel>* labels;
+
+ // Define the varoius different groups of path types
+
+ // All search paths
+ labels = &this->PathGroupLabelMap[PathGroup::All];
+ labels->push_back(PathLabel::CMake);
+ labels->push_back(PathLabel::CMakeEnvironment);
+ labels->push_back(PathLabel::Hints);
+ labels->push_back(PathLabel::SystemEnvironment);
+ labels->push_back(PathLabel::CMakeSystem);
+ labels->push_back(PathLabel::Guess);
+
+ // Define the search group order
+ this->PathGroupOrder.push_back(PathGroup::All);
+
+ // Create the idividual labeld search paths
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::CMake, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::CMakeEnvironment, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::Hints, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::SystemEnvironment, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::CMakeSystem, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::Guess, cmSearchPath(this)));
+}
+
+void cmFindCommon::SelectDefaultRootPathMode()
+{
+ // Check the policy variable for this find command type.
+ std::string findRootPathVar = "CMAKE_FIND_ROOT_PATH_MODE_";
+ findRootPathVar += this->CMakePathName;
+ std::string rootPathMode =
+ this->Makefile->GetSafeDefinition(findRootPathVar);
+ if (rootPathMode == "NEVER") {
+ this->FindRootPathMode = RootPathModeNever;
+ } else if (rootPathMode == "ONLY") {
+ this->FindRootPathMode = RootPathModeOnly;
+ } else if (rootPathMode == "BOTH") {
+ this->FindRootPathMode = RootPathModeBoth;
+ }
+}
+
+void cmFindCommon::SelectDefaultMacMode()
+{
+ std::string ff = this->Makefile->GetSafeDefinition("CMAKE_FIND_FRAMEWORK");
+ if (ff == "NEVER") {
+ this->SearchFrameworkLast = false;
+ this->SearchFrameworkFirst = false;
+ this->SearchFrameworkOnly = false;
+ } else if (ff == "ONLY") {
+ this->SearchFrameworkLast = false;
+ this->SearchFrameworkFirst = false;
+ this->SearchFrameworkOnly = true;
+ } else if (ff == "FIRST") {
+ this->SearchFrameworkLast = false;
+ this->SearchFrameworkFirst = true;
+ this->SearchFrameworkOnly = false;
+ } else if (ff == "LAST") {
+ this->SearchFrameworkLast = true;
+ this->SearchFrameworkFirst = false;
+ this->SearchFrameworkOnly = false;
+ }
+
+ std::string fab = this->Makefile->GetSafeDefinition("CMAKE_FIND_APPBUNDLE");
+ if (fab == "NEVER") {
+ this->SearchAppBundleLast = false;
+ this->SearchAppBundleFirst = false;
+ this->SearchAppBundleOnly = false;
+ } else if (fab == "ONLY") {
+ this->SearchAppBundleLast = false;
+ this->SearchAppBundleFirst = false;
+ this->SearchAppBundleOnly = true;
+ } else if (fab == "FIRST") {
+ this->SearchAppBundleLast = false;
+ this->SearchAppBundleFirst = true;
+ this->SearchAppBundleOnly = false;
+ } else if (fab == "LAST") {
+ this->SearchAppBundleLast = true;
+ this->SearchAppBundleFirst = false;
+ this->SearchAppBundleOnly = false;
+ }
+}
+
+void cmFindCommon::RerootPaths(std::vector<std::string>& paths)
+{
+#if 0
+ for(std::vector<std::string>::const_iterator i = paths.begin();
+ i != paths.end(); ++i)
+ {
+ fprintf(stderr, "[%s]\n", i->c_str());
+ }
+#endif
+ // Short-circuit if there is nothing to do.
+ if (this->FindRootPathMode == RootPathModeNever) {
+ return;
+ }
+
+ const char* sysroot = this->Makefile->GetDefinition("CMAKE_SYSROOT");
+ const char* rootPath = this->Makefile->GetDefinition("CMAKE_FIND_ROOT_PATH");
+ const bool noSysroot = !sysroot || !*sysroot;
+ const bool noRootPath = !rootPath || !*rootPath;
+ if (noSysroot && noRootPath) {
+ return;
+ }
+
+ // Construct the list of path roots with no trailing slashes.
+ std::vector<std::string> roots;
+ if (rootPath) {
+ cmSystemTools::ExpandListArgument(rootPath, roots);
+ }
+ if (sysroot) {
+ roots.push_back(sysroot);
+ }
+ for (std::vector<std::string>::iterator ri = roots.begin();
+ ri != roots.end(); ++ri) {
+ cmSystemTools::ConvertToUnixSlashes(*ri);
+ }
+
+ const char* stagePrefix =
+ this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
+
+ // Copy the original set of unrooted paths.
+ std::vector<std::string> unrootedPaths = paths;
+ paths.clear();
+
+ for (std::vector<std::string>::const_iterator ri = roots.begin();
+ ri != roots.end(); ++ri) {
+ for (std::vector<std::string>::const_iterator ui = unrootedPaths.begin();
+ ui != unrootedPaths.end(); ++ui) {
+ // Place the unrooted path under the current root if it is not
+ // already inside. Skip the unrooted path if it is relative to
+ // a user home directory or is empty.
+ std::string rootedDir;
+ if (cmSystemTools::IsSubDirectory(*ui, *ri) ||
+ (stagePrefix && cmSystemTools::IsSubDirectory(*ui, stagePrefix))) {
+ rootedDir = *ui;
+ } else if (!ui->empty() && (*ui)[0] != '~') {
+ // Start with the new root.
+ rootedDir = *ri;
+ rootedDir += "/";
+
+ // Append the original path with its old root removed.
+ rootedDir += cmSystemTools::SplitPathRootComponent(*ui);
+ }
+
+ // Store the new path.
+ paths.push_back(rootedDir);
+ }
+ }
+
+ // If searching both rooted and unrooted paths add the original
+ // paths again.
+ if (this->FindRootPathMode == RootPathModeBoth) {
+ paths.insert(paths.end(), unrootedPaths.begin(), unrootedPaths.end());
+ }
+}
+
+void cmFindCommon::FilterPaths(const std::vector<std::string>& inPaths,
+ const std::set<std::string>& ignore,
+ std::vector<std::string>& outPaths)
+{
+ for (std::vector<std::string>::const_iterator i = inPaths.begin();
+ i != inPaths.end(); ++i) {
+ if (ignore.count(*i) == 0) {
+ outPaths.push_back(*i);
+ }
+ }
+}
+
+void cmFindCommon::GetIgnoredPaths(std::vector<std::string>& ignore)
+{
+ // null-terminated list of paths.
+ static const char* paths[] = { "CMAKE_SYSTEM_IGNORE_PATH",
+ "CMAKE_IGNORE_PATH", CM_NULLPTR };
+
+ // Construct the list of path roots with no trailing slashes.
+ for (const char** pathName = paths; *pathName; ++pathName) {
+ // Get the list of paths to ignore from the variable.
+ const char* ignorePath = this->Makefile->GetDefinition(*pathName);
+ if ((ignorePath == CM_NULLPTR) || (strlen(ignorePath) == 0)) {
+ continue;
+ }
+
+ cmSystemTools::ExpandListArgument(ignorePath, ignore);
+ }
+
+ for (std::vector<std::string>::iterator i = ignore.begin();
+ i != ignore.end(); ++i) {
+ cmSystemTools::ConvertToUnixSlashes(*i);
+ }
+}
+
+void cmFindCommon::GetIgnoredPaths(std::set<std::string>& ignore)
+{
+ std::vector<std::string> ignoreVec;
+ GetIgnoredPaths(ignoreVec);
+ ignore.insert(ignoreVec.begin(), ignoreVec.end());
+}
+
+bool cmFindCommon::CheckCommonArgument(std::string const& arg)
+{
+ if (arg == "NO_DEFAULT_PATH") {
+ this->NoDefaultPath = true;
+ } else if (arg == "NO_CMAKE_ENVIRONMENT_PATH") {
+ this->NoCMakeEnvironmentPath = true;
+ } else if (arg == "NO_CMAKE_PATH") {
+ this->NoCMakePath = true;
+ } else if (arg == "NO_SYSTEM_ENVIRONMENT_PATH") {
+ this->NoSystemEnvironmentPath = true;
+ } else if (arg == "NO_CMAKE_SYSTEM_PATH") {
+ this->NoCMakeSystemPath = true;
+ } else if (arg == "NO_CMAKE_FIND_ROOT_PATH") {
+ this->FindRootPathMode = RootPathModeNever;
+ } else if (arg == "ONLY_CMAKE_FIND_ROOT_PATH") {
+ this->FindRootPathMode = RootPathModeOnly;
+ } else if (arg == "CMAKE_FIND_ROOT_PATH_BOTH") {
+ this->FindRootPathMode = RootPathModeBoth;
+ } else {
+ // The argument is not one of the above.
+ return false;
+ }
+
+ // The argument is one of the above.
+ return true;
+}
+
+void cmFindCommon::AddPathSuffix(std::string const& arg)
+{
+ std::string suffix = arg;
+
+ // Strip leading and trailing slashes.
+ if (suffix.empty()) {
+ return;
+ }
+ if (suffix[0] == '/') {
+ suffix = suffix.substr(1, suffix.npos);
+ }
+ if (suffix.empty()) {
+ return;
+ }
+ if (suffix[suffix.size() - 1] == '/') {
+ suffix = suffix.substr(0, suffix.size() - 1);
+ }
+ if (suffix.empty()) {
+ return;
+ }
+
+ // Store the suffix.
+ this->SearchPathSuffixes.push_back(suffix);
+}
+
+void AddTrailingSlash(std::string& s)
+{
+ if (!s.empty() && *s.rbegin() != '/') {
+ s += '/';
+ }
+}
+void cmFindCommon::ComputeFinalPaths()
+{
+ // Filter out ignored paths from the prefix list
+ std::set<std::string> ignored;
+ this->GetIgnoredPaths(ignored);
+
+ // Combine the seperate path types, filtering out ignores
+ this->SearchPaths.clear();
+ std::vector<PathLabel>& allLabels = this->PathGroupLabelMap[PathGroup::All];
+ for (std::vector<PathLabel>::const_iterator l = allLabels.begin();
+ l != allLabels.end(); ++l) {
+ this->LabeledPaths[*l].ExtractWithout(ignored, this->SearchPaths);
+ }
+
+ // Expand list of paths inside all search roots.
+ this->RerootPaths(this->SearchPaths);
+
+ // Add a trailing slash to all paths to aid the search process.
+ std::for_each(this->SearchPaths.begin(), this->SearchPaths.end(),
+ &AddTrailingSlash);
+}
+
+void cmFindCommon::SetMakefile(cmMakefile* makefile)
+{
+ cmCommand::SetMakefile(makefile);
+
+ // If we are building for Apple (OSX or also iphone), make sure
+ // that frameworks and bundles are searched first.
+ if (this->Makefile->IsOn("APPLE")) {
+ this->SearchFrameworkFirst = true;
+ this->SearchAppBundleFirst = true;
+ }
+}
diff --git a/Source/cmFindCommon.h b/Source/cmFindCommon.h
new file mode 100644
index 0000000..0f8d826
--- /dev/null
+++ b/Source/cmFindCommon.h
@@ -0,0 +1,136 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFindCommon_h
+#define cmFindCommon_h
+
+#include "cmCommand.h"
+#include "cmPathLabel.h"
+#include "cmSearchPath.h"
+
+/** \class cmFindCommon
+ * \brief Base class for FIND_XXX implementations.
+ *
+ * cmFindCommon is a parent class for cmFindBase,
+ * cmFindProgramCommand, cmFindPathCommand, cmFindLibraryCommand,
+ * cmFindFileCommand, and cmFindPackageCommand.
+ */
+class cmFindCommon : public cmCommand
+{
+public:
+ cmFindCommon();
+ ~cmFindCommon() CM_OVERRIDE;
+ cmTypeMacro(cmFindCommon, cmCommand);
+
+protected:
+ friend class cmSearchPath;
+
+ /** Used to define groups of path labels */
+ class PathGroup : public cmPathLabel
+ {
+ protected:
+ PathGroup();
+
+ public:
+ PathGroup(const std::string& label)
+ : cmPathLabel(label)
+ {
+ }
+ static PathGroup All;
+ };
+
+ /* Individual path types */
+ class PathLabel : public cmPathLabel
+ {
+ protected:
+ PathLabel();
+
+ public:
+ PathLabel(const std::string& label)
+ : cmPathLabel(label)
+ {
+ }
+ static PathLabel CMake;
+ static PathLabel CMakeEnvironment;
+ static PathLabel Hints;
+ static PathLabel SystemEnvironment;
+ static PathLabel CMakeSystem;
+ static PathLabel Guess;
+ };
+
+ enum RootPathMode
+ {
+ RootPathModeNever,
+ RootPathModeOnly,
+ RootPathModeBoth
+ };
+
+ /** Construct the various path groups and labels */
+ void InitializeSearchPathGroups();
+
+ /** Place a set of search paths under the search roots. */
+ void RerootPaths(std::vector<std::string>& paths);
+
+ /** Get ignored paths from CMAKE_[SYSTEM_]IGNORE_path variables. */
+ void GetIgnoredPaths(std::vector<std::string>& ignore);
+ void GetIgnoredPaths(std::set<std::string>& ignore);
+
+ /** Remove paths in the ignore set from the supplied vector. */
+ void FilterPaths(const std::vector<std::string>& inPaths,
+ const std::set<std::string>& ignore,
+ std::vector<std::string>& outPaths);
+
+ /** Compute final search path list (reroot + trailing slash). */
+ void ComputeFinalPaths();
+
+ /** Compute the current default root path mode. */
+ void SelectDefaultRootPathMode();
+
+ /** Compute the current default bundle/framework search policy. */
+ void SelectDefaultMacMode();
+
+ // Path arguments prior to path manipulation routines
+ std::vector<std::string> UserHintsArgs;
+ std::vector<std::string> UserGuessArgs;
+
+ std::string CMakePathName;
+ RootPathMode FindRootPathMode;
+
+ bool CheckCommonArgument(std::string const& arg);
+ void AddPathSuffix(std::string const& arg);
+ void SetMakefile(cmMakefile* makefile);
+
+ bool NoDefaultPath;
+ bool NoCMakePath;
+ bool NoCMakeEnvironmentPath;
+ bool NoSystemEnvironmentPath;
+ bool NoCMakeSystemPath;
+
+ std::vector<std::string> SearchPathSuffixes;
+
+ std::map<PathGroup, std::vector<PathLabel> > PathGroupLabelMap;
+ std::vector<PathGroup> PathGroupOrder;
+ std::map<std::string, PathLabel> PathLabelStringMap;
+ std::map<PathLabel, cmSearchPath> LabeledPaths;
+
+ std::vector<std::string> SearchPaths;
+ std::set<std::string> SearchPathsEmitted;
+
+ bool SearchFrameworkFirst;
+ bool SearchFrameworkOnly;
+ bool SearchFrameworkLast;
+
+ bool SearchAppBundleFirst;
+ bool SearchAppBundleOnly;
+ bool SearchAppBundleLast;
+};
+
+#endif
diff --git a/Source/cmFindFileCommand.cxx b/Source/cmFindFileCommand.cxx
new file mode 100644
index 0000000..a6666ba
--- /dev/null
+++ b/Source/cmFindFileCommand.cxx
@@ -0,0 +1,19 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmFindFileCommand.h"
+
+#include "cmSystemTools.h"
+
+cmFindFileCommand::cmFindFileCommand()
+{
+ this->IncludeFileInPath = true;
+}
diff --git a/Source/cmFindFileCommand.h b/Source/cmFindFileCommand.h
new file mode 100644
index 0000000..68bd5b9
--- /dev/null
+++ b/Source/cmFindFileCommand.h
@@ -0,0 +1,38 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFindFileCommand_h
+#define cmFindFileCommand_h
+
+#include "cmFindPathCommand.h"
+
+/** \class cmFindFileCommand
+ * \brief Define a command to search for an executable program.
+ *
+ * cmFindFileCommand is used to define a CMake variable
+ * that specifies an executable program. The command searches
+ * in the current path (e.g., PATH environment variable) for
+ * an executable that matches one of the supplied names.
+ */
+class cmFindFileCommand : public cmFindPathCommand
+{
+public:
+ cmFindFileCommand();
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmFindFileCommand; }
+ std::string GetName() const CM_OVERRIDE { return "find_file"; }
+
+ cmTypeMacro(cmFindFileCommand, cmFindPathCommand);
+};
+
+#endif
diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx
new file mode 100644
index 0000000..3094fcf
--- /dev/null
+++ b/Source/cmFindLibraryCommand.cxx
@@ -0,0 +1,477 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmFindLibraryCommand.h"
+
+#include <cmsys/Directory.hxx>
+
+cmFindLibraryCommand::cmFindLibraryCommand()
+{
+ this->EnvironmentPath = "LIB";
+ this->NamesPerDirAllowed = true;
+}
+
+// cmFindLibraryCommand
+bool cmFindLibraryCommand::InitialPass(std::vector<std::string> const& argsIn,
+ cmExecutionStatus&)
+{
+ this->VariableDocumentation = "Path to a library.";
+ this->CMakePathName = "LIBRARY";
+ if (!this->ParseArguments(argsIn)) {
+ return false;
+ }
+ if (this->AlreadyInCache) {
+ // If the user specifies the entry on the command line without a
+ // type we should add the type and docstring but keep the original
+ // value.
+ if (this->AlreadyInCacheWithoutMetaInfo) {
+ this->Makefile->AddCacheDefinition(this->VariableName, "",
+ this->VariableDocumentation.c_str(),
+ cmState::FILEPATH);
+ }
+ return true;
+ }
+
+ if (this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_LIB32_PATHS")) {
+ // add special 32 bit paths if this is a 32 bit compile.
+ if (this->Makefile->PlatformIs32Bit()) {
+ this->AddArchitecturePaths("32");
+ }
+ }
+
+ if (this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_LIB64_PATHS")) {
+ // add special 64 bit paths if this is a 64 bit compile.
+ if (this->Makefile->PlatformIs64Bit()) {
+ this->AddArchitecturePaths("64");
+ }
+ }
+
+ std::string library = this->FindLibrary();
+ if (library != "") {
+ // Save the value in the cache
+ this->Makefile->AddCacheDefinition(this->VariableName, library.c_str(),
+ this->VariableDocumentation.c_str(),
+ cmState::FILEPATH);
+ return true;
+ }
+ std::string notfound = this->VariableName + "-NOTFOUND";
+ this->Makefile->AddCacheDefinition(this->VariableName, notfound.c_str(),
+ this->VariableDocumentation.c_str(),
+ cmState::FILEPATH);
+ return true;
+}
+
+void cmFindLibraryCommand::AddArchitecturePaths(const char* suffix)
+{
+ std::vector<std::string> original;
+ original.swap(this->SearchPaths);
+ for (std::vector<std::string>::const_iterator i = original.begin();
+ i != original.end(); ++i) {
+ this->AddArchitecturePath(*i, 0, suffix);
+ }
+}
+
+void cmFindLibraryCommand::AddArchitecturePath(
+ std::string const& dir, std::string::size_type start_pos, const char* suffix,
+ bool fresh)
+{
+ std::string::size_type pos = dir.find("lib/", start_pos);
+ if (pos != std::string::npos) {
+ std::string cur_dir = dir.substr(0, pos + 3);
+
+ // Follow "lib<suffix>".
+ std::string next_dir = cur_dir + suffix;
+ if (cmSystemTools::FileIsDirectory(next_dir)) {
+ next_dir += dir.substr(pos + 3);
+ std::string::size_type next_pos = pos + 3 + strlen(suffix) + 1;
+ this->AddArchitecturePath(next_dir, next_pos, suffix);
+ }
+
+ // Follow "lib".
+ if (cmSystemTools::FileIsDirectory(cur_dir)) {
+ this->AddArchitecturePath(dir, pos + 3 + 1, suffix, false);
+ }
+ }
+ if (fresh) {
+ // Check for <dir><suffix>/.
+ std::string cur_dir = dir + suffix + "/";
+ if (cmSystemTools::FileIsDirectory(cur_dir)) {
+ this->SearchPaths.push_back(cur_dir);
+ }
+
+ // Now add the original unchanged path
+ if (cmSystemTools::FileIsDirectory(dir)) {
+ this->SearchPaths.push_back(dir);
+ }
+ }
+}
+
+std::string cmFindLibraryCommand::FindLibrary()
+{
+ std::string library;
+ if (this->SearchFrameworkFirst || this->SearchFrameworkOnly) {
+ library = this->FindFrameworkLibrary();
+ }
+ if (library.empty() && !this->SearchFrameworkOnly) {
+ library = this->FindNormalLibrary();
+ }
+ if (library.empty() && this->SearchFrameworkLast) {
+ library = this->FindFrameworkLibrary();
+ }
+ return library;
+}
+
+struct cmFindLibraryHelper
+{
+ cmFindLibraryHelper(cmMakefile* mf);
+
+ // Context information.
+ cmMakefile* Makefile;
+ cmGlobalGenerator* GG;
+
+ // List of valid prefixes and suffixes.
+ std::vector<std::string> Prefixes;
+ std::vector<std::string> Suffixes;
+ std::string PrefixRegexStr;
+ std::string SuffixRegexStr;
+
+ // Keep track of the best library file found so far.
+ typedef std::vector<std::string>::size_type size_type;
+ std::string BestPath;
+
+ // Support for OpenBSD shared library naming: lib<name>.so.<major>.<minor>
+ bool OpenBSD;
+
+ // Current names under consideration.
+ struct Name
+ {
+ bool TryRaw;
+ std::string Raw;
+ cmsys::RegularExpression Regex;
+ Name()
+ : TryRaw(false)
+ {
+ }
+ };
+ std::vector<Name> Names;
+
+ // Current full path under consideration.
+ std::string TestPath;
+
+ void RegexFromLiteral(std::string& out, std::string const& in);
+ void RegexFromList(std::string& out, std::vector<std::string> const& in);
+ size_type GetPrefixIndex(std::string const& prefix)
+ {
+ return std::find(this->Prefixes.begin(), this->Prefixes.end(), prefix) -
+ this->Prefixes.begin();
+ }
+ size_type GetSuffixIndex(std::string const& suffix)
+ {
+ return std::find(this->Suffixes.begin(), this->Suffixes.end(), suffix) -
+ this->Suffixes.begin();
+ }
+ bool HasValidSuffix(std::string const& name);
+ void AddName(std::string const& name);
+ void SetName(std::string const& name);
+ bool CheckDirectory(std::string const& path);
+ bool CheckDirectoryForName(std::string const& path, Name& name);
+};
+
+cmFindLibraryHelper::cmFindLibraryHelper(cmMakefile* mf)
+ : Makefile(mf)
+{
+ this->GG = this->Makefile->GetGlobalGenerator();
+
+ // Collect the list of library name prefixes/suffixes to try.
+ const char* prefixes_list =
+ this->Makefile->GetRequiredDefinition("CMAKE_FIND_LIBRARY_PREFIXES");
+ const char* suffixes_list =
+ this->Makefile->GetRequiredDefinition("CMAKE_FIND_LIBRARY_SUFFIXES");
+ cmSystemTools::ExpandListArgument(prefixes_list, this->Prefixes, true);
+ cmSystemTools::ExpandListArgument(suffixes_list, this->Suffixes, true);
+ this->RegexFromList(this->PrefixRegexStr, this->Prefixes);
+ this->RegexFromList(this->SuffixRegexStr, this->Suffixes);
+
+ // Check whether to use OpenBSD-style library version comparisons.
+ this->OpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
+}
+
+void cmFindLibraryHelper::RegexFromLiteral(std::string& out,
+ std::string const& in)
+{
+ for (std::string::const_iterator ci = in.begin(); ci != in.end(); ++ci) {
+ char ch = *ci;
+ if (ch == '[' || ch == ']' || ch == '(' || ch == ')' || ch == '\\' ||
+ ch == '.' || ch == '*' || ch == '+' || ch == '?' || ch == '-' ||
+ ch == '^' || ch == '$') {
+ out += "\\";
+ }
+#if defined(_WIN32) || defined(__APPLE__)
+ out += tolower(ch);
+#else
+ out += ch;
+#endif
+ }
+}
+
+void cmFindLibraryHelper::RegexFromList(std::string& out,
+ std::vector<std::string> const& in)
+{
+ // Surround the list in parens so the '|' does not apply to anything
+ // else and the result can be checked after matching.
+ out += "(";
+ const char* sep = "";
+ for (std::vector<std::string>::const_iterator si = in.begin();
+ si != in.end(); ++si) {
+ // Separate from previous item.
+ out += sep;
+ sep = "|";
+
+ // Append this item.
+ this->RegexFromLiteral(out, *si);
+ }
+ out += ")";
+}
+
+bool cmFindLibraryHelper::HasValidSuffix(std::string const& name)
+{
+ for (std::vector<std::string>::const_iterator si = this->Suffixes.begin();
+ si != this->Suffixes.end(); ++si) {
+ std::string suffix = *si;
+ if (name.length() <= suffix.length()) {
+ continue;
+ }
+ // Check if the given name ends in a valid library suffix.
+ if (name.substr(name.size() - suffix.length()) == suffix) {
+ return true;
+ }
+ // Check if a valid library suffix is somewhere in the name,
+ // this may happen e.g. for versioned shared libraries: libfoo.so.2
+ suffix += ".";
+ if (name.find(suffix) != name.npos) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmFindLibraryHelper::AddName(std::string const& name)
+{
+ Name entry;
+
+ // Consider checking the raw name too.
+ entry.TryRaw = this->HasValidSuffix(name);
+ entry.Raw = name;
+
+ // Build a regular expression to match library names.
+ std::string regex = "^";
+ regex += this->PrefixRegexStr;
+ this->RegexFromLiteral(regex, name);
+ regex += this->SuffixRegexStr;
+ if (this->OpenBSD) {
+ regex += "(\\.[0-9]+\\.[0-9]+)?";
+ }
+ regex += "$";
+ entry.Regex.compile(regex.c_str());
+ this->Names.push_back(entry);
+}
+
+void cmFindLibraryHelper::SetName(std::string const& name)
+{
+ this->Names.clear();
+ this->AddName(name);
+}
+
+bool cmFindLibraryHelper::CheckDirectory(std::string const& path)
+{
+ for (std::vector<Name>::iterator i = this->Names.begin();
+ i != this->Names.end(); ++i) {
+ if (this->CheckDirectoryForName(path, *i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmFindLibraryHelper::CheckDirectoryForName(std::string const& path,
+ Name& name)
+{
+ // If the original library name provided by the user matches one of
+ // the suffixes, try it first. This allows users to search
+ // specifically for a static library on some platforms (on MS tools
+ // one cannot tell just from the library name whether it is a static
+ // library or an import library).
+ if (name.TryRaw) {
+ this->TestPath = path;
+ this->TestPath += name.Raw;
+ if (cmSystemTools::FileExists(this->TestPath.c_str(), true)) {
+ this->BestPath = cmSystemTools::CollapseFullPath(this->TestPath);
+ cmSystemTools::ConvertToUnixSlashes(this->BestPath);
+ return true;
+ }
+ }
+
+ // No library file has yet been found.
+ size_type bestPrefix = this->Prefixes.size();
+ size_type bestSuffix = this->Suffixes.size();
+ unsigned int bestMajor = 0;
+ unsigned int bestMinor = 0;
+
+ // Search for a file matching the library name regex.
+ std::string dir = path;
+ cmSystemTools::ConvertToUnixSlashes(dir);
+ std::set<std::string> const& files = this->GG->GetDirectoryContent(dir);
+ for (std::set<std::string>::const_iterator fi = files.begin();
+ fi != files.end(); ++fi) {
+ std::string const& origName = *fi;
+#if defined(_WIN32) || defined(__APPLE__)
+ std::string testName = cmSystemTools::LowerCase(origName);
+#else
+ std::string const& testName = origName;
+#endif
+ if (name.Regex.find(testName)) {
+ this->TestPath = path;
+ this->TestPath += origName;
+ if (!cmSystemTools::FileIsDirectory(this->TestPath)) {
+ // This is a matching file. Check if it is better than the
+ // best name found so far. Earlier prefixes are preferred,
+ // followed by earlier suffixes. For OpenBSD, shared library
+ // version extensions are compared.
+ size_type prefix = this->GetPrefixIndex(name.Regex.match(1));
+ size_type suffix = this->GetSuffixIndex(name.Regex.match(2));
+ unsigned int major = 0;
+ unsigned int minor = 0;
+ if (this->OpenBSD) {
+ sscanf(name.Regex.match(3).c_str(), ".%u.%u", &major, &minor);
+ }
+ if (this->BestPath.empty() || prefix < bestPrefix ||
+ (prefix == bestPrefix && suffix < bestSuffix) ||
+ (prefix == bestPrefix && suffix == bestSuffix &&
+ (major > bestMajor ||
+ (major == bestMajor && minor > bestMinor)))) {
+ this->BestPath = this->TestPath;
+ bestPrefix = prefix;
+ bestSuffix = suffix;
+ bestMajor = major;
+ bestMinor = minor;
+ }
+ }
+ }
+ }
+
+ // Use the best candidate found in this directory, if any.
+ return !this->BestPath.empty();
+}
+
+std::string cmFindLibraryCommand::FindNormalLibrary()
+{
+ if (this->NamesPerDir) {
+ return this->FindNormalLibraryNamesPerDir();
+ } else {
+ return this->FindNormalLibraryDirsPerName();
+ }
+}
+
+std::string cmFindLibraryCommand::FindNormalLibraryNamesPerDir()
+{
+ // Search for all names in each directory.
+ cmFindLibraryHelper helper(this->Makefile);
+ for (std::vector<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ helper.AddName(*ni);
+ }
+ // Search every directory.
+ for (std::vector<std::string>::const_iterator p = this->SearchPaths.begin();
+ p != this->SearchPaths.end(); ++p) {
+ if (helper.CheckDirectory(*p)) {
+ return helper.BestPath;
+ }
+ }
+ // Couldn't find the library.
+ return "";
+}
+
+std::string cmFindLibraryCommand::FindNormalLibraryDirsPerName()
+{
+ // Search the entire path for each name.
+ cmFindLibraryHelper helper(this->Makefile);
+ for (std::vector<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ // Switch to searching for this name.
+ helper.SetName(*ni);
+
+ // Search every directory.
+ for (std::vector<std::string>::const_iterator p =
+ this->SearchPaths.begin();
+ p != this->SearchPaths.end(); ++p) {
+ if (helper.CheckDirectory(*p)) {
+ return helper.BestPath;
+ }
+ }
+ }
+ // Couldn't find the library.
+ return "";
+}
+
+std::string cmFindLibraryCommand::FindFrameworkLibrary()
+{
+ if (this->NamesPerDir) {
+ return this->FindFrameworkLibraryNamesPerDir();
+ } else {
+ return this->FindFrameworkLibraryDirsPerName();
+ }
+}
+
+std::string cmFindLibraryCommand::FindFrameworkLibraryNamesPerDir()
+{
+ std::string fwPath;
+ // Search for all names in each search path.
+ for (std::vector<std::string>::const_iterator di = this->SearchPaths.begin();
+ di != this->SearchPaths.end(); ++di) {
+ for (std::vector<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ fwPath = *di;
+ fwPath += *ni;
+ fwPath += ".framework";
+ if (cmSystemTools::FileIsDirectory(fwPath)) {
+ return cmSystemTools::CollapseFullPath(fwPath);
+ }
+ }
+ }
+
+ // No framework found.
+ return "";
+}
+
+std::string cmFindLibraryCommand::FindFrameworkLibraryDirsPerName()
+{
+ std::string fwPath;
+ // Search for each name in all search paths.
+ for (std::vector<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ for (std::vector<std::string>::const_iterator di =
+ this->SearchPaths.begin();
+ di != this->SearchPaths.end(); ++di) {
+ fwPath = *di;
+ fwPath += *ni;
+ fwPath += ".framework";
+ if (cmSystemTools::FileIsDirectory(fwPath)) {
+ return cmSystemTools::CollapseFullPath(fwPath);
+ }
+ }
+ }
+
+ // No framework found.
+ return "";
+}
diff --git a/Source/cmFindLibraryCommand.h b/Source/cmFindLibraryCommand.h
new file mode 100644
index 0000000..813decd
--- /dev/null
+++ b/Source/cmFindLibraryCommand.h
@@ -0,0 +1,68 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFindLibraryCommand_h
+#define cmFindLibraryCommand_h
+
+#include "cmFindBase.h"
+
+/** \class cmFindLibraryCommand
+ * \brief Define a command to search for a library.
+ *
+ * cmFindLibraryCommand is used to define a CMake variable
+ * that specifies a library. The command searches for a given
+ * file in a list of directories.
+ */
+class cmFindLibraryCommand : public cmFindBase
+{
+public:
+ cmFindLibraryCommand();
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmFindLibraryCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "find_library"; }
+
+ cmTypeMacro(cmFindLibraryCommand, cmFindBase);
+
+protected:
+ void AddArchitecturePaths(const char* suffix);
+ void AddArchitecturePath(std::string const& dir,
+ std::string::size_type start_pos,
+ const char* suffix, bool fresh = true);
+ std::string FindLibrary();
+
+private:
+ std::string FindNormalLibrary();
+ std::string FindNormalLibraryNamesPerDir();
+ std::string FindNormalLibraryDirsPerName();
+ std::string FindFrameworkLibrary();
+ std::string FindFrameworkLibraryNamesPerDir();
+ std::string FindFrameworkLibraryDirsPerName();
+};
+
+#endif
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
new file mode 100644
index 0000000..d5fd75d
--- /dev/null
+++ b/Source/cmFindPackageCommand.cxx
@@ -0,0 +1,2065 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmFindPackageCommand.h"
+
+#include "cmAlgorithms.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/Encoding.hxx>
+#include <cmsys/RegularExpression.hxx>
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+#include "cmVariableWatch.h"
+#endif
+
+#if defined(__HAIKU__)
+#include <FindDirectory.h>
+#include <StorageDefs.h>
+#include <string.h>
+#endif
+
+cmFindPackageCommand::PathLabel cmFindPackageCommand::PathLabel::UserRegistry(
+ "PACKAGE_REGISTRY");
+cmFindPackageCommand::PathLabel cmFindPackageCommand::PathLabel::Builds(
+ "BUILDS");
+cmFindPackageCommand::PathLabel
+ cmFindPackageCommand::PathLabel::SystemRegistry("SYSTEM_PACKAGE_REGISTRY");
+
+cmFindPackageCommand::cmFindPackageCommand()
+{
+ this->CMakePathName = "PACKAGE";
+ this->Quiet = false;
+ this->Required = false;
+ this->NoUserRegistry = false;
+ this->NoSystemRegistry = false;
+ this->UseConfigFiles = true;
+ this->UseFindModules = true;
+ this->DebugMode = false;
+ this->UseLib32Paths = false;
+ this->UseLib64Paths = false;
+ this->PolicyScope = true;
+ this->VersionMajor = 0;
+ this->VersionMinor = 0;
+ this->VersionPatch = 0;
+ this->VersionTweak = 0;
+ this->VersionCount = 0;
+ this->VersionExact = false;
+ this->VersionFoundMajor = 0;
+ this->VersionFoundMinor = 0;
+ this->VersionFoundPatch = 0;
+ this->VersionFoundTweak = 0;
+ this->VersionFoundCount = 0;
+ this->RequiredCMakeVersion = 0;
+
+ this->AppendSearchPathGroups();
+}
+
+void cmFindPackageCommand::AppendSearchPathGroups()
+{
+ std::vector<cmFindCommon::PathLabel>* labels;
+
+ // Update the All group with new paths
+ labels = &this->PathGroupLabelMap[PathGroup::All];
+ labels->insert(
+ std::find(labels->begin(), labels->end(), PathLabel::CMakeSystem),
+ PathLabel::UserRegistry);
+ labels->insert(
+ std::find(labels->begin(), labels->end(), PathLabel::CMakeSystem),
+ PathLabel::Builds);
+ labels->insert(std::find(labels->begin(), labels->end(), PathLabel::Guess),
+ PathLabel::SystemRegistry);
+
+ // Create the new path objects
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::UserRegistry, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::Builds, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::SystemRegistry, cmSearchPath(this)));
+}
+
+bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Lookup required version of CMake.
+ if (const char* rv =
+ this->Makefile->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
+ unsigned int v[3] = { 0, 0, 0 };
+ sscanf(rv, "%u.%u.%u", &v[0], &v[1], &v[2]);
+ this->RequiredCMakeVersion = CMake_VERSION_ENCODE(v[0], v[1], v[2]);
+ }
+
+ // Check for debug mode.
+ this->DebugMode = this->Makefile->IsOn("CMAKE_FIND_DEBUG_MODE");
+
+ // Lookup target architecture, if any.
+ if (const char* arch =
+ this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) {
+ this->LibraryArchitecture = arch;
+ }
+
+ // Lookup whether lib32 paths should be used.
+ if (this->Makefile->PlatformIs32Bit() &&
+ this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_LIB32_PATHS")) {
+ this->UseLib32Paths = true;
+ }
+
+ // Lookup whether lib64 paths should be used.
+ if (this->Makefile->PlatformIs64Bit() &&
+ this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_LIB64_PATHS")) {
+ this->UseLib64Paths = true;
+ }
+
+ // Check if User Package Registry should be disabled
+ if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY")) {
+ this->NoUserRegistry = true;
+ }
+
+ // Check if System Package Registry should be disabled
+ if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY")) {
+ this->NoSystemRegistry = true;
+ }
+
+ // Find the current root path mode.
+ this->SelectDefaultRootPathMode();
+
+ // Find the current bundle/framework search policy.
+ this->SelectDefaultMacMode();
+
+ // Record options.
+ this->Name = args[0];
+ std::string components;
+ const char* components_sep = "";
+ std::set<std::string> requiredComponents;
+ std::set<std::string> optionalComponents;
+
+ // Always search directly in a generated path.
+ this->SearchPathSuffixes.push_back("");
+
+ // Parse the arguments.
+ enum Doing
+ {
+ DoingNone,
+ DoingComponents,
+ DoingOptionalComponents,
+ DoingNames,
+ DoingPaths,
+ DoingPathSuffixes,
+ DoingConfigs,
+ DoingHints
+ };
+ Doing doing = DoingNone;
+ cmsys::RegularExpression version("^[0-9.]+$");
+ bool haveVersion = false;
+ std::set<unsigned int> configArgs;
+ std::set<unsigned int> moduleArgs;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "QUIET") {
+ this->Quiet = true;
+ doing = DoingNone;
+ } else if (args[i] == "EXACT") {
+ this->VersionExact = true;
+ doing = DoingNone;
+ } else if (args[i] == "MODULE") {
+ moduleArgs.insert(i);
+ doing = DoingNone;
+ } else if (args[i] == "CONFIG") {
+ configArgs.insert(i);
+ doing = DoingNone;
+ } else if (args[i] == "NO_MODULE") {
+ configArgs.insert(i);
+ doing = DoingNone;
+ } else if (args[i] == "REQUIRED") {
+ this->Required = true;
+ doing = DoingComponents;
+ } else if (args[i] == "COMPONENTS") {
+ doing = DoingComponents;
+ } else if (args[i] == "OPTIONAL_COMPONENTS") {
+ doing = DoingOptionalComponents;
+ } else if (args[i] == "NAMES") {
+ configArgs.insert(i);
+ doing = DoingNames;
+ } else if (args[i] == "PATHS") {
+ configArgs.insert(i);
+ doing = DoingPaths;
+ } else if (args[i] == "HINTS") {
+ configArgs.insert(i);
+ doing = DoingHints;
+ } else if (args[i] == "PATH_SUFFIXES") {
+ configArgs.insert(i);
+ doing = DoingPathSuffixes;
+ } else if (args[i] == "CONFIGS") {
+ configArgs.insert(i);
+ doing = DoingConfigs;
+ } else if (args[i] == "NO_POLICY_SCOPE") {
+ this->PolicyScope = false;
+ doing = DoingNone;
+ } else if (args[i] == "NO_CMAKE_PACKAGE_REGISTRY") {
+ this->NoUserRegistry = true;
+ configArgs.insert(i);
+ doing = DoingNone;
+ } else if (args[i] == "NO_CMAKE_SYSTEM_PACKAGE_REGISTRY") {
+ this->NoSystemRegistry = true;
+ configArgs.insert(i);
+ doing = DoingNone;
+ } else if (args[i] == "NO_CMAKE_BUILDS_PATH") {
+ // Ignore legacy option.
+ configArgs.insert(i);
+ doing = DoingNone;
+ } else if (this->CheckCommonArgument(args[i])) {
+ configArgs.insert(i);
+ doing = DoingNone;
+ } else if ((doing == DoingComponents) ||
+ (doing == DoingOptionalComponents)) {
+ // Set a variable telling the find script whether this component
+ // is required.
+ const char* isRequired = "1";
+ if (doing == DoingOptionalComponents) {
+ isRequired = "0";
+ optionalComponents.insert(args[i]);
+ } else {
+ requiredComponents.insert(args[i]);
+ }
+
+ std::string req_var = this->Name + "_FIND_REQUIRED_" + args[i];
+ this->AddFindDefinition(req_var, isRequired);
+
+ // Append to the list of required components.
+ components += components_sep;
+ components += args[i];
+ components_sep = ";";
+ } else if (doing == DoingNames) {
+ this->Names.push_back(args[i]);
+ } else if (doing == DoingPaths) {
+ this->UserGuessArgs.push_back(args[i]);
+ } else if (doing == DoingHints) {
+ this->UserHintsArgs.push_back(args[i]);
+ } else if (doing == DoingPathSuffixes) {
+ this->AddPathSuffix(args[i]);
+ } else if (doing == DoingConfigs) {
+ if (args[i].find_first_of(":/\\") != args[i].npos ||
+ cmSystemTools::GetFilenameLastExtension(args[i]) != ".cmake") {
+ std::ostringstream e;
+ e << "given CONFIGS option followed by invalid file name \"" << args[i]
+ << "\". The names given must be file names without "
+ << "a path and with a \".cmake\" extension.";
+ this->SetError(e.str());
+ return false;
+ }
+ this->Configs.push_back(args[i]);
+ } else if (!haveVersion && version.find(args[i].c_str())) {
+ haveVersion = true;
+ this->Version = args[i];
+ } else {
+ std::ostringstream e;
+ e << "called with invalid argument \"" << args[i] << "\"";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ std::vector<std::string> doubledComponents;
+ std::set_intersection(requiredComponents.begin(), requiredComponents.end(),
+ optionalComponents.begin(), optionalComponents.end(),
+ std::back_inserter(doubledComponents));
+ if (!doubledComponents.empty()) {
+ std::ostringstream e;
+ e << "called with components that are both required and optional:\n";
+ e << cmWrap(" ", doubledComponents, "", "\n") << "\n";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Maybe choose one mode exclusively.
+ this->UseFindModules = configArgs.empty();
+ this->UseConfigFiles = moduleArgs.empty();
+ if (!this->UseFindModules && !this->UseConfigFiles) {
+ std::ostringstream e;
+ e << "given options exclusive to Module mode:\n";
+ for (std::set<unsigned int>::const_iterator si = moduleArgs.begin();
+ si != moduleArgs.end(); ++si) {
+ e << " " << args[*si] << "\n";
+ }
+ e << "and options exclusive to Config mode:\n";
+ for (std::set<unsigned int>::const_iterator si = configArgs.begin();
+ si != configArgs.end(); ++si) {
+ e << " " << args[*si] << "\n";
+ }
+ e << "The options are incompatible.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Ignore EXACT with no version.
+ if (this->Version.empty() && this->VersionExact) {
+ this->VersionExact = false;
+ this->Makefile->IssueMessage(
+ cmake::AUTHOR_WARNING, "Ignoring EXACT since no version is requested.");
+ }
+
+ if (this->Version.empty() || components.empty()) {
+ // Check whether we are recursing inside "Find<name>.cmake" within
+ // another find_package(<name>) call.
+ std::string mod = this->Name;
+ mod += "_FIND_MODULE";
+ if (this->Makefile->IsOn(mod)) {
+ if (this->Version.empty()) {
+ // Get version information from the outer call if necessary.
+ // Requested version string.
+ std::string ver = this->Name;
+ ver += "_FIND_VERSION";
+ this->Version = this->Makefile->GetSafeDefinition(ver);
+
+ // Whether an exact version is required.
+ std::string exact = this->Name;
+ exact += "_FIND_VERSION_EXACT";
+ this->VersionExact = this->Makefile->IsOn(exact);
+ }
+ if (components.empty()) {
+ std::string components_var = this->Name + "_FIND_COMPONENTS";
+ components = this->Makefile->GetSafeDefinition(components_var);
+ }
+ }
+ }
+
+ if (!this->Version.empty()) {
+ // Try to parse the version number and store the results that were
+ // successfully parsed.
+ unsigned int parsed_major;
+ unsigned int parsed_minor;
+ unsigned int parsed_patch;
+ unsigned int parsed_tweak;
+ this->VersionCount =
+ sscanf(this->Version.c_str(), "%u.%u.%u.%u", &parsed_major,
+ &parsed_minor, &parsed_patch, &parsed_tweak);
+ switch (this->VersionCount) {
+ case 4:
+ this->VersionTweak = parsed_tweak; // no break!
+ case 3:
+ this->VersionPatch = parsed_patch; // no break!
+ case 2:
+ this->VersionMinor = parsed_minor; // no break!
+ case 1:
+ this->VersionMajor = parsed_major; // no break!
+ default:
+ break;
+ }
+ }
+
+ std::string disableFindPackageVar = "CMAKE_DISABLE_FIND_PACKAGE_";
+ disableFindPackageVar += this->Name;
+ if (this->Makefile->IsOn(disableFindPackageVar)) {
+ if (this->Required) {
+ std::ostringstream e;
+ e << "for module " << this->Name << " called with REQUIRED, but "
+ << disableFindPackageVar
+ << " is enabled. A REQUIRED package cannot be disabled.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+ }
+
+ this->SetModuleVariables(components);
+
+ // See if there is a Find<package>.cmake module.
+ if (this->UseFindModules) {
+ bool foundModule = false;
+ if (!this->FindModule(foundModule)) {
+ this->AppendSuccessInformation();
+ return false;
+ }
+ if (foundModule) {
+ this->AppendSuccessInformation();
+ return 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(cmake::AUTHOR_WARNING, aw.str());
+ }
+
+ // No find module. Assume the project has a CMake config file. Use
+ // a <package>_DIR cache variable to locate it.
+ this->Variable = this->Name;
+ this->Variable += "_DIR";
+
+ // Add the default name.
+ if (this->Names.empty()) {
+ this->Names.push_back(this->Name);
+ }
+
+ // Add the default configs.
+ if (this->Configs.empty()) {
+ for (std::vector<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ std::string config = *ni;
+ config += "Config.cmake";
+ this->Configs.push_back(config);
+
+ config = cmSystemTools::LowerCase(*ni);
+ config += "-config.cmake";
+ this->Configs.push_back(config);
+ }
+ }
+
+ // get igonored paths from vars and reroot them.
+ std::vector<std::string> ignored;
+ this->GetIgnoredPaths(ignored);
+ this->RerootPaths(ignored);
+
+ // Construct a set of ignored paths
+ this->IgnoredPaths.clear();
+ this->IgnoredPaths.insert(ignored.begin(), ignored.end());
+
+ // Find and load the package.
+ bool result = this->HandlePackageMode();
+ this->AppendSuccessInformation();
+ return result;
+}
+
+void cmFindPackageCommand::SetModuleVariables(const std::string& components)
+{
+ this->AddFindDefinition("CMAKE_FIND_PACKAGE_NAME", this->Name.c_str());
+
+ // Store the list of components.
+ std::string components_var = this->Name + "_FIND_COMPONENTS";
+ this->AddFindDefinition(components_var, components.c_str());
+
+ if (this->Quiet) {
+ // Tell the module that is about to be read that it should find
+ // quietly.
+ std::string quietly = this->Name;
+ quietly += "_FIND_QUIETLY";
+ this->AddFindDefinition(quietly, "1");
+ }
+
+ if (this->Required) {
+ // Tell the module that is about to be read that it should report
+ // a fatal error if the package is not found.
+ std::string req = this->Name;
+ req += "_FIND_REQUIRED";
+ this->AddFindDefinition(req, "1");
+ }
+
+ if (!this->Version.empty()) {
+ // Tell the module that is about to be read what version of the
+ // package has been requested.
+ std::string ver = this->Name;
+ ver += "_FIND_VERSION";
+ this->AddFindDefinition(ver, this->Version.c_str());
+ char buf[64];
+ sprintf(buf, "%u", this->VersionMajor);
+ this->AddFindDefinition(ver + "_MAJOR", buf);
+ sprintf(buf, "%u", this->VersionMinor);
+ this->AddFindDefinition(ver + "_MINOR", buf);
+ sprintf(buf, "%u", this->VersionPatch);
+ this->AddFindDefinition(ver + "_PATCH", buf);
+ sprintf(buf, "%u", this->VersionTweak);
+ this->AddFindDefinition(ver + "_TWEAK", buf);
+ sprintf(buf, "%u", this->VersionCount);
+ this->AddFindDefinition(ver + "_COUNT", buf);
+
+ // Tell the module whether an exact version has been requested.
+ std::string exact = this->Name;
+ exact += "_FIND_VERSION_EXACT";
+ this->AddFindDefinition(exact, this->VersionExact ? "1" : "0");
+ }
+}
+
+void cmFindPackageCommand::AddFindDefinition(const std::string& var,
+ const char* val)
+{
+ if (const char* old = this->Makefile->GetDefinition(var)) {
+ this->OriginalDefs[var].exists = true;
+ this->OriginalDefs[var].value = old;
+ } else {
+ this->OriginalDefs[var].exists = false;
+ }
+ this->Makefile->AddDefinition(var, val);
+}
+
+void cmFindPackageCommand::RestoreFindDefinitions()
+{
+ for (std::map<std::string, OriginalDef>::iterator i =
+ this->OriginalDefs.begin();
+ i != this->OriginalDefs.end(); ++i) {
+ OriginalDef const& od = i->second;
+ if (od.exists) {
+ this->Makefile->AddDefinition(i->first, od.value.c_str());
+ } else {
+ this->Makefile->RemoveDefinition(i->first);
+ }
+ }
+}
+
+bool cmFindPackageCommand::FindModule(bool& found)
+{
+ std::string module = "Find";
+ module += this->Name;
+ module += ".cmake";
+ std::string mfile = this->Makefile->GetModulesFile(module.c_str());
+ if (!mfile.empty()) {
+ // Load the module we found, and set "<name>_FIND_MODULE" to true
+ // while inside it.
+ found = true;
+ std::string var = this->Name;
+ var += "_FIND_MODULE";
+ this->Makefile->AddDefinition(var, "1");
+ bool result = this->ReadListFile(mfile.c_str(), DoPolicyScope);
+ this->Makefile->RemoveDefinition(var);
+ return result;
+ }
+ return true;
+}
+
+bool cmFindPackageCommand::HandlePackageMode()
+{
+ this->ConsideredConfigs.clear();
+
+ // Support old capitalization behavior.
+ std::string upperDir = cmSystemTools::UpperCase(this->Name);
+ std::string upperFound = cmSystemTools::UpperCase(this->Name);
+ upperDir += "_DIR";
+ upperFound += "_FOUND";
+
+ // Try to find the config file.
+ const char* def = this->Makefile->GetDefinition(this->Variable);
+
+ // Try to load the config file if the directory is known
+ bool fileFound = false;
+ if (this->UseConfigFiles) {
+ if (!cmSystemTools::IsOff(def)) {
+ // Get the directory from the variable value.
+ std::string dir = def;
+ cmSystemTools::ConvertToUnixSlashes(dir);
+
+ // Treat relative paths with respect to the current source dir.
+ if (!cmSystemTools::FileIsFullPath(dir.c_str())) {
+ dir = "/" + dir;
+ dir = this->Makefile->GetCurrentSourceDirectory() + dir;
+ }
+ // The file location was cached. Look for the correct file.
+ std::string file;
+ if (this->FindConfigFile(dir, file)) {
+ this->FileFound = file;
+ fileFound = true;
+ }
+ def = this->Makefile->GetDefinition(this->Variable);
+ }
+
+ // Search for the config file if it is not already found.
+ if (cmSystemTools::IsOff(def) || !fileFound) {
+ fileFound = this->FindConfig();
+ }
+
+ // Sanity check.
+ if (fileFound && this->FileFound.empty()) {
+ this->Makefile->IssueMessage(
+ cmake::INTERNAL_ERROR, "fileFound is true but FileFound is empty!");
+ fileFound = false;
+ }
+ }
+
+ std::string foundVar = this->Name;
+ foundVar += "_FOUND";
+ std::string notFoundMessageVar = this->Name;
+ notFoundMessageVar += "_NOT_FOUND_MESSAGE";
+ std::string notFoundMessage;
+
+ // If the directory for the config file was found, try to read the file.
+ bool result = true;
+ bool found = false;
+ bool configFileSetFOUNDFalse = false;
+
+ if (fileFound) {
+ if ((this->Makefile->IsDefinitionSet(foundVar)) &&
+ (this->Makefile->IsOn(foundVar) == false)) {
+ // by removing Foo_FOUND here if it is FALSE, we don't really change
+ // the situation for the Config file which is about to be included,
+ // but we make it possible to detect later on whether the Config file
+ // has set Foo_FOUND to FALSE itself:
+ this->Makefile->RemoveDefinition(foundVar);
+ }
+ this->Makefile->RemoveDefinition(notFoundMessageVar);
+
+ // Set the version variables before loading the config file.
+ // It may override them.
+ this->StoreVersionFound();
+
+ // Parse the configuration file.
+ if (this->ReadListFile(this->FileFound.c_str(), DoPolicyScope)) {
+ // The package has been found.
+ found = true;
+
+ // Check whether the Config file has set Foo_FOUND to FALSE:
+ if ((this->Makefile->IsDefinitionSet(foundVar)) &&
+ (this->Makefile->IsOn(foundVar) == false)) {
+ // we get here if the Config file has set Foo_FOUND actively to FALSE
+ found = false;
+ configFileSetFOUNDFalse = true;
+ notFoundMessage =
+ this->Makefile->GetSafeDefinition(notFoundMessageVar);
+ }
+ } else {
+ // The configuration file is invalid.
+ result = false;
+ }
+ }
+
+ if (result && !found && (!this->Quiet || this->Required)) {
+ // The variable is not set.
+ std::ostringstream e;
+ std::ostringstream aw;
+ if (configFileSetFOUNDFalse) {
+ /* clang-format off */
+ e << "Found package configuration file:\n"
+ " " << this->FileFound << "\n"
+ "but it set " << foundVar << " to FALSE so package \"" <<
+ this->Name << "\" is considered to be NOT FOUND.";
+ /* clang-format on */
+ if (!notFoundMessage.empty()) {
+ e << " Reason given by package: \n" << notFoundMessage << "\n";
+ }
+ }
+ // If there are files in ConsideredConfigs, it means that FooConfig.cmake
+ // have been found, but they didn't have appropriate versions.
+ else if (!this->ConsideredConfigs.empty()) {
+ std::vector<ConfigFileInfo>::const_iterator duplicate_end =
+ cmRemoveDuplicates(this->ConsideredConfigs);
+ e << "Could not find a configuration file for package \"" << this->Name
+ << "\" that "
+ << (this->VersionExact ? "exactly matches" : "is compatible with")
+ << " 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";
+ }
+ } else {
+ std::string requestedVersionString;
+ if (!this->Version.empty()) {
+ requestedVersionString = " (requested version ";
+ requestedVersionString += this->Version;
+ requestedVersionString += ")";
+ }
+
+ if (this->UseConfigFiles) {
+ if (this->UseFindModules) {
+ e << "By not providing \"Find" << this->Name
+ << ".cmake\" in "
+ "CMAKE_MODULE_PATH this project has asked CMake to find a "
+ "package configuration file provided by \""
+ << this->Name << "\", "
+ "but CMake did not find one.\n";
+ }
+
+ if (this->Configs.size() == 1) {
+ e << "Could not find a package configuration file named \""
+ << this->Configs[0] << "\" provided by package \"" << this->Name
+ << "\"" << requestedVersionString << ".\n";
+ } else {
+ e << "Could not find a package configuration file provided by \""
+ << this->Name << "\"" << requestedVersionString
+ << " with any of the following names:\n"
+ << cmWrap(" ", this->Configs, "", "\n") << "\n";
+ }
+
+ e << "Add the installation prefix of \"" << this->Name
+ << "\" to "
+ "CMAKE_PREFIX_PATH or set \""
+ << this->Variable << "\" to a "
+ "directory containing one of the above files. "
+ "If \""
+ << this->Name << "\" provides a separate development "
+ "package or SDK, be sure it has been installed.";
+ } else // if(!this->UseFindModules && !this->UseConfigFiles)
+ {
+ e << "No \"Find" << this->Name << ".cmake\" found in "
+ << "CMAKE_MODULE_PATH.";
+
+ aw << "Find" << this->Name
+ << ".cmake must either be part of this "
+ "project itself, in this case adjust CMAKE_MODULE_PATH so that "
+ "it points to the correct location inside its source tree.\n"
+ "Or it must be installed by a package which has already been "
+ "found via find_package(). In this case make sure that "
+ "package has indeed been found and adjust CMAKE_MODULE_PATH to "
+ "contain the location where that package has installed "
+ "Find"
+ << this->Name
+ << ".cmake. This must be a location "
+ "provided by that package. This error in general means that "
+ "the buildsystem of this project is relying on a Find-module "
+ "without ensuring that it is actually available.\n";
+ }
+ }
+
+ this->Makefile->IssueMessage(
+ this->Required ? cmake::FATAL_ERROR : cmake::WARNING, e.str());
+ if (this->Required) {
+ cmSystemTools::SetFatalErrorOccured();
+ }
+
+ if (!aw.str().empty()) {
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, aw.str());
+ }
+ }
+
+ // Set a variable marking whether the package was found.
+ this->Makefile->AddDefinition(foundVar, found ? "1" : "0");
+
+ // Set a variable naming the configuration file that was found.
+ std::string fileVar = this->Name;
+ fileVar += "_CONFIG";
+ if (found) {
+ this->Makefile->AddDefinition(fileVar, this->FileFound.c_str());
+ } else {
+ this->Makefile->RemoveDefinition(fileVar);
+ }
+
+ std::string consideredConfigsVar = this->Name;
+ consideredConfigsVar += "_CONSIDERED_CONFIGS";
+ std::string consideredVersionsVar = this->Name;
+ consideredVersionsVar += "_CONSIDERED_VERSIONS";
+
+ std::string consideredConfigFiles;
+ std::string consideredVersions;
+
+ const char* sep = "";
+ for (std::vector<ConfigFileInfo>::const_iterator i =
+ this->ConsideredConfigs.begin();
+ i != this->ConsideredConfigs.end(); ++i) {
+ consideredConfigFiles += sep;
+ consideredVersions += sep;
+ consideredConfigFiles += i->filename;
+ consideredVersions += i->version;
+ sep = ";";
+ }
+
+ this->Makefile->AddDefinition(consideredConfigsVar,
+ consideredConfigFiles.c_str());
+
+ this->Makefile->AddDefinition(consideredVersionsVar,
+ consideredVersions.c_str());
+
+ return result;
+}
+
+bool cmFindPackageCommand::FindConfig()
+{
+ // Compute the set of search prefixes.
+ this->ComputePrefixes();
+
+ // Look for the project's configuration file.
+ bool found = false;
+
+ // Search for frameworks.
+ if (!found && (this->SearchFrameworkFirst || this->SearchFrameworkOnly)) {
+ found = this->FindFrameworkConfig();
+ }
+
+ // Search for apps.
+ if (!found && (this->SearchAppBundleFirst || this->SearchAppBundleOnly)) {
+ found = this->FindAppBundleConfig();
+ }
+
+ // Search prefixes.
+ if (!found && !(this->SearchFrameworkOnly || this->SearchAppBundleOnly)) {
+ found = this->FindPrefixedConfig();
+ }
+
+ // Search for frameworks.
+ if (!found && this->SearchFrameworkLast) {
+ found = this->FindFrameworkConfig();
+ }
+
+ // Search for apps.
+ if (!found && this->SearchAppBundleLast) {
+ found = this->FindAppBundleConfig();
+ }
+
+ // Store the entry in the cache so it can be set by the user.
+ std::string init;
+ if (found) {
+ init = cmSystemTools::GetFilenamePath(this->FileFound);
+ } else {
+ init = this->Variable + "-NOTFOUND";
+ }
+ std::string help =
+ "The directory containing a CMake configuration file for ";
+ help += this->Name;
+ help += ".";
+ // We force the value since we do not get here if it was already set.
+ this->Makefile->AddCacheDefinition(this->Variable, init.c_str(),
+ help.c_str(), cmState::PATH, true);
+ return found;
+}
+
+bool cmFindPackageCommand::FindPrefixedConfig()
+{
+ std::vector<std::string>& prefixes = this->SearchPaths;
+ for (std::vector<std::string>::const_iterator pi = prefixes.begin();
+ pi != prefixes.end(); ++pi) {
+ if (this->SearchPrefix(*pi)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmFindPackageCommand::FindFrameworkConfig()
+{
+ std::vector<std::string>& prefixes = this->SearchPaths;
+ for (std::vector<std::string>::const_iterator i = prefixes.begin();
+ i != prefixes.end(); ++i) {
+ if (this->SearchFrameworkPrefix(*i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmFindPackageCommand::FindAppBundleConfig()
+{
+ std::vector<std::string>& prefixes = this->SearchPaths;
+ for (std::vector<std::string>::const_iterator i = prefixes.begin();
+ i != prefixes.end(); ++i) {
+ if (this->SearchAppBundlePrefix(*i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmFindPackageCommand::ReadListFile(const char* f, PolicyScopeRule psr)
+{
+ const bool noPolicyScope = !this->PolicyScope || psr == NoPolicyScope;
+ if (this->Makefile->ReadDependentFile(f, noPolicyScope)) {
+ return true;
+ }
+ std::string e = "Error reading CMake code from \"";
+ e += f;
+ e += "\".";
+ this->SetError(e);
+ return false;
+}
+
+void cmFindPackageCommand::AppendToFoundProperty(bool found)
+{
+ std::vector<std::string> foundContents;
+ const char* foundProp =
+ this->Makefile->GetState()->GetGlobalProperty("PACKAGES_FOUND");
+ if (foundProp && *foundProp) {
+ std::string tmp = foundProp;
+
+ cmSystemTools::ExpandListArgument(tmp, foundContents, false);
+ std::vector<std::string>::iterator nameIt =
+ std::find(foundContents.begin(), foundContents.end(), this->Name);
+ if (nameIt != foundContents.end()) {
+ foundContents.erase(nameIt);
+ }
+ }
+
+ std::vector<std::string> notFoundContents;
+ const char* notFoundProp =
+ this->Makefile->GetState()->GetGlobalProperty("PACKAGES_NOT_FOUND");
+ if (notFoundProp && *notFoundProp) {
+ std::string tmp = notFoundProp;
+
+ cmSystemTools::ExpandListArgument(tmp, notFoundContents, false);
+ std::vector<std::string>::iterator nameIt =
+ std::find(notFoundContents.begin(), notFoundContents.end(), this->Name);
+ if (nameIt != notFoundContents.end()) {
+ notFoundContents.erase(nameIt);
+ }
+ }
+
+ if (found) {
+ foundContents.push_back(this->Name);
+ } else {
+ notFoundContents.push_back(this->Name);
+ }
+
+ std::string tmp = cmJoin(foundContents, ";");
+ this->Makefile->GetState()->SetGlobalProperty("PACKAGES_FOUND", tmp.c_str());
+
+ tmp = cmJoin(notFoundContents, ";");
+ this->Makefile->GetState()->SetGlobalProperty("PACKAGES_NOT_FOUND",
+ tmp.c_str());
+}
+
+void cmFindPackageCommand::AppendSuccessInformation()
+{
+ {
+ std::string transitivePropName = "_CMAKE_";
+ transitivePropName += this->Name + "_TRANSITIVE_DEPENDENCY";
+ this->Makefile->GetState()->SetGlobalProperty(transitivePropName, "False");
+ }
+ std::string found = this->Name;
+ found += "_FOUND";
+ std::string upperFound = cmSystemTools::UpperCase(found);
+
+ const char* upperResult = this->Makefile->GetDefinition(upperFound);
+ const char* result = this->Makefile->GetDefinition(found);
+ bool packageFound =
+ ((cmSystemTools::IsOn(result)) || (cmSystemTools::IsOn(upperResult)));
+
+ this->AppendToFoundProperty(packageFound);
+
+ // Record whether the find was quiet or not, so this can be used
+ // e.g. in FeatureSummary.cmake
+ std::string quietInfoPropName = "_CMAKE_";
+ quietInfoPropName += this->Name;
+ quietInfoPropName += "_QUIET";
+ this->Makefile->GetState()->SetGlobalProperty(
+ quietInfoPropName, this->Quiet ? "TRUE" : "FALSE");
+
+ // set a global property to record the required version of this package
+ std::string versionInfoPropName = "_CMAKE_";
+ versionInfoPropName += this->Name;
+ versionInfoPropName += "_REQUIRED_VERSION";
+ std::string versionInfo;
+ if (!this->Version.empty()) {
+ versionInfo = this->VersionExact ? "==" : ">=";
+ versionInfo += " ";
+ versionInfo += this->Version;
+ }
+ this->Makefile->GetState()->SetGlobalProperty(versionInfoPropName,
+ versionInfo.c_str());
+ if (this->Required) {
+ std::string requiredInfoPropName = "_CMAKE_";
+ requiredInfoPropName += this->Name;
+ requiredInfoPropName += "_TYPE";
+ this->Makefile->GetState()->SetGlobalProperty(requiredInfoPropName,
+ "REQUIRED");
+ }
+
+ // Restore original state of "_FIND_" variables we set.
+ this->RestoreFindDefinitions();
+}
+
+void cmFindPackageCommand::ComputePrefixes()
+{
+ if (!this->NoDefaultPath) {
+ if (!this->NoCMakePath) {
+ this->FillPrefixesCMakeVariable();
+ }
+ if (!this->NoCMakeEnvironmentPath) {
+ this->FillPrefixesCMakeEnvironment();
+ }
+ }
+ this->FillPrefixesUserHints();
+ if (!this->NoDefaultPath) {
+ if (!this->NoSystemEnvironmentPath) {
+ this->FillPrefixesSystemEnvironment();
+ }
+ if (!this->NoUserRegistry) {
+ this->FillPrefixesUserRegistry();
+ }
+ if (!this->NoCMakeSystemPath) {
+ this->FillPrefixesCMakeSystemVariable();
+ }
+ if (!this->NoSystemRegistry) {
+ this->FillPrefixesSystemRegistry();
+ }
+ }
+ this->FillPrefixesUserGuess();
+
+ this->ComputeFinalPaths();
+}
+
+void cmFindPackageCommand::FillPrefixesCMakeEnvironment()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::CMakeEnvironment];
+
+ // Check the environment variable with the same name as the cache
+ // entry.
+ paths.AddEnvPath(this->Variable);
+
+ // And now the general CMake environment variables
+ paths.AddEnvPath("CMAKE_PREFIX_PATH");
+ paths.AddEnvPath("CMAKE_FRAMEWORK_PATH");
+ paths.AddEnvPath("CMAKE_APPBUNDLE_PATH");
+}
+
+void cmFindPackageCommand::FillPrefixesCMakeVariable()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::CMake];
+
+ paths.AddCMakePath("CMAKE_PREFIX_PATH");
+ paths.AddCMakePath("CMAKE_FRAMEWORK_PATH");
+ paths.AddCMakePath("CMAKE_APPBUNDLE_PATH");
+}
+
+void cmFindPackageCommand::FillPrefixesSystemEnvironment()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::SystemEnvironment];
+
+ // Use the system search path to generate prefixes.
+ // Relative paths are interpreted with respect to the current
+ // working directory.
+ std::vector<std::string> tmp;
+ cmSystemTools::GetPath(tmp);
+ for (std::vector<std::string>::iterator i = tmp.begin(); i != tmp.end();
+ ++i) {
+ // If the path is a PREFIX/bin case then add its parent instead.
+ if ((cmHasLiteralSuffix(*i, "/bin")) ||
+ (cmHasLiteralSuffix(*i, "/sbin"))) {
+ paths.AddPath(cmSystemTools::GetFilenamePath(*i));
+ } else {
+ paths.AddPath(*i);
+ }
+ }
+}
+
+void cmFindPackageCommand::FillPrefixesUserRegistry()
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ this->LoadPackageRegistryWinUser();
+#elif defined(__HAIKU__)
+ char dir[B_PATH_NAME_LENGTH];
+ if (find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, dir, sizeof(dir)) ==
+ B_OK) {
+ std::string fname = dir;
+ fname += "/cmake/packages/";
+ fname += Name;
+ this->LoadPackageRegistryDir(fname,
+ this->LabeledPaths[PathLabel::UserRegistry]);
+ }
+#else
+ if (const char* home = cmSystemTools::GetEnv("HOME")) {
+ std::string dir = home;
+ dir += "/.cmake/packages/";
+ dir += this->Name;
+ this->LoadPackageRegistryDir(dir,
+ this->LabeledPaths[PathLabel::UserRegistry]);
+ }
+#endif
+}
+
+void cmFindPackageCommand::FillPrefixesSystemRegistry()
+{
+ if (this->NoSystemRegistry || this->NoDefaultPath) {
+ return;
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ this->LoadPackageRegistryWinSystem();
+#endif
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <windows.h>
+#undef GetCurrentDirectory
+// http://msdn.microsoft.com/en-us/library/aa384253%28v=vs.85%29.aspx
+#if !defined(KEY_WOW64_32KEY)
+#define KEY_WOW64_32KEY 0x0200
+#endif
+#if !defined(KEY_WOW64_64KEY)
+#define KEY_WOW64_64KEY 0x0100
+#endif
+void cmFindPackageCommand::LoadPackageRegistryWinUser()
+{
+ // HKEY_CURRENT_USER\\Software shares 32-bit and 64-bit views.
+ this->LoadPackageRegistryWin(true, 0,
+ this->LabeledPaths[PathLabel::UserRegistry]);
+}
+
+void cmFindPackageCommand::LoadPackageRegistryWinSystem()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::SystemRegistry];
+
+ // HKEY_LOCAL_MACHINE\\SOFTWARE has separate 32-bit and 64-bit views.
+ // Prefer the target platform view first.
+ if (this->Makefile->PlatformIs64Bit()) {
+ this->LoadPackageRegistryWin(false, KEY_WOW64_64KEY, paths);
+ this->LoadPackageRegistryWin(false, KEY_WOW64_32KEY, paths);
+ } else {
+ this->LoadPackageRegistryWin(false, KEY_WOW64_32KEY, paths);
+ this->LoadPackageRegistryWin(false, KEY_WOW64_64KEY, paths);
+ }
+}
+
+void cmFindPackageCommand::LoadPackageRegistryWin(bool user, unsigned int view,
+ cmSearchPath& outPaths)
+{
+ std::wstring key = L"Software\\Kitware\\CMake\\Packages\\";
+ key += cmsys::Encoding::ToWide(this->Name);
+ std::set<std::wstring> bad;
+ HKEY hKey;
+ if (RegOpenKeyExW(user ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, key.c_str(),
+ 0, KEY_QUERY_VALUE | view, &hKey) == ERROR_SUCCESS) {
+ DWORD valueType = REG_NONE;
+ wchar_t name[16383]; // RegEnumValue docs limit name to 32767 _bytes_
+ std::vector<wchar_t> data(512);
+ bool done = false;
+ DWORD index = 0;
+ while (!done) {
+ DWORD nameSize = static_cast<DWORD>(sizeof(name));
+ DWORD dataSize = static_cast<DWORD>(data.size() * sizeof(data[0]));
+ switch (RegEnumValueW(hKey, index, name, &nameSize, 0, &valueType,
+ (BYTE*)&data[0], &dataSize)) {
+ case ERROR_SUCCESS:
+ ++index;
+ if (valueType == REG_SZ) {
+ data[dataSize] = 0;
+ if (!this->CheckPackageRegistryEntry(
+ cmsys::Encoding::ToNarrow(&data[0]), outPaths)) {
+ // The entry is invalid.
+ bad.insert(name);
+ }
+ }
+ break;
+ case ERROR_MORE_DATA:
+ data.resize((dataSize + sizeof(data[0]) - 1) / sizeof(data[0]));
+ break;
+ case ERROR_NO_MORE_ITEMS:
+ default:
+ done = true;
+ break;
+ }
+ }
+ RegCloseKey(hKey);
+ }
+
+ // Remove bad values if possible.
+ if (user && !bad.empty() &&
+ RegOpenKeyExW(HKEY_CURRENT_USER, key.c_str(), 0, KEY_SET_VALUE | view,
+ &hKey) == ERROR_SUCCESS) {
+ for (std::set<std::wstring>::const_iterator vi = bad.begin();
+ vi != bad.end(); ++vi) {
+ RegDeleteValueW(hKey, vi->c_str());
+ }
+ RegCloseKey(hKey);
+ }
+}
+#else
+class cmFindPackageCommandHoldFile
+{
+ const char* File;
+
+public:
+ cmFindPackageCommandHoldFile(const char* f)
+ : File(f)
+ {
+ }
+ ~cmFindPackageCommandHoldFile()
+ {
+ if (this->File) {
+ cmSystemTools::RemoveFile(this->File);
+ }
+ }
+ void Release() { this->File = CM_NULLPTR; }
+};
+
+void cmFindPackageCommand::LoadPackageRegistryDir(std::string const& dir,
+ cmSearchPath& outPaths)
+{
+ cmsys::Directory files;
+ if (!files.Load(dir)) {
+ return;
+ }
+
+ std::string fname;
+ for (unsigned long i = 0; i < files.GetNumberOfFiles(); ++i) {
+ fname = dir;
+ fname += "/";
+ fname += files.GetFile(i);
+
+ if (!cmSystemTools::FileIsDirectory(fname)) {
+ // Hold this file hostage until it behaves.
+ cmFindPackageCommandHoldFile holdFile(fname.c_str());
+
+ // Load the file.
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+ std::string fentry;
+ if (fin && cmSystemTools::GetLineFromStream(fin, fentry) &&
+ this->CheckPackageRegistryEntry(fentry, outPaths)) {
+ // The file references an existing package, so release it.
+ holdFile.Release();
+ }
+ }
+ }
+
+ // TODO: Wipe out the directory if it is empty.
+}
+#endif
+
+bool cmFindPackageCommand::CheckPackageRegistryEntry(const std::string& fname,
+ cmSearchPath& outPaths)
+{
+ // Parse the content of one package registry entry.
+ if (cmSystemTools::FileIsFullPath(fname.c_str())) {
+ // The first line in the stream is the full path to a file or
+ // directory containing the package.
+ if (cmSystemTools::FileExists(fname.c_str())) {
+ // The path exists. Look for the package here.
+ if (!cmSystemTools::FileIsDirectory(fname)) {
+ outPaths.AddPath(cmSystemTools::GetFilenamePath(fname));
+ } else {
+ outPaths.AddPath(fname);
+ }
+ return true;
+ } else {
+ // The path does not exist. Assume the stream content is
+ // associated with an old package that no longer exists, and
+ // delete it to keep the package registry clean.
+ return false;
+ }
+ } else {
+ // The first line in the stream is not the full path to a file or
+ // directory. Assume the stream content was created by a future
+ // version of CMake that uses a different format, and leave it.
+ return true;
+ }
+}
+
+void cmFindPackageCommand::FillPrefixesCMakeSystemVariable()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::CMakeSystem];
+
+ paths.AddCMakePath("CMAKE_SYSTEM_PREFIX_PATH");
+ paths.AddCMakePath("CMAKE_SYSTEM_FRAMEWORK_PATH");
+ paths.AddCMakePath("CMAKE_SYSTEM_APPBUNDLE_PATH");
+}
+
+void cmFindPackageCommand::FillPrefixesUserGuess()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::Guess];
+
+ for (std::vector<std::string>::const_iterator p =
+ this->UserGuessArgs.begin();
+ p != this->UserGuessArgs.end(); ++p) {
+ paths.AddUserPath(*p);
+ }
+}
+
+void cmFindPackageCommand::FillPrefixesUserHints()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::Hints];
+
+ for (std::vector<std::string>::const_iterator p =
+ this->UserHintsArgs.begin();
+ p != this->UserHintsArgs.end(); ++p) {
+ paths.AddUserPath(*p);
+ }
+}
+
+bool cmFindPackageCommand::SearchDirectory(std::string const& dir)
+{
+ assert(!dir.empty() && dir[dir.size() - 1] == '/');
+
+ // Check each path suffix on this directory.
+ for (std::vector<std::string>::const_iterator si =
+ this->SearchPathSuffixes.begin();
+ si != this->SearchPathSuffixes.end(); ++si) {
+ std::string d = dir;
+ if (!si->empty()) {
+ d += *si;
+ d += "/";
+ }
+ if (this->CheckDirectory(d)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmFindPackageCommand::CheckDirectory(std::string const& dir)
+{
+ assert(!dir.empty() && dir[dir.size() - 1] == '/');
+
+ // Look for the file in this directory.
+ std::string d = dir.substr(0, dir.size() - 1);
+ if (this->FindConfigFile(d, this->FileFound)) {
+ // Remove duplicate slashes.
+ cmSystemTools::ConvertToUnixSlashes(this->FileFound);
+ return true;
+ }
+ return false;
+}
+
+bool cmFindPackageCommand::FindConfigFile(std::string const& dir,
+ std::string& file)
+{
+ if (this->IgnoredPaths.count(dir)) {
+ return false;
+ }
+
+ for (std::vector<std::string>::const_iterator ci = this->Configs.begin();
+ ci != this->Configs.end(); ++ci) {
+ file = dir;
+ file += "/";
+ file += *ci;
+ if (this->DebugMode) {
+ fprintf(stderr, "Checking file [%s]\n", file.c_str());
+ }
+ if (cmSystemTools::FileExists(file.c_str(), true) &&
+ this->CheckVersion(file)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmFindPackageCommand::CheckVersion(std::string const& config_file)
+{
+ bool result = false; // by default, assume the version is not ok.
+ bool haveResult = false;
+ std::string version = "unknown";
+
+ // Get the filename without the .cmake extension.
+ std::string::size_type pos = config_file.rfind('.');
+ std::string version_file_base = config_file.substr(0, pos);
+
+ // Look for foo-config-version.cmake
+ std::string version_file = version_file_base;
+ version_file += "-version.cmake";
+ if ((haveResult == false) &&
+ (cmSystemTools::FileExists(version_file.c_str(), true))) {
+ result = this->CheckVersionFile(version_file, version);
+ haveResult = true;
+ }
+
+ // Look for fooConfigVersion.cmake
+ version_file = version_file_base;
+ version_file += "Version.cmake";
+ if ((haveResult == false) &&
+ (cmSystemTools::FileExists(version_file.c_str(), true))) {
+ result = this->CheckVersionFile(version_file, version);
+ haveResult = true;
+ }
+
+ // If no version was requested a versionless package is acceptable.
+ if ((haveResult == false) && (this->Version.empty())) {
+ result = true;
+ }
+
+ ConfigFileInfo configFileInfo;
+ configFileInfo.filename = config_file;
+ configFileInfo.version = version;
+ this->ConsideredConfigs.push_back(configFileInfo);
+
+ return result;
+}
+
+bool cmFindPackageCommand::CheckVersionFile(std::string const& version_file,
+ std::string& result_version)
+{
+ // The version file will be loaded in an isolated scope.
+ cmMakefile::ScopePushPop varScope(this->Makefile);
+ cmMakefile::PolicyPushPop polScope(this->Makefile);
+ static_cast<void>(varScope);
+ static_cast<void>(polScope);
+
+ // Clear the output variables.
+ this->Makefile->RemoveDefinition("PACKAGE_VERSION");
+ this->Makefile->RemoveDefinition("PACKAGE_VERSION_UNSUITABLE");
+ this->Makefile->RemoveDefinition("PACKAGE_VERSION_COMPATIBLE");
+ this->Makefile->RemoveDefinition("PACKAGE_VERSION_EXACT");
+
+ // Set the input variables.
+ this->Makefile->AddDefinition("PACKAGE_FIND_NAME", this->Name.c_str());
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION", this->Version.c_str());
+ char buf[64];
+ sprintf(buf, "%u", this->VersionMajor);
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_MAJOR", buf);
+ sprintf(buf, "%u", this->VersionMinor);
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_MINOR", buf);
+ sprintf(buf, "%u", this->VersionPatch);
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_PATCH", buf);
+ sprintf(buf, "%u", this->VersionTweak);
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_TWEAK", buf);
+ sprintf(buf, "%u", this->VersionCount);
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_COUNT", buf);
+
+ // Load the version check file. Pass NoPolicyScope because we do
+ // our own policy push/pop independent of CMP0011.
+ bool suitable = false;
+ if (this->ReadListFile(version_file.c_str(), NoPolicyScope)) {
+ // Check the output variables.
+ bool okay = this->Makefile->IsOn("PACKAGE_VERSION_EXACT");
+ bool unsuitable = this->Makefile->IsOn("PACKAGE_VERSION_UNSUITABLE");
+ if (!okay && !this->VersionExact) {
+ okay = this->Makefile->IsOn("PACKAGE_VERSION_COMPATIBLE");
+ }
+
+ // The package is suitable if the version is okay and not
+ // explicitly unsuitable.
+ suitable = !unsuitable && (okay || this->Version.empty());
+ if (suitable) {
+ // Get the version found.
+ this->VersionFound =
+ this->Makefile->GetSafeDefinition("PACKAGE_VERSION");
+
+ // Try to parse the version number and store the results that were
+ // successfully parsed.
+ unsigned int parsed_major;
+ unsigned int parsed_minor;
+ unsigned int parsed_patch;
+ unsigned int parsed_tweak;
+ this->VersionFoundCount =
+ sscanf(this->VersionFound.c_str(), "%u.%u.%u.%u", &parsed_major,
+ &parsed_minor, &parsed_patch, &parsed_tweak);
+ switch (this->VersionFoundCount) {
+ case 4:
+ this->VersionFoundTweak = parsed_tweak; // no break!
+ case 3:
+ this->VersionFoundPatch = parsed_patch; // no break!
+ case 2:
+ this->VersionFoundMinor = parsed_minor; // no break!
+ case 1:
+ this->VersionFoundMajor = parsed_major; // no break!
+ default:
+ break;
+ }
+ }
+ }
+
+ result_version = this->Makefile->GetSafeDefinition("PACKAGE_VERSION");
+ if (result_version.empty()) {
+ result_version = "unknown";
+ }
+
+ // Succeed if the version is suitable.
+ return suitable;
+}
+
+void cmFindPackageCommand::StoreVersionFound()
+{
+ // Store the whole version string.
+ std::string ver = this->Name;
+ ver += "_VERSION";
+ if (this->VersionFound.empty()) {
+ this->Makefile->RemoveDefinition(ver);
+ } else {
+ this->Makefile->AddDefinition(ver, this->VersionFound.c_str());
+ }
+
+ // Store the version components.
+ char buf[64];
+ sprintf(buf, "%u", this->VersionFoundMajor);
+ this->Makefile->AddDefinition(ver + "_MAJOR", buf);
+ sprintf(buf, "%u", this->VersionFoundMinor);
+ this->Makefile->AddDefinition(ver + "_MINOR", buf);
+ sprintf(buf, "%u", this->VersionFoundPatch);
+ this->Makefile->AddDefinition(ver + "_PATCH", buf);
+ sprintf(buf, "%u", this->VersionFoundTweak);
+ this->Makefile->AddDefinition(ver + "_TWEAK", buf);
+ sprintf(buf, "%u", this->VersionFoundCount);
+ this->Makefile->AddDefinition(ver + "_COUNT", buf);
+}
+
+#include <cm_auto_ptr.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/String.h>
+
+class cmFileList;
+class cmFileListGeneratorBase
+{
+public:
+ virtual ~cmFileListGeneratorBase() {}
+protected:
+ bool Consider(std::string const& fullPath, cmFileList& listing);
+
+private:
+ bool Search(cmFileList&);
+ virtual bool Search(std::string const& parent, cmFileList&) = 0;
+ virtual CM_AUTO_PTR<cmFileListGeneratorBase> Clone() const = 0;
+ friend class cmFileList;
+ cmFileListGeneratorBase* SetNext(cmFileListGeneratorBase const& next);
+ CM_AUTO_PTR<cmFileListGeneratorBase> Next;
+};
+
+class cmFileList
+{
+public:
+ cmFileList()
+ : First()
+ , Last(CM_NULLPTR)
+ {
+ }
+ virtual ~cmFileList() {}
+ cmFileList& operator/(cmFileListGeneratorBase const& rhs)
+ {
+ if (this->Last) {
+ this->Last = this->Last->SetNext(rhs);
+ } else {
+ this->First = rhs.Clone();
+ this->Last = this->First.get();
+ }
+ return *this;
+ }
+ bool Search()
+ {
+ if (this->First.get()) {
+ return this->First->Search(*this);
+ }
+ return false;
+ }
+
+private:
+ virtual bool Visit(std::string const& fullPath) = 0;
+ friend class cmFileListGeneratorBase;
+ CM_AUTO_PTR<cmFileListGeneratorBase> First;
+ cmFileListGeneratorBase* Last;
+};
+
+class cmFindPackageFileList : public cmFileList
+{
+public:
+ cmFindPackageFileList(cmFindPackageCommand* fpc, bool use_suffixes = true)
+ : cmFileList()
+ , FPC(fpc)
+ , UseSuffixes(use_suffixes)
+ {
+ }
+
+private:
+ bool Visit(std::string const& fullPath) CM_OVERRIDE
+ {
+ if (this->UseSuffixes) {
+ return this->FPC->SearchDirectory(fullPath);
+ } else {
+ return this->FPC->CheckDirectory(fullPath);
+ }
+ }
+ cmFindPackageCommand* FPC;
+ bool UseSuffixes;
+};
+
+bool cmFileListGeneratorBase::Search(cmFileList& listing)
+{
+ return this->Search("", listing);
+}
+
+cmFileListGeneratorBase* cmFileListGeneratorBase::SetNext(
+ cmFileListGeneratorBase const& next)
+{
+ this->Next = next.Clone();
+ return this->Next.get();
+}
+
+bool cmFileListGeneratorBase::Consider(std::string const& fullPath,
+ cmFileList& listing)
+{
+ if (this->Next.get()) {
+ return this->Next->Search(fullPath + "/", listing);
+ } else {
+ return listing.Visit(fullPath + "/");
+ }
+}
+
+class cmFileListGeneratorFixed : public cmFileListGeneratorBase
+{
+public:
+ cmFileListGeneratorFixed(std::string const& str)
+ : cmFileListGeneratorBase()
+ , String(str)
+ {
+ }
+ cmFileListGeneratorFixed(cmFileListGeneratorFixed const& r)
+ : cmFileListGeneratorBase()
+ , String(r.String)
+ {
+ }
+
+private:
+ std::string String;
+ bool Search(std::string const& parent, cmFileList& lister) CM_OVERRIDE
+ {
+ std::string fullPath = parent + this->String;
+ return this->Consider(fullPath, lister);
+ }
+ CM_AUTO_PTR<cmFileListGeneratorBase> Clone() const CM_OVERRIDE
+ {
+ CM_AUTO_PTR<cmFileListGeneratorBase> g(
+ new cmFileListGeneratorFixed(*this));
+ return g;
+ }
+};
+
+class cmFileListGeneratorEnumerate : public cmFileListGeneratorBase
+{
+public:
+ cmFileListGeneratorEnumerate(std::vector<std::string> const& v)
+ : cmFileListGeneratorBase()
+ , Vector(v)
+ {
+ }
+ cmFileListGeneratorEnumerate(cmFileListGeneratorEnumerate const& r)
+ : cmFileListGeneratorBase()
+ , Vector(r.Vector)
+ {
+ }
+
+private:
+ std::vector<std::string> const& Vector;
+ bool Search(std::string const& parent, cmFileList& lister) CM_OVERRIDE
+ {
+ for (std::vector<std::string>::const_iterator i = this->Vector.begin();
+ i != this->Vector.end(); ++i) {
+ if (this->Consider(parent + *i, lister)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ CM_AUTO_PTR<cmFileListGeneratorBase> Clone() const CM_OVERRIDE
+ {
+ CM_AUTO_PTR<cmFileListGeneratorBase> g(
+ new cmFileListGeneratorEnumerate(*this));
+ return g;
+ }
+};
+
+class cmFileListGeneratorProject : public cmFileListGeneratorBase
+{
+public:
+ cmFileListGeneratorProject(std::vector<std::string> const& names)
+ : cmFileListGeneratorBase()
+ , Names(names)
+ {
+ }
+ cmFileListGeneratorProject(cmFileListGeneratorProject const& r)
+ : cmFileListGeneratorBase()
+ , Names(r.Names)
+ {
+ }
+
+private:
+ std::vector<std::string> const& Names;
+ bool Search(std::string const& parent, cmFileList& lister) CM_OVERRIDE
+ {
+ // Construct a list of matches.
+ std::vector<std::string> matches;
+ cmsys::Directory d;
+ d.Load(parent);
+ for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
+ const char* fname = d.GetFile(i);
+ if (strcmp(fname, ".") == 0 || strcmp(fname, "..") == 0) {
+ continue;
+ }
+ for (std::vector<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ if (cmsysString_strncasecmp(fname, ni->c_str(), ni->length()) == 0) {
+ matches.push_back(fname);
+ }
+ }
+ }
+
+ for (std::vector<std::string>::const_iterator i = matches.begin();
+ i != matches.end(); ++i) {
+ if (this->Consider(parent + *i, lister)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ CM_AUTO_PTR<cmFileListGeneratorBase> Clone() const CM_OVERRIDE
+ {
+ CM_AUTO_PTR<cmFileListGeneratorBase> g(
+ new cmFileListGeneratorProject(*this));
+ return g;
+ }
+};
+
+class cmFileListGeneratorMacProject : public cmFileListGeneratorBase
+{
+public:
+ cmFileListGeneratorMacProject(std::vector<std::string> const& names,
+ const char* ext)
+ : cmFileListGeneratorBase()
+ , Names(names)
+ , Extension(ext)
+ {
+ }
+ cmFileListGeneratorMacProject(cmFileListGeneratorMacProject const& r)
+ : cmFileListGeneratorBase()
+ , Names(r.Names)
+ , Extension(r.Extension)
+ {
+ }
+
+private:
+ std::vector<std::string> const& Names;
+ std::string Extension;
+ bool Search(std::string const& parent, cmFileList& lister) CM_OVERRIDE
+ {
+ // Construct a list of matches.
+ std::vector<std::string> matches;
+ cmsys::Directory d;
+ d.Load(parent);
+ for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
+ const char* fname = d.GetFile(i);
+ if (strcmp(fname, ".") == 0 || strcmp(fname, "..") == 0) {
+ continue;
+ }
+ for (std::vector<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ std::string name = *ni;
+ name += this->Extension;
+ if (cmsysString_strcasecmp(fname, name.c_str()) == 0) {
+ matches.push_back(fname);
+ }
+ }
+ }
+
+ for (std::vector<std::string>::const_iterator i = matches.begin();
+ i != matches.end(); ++i) {
+ if (this->Consider(parent + *i, lister)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ CM_AUTO_PTR<cmFileListGeneratorBase> Clone() const CM_OVERRIDE
+ {
+ CM_AUTO_PTR<cmFileListGeneratorBase> g(
+ new cmFileListGeneratorMacProject(*this));
+ return g;
+ }
+};
+
+class cmFileListGeneratorCaseInsensitive : public cmFileListGeneratorBase
+{
+public:
+ cmFileListGeneratorCaseInsensitive(std::string const& str)
+ : cmFileListGeneratorBase()
+ , String(str)
+ {
+ }
+ cmFileListGeneratorCaseInsensitive(
+ cmFileListGeneratorCaseInsensitive const& r)
+ : cmFileListGeneratorBase()
+ , String(r.String)
+ {
+ }
+
+private:
+ std::string String;
+ bool Search(std::string const& parent, cmFileList& lister) CM_OVERRIDE
+ {
+ // Look for matching files.
+ std::vector<std::string> matches;
+ cmsys::Directory d;
+ d.Load(parent);
+ for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
+ const char* fname = d.GetFile(i);
+ if (strcmp(fname, ".") == 0 || strcmp(fname, "..") == 0) {
+ continue;
+ }
+ if (cmsysString_strcasecmp(fname, this->String.c_str()) == 0) {
+ if (this->Consider(parent + fname, lister)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ CM_AUTO_PTR<cmFileListGeneratorBase> Clone() const CM_OVERRIDE
+ {
+ CM_AUTO_PTR<cmFileListGeneratorBase> g(
+ new cmFileListGeneratorCaseInsensitive(*this));
+ return g;
+ }
+};
+
+class cmFileListGeneratorGlob : public cmFileListGeneratorBase
+{
+public:
+ cmFileListGeneratorGlob(std::string const& str)
+ : cmFileListGeneratorBase()
+ , Pattern(str)
+ {
+ }
+ cmFileListGeneratorGlob(cmFileListGeneratorGlob const& r)
+ : cmFileListGeneratorBase()
+ , Pattern(r.Pattern)
+ {
+ }
+
+private:
+ std::string Pattern;
+ bool Search(std::string const& parent, cmFileList& lister) CM_OVERRIDE
+ {
+ // Glob the set of matching files.
+ std::string expr = parent;
+ expr += this->Pattern;
+ cmsys::Glob g;
+ if (!g.FindFiles(expr)) {
+ return false;
+ }
+ std::vector<std::string> const& files = g.GetFiles();
+
+ // Look for directories among the matches.
+ for (std::vector<std::string>::const_iterator fi = files.begin();
+ fi != files.end(); ++fi) {
+ if (cmSystemTools::FileIsDirectory(*fi)) {
+ if (this->Consider(*fi, lister)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ CM_AUTO_PTR<cmFileListGeneratorBase> Clone() const CM_OVERRIDE
+ {
+ CM_AUTO_PTR<cmFileListGeneratorBase> g(new cmFileListGeneratorGlob(*this));
+ return g;
+ }
+};
+
+bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
+{
+ assert(!prefix_in.empty() && prefix_in[prefix_in.size() - 1] == '/');
+ if (this->DebugMode) {
+ fprintf(stderr, "Checking prefix [%s]\n", prefix_in.c_str());
+ }
+
+ // Skip this if the prefix does not exist.
+ if (!cmSystemTools::FileIsDirectory(prefix_in)) {
+ return false;
+ }
+
+ // PREFIX/ (useful on windows or in build trees)
+ if (this->SearchDirectory(prefix_in)) {
+ return true;
+ }
+
+ // Strip the trailing slash because the path generator is about to
+ // add one.
+ std::string prefix = prefix_in.substr(0, prefix_in.size() - 1);
+
+ // PREFIX/(cmake|CMake)/ (useful on windows or in build trees)
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorCaseInsensitive("cmake");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // PREFIX/(Foo|foo|FOO).*/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorProject(this->Names);
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // PREFIX/(Foo|foo|FOO).*/(cmake|CMake)/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorProject(this->Names) /
+ cmFileListGeneratorCaseInsensitive("cmake");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // Construct list of common install locations (lib and share).
+ std::vector<std::string> common;
+ if (!this->LibraryArchitecture.empty()) {
+ common.push_back("lib/" + this->LibraryArchitecture);
+ }
+ if (this->UseLib32Paths) {
+ common.push_back("lib32");
+ }
+ if (this->UseLib64Paths) {
+ common.push_back("lib64");
+ }
+ common.push_back("lib");
+ common.push_back("share");
+
+ // PREFIX/(lib/ARCH|lib|share)/cmake/(Foo|foo|FOO).*/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorEnumerate(common) /
+ cmFileListGeneratorFixed("cmake") /
+ cmFileListGeneratorProject(this->Names);
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // PREFIX/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorEnumerate(common) /
+ cmFileListGeneratorProject(this->Names);
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // PREFIX/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/(cmake|CMake)/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorEnumerate(common) /
+ cmFileListGeneratorProject(this->Names) /
+ cmFileListGeneratorCaseInsensitive("cmake");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool cmFindPackageCommand::SearchFrameworkPrefix(std::string const& prefix_in)
+{
+ assert(!prefix_in.empty() && prefix_in[prefix_in.size() - 1] == '/');
+ if (this->DebugMode) {
+ fprintf(stderr, "Checking framework prefix [%s]\n", prefix_in.c_str());
+ }
+
+ // Strip the trailing slash because the path generator is about to
+ // add one.
+ std::string prefix = prefix_in.substr(0, prefix_in.size() - 1);
+
+ // <prefix>/Foo.framework/Resources/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorMacProject(this->Names, ".framework") /
+ cmFileListGeneratorFixed("Resources");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+ // <prefix>/Foo.framework/Resources/CMake/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorMacProject(this->Names, ".framework") /
+ cmFileListGeneratorFixed("Resources") /
+ cmFileListGeneratorCaseInsensitive("cmake");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // <prefix>/Foo.framework/Versions/*/Resources/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorMacProject(this->Names, ".framework") /
+ cmFileListGeneratorFixed("Versions") /
+ cmFileListGeneratorGlob("*/Resources");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // <prefix>/Foo.framework/Versions/*/Resources/CMake/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorMacProject(this->Names, ".framework") /
+ cmFileListGeneratorFixed("Versions") /
+ cmFileListGeneratorGlob("*/Resources") /
+ cmFileListGeneratorCaseInsensitive("cmake");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool cmFindPackageCommand::SearchAppBundlePrefix(std::string const& prefix_in)
+{
+ assert(!prefix_in.empty() && prefix_in[prefix_in.size() - 1] == '/');
+ if (this->DebugMode) {
+ fprintf(stderr, "Checking bundle prefix [%s]\n", prefix_in.c_str());
+ }
+
+ // Strip the trailing slash because the path generator is about to
+ // add one.
+ std::string prefix = prefix_in.substr(0, prefix_in.size() - 1);
+
+ // <prefix>/Foo.app/Contents/Resources
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorMacProject(this->Names, ".app") /
+ cmFileListGeneratorFixed("Contents/Resources");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // <prefix>/Foo.app/Contents/Resources/CMake
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorMacProject(this->Names, ".app") /
+ cmFileListGeneratorFixed("Contents/Resources") /
+ cmFileListGeneratorCaseInsensitive("cmake");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// TODO: Debug cmsys::Glob double slash problem.
diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h
new file mode 100644
index 0000000..087107e
--- /dev/null
+++ b/Source/cmFindPackageCommand.h
@@ -0,0 +1,182 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFindPackageCommand_h
+#define cmFindPackageCommand_h
+
+#include "cmFindCommon.h"
+
+class cmFindPackageFileList;
+
+/** \class cmFindPackageCommand
+ * \brief Load settings from an external project.
+ *
+ * cmFindPackageCommand
+ */
+class cmFindPackageCommand : public cmFindCommon
+{
+public:
+ cmFindPackageCommand();
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmFindPackageCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "find_package"; }
+
+ cmTypeMacro(cmFindPackageCommand, cmFindCommon);
+
+private:
+ class PathLabel : public cmFindCommon::PathLabel
+ {
+ protected:
+ PathLabel();
+
+ public:
+ PathLabel(const std::string& label)
+ : cmFindCommon::PathLabel(label)
+ {
+ }
+ static PathLabel UserRegistry;
+ static PathLabel Builds;
+ static PathLabel SystemRegistry;
+ };
+
+ // Add additional search path labels and groups not present in the
+ // parent class
+ void AppendSearchPathGroups();
+
+ void AppendSuccessInformation();
+ void AppendToFoundProperty(bool found);
+ void SetModuleVariables(const std::string& components);
+ bool FindModule(bool& found);
+ void AddFindDefinition(const std::string& var, const char* val);
+ void RestoreFindDefinitions();
+ bool HandlePackageMode();
+ bool FindConfig();
+ bool FindPrefixedConfig();
+ bool FindFrameworkConfig();
+ bool FindAppBundleConfig();
+ enum PolicyScopeRule
+ {
+ NoPolicyScope,
+ DoPolicyScope
+ };
+ bool ReadListFile(const char* f, PolicyScopeRule psr);
+ void StoreVersionFound();
+
+ void ComputePrefixes();
+ void FillPrefixesCMakeEnvironment();
+ void FillPrefixesCMakeVariable();
+ void FillPrefixesSystemEnvironment();
+ void FillPrefixesUserRegistry();
+ void FillPrefixesSystemRegistry();
+ void FillPrefixesCMakeSystemVariable();
+ void FillPrefixesUserGuess();
+ void FillPrefixesUserHints();
+ void LoadPackageRegistryDir(std::string const& dir, cmSearchPath& outPaths);
+ void LoadPackageRegistryWinUser();
+ void LoadPackageRegistryWinSystem();
+ void LoadPackageRegistryWin(bool user, unsigned int view,
+ cmSearchPath& outPaths);
+ bool CheckPackageRegistryEntry(const std::string& fname,
+ cmSearchPath& outPaths);
+ bool SearchDirectory(std::string const& dir);
+ bool CheckDirectory(std::string const& dir);
+ bool FindConfigFile(std::string const& dir, std::string& file);
+ bool CheckVersion(std::string const& config_file);
+ bool CheckVersionFile(std::string const& version_file,
+ std::string& result_version);
+ bool SearchPrefix(std::string const& prefix);
+ bool SearchFrameworkPrefix(std::string const& prefix_in);
+ bool SearchAppBundlePrefix(std::string const& prefix_in);
+
+ friend class cmFindPackageFileList;
+
+ struct OriginalDef
+ {
+ bool exists;
+ std::string value;
+ };
+ std::map<std::string, OriginalDef> OriginalDefs;
+
+ std::string Name;
+ std::string Variable;
+ std::string Version;
+ unsigned int VersionMajor;
+ unsigned int VersionMinor;
+ unsigned int VersionPatch;
+ unsigned int VersionTweak;
+ unsigned int VersionCount;
+ bool VersionExact;
+ std::string FileFound;
+ std::string VersionFound;
+ unsigned int VersionFoundMajor;
+ unsigned int VersionFoundMinor;
+ unsigned int VersionFoundPatch;
+ unsigned int VersionFoundTweak;
+ unsigned int VersionFoundCount;
+ KWIML_INT_uint64_t RequiredCMakeVersion;
+ bool Quiet;
+ bool Required;
+ bool UseConfigFiles;
+ bool UseFindModules;
+ bool NoUserRegistry;
+ bool NoSystemRegistry;
+ bool DebugMode;
+ bool UseLib32Paths;
+ bool UseLib64Paths;
+ bool PolicyScope;
+ std::string LibraryArchitecture;
+ std::vector<std::string> Names;
+ std::vector<std::string> Configs;
+ std::set<std::string> IgnoredPaths;
+
+ struct ConfigFileInfo
+ {
+ std::string filename;
+ std::string version;
+
+ bool operator<(ConfigFileInfo const& rhs) const
+ {
+ return this->filename < rhs.filename;
+ }
+
+ bool operator==(ConfigFileInfo const& rhs) const
+ {
+ return this->filename == rhs.filename;
+ }
+
+ bool operator!=(ConfigFileInfo const& rhs) const
+ {
+ return !(*this == rhs);
+ }
+ };
+ std::vector<ConfigFileInfo> ConsideredConfigs;
+};
+
+#endif
diff --git a/Source/cmFindPathCommand.cxx b/Source/cmFindPathCommand.cxx
new file mode 100644
index 0000000..d71fc1a
--- /dev/null
+++ b/Source/cmFindPathCommand.cxx
@@ -0,0 +1,162 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmFindPathCommand.h"
+
+#include <cmsys/Glob.hxx>
+
+cmFindPathCommand::cmFindPathCommand()
+{
+ this->EnvironmentPath = "INCLUDE";
+ this->IncludeFileInPath = false;
+}
+
+// cmFindPathCommand
+bool cmFindPathCommand::InitialPass(std::vector<std::string> const& argsIn,
+ cmExecutionStatus&)
+{
+ this->VariableDocumentation = "Path to a file.";
+ this->CMakePathName = "INCLUDE";
+ if (!this->ParseArguments(argsIn)) {
+ return false;
+ }
+ if (this->AlreadyInCache) {
+ // If the user specifies the entry on the command line without a
+ // type we should add the type and docstring but keep the original
+ // value.
+ if (this->AlreadyInCacheWithoutMetaInfo) {
+ this->Makefile->AddCacheDefinition(
+ this->VariableName, "", this->VariableDocumentation.c_str(),
+ (this->IncludeFileInPath ? cmState::FILEPATH : cmState::PATH));
+ }
+ return true;
+ }
+
+ std::string result = this->FindHeader();
+ if (!result.empty()) {
+ this->Makefile->AddCacheDefinition(
+ this->VariableName, result.c_str(), this->VariableDocumentation.c_str(),
+ (this->IncludeFileInPath) ? cmState::FILEPATH : cmState::PATH);
+ return true;
+ }
+ this->Makefile->AddCacheDefinition(
+ this->VariableName, (this->VariableName + "-NOTFOUND").c_str(),
+ this->VariableDocumentation.c_str(),
+ (this->IncludeFileInPath) ? cmState::FILEPATH : cmState::PATH);
+ return true;
+}
+
+std::string cmFindPathCommand::FindHeader()
+{
+ std::string header;
+ if (this->SearchFrameworkFirst || this->SearchFrameworkOnly) {
+ header = this->FindFrameworkHeader();
+ }
+ if (header.empty() && !this->SearchFrameworkOnly) {
+ header = this->FindNormalHeader();
+ }
+ if (header.empty() && this->SearchFrameworkLast) {
+ header = this->FindFrameworkHeader();
+ }
+ return header;
+}
+
+std::string cmFindPathCommand::FindHeaderInFramework(std::string const& file,
+ std::string const& dir)
+{
+ std::string fileName = file;
+ std::string frameWorkName;
+ std::string::size_type pos = fileName.find("/");
+ // if there is a / in the name try to find the header as a framework
+ // For example bar/foo.h would look for:
+ // bar.framework/Headers/foo.h
+ if (pos != fileName.npos) {
+ // remove the name from the slash;
+ fileName = fileName.substr(pos + 1);
+ frameWorkName = file;
+ frameWorkName =
+ frameWorkName.substr(0, frameWorkName.size() - fileName.size() - 1);
+ // if the framework has a path in it then just use the filename
+ if (frameWorkName.find("/") != frameWorkName.npos) {
+ fileName = file;
+ frameWorkName = "";
+ }
+ if (!frameWorkName.empty()) {
+ std::string fpath = dir;
+ fpath += frameWorkName;
+ fpath += ".framework";
+ std::string intPath = fpath;
+ intPath += "/Headers/";
+ intPath += fileName;
+ if (cmSystemTools::FileExists(intPath.c_str())) {
+ if (this->IncludeFileInPath) {
+ return intPath;
+ }
+ return fpath;
+ }
+ }
+ }
+ // if it is not found yet or not a framework header, then do a glob search
+ // for all frameworks in the directory: dir/*.framework/Headers/<file>
+ std::string glob = dir;
+ glob += "*.framework/Headers/";
+ glob += file;
+ cmsys::Glob globIt;
+ globIt.FindFiles(glob);
+ std::vector<std::string> files = globIt.GetFiles();
+ if (!files.empty()) {
+ std::string fheader = cmSystemTools::CollapseFullPath(files[0]);
+ if (this->IncludeFileInPath) {
+ return fheader;
+ }
+ fheader.resize(fheader.size() - file.size());
+ return fheader;
+ }
+ return "";
+}
+
+std::string cmFindPathCommand::FindNormalHeader()
+{
+ std::string tryPath;
+ for (std::vector<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ for (std::vector<std::string>::const_iterator p =
+ this->SearchPaths.begin();
+ p != this->SearchPaths.end(); ++p) {
+ tryPath = *p;
+ tryPath += *ni;
+ if (cmSystemTools::FileExists(tryPath.c_str())) {
+ if (this->IncludeFileInPath) {
+ return tryPath;
+ } else {
+ return *p;
+ }
+ }
+ }
+ }
+ return "";
+}
+
+std::string cmFindPathCommand::FindFrameworkHeader()
+{
+ for (std::vector<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ for (std::vector<std::string>::const_iterator p =
+ this->SearchPaths.begin();
+ p != this->SearchPaths.end(); ++p) {
+ std::string fwPath = this->FindHeaderInFramework(*ni, *p);
+ if (!fwPath.empty()) {
+ return fwPath;
+ }
+ }
+ }
+ return "";
+}
diff --git a/Source/cmFindPathCommand.h b/Source/cmFindPathCommand.h
new file mode 100644
index 0000000..52ce3b0
--- /dev/null
+++ b/Source/cmFindPathCommand.h
@@ -0,0 +1,61 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFindPathCommand_h
+#define cmFindPathCommand_h
+
+#include "cmFindBase.h"
+
+/** \class cmFindPathCommand
+ * \brief Define a command to search for a library.
+ *
+ * cmFindPathCommand is used to define a CMake variable
+ * that specifies a library. The command searches for a given
+ * file in a list of directories.
+ */
+class cmFindPathCommand : public cmFindBase
+{
+public:
+ cmFindPathCommand();
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmFindPathCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "find_path"; }
+
+ cmTypeMacro(cmFindPathCommand, cmFindBase);
+ bool IncludeFileInPath;
+
+private:
+ std::string FindHeaderInFramework(std::string const& file,
+ std::string const& dir);
+ std::string FindHeader();
+ std::string FindNormalHeader();
+ std::string FindFrameworkHeader();
+};
+
+#endif
diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx
new file mode 100644
index 0000000..8d142c9
--- /dev/null
+++ b/Source/cmFindProgramCommand.cxx
@@ -0,0 +1,267 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmFindProgramCommand.h"
+
+#include <stdlib.h>
+
+#if defined(__APPLE__)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+struct cmFindProgramHelper
+{
+ cmFindProgramHelper()
+ {
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+ // Consider platform-specific extensions.
+ this->Extensions.push_back(".com");
+ this->Extensions.push_back(".exe");
+#endif
+ // Consider original name with no extensions.
+ this->Extensions.push_back("");
+ }
+
+ // List of valid extensions.
+ std::vector<std::string> Extensions;
+
+ // Keep track of the best program file found so far.
+ std::string BestPath;
+
+ // Current names under consideration.
+ std::vector<std::string> Names;
+
+ // Current full path under consideration.
+ std::string TestPath;
+
+ void AddName(std::string const& name) { this->Names.push_back(name); }
+ void SetName(std::string const& name)
+ {
+ this->Names.clear();
+ this->AddName(name);
+ }
+ bool CheckDirectory(std::string const& path)
+ {
+ for (std::vector<std::string>::iterator i = this->Names.begin();
+ i != this->Names.end(); ++i) {
+ if (this->CheckDirectoryForName(path, *i)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ bool CheckDirectoryForName(std::string const& path, std::string const& name)
+ {
+ for (std::vector<std::string>::iterator ext = this->Extensions.begin();
+ ext != this->Extensions.end(); ++ext) {
+ this->TestPath = path;
+ this->TestPath += name;
+ if (!ext->empty() && cmSystemTools::StringEndsWith(name, ext->c_str())) {
+ continue;
+ }
+ this->TestPath += *ext;
+ if (cmSystemTools::FileExists(this->TestPath, true)) {
+ this->BestPath = cmSystemTools::CollapseFullPath(this->TestPath);
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+cmFindProgramCommand::cmFindProgramCommand()
+{
+ this->NamesPerDirAllowed = true;
+}
+
+// cmFindProgramCommand
+bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn,
+ cmExecutionStatus&)
+{
+ this->VariableDocumentation = "Path to a program.";
+ this->CMakePathName = "PROGRAM";
+ // call cmFindBase::ParseArguments
+ if (!this->ParseArguments(argsIn)) {
+ return false;
+ }
+ if (this->AlreadyInCache) {
+ // If the user specifies the entry on the command line without a
+ // type we should add the type and docstring but keep the original
+ // value.
+ if (this->AlreadyInCacheWithoutMetaInfo) {
+ this->Makefile->AddCacheDefinition(this->VariableName, "",
+ this->VariableDocumentation.c_str(),
+ cmState::FILEPATH);
+ }
+ return true;
+ }
+
+ std::string result = FindProgram();
+ if (result != "") {
+ // Save the value in the cache
+ this->Makefile->AddCacheDefinition(this->VariableName, result.c_str(),
+ this->VariableDocumentation.c_str(),
+ cmState::FILEPATH);
+
+ return true;
+ }
+ this->Makefile->AddCacheDefinition(
+ this->VariableName, (this->VariableName + "-NOTFOUND").c_str(),
+ this->VariableDocumentation.c_str(), cmState::FILEPATH);
+ return true;
+}
+
+std::string cmFindProgramCommand::FindProgram()
+{
+ std::string program = "";
+
+ if (this->SearchAppBundleFirst || this->SearchAppBundleOnly) {
+ program = FindAppBundle();
+ }
+ if (program.empty() && !this->SearchAppBundleOnly) {
+ program = this->FindNormalProgram();
+ }
+
+ if (program.empty() && this->SearchAppBundleLast) {
+ program = this->FindAppBundle();
+ }
+ return program;
+}
+
+std::string cmFindProgramCommand::FindNormalProgram()
+{
+ if (this->NamesPerDir) {
+ return this->FindNormalProgramNamesPerDir();
+ } else {
+ return this->FindNormalProgramDirsPerName();
+ }
+}
+
+std::string cmFindProgramCommand::FindNormalProgramNamesPerDir()
+{
+ // Search for all names in each directory.
+ cmFindProgramHelper helper;
+ for (std::vector<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ helper.AddName(*ni);
+ }
+
+ // Check for the names themselves (e.g. absolute paths).
+ if (helper.CheckDirectory(std::string())) {
+ return helper.BestPath;
+ }
+
+ // Search every directory.
+ for (std::vector<std::string>::const_iterator p = this->SearchPaths.begin();
+ p != this->SearchPaths.end(); ++p) {
+ if (helper.CheckDirectory(*p)) {
+ return helper.BestPath;
+ }
+ }
+ // Couldn't find the program.
+ return "";
+}
+
+std::string cmFindProgramCommand::FindNormalProgramDirsPerName()
+{
+ // Search the entire path for each name.
+ cmFindProgramHelper helper;
+ for (std::vector<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ // Switch to searching for this name.
+ helper.SetName(*ni);
+
+ // Check for the name by itself (e.g. an absolute path).
+ if (helper.CheckDirectory(std::string())) {
+ return helper.BestPath;
+ }
+
+ // Search every directory.
+ for (std::vector<std::string>::const_iterator p =
+ this->SearchPaths.begin();
+ p != this->SearchPaths.end(); ++p) {
+ if (helper.CheckDirectory(*p)) {
+ return helper.BestPath;
+ }
+ }
+ }
+ // Couldn't find the program.
+ return "";
+}
+
+std::string cmFindProgramCommand::FindAppBundle()
+{
+ for (std::vector<std::string>::const_iterator name = this->Names.begin();
+ name != this->Names.end(); ++name) {
+
+ std::string appName = *name + std::string(".app");
+ std::string appPath =
+ cmSystemTools::FindDirectory(appName, this->SearchPaths, true);
+
+ if (!appPath.empty()) {
+ std::string executable = GetBundleExecutable(appPath);
+ if (!executable.empty()) {
+ return cmSystemTools::CollapseFullPath(executable);
+ }
+ }
+ }
+
+ // Couldn't find app bundle
+ return "";
+}
+
+std::string cmFindProgramCommand::GetBundleExecutable(std::string bundlePath)
+{
+ std::string executable = "";
+ (void)bundlePath;
+#if defined(__APPLE__)
+ // Started with an example on developer.apple.com about finding bundles
+ // and modified from that.
+
+ // Get a CFString of the app bundle path
+ // XXX - Is it safe to assume everything is in UTF8?
+ CFStringRef bundlePathCFS = CFStringCreateWithCString(
+ kCFAllocatorDefault, bundlePath.c_str(), kCFStringEncodingUTF8);
+
+ // Make a CFURLRef from the CFString representation of the
+ // bundle’s path.
+ CFURLRef bundleURL = CFURLCreateWithFileSystemPath(
+ kCFAllocatorDefault, bundlePathCFS, kCFURLPOSIXPathStyle, true);
+
+ // Make a bundle instance using the URLRef.
+ CFBundleRef appBundle = CFBundleCreate(kCFAllocatorDefault, bundleURL);
+
+ // returned executableURL is relative to <appbundle>/Contents/MacOS/
+ CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
+
+ if (executableURL != NULL) {
+ const int MAX_OSX_PATH_SIZE = 1024;
+ char buffer[MAX_OSX_PATH_SIZE];
+
+ // Convert the CFString to a C string
+ CFStringGetCString(CFURLGetString(executableURL), buffer,
+ MAX_OSX_PATH_SIZE, kCFStringEncodingUTF8);
+
+ // And finally to a c++ string
+ executable = bundlePath + "/Contents/MacOS/" + std::string(buffer);
+ // Only release CFURLRef if it's not null
+ CFRelease(executableURL);
+ }
+
+ // Any CF objects returned from functions with "create" or
+ // "copy" in their names must be released by us!
+ CFRelease(bundlePathCFS);
+ CFRelease(bundleURL);
+ CFRelease(appBundle);
+#endif
+
+ return executable;
+}
diff --git a/Source/cmFindProgramCommand.h b/Source/cmFindProgramCommand.h
new file mode 100644
index 0000000..1953f59
--- /dev/null
+++ b/Source/cmFindProgramCommand.h
@@ -0,0 +1,62 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFindProgramCommand_h
+#define cmFindProgramCommand_h
+
+#include "cmFindBase.h"
+
+/** \class cmFindProgramCommand
+ * \brief Define a command to search for an executable program.
+ *
+ * cmFindProgramCommand is used to define a CMake variable
+ * that specifies an executable program. The command searches
+ * in the current path (e.g., PATH environment variable) for
+ * an executable that matches one of the supplied names.
+ */
+class cmFindProgramCommand : public cmFindBase
+{
+public:
+ cmFindProgramCommand();
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmFindProgramCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "find_program"; }
+
+ cmTypeMacro(cmFindProgramCommand, cmFindBase);
+
+private:
+ std::string FindProgram();
+ std::string FindNormalProgram();
+ std::string FindNormalProgramDirsPerName();
+ std::string FindNormalProgramNamesPerDir();
+ std::string FindAppBundle();
+ std::string GetBundleExecutable(std::string bundlePath);
+};
+
+#endif
diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx
new file mode 100644
index 0000000..c6e5f06
--- /dev/null
+++ b/Source/cmForEachCommand.cxx
@@ -0,0 +1,221 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmForEachCommand.h"
+
+#include <cm_auto_ptr.hxx>
+
+cmForEachFunctionBlocker::cmForEachFunctionBlocker(cmMakefile* mf)
+ : Makefile(mf)
+ , Depth(0)
+{
+ this->Makefile->PushLoopBlock();
+}
+
+cmForEachFunctionBlocker::~cmForEachFunctionBlocker()
+{
+ this->Makefile->PopLoopBlock();
+}
+
+bool cmForEachFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
+ cmMakefile& mf,
+ cmExecutionStatus& inStatus)
+{
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(), "foreach")) {
+ // record the number of nested foreach commands
+ this->Depth++;
+ } else if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endforeach")) {
+ // if this is the endofreach for this statement
+ if (!this->Depth) {
+ // Remove the function blocker for this scope or bail.
+ CM_AUTO_PTR<cmFunctionBlocker> fb(mf.RemoveFunctionBlocker(this, lff));
+ if (!fb.get()) {
+ return false;
+ }
+
+ // at end of for each execute recorded commands
+ // store the old value
+ std::string oldDef;
+ 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) {
+ // set the variable to the loop value
+ mf.AddDefinition(this->Args[0], j->c_str());
+ // Invoke all the functions that were collected in the block.
+ cmExecutionStatus status;
+ for (unsigned int c = 0; c < this->Functions.size(); ++c) {
+ status.Clear();
+ mf.ExecuteCommand(this->Functions[c], status);
+ if (status.GetReturnInvoked()) {
+ inStatus.SetReturnInvoked(true);
+ // restore the variable to its prior value
+ mf.AddDefinition(this->Args[0], oldDef.c_str());
+ return true;
+ }
+ if (status.GetBreakInvoked()) {
+ // restore the variable to its prior value
+ mf.AddDefinition(this->Args[0], oldDef.c_str());
+ return true;
+ }
+ if (status.GetContinueInvoked()) {
+ break;
+ }
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return true;
+ }
+ }
+ }
+
+ // restore the variable to its prior value
+ mf.AddDefinition(this->Args[0], oldDef.c_str());
+ return true;
+ } else {
+ // close out a nested foreach
+ this->Depth--;
+ }
+ }
+
+ // record the command
+ this->Functions.push_back(lff);
+
+ // always return true
+ return true;
+}
+
+bool cmForEachFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
+ cmMakefile& mf)
+{
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endforeach")) {
+ std::vector<std::string> expandedArguments;
+ mf.ExpandArguments(lff.Arguments, expandedArguments);
+ // if the endforeach has arguments then make sure
+ // they match the begin foreach arguments
+ if ((expandedArguments.empty() ||
+ (expandedArguments[0] == this->Args[0]))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmForEachCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ if (args.size() > 1 && args[1] == "IN") {
+ return this->HandleInMode(args);
+ }
+
+ // create a function blocker
+ cmForEachFunctionBlocker* f = new cmForEachFunctionBlocker(this->Makefile);
+ if (args.size() > 1) {
+ if (args[1] == "RANGE") {
+ int start = 0;
+ int stop = 0;
+ int step = 0;
+ if (args.size() == 3) {
+ stop = atoi(args[2].c_str());
+ }
+ if (args.size() == 4) {
+ start = atoi(args[2].c_str());
+ stop = atoi(args[3].c_str());
+ }
+ if (args.size() == 5) {
+ start = atoi(args[2].c_str());
+ stop = atoi(args[3].c_str());
+ step = atoi(args[4].c_str());
+ }
+ if (step == 0) {
+ if (start > stop) {
+ step = -1;
+ } else {
+ step = 1;
+ }
+ }
+ if ((start > stop && step > 0) || (start < stop && step < 0) ||
+ step == 0) {
+ std::ostringstream str;
+ str << "called with incorrect range specification: start ";
+ str << start << ", stop " << stop << ", step " << step;
+ this->SetError(str.str());
+ return false;
+ }
+ std::vector<std::string> range;
+ char buffer[100];
+ range.push_back(args[0]);
+ int cc;
+ for (cc = start;; cc += step) {
+ if ((step > 0 && cc > stop) || (step < 0 && cc < stop)) {
+ break;
+ }
+ sprintf(buffer, "%d", cc);
+ range.push_back(buffer);
+ if (cc == stop) {
+ break;
+ }
+ }
+ f->Args = range;
+ } else {
+ f->Args = args;
+ }
+ } else {
+ f->Args = args;
+ }
+ this->Makefile->AddFunctionBlocker(f);
+
+ return true;
+}
+
+bool cmForEachCommand::HandleInMode(std::vector<std::string> const& args)
+{
+ CM_AUTO_PTR<cmForEachFunctionBlocker> f(
+ new cmForEachFunctionBlocker(this->Makefile));
+ f->Args.push_back(args[0]);
+
+ enum Doing
+ {
+ DoingNone,
+ DoingLists,
+ DoingItems
+ };
+ Doing doing = DoingNone;
+ for (unsigned int i = 2; i < args.size(); ++i) {
+ if (doing == DoingItems) {
+ f->Args.push_back(args[i]);
+ } else if (args[i] == "LISTS") {
+ doing = DoingLists;
+ } else if (args[i] == "ITEMS") {
+ doing = DoingItems;
+ } else if (doing == DoingLists) {
+ const char* value = this->Makefile->GetDefinition(args[i]);
+ if (value && *value) {
+ cmSystemTools::ExpandListArgument(value, f->Args, true);
+ }
+ } else {
+ std::ostringstream e;
+ e << "Unknown argument:\n"
+ << " " << args[i] << "\n";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return true;
+ }
+ }
+
+ this->Makefile->AddFunctionBlocker(f.release()); // TODO: pass auto_ptr
+
+ return true;
+}
diff --git a/Source/cmForEachCommand.h b/Source/cmForEachCommand.h
new file mode 100644
index 0000000..887e6e9
--- /dev/null
+++ b/Source/cmForEachCommand.h
@@ -0,0 +1,69 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmForEachCommand_h
+#define cmForEachCommand_h
+
+#include "cmCommand.h"
+
+#include "cmFunctionBlocker.h"
+#include "cmListFileCache.h"
+
+class cmForEachFunctionBlocker : public cmFunctionBlocker
+{
+public:
+ cmForEachFunctionBlocker(cmMakefile* mf);
+ ~cmForEachFunctionBlocker() CM_OVERRIDE;
+ bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf,
+ cmExecutionStatus&) CM_OVERRIDE;
+ bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) CM_OVERRIDE;
+
+ std::vector<std::string> Args;
+ std::vector<cmListFileFunction> Functions;
+
+private:
+ cmMakefile* Makefile;
+ int Depth;
+};
+
+/// Starts foreach() ... endforeach() block
+class cmForEachCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmForEachCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "foreach"; }
+
+ cmTypeMacro(cmForEachCommand, cmCommand);
+
+private:
+ bool HandleInMode(std::vector<std::string> const& args);
+};
+
+#endif
diff --git a/Source/cmFortranLexer.cxx b/Source/cmFortranLexer.cxx
new file mode 100644
index 0000000..7cde4cb
--- /dev/null
+++ b/Source/cmFortranLexer.cxx
@@ -0,0 +1,2431 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#line 2 "cmFortranLexer.cxx"
+
+#line 4 "cmFortranLexer.cxx"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 39
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE cmFortran_yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+ #define YY_LINENO_REWIND_TO(ptr)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via cmFortran_yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void cmFortran_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void cmFortran_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmFortran_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void cmFortran_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmFortran_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmFortran_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void cmFortran_yypop_buffer_state (yyscan_t yyscanner );
+
+static void cmFortran_yyensure_buffer_stack (yyscan_t yyscanner );
+static void cmFortran_yy_load_buffer_state (yyscan_t yyscanner );
+static void cmFortran_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER cmFortran_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE cmFortran_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmFortran_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmFortran_yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+void *cmFortran_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *cmFortran_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void cmFortran_yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer cmFortran_yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ cmFortran_yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ cmFortran_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ cmFortran_yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ cmFortran_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cmFortran_yywrap(yyscanner) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 45
+#define YY_END_OF_BUFFER 46
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[173] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 46, 40, 42, 41, 44, 1, 40, 33, 2, 35,
+ 40, 41, 38, 40, 39, 40, 39, 42, 40, 41,
+ 40, 39, 9, 8, 9, 4, 3, 40, 0, 10,
+ 0, 0, 0, 0, 0, 33, 33, 34, 36, 38,
+ 40, 39, 0, 43, 39, 0, 0, 0, 12, 0,
+ 0, 0, 0, 0, 0, 40, 0, 11, 39, 0,
+ 0, 5, 0, 0, 0, 29, 0, 0, 33, 33,
+ 33, 33, 0, 0, 12, 12, 0, 0, 0, 23,
+ 0, 0, 0, 0, 0, 0, 6, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 30, 31,
+ 0, 0, 0, 0, 0, 0, 0, 24, 25, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 32, 27,
+ 0, 0, 20, 0, 0, 26, 21, 0, 0, 0,
+ 19, 0, 0, 18, 28, 0, 0, 17, 22, 0,
+ 7, 37, 7, 15, 0, 14, 16, 0, 0, 0,
+ 13, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 5, 6, 7, 8, 9, 1, 10, 11, 1,
+ 1, 12, 1, 13, 1, 1, 1, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 15, 16, 17,
+ 18, 19, 20, 1, 21, 21, 22, 23, 24, 25,
+ 21, 21, 26, 21, 21, 27, 21, 28, 21, 21,
+ 21, 21, 29, 21, 30, 21, 21, 21, 21, 21,
+ 1, 31, 1, 1, 32, 1, 21, 21, 33, 34,
+
+ 35, 36, 21, 21, 37, 21, 21, 38, 21, 39,
+ 21, 21, 21, 21, 40, 21, 41, 21, 21, 21,
+ 21, 21, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[42] =
+ { 0,
+ 1, 2, 2, 3, 4, 3, 3, 1, 1, 3,
+ 3, 1, 3, 5, 1, 3, 1, 3, 6, 1,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 1, 5, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7
+ } ;
+
+static yyconst flex_int16_t yy_base[182] =
+ { 0,
+ 0, 40, 0, 41, 220, 48, 44, 54, 56, 65,
+ 220, 0, 535, 535, 216, 535, 81, 74, 535, 535,
+ 186, 535, 153, 145, 0, 85, 122, 87, 154, 155,
+ 195, 227, 535, 147, 91, 535, 535, 0, 147, 535,
+ 267, 34, 70, 74, 34, 122, 141, 535, 0, 535,
+ 112, 0, 98, 535, 0, 156, 307, 0, 143, 43,
+ 155, 151, 48, 101, 130, 348, 130, 535, 0, 121,
+ 197, 165, 172, 244, 182, 183, 191, 248, 273, 293,
+ 308, 314, 321, 246, 275, 216, 269, 299, 304, 327,
+ 307, 304, 312, 116, 107, 367, 535, 327, 334, 347,
+
+ 347, 350, 352, 349, 354, 359, 357, 363, 366, 365,
+ 369, 372, 369, 373, 374, 101, 86, 372, 535, 535,
+ 378, 380, 386, 382, 388, 388, 389, 535, 535, 393,
+ 394, 396, 392, 430, 400, 56, 47, 403, 535, 535,
+ 409, 414, 535, 409, 416, 535, 535, 416, 419, 441,
+ 535, 117, 0, 535, 535, 423, 426, 535, 535, 430,
+ 535, 535, 535, 535, 432, 457, 535, 459, 0, 25,
+ 535, 535, 476, 483, 489, 492, 499, 506, 513, 520,
+ 527
+ } ;
+
+static yyconst flex_int16_t yy_def[182] =
+ { 0,
+ 172, 1, 1, 1, 1, 1, 173, 173, 173, 173,
+ 172, 174, 172, 172, 175, 172, 174, 172, 172, 172,
+ 174, 172, 172, 174, 176, 174, 176, 172, 172, 172,
+ 177, 172, 172, 172, 172, 172, 172, 174, 175, 172,
+ 172, 172, 172, 172, 172, 172, 178, 172, 174, 172,
+ 174, 176, 172, 172, 27, 172, 172, 57, 174, 172,
+ 172, 172, 172, 172, 172, 177, 177, 172, 32, 172,
+ 172, 172, 172, 172, 172, 172, 172, 172, 178, 178,
+ 178, 178, 172, 172, 172, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+
+ 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+ 172, 179, 180, 172, 172, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172, 172, 172, 181, 181,
+ 172, 0, 172, 172, 172, 172, 172, 172, 172, 172,
+ 172
+ } ;
+
+static yyconst flex_int16_t yy_nxt[577] =
+ { 0,
+ 12, 13, 14, 13, 13, 15, 16, 12, 17, 18,
+ 19, 12, 20, 12, 21, 22, 12, 23, 12, 24,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 26, 27, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 28, 28, 171, 28, 28, 34, 29, 29, 28,
+ 30, 153, 28, 35, 36, 29, 34, 73, 34, 31,
+ 152, 78, 37, 35, 36, 35, 87, 34, 73, 32,
+ 32, 37, 78, 92, 35, 46, 46, 87, 46, 47,
+ 32, 32, 41, 48, 92, 41, 53, 54, 56, 53,
+ 137, 56, 71, 72, 57, 71, 74, 75, 76, 53,
+
+ 54, 77, 53, 42, 43, 136, 44, 74, 75, 76,
+ 45, 117, 77, 83, 42, 43, 83, 44, 162, 162,
+ 116, 45, 38, 46, 46, 95, 46, 47, 93, 38,
+ 38, 48, 68, 38, 94, 55, 38, 84, 38, 93,
+ 38, 38, 80, 46, 86, 80, 81, 86, 84, 40,
+ 82, 70, 38, 55, 38, 58, 59, 56, 58, 65,
+ 56, 38, 38, 57, 51, 38, 96, 59, 38, 96,
+ 38, 50, 38, 38, 97, 90, 60, 61, 91, 62,
+ 63, 88, 89, 64, 38, 38, 90, 60, 61, 91,
+ 62, 63, 88, 89, 64, 66, 98, 68, 71, 72,
+
+ 49, 71, 66, 66, 101, 102, 66, 98, 66, 66,
+ 103, 66, 104, 66, 66, 101, 102, 86, 40, 172,
+ 86, 103, 30, 104, 172, 66, 66, 67, 67, 68,
+ 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+ 69, 67, 67, 67, 67, 67, 67, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 67, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69, 41, 99,
+ 105, 41, 100, 106, 80, 46, 86, 80, 81, 86,
+ 99, 105, 82, 100, 106, 172, 172, 172, 85, 42,
+ 43, 172, 44, 107, 80, 46, 45, 80, 81, 172,
+
+ 42, 43, 82, 44, 107, 172, 172, 45, 58, 80,
+ 46, 58, 80, 81, 172, 80, 46, 82, 80, 81,
+ 85, 172, 83, 82, 108, 83, 110, 109, 113, 60,
+ 61, 114, 62, 63, 115, 108, 64, 110, 109, 113,
+ 60, 61, 114, 62, 63, 115, 84, 64, 66, 111,
+ 68, 172, 118, 172, 112, 66, 66, 84, 119, 66,
+ 111, 66, 66, 118, 66, 112, 66, 66, 96, 119,
+ 120, 96, 121, 122, 123, 124, 97, 125, 66, 66,
+ 126, 120, 127, 121, 122, 123, 124, 128, 125, 129,
+ 130, 126, 131, 127, 132, 133, 134, 135, 128, 138,
+
+ 129, 130, 139, 131, 140, 132, 133, 134, 135, 141,
+ 138, 142, 143, 139, 144, 140, 145, 146, 147, 148,
+ 141, 149, 142, 143, 151, 144, 154, 145, 146, 147,
+ 148, 150, 149, 155, 150, 151, 156, 154, 157, 158,
+ 159, 160, 150, 85, 155, 150, 164, 156, 165, 157,
+ 158, 159, 160, 166, 85, 167, 172, 164, 168, 165,
+ 168, 168, 172, 168, 166, 172, 167, 172, 172, 172,
+ 172, 172, 172, 169, 172, 169, 33, 33, 33, 33,
+ 33, 33, 33, 38, 172, 172, 172, 38, 38, 39,
+ 39, 39, 39, 39, 39, 39, 52, 172, 52, 67,
+
+ 67, 67, 67, 67, 67, 67, 79, 79, 79, 79,
+ 79, 79, 79, 161, 161, 161, 172, 161, 161, 161,
+ 163, 172, 163, 172, 163, 163, 163, 170, 170, 170,
+ 170, 170, 172, 170, 11, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172
+ } ;
+
+static yyconst flex_int16_t yy_chk[577] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 170, 2, 4, 7, 2, 4, 6,
+ 6, 137, 6, 7, 7, 6, 8, 42, 9, 6,
+ 136, 45, 9, 8, 8, 9, 60, 10, 42, 6,
+ 6, 10, 45, 63, 10, 18, 18, 60, 18, 18,
+ 6, 6, 17, 18, 63, 17, 26, 26, 28, 26,
+ 117, 28, 35, 35, 28, 35, 43, 43, 44, 53,
+
+ 53, 44, 53, 17, 17, 116, 17, 43, 43, 44,
+ 17, 95, 44, 51, 17, 17, 51, 17, 152, 152,
+ 94, 17, 27, 46, 46, 70, 46, 46, 64, 27,
+ 27, 46, 67, 27, 65, 27, 27, 51, 27, 64,
+ 27, 27, 47, 47, 59, 47, 47, 59, 51, 39,
+ 47, 34, 27, 27, 29, 29, 59, 56, 29, 30,
+ 56, 29, 29, 56, 24, 29, 72, 29, 29, 72,
+ 29, 23, 29, 29, 72, 62, 29, 29, 62, 29,
+ 29, 61, 61, 29, 29, 29, 62, 29, 29, 62,
+ 29, 29, 61, 61, 29, 31, 73, 31, 71, 71,
+
+ 21, 71, 31, 31, 75, 76, 31, 73, 31, 31,
+ 76, 31, 77, 31, 31, 75, 76, 86, 15, 11,
+ 86, 76, 5, 77, 0, 31, 31, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 41, 74,
+ 78, 41, 74, 84, 79, 79, 85, 79, 79, 85,
+ 74, 78, 79, 74, 84, 0, 0, 0, 85, 41,
+ 41, 0, 41, 87, 80, 80, 41, 80, 80, 0,
+
+ 41, 41, 80, 41, 87, 0, 0, 41, 57, 81,
+ 81, 57, 81, 81, 0, 82, 82, 81, 82, 82,
+ 57, 0, 83, 82, 88, 83, 89, 88, 91, 57,
+ 57, 92, 57, 57, 93, 88, 57, 89, 88, 91,
+ 57, 57, 92, 57, 57, 93, 83, 57, 66, 90,
+ 66, 0, 98, 0, 90, 66, 66, 83, 99, 66,
+ 90, 66, 66, 98, 66, 90, 66, 66, 96, 99,
+ 100, 96, 101, 102, 103, 104, 96, 105, 66, 66,
+ 106, 100, 107, 101, 102, 103, 104, 108, 105, 109,
+ 110, 106, 111, 107, 112, 113, 114, 115, 108, 118,
+
+ 109, 110, 121, 111, 122, 112, 113, 114, 115, 123,
+ 118, 124, 125, 121, 126, 122, 127, 130, 131, 132,
+ 123, 133, 124, 125, 135, 126, 138, 127, 130, 131,
+ 132, 134, 133, 141, 134, 135, 142, 138, 144, 145,
+ 148, 149, 150, 134, 141, 150, 156, 142, 157, 144,
+ 145, 148, 149, 160, 150, 165, 0, 156, 166, 157,
+ 168, 166, 0, 168, 160, 0, 165, 0, 0, 0,
+ 0, 0, 0, 166, 0, 168, 173, 173, 173, 173,
+ 173, 173, 173, 174, 0, 0, 0, 174, 174, 175,
+ 175, 175, 175, 175, 175, 175, 176, 0, 176, 177,
+
+ 177, 177, 177, 177, 177, 177, 178, 178, 178, 178,
+ 178, 178, 178, 179, 179, 179, 0, 179, 179, 179,
+ 180, 0, 180, 0, 180, 180, 180, 181, 181, 181,
+ 181, 181, 0, 181, 172, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+ 172, 172, 172, 172, 172, 172
+ } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "cmFortranLexer.in.l"
+#line 2 "cmFortranLexer.in.l"
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*-------------------------------------------------------------------------
+ Portions of this source have been derived from makedepf90 version 2.8.8,
+
+ Copyright (C) 2000--2006 Erik Edelmann <erik.edelmann@iki.fi>
+
+ The code was originally distributed under the GPL but permission
+ from the copyright holder has been obtained to distribute this
+ derived work under the CMake license.
+-------------------------------------------------------------------------*/
+
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run flex like this:
+
+ flex -i --prefix=cmFortran_yy --header-file=cmFortranLexer.h -ocmFortranLexer.cxx cmFortranLexer.in.l
+
+Modify cmFortranLexer.cxx:
+ - remove TABs
+ - remove use of the 'register' storage class specifier
+ - remove "yyscanner" argument from these methods:
+ yy_fatal_error, cmFortran_yyalloc, cmFortran_yyrealloc, cmFortran_yyfree
+ - remove "yyscanner = NULL" from end of cmFortran_yylex_destroy
+ - remove all YY_BREAK lines occurring right after return statements
+ - change while ( 1 ) to for(;;)
+
+Modify cmFortranLexer.h:
+ - remove TABs
+ - remove the yy_init_globals function
+ - remove the block that includes unistd.h
+ - remove #line directives (avoids bogus warning on old Sun)
+
+*/
+
+#include "cmStandardLexer.h"
+
+#define cmFortranLexer_cxx
+#include "cmFortranParser.h" /* Interface to parser object. */
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ { result = cmFortranParser_Input(yyextra, buf, max_size); }
+
+/* Include the set of tokens from the parser. */
+#include "cmFortranParserTokens.h"
+
+/*--------------------------------------------------------------------------*/
+
+
+#line 689 "cmFortranLexer.cxx"
+
+#define INITIAL 0
+#define free_fmt 1
+#define fixed_fmt 2
+#define str_sq 3
+#define str_dq 4
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ yy_size_t yy_n_chars;
+ yy_size_t yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+int cmFortran_yylex_init (yyscan_t* scanner);
+
+int cmFortran_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int cmFortran_yylex_destroy (yyscan_t yyscanner );
+
+int cmFortran_yyget_debug (yyscan_t yyscanner );
+
+void cmFortran_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE cmFortran_yyget_extra (yyscan_t yyscanner );
+
+void cmFortran_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *cmFortran_yyget_in (yyscan_t yyscanner );
+
+void cmFortran_yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *cmFortran_yyget_out (yyscan_t yyscanner );
+
+void cmFortran_yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+yy_size_t cmFortran_yyget_leng (yyscan_t yyscanner );
+
+char *cmFortran_yyget_text (yyscan_t yyscanner );
+
+int cmFortran_yyget_lineno (yyscan_t yyscanner );
+
+void cmFortran_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+int cmFortran_yyget_column (yyscan_t yyscanner );
+
+void cmFortran_yyset_column (int column_no ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int cmFortran_yywrap (yyscan_t yyscanner );
+#else
+extern int cmFortran_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+ static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner);
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int cmFortran_yylex (yyscan_t yyscanner);
+
+#define YY_DECL int cmFortran_yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ if ( yyleng > 0 ) \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+ (yytext[yyleng - 1] == '\n'); \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ cmFortran_yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ cmFortran_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ cmFortran_yy_load_buffer_state(yyscanner );
+ }
+
+ {
+#line 72 "cmFortranLexer.in.l"
+
+
+#line 956 "cmFortranLexer.cxx"
+
+ for(;;) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+ yy_current_state += YY_AT_BOL();
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 173 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 535 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 74 "cmFortranLexer.in.l"
+{
+ cmFortranParser_StringStart(yyextra);
+ cmFortranParser_SetOldStartcond(yyextra, YY_START);
+ BEGIN(str_dq);
+}
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 80 "cmFortranLexer.in.l"
+{
+ cmFortranParser_StringStart(yyextra);
+ cmFortranParser_SetOldStartcond(yyextra, YY_START);
+ BEGIN(str_sq);
+}
+ YY_BREAK
+case 3:
+#line 87 "cmFortranLexer.in.l"
+case 4:
+YY_RULE_SETUP
+#line 87 "cmFortranLexer.in.l"
+{
+ BEGIN(cmFortranParser_GetOldStartcond(yyextra) );
+ yylvalp->string = strdup(cmFortranParser_StringEnd(yyextra));
+ return STRING;
+}
+case 5:
+/* rule 5 can match eol */
+#line 94 "cmFortranLexer.in.l"
+case 6:
+/* rule 6 can match eol */
+YY_RULE_SETUP
+#line 94 "cmFortranLexer.in.l"
+/* Ignore (continued strings, free fmt) */
+ YY_BREAK
+case 7:
+/* rule 7 can match eol */
+YY_RULE_SETUP
+#line 96 "cmFortranLexer.in.l"
+{
+ if (cmFortranParser_GetOldStartcond(yyextra) == fixed_fmt)
+ ; /* Ignore (cont. strings, fixed fmt) */
+ else
+ {
+ unput(yytext[strlen(yytext)-1]);
+ }
+}
+ YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+#line 106 "cmFortranLexer.in.l"
+{
+ unput ('\n');
+ BEGIN(INITIAL);
+ return UNTERMINATED_STRING;
+}
+case 9:
+YY_RULE_SETUP
+#line 112 "cmFortranLexer.in.l"
+{
+ cmFortranParser_StringAppend(yyextra, yytext[0]);
+}
+ YY_BREAK
+case 10:
+/* rule 10 can match eol */
+YY_RULE_SETUP
+#line 116 "cmFortranLexer.in.l"
+{ return EOSTMT; } /* Treat comments like */
+case 11:
+/* rule 11 can match eol */
+YY_RULE_SETUP
+#line 117 "cmFortranLexer.in.l"
+{ return EOSTMT; } /* empty lines */
+case 12:
+YY_RULE_SETUP
+#line 119 "cmFortranLexer.in.l"
+{ return CPP_LINE_DIRECTIVE; }
+case 13:
+/* rule 13 can match eol */
+YY_RULE_SETUP
+#line 120 "cmFortranLexer.in.l"
+{
+ yytext[yyleng-1] = 0;
+ yylvalp->string = strdup(strchr(yytext, '<')+1);
+ return CPP_INCLUDE_ANGLE;
+}
+case 14:
+YY_RULE_SETUP
+#line 125 "cmFortranLexer.in.l"
+{ return CPP_INCLUDE; }
+case 15:
+YY_RULE_SETUP
+#line 126 "cmFortranLexer.in.l"
+{ return F90PPR_INCLUDE; }
+case 16:
+YY_RULE_SETUP
+#line 127 "cmFortranLexer.in.l"
+{ return COCO_INCLUDE; }
+case 17:
+YY_RULE_SETUP
+#line 129 "cmFortranLexer.in.l"
+{ return CPP_DEFINE; }
+case 18:
+YY_RULE_SETUP
+#line 130 "cmFortranLexer.in.l"
+{ return F90PPR_DEFINE; }
+case 19:
+YY_RULE_SETUP
+#line 132 "cmFortranLexer.in.l"
+{ return CPP_UNDEF; }
+case 20:
+YY_RULE_SETUP
+#line 133 "cmFortranLexer.in.l"
+{ return F90PPR_UNDEF; }
+case 21:
+YY_RULE_SETUP
+#line 135 "cmFortranLexer.in.l"
+{ return CPP_IFDEF; }
+case 22:
+YY_RULE_SETUP
+#line 136 "cmFortranLexer.in.l"
+{ return CPP_IFNDEF; }
+case 23:
+YY_RULE_SETUP
+#line 137 "cmFortranLexer.in.l"
+{ return CPP_IF; }
+case 24:
+YY_RULE_SETUP
+#line 138 "cmFortranLexer.in.l"
+{ return CPP_ELIF; }
+case 25:
+YY_RULE_SETUP
+#line 139 "cmFortranLexer.in.l"
+{ return CPP_ELSE; }
+case 26:
+YY_RULE_SETUP
+#line 140 "cmFortranLexer.in.l"
+{ return CPP_ENDIF; }
+case 27:
+YY_RULE_SETUP
+#line 142 "cmFortranLexer.in.l"
+{ return F90PPR_IFDEF; }
+case 28:
+YY_RULE_SETUP
+#line 143 "cmFortranLexer.in.l"
+{ return F90PPR_IFNDEF; }
+case 29:
+YY_RULE_SETUP
+#line 144 "cmFortranLexer.in.l"
+{ return F90PPR_IF; }
+case 30:
+YY_RULE_SETUP
+#line 145 "cmFortranLexer.in.l"
+{ return F90PPR_ELIF; }
+case 31:
+YY_RULE_SETUP
+#line 146 "cmFortranLexer.in.l"
+{ return F90PPR_ELSE; }
+case 32:
+YY_RULE_SETUP
+#line 147 "cmFortranLexer.in.l"
+{ return F90PPR_ENDIF; }
+/* Line continuations, possible involving comments. */
+case 33:
+/* rule 33 can match eol */
+YY_RULE_SETUP
+#line 150 "cmFortranLexer.in.l"
+
+ YY_BREAK
+case 34:
+/* rule 34 can match eol */
+YY_RULE_SETUP
+#line 151 "cmFortranLexer.in.l"
+
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 153 "cmFortranLexer.in.l"
+{ return COMMA; }
+case 36:
+YY_RULE_SETUP
+#line 155 "cmFortranLexer.in.l"
+{ return DCOLON; }
+case 37:
+/* rule 37 can match eol */
+YY_RULE_SETUP
+#line 157 "cmFortranLexer.in.l"
+{ return GARBAGE; }
+case 38:
+YY_RULE_SETUP
+#line 159 "cmFortranLexer.in.l"
+{ return ASSIGNMENT_OP; }
+case 39:
+YY_RULE_SETUP
+#line 161 "cmFortranLexer.in.l"
+{
+ yylvalp->string = strdup(yytext);
+ return WORD;
+}
+case 40:
+YY_RULE_SETUP
+#line 166 "cmFortranLexer.in.l"
+{ return GARBAGE; }
+case 41:
+/* rule 41 can match eol */
+YY_RULE_SETUP
+#line 168 "cmFortranLexer.in.l"
+{ return EOSTMT; }
+case 42:
+YY_RULE_SETUP
+#line 171 "cmFortranLexer.in.l"
+/* Ignore */
+ YY_BREAK
+case 43:
+/* rule 43 can match eol */
+YY_RULE_SETUP
+#line 172 "cmFortranLexer.in.l"
+/* Ignore line-endings preceded by \ */
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 174 "cmFortranLexer.in.l"
+{ return *yytext; }
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(free_fmt):
+case YY_STATE_EOF(fixed_fmt):
+case YY_STATE_EOF(str_sq):
+case YY_STATE_EOF(str_dq):
+#line 176 "cmFortranLexer.in.l"
+{
+ if(!cmFortranParser_FilePop(yyextra) )
+ {
+ return YY_NULL;
+ }
+}
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 183 "cmFortranLexer.in.l"
+ECHO;
+ YY_BREAK
+#line 1291 "cmFortranLexer.cxx"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * cmFortran_yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( cmFortran_yywrap(yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of cmFortran_yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ cmFortran_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ cmFortran_yyrestart(yyin ,yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) cmFortran_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+ yy_current_state += YY_AT_BOL();
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 173 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 173 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 172);
+
+ (void)yyg;
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ static void yyunput (int c, char * yy_bp , yyscan_t yyscanner)
+{
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yyg->yy_hold_char;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ yy_size_t number_to_move = yyg->yy_n_chars + 2;
+ char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ yyg->yytext_ptr = yy_bp;
+ yyg->yy_hold_char = *yy_cp;
+ yyg->yy_c_buf_p = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ cmFortran_yyrestart(yyin ,yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( cmFortran_yywrap(yyscanner ) )
+ return EOF;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void cmFortran_yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ cmFortran_yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ cmFortran_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ cmFortran_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+ cmFortran_yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void cmFortran_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * cmFortran_yypop_buffer_state();
+ * cmFortran_yypush_buffer_state(new_buffer);
+ */
+ cmFortran_yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ cmFortran_yy_load_buffer_state(yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (cmFortran_yywrap()) processing, but the only time this flag
+ * is looked at is after cmFortran_yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void cmFortran_yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE cmFortran_yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) cmFortran_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in cmFortran_yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) cmFortran_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in cmFortran_yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ cmFortran_yy_init_buffer(b,file ,yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with cmFortran_yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void cmFortran_yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ cmFortran_yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+ cmFortran_yyfree((void *) b ,yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a cmFortran_yyrestart() or at EOF.
+ */
+ static void cmFortran_yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ cmFortran_yy_flush_buffer(b ,yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then cmFortran_yy_init_buffer was _probably_
+ * called from cmFortran_yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void cmFortran_yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ cmFortran_yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void cmFortran_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ cmFortran_yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from cmFortran_yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from cmFortran_yy_switch_to_buffer. */
+ cmFortran_yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void cmFortran_yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ cmFortran_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ cmFortran_yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void cmFortran_yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)cmFortran_yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in cmFortran_yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)cmFortran_yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in cmFortran_yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cmFortran_yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) cmFortran_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in cmFortran_yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ cmFortran_yy_switch_to_buffer(b ,yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to cmFortran_yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * cmFortran_yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE cmFortran_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+
+ return cmFortran_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to cmFortran_yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cmFortran_yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ yy_size_t i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) cmFortran_yyalloc(n ,yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in cmFortran_yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = cmFortran_yy_scan_buffer(buf,n ,yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in cmFortran_yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t)
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE cmFortran_yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int cmFortran_yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int cmFortran_yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *cmFortran_yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *cmFortran_yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+yy_size_t cmFortran_yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *cmFortran_yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void cmFortran_yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number The line number to set.
+ * @param yyscanner The scanner object.
+ */
+void cmFortran_yyset_lineno (int line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "cmFortran_yyset_lineno called with no buffer" );
+
+ yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param column_no The column number to set.
+ * @param yyscanner The scanner object.
+ */
+void cmFortran_yyset_column (int column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "cmFortran_yyset_column called with no buffer" );
+
+ yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see cmFortran_yy_switch_to_buffer
+ */
+void cmFortran_yyset_in (FILE * in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = in_str ;
+}
+
+void cmFortran_yyset_out (FILE * out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = out_str ;
+}
+
+int cmFortran_yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void cmFortran_yyset_debug (int bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+/* User-visible API */
+
+/* cmFortran_yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int cmFortran_yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) cmFortran_yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* cmFortran_yylex_init_extra has the same functionality as cmFortran_yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to cmFortran_yyalloc in
+ * the yyextra field.
+ */
+
+int cmFortran_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+ struct yyguts_t dummy_yyguts;
+
+ cmFortran_yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) cmFortran_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ cmFortran_yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from cmFortran_yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = 0;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = (char *) 0;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * cmFortran_yylex_init()
+ */
+ return 0;
+}
+
+/* cmFortran_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int cmFortran_yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ cmFortran_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ cmFortran_yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ cmFortran_yyfree(yyg->yy_buffer_stack ,yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ cmFortran_yyfree(yyg->yy_start_stack ,yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * cmFortran_yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ cmFortran_yyfree ( yyscanner , yyscanner );
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *cmFortran_yyalloc (yy_size_t size , yyscan_t)
+{
+ return (void *) malloc( size );
+}
+
+void *cmFortran_yyrealloc (void * ptr, yy_size_t size , yyscan_t)
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void cmFortran_yyfree (void * ptr , yyscan_t)
+{
+ free( (char *) ptr ); /* see cmFortran_yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 182 "cmFortranLexer.in.l"
+
+
+
+/*--------------------------------------------------------------------------*/
+YY_BUFFER_STATE cmFortranLexer_GetCurrentBuffer(yyscan_t yyscanner)
+{
+ /* Hack into the internal flex-generated scanner to get the buffer. */
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return YY_CURRENT_BUFFER;
+}
diff --git a/Source/cmFortranLexer.h b/Source/cmFortranLexer.h
new file mode 100644
index 0000000..b9ff0dc
--- /dev/null
+++ b/Source/cmFortranLexer.h
@@ -0,0 +1,352 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFortran_yyHEADER_H
+#define cmFortran_yyHEADER_H 1
+#define cmFortran_yyIN_HEADER 1
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 39
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void cmFortran_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void cmFortran_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmFortran_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void cmFortran_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmFortran_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmFortran_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void cmFortran_yypop_buffer_state (yyscan_t yyscanner );
+
+YY_BUFFER_STATE cmFortran_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmFortran_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmFortran_yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+void *cmFortran_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *cmFortran_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void cmFortran_yyfree (void * ,yyscan_t yyscanner );
+
+/* Begin user sect3 */
+
+#define cmFortran_yywrap(yyscanner) 1
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+#define free_fmt 1
+#define fixed_fmt 2
+#define str_sq 3
+#define str_dq 4
+
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+int cmFortran_yylex_init (yyscan_t* scanner);
+
+int cmFortran_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int cmFortran_yylex_destroy (yyscan_t yyscanner );
+
+int cmFortran_yyget_debug (yyscan_t yyscanner );
+
+void cmFortran_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE cmFortran_yyget_extra (yyscan_t yyscanner );
+
+void cmFortran_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *cmFortran_yyget_in (yyscan_t yyscanner );
+
+void cmFortran_yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *cmFortran_yyget_out (yyscan_t yyscanner );
+
+void cmFortran_yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+yy_size_t cmFortran_yyget_leng (yyscan_t yyscanner );
+
+char *cmFortran_yyget_text (yyscan_t yyscanner );
+
+int cmFortran_yyget_lineno (yyscan_t yyscanner );
+
+void cmFortran_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+int cmFortran_yyget_column (yyscan_t yyscanner );
+
+void cmFortran_yyset_column (int column_no ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int cmFortran_yywrap (yyscan_t yyscanner );
+#else
+extern int cmFortran_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int cmFortran_yylex (yyscan_t yyscanner);
+
+#define YY_DECL int cmFortran_yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#undef cmFortran_yyIN_HEADER
+#endif /* cmFortran_yyHEADER_H */
diff --git a/Source/cmFortranLexer.in.l b/Source/cmFortranLexer.in.l
new file mode 100644
index 0000000..e59ff5f
--- /dev/null
+++ b/Source/cmFortranLexer.in.l
@@ -0,0 +1,191 @@
+%{
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*-------------------------------------------------------------------------
+ Portions of this source have been derived from makedepf90 version 2.8.8,
+
+ Copyright (C) 2000--2006 Erik Edelmann <erik.edelmann@iki.fi>
+
+ The code was originally distributed under the GPL but permission
+ from the copyright holder has been obtained to distribute this
+ derived work under the CMake license.
+-------------------------------------------------------------------------*/
+
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run flex like this:
+
+ flex -i --prefix=cmFortran_yy --header-file=cmFortranLexer.h -ocmFortranLexer.cxx cmFortranLexer.in.l
+
+Modify cmFortranLexer.cxx:
+ - remove TABs
+ - remove use of the 'register' storage class specifier
+ - remove "yyscanner" argument from these methods:
+ yy_fatal_error, cmFortran_yyalloc, cmFortran_yyrealloc, cmFortran_yyfree
+ - remove "yyscanner = NULL" from end of cmFortran_yylex_destroy
+ - remove all YY_BREAK lines occurring right after return statements
+ - change while ( 1 ) to for(;;)
+
+Modify cmFortranLexer.h:
+ - remove TABs
+ - remove the yy_init_globals function
+ - remove the block that includes unistd.h
+ - remove #line directives (avoids bogus warning on old Sun)
+
+*/
+
+#include "cmStandardLexer.h"
+
+#define cmFortranLexer_cxx
+#include "cmFortranParser.h" /* Interface to parser object. */
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ { result = cmFortranParser_Input(yyextra, buf, max_size); }
+
+/* Include the set of tokens from the parser. */
+#include "cmFortranParserTokens.h"
+
+/*--------------------------------------------------------------------------*/
+%}
+
+
+%option reentrant
+%option noyywrap
+%pointer
+
+%s free_fmt fixed_fmt
+%x str_sq str_dq
+
+%%
+
+\" {
+ cmFortranParser_StringStart(yyextra);
+ cmFortranParser_SetOldStartcond(yyextra, YY_START);
+ BEGIN(str_dq);
+}
+
+' {
+ cmFortranParser_StringStart(yyextra);
+ cmFortranParser_SetOldStartcond(yyextra, YY_START);
+ BEGIN(str_sq);
+}
+
+<str_dq>\" |
+<str_sq>' {
+ BEGIN(cmFortranParser_GetOldStartcond(yyextra) );
+ yylvalp->string = strdup(cmFortranParser_StringEnd(yyextra));
+ return STRING;
+}
+
+<str_dq,str_sq>&[ \t]*\n |
+<str_dq,str_sq>&[ \t]*\n[ \t]*& /* Ignore (continued strings, free fmt) */
+
+<fixed_fmt,str_dq,str_sq>\n[ ]{5}[^ \t\n] {
+ if (cmFortranParser_GetOldStartcond(yyextra) == fixed_fmt)
+ ; /* Ignore (cont. strings, fixed fmt) */
+ else
+ {
+ unput(yytext[strlen(yytext)-1]);
+ }
+}
+
+
+<str_dq,str_sq>\n {
+ unput ('\n');
+ BEGIN(INITIAL);
+ return UNTERMINATED_STRING;
+}
+
+<str_sq,str_dq>. {
+ cmFortranParser_StringAppend(yyextra, yytext[0]);
+}
+
+!.*\n { return EOSTMT; } /* Treat comments like */
+<fixed_fmt>^[cC*dD].*\n { return EOSTMT; } /* empty lines */
+
+^[ \t]*#([ \t]*line)?[ \t]*[0-9]+[ \t]* { return CPP_LINE_DIRECTIVE; }
+^[ \t]*#[ \t]*include[ \t]*<[^>]+> {
+ yytext[yyleng-1] = 0;
+ yylvalp->string = strdup(strchr(yytext, '<')+1);
+ return CPP_INCLUDE_ANGLE;
+}
+^[ \t]*#[ \t]*include { return CPP_INCLUDE; }
+\$[ \t]*include { return F90PPR_INCLUDE; }
+\?\?[ \t]*include { return COCO_INCLUDE; }
+
+^[ \t]*#[ \t]*define { return CPP_DEFINE; }
+\$[ \t]*DEFINE { return F90PPR_DEFINE; }
+
+^[ \t]*#[ \t]*undef { return CPP_UNDEF; }
+\$[ \t]*UNDEF { return F90PPR_UNDEF; }
+
+^[ \t]*#[ \t]*ifdef { return CPP_IFDEF; }
+^[ \t]*#[ \t]*ifndef { return CPP_IFNDEF; }
+^[ \t]*#[ \t]*if { return CPP_IF; }
+^[ \t]*#[ \t]*elif { return CPP_ELIF; }
+^[ \t]*#[ \t]*else { return CPP_ELSE; }
+^[ \t]*#[ \t]*endif { return CPP_ENDIF; }
+
+$[ \t]*ifdef { return F90PPR_IFDEF; }
+$[ \t]*ifndef { return F90PPR_IFNDEF; }
+$[ \t]*if { return F90PPR_IF; }
+$[ \t]*elif { return F90PPR_ELIF; }
+$[ \t]*else { return F90PPR_ELSE; }
+$[ \t]*endif { return F90PPR_ENDIF; }
+
+ /* Line continuations, possible involving comments. */
+&([ \t\n]*|!.*)*
+&([ \t\n]*|!.*)*&
+
+, { return COMMA; }
+
+:: { return DCOLON; }
+
+<fixed_fmt>\n[ ]{5}[^ ] { return GARBAGE; }
+
+=|=> { return ASSIGNMENT_OP; }
+
+[a-zA-Z_][a-zA-Z_0-9]* {
+ yylvalp->string = strdup(yytext);
+ return WORD;
+}
+
+[^ \t\n\r;,!'"a-zA-Z=&]+ { return GARBAGE; }
+
+;|\n { return EOSTMT; }
+
+
+[ \t\r,] /* Ignore */
+\\[ \t]*\n /* Ignore line-endings preceded by \ */
+
+. { return *yytext; }
+
+<<EOF>> {
+ if(!cmFortranParser_FilePop(yyextra) )
+ {
+ return YY_NULL;
+ }
+}
+
+%%
+
+/*--------------------------------------------------------------------------*/
+YY_BUFFER_STATE cmFortranLexer_GetCurrentBuffer(yyscan_t yyscanner)
+{
+ /* Hack into the internal flex-generated scanner to get the buffer. */
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return YY_CURRENT_BUFFER;
+}
diff --git a/Source/cmFortranParser.cxx b/Source/cmFortranParser.cxx
new file mode 100644
index 0000000..21a6443
--- /dev/null
+++ b/Source/cmFortranParser.cxx
@@ -0,0 +1,1916 @@
+/* A Bison parser, made by GNU Bison 3.0.2. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "3.0.2"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+/* Substitute the variable and function names. */
+#define yyparse cmFortran_yyparse
+#define yylex cmFortran_yylex
+#define yyerror cmFortran_yyerror
+#define yydebug cmFortran_yydebug
+#define yynerrs cmFortran_yynerrs
+
+
+/* Copy the first part of user declarations. */
+#line 1 "cmFortranParser.y" /* yacc.c:339 */
+
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*-------------------------------------------------------------------------
+ Portions of this source have been derived from makedepf90 version 2.8.8,
+
+ Copyright (C) 2000--2006 Erik Edelmann <erik.edelmann@iki.fi>
+
+ The code was originally distributed under the GPL but permission
+ from the copyright holder has been obtained to distribute this
+ derived work under the CMake license.
+-------------------------------------------------------------------------*/
+
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --yacc --name-prefix=cmFortran_yy
+ --defines=cmFortranParserTokens.h
+ -ocmFortranParser.cxx
+ cmFortranParser.y
+
+Modify cmFortranParser.cxx:
+ - "#if 0" out yyerrorlab block in range ["goto yyerrlab1", "yyerrlab1:"]
+*/
+
+/*-------------------------------------------------------------------------*/
+#define cmFortranParser_cxx
+#include "cmFortranParser.h" /* Interface to parser object. */
+#include "cmFortranParserTokens.h" /* Need YYSTYPE for YY_DECL. */
+
+#include <cmsys/String.h>
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Helper function to forward error callback from parser. */
+static void cmFortran_yyerror(yyscan_t yyscanner, const char* message)
+{
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_Error(parser, message);
+}
+
+static bool cmFortranParserIsKeyword(const char* word,
+ const char* keyword)
+{
+ return cmsysString_strcasecmp(word, keyword) == 0;
+}
+
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch contains default but no case. */
+# pragma warning (disable: 4701) /* Local variable may not be initialized. */
+# pragma warning (disable: 4702) /* Unreachable code. */
+# pragma warning (disable: 4127) /* Conditional expression is constant. */
+# pragma warning (disable: 4244) /* Conversion to smaller type, data loss. */
+#endif
+
+#line 143 "cmFortranParser.cxx" /* yacc.c:339 */
+
+# ifndef YY_NULLPTR
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULLPTR nullptr
+# else
+# define YY_NULLPTR 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "cmFortranParserTokens.h". */
+#ifndef YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED
+# define YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int cmFortran_yydebug;
+#endif
+
+/* Token type. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ EOSTMT = 258,
+ ASSIGNMENT_OP = 259,
+ GARBAGE = 260,
+ CPP_LINE_DIRECTIVE = 261,
+ CPP_INCLUDE = 262,
+ F90PPR_INCLUDE = 263,
+ COCO_INCLUDE = 264,
+ F90PPR_DEFINE = 265,
+ CPP_DEFINE = 266,
+ F90PPR_UNDEF = 267,
+ CPP_UNDEF = 268,
+ CPP_IFDEF = 269,
+ CPP_IFNDEF = 270,
+ CPP_IF = 271,
+ CPP_ELSE = 272,
+ CPP_ELIF = 273,
+ CPP_ENDIF = 274,
+ F90PPR_IFDEF = 275,
+ F90PPR_IFNDEF = 276,
+ F90PPR_IF = 277,
+ F90PPR_ELSE = 278,
+ F90PPR_ELIF = 279,
+ F90PPR_ENDIF = 280,
+ COMMA = 281,
+ DCOLON = 282,
+ CPP_TOENDL = 283,
+ UNTERMINATED_STRING = 284,
+ STRING = 285,
+ WORD = 286,
+ CPP_INCLUDE_ANGLE = 287
+ };
+#endif
+/* Tokens. */
+#define EOSTMT 258
+#define ASSIGNMENT_OP 259
+#define GARBAGE 260
+#define CPP_LINE_DIRECTIVE 261
+#define CPP_INCLUDE 262
+#define F90PPR_INCLUDE 263
+#define COCO_INCLUDE 264
+#define F90PPR_DEFINE 265
+#define CPP_DEFINE 266
+#define F90PPR_UNDEF 267
+#define CPP_UNDEF 268
+#define CPP_IFDEF 269
+#define CPP_IFNDEF 270
+#define CPP_IF 271
+#define CPP_ELSE 272
+#define CPP_ELIF 273
+#define CPP_ENDIF 274
+#define F90PPR_IFDEF 275
+#define F90PPR_IFNDEF 276
+#define F90PPR_IF 277
+#define F90PPR_ELSE 278
+#define F90PPR_ELIF 279
+#define F90PPR_ENDIF 280
+#define COMMA 281
+#define DCOLON 282
+#define CPP_TOENDL 283
+#define UNTERMINATED_STRING 284
+#define STRING 285
+#define WORD 286
+#define CPP_INCLUDE_ANGLE 287
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE YYSTYPE;
+union YYSTYPE
+{
+#line 81 "cmFortranParser.y" /* yacc.c:355 */
+
+ char* string;
+
+#line 251 "cmFortranParser.cxx" /* yacc.c:355 */
+};
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+
+int cmFortran_yyparse (yyscan_t yyscanner);
+
+#endif /* !YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED */
+
+/* Copy the second part of user declarations. */
+
+#line 265 "cmFortranParser.cxx" /* yacc.c:358 */
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE
+# if (defined __GNUC__ \
+ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \
+ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+# define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+# else
+# define YY_ATTRIBUTE(Spec) /* empty */
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_PURE
+# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__))
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+#endif
+
+#if !defined _Noreturn \
+ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
+# if defined _MSC_VER && 1200 <= _MSC_VER
+# define _Noreturn __declspec (noreturn)
+# else
+# define _Noreturn YY_ATTRIBUTE ((__noreturn__))
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's 'empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 290
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 33
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 16
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 54
+/* YYNSTATES -- Number of states. */
+#define YYNSTATES 101
+
+/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+ by yylex, with out-of-bounds checking. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 287
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex, without out-of-bounds checking. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32
+};
+
+#if YYDEBUG
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 104, 104, 104, 106, 106, 108, 114, 124, 154,
+ 165, 178, 189, 196, 203, 210, 216, 222, 228, 234,
+ 239, 244, 249, 254, 258, 259, 260, 265, 265, 265,
+ 266, 266, 267, 267, 268, 268, 269, 269, 270, 270,
+ 271, 271, 272, 272, 273, 273, 274, 274, 277, 278,
+ 279, 280, 281, 282, 283
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 1
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "EOSTMT", "ASSIGNMENT_OP", "GARBAGE",
+ "CPP_LINE_DIRECTIVE", "CPP_INCLUDE", "F90PPR_INCLUDE", "COCO_INCLUDE",
+ "F90PPR_DEFINE", "CPP_DEFINE", "F90PPR_UNDEF", "CPP_UNDEF", "CPP_IFDEF",
+ "CPP_IFNDEF", "CPP_IF", "CPP_ELSE", "CPP_ELIF", "CPP_ENDIF",
+ "F90PPR_IFDEF", "F90PPR_IFNDEF", "F90PPR_IF", "F90PPR_ELSE",
+ "F90PPR_ELIF", "F90PPR_ENDIF", "COMMA", "DCOLON", "CPP_TOENDL",
+ "UNTERMINATED_STRING", "STRING", "WORD", "CPP_INCLUDE_ANGLE", "$accept",
+ "code", "stmt", "assignment_stmt", "keyword_stmt", "include", "define",
+ "undef", "ifdef", "ifndef", "if", "elif", "else", "endif", "other",
+ "misc_code", YY_NULLPTR
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+ (internal) symbol number NUM (which must be that of a token). */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287
+};
+# endif
+
+#define YYPACT_NINF -30
+
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-30)))
+
+#define YYTABLE_NINF -1
+
+#define yytable_value_is_error(Yytable_value) \
+ 0
+
+ /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+static const yytype_int16 yypact[] =
+{
+ -30, 41, -30, -30, -30, -30, -29, -30, -30, -30,
+ -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
+ -30, -30, -30, -30, -30, -30, 259, -30, -30, -30,
+ -30, -28, -23, -18, -16, -13, -30, -30, -30, -30,
+ 2, -30, -30, -30, -30, -12, -9, -30, -30, 64,
+ -30, -30, -30, -30, -30, 71, 77, 83, 112, -30,
+ -30, -30, -30, -30, -30, -30, -30, -30, 118, 124,
+ 130, -24, -30, 159, 165, -30, 171, 177, 206, 212,
+ 218, -30, -30, -30, -30, -30, -30, -30, -1, 224,
+ -30, -30, -30, -30, -30, -30, -30, -30, -30, 253,
+ -30
+};
+
+ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE does not specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 2, 0, 1, 26, 25, 46, 0, 27, 28, 29,
+ 31, 30, 33, 32, 34, 36, 38, 42, 40, 44,
+ 35, 37, 39, 43, 41, 45, 0, 46, 3, 5,
+ 4, 0, 0, 0, 0, 0, 46, 46, 46, 46,
+ 0, 46, 7, 46, 46, 0, 0, 46, 46, 0,
+ 46, 46, 46, 46, 46, 0, 0, 0, 0, 24,
+ 51, 50, 53, 52, 54, 49, 48, 47, 0, 0,
+ 0, 0, 46, 0, 0, 13, 0, 0, 0, 0,
+ 0, 19, 20, 21, 22, 12, 6, 23, 0, 0,
+ 11, 8, 14, 15, 16, 17, 18, 46, 9, 0,
+ 10
+};
+
+ /* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
+ -30, -30, -30, -30, -27, -30
+};
+
+ /* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 1, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 67
+};
+
+ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule whose
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+static const yytype_uint8 yytable[] =
+{
+ 49, 41, 50, 88, 0, 59, 60, 61, 51, 55,
+ 56, 57, 58, 52, 68, 53, 69, 70, 54, 71,
+ 73, 74, 72, 76, 77, 78, 79, 80, 62, 63,
+ 97, 64, 65, 66, 0, 0, 0, 0, 0, 0,
+ 0, 2, 3, 0, 4, 89, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 75, 60, 61,
+ 99, 0, 26, 27, 81, 60, 61, 0, 0, 0,
+ 82, 60, 61, 0, 0, 0, 83, 60, 61, 0,
+ 62, 63, 0, 64, 65, 66, 0, 62, 63, 0,
+ 64, 65, 66, 62, 63, 0, 64, 65, 66, 62,
+ 63, 0, 64, 65, 66, 84, 60, 61, 0, 0,
+ 0, 85, 60, 61, 0, 0, 0, 86, 60, 61,
+ 0, 0, 0, 87, 60, 61, 0, 0, 62, 63,
+ 0, 64, 65, 66, 62, 63, 0, 64, 65, 66,
+ 62, 63, 0, 64, 65, 66, 62, 63, 0, 64,
+ 65, 66, 90, 60, 61, 0, 0, 0, 91, 60,
+ 61, 0, 0, 0, 92, 60, 61, 0, 0, 0,
+ 93, 60, 61, 0, 0, 62, 63, 0, 64, 65,
+ 66, 62, 63, 0, 64, 65, 66, 62, 63, 0,
+ 64, 65, 66, 62, 63, 0, 64, 65, 66, 94,
+ 60, 61, 0, 0, 0, 95, 60, 61, 0, 0,
+ 0, 96, 60, 61, 0, 0, 0, 98, 60, 61,
+ 0, 0, 62, 63, 0, 64, 65, 66, 62, 63,
+ 0, 64, 65, 66, 62, 63, 0, 64, 65, 66,
+ 62, 63, 0, 64, 65, 66, 100, 60, 61, 0,
+ 0, 0, 42, 43, 44, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 62,
+ 63, 0, 64, 65, 66, 45, 46, 0, 0, 47,
+ 48
+};
+
+static const yytype_int8 yycheck[] =
+{
+ 27, 30, 30, 27, -1, 3, 4, 5, 31, 36,
+ 37, 38, 39, 31, 41, 31, 43, 44, 31, 31,
+ 47, 48, 31, 50, 51, 52, 53, 54, 26, 27,
+ 31, 29, 30, 31, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, -1, 3, 72, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 3, 4, 5,
+ 97, -1, 31, 32, 3, 4, 5, -1, -1, -1,
+ 3, 4, 5, -1, -1, -1, 3, 4, 5, -1,
+ 26, 27, -1, 29, 30, 31, -1, 26, 27, -1,
+ 29, 30, 31, 26, 27, -1, 29, 30, 31, 26,
+ 27, -1, 29, 30, 31, 3, 4, 5, -1, -1,
+ -1, 3, 4, 5, -1, -1, -1, 3, 4, 5,
+ -1, -1, -1, 3, 4, 5, -1, -1, 26, 27,
+ -1, 29, 30, 31, 26, 27, -1, 29, 30, 31,
+ 26, 27, -1, 29, 30, 31, 26, 27, -1, 29,
+ 30, 31, 3, 4, 5, -1, -1, -1, 3, 4,
+ 5, -1, -1, -1, 3, 4, 5, -1, -1, -1,
+ 3, 4, 5, -1, -1, 26, 27, -1, 29, 30,
+ 31, 26, 27, -1, 29, 30, 31, 26, 27, -1,
+ 29, 30, 31, 26, 27, -1, 29, 30, 31, 3,
+ 4, 5, -1, -1, -1, 3, 4, 5, -1, -1,
+ -1, 3, 4, 5, -1, -1, -1, 3, 4, 5,
+ -1, -1, 26, 27, -1, 29, 30, 31, 26, 27,
+ -1, 29, 30, 31, 26, 27, -1, 29, 30, 31,
+ 26, 27, -1, 29, 30, 31, 3, 4, 5, -1,
+ -1, -1, 3, 4, 5, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 26,
+ 27, -1, 29, 30, 31, 26, 27, -1, -1, 30,
+ 31
+};
+
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 34, 0, 1, 3, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 31, 32, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 30, 3, 4, 5, 26, 27, 30, 31, 47,
+ 30, 31, 31, 31, 31, 47, 47, 47, 47, 3,
+ 4, 5, 26, 27, 29, 30, 31, 48, 47, 47,
+ 47, 31, 31, 47, 47, 3, 47, 47, 47, 47,
+ 47, 3, 3, 3, 3, 3, 3, 3, 27, 47,
+ 3, 3, 3, 3, 3, 3, 3, 31, 3, 47,
+ 3
+};
+
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 33, 34, 34, 35, 35, 36, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 38, 38, 38,
+ 39, 39, 40, 40, 41, 41, 42, 42, 43, 43,
+ 44, 44, 45, 45, 46, 46, 47, 47, 48, 48,
+ 48, 48, 48, 48, 48
+};
+
+ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 0, 2, 1, 1, 4, 2, 4, 5,
+ 7, 4, 4, 3, 4, 4, 4, 4, 4, 3,
+ 3, 3, 3, 4, 3, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 0, 2, 1, 1,
+ 1, 1, 1, 1, 1
+};
+
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (yyscanner, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (0)
+
+/* Error token number */
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value, yyscanner); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+
+/*----------------------------------------.
+| Print this symbol's value on YYOUTPUT. |
+`----------------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ YYUSE (yyscanner);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ YYUSE (yytype);
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+{
+ YYFPRINTF (yyoutput, "%s %s (",
+ yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yyscanner);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, yyscan_t yyscanner)
+{
+ unsigned long int yylno = yyrline[yyrule];
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr,
+ yystos[yyssp[yyi + 1 - yynrhs]],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ , yyscanner);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyssp, yyvsp, Rule, yyscanner); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+yystrlen (const char *yystr)
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULLPTR;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, yyscan_t yyscanner)
+{
+ YYUSE (yyvaluep);
+ YYUSE (yyscanner);
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YYUSE (yytype);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+int
+yyparse (yyscan_t yyscanner)
+{
+/* The lookahead symbol. */
+int yychar;
+
+
+/* The semantic value of the lookahead symbol. */
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
+YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
+
+ /* Number of syntax errors so far. */
+ int yynerrs;
+
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ 'yyss': related to states.
+ 'yyvs': related to semantic values.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = yylex (&yylval, yyscanner);
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ '$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 6:
+#line 109 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ free((yyvsp[-3].string));
+ }
+#line 1457 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 7:
+#line 115 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ if (cmFortranParserIsKeyword((yyvsp[-1].string), "interface"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_SetInInterface(parser, true);
+ }
+ free((yyvsp[-1].string));
+ }
+#line 1471 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 8:
+#line 125 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ if (cmFortranParserIsKeyword((yyvsp[-3].string), "use"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
+ }
+ else if (cmFortranParserIsKeyword((yyvsp[-3].string), "module"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleModule(parser, (yyvsp[-2].string));
+ }
+ else if (cmFortranParserIsKeyword((yyvsp[-3].string), "interface"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_SetInInterface(parser, true);
+ }
+ else if (cmFortranParserIsKeyword((yyvsp[-2].string), "interface") &&
+ cmFortranParserIsKeyword((yyvsp[-3].string), "end"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_SetInInterface(parser, false);
+ }
+ free((yyvsp[-3].string));
+ free((yyvsp[-2].string));
+ }
+#line 1505 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 9:
+#line 155 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ if (cmFortranParserIsKeyword((yyvsp[-4].string), "use"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
+ }
+ free((yyvsp[-4].string));
+ free((yyvsp[-2].string));
+ }
+#line 1520 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 10:
+#line 166 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ if (cmFortranParserIsKeyword((yyvsp[-6].string), "use") &&
+ cmFortranParserIsKeyword((yyvsp[-4].string), "non_intrinsic") )
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
+ }
+ free((yyvsp[-6].string));
+ free((yyvsp[-4].string));
+ free((yyvsp[-2].string));
+ }
+#line 1537 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 11:
+#line 179 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ if (cmFortranParserIsKeyword((yyvsp[-3].string), "include"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
+ }
+ free((yyvsp[-3].string));
+ free((yyvsp[-2].string));
+ }
+#line 1552 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 12:
+#line 190 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleLineDirective(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1563 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 13:
+#line 197 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1574 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 14:
+#line 204 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1585 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 15:
+#line 211 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleDefine(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1595 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 16:
+#line 217 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUndef(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1605 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 17:
+#line 223 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleIfdef(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1615 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 18:
+#line 229 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleIfndef(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1625 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 19:
+#line 235 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleIf(parser);
+ }
+#line 1634 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 20:
+#line 240 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleElif(parser);
+ }
+#line 1643 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 21:
+#line 245 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleElse(parser);
+ }
+#line 1652 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 22:
+#line 250 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleEndif(parser);
+ }
+#line 1661 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 23:
+#line 255 "cmFortranParser.y" /* yacc.c:1646 */
+ {
+ free((yyvsp[-3].string));
+ }
+#line 1669 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 48:
+#line 277 "cmFortranParser.y" /* yacc.c:1646 */
+ { free ((yyvsp[0].string)); }
+#line 1675 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+ case 49:
+#line 278 "cmFortranParser.y" /* yacc.c:1646 */
+ { free ((yyvsp[0].string)); }
+#line 1681 "cmFortranParser.cxx" /* yacc.c:1646 */
+ break;
+
+
+#line 1685 "cmFortranParser.cxx" /* yacc.c:1646 */
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now 'shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error. |
+`--------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (yyscanner, YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yyscanner, yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, yyscanner);
+ yychar = YYEMPTY;
+ }
+ }
+
+#if 0
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+#endif
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp, yyscanner);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (yyscanner, YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, yyscanner);
+ }
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp, yyscanner);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ return yyresult;
+}
+#line 286 "cmFortranParser.y" /* yacc.c:1906 */
+
+/* End of grammar */
diff --git a/Source/cmFortranParser.h b/Source/cmFortranParser.h
new file mode 100644
index 0000000..07e1b1c
--- /dev/null
+++ b/Source/cmFortranParser.h
@@ -0,0 +1,160 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFortranParser_h
+#define cmFortranParser_h
+
+#if !defined(cmFortranLexer_cxx) && !defined(cmFortranParser_cxx)
+#include "cmStandardIncludes.h"
+#endif
+
+#include <stddef.h> /* size_t */
+
+/* Forward declare parser object type. */
+typedef struct cmFortranParser_s cmFortranParser;
+
+/* Functions to enter/exit #include'd files in order. */
+bool cmFortranParser_FilePush(cmFortranParser* parser, const char* fname);
+bool cmFortranParser_FilePop(cmFortranParser* parser);
+
+/* Callbacks for lexer. */
+int cmFortranParser_Input(cmFortranParser* parser, char* buffer,
+ size_t bufferSize);
+
+void cmFortranParser_StringStart(cmFortranParser* parser);
+const char* cmFortranParser_StringEnd(cmFortranParser* parser);
+void cmFortranParser_StringAppend(cmFortranParser* parser, char c);
+
+void cmFortranParser_SetInInterface(cmFortranParser* parser, bool is_in);
+bool cmFortranParser_GetInInterface(cmFortranParser* parser);
+
+void cmFortranParser_SetInPPFalseBranch(cmFortranParser* parser, bool is_in);
+bool cmFortranParser_GetInPPFalseBranch(cmFortranParser* parser);
+
+void cmFortranParser_SetOldStartcond(cmFortranParser* parser, int arg);
+int cmFortranParser_GetOldStartcond(cmFortranParser* parser);
+
+/* Callbacks for parser. */
+void cmFortranParser_Error(cmFortranParser* parser, const char* message);
+void cmFortranParser_RuleUse(cmFortranParser* parser, const char* name);
+void cmFortranParser_RuleLineDirective(cmFortranParser* parser,
+ const char* filename);
+void cmFortranParser_RuleInclude(cmFortranParser* parser, const char* name);
+void cmFortranParser_RuleModule(cmFortranParser* parser, const char* name);
+void cmFortranParser_RuleDefine(cmFortranParser* parser, const char* name);
+void cmFortranParser_RuleUndef(cmFortranParser* parser, const char* name);
+void cmFortranParser_RuleIfdef(cmFortranParser* parser, const char* name);
+void cmFortranParser_RuleIfndef(cmFortranParser* parser, const char* name);
+void cmFortranParser_RuleIf(cmFortranParser* parser);
+void cmFortranParser_RuleElif(cmFortranParser* parser);
+void cmFortranParser_RuleElse(cmFortranParser* parser);
+void cmFortranParser_RuleEndif(cmFortranParser* parser);
+
+/* Define the parser stack element type. */
+typedef union cmFortran_yystype_u cmFortran_yystype;
+union cmFortran_yystype_u
+{
+ char* string;
+};
+
+/* Setup the proper yylex interface. */
+#define YY_EXTRA_TYPE cmFortranParser*
+#define YY_DECL int cmFortran_yylex(YYSTYPE* yylvalp, yyscan_t yyscanner)
+#define YYSTYPE cmFortran_yystype
+#define YYSTYPE_IS_DECLARED 1
+#if !defined(cmFortranLexer_cxx)
+#include "cmFortranLexer.h"
+#endif
+#if !defined(cmFortranLexer_cxx)
+#if !defined(cmFortranParser_cxx)
+#undef YY_EXTRA_TYPE
+#undef YY_DECL
+#undef YYSTYPE
+#undef YYSTYPE_IS_DECLARED
+#endif
+#endif
+
+#if !defined(cmFortranLexer_cxx) && !defined(cmFortranParser_cxx)
+#include <stack>
+
+// Information about a single source file.
+class cmFortranSourceInfo
+{
+public:
+ // The name of the source file.
+ std::string Source;
+
+ // 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;
+};
+
+// Parser methods not included in generated interface.
+
+// Get the current buffer processed by the lexer.
+YY_BUFFER_STATE cmFortranLexer_GetCurrentBuffer(yyscan_t yyscanner);
+
+// The parser entry point.
+int cmFortran_yyparse(yyscan_t);
+
+// Define parser object internal structure.
+struct cmFortranFile
+{
+ cmFortranFile(FILE* file, YY_BUFFER_STATE buffer, const std::string& dir)
+ : File(file)
+ , Buffer(buffer)
+ , Directory(dir)
+ {
+ }
+ FILE* File;
+ YY_BUFFER_STATE Buffer;
+ std::string Directory;
+};
+
+struct cmFortranParser_s
+{
+ cmFortranParser_s(std::vector<std::string> const& includes,
+ std::set<std::string> const& defines,
+ cmFortranSourceInfo& info);
+ ~cmFortranParser_s();
+
+ bool FindIncludeFile(const char* dir, const char* includeName,
+ std::string& fileName);
+
+ // The include file search path.
+ std::vector<std::string> IncludePath;
+
+ // Lexical scanner instance.
+ yyscan_t Scanner;
+
+ // Stack of open files in the translation unit.
+ std::stack<cmFortranFile> FileStack;
+
+ // Buffer for string literals.
+ std::string TokenString;
+
+ // Flag for whether lexer is reading from inside an interface.
+ bool InInterface;
+
+ int OldStartcond;
+ std::set<std::string> PPDefinitions;
+ size_t InPPFalseBranch;
+ std::stack<bool> SkipToEnd;
+
+ // Information about the parsed source.
+ cmFortranSourceInfo& Info;
+};
+#endif
+
+#endif
diff --git a/Source/cmFortranParser.y b/Source/cmFortranParser.y
new file mode 100644
index 0000000..83f441a
--- /dev/null
+++ b/Source/cmFortranParser.y
@@ -0,0 +1,287 @@
+%{
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*-------------------------------------------------------------------------
+ Portions of this source have been derived from makedepf90 version 2.8.8,
+
+ Copyright (C) 2000--2006 Erik Edelmann <erik.edelmann@iki.fi>
+
+ The code was originally distributed under the GPL but permission
+ from the copyright holder has been obtained to distribute this
+ derived work under the CMake license.
+-------------------------------------------------------------------------*/
+
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --yacc --name-prefix=cmFortran_yy
+ --defines=cmFortranParserTokens.h
+ -ocmFortranParser.cxx
+ cmFortranParser.y
+
+Modify cmFortranParser.cxx:
+ - "#if 0" out yyerrorlab block in range ["goto yyerrlab1", "yyerrlab1:"]
+*/
+
+/*-------------------------------------------------------------------------*/
+#define cmFortranParser_cxx
+#include "cmFortranParser.h" /* Interface to parser object. */
+#include "cmFortranParserTokens.h" /* Need YYSTYPE for YY_DECL. */
+
+#include <cmsys/String.h>
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Helper function to forward error callback from parser. */
+static void cmFortran_yyerror(yyscan_t yyscanner, const char* message)
+{
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_Error(parser, message);
+}
+
+static bool cmFortranParserIsKeyword(const char* word,
+ const char* keyword)
+{
+ return cmsysString_strcasecmp(word, keyword) == 0;
+}
+
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch contains default but no case. */
+# pragma warning (disable: 4701) /* Local variable may not be initialized. */
+# pragma warning (disable: 4702) /* Unreachable code. */
+# pragma warning (disable: 4127) /* Conditional expression is constant. */
+# pragma warning (disable: 4244) /* Conversion to smaller type, data loss. */
+#endif
+%}
+
+/* Generate a reentrant parser object. */
+%define api.pure
+
+/* Configure the parser to use a lexer object. */
+%lex-param {yyscan_t yyscanner}
+%parse-param {yyscan_t yyscanner}
+
+%define parse.error verbose
+
+%union {
+ char* string;
+}
+
+/*-------------------------------------------------------------------------*/
+/* Tokens */
+%token EOSTMT ASSIGNMENT_OP GARBAGE
+%token CPP_LINE_DIRECTIVE
+%token CPP_INCLUDE F90PPR_INCLUDE COCO_INCLUDE
+%token F90PPR_DEFINE CPP_DEFINE F90PPR_UNDEF CPP_UNDEF
+%token CPP_IFDEF CPP_IFNDEF CPP_IF CPP_ELSE CPP_ELIF CPP_ENDIF
+%token F90PPR_IFDEF F90PPR_IFNDEF F90PPR_IF
+%token F90PPR_ELSE F90PPR_ELIF F90PPR_ENDIF
+%token COMMA DCOLON
+%token <string> CPP_TOENDL
+%token <number> UNTERMINATED_STRING
+%token <string> STRING WORD
+%token <string> CPP_INCLUDE_ANGLE
+
+/*-------------------------------------------------------------------------*/
+/* grammar */
+%%
+
+code: /* empty */ | code stmt;
+
+stmt: keyword_stmt | assignment_stmt;
+
+assignment_stmt: WORD ASSIGNMENT_OP other EOSTMT /* Ignore */
+ {
+ free($1);
+ }
+
+keyword_stmt:
+ WORD EOSTMT
+ {
+ if (cmFortranParserIsKeyword($1, "interface"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_SetInInterface(parser, true);
+ }
+ free($1);
+ }
+| WORD WORD other EOSTMT
+ {
+ if (cmFortranParserIsKeyword($1, "use"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUse(parser, $2);
+ }
+ else if (cmFortranParserIsKeyword($1, "module"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleModule(parser, $2);
+ }
+ else if (cmFortranParserIsKeyword($1, "interface"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_SetInInterface(parser, true);
+ }
+ else if (cmFortranParserIsKeyword($2, "interface") &&
+ cmFortranParserIsKeyword($1, "end"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_SetInInterface(parser, false);
+ }
+ free($1);
+ free($2);
+ }
+| WORD DCOLON WORD other EOSTMT
+ {
+ if (cmFortranParserIsKeyword($1, "use"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUse(parser, $3);
+ }
+ free($1);
+ free($3);
+ }
+| WORD COMMA WORD DCOLON WORD other EOSTMT
+ {
+ if (cmFortranParserIsKeyword($1, "use") &&
+ cmFortranParserIsKeyword($3, "non_intrinsic") )
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUse(parser, $5);
+ }
+ free($1);
+ free($3);
+ free($5);
+ }
+| WORD STRING other EOSTMT /* Ignore */
+ {
+ if (cmFortranParserIsKeyword($1, "include"))
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleInclude(parser, $2);
+ }
+ free($1);
+ free($2);
+ }
+| CPP_LINE_DIRECTIVE STRING other EOSTMT
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleLineDirective(parser, $2);
+ free($2);
+ }
+| CPP_INCLUDE_ANGLE other EOSTMT
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleInclude(parser, $1);
+ free($1);
+ }
+| include STRING other EOSTMT
+ {
+ cmFortranParser* parser =
+ cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleInclude(parser, $2);
+ free($2);
+ }
+| define WORD other EOSTMT
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleDefine(parser, $2);
+ free($2);
+ }
+| undef WORD other EOSTMT
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUndef(parser, $2);
+ free($2);
+ }
+| ifdef WORD other EOSTMT
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleIfdef(parser, $2);
+ free($2);
+ }
+| ifndef WORD other EOSTMT
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleIfndef(parser, $2);
+ free($2);
+ }
+| if other EOSTMT
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleIf(parser);
+ }
+| elif other EOSTMT
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleElif(parser);
+ }
+| else other EOSTMT
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleElse(parser);
+ }
+| endif other EOSTMT
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleEndif(parser);
+ }
+| WORD GARBAGE other EOSTMT /* Ignore */
+ {
+ free($1);
+ }
+| GARBAGE other EOSTMT
+| EOSTMT
+| error
+;
+
+
+
+include: CPP_INCLUDE | F90PPR_INCLUDE | COCO_INCLUDE ;
+define: CPP_DEFINE | F90PPR_DEFINE;
+undef: CPP_UNDEF | F90PPR_UNDEF ;
+ifdef: CPP_IFDEF | F90PPR_IFDEF ;
+ifndef: CPP_IFNDEF | F90PPR_IFNDEF ;
+if: CPP_IF | F90PPR_IF ;
+elif: CPP_ELIF | F90PPR_ELIF ;
+else: CPP_ELSE | F90PPR_ELSE ;
+endif: CPP_ENDIF | F90PPR_ENDIF ;
+other: /* empty */ | other misc_code ;
+
+misc_code:
+ WORD { free ($1); }
+| STRING { free ($1); }
+| GARBAGE
+| ASSIGNMENT_OP
+| DCOLON
+| COMMA
+| UNTERMINATED_STRING
+;
+
+%%
+/* End of grammar */
diff --git a/Source/cmFortranParserImpl.cxx b/Source/cmFortranParserImpl.cxx
new file mode 100644
index 0000000..a72204a
--- /dev/null
+++ b/Source/cmFortranParserImpl.cxx
@@ -0,0 +1,359 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmFortranParser.h"
+
+#include "cmSystemTools.h"
+#include <assert.h>
+
+bool cmFortranParser_s::FindIncludeFile(const char* dir,
+ const char* includeName,
+ std::string& fileName)
+{
+ // If the file is a full path, include it directly.
+ if (cmSystemTools::FileIsFullPath(includeName)) {
+ fileName = includeName;
+ return cmSystemTools::FileExists(fileName.c_str(), true);
+ } else {
+ // Check for the file in the directory containing the including
+ // file.
+ std::string fullName = dir;
+ fullName += "/";
+ fullName += includeName;
+ if (cmSystemTools::FileExists(fullName.c_str(), true)) {
+ fileName = fullName;
+ return true;
+ }
+
+ // Search the include path for the file.
+ for (std::vector<std::string>::const_iterator i =
+ this->IncludePath.begin();
+ i != this->IncludePath.end(); ++i) {
+ fullName = *i;
+ fullName += "/";
+ fullName += includeName;
+ if (cmSystemTools::FileExists(fullName.c_str(), true)) {
+ fileName = fullName;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+cmFortranParser_s::cmFortranParser_s(std::vector<std::string> const& includes,
+ std::set<std::string> const& defines,
+ cmFortranSourceInfo& info)
+ : IncludePath(includes)
+ , PPDefinitions(defines)
+ , Info(info)
+{
+ this->InInterface = 0;
+ this->InPPFalseBranch = 0;
+
+ // Initialize the lexical scanner.
+ cmFortran_yylex_init(&this->Scanner);
+ cmFortran_yyset_extra(this, this->Scanner);
+
+ // Create a dummy buffer that is never read but is the fallback
+ // buffer when the last file is popped off the stack.
+ YY_BUFFER_STATE buffer =
+ cmFortran_yy_create_buffer(CM_NULLPTR, 4, this->Scanner);
+ cmFortran_yy_switch_to_buffer(buffer, this->Scanner);
+}
+
+cmFortranParser_s::~cmFortranParser_s()
+{
+ cmFortran_yylex_destroy(this->Scanner);
+}
+
+bool cmFortranParser_FilePush(cmFortranParser* parser, const char* fname)
+{
+ // Open the new file and push it onto the stack. Save the old
+ // buffer with it on the stack.
+ if (FILE* file = cmsys::SystemTools::Fopen(fname, "rb")) {
+ YY_BUFFER_STATE current = cmFortranLexer_GetCurrentBuffer(parser->Scanner);
+ std::string dir = cmSystemTools::GetParentDirectory(fname);
+ cmFortranFile f(file, current, dir);
+ YY_BUFFER_STATE buffer =
+ cmFortran_yy_create_buffer(CM_NULLPTR, 16384, parser->Scanner);
+ cmFortran_yy_switch_to_buffer(buffer, parser->Scanner);
+ parser->FileStack.push(f);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+bool cmFortranParser_FilePop(cmFortranParser* parser)
+{
+ // Pop one file off the stack and close it. Switch the lexer back
+ // to the next one on the stack.
+ if (parser->FileStack.empty()) {
+ return 0;
+ } else {
+ cmFortranFile f = parser->FileStack.top();
+ parser->FileStack.pop();
+ fclose(f.File);
+ YY_BUFFER_STATE current = cmFortranLexer_GetCurrentBuffer(parser->Scanner);
+ cmFortran_yy_delete_buffer(current, parser->Scanner);
+ cmFortran_yy_switch_to_buffer(f.Buffer, parser->Scanner);
+ return 1;
+ }
+}
+
+int cmFortranParser_Input(cmFortranParser* parser, char* buffer,
+ size_t bufferSize)
+{
+ // Read from the file on top of the stack. If the stack is empty,
+ // the end of the translation unit has been reached.
+ if (!parser->FileStack.empty()) {
+ FILE* file = parser->FileStack.top().File;
+ return (int)fread(buffer, 1, bufferSize, file);
+ }
+ return 0;
+}
+
+void cmFortranParser_StringStart(cmFortranParser* parser)
+{
+ parser->TokenString = "";
+}
+
+const char* cmFortranParser_StringEnd(cmFortranParser* parser)
+{
+ return parser->TokenString.c_str();
+}
+
+void cmFortranParser_StringAppend(cmFortranParser* parser, char c)
+{
+ parser->TokenString += c;
+}
+
+void cmFortranParser_SetInInterface(cmFortranParser* parser, bool in)
+{
+ if (parser->InPPFalseBranch) {
+ return;
+ }
+
+ parser->InInterface = in;
+}
+
+bool cmFortranParser_GetInInterface(cmFortranParser* parser)
+{
+ return parser->InInterface;
+}
+
+void cmFortranParser_SetOldStartcond(cmFortranParser* parser, int arg)
+{
+ parser->OldStartcond = arg;
+}
+
+int cmFortranParser_GetOldStartcond(cmFortranParser* parser)
+{
+ return parser->OldStartcond;
+}
+
+void cmFortranParser_Error(cmFortranParser*, const char*)
+{
+ // If there is a parser error just ignore it. The source will not
+ // compile and the user will edit it. Then dependencies will have
+ // to be regenerated anyway.
+}
+
+void cmFortranParser_RuleUse(cmFortranParser* parser, const char* name)
+{
+ if (!parser->InPPFalseBranch) {
+ parser->Info.Requires.insert(cmSystemTools::LowerCase(name));
+ }
+}
+
+void cmFortranParser_RuleLineDirective(cmFortranParser* parser,
+ const char* filename)
+{
+ // This is a #line directive naming a file encountered during preprocessing.
+ std::string included = filename;
+
+ // Skip #line directives referencing non-files like
+ // "<built-in>" or "<command-line>".
+ if (included.empty() || included[0] == '<') {
+ return;
+ }
+
+ // Fix windows file path separators since our lexer does not
+ // process escape sequences in string literals.
+ cmSystemTools::ReplaceString(included, "\\\\", "\\");
+ cmSystemTools::ConvertToUnixSlashes(included);
+
+ // Save the named file as included in the source.
+ if (cmSystemTools::FileExists(included, true)) {
+ parser->Info.Includes.insert(included);
+ }
+}
+
+void cmFortranParser_RuleInclude(cmFortranParser* parser, const char* name)
+{
+ if (parser->InPPFalseBranch) {
+ return;
+ }
+
+ // If processing an include statement there must be an open file.
+ assert(!parser->FileStack.empty());
+
+ // Get the directory containing the source in which the include
+ // statement appears. This is always the first search location for
+ // Fortran include files.
+ std::string dir = parser->FileStack.top().Directory;
+
+ // Find the included file. If it cannot be found just ignore the
+ // problem because either the source will not compile or the user
+ // does not care about depending on this included source.
+ std::string fullName;
+ if (parser->FindIncludeFile(dir.c_str(), name, fullName)) {
+ // Found the included file. Save it in the set of included files.
+ parser->Info.Includes.insert(fullName);
+
+ // Parse it immediately to translate the source inline.
+ cmFortranParser_FilePush(parser, fullName.c_str());
+ }
+}
+
+void cmFortranParser_RuleModule(cmFortranParser* parser, const char* name)
+{
+ if (!parser->InPPFalseBranch && !parser->InInterface) {
+ parser->Info.Provides.insert(cmSystemTools::LowerCase(name));
+ }
+}
+
+void cmFortranParser_RuleDefine(cmFortranParser* parser, const char* macro)
+{
+ if (!parser->InPPFalseBranch) {
+ parser->PPDefinitions.insert(macro);
+ }
+}
+
+void cmFortranParser_RuleUndef(cmFortranParser* parser, const char* macro)
+{
+ if (!parser->InPPFalseBranch) {
+ std::set<std::string>::iterator match;
+ match = parser->PPDefinitions.find(macro);
+ if (match != parser->PPDefinitions.end()) {
+ parser->PPDefinitions.erase(match);
+ }
+ }
+}
+
+void cmFortranParser_RuleIfdef(cmFortranParser* parser, const char* macro)
+{
+ // A new PP branch has been opened
+ parser->SkipToEnd.push(false);
+
+ if (parser->InPPFalseBranch) {
+ parser->InPPFalseBranch++;
+ } else if (parser->PPDefinitions.find(macro) ==
+ parser->PPDefinitions.end()) {
+ parser->InPPFalseBranch = 1;
+ } else {
+ parser->SkipToEnd.top() = true;
+ }
+}
+
+void cmFortranParser_RuleIfndef(cmFortranParser* parser, const char* macro)
+{
+ // A new PP branch has been opened
+ parser->SkipToEnd.push(false);
+
+ if (parser->InPPFalseBranch) {
+ parser->InPPFalseBranch++;
+ } else if (parser->PPDefinitions.find(macro) !=
+ parser->PPDefinitions.end()) {
+ parser->InPPFalseBranch = 1;
+ } else {
+ // ignore other branches
+ parser->SkipToEnd.top() = true;
+ }
+}
+
+void cmFortranParser_RuleIf(cmFortranParser* parser)
+{
+ /* Note: The current parser is _not_ able to get statements like
+ * #if 0
+ * #if 1
+ * #if MYSMBOL
+ * #if defined(MYSYMBOL)
+ * #if defined(MYSYMBOL) && ...
+ * right. The same for #elif. Thus in
+ * #if SYMBOL_1
+ * ..
+ * #elif SYMBOL_2
+ * ...
+ * ...
+ * #elif SYMBOL_N
+ * ..
+ * #else
+ * ..
+ * #endif
+ * _all_ N+1 branches are considered. If you got something like this
+ * #if defined(MYSYMBOL)
+ * #if !defined(MYSYMBOL)
+ * use
+ * #ifdef MYSYMBOL
+ * #ifndef MYSYMBOL
+ * instead.
+ */
+
+ // A new PP branch has been opened
+ // Never skip! See note above.
+ parser->SkipToEnd.push(false);
+}
+
+void cmFortranParser_RuleElif(cmFortranParser* parser)
+{
+ /* Note: There are parser limitations. See the note at
+ * cmFortranParser_RuleIf(..)
+ */
+
+ // Always taken unless an #ifdef or #ifndef-branch has been taken
+ // already. If the second condition isn't meet already
+ // (parser->InPPFalseBranch == 0) correct it.
+ if (!parser->SkipToEnd.empty() && parser->SkipToEnd.top() &&
+ !parser->InPPFalseBranch) {
+ parser->InPPFalseBranch = 1;
+ }
+}
+
+void cmFortranParser_RuleElse(cmFortranParser* parser)
+{
+ // if the parent branch is false do nothing!
+ if (parser->InPPFalseBranch > 1) {
+ return;
+ }
+
+ // parser->InPPFalseBranch is either 0 or 1. We change it depending on
+ // parser->SkipToEnd.top()
+ if (!parser->SkipToEnd.empty() && parser->SkipToEnd.top()) {
+ parser->InPPFalseBranch = 1;
+ } else {
+ parser->InPPFalseBranch = 0;
+ }
+}
+
+void cmFortranParser_RuleEndif(cmFortranParser* parser)
+{
+ if (!parser->SkipToEnd.empty()) {
+ parser->SkipToEnd.pop();
+ }
+
+ // #endif doesn't know if there was a "#else" in before, so it
+ // always decreases InPPFalseBranch
+ if (parser->InPPFalseBranch) {
+ parser->InPPFalseBranch--;
+ }
+}
diff --git a/Source/cmFortranParserTokens.h b/Source/cmFortranParserTokens.h
new file mode 100644
index 0000000..ac49840
--- /dev/null
+++ b/Source/cmFortranParserTokens.h
@@ -0,0 +1,131 @@
+/* A Bison parser, made by GNU Bison 3.0.2. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED
+# define YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int cmFortran_yydebug;
+#endif
+
+/* Token type. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ EOSTMT = 258,
+ ASSIGNMENT_OP = 259,
+ GARBAGE = 260,
+ CPP_LINE_DIRECTIVE = 261,
+ CPP_INCLUDE = 262,
+ F90PPR_INCLUDE = 263,
+ COCO_INCLUDE = 264,
+ F90PPR_DEFINE = 265,
+ CPP_DEFINE = 266,
+ F90PPR_UNDEF = 267,
+ CPP_UNDEF = 268,
+ CPP_IFDEF = 269,
+ CPP_IFNDEF = 270,
+ CPP_IF = 271,
+ CPP_ELSE = 272,
+ CPP_ELIF = 273,
+ CPP_ENDIF = 274,
+ F90PPR_IFDEF = 275,
+ F90PPR_IFNDEF = 276,
+ F90PPR_IF = 277,
+ F90PPR_ELSE = 278,
+ F90PPR_ELIF = 279,
+ F90PPR_ENDIF = 280,
+ COMMA = 281,
+ DCOLON = 282,
+ CPP_TOENDL = 283,
+ UNTERMINATED_STRING = 284,
+ STRING = 285,
+ WORD = 286,
+ CPP_INCLUDE_ANGLE = 287
+ };
+#endif
+/* Tokens. */
+#define EOSTMT 258
+#define ASSIGNMENT_OP 259
+#define GARBAGE 260
+#define CPP_LINE_DIRECTIVE 261
+#define CPP_INCLUDE 262
+#define F90PPR_INCLUDE 263
+#define COCO_INCLUDE 264
+#define F90PPR_DEFINE 265
+#define CPP_DEFINE 266
+#define F90PPR_UNDEF 267
+#define CPP_UNDEF 268
+#define CPP_IFDEF 269
+#define CPP_IFNDEF 270
+#define CPP_IF 271
+#define CPP_ELSE 272
+#define CPP_ELIF 273
+#define CPP_ENDIF 274
+#define F90PPR_IFDEF 275
+#define F90PPR_IFNDEF 276
+#define F90PPR_IF 277
+#define F90PPR_ELSE 278
+#define F90PPR_ELIF 279
+#define F90PPR_ENDIF 280
+#define COMMA 281
+#define DCOLON 282
+#define CPP_TOENDL 283
+#define UNTERMINATED_STRING 284
+#define STRING 285
+#define WORD 286
+#define CPP_INCLUDE_ANGLE 287
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE YYSTYPE;
+union YYSTYPE
+{
+#line 81 "cmFortranParser.y" /* yacc.c:1909 */
+
+ char* string;
+
+#line 122 "cmFortranParserTokens.h" /* yacc.c:1909 */
+};
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+
+int cmFortran_yyparse (yyscan_t yyscanner);
+
+#endif /* !YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED */
diff --git a/Source/cmFunctionBlocker.h b/Source/cmFunctionBlocker.h
new file mode 100644
index 0000000..c7e3b71
--- /dev/null
+++ b/Source/cmFunctionBlocker.h
@@ -0,0 +1,55 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFunctionBlocker_h
+#define cmFunctionBlocker_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmExecutionStatus.h"
+#include "cmListFileCache.h"
+class cmMakefile;
+
+class cmFunctionBlocker
+{
+public:
+ /**
+ * should a function be blocked
+ */
+ virtual bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf,
+ cmExecutionStatus& status) = 0;
+
+ /**
+ * should this function blocker be removed, useful when one function adds a
+ * blocker and another must remove it
+ */
+ virtual bool ShouldRemove(const cmListFileFunction&, cmMakefile&)
+ {
+ return false;
+ }
+
+ virtual ~cmFunctionBlocker() {}
+
+ /** Set/Get the context in which this blocker is created. */
+ void SetStartingContext(cmListFileContext const& lfc)
+ {
+ this->StartingContext = lfc;
+ }
+ cmListFileContext const& GetStartingContext() const
+ {
+ return this->StartingContext;
+ }
+
+private:
+ cmListFileContext StartingContext;
+};
+
+#endif
diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx
new file mode 100644
index 0000000..40c54db
--- /dev/null
+++ b/Source/cmFunctionCommand.cxx
@@ -0,0 +1,215 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmFunctionCommand.h"
+
+#include "cmake.h"
+
+// define the class for function commands
+class cmFunctionHelperCommand : public cmCommand
+{
+public:
+ cmFunctionHelperCommand() {}
+
+ ///! clean up any memory allocated by the function
+ ~cmFunctionHelperCommand() CM_OVERRIDE {}
+
+ /**
+ * This is used to avoid including this command
+ * in documentation. This is mainly used by
+ * cmMacroHelperCommand and cmFunctionHelperCommand
+ * which cannot provide appropriate documentation.
+ */
+ bool ShouldAppearInDocumentation() const CM_OVERRIDE { return false; }
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmFunctionHelperCommand* newC = new cmFunctionHelperCommand;
+ // we must copy when we clone
+ newC->Args = this->Args;
+ newC->Functions = this->Functions;
+ newC->Policies = this->Policies;
+ newC->FilePath = this->FilePath;
+ return newC;
+ }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InvokeInitialPass(const std::vector<cmListFileArgument>& args,
+ cmExecutionStatus&) CM_OVERRIDE;
+
+ bool InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&) CM_OVERRIDE
+ {
+ return false;
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return this->Args[0]; }
+
+ cmTypeMacro(cmFunctionHelperCommand, cmCommand);
+
+ std::vector<std::string> Args;
+ std::vector<cmListFileFunction> Functions;
+ cmPolicies::PolicyMap Policies;
+ std::string FilePath;
+};
+
+bool cmFunctionHelperCommand::InvokeInitialPass(
+ const std::vector<cmListFileArgument>& args, cmExecutionStatus& inStatus)
+{
+ // Expand the argument list to the function.
+ std::vector<std::string> expandedArgs;
+ this->Makefile->ExpandArguments(args, expandedArgs);
+
+ // make sure the number of arguments passed is at least the number
+ // required by the signature
+ if (expandedArgs.size() < this->Args.size() - 1) {
+ std::string errorMsg =
+ "Function invoked with incorrect arguments for function named: ";
+ errorMsg += this->Args[0];
+ this->SetError(errorMsg);
+ return false;
+ }
+
+ cmMakefile::FunctionPushPop functionScope(this->Makefile, this->FilePath,
+ this->Policies);
+
+ // set the value of argc
+ std::ostringstream strStream;
+ strStream << expandedArgs.size();
+ this->Makefile->AddDefinition("ARGC", strStream.str().c_str());
+ this->Makefile->MarkVariableAsUsed("ARGC");
+
+ // set the values for ARGV0 ARGV1 ...
+ for (unsigned int t = 0; t < expandedArgs.size(); ++t) {
+ std::ostringstream tmpStream;
+ tmpStream << "ARGV" << t;
+ this->Makefile->AddDefinition(tmpStream.str(), expandedArgs[t].c_str());
+ this->Makefile->MarkVariableAsUsed(tmpStream.str());
+ }
+
+ // define the formal arguments
+ for (unsigned int j = 1; j < this->Args.size(); ++j) {
+ this->Makefile->AddDefinition(this->Args[j], expandedArgs[j - 1].c_str());
+ }
+
+ // define ARGV and ARGN
+ std::string argvDef = cmJoin(expandedArgs, ";");
+ std::vector<std::string>::const_iterator eit =
+ expandedArgs.begin() + (this->Args.size() - 1);
+ std::string argnDef = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
+ this->Makefile->AddDefinition("ARGV", argvDef.c_str());
+ this->Makefile->MarkVariableAsUsed("ARGV");
+ this->Makefile->AddDefinition("ARGN", argnDef.c_str());
+ this->Makefile->MarkVariableAsUsed("ARGN");
+
+ // Invoke all the functions that were collected in the block.
+ // for each function
+ for (unsigned int c = 0; c < this->Functions.size(); ++c) {
+ cmExecutionStatus status;
+ if (!this->Makefile->ExecuteCommand(this->Functions[c], status) ||
+ status.GetNestedError()) {
+ // The error message should have already included the call stack
+ // so we do not need to report an error here.
+ functionScope.Quiet();
+ inStatus.SetNestedError(true);
+ return false;
+ }
+ if (status.GetReturnInvoked()) {
+ return true;
+ }
+ }
+
+ // pop scope on the makefile
+ return true;
+}
+
+bool cmFunctionFunctionBlocker::IsFunctionBlocked(
+ const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus&)
+{
+ // record commands until we hit the ENDFUNCTION
+ // at the ENDFUNCTION call we shift gears and start looking for invocations
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(), "function")) {
+ this->Depth++;
+ } else if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endfunction")) {
+ // if this is the endfunction for this function then execute
+ if (!this->Depth) {
+ // create a new command and add it to cmake
+ cmFunctionHelperCommand* f = new cmFunctionHelperCommand();
+ f->Args = this->Args;
+ f->Functions = this->Functions;
+ f->FilePath = this->GetStartingContext().FilePath;
+ mf.RecordPolicies(f->Policies);
+
+ std::string newName = "_" + this->Args[0];
+ mf.GetState()->RenameCommand(this->Args[0], newName);
+ mf.GetState()->AddCommand(f);
+
+ // remove the function blocker now that the function is defined
+ mf.RemoveFunctionBlocker(this, lff);
+ return true;
+ } else {
+ // decrement for each nested function that ends
+ this->Depth--;
+ }
+ }
+
+ // if it wasn't an endfunction and we are not executing then we must be
+ // recording
+ this->Functions.push_back(lff);
+ return true;
+}
+
+bool cmFunctionFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
+ cmMakefile& mf)
+{
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endfunction")) {
+ std::vector<std::string> expandedArguments;
+ mf.ExpandArguments(lff.Arguments, expandedArguments,
+ this->GetStartingContext().FilePath.c_str());
+ // if the endfunction has arguments then make sure
+ // they match the ones in the opening function command
+ if ((expandedArguments.empty() ||
+ (expandedArguments[0] == this->Args[0]))) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool cmFunctionCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // create a function blocker
+ cmFunctionFunctionBlocker* f = new cmFunctionFunctionBlocker();
+ f->Args.insert(f->Args.end(), args.begin(), args.end());
+ this->Makefile->AddFunctionBlocker(f);
+ return true;
+}
diff --git a/Source/cmFunctionCommand.h b/Source/cmFunctionCommand.h
new file mode 100644
index 0000000..2c7a884
--- /dev/null
+++ b/Source/cmFunctionCommand.h
@@ -0,0 +1,62 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmFunctionCommand_h
+#define cmFunctionCommand_h
+
+#include "cmCommand.h"
+
+#include "cmFunctionBlocker.h"
+
+class cmFunctionFunctionBlocker : public cmFunctionBlocker
+{
+public:
+ cmFunctionFunctionBlocker() { this->Depth = 0; }
+ ~cmFunctionFunctionBlocker() CM_OVERRIDE {}
+ bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf,
+ cmExecutionStatus&) CM_OVERRIDE;
+ bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) CM_OVERRIDE;
+
+ std::vector<std::string> Args;
+ std::vector<cmListFileFunction> Functions;
+ int Depth;
+};
+
+/// Starts function() ... endfunction() block
+class cmFunctionCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmFunctionCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "function"; }
+
+ cmTypeMacro(cmFunctionCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx
new file mode 100644
index 0000000..c35a1bc
--- /dev/null
+++ b/Source/cmGeneratedFileStream.cxx
@@ -0,0 +1,223 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGeneratedFileStream.h"
+
+#include "cmSystemTools.h"
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include <cm_zlib.h>
+#endif
+
+cmGeneratedFileStream::cmGeneratedFileStream()
+ : cmGeneratedFileStreamBase()
+ , Stream()
+{
+}
+
+cmGeneratedFileStream::cmGeneratedFileStream(const char* name, bool quiet)
+ : cmGeneratedFileStreamBase(name)
+ , Stream(TempName.c_str())
+{
+ // Check if the file opened.
+ if (!*this && !quiet) {
+ cmSystemTools::Error("Cannot open file for write: ",
+ this->TempName.c_str());
+ cmSystemTools::ReportLastSystemError("");
+ }
+}
+
+cmGeneratedFileStream::~cmGeneratedFileStream()
+{
+ // This is the first destructor called. Check the status of the
+ // stream and give the information to the private base. Next the
+ // stream will be destroyed which will close the temporary file.
+ // Finally the base destructor will be called to replace the
+ // destination file.
+ this->Okay = !this->fail();
+}
+
+cmGeneratedFileStream& cmGeneratedFileStream::Open(const char* name,
+ bool quiet, bool binaryFlag)
+{
+ // Store the file name and construct the temporary file name.
+ this->cmGeneratedFileStreamBase::Open(name);
+
+ // Open the temporary output file.
+ if (binaryFlag) {
+ this->Stream::open(this->TempName.c_str(),
+ std::ios::out | std::ios::binary);
+ } else {
+ this->Stream::open(this->TempName.c_str());
+ }
+
+ // Check if the file opened.
+ if (!*this && !quiet) {
+ cmSystemTools::Error("Cannot open file for write: ",
+ this->TempName.c_str());
+ cmSystemTools::ReportLastSystemError("");
+ }
+ return *this;
+}
+
+bool cmGeneratedFileStream::Close()
+{
+ // Save whether the temporary output file is valid before closing.
+ this->Okay = !this->fail();
+
+ // Close the temporary output file.
+ this->Stream::close();
+
+ // Remove the temporary file (possibly by renaming to the real file).
+ return this->cmGeneratedFileStreamBase::Close();
+}
+
+void cmGeneratedFileStream::SetCopyIfDifferent(bool copy_if_different)
+{
+ this->CopyIfDifferent = copy_if_different;
+}
+
+void cmGeneratedFileStream::SetCompression(bool compression)
+{
+ this->Compress = compression;
+}
+
+void cmGeneratedFileStream::SetCompressionExtraExtension(bool ext)
+{
+ this->CompressExtraExtension = ext;
+}
+
+cmGeneratedFileStreamBase::cmGeneratedFileStreamBase()
+ : Name()
+ , TempName()
+ , CopyIfDifferent(false)
+ , Okay(false)
+ , Compress(false)
+ , CompressExtraExtension(true)
+{
+}
+
+cmGeneratedFileStreamBase::cmGeneratedFileStreamBase(const char* name)
+ : Name()
+ , TempName()
+ , CopyIfDifferent(false)
+ , Okay(false)
+ , Compress(false)
+ , CompressExtraExtension(true)
+{
+ this->Open(name);
+}
+
+cmGeneratedFileStreamBase::~cmGeneratedFileStreamBase()
+{
+ this->Close();
+}
+
+void cmGeneratedFileStreamBase::Open(const char* name)
+{
+ // Save the original name of the file.
+ this->Name = name;
+
+ // Create the name of the temporary file.
+ this->TempName = name;
+#if defined(__VMS)
+ this->TempName += "_tmp";
+#else
+ this->TempName += ".tmp";
+#endif
+
+ // Make sure the temporary file that will be used is not present.
+ cmSystemTools::RemoveFile(this->TempName);
+
+ std::string dir = cmSystemTools::GetFilenamePath(this->TempName);
+ cmSystemTools::MakeDirectory(dir.c_str());
+}
+
+bool cmGeneratedFileStreamBase::Close()
+{
+ bool replaced = false;
+
+ std::string resname = this->Name;
+ if (this->Compress && this->CompressExtraExtension) {
+ resname += ".gz";
+ }
+
+ // Only consider replacing the destination file if no error
+ // occurred.
+ if (!this->Name.empty() && this->Okay &&
+ (!this->CopyIfDifferent ||
+ cmSystemTools::FilesDiffer(this->TempName, resname))) {
+ // The destination is to be replaced. Rename the temporary to the
+ // destination atomically.
+ if (this->Compress) {
+ std::string gzname = this->TempName + ".temp.gz";
+ if (this->CompressFile(this->TempName.c_str(), gzname.c_str())) {
+ this->RenameFile(gzname.c_str(), resname.c_str());
+ }
+ cmSystemTools::RemoveFile(gzname);
+ } else {
+ this->RenameFile(this->TempName.c_str(), resname.c_str());
+ }
+
+ replaced = true;
+ }
+
+ // Else, the destination was not replaced.
+ //
+ // Always delete the temporary file. We never want it to stay around.
+ cmSystemTools::RemoveFile(this->TempName);
+
+ return replaced;
+}
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+int cmGeneratedFileStreamBase::CompressFile(const char* oldname,
+ const char* newname)
+{
+ gzFile gf = gzopen(newname, "w");
+ if (!gf) {
+ return 0;
+ }
+ FILE* ifs = cmsys::SystemTools::Fopen(oldname, "r");
+ if (!ifs) {
+ return 0;
+ }
+ size_t res;
+ const size_t BUFFER_SIZE = 1024;
+ char buffer[BUFFER_SIZE];
+ while ((res = fread(buffer, 1, BUFFER_SIZE, ifs)) > 0) {
+ if (!gzwrite(gf, buffer, static_cast<int>(res))) {
+ fclose(ifs);
+ gzclose(gf);
+ return 0;
+ }
+ }
+ fclose(ifs);
+ gzclose(gf);
+ return 1;
+}
+#else
+int cmGeneratedFileStreamBase::CompressFile(const char*, const char*)
+{
+ return 0;
+}
+#endif
+
+int cmGeneratedFileStreamBase::RenameFile(const char* oldname,
+ const char* newname)
+{
+ return cmSystemTools::RenameFile(oldname, newname);
+}
+
+void cmGeneratedFileStream::SetName(const std::string& fname)
+{
+ this->Name = fname;
+}
diff --git a/Source/cmGeneratedFileStream.h b/Source/cmGeneratedFileStream.h
new file mode 100644
index 0000000..3480c5b
--- /dev/null
+++ b/Source/cmGeneratedFileStream.h
@@ -0,0 +1,146 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGeneratedFileStream_h
+#define cmGeneratedFileStream_h
+
+#include "cmStandardIncludes.h"
+
+#include <cmsys/FStream.hxx>
+
+// This is the first base class of cmGeneratedFileStream. It will be
+// created before and destroyed after the ofstream portion and can
+// therefore be used to manage the temporary file.
+class cmGeneratedFileStreamBase
+{
+protected:
+ // This constructor does not prepare the temporary file. The open
+ // method must be used.
+ cmGeneratedFileStreamBase();
+
+ // This constructor prepares the temporary output file.
+ cmGeneratedFileStreamBase(const char* name);
+
+ // The destructor renames the temporary output file to the real name.
+ ~cmGeneratedFileStreamBase();
+
+ // Internal methods to handle the temporary file. Open is always
+ // called before the real stream is opened. Close is always called
+ // after the real stream is closed and Okay is set to whether the
+ // real stream was still valid for writing when it was closed.
+ void Open(const char* name);
+ bool Close();
+
+ // Internal file replacement implementation.
+ int RenameFile(const char* oldname, const char* newname);
+
+ // Internal file compression implementation.
+ int CompressFile(const char* oldname, const char* newname);
+
+ // The name of the final destination file for the output.
+ std::string Name;
+
+ // The name of the temporary file.
+ std::string TempName;
+
+ // Whether to do a copy-if-different.
+ bool CopyIfDifferent;
+
+ // Whether the real file stream was valid when it was closed.
+ bool Okay;
+
+ // Whether the destination file is compressed
+ bool Compress;
+
+ // Whether the destination file is compressed
+ bool CompressExtraExtension;
+};
+
+/** \class cmGeneratedFileStream
+ * \brief Output stream for generated files.
+ *
+ * File generation should be atomic so that if CMake is killed then a
+ * generated file is either the original version or the complete new
+ * version. This stream is used to make sure file generation is
+ * atomic. Optionally the output file is only replaced if its
+ * contents have changed to prevent the file modification time from
+ * being updated.
+ */
+class cmGeneratedFileStream : private cmGeneratedFileStreamBase,
+ public cmsys::ofstream
+{
+public:
+ typedef cmsys::ofstream Stream;
+
+ /**
+ * This constructor prepares a default stream. The open method must
+ * be used before writing to the stream.
+ */
+ cmGeneratedFileStream();
+
+ /**
+ * This constructor takes the name of the file to be generated. It
+ * automatically generates a name for the temporary file. If the
+ * file cannot be opened an error message is produced unless the
+ * second argument is set to true.
+ */
+ cmGeneratedFileStream(const char* name, bool quiet = false);
+
+ /**
+ * The destructor checks the stream status to be sure the temporary
+ * file was successfully written before allowing the original to be
+ * replaced.
+ */
+ ~cmGeneratedFileStream() CM_OVERRIDE;
+
+ /**
+ * Open an output file by name. This should be used only with a
+ * non-open stream. It automatically generates a name for the
+ * temporary file. If the file cannot be opened an error message is
+ * produced unless the second argument is set to true.
+ */
+ cmGeneratedFileStream& Open(const char* name, bool quiet = false,
+ bool binaryFlag = false);
+
+ /**
+ * Close the output file. This should be used only with an open
+ * stream. The temporary file is atomically renamed to the
+ * destionation file if the stream is still valid when this method
+ * is called.
+ */
+ bool Close();
+
+ /**
+ * Set whether copy-if-different is done.
+ */
+ void SetCopyIfDifferent(bool copy_if_different);
+
+ /**
+ * Set whether compression is done.
+ */
+ void SetCompression(bool compression);
+
+ /**
+ * Set whether compression has extra extension
+ */
+ void SetCompressionExtraExtension(bool ext);
+
+ /**
+ * Set name of the file that will hold the actual output. This method allows
+ * the output file to be changed during the use of cmGeneratedFileStream.
+ */
+ void SetName(const std::string& fname);
+
+private:
+ cmGeneratedFileStream(cmGeneratedFileStream const&); // not implemented
+};
+
+#endif
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
new file mode 100644
index 0000000..983bfb4
--- /dev/null
+++ b/Source/cmGeneratorExpression.cxx
@@ -0,0 +1,392 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGeneratorExpression.h"
+
+#include "assert.h"
+#include "cmAlgorithms.h"
+#include "cmSystemTools.h"
+
+#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGeneratorExpressionEvaluator.h"
+#include "cmGeneratorExpressionLexer.h"
+#include "cmGeneratorExpressionParser.h"
+
+cmGeneratorExpression::cmGeneratorExpression(
+ const cmListFileBacktrace& backtrace)
+ : Backtrace(backtrace)
+{
+}
+
+CM_AUTO_PTR<cmCompiledGeneratorExpression> cmGeneratorExpression::Parse(
+ std::string const& input)
+{
+ return CM_AUTO_PTR<cmCompiledGeneratorExpression>(
+ new cmCompiledGeneratorExpression(this->Backtrace, input));
+}
+
+CM_AUTO_PTR<cmCompiledGeneratorExpression> cmGeneratorExpression::Parse(
+ const char* input)
+{
+ return this->Parse(std::string(input ? input : ""));
+}
+
+cmGeneratorExpression::~cmGeneratorExpression()
+{
+}
+
+const char* cmCompiledGeneratorExpression::Evaluate(
+ cmLocalGenerator* lg, const std::string& config, bool quiet,
+ const cmGeneratorTarget* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::string const& language) const
+{
+ return this->Evaluate(lg, config, quiet, headTarget, headTarget, dagChecker,
+ language);
+}
+
+const char* cmCompiledGeneratorExpression::Evaluate(
+ cmLocalGenerator* lg, const std::string& config, bool quiet,
+ const cmGeneratorTarget* headTarget, const cmGeneratorTarget* currentTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::string const& language) const
+{
+ cmGeneratorExpressionContext context(
+ lg, config, quiet, headTarget, currentTarget ? currentTarget : headTarget,
+ this->EvaluateForBuildsystem, this->Backtrace, language);
+
+ return this->EvaluateWithContext(context, dagChecker);
+}
+
+const char* cmCompiledGeneratorExpression::EvaluateWithContext(
+ cmGeneratorExpressionContext& context,
+ cmGeneratorExpressionDAGChecker* dagChecker) const
+{
+ if (!this->NeedsEvaluation) {
+ return this->Input.c_str();
+ }
+
+ this->Output = "";
+
+ std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
+ this->Evaluators.begin();
+ const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
+ this->Evaluators.end();
+
+ for (; it != end; ++it) {
+ this->Output += (*it)->Evaluate(&context, dagChecker);
+
+ this->SeenTargetProperties.insert(context.SeenTargetProperties.begin(),
+ context.SeenTargetProperties.end());
+ if (context.HadError) {
+ this->Output = "";
+ break;
+ }
+ }
+
+ this->MaxLanguageStandard = context.MaxLanguageStandard;
+
+ if (!context.HadError) {
+ this->HadContextSensitiveCondition = context.HadContextSensitiveCondition;
+ this->HadHeadSensitiveCondition = context.HadHeadSensitiveCondition;
+ this->SourceSensitiveTargets = context.SourceSensitiveTargets;
+ }
+
+ this->DependTargets = context.DependTargets;
+ this->AllTargetsSeen = context.AllTargets;
+ // TODO: Return a std::string from here instead?
+ return this->Output.c_str();
+}
+
+cmCompiledGeneratorExpression::cmCompiledGeneratorExpression(
+ cmListFileBacktrace const& backtrace, const std::string& input)
+ : Backtrace(backtrace)
+ , Input(input)
+ , HadContextSensitiveCondition(false)
+ , HadHeadSensitiveCondition(false)
+ , EvaluateForBuildsystem(false)
+{
+ cmGeneratorExpressionLexer l;
+ std::vector<cmGeneratorExpressionToken> tokens = l.Tokenize(this->Input);
+ this->NeedsEvaluation = l.GetSawGeneratorExpression();
+
+ if (this->NeedsEvaluation) {
+ cmGeneratorExpressionParser p(tokens);
+ p.Parse(this->Evaluators);
+ }
+}
+
+cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression()
+{
+ cmDeleteAll(this->Evaluators);
+}
+
+std::string cmGeneratorExpression::StripEmptyListElements(
+ const std::string& input)
+{
+ if (input.find(';') == input.npos) {
+ return input;
+ }
+ std::string result;
+ result.reserve(input.size());
+
+ const char* c = input.c_str();
+ const char* last = c;
+ bool skipSemiColons = true;
+ for (; *c; ++c) {
+ if (*c == ';') {
+ if (skipSemiColons) {
+ result.append(last, c - last);
+ last = c + 1;
+ }
+ skipSemiColons = true;
+ } else {
+ skipSemiColons = false;
+ }
+ }
+ result.append(last);
+
+ if (!result.empty() && *(result.end() - 1) == ';') {
+ result.resize(result.size() - 1);
+ }
+
+ return result;
+}
+
+static std::string stripAllGeneratorExpressions(const std::string& input)
+{
+ std::string result;
+ std::string::size_type pos = 0;
+ std::string::size_type lastPos = pos;
+ int nestingLevel = 0;
+ while ((pos = input.find("$<", lastPos)) != input.npos) {
+ result += input.substr(lastPos, pos - lastPos);
+ pos += 2;
+ nestingLevel = 1;
+ const char* c = input.c_str() + pos;
+ const char* const cStart = c;
+ for (; *c; ++c) {
+ if (c[0] == '$' && c[1] == '<') {
+ ++nestingLevel;
+ ++c;
+ continue;
+ }
+ if (c[0] == '>') {
+ --nestingLevel;
+ if (nestingLevel == 0) {
+ break;
+ }
+ }
+ }
+ const std::string::size_type traversed = (c - cStart) + 1;
+ if (!*c) {
+ result += "$<" + input.substr(pos, traversed);
+ }
+ pos += traversed;
+ lastPos = pos;
+ }
+ if (nestingLevel == 0) {
+ result += input.substr(lastPos);
+ }
+ return cmGeneratorExpression::StripEmptyListElements(result);
+}
+
+static void prefixItems(const std::string& content, std::string& result,
+ const std::string& prefix)
+{
+ std::vector<std::string> entries;
+ cmGeneratorExpression::Split(content, entries);
+ const char* sep = "";
+ for (std::vector<std::string>::const_iterator ei = entries.begin();
+ ei != entries.end(); ++ei) {
+ result += sep;
+ sep = ";";
+ if (!cmSystemTools::FileIsFullPath(ei->c_str()) &&
+ cmGeneratorExpression::Find(*ei) != 0) {
+ result += prefix;
+ }
+ result += *ei;
+ }
+}
+
+static std::string stripExportInterface(
+ const std::string& input, cmGeneratorExpression::PreprocessContext context,
+ bool resolveRelative)
+{
+ std::string result;
+
+ int nestingLevel = 0;
+ std::string::size_type pos = 0;
+ std::string::size_type lastPos = pos;
+ while (true) {
+ std::string::size_type bPos = input.find("$<BUILD_INTERFACE:", lastPos);
+ std::string::size_type iPos = input.find("$<INSTALL_INTERFACE:", lastPos);
+
+ if (bPos == std::string::npos && iPos == std::string::npos) {
+ break;
+ }
+
+ if (bPos == std::string::npos) {
+ pos = iPos;
+ } else if (iPos == std::string::npos) {
+ pos = bPos;
+ } else {
+ pos = (bPos < iPos) ? bPos : iPos;
+ }
+
+ result += input.substr(lastPos, pos - lastPos);
+ const bool gotInstallInterface = input[pos + 2] == 'I';
+ pos += gotInstallInterface ? sizeof("$<INSTALL_INTERFACE:") - 1
+ : sizeof("$<BUILD_INTERFACE:") - 1;
+ nestingLevel = 1;
+ const char* c = input.c_str() + pos;
+ const char* const cStart = c;
+ for (; *c; ++c) {
+ if (c[0] == '$' && c[1] == '<') {
+ ++nestingLevel;
+ ++c;
+ continue;
+ }
+ if (c[0] == '>') {
+ --nestingLevel;
+ if (nestingLevel != 0) {
+ continue;
+ }
+ if (context == cmGeneratorExpression::BuildInterface &&
+ !gotInstallInterface) {
+ result += input.substr(pos, c - cStart);
+ } else if (context == cmGeneratorExpression::InstallInterface &&
+ gotInstallInterface) {
+ const std::string content = input.substr(pos, c - cStart);
+ if (resolveRelative) {
+ prefixItems(content, result, "${_IMPORT_PREFIX}/");
+ } else {
+ result += content;
+ }
+ }
+ break;
+ }
+ }
+ const std::string::size_type traversed = (c - cStart) + 1;
+ if (!*c) {
+ result += std::string(gotInstallInterface ? "$<INSTALL_INTERFACE:"
+ : "$<BUILD_INTERFACE:") +
+ input.substr(pos, traversed);
+ }
+ pos += traversed;
+ lastPos = pos;
+ }
+ if (nestingLevel == 0) {
+ result += input.substr(lastPos);
+ }
+
+ return cmGeneratorExpression::StripEmptyListElements(result);
+}
+
+void cmGeneratorExpression::Split(const std::string& input,
+ std::vector<std::string>& output)
+{
+ std::string::size_type pos = 0;
+ std::string::size_type lastPos = pos;
+ while ((pos = input.find("$<", lastPos)) != input.npos) {
+ std::string part = input.substr(lastPos, pos - lastPos);
+ std::string preGenex;
+ if (!part.empty()) {
+ std::string::size_type startPos = input.rfind(';', pos);
+ if (startPos == std::string::npos) {
+ preGenex = part;
+ part = "";
+ } else if (startPos != pos - 1 && startPos >= lastPos) {
+ part = input.substr(lastPos, startPos - lastPos);
+ preGenex = input.substr(startPos + 1, pos - startPos - 1);
+ }
+ if (!part.empty()) {
+ cmSystemTools::ExpandListArgument(part, output);
+ }
+ }
+ pos += 2;
+ int nestingLevel = 1;
+ const char* c = input.c_str() + pos;
+ const char* const cStart = c;
+ for (; *c; ++c) {
+ if (c[0] == '$' && c[1] == '<') {
+ ++nestingLevel;
+ ++c;
+ continue;
+ }
+ if (c[0] == '>') {
+ --nestingLevel;
+ if (nestingLevel == 0) {
+ break;
+ }
+ }
+ }
+ for (; *c; ++c) {
+ // Capture the part after the genex and before the next ';'
+ if (c[0] == ';') {
+ --c;
+ break;
+ }
+ }
+ const std::string::size_type traversed = (c - cStart) + 1;
+ output.push_back(preGenex + "$<" + input.substr(pos, traversed));
+ pos += traversed;
+ lastPos = pos;
+ }
+ if (lastPos < input.size()) {
+ cmSystemTools::ExpandListArgument(input.substr(lastPos), output);
+ }
+}
+
+std::string cmGeneratorExpression::Preprocess(const std::string& input,
+ PreprocessContext context,
+ bool resolveRelative)
+{
+ if (context == StripAllGeneratorExpressions) {
+ return stripAllGeneratorExpressions(input);
+ } else if (context == BuildInterface || context == InstallInterface) {
+ return stripExportInterface(input, context, resolveRelative);
+ }
+
+ assert(0 && "cmGeneratorExpression::Preprocess called with invalid args");
+ return std::string();
+}
+
+std::string::size_type cmGeneratorExpression::Find(const std::string& input)
+{
+ const std::string::size_type openpos = input.find("$<");
+ if (openpos != std::string::npos &&
+ input.find('>', openpos) != std::string::npos) {
+ return openpos;
+ }
+ return std::string::npos;
+}
+
+bool cmGeneratorExpression::IsValidTargetName(const std::string& input)
+{
+ // The ':' is supported to allow use with IMPORTED targets. At least
+ // Qt 4 and 5 IMPORTED targets use ':' as the namespace delimiter.
+ static cmsys::RegularExpression targetNameValidator("^[A-Za-z0-9_.:+-]+$");
+
+ return targetNameValidator.find(input);
+}
+
+void cmCompiledGeneratorExpression::GetMaxLanguageStandard(
+ const cmGeneratorTarget* tgt, std::map<std::string, std::string>& mapping)
+{
+ typedef std::map<cmGeneratorTarget const*,
+ std::map<std::string, std::string> >
+ MapType;
+ MapType::const_iterator it = this->MaxLanguageStandard.find(tgt);
+ if (it != this->MaxLanguageStandard.end()) {
+ mapping = it->second;
+ }
+}
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
new file mode 100644
index 0000000..2f91608
--- /dev/null
+++ b/Source/cmGeneratorExpression.h
@@ -0,0 +1,167 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmGeneratorExpression_h
+#define cmGeneratorExpression_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmListFileCache.h"
+
+#include <cm_auto_ptr.hxx>
+#include <cmsys/RegularExpression.hxx>
+
+class cmGeneratorTarget;
+class cmLocalGenerator;
+class cmListFileBacktrace;
+
+struct cmGeneratorExpressionEvaluator;
+struct cmGeneratorExpressionContext;
+struct cmGeneratorExpressionDAGChecker;
+
+class cmCompiledGeneratorExpression;
+
+/** \class cmGeneratorExpression
+ * \brief Evaluate generate-time query expression syntax.
+ *
+ * cmGeneratorExpression instances are used by build system generator
+ * implementations to evaluate the $<> generator expression syntax.
+ * Generator expressions are evaluated just before the generate step
+ * writes strings into the build system. They have knowledge of the
+ * build configuration which is not available at configure time.
+ */
+class cmGeneratorExpression
+{
+public:
+ /** Construct. */
+ cmGeneratorExpression(
+ cmListFileBacktrace const& backtrace = cmListFileBacktrace());
+ ~cmGeneratorExpression();
+
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> Parse(std::string const& input);
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> Parse(const char* input);
+
+ enum PreprocessContext
+ {
+ StripAllGeneratorExpressions,
+ BuildInterface,
+ InstallInterface
+ };
+
+ static std::string Preprocess(const std::string& input,
+ PreprocessContext context,
+ bool resolveRelative = false);
+
+ static void Split(const std::string& input,
+ std::vector<std::string>& output);
+
+ static std::string::size_type Find(const std::string& input);
+
+ static bool IsValidTargetName(const std::string& input);
+
+ static std::string StripEmptyListElements(const std::string& input);
+
+private:
+ cmGeneratorExpression(const cmGeneratorExpression&);
+ void operator=(const cmGeneratorExpression&);
+
+ cmListFileBacktrace Backtrace;
+};
+
+class cmCompiledGeneratorExpression
+{
+public:
+ const char* Evaluate(
+ cmLocalGenerator* lg, const std::string& config, bool quiet = false,
+ cmGeneratorTarget const* headTarget = CM_NULLPTR,
+ cmGeneratorTarget const* currentTarget = CM_NULLPTR,
+ cmGeneratorExpressionDAGChecker* dagChecker = CM_NULLPTR,
+ std::string const& language = std::string()) const;
+ const char* Evaluate(cmLocalGenerator* lg, const std::string& config,
+ bool quiet, cmGeneratorTarget const* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::string const& language = std::string()) const;
+
+ /** Get set of targets found during evaluations. */
+ std::set<cmGeneratorTarget*> const& GetTargets() const
+ {
+ return this->DependTargets;
+ }
+
+ std::set<std::string> const& GetSeenTargetProperties() const
+ {
+ return this->SeenTargetProperties;
+ }
+
+ std::set<cmGeneratorTarget const*> const& GetAllTargetsSeen() const
+ {
+ return this->AllTargetsSeen;
+ }
+
+ ~cmCompiledGeneratorExpression();
+
+ std::string const& GetInput() const { return this->Input; }
+
+ cmListFileBacktrace GetBacktrace() const { return this->Backtrace; }
+ bool GetHadContextSensitiveCondition() const
+ {
+ return this->HadContextSensitiveCondition;
+ }
+ bool GetHadHeadSensitiveCondition() const
+ {
+ return this->HadHeadSensitiveCondition;
+ }
+ std::set<cmGeneratorTarget const*> GetSourceSensitiveTargets() const
+ {
+ return this->SourceSensitiveTargets;
+ }
+
+ void SetEvaluateForBuildsystem(bool eval)
+ {
+ this->EvaluateForBuildsystem = eval;
+ }
+
+ void GetMaxLanguageStandard(cmGeneratorTarget const* tgt,
+ std::map<std::string, std::string>& mapping);
+
+private:
+ const char* EvaluateWithContext(
+ cmGeneratorExpressionContext& context,
+ cmGeneratorExpressionDAGChecker* dagChecker) const;
+
+ cmCompiledGeneratorExpression(cmListFileBacktrace const& backtrace,
+ const std::string& input);
+
+ friend class cmGeneratorExpression;
+
+ cmCompiledGeneratorExpression(const cmCompiledGeneratorExpression&);
+ void operator=(const cmCompiledGeneratorExpression&);
+
+ cmListFileBacktrace Backtrace;
+ std::vector<cmGeneratorExpressionEvaluator*> Evaluators;
+ const std::string Input;
+ bool NeedsEvaluation;
+
+ mutable std::set<cmGeneratorTarget*> DependTargets;
+ mutable std::set<cmGeneratorTarget const*> AllTargetsSeen;
+ mutable std::set<std::string> SeenTargetProperties;
+ mutable std::map<cmGeneratorTarget const*,
+ std::map<std::string, std::string> >
+ MaxLanguageStandard;
+ mutable std::string Output;
+ mutable bool HadContextSensitiveCondition;
+ mutable bool HadHeadSensitiveCondition;
+ mutable std::set<cmGeneratorTarget const*> SourceSensitiveTargets;
+ bool EvaluateForBuildsystem;
+};
+
+#endif
diff --git a/Source/cmGeneratorExpressionContext.cxx b/Source/cmGeneratorExpressionContext.cxx
new file mode 100644
index 0000000..8da6b50
--- /dev/null
+++ b/Source/cmGeneratorExpressionContext.cxx
@@ -0,0 +1,34 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmGeneratorExpressionContext.h"
+
+#include "cmGeneratorTarget.h"
+
+cmGeneratorExpressionContext::cmGeneratorExpressionContext(
+ cmLocalGenerator* lg, std::string const& config, bool quiet,
+ cmGeneratorTarget const* headTarget, const cmGeneratorTarget* currentTarget,
+ bool evaluateForBuildsystem, cmListFileBacktrace const& backtrace,
+ std::string const& language)
+ : Backtrace(backtrace)
+ , LG(lg)
+ , Config(config)
+ , Language(language)
+ , HeadTarget(headTarget)
+ , CurrentTarget(currentTarget)
+ , Quiet(quiet)
+ , HadError(false)
+ , HadContextSensitiveCondition(false)
+ , HadHeadSensitiveCondition(false)
+ , EvaluateForBuildsystem(evaluateForBuildsystem)
+{
+}
diff --git a/Source/cmGeneratorExpressionContext.h b/Source/cmGeneratorExpressionContext.h
new file mode 100644
index 0000000..cff7289
--- /dev/null
+++ b/Source/cmGeneratorExpressionContext.h
@@ -0,0 +1,55 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGeneratorExpressionContext_h
+#define cmGeneratorExpressionContext_h
+
+#include "cmListFileCache.h"
+
+#include <map>
+#include <set>
+#include <string>
+
+class cmGeneratorTarget;
+class cmLocalGenerator;
+
+struct cmGeneratorExpressionContext
+{
+ cmGeneratorExpressionContext(cmLocalGenerator* lg, std::string const& config,
+ bool quiet, const cmGeneratorTarget* headTarget,
+ cmGeneratorTarget const* currentTarget,
+ bool evaluateForBuildsystem,
+ cmListFileBacktrace const& backtrace,
+ std::string const& language);
+
+ cmListFileBacktrace Backtrace;
+ std::set<cmGeneratorTarget*> DependTargets;
+ std::set<cmGeneratorTarget const*> AllTargets;
+ std::set<std::string> SeenTargetProperties;
+ std::set<cmGeneratorTarget const*> SourceSensitiveTargets;
+ std::map<cmGeneratorTarget const*, std::map<std::string, std::string> >
+ MaxLanguageStandard;
+ cmLocalGenerator* LG;
+ std::string Config;
+ std::string Language;
+ // The target whose property is being evaluated.
+ cmGeneratorTarget const* HeadTarget;
+ // The dependent of HeadTarget which appears
+ // directly or indirectly in the property.
+ cmGeneratorTarget const* CurrentTarget;
+ bool Quiet;
+ bool HadError;
+ bool HadContextSensitiveCondition;
+ bool HadHeadSensitiveCondition;
+ bool EvaluateForBuildsystem;
+};
+
+#endif
diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx
new file mode 100644
index 0000000..c700156
--- /dev/null
+++ b/Source/cmGeneratorExpressionDAGChecker.cxx
@@ -0,0 +1,225 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmGeneratorExpressionDAGChecker.h"
+
+#include "cmAlgorithms.h"
+#include "cmLocalGenerator.h"
+
+cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
+ const cmListFileBacktrace& backtrace, const std::string& target,
+ const std::string& property, const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* parent)
+ : Parent(parent)
+ , Target(target)
+ , Property(property)
+ , Content(content)
+ , Backtrace(backtrace)
+ , TransitivePropertiesOnly(false)
+{
+ Initialize();
+}
+
+cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
+ const std::string& target, const std::string& property,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* parent)
+ : Parent(parent)
+ , Target(target)
+ , Property(property)
+ , Content(content)
+ , Backtrace()
+ , TransitivePropertiesOnly(false)
+{
+ Initialize();
+}
+
+void cmGeneratorExpressionDAGChecker::Initialize()
+{
+ const cmGeneratorExpressionDAGChecker* top = this;
+ const cmGeneratorExpressionDAGChecker* p = this->Parent;
+ while (p) {
+ top = p;
+ p = p->Parent;
+ }
+ this->CheckResult = this->CheckGraph();
+
+#define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) top->METHOD() ||
+
+ if (CheckResult == DAG && (CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
+ TEST_TRANSITIVE_PROPERTY_METHOD) false))
+#undef TEST_TRANSITIVE_PROPERTY_METHOD
+ {
+ std::map<std::string, std::set<std::string> >::const_iterator it =
+ top->Seen.find(this->Target);
+ if (it != top->Seen.end()) {
+ const std::set<std::string>& propSet = it->second;
+ if (propSet.find(this->Property) != propSet.end()) {
+ this->CheckResult = ALREADY_SEEN;
+ return;
+ }
+ }
+ const_cast<cmGeneratorExpressionDAGChecker*>(top)
+ ->Seen[this->Target]
+ .insert(this->Property);
+ }
+}
+
+cmGeneratorExpressionDAGChecker::Result
+cmGeneratorExpressionDAGChecker::Check() const
+{
+ return this->CheckResult;
+}
+
+void cmGeneratorExpressionDAGChecker::ReportError(
+ cmGeneratorExpressionContext* context, const std::string& expr)
+{
+ if (this->CheckResult == DAG) {
+ return;
+ }
+
+ context->HadError = true;
+ if (context->Quiet) {
+ return;
+ }
+
+ const cmGeneratorExpressionDAGChecker* parent = this->Parent;
+
+ if (parent && !parent->Parent) {
+ std::ostringstream e;
+ e << "Error evaluating generator expression:\n"
+ << " " << expr << "\n"
+ << "Self reference on target \"" << context->HeadTarget->GetName()
+ << "\".\n";
+ context->LG->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
+ parent->Backtrace);
+ return;
+ }
+
+ {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "Error evaluating generator expression:\n"
+ << " " << expr << "\n"
+ << "Dependency loop found.";
+ /* clang-format on */
+ context->LG->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
+ context->Backtrace);
+ }
+
+ int loopStep = 1;
+ while (parent) {
+ std::ostringstream e;
+ e << "Loop step " << loopStep << "\n"
+ << " "
+ << (parent->Content ? parent->Content->GetOriginalExpression() : expr)
+ << "\n";
+ context->LG->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
+ parent->Backtrace);
+ parent = parent->Parent;
+ ++loopStep;
+ }
+}
+
+cmGeneratorExpressionDAGChecker::Result
+cmGeneratorExpressionDAGChecker::CheckGraph() const
+{
+ const cmGeneratorExpressionDAGChecker* parent = this->Parent;
+ while (parent) {
+ if (this->Target == parent->Target && this->Property == parent->Property) {
+ return (parent == this->Parent) ? SELF_REFERENCE : CYCLIC_REFERENCE;
+ }
+ parent = parent->Parent;
+ }
+ return DAG;
+}
+
+bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly()
+{
+ const cmGeneratorExpressionDAGChecker* top = this;
+ const cmGeneratorExpressionDAGChecker* parent = this->Parent;
+ while (parent) {
+ top = parent;
+ parent = parent->Parent;
+ }
+
+ return top->TransitivePropertiesOnly;
+}
+
+bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(const char* tgt)
+{
+ const cmGeneratorExpressionDAGChecker* top = this;
+ const cmGeneratorExpressionDAGChecker* parent = this->Parent;
+ while (parent) {
+ top = parent;
+ parent = parent->Parent;
+ }
+
+ const char* prop = top->Property.c_str();
+
+ if (tgt) {
+ return top->Target == tgt && strcmp(prop, "LINK_LIBRARIES") == 0;
+ }
+
+ return (strcmp(prop, "LINK_LIBRARIES") == 0 ||
+ strcmp(prop, "LINK_INTERFACE_LIBRARIES") == 0 ||
+ strcmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES") == 0 ||
+ cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES_") ||
+ cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_")) ||
+ strcmp(prop, "INTERFACE_LINK_LIBRARIES") == 0;
+}
+
+std::string cmGeneratorExpressionDAGChecker::TopTarget() const
+{
+ const cmGeneratorExpressionDAGChecker* top = this;
+ const cmGeneratorExpressionDAGChecker* parent = this->Parent;
+ while (parent) {
+ top = parent;
+ parent = parent->Parent;
+ }
+ return top->Target;
+}
+
+enum TransitiveProperty
+{
+#define DEFINE_ENUM_ENTRY(NAME) NAME,
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(DEFINE_ENUM_ENTRY)
+#undef DEFINE_ENUM_ENTRY
+ TransitivePropertyTerminal
+};
+
+template <TransitiveProperty>
+bool additionalTest(const char* const)
+{
+ return false;
+}
+
+template <>
+bool additionalTest<COMPILE_DEFINITIONS>(const char* const prop)
+{
+ return cmHasLiteralPrefix(prop, "COMPILE_DEFINITIONS_");
+}
+
+#define DEFINE_TRANSITIVE_PROPERTY_METHOD(METHOD, PROPERTY) \
+ bool cmGeneratorExpressionDAGChecker::METHOD() const \
+ { \
+ const char* const prop = this->Property.c_str(); \
+ if (strcmp(prop, #PROPERTY) == 0 || \
+ strcmp(prop, "INTERFACE_" #PROPERTY) == 0) { \
+ return true; \
+ } \
+ return additionalTest<PROPERTY>(prop); \
+ }
+
+CM_FOR_EACH_TRANSITIVE_PROPERTY(DEFINE_TRANSITIVE_PROPERTY_METHOD)
+
+#undef DEFINE_TRANSITIVE_PROPERTY_METHOD
diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h
new file mode 100644
index 0000000..6b7fe9a
--- /dev/null
+++ b/Source/cmGeneratorExpressionDAGChecker.h
@@ -0,0 +1,94 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGeneratorExpressionDAGChecker_h
+#define cmGeneratorExpressionDAGChecker_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmGeneratorExpressionEvaluator.h"
+
+#define CM_SELECT_BOTH(F, A1, A2) F(A1, A2)
+#define CM_SELECT_FIRST(F, A1, A2) F(A1)
+#define CM_SELECT_SECOND(F, A1, A2) F(A2)
+
+#define CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, SELECT) \
+ SELECT(F, EvaluatingIncludeDirectories, INCLUDE_DIRECTORIES) \
+ SELECT(F, EvaluatingSystemIncludeDirectories, SYSTEM_INCLUDE_DIRECTORIES) \
+ SELECT(F, EvaluatingCompileDefinitions, COMPILE_DEFINITIONS) \
+ SELECT(F, EvaluatingCompileOptions, COMPILE_OPTIONS) \
+ SELECT(F, EvaluatingAutoUicOptions, AUTOUIC_OPTIONS) \
+ SELECT(F, EvaluatingSources, SOURCES) \
+ SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES)
+
+#define CM_FOR_EACH_TRANSITIVE_PROPERTY(F) \
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH)
+
+#define CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(F) \
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_FIRST)
+
+#define CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(F) \
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_SECOND)
+
+struct cmGeneratorExpressionDAGChecker
+{
+ cmGeneratorExpressionDAGChecker(const cmListFileBacktrace& backtrace,
+ const std::string& target,
+ const std::string& property,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* parent);
+ cmGeneratorExpressionDAGChecker(const std::string& target,
+ const std::string& property,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* parent);
+
+ enum Result
+ {
+ DAG,
+ SELF_REFERENCE,
+ CYCLIC_REFERENCE,
+ ALREADY_SEEN
+ };
+
+ Result Check() const;
+
+ void ReportError(cmGeneratorExpressionContext* context,
+ const std::string& expr);
+
+ bool EvaluatingLinkLibraries(const char* tgt = CM_NULLPTR);
+
+#define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) bool METHOD() const;
+
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(DECLARE_TRANSITIVE_PROPERTY_METHOD)
+
+#undef DECLARE_TRANSITIVE_PROPERTY_METHOD
+
+ bool GetTransitivePropertiesOnly();
+ void SetTransitivePropertiesOnly() { this->TransitivePropertiesOnly = true; }
+
+ std::string TopTarget() const;
+
+private:
+ Result CheckGraph() const;
+ void Initialize();
+
+private:
+ const cmGeneratorExpressionDAGChecker* const Parent;
+ const std::string Target;
+ const std::string Property;
+ std::map<std::string, std::set<std::string> > Seen;
+ const GeneratorExpressionContent* const Content;
+ const cmListFileBacktrace Backtrace;
+ Result CheckResult;
+ bool TransitivePropertiesOnly;
+};
+
+#endif
diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx
new file mode 100644
index 0000000..c01c4fc
--- /dev/null
+++ b/Source/cmGeneratorExpressionEvaluationFile.cxx
@@ -0,0 +1,163 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmGeneratorExpressionEvaluationFile.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include <cmsys/FStream.hxx>
+
+#include <assert.h>
+
+cmGeneratorExpressionEvaluationFile::cmGeneratorExpressionEvaluationFile(
+ const std::string& input,
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> outputFileExpr,
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> condition, bool inputIsContent)
+ : Input(input)
+ , OutputFileExpr(outputFileExpr)
+ , Condition(condition)
+ , InputIsContent(inputIsContent)
+{
+}
+
+void cmGeneratorExpressionEvaluationFile::Generate(
+ cmLocalGenerator* lg, const std::string& config, const std::string& lang,
+ cmCompiledGeneratorExpression* inputExpression,
+ std::map<std::string, std::string>& outputFiles, mode_t perm)
+{
+ std::string rawCondition = this->Condition->GetInput();
+ if (!rawCondition.empty()) {
+ std::string condResult = this->Condition->Evaluate(
+ lg, config, false, CM_NULLPTR, CM_NULLPTR, CM_NULLPTR, lang);
+ if (condResult == "0") {
+ return;
+ }
+ if (condResult != "1") {
+ std::ostringstream e;
+ e << "Evaluation file condition \"" << rawCondition
+ << "\" did "
+ "not evaluate to valid content. Got \""
+ << condResult << "\".";
+ lg->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ }
+
+ const std::string outputFileName = this->OutputFileExpr->Evaluate(
+ lg, config, false, CM_NULLPTR, CM_NULLPTR, CM_NULLPTR, lang);
+ const std::string outputContent = inputExpression->Evaluate(
+ lg, config, false, CM_NULLPTR, CM_NULLPTR, CM_NULLPTR, lang);
+
+ std::map<std::string, std::string>::iterator it =
+ outputFiles.find(outputFileName);
+
+ if (it != outputFiles.end()) {
+ if (it->second == outputContent) {
+ return;
+ }
+ std::ostringstream e;
+ e << "Evaluation file to be written multiple times for different "
+ "configurations or languages with different content:\n "
+ << outputFileName;
+ lg->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+
+ lg->GetMakefile()->AddCMakeOutputFile(outputFileName);
+ this->Files.push_back(outputFileName);
+ outputFiles[outputFileName] = outputContent;
+
+ cmGeneratedFileStream fout(outputFileName.c_str());
+ fout.SetCopyIfDifferent(true);
+ fout << outputContent;
+ if (fout.Close() && perm) {
+ cmSystemTools::SetPermissions(outputFileName.c_str(), perm);
+ }
+}
+
+void cmGeneratorExpressionEvaluationFile::CreateOutputFile(
+ cmLocalGenerator* lg, std::string const& config)
+{
+ std::vector<std::string> enabledLanguages;
+ cmGlobalGenerator* gg = lg->GetGlobalGenerator();
+ gg->GetEnabledLanguages(enabledLanguages);
+
+ for (std::vector<std::string>::const_iterator le = enabledLanguages.begin();
+ le != enabledLanguages.end(); ++le) {
+ std::string name = this->OutputFileExpr->Evaluate(
+ lg, config, false, CM_NULLPTR, CM_NULLPTR, CM_NULLPTR, *le);
+ cmSourceFile* sf = lg->GetMakefile()->GetOrCreateSource(name);
+ sf->SetProperty("GENERATED", "1");
+
+ gg->SetFilenameTargetDepends(
+ sf, this->OutputFileExpr->GetSourceSensitiveTargets());
+ }
+}
+
+void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg)
+{
+ mode_t perm = 0;
+ std::string inputContent;
+ if (this->InputIsContent) {
+ inputContent = this->Input;
+ } else {
+ lg->GetMakefile()->AddCMakeDependFile(this->Input);
+ cmSystemTools::GetPermissions(this->Input.c_str(), perm);
+ cmsys::ifstream fin(this->Input.c_str());
+ if (!fin) {
+ std::ostringstream e;
+ e << "Evaluation file \"" << this->Input << "\" cannot be read.";
+ lg->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+
+ std::string line;
+ std::string sep;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ inputContent += sep + line;
+ sep = "\n";
+ }
+ inputContent += sep;
+ }
+
+ cmListFileBacktrace lfbt = this->OutputFileExpr->GetBacktrace();
+ cmGeneratorExpression contentGE(lfbt);
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> inputExpression =
+ contentGE.Parse(inputContent);
+
+ std::map<std::string, std::string> outputFiles;
+
+ std::vector<std::string> allConfigs;
+ lg->GetMakefile()->GetConfigurations(allConfigs);
+
+ if (allConfigs.empty()) {
+ allConfigs.push_back("");
+ }
+
+ std::vector<std::string> enabledLanguages;
+ cmGlobalGenerator* gg = lg->GetGlobalGenerator();
+ gg->GetEnabledLanguages(enabledLanguages);
+
+ for (std::vector<std::string>::const_iterator le = enabledLanguages.begin();
+ le != enabledLanguages.end(); ++le) {
+ for (std::vector<std::string>::const_iterator li = allConfigs.begin();
+ li != allConfigs.end(); ++li) {
+ this->Generate(lg, *li, *le, inputExpression.get(), outputFiles, perm);
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return;
+ }
+ }
+ }
+}
diff --git a/Source/cmGeneratorExpressionEvaluationFile.h b/Source/cmGeneratorExpressionEvaluationFile.h
new file mode 100644
index 0000000..52ba2d8
--- /dev/null
+++ b/Source/cmGeneratorExpressionEvaluationFile.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGeneratorExpressionEvaluationFile_h
+#define cmGeneratorExpressionEvaluationFile_h
+
+#include "cmGeneratorExpression.h"
+
+#include <cm_auto_ptr.hxx>
+#include <sys/types.h>
+
+class cmLocalGenerator;
+
+class cmGeneratorExpressionEvaluationFile
+{
+public:
+ cmGeneratorExpressionEvaluationFile(
+ const std::string& input,
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> outputFileExpr,
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> condition, bool inputIsContent);
+
+ void Generate(cmLocalGenerator* lg);
+
+ std::vector<std::string> GetFiles() const { return this->Files; }
+
+ void CreateOutputFile(cmLocalGenerator* lg, std::string const& config);
+
+private:
+ void Generate(cmLocalGenerator* lg, const std::string& config,
+ const std::string& lang,
+ cmCompiledGeneratorExpression* inputExpression,
+ std::map<std::string, std::string>& outputFiles, mode_t perm);
+
+private:
+ const std::string Input;
+ const CM_AUTO_PTR<cmCompiledGeneratorExpression> OutputFileExpr;
+ const CM_AUTO_PTR<cmCompiledGeneratorExpression> Condition;
+ std::vector<std::string> Files;
+ const bool InputIsContent;
+};
+
+#endif
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
new file mode 100644
index 0000000..66437eb
--- /dev/null
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -0,0 +1,211 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGeneratorExpressionEvaluator.h"
+
+#include "cmAlgorithms.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGeneratorExpressionParser.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+
+#include <cmsys/String.h>
+
+#include <assert.h>
+#include <errno.h>
+
+#include "cmGeneratorExpressionNode.h"
+
+GeneratorExpressionContent::GeneratorExpressionContent(
+ const char* startContent, size_t length)
+ : StartContent(startContent)
+ , ContentLength(length)
+{
+}
+
+std::string GeneratorExpressionContent::GetOriginalExpression() const
+{
+ return std::string(this->StartContent, this->ContentLength);
+}
+
+std::string GeneratorExpressionContent::ProcessArbitraryContent(
+ const cmGeneratorExpressionNode* node, const std::string& identifier,
+ cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
+ pit) const
+{
+ std::string result;
+
+ const std::vector<
+ 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) {
+ if (node->RequiresLiteralInput()) {
+ if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text) {
+ reportError(context, this->GetOriginalExpression(), "$<" +
+ identifier + "> expression requires literal input.");
+ return std::string();
+ }
+ }
+ result += (*it)->Evaluate(context, dagChecker);
+ if (context->HadError) {
+ return std::string();
+ }
+ }
+ if ((pit + 1) != pend) {
+ result += ",";
+ }
+ }
+ if (node->RequiresLiteralInput()) {
+ std::vector<std::string> parameters;
+ parameters.push_back(result);
+ return node->Evaluate(parameters, context, this, dagChecker);
+ }
+ return result;
+}
+
+std::string GeneratorExpressionContent::Evaluate(
+ cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagChecker) const
+{
+ 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);
+ if (context->HadError) {
+ return std::string();
+ }
+ }
+ }
+
+ const cmGeneratorExpressionNode* node =
+ cmGeneratorExpressionNode::GetNode(identifier);
+
+ if (!node) {
+ reportError(context, this->GetOriginalExpression(),
+ "Expression did not evaluate to a known generator expression");
+ return std::string();
+ }
+
+ if (!node->GeneratesContent()) {
+ if (node->NumExpectedParameters() == 1 &&
+ node->AcceptsArbitraryContentParameter()) {
+ if (this->ParamChildren.empty()) {
+ reportError(context, this->GetOriginalExpression(),
+ "$<" + identifier + "> expression requires a parameter.");
+ }
+ } else {
+ std::vector<std::string> parameters;
+ this->EvaluateParameters(node, identifier, context, dagChecker,
+ parameters);
+ }
+ return std::string();
+ }
+
+ std::vector<std::string> parameters;
+ this->EvaluateParameters(node, identifier, context, dagChecker, parameters);
+ if (context->HadError) {
+ return std::string();
+ }
+
+ return node->Evaluate(parameters, context, this, dagChecker);
+}
+
+std::string GeneratorExpressionContent::EvaluateParameters(
+ const cmGeneratorExpressionNode* node, const std::string& identifier,
+ cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::vector<std::string>& parameters) const
+{
+ const int numExpected = node->NumExpectedParameters();
+ {
+ std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
+ pit = this->ParamChildren.begin();
+ const std::vector<
+ std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator pend =
+ this->ParamChildren.end();
+ const bool acceptsArbitraryContent =
+ node->AcceptsArbitraryContentParameter();
+ int counter = 1;
+ for (; pit != pend; ++pit, ++counter) {
+ if (acceptsArbitraryContent && counter == numExpected) {
+ std::string lastParam = this->ProcessArbitraryContent(
+ node, identifier, context, dagChecker, pit);
+ parameters.push_back(lastParam);
+ return std::string();
+ } else {
+ 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);
+ if (context->HadError) {
+ return std::string();
+ }
+ }
+ parameters.push_back(parameter);
+ }
+ }
+ }
+
+ if ((numExpected > cmGeneratorExpressionNode::DynamicParameters &&
+ (unsigned int)numExpected != parameters.size())) {
+ if (numExpected == 0) {
+ reportError(context, this->GetOriginalExpression(),
+ "$<" + identifier + "> expression requires no parameters.");
+ } else if (numExpected == 1) {
+ reportError(context, this->GetOriginalExpression(), "$<" + identifier +
+ "> expression requires "
+ "exactly one parameter.");
+ } else {
+ std::ostringstream e;
+ e << "$<" + identifier + "> expression requires " << numExpected
+ << " comma separated parameters, but got " << parameters.size()
+ << " instead.";
+ reportError(context, this->GetOriginalExpression(), e.str());
+ }
+ return std::string();
+ }
+
+ if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters &&
+ parameters.empty()) {
+ reportError(context, this->GetOriginalExpression(), "$<" + identifier +
+ "> expression requires at least one parameter.");
+ }
+ if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters &&
+ parameters.size() > 1) {
+ reportError(context, this->GetOriginalExpression(), "$<" + identifier +
+ "> expression requires one or zero parameters.");
+ }
+ return std::string();
+}
+
+GeneratorExpressionContent::~GeneratorExpressionContent()
+{
+ cmDeleteAll(this->IdentifierChildren);
+ std::for_each(this->ParamChildren.begin(), this->ParamChildren.end(),
+ cmDeleteAll<std::vector<cmGeneratorExpressionEvaluator*> >);
+}
diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h
new file mode 100644
index 0000000..58e732b
--- /dev/null
+++ b/Source/cmGeneratorExpressionEvaluator.h
@@ -0,0 +1,121 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGeneratorExpressionEvaluator_h
+#define cmGeneratorExpressionEvaluator_h
+
+#include "cmGeneratorExpressionContext.h"
+
+#include "cmListFileCache.h"
+
+#include <string>
+#include <vector>
+
+struct cmGeneratorExpressionDAGChecker;
+struct cmGeneratorExpressionNode;
+
+struct cmGeneratorExpressionEvaluator
+{
+ cmGeneratorExpressionEvaluator() {}
+ virtual ~cmGeneratorExpressionEvaluator() {}
+
+ enum Type
+ {
+ Text,
+ Generator
+ };
+
+ virtual Type GetType() const = 0;
+
+ virtual std::string Evaluate(cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker*) const = 0;
+
+private:
+ cmGeneratorExpressionEvaluator(const cmGeneratorExpressionEvaluator&);
+ void operator=(const cmGeneratorExpressionEvaluator&);
+};
+
+struct TextContent : public cmGeneratorExpressionEvaluator
+{
+ TextContent(const char* start, size_t length)
+ : Content(start)
+ , Length(length)
+ {
+ }
+
+ std::string Evaluate(cmGeneratorExpressionContext*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return std::string(this->Content, this->Length);
+ }
+
+ Type GetType() const CM_OVERRIDE
+ {
+ return cmGeneratorExpressionEvaluator::Text;
+ }
+
+ void Extend(size_t length) { this->Length += length; }
+
+ size_t GetLength() { return this->Length; }
+
+private:
+ const char* Content;
+ size_t Length;
+};
+
+struct GeneratorExpressionContent : public cmGeneratorExpressionEvaluator
+{
+ GeneratorExpressionContent(const char* startContent, size_t length);
+ void SetIdentifier(std::vector<cmGeneratorExpressionEvaluator*> identifier)
+ {
+ this->IdentifierChildren = identifier;
+ }
+
+ void SetParameters(
+ std::vector<std::vector<cmGeneratorExpressionEvaluator*> > parameters)
+ {
+ this->ParamChildren = parameters;
+ }
+
+ Type GetType() const CM_OVERRIDE
+ {
+ return cmGeneratorExpressionEvaluator::Generator;
+ }
+
+ std::string Evaluate(cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE;
+
+ std::string GetOriginalExpression() const;
+
+ ~GeneratorExpressionContent() CM_OVERRIDE;
+
+private:
+ std::string EvaluateParameters(const cmGeneratorExpressionNode* node,
+ const std::string& identifier,
+ cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::vector<std::string>& parameters) const;
+
+ std::string ProcessArbitraryContent(
+ const cmGeneratorExpressionNode* node, const std::string& identifier,
+ cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
+ pit) const;
+
+private:
+ std::vector<cmGeneratorExpressionEvaluator*> IdentifierChildren;
+ std::vector<std::vector<cmGeneratorExpressionEvaluator*> > ParamChildren;
+ const char* StartContent;
+ size_t ContentLength;
+};
+
+#endif
diff --git a/Source/cmGeneratorExpressionLexer.cxx b/Source/cmGeneratorExpressionLexer.cxx
new file mode 100644
index 0000000..5a4eccc
--- /dev/null
+++ b/Source/cmGeneratorExpressionLexer.cxx
@@ -0,0 +1,75 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGeneratorExpressionLexer.h"
+
+cmGeneratorExpressionLexer::cmGeneratorExpressionLexer()
+ : SawBeginExpression(false)
+ , SawGeneratorExpression(false)
+{
+}
+
+static void InsertText(const char* upto, const char* c,
+ std::vector<cmGeneratorExpressionToken>& result)
+{
+ if (upto != c) {
+ result.push_back(cmGeneratorExpressionToken(
+ cmGeneratorExpressionToken::Text, upto, c - upto));
+ }
+}
+
+std::vector<cmGeneratorExpressionToken> cmGeneratorExpressionLexer::Tokenize(
+ const std::string& input)
+{
+ std::vector<cmGeneratorExpressionToken> result;
+
+ const char* c = input.c_str();
+ const char* upto = c;
+
+ for (; *c; ++c) {
+ switch (*c) {
+ case '$':
+ if (c[1] == '<') {
+ InsertText(upto, c, result);
+ result.push_back(cmGeneratorExpressionToken(
+ cmGeneratorExpressionToken::BeginExpression, c, 2));
+ upto = c + 2;
+ ++c;
+ SawBeginExpression = true;
+ }
+ break;
+ case '>':
+ InsertText(upto, c, result);
+ result.push_back(cmGeneratorExpressionToken(
+ cmGeneratorExpressionToken::EndExpression, c, 1));
+ upto = c + 1;
+ SawGeneratorExpression = SawBeginExpression;
+ break;
+ case ':':
+ InsertText(upto, c, result);
+ result.push_back(cmGeneratorExpressionToken(
+ cmGeneratorExpressionToken::ColonSeparator, c, 1));
+ upto = c + 1;
+ break;
+ case ',':
+ InsertText(upto, c, result);
+ result.push_back(cmGeneratorExpressionToken(
+ cmGeneratorExpressionToken::CommaSeparator, c, 1));
+ upto = c + 1;
+ break;
+ default:
+ break;
+ }
+ }
+ InsertText(upto, c, result);
+
+ return result;
+}
diff --git a/Source/cmGeneratorExpressionLexer.h b/Source/cmGeneratorExpressionLexer.h
new file mode 100644
index 0000000..72ad731
--- /dev/null
+++ b/Source/cmGeneratorExpressionLexer.h
@@ -0,0 +1,60 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGeneratorExpressionLexer_h
+#define cmGeneratorExpressionLexer_h
+
+#include "cmStandardIncludes.h"
+
+#include <vector>
+
+struct cmGeneratorExpressionToken
+{
+ cmGeneratorExpressionToken(unsigned type, const char* c, size_t l)
+ : TokenType(type)
+ , Content(c)
+ , Length(l)
+ {
+ }
+ enum
+ {
+ Text,
+ BeginExpression,
+ EndExpression,
+ ColonSeparator,
+ CommaSeparator
+ };
+ unsigned TokenType;
+ const char* Content;
+ size_t Length;
+};
+
+/** \class cmGeneratorExpressionLexer
+ *
+ */
+class cmGeneratorExpressionLexer
+{
+public:
+ cmGeneratorExpressionLexer();
+
+ std::vector<cmGeneratorExpressionToken> Tokenize(const std::string& input);
+
+ bool GetSawGeneratorExpression() const
+ {
+ return this->SawGeneratorExpression;
+ }
+
+private:
+ bool SawBeginExpression;
+ bool SawGeneratorExpression;
+};
+
+#endif
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
new file mode 100644
index 0000000..ca7250b
--- /dev/null
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -0,0 +1,1708 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmGeneratorExpressionNode.h"
+
+#include "cmAlgorithms.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+
+std::string cmGeneratorExpressionNode::EvaluateDependentExpression(
+ std::string const& prop, cmLocalGenerator* lg,
+ cmGeneratorExpressionContext* context, cmGeneratorTarget const* headTarget,
+ cmGeneratorTarget const* currentTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker)
+{
+ cmGeneratorExpression ge(context->Backtrace);
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
+ cge->SetEvaluateForBuildsystem(context->EvaluateForBuildsystem);
+ std::string result =
+ cge->Evaluate(lg, context->Config, context->Quiet, headTarget,
+ currentTarget, dagChecker, context->Language);
+ if (cge->GetHadContextSensitiveCondition()) {
+ context->HadContextSensitiveCondition = true;
+ }
+ if (cge->GetHadHeadSensitiveCondition()) {
+ context->HadHeadSensitiveCondition = true;
+ }
+ return result;
+}
+
+static const struct ZeroNode : public cmGeneratorExpressionNode
+{
+ ZeroNode() {}
+
+ bool GeneratesContent() const CM_OVERRIDE { return false; }
+
+ bool AcceptsArbitraryContentParameter() const CM_OVERRIDE { return true; }
+
+ std::string Evaluate(const std::vector<std::string>&,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return std::string();
+ }
+} zeroNode;
+
+static const struct OneNode : public cmGeneratorExpressionNode
+{
+ OneNode() {}
+
+ bool AcceptsArbitraryContentParameter() const CM_OVERRIDE { return true; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return parameters.front();
+ }
+} oneNode;
+
+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() {} \
+ 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; \
+ } else 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
+
+static const struct NotNode : public cmGeneratorExpressionNode
+{
+ NotNode() {}
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ if (*parameters.begin() != "0" && *parameters.begin() != "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";
+ }
+} notNode;
+
+static const struct BoolNode : public cmGeneratorExpressionNode
+{
+ BoolNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 1; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return !cmSystemTools::IsOff(parameters.begin()->c_str()) ? "1" : "0";
+ }
+} boolNode;
+
+static const struct StrEqualNode : public cmGeneratorExpressionNode
+{
+ StrEqualNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 2; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return *parameters.begin() == parameters[1] ? "1" : "0";
+ }
+} strEqualNode;
+
+static const struct EqualNode : public cmGeneratorExpressionNode
+{
+ EqualNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 2; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker*) const CM_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;
+ }
+
+ base = 0;
+ flipSign = false;
+
+ 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")) {
+ base = 2;
+ rhs += 3;
+ flipSign = true;
+ }
+ if (cmHasLiteralPrefix(rhs, "+0b") || cmHasLiteralPrefix(rhs, "+0B")) {
+ base = 2;
+ rhs += 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();
+ }
+
+ if (flipSign) {
+ rnum = -rnum;
+ }
+
+ return lnum == rnum ? "1" : "0";
+ }
+} equalNode;
+
+static const struct LowerCaseNode : public cmGeneratorExpressionNode
+{
+ LowerCaseNode() {}
+
+ bool AcceptsArbitraryContentParameter() const CM_OVERRIDE { return true; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return cmSystemTools::LowerCase(parameters.front());
+ }
+} lowerCaseNode;
+
+static const struct UpperCaseNode : public cmGeneratorExpressionNode
+{
+ UpperCaseNode() {}
+
+ bool AcceptsArbitraryContentParameter() const CM_OVERRIDE { return true; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return cmSystemTools::UpperCase(parameters.front());
+ }
+} upperCaseNode;
+
+static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode
+{
+ MakeCIdentifierNode() {}
+
+ bool AcceptsArbitraryContentParameter() const CM_OVERRIDE { return true; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return cmSystemTools::MakeCidentifier(parameters.front());
+ }
+} makeCIdentifierNode;
+
+static const struct Angle_RNode : public cmGeneratorExpressionNode
+{
+ Angle_RNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 0; }
+
+ std::string Evaluate(const std::vector<std::string>&,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return ">";
+ }
+} angle_rNode;
+
+static const struct CommaNode : public cmGeneratorExpressionNode
+{
+ CommaNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 0; }
+
+ std::string Evaluate(const std::vector<std::string>&,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return ",";
+ }
+} commaNode;
+
+static const struct SemicolonNode : public cmGeneratorExpressionNode
+{
+ SemicolonNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 0; }
+
+ std::string Evaluate(const std::vector<std::string>&,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return ";";
+ }
+} semicolonNode;
+
+struct CompilerIdNode : public cmGeneratorExpressionNode
+{
+ CompilerIdNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return OneOrZeroParameters; }
+
+ std::string EvaluateWithLanguage(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker*,
+ const std::string& lang) const
+ {
+ const char* compilerId = context->LG->GetMakefile()->GetSafeDefinition(
+ "CMAKE_" + lang + "_COMPILER_ID");
+ if (parameters.empty()) {
+ return compilerId ? 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) {
+ return parameters.front().empty() ? "1" : "0";
+ }
+
+ if (strcmp(parameters.begin()->c_str(), compilerId) == 0) {
+ return "1";
+ }
+
+ if (cmsysString_strcasecmp(parameters.begin()->c_str(), compilerId) == 0) {
+ switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) {
+ case cmPolicies::WARN: {
+ std::ostringstream e;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0044);
+ context->LG->GetCMakeInstance()->IssueMessage(
+ cmake::AUTHOR_WARNING, e.str(), context->Backtrace);
+ }
+ case cmPolicies::OLD:
+ return "1";
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ break;
+ }
+ }
+ return "0";
+ }
+};
+
+static const struct CCompilerIdNode : public CompilerIdNode
+{
+ CCompilerIdNode() {}
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const
+ CM_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
+{
+ CXXCompilerIdNode() {}
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const
+ CM_OVERRIDE
+ {
+ 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;
+
+struct CompilerVersionNode : public cmGeneratorExpressionNode
+{
+ CompilerVersionNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return OneOrZeroParameters; }
+
+ std::string EvaluateWithLanguage(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker*,
+ const std::string& lang) const
+ {
+ const char* compilerVersion =
+ context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
+ "_COMPILER_VERSION");
+ if (parameters.empty()) {
+ return compilerVersion ? compilerVersion : "";
+ }
+
+ static cmsys::RegularExpression compilerIdValidator("^[0-9\\.]*$");
+ if (!compilerIdValidator.find(*parameters.begin())) {
+ reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return std::string();
+ }
+ if (!compilerVersion) {
+ return parameters.front().empty() ? "1" : "0";
+ }
+
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
+ parameters.begin()->c_str(),
+ compilerVersion)
+ ? "1"
+ : "0";
+ }
+};
+
+static const struct CCompilerVersionNode : public CompilerVersionNode
+{
+ CCompilerVersionNode() {}
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const
+ CM_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() {}
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const
+ CM_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;
+
+struct PlatformIdNode : public cmGeneratorExpressionNode
+{
+ PlatformIdNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return OneOrZeroParameters; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ const char* platformId =
+ context->LG->GetMakefile()->GetSafeDefinition("CMAKE_SYSTEM_NAME");
+ if (parameters.empty()) {
+ return platformId ? platformId : "";
+ }
+
+ if (!platformId) {
+ return parameters.front().empty() ? "1" : "0";
+ }
+
+ if (strcmp(parameters.begin()->c_str(), platformId) == 0) {
+ return "1";
+ }
+ return "0";
+ }
+} platformIdNode;
+
+static const struct VersionGreaterNode : public cmGeneratorExpressionNode
+{
+ VersionGreaterNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 2; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER,
+ parameters.front().c_str(),
+ parameters[1].c_str())
+ ? "1"
+ : "0";
+ }
+} versionGreaterNode;
+
+static const struct VersionLessNode : public cmGeneratorExpressionNode
+{
+ VersionLessNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 2; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
+ parameters.front().c_str(),
+ parameters[1].c_str())
+ ? "1"
+ : "0";
+ }
+} versionLessNode;
+
+static const struct VersionEqualNode : public cmGeneratorExpressionNode
+{
+ VersionEqualNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 2; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
+ parameters.front().c_str(),
+ parameters[1].c_str())
+ ? "1"
+ : "0";
+ }
+} versionEqualNode;
+
+static const struct LinkOnlyNode : public cmGeneratorExpressionNode
+{
+ LinkOnlyNode() {}
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters, cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker* dagChecker) const CM_OVERRIDE
+ {
+ if (!dagChecker->GetTransitivePropertiesOnly()) {
+ return parameters.front();
+ }
+ return "";
+ }
+} linkOnlyNode;
+
+static const struct ConfigurationNode : public cmGeneratorExpressionNode
+{
+ ConfigurationNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 0; }
+
+ std::string Evaluate(const std::vector<std::string>&,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ context->HadContextSensitiveCondition = true;
+ return context->Config;
+ }
+} configurationNode;
+
+static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
+{
+ ConfigurationTestNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return OneOrZeroParameters; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ if (parameters.empty()) {
+ return configurationNode.Evaluate(parameters, context, content,
+ CM_NULLPTR);
+ }
+ static cmsys::RegularExpression configValidator("^[A-Za-z0-9_]*$");
+ if (!configValidator.find(*parameters.begin())) {
+ reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return std::string();
+ }
+ context->HadContextSensitiveCondition = true;
+ if (context->Config.empty()) {
+ return parameters.front().empty() ? "1" : "0";
+ }
+
+ if (cmsysString_strcasecmp(parameters.begin()->c_str(),
+ context->Config.c_str()) == 0) {
+ return "1";
+ }
+
+ if (context->CurrentTarget && context->CurrentTarget->IsImported()) {
+ const char* loc = CM_NULLPTR;
+ const char* imp = CM_NULLPTR;
+ std::string suffix;
+ if (context->CurrentTarget->Target->GetMappedConfig(
+ context->Config, &loc, &imp, suffix)) {
+ // This imported target has an appropriate location
+ // for this (possibly mapped) config.
+ // Check if there is a proper config mapping for the tested config.
+ std::vector<std::string> mappedConfigs;
+ std::string mapProp = "MAP_IMPORTED_CONFIG_";
+ mapProp += cmSystemTools::UpperCase(context->Config);
+ if (const char* mapValue =
+ context->CurrentTarget->GetProperty(mapProp)) {
+ cmSystemTools::ExpandListArgument(cmSystemTools::UpperCase(mapValue),
+ mappedConfigs);
+ return std::find(mappedConfigs.begin(), mappedConfigs.end(),
+ cmSystemTools::UpperCase(parameters.front())) !=
+ mappedConfigs.end()
+ ? "1"
+ : "0";
+ }
+ }
+ }
+ return "0";
+ }
+} configurationTestNode;
+
+static const struct JoinNode : public cmGeneratorExpressionNode
+{
+ JoinNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 2; }
+
+ bool AcceptsArbitraryContentParameter() const CM_OVERRIDE { return true; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(parameters.front(), list);
+ return cmJoin(list, parameters[1]);
+ }
+} joinNode;
+
+static const struct CompileLanguageNode : public cmGeneratorExpressionNode
+{
+ CompileLanguageNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return OneOrZeroParameters; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const
+ CM_OVERRIDE
+ {
+ if (context->Language.empty()) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<COMPILE_LANGUAGE:...> may only be used to specify include "
+ "directories compile definitions, compile options and to evaluate "
+ "components of the file(GENERATE) command.");
+ return std::string();
+ }
+
+ std::vector<std::string> enabledLanguages;
+ cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
+ gg->GetEnabledLanguages(enabledLanguages);
+ if (!parameters.empty() &&
+ std::find(enabledLanguages.begin(), enabledLanguages.end(),
+ parameters.front()) == enabledLanguages.end()) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<COMPILE_LANGUAGE:...> Unknown language.");
+ return std::string();
+ }
+ std::string genName = gg->GetName();
+ if (genName.find("Visual Studio") != std::string::npos) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<COMPILE_LANGUAGE:...> may not be used with Visual Studio "
+ "generators.");
+ return std::string();
+ } else if (genName.find("Xcode") != std::string::npos) {
+ if (dagChecker && (dagChecker->EvaluatingCompileDefinitions() ||
+ dagChecker->EvaluatingIncludeDirectories())) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<COMPILE_LANGUAGE:...> may only be used with COMPILE_OPTIONS "
+ "with the Xcode generator.");
+ return std::string();
+ }
+ } else {
+ if (genName.find("Makefiles") == std::string::npos &&
+ genName.find("Ninja") == std::string::npos &&
+ genName.find("Watcom WMake") == std::string::npos) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<COMPILE_LANGUAGE:...> not supported for this generator.");
+ return std::string();
+ }
+ }
+ if (parameters.empty()) {
+ return context->Language;
+ }
+ return context->Language == parameters.front() ? "1" : "0";
+ }
+} languageNode;
+
+#define TRANSITIVE_PROPERTY_NAME(PROPERTY) , "INTERFACE_" #PROPERTY
+
+static const char* targetPropertyTransitiveWhitelist[] = {
+ CM_NULLPTR CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(TRANSITIVE_PROPERTY_NAME)
+};
+
+#undef TRANSITIVE_PROPERTY_NAME
+
+template <typename T>
+std::string getLinkedTargetsContent(
+ std::vector<T> const& libraries, cmGeneratorTarget const* target,
+ cmGeneratorTarget const* headTarget, cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ const std::string& interfacePropertyName)
+{
+ std::string linkedTargetsContent;
+ std::string sep;
+ std::string depString;
+ for (typename std::vector<T>::const_iterator it = libraries.begin();
+ it != libraries.end(); ++it) {
+ // Broken code can have a target in its own link interface.
+ // Don't follow such link interface entries so as not to create a
+ // self-referencing loop.
+ if (it->Target && it->Target != target) {
+ depString += sep + "$<TARGET_PROPERTY:" + it->Target->GetName() + "," +
+ interfacePropertyName + ">";
+ sep = ";";
+ }
+ }
+ if (!depString.empty()) {
+ linkedTargetsContent =
+ cmGeneratorExpressionNode::EvaluateDependentExpression(
+ depString, target->GetLocalGenerator(), context, headTarget, target,
+ dagChecker);
+ }
+ linkedTargetsContent =
+ cmGeneratorExpression::StripEmptyListElements(linkedTargetsContent);
+ return linkedTargetsContent;
+}
+
+static const struct TargetPropertyNode : public cmGeneratorExpressionNode
+{
+ TargetPropertyNode() {}
+
+ // This node handles errors on parameter count itself.
+ int NumExpectedParameters() const CM_OVERRIDE { return OneOrMoreParameters; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagCheckerParent) const
+ CM_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();
+ }
+
+ 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();
+ propertyName = parameters[1];
+ if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
+ if (!propertyNameValidator.find(propertyName.c_str())) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "Target name and property name not supported.");
+ return std::string();
+ }
+ ::reportError(context, content->GetOriginalExpression(),
+ "Target name not supported.");
+ return std::string();
+ }
+ if (propertyName == "ALIASED_TARGET") {
+ if (context->LG->GetMakefile()->IsAlias(targetName)) {
+ if (cmGeneratorTarget* tgt =
+ context->LG->FindGeneratorTargetToUse(targetName)) {
+ return tgt->GetName();
+ }
+ }
+ return "";
+ }
+ target = context->LG->FindGeneratorTargetToUse(targetName);
+
+ if (!target) {
+ std::ostringstream e;
+ e << "Target \"" << targetName << "\" not found.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+ context->AllTargets.insert(target);
+ }
+
+ if (target == context->HeadTarget) {
+ // 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);
+ }
+ if (propertyName == "SOURCES") {
+ context->SourceSensitiveTargets.insert(target);
+ }
+
+ if (propertyName.empty()) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<TARGET_PROPERTY:...> expression requires a non-empty property "
+ "name.");
+ return std::string();
+ }
+
+ if (!propertyNameValidator.find(propertyName)) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "Property name not supported.");
+ return std::string();
+ }
+
+ assert(target);
+
+ if (propertyName == "LINKER_LANGUAGE") {
+ if (target->LinkLanguagePropagatesToDependents() && dagCheckerParent &&
+ (dagCheckerParent->EvaluatingLinkLibraries() ||
+ dagCheckerParent->EvaluatingSources())) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "LINKER_LANGUAGE target property can not be used while evaluating "
+ "link libraries for a static library");
+ return std::string();
+ }
+ return target->GetLinkerLanguage(context->Config);
+ }
+
+ cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
+ target->GetName(), propertyName,
+ content, dagCheckerParent);
+
+ switch (dagChecker.Check()) {
+ case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
+ dagChecker.ReportError(context, content->GetOriginalExpression());
+ return std::string();
+ case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
+ // No error. We just skip cyclic references.
+ return std::string();
+ case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+ for (size_t i = 1; i < cmArraySize(targetPropertyTransitiveWhitelist);
+ ++i) {
+ if (targetPropertyTransitiveWhitelist[i] == propertyName) {
+ // No error. We're not going to find anything new here.
+ return std::string();
+ }
+ }
+ case cmGeneratorExpressionDAGChecker::DAG:
+ break;
+ }
+
+ const char* prop = target->GetProperty(propertyName);
+
+ if (dagCheckerParent) {
+ if (dagCheckerParent->EvaluatingLinkLibraries()) {
+#define TRANSITIVE_PROPERTY_COMPARE(PROPERTY) \
+ (#PROPERTY == propertyName || "INTERFACE_" #PROPERTY == propertyName) ||
+ if (CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(
+ TRANSITIVE_PROPERTY_COMPARE) false) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<TARGET_PROPERTY:...> expression in link libraries "
+ "evaluation depends on target property which is transitive "
+ "over the link libraries, creating a recursion.");
+ return std::string();
+ }
+#undef TRANSITIVE_PROPERTY_COMPARE
+
+ if (!prop) {
+ return std::string();
+ }
+ } else {
+#define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) dagCheckerParent->METHOD() ||
+
+ assert(CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
+ ASSERT_TRANSITIVE_PROPERTY_METHOD) false);
+#undef ASSERT_TRANSITIVE_PROPERTY_METHOD
+ }
+ }
+
+ std::string linkedTargetsContent;
+
+ std::string interfacePropertyName;
+ bool isInterfaceProperty = false;
+
+#define POPULATE_INTERFACE_PROPERTY_NAME(prop) \
+ if (propertyName == #prop) { \
+ interfacePropertyName = "INTERFACE_" #prop; \
+ } else if (propertyName == "INTERFACE_" #prop) { \
+ interfacePropertyName = "INTERFACE_" #prop; \
+ isInterfaceProperty = true; \
+ } else
+
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(POPULATE_INTERFACE_PROPERTY_NAME)
+ // Note that the above macro terminates with an else
+ /* else */ if (cmHasLiteralPrefix(propertyName.c_str(),
+ "COMPILE_DEFINITIONS_")) {
+ cmPolicies::PolicyStatus polSt =
+ context->LG->GetPolicyStatus(cmPolicies::CMP0043);
+ if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
+ interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS";
+ }
+ }
+#undef POPULATE_INTERFACE_PROPERTY_NAME
+ cmGeneratorTarget const* headTarget =
+ context->HeadTarget && isInterfaceProperty ? context->HeadTarget
+ : target;
+
+ if (isInterfaceProperty) {
+ if (cmLinkInterfaceLibraries const* iface =
+ target->GetLinkInterfaceLibraries(context->Config, headTarget,
+ true)) {
+ linkedTargetsContent =
+ getLinkedTargetsContent(iface->Libraries, target, headTarget,
+ context, &dagChecker, interfacePropertyName);
+ }
+ } else if (!interfacePropertyName.empty()) {
+ if (cmLinkImplementationLibraries const* impl =
+ target->GetLinkImplementationLibraries(context->Config)) {
+ linkedTargetsContent =
+ getLinkedTargetsContent(impl->Libraries, target, target, context,
+ &dagChecker, interfacePropertyName);
+ }
+ }
+
+ if (!prop) {
+ if (target->IsImported() ||
+ target->GetType() == cmState::INTERFACE_LIBRARY) {
+ return linkedTargetsContent;
+ }
+ if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
+ context->Config)) {
+ context->HadContextSensitiveCondition = true;
+ return target->GetLinkInterfaceDependentBoolProperty(propertyName,
+ context->Config)
+ ? "1"
+ : "0";
+ }
+ if (target->IsLinkInterfaceDependentStringProperty(propertyName,
+ context->Config)) {
+ context->HadContextSensitiveCondition = true;
+ const char* propContent =
+ target->GetLinkInterfaceDependentStringProperty(propertyName,
+ context->Config);
+ return propContent ? propContent : "";
+ }
+ if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName,
+ context->Config)) {
+ context->HadContextSensitiveCondition = true;
+ const char* propContent =
+ target->GetLinkInterfaceDependentNumberMinProperty(propertyName,
+ context->Config);
+ return propContent ? propContent : "";
+ }
+ if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName,
+ context->Config)) {
+ context->HadContextSensitiveCondition = true;
+ const char* propContent =
+ target->GetLinkInterfaceDependentNumberMaxProperty(propertyName,
+ context->Config);
+ return propContent ? propContent : "";
+ }
+
+ return linkedTargetsContent;
+ }
+
+ if (!target->IsImported() && dagCheckerParent &&
+ !dagCheckerParent->EvaluatingLinkLibraries()) {
+ if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName,
+ context->Config)) {
+ context->HadContextSensitiveCondition = true;
+ const char* propContent =
+ target->GetLinkInterfaceDependentNumberMinProperty(propertyName,
+ context->Config);
+ return propContent ? propContent : "";
+ }
+ if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName,
+ context->Config)) {
+ context->HadContextSensitiveCondition = true;
+ const char* propContent =
+ target->GetLinkInterfaceDependentNumberMaxProperty(propertyName,
+ context->Config);
+ return propContent ? propContent : "";
+ }
+ }
+ if (!interfacePropertyName.empty()) {
+ std::string result = this->EvaluateDependentExpression(
+ prop, context->LG, context, headTarget, target, &dagChecker);
+ if (!linkedTargetsContent.empty()) {
+ result += (result.empty() ? "" : ";") + linkedTargetsContent;
+ }
+ return result;
+ }
+ return prop;
+ }
+} targetPropertyNode;
+
+static const struct TargetNameNode : public cmGeneratorExpressionNode
+{
+ TargetNameNode() {}
+
+ bool GeneratesContent() const CM_OVERRIDE { return true; }
+
+ bool AcceptsArbitraryContentParameter() const CM_OVERRIDE { return true; }
+ bool RequiresLiteralInput() const CM_OVERRIDE { return true; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext*,
+ const GeneratorExpressionContent*,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ return parameters.front();
+ }
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 1; }
+
+} targetNameNode;
+
+static const struct TargetObjectsNode : public cmGeneratorExpressionNode
+{
+ TargetObjectsNode() {}
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ if (!context->EvaluateForBuildsystem) {
+ std::ostringstream e;
+ e << "The evaluation of the TARGET_OBJECTS generator expression "
+ "is only suitable for consumption by CMake. It is not suitable "
+ "for writing out elsewhere.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+
+ std::string tgtName = parameters.front();
+ cmGeneratorTarget* gt = context->LG->FindGeneratorTargetToUse(tgtName);
+ if (!gt) {
+ std::ostringstream e;
+ e << "Objects of target \"" << tgtName
+ << "\" referenced but no such target exists.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+ if (gt->GetType() != cmState::OBJECT_LIBRARY) {
+ std::ostringstream e;
+ e << "Objects of target \"" << tgtName
+ << "\" referenced but is not an OBJECT library.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+
+ std::vector<cmSourceFile const*> objectSources;
+ gt->GetObjectSources(objectSources, context->Config);
+ std::map<cmSourceFile const*, std::string> mapping;
+
+ for (std::vector<cmSourceFile const*>::const_iterator it =
+ objectSources.begin();
+ it != objectSources.end(); ++it) {
+ mapping[*it];
+ }
+
+ gt->LocalGenerator->ComputeObjectFilenames(mapping, gt);
+
+ std::string obj_dir = gt->ObjectDirectory;
+ std::string result;
+ const char* sep = "";
+ for (std::vector<cmSourceFile const*>::const_iterator it =
+ objectSources.begin();
+ it != objectSources.end(); ++it) {
+ // 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());
+ result += sep;
+ std::string objFile = obj_dir + map_it->second;
+ cmSourceFile* sf =
+ context->LG->GetMakefile()->GetOrCreateSource(objFile, true);
+ sf->SetObjectLibrary(tgtName);
+ sf->SetProperty("EXTERNAL_OBJECT", "1");
+ result += objFile;
+ sep = ";";
+ }
+ return result;
+ }
+} targetObjectsNode;
+
+static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
+{
+ CompileFeaturesNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return OneOrMoreParameters; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const
+ CM_OVERRIDE
+ {
+ cmGeneratorTarget const* target = context->HeadTarget;
+ if (!target) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<COMPILE_FEATURE> may only be used with binary targets. It may "
+ "not be used with add_custom_command or add_custom_target.");
+ return std::string();
+ }
+ context->HadHeadSensitiveCondition = true;
+
+ typedef std::map<std::string, std::vector<std::string> > LangMap;
+ static LangMap availableFeatures;
+
+ LangMap testedFeatures;
+
+ for (std::vector<std::string>::const_iterator it = parameters.begin();
+ it != parameters.end(); ++it) {
+ std::string error;
+ std::string lang;
+ if (!context->LG->GetMakefile()->CompileFeatureKnown(
+ context->HeadTarget->Target, *it, lang, &error)) {
+ reportError(context, content->GetOriginalExpression(), error);
+ return std::string();
+ }
+ testedFeatures[lang].push_back(*it);
+
+ if (availableFeatures.find(lang) == availableFeatures.end()) {
+ const char* featuresKnown =
+ context->LG->GetMakefile()->CompileFeaturesAvailable(lang, &error);
+ if (!featuresKnown) {
+ reportError(context, content->GetOriginalExpression(), error);
+ return std::string();
+ }
+ cmSystemTools::ExpandListArgument(featuresKnown,
+ availableFeatures[lang]);
+ }
+ }
+
+ bool evalLL = dagChecker && dagChecker->EvaluatingLinkLibraries();
+
+ for (LangMap::const_iterator lit = testedFeatures.begin();
+ lit != testedFeatures.end(); ++lit) {
+ std::vector<std::string> const& langAvailable =
+ availableFeatures[lit->first];
+ const char* standardDefault = context->LG->GetMakefile()->GetDefinition(
+ "CMAKE_" + lit->first + "_STANDARD_DEFAULT");
+ for (std::vector<std::string>::const_iterator it = lit->second.begin();
+ it != lit->second.end(); ++it) {
+ if (std::find(langAvailable.begin(), langAvailable.end(), *it) ==
+ langAvailable.end()) {
+ return "0";
+ }
+ if (standardDefault && !*standardDefault) {
+ // This compiler has no notion of language standard levels.
+ // All features known for the language are always available.
+ continue;
+ }
+ if (!context->LG->GetMakefile()->HaveStandardAvailable(
+ target->Target, lit->first, *it)) {
+ if (evalLL) {
+ const char* l = target->GetProperty(lit->first + "_STANDARD");
+ if (!l) {
+ l = standardDefault;
+ }
+ assert(l);
+ context->MaxLanguageStandard[target][lit->first] = l;
+ } else {
+ return "0";
+ }
+ }
+ }
+ }
+ return "1";
+ }
+} compileFeaturesNode;
+
+static const char* targetPolicyWhitelist[] = {
+ CM_NULLPTR
+#define TARGET_POLICY_STRING(POLICY) , #POLICY
+
+ CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_STRING)
+
+#undef TARGET_POLICY_STRING
+};
+
+cmPolicies::PolicyStatus statusForTarget(cmGeneratorTarget const* tgt,
+ const char* policy)
+{
+#define RETURN_POLICY(POLICY) \
+ if (strcmp(policy, #POLICY) == 0) { \
+ return tgt->GetPolicyStatus##POLICY(); \
+ }
+
+ CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY)
+
+#undef RETURN_POLICY
+
+ assert(0 && "Unreachable code. Not a valid policy");
+ return cmPolicies::WARN;
+}
+
+cmPolicies::PolicyID policyForString(const char* policy_id)
+{
+#define RETURN_POLICY_ID(POLICY_ID) \
+ if (strcmp(policy_id, #POLICY_ID) == 0) { \
+ return cmPolicies::POLICY_ID; \
+ }
+
+ CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY_ID)
+
+#undef RETURN_POLICY_ID
+
+ assert(0 && "Unreachable code. Not a valid policy");
+ return cmPolicies::CMP0002;
+}
+
+static const struct TargetPolicyNode : public cmGeneratorExpressionNode
+{
+ TargetPolicyNode() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 1; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ if (!context->HeadTarget) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<TARGET_POLICY:prop> may only be used with binary targets. It "
+ "may not be used with add_custom_command or add_custom_target.");
+ return std::string();
+ }
+
+ context->HadContextSensitiveCondition = true;
+ context->HadHeadSensitiveCondition = true;
+
+ for (size_t i = 1; i < cmArraySize(targetPolicyWhitelist); ++i) {
+ const char* policy = targetPolicyWhitelist[i];
+ if (parameters.front() == policy) {
+ cmLocalGenerator* lg = context->HeadTarget->GetLocalGenerator();
+ switch (statusForTarget(context->HeadTarget, policy)) {
+ case cmPolicies::WARN:
+ lg->IssueMessage(
+ cmake::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(policyForString(policy)));
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::OLD:
+ return "0";
+ case cmPolicies::NEW:
+ return "1";
+ }
+ }
+ }
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<TARGET_POLICY:prop> may only be used with a limited number of "
+ "policies. Currently it may be used with the following policies:\n"
+
+#define STRINGIFY_HELPER(X) #X
+#define STRINGIFY(X) STRINGIFY_HELPER(X)
+
+#define TARGET_POLICY_LIST_ITEM(POLICY) " * " STRINGIFY(POLICY) "\n"
+
+ CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_LIST_ITEM)
+
+#undef TARGET_POLICY_LIST_ITEM
+ );
+ return std::string();
+ }
+
+} targetPolicyNode;
+
+static const struct InstallPrefixNode : public cmGeneratorExpressionNode
+{
+ InstallPrefixNode() {}
+
+ bool GeneratesContent() const CM_OVERRIDE { return true; }
+ int NumExpectedParameters() const CM_OVERRIDE { return 0; }
+
+ std::string Evaluate(const std::vector<std::string>&,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ reportError(context, content->GetOriginalExpression(),
+ "INSTALL_PREFIX is a marker for install(EXPORT) only. It "
+ "should never be evaluated.");
+ return std::string();
+ }
+
+} installPrefixNode;
+
+class ArtifactNameTag;
+class ArtifactLinkerTag;
+class ArtifactSonameTag;
+class ArtifactPdbTag;
+
+class ArtifactPathTag;
+class ArtifactDirTag;
+
+template <typename ArtifactT>
+struct TargetFilesystemArtifactResultCreator
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content);
+};
+
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag>
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ // The target soname file (.so.1).
+ if (target->IsDLLPlatform()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_SONAME_FILE is not allowed "
+ "for DLL target platforms.");
+ return std::string();
+ }
+ if (target->GetType() != cmState::SHARED_LIBRARY) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_SONAME_FILE is allowed only for "
+ "SHARED libraries.");
+ return std::string();
+ }
+ std::string result = target->GetDirectory(context->Config);
+ result += "/";
+ result += target->GetSOName(context->Config);
+ return result;
+ }
+};
+
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag>
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (target->IsImported()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE 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 is not supported by the target linker.");
+ return std::string();
+ }
+
+ cmState::TargetType targetType = target->GetType();
+
+ if (targetType != cmState::SHARED_LIBRARY &&
+ targetType != cmState::MODULE_LIBRARY &&
+ targetType != cmState::EXECUTABLE) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE is allowed only for "
+ "targets with linker created artifacts.");
+ return std::string();
+ }
+
+ std::string result = target->GetPDBDirectory(context->Config);
+ result += "/";
+ result += target->GetPDBName(context->Config);
+ return result;
+ }
+};
+
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag>
+{
+ static std::string Create(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 is allowed only for libraries and "
+ "executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+ return target->GetFullPath(context->Config, target->HasImportLibrary());
+ }
+};
+
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactNameTag>
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent*)
+ {
+ return target->GetFullPath(context->Config, false, true);
+ }
+};
+
+template <typename ArtifactT>
+struct TargetFilesystemArtifactResultGetter
+{
+ static std::string Get(const std::string& result);
+};
+
+template <>
+struct TargetFilesystemArtifactResultGetter<ArtifactNameTag>
+{
+ static std::string Get(const std::string& result)
+ {
+ return cmSystemTools::GetFilenameName(result);
+ }
+};
+
+template <>
+struct TargetFilesystemArtifactResultGetter<ArtifactDirTag>
+{
+ static std::string Get(const std::string& result)
+ {
+ return cmSystemTools::GetFilenamePath(result);
+ }
+};
+
+template <>
+struct TargetFilesystemArtifactResultGetter<ArtifactPathTag>
+{
+ static std::string Get(const std::string& result) { return result; }
+};
+
+template <typename ArtifactT, typename ComponentT>
+struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
+{
+ TargetFilesystemArtifact() {}
+
+ int NumExpectedParameters() const CM_OVERRIDE { return 1; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const
+ CM_OVERRIDE
+ {
+ // Lookup the referenced target.
+ std::string name = *parameters.begin();
+
+ if (!cmGeneratorExpression::IsValidTargetName(name)) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return std::string();
+ }
+ cmGeneratorTarget* target = context->LG->FindGeneratorTargetToUse(name);
+ if (!target) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "No target \"" + name + "\"");
+ return std::string();
+ }
+ if (target->GetType() >= cmState::OBJECT_LIBRARY &&
+ target->GetType() != cmState::UNKNOWN_LIBRARY) {
+ ::reportError(context, content->GetOriginalExpression(), "Target \"" +
+ name + "\" is not an executable or library.");
+ return std::string();
+ }
+ if (dagChecker && (dagChecker->EvaluatingLinkLibraries(name.c_str()) ||
+ (dagChecker->EvaluatingSources() &&
+ name == dagChecker->TopTarget()))) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "Expressions which require the linker language may not "
+ "be used while evaluating link libraries");
+ return std::string();
+ }
+ context->DependTargets.insert(target);
+ context->AllTargets.insert(target);
+
+ std::string result =
+ TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, context,
+ content);
+ if (context->HadError) {
+ return std::string();
+ }
+ return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
+ }
+};
+
+template <typename ArtifactT>
+struct TargetFilesystemArtifactNodeGroup
+{
+ TargetFilesystemArtifactNodeGroup() {}
+
+ TargetFilesystemArtifact<ArtifactT, ArtifactPathTag> File;
+ TargetFilesystemArtifact<ArtifactT, ArtifactNameTag> FileName;
+ TargetFilesystemArtifact<ArtifactT, ArtifactDirTag> FileDir;
+};
+
+static const TargetFilesystemArtifactNodeGroup<ArtifactNameTag>
+ targetNodeGroup;
+
+static const TargetFilesystemArtifactNodeGroup<ArtifactLinkerTag>
+ targetLinkerNodeGroup;
+
+static const TargetFilesystemArtifactNodeGroup<ArtifactSonameTag>
+ targetSoNameNodeGroup;
+
+static const TargetFilesystemArtifactNodeGroup<ArtifactPdbTag>
+ targetPdbNodeGroup;
+
+static const struct ShellPathNode : public cmGeneratorExpressionNode
+{
+ ShellPathNode() {}
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+ {
+ if (!cmSystemTools::FileIsFullPath(parameters.front())) {
+ reportError(context, content->GetOriginalExpression(),
+ "\"" + parameters.front() + "\" is not an absolute path.");
+ return std::string();
+ }
+ cmOutputConverter converter(context->LG->GetStateSnapshot());
+ return converter.ConvertDirectorySeparatorsForShell(parameters.front());
+ }
+} 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["VERSION_GREATER"] = &versionGreaterNode;
+ nodeMap["VERSION_LESS"] = &versionLessNode;
+ nodeMap["VERSION_EQUAL"] = &versionEqualNode;
+ nodeMap["C_COMPILER_VERSION"] = &cCompilerVersionNode;
+ nodeMap["CXX_COMPILER_VERSION"] = &cxxCompilerVersionNode;
+ 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["STREQUAL"] = &strEqualNode;
+ nodeMap["EQUAL"] = &equalNode;
+ nodeMap["LOWER_CASE"] = &lowerCaseNode;
+ nodeMap["UPPER_CASE"] = &upperCaseNode;
+ nodeMap["MAKE_C_IDENTIFIER"] = &makeCIdentifierNode;
+ nodeMap["BOOL"] = &boolNode;
+ 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["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 CM_NULLPTR;
+ }
+ return i->second;
+}
+
+void reportError(cmGeneratorExpressionContext* context,
+ const std::string& expr, const std::string& result)
+{
+ context->HadError = true;
+ if (context->Quiet) {
+ return;
+ }
+
+ std::ostringstream e;
+ /* clang-format off */
+ e << "Error evaluating generator expression:\n"
+ << " " << expr << "\n"
+ << result;
+ /* clang-format on */
+ context->LG->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
+ context->Backtrace);
+}
diff --git a/Source/cmGeneratorExpressionNode.h b/Source/cmGeneratorExpressionNode.h
new file mode 100644
index 0000000..3ee57eb
--- /dev/null
+++ b/Source/cmGeneratorExpressionNode.h
@@ -0,0 +1,67 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGeneratorExpressionNode_h
+#define cmGeneratorExpressionNode_h
+
+#include "cmGeneratorExpression.h"
+
+#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGeneratorExpressionEvaluator.h"
+#include "cmGeneratorExpressionParser.h"
+#include "cmLocalGenerator.h"
+#include "cmSourceFile.h"
+
+#include <cmsys/String.h>
+
+#include <assert.h>
+#include <errno.h>
+
+#include "cmListFileCache.h"
+
+struct cmGeneratorExpressionNode
+{
+ enum
+ {
+ DynamicParameters = 0,
+ OneOrMoreParameters = -1,
+ OneOrZeroParameters = -2
+ };
+ virtual ~cmGeneratorExpressionNode() {}
+
+ virtual bool GeneratesContent() const { return true; }
+
+ virtual bool RequiresLiteralInput() const { return false; }
+
+ virtual bool AcceptsArbitraryContentParameter() const { return false; }
+
+ virtual int NumExpectedParameters() const { return 1; }
+
+ virtual std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const = 0;
+
+ static std::string EvaluateDependentExpression(
+ std::string const& prop, cmLocalGenerator* lg,
+ cmGeneratorExpressionContext* context, const cmGeneratorTarget* headTarget,
+ const cmGeneratorTarget* currentTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker);
+
+ static const cmGeneratorExpressionNode* GetNode(
+ const std::string& identifier);
+};
+
+void reportError(cmGeneratorExpressionContext* context,
+ const std::string& expr, const std::string& result);
+
+#endif
diff --git a/Source/cmGeneratorExpressionParser.cxx b/Source/cmGeneratorExpressionParser.cxx
new file mode 100644
index 0000000..f853f8d
--- /dev/null
+++ b/Source/cmGeneratorExpressionParser.cxx
@@ -0,0 +1,261 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmGeneratorExpressionParser.h"
+
+#include "cmGeneratorExpressionEvaluator.h"
+
+#include "assert.h"
+
+cmGeneratorExpressionParser::cmGeneratorExpressionParser(
+ const std::vector<cmGeneratorExpressionToken>& tokens)
+ : Tokens(tokens)
+ , NestingLevel(0)
+{
+}
+
+void cmGeneratorExpressionParser::Parse(
+ std::vector<cmGeneratorExpressionEvaluator*>& result)
+{
+ it = this->Tokens.begin();
+
+ while (this->it != this->Tokens.end()) {
+ this->ParseContent(result);
+ }
+}
+
+static void extendText(
+ std::vector<cmGeneratorExpressionEvaluator*>& result,
+ std::vector<cmGeneratorExpressionToken>::const_iterator it)
+{
+ if (!result.empty() &&
+ (*(result.end() - 1))->GetType() ==
+ cmGeneratorExpressionEvaluator::Text) {
+ TextContent* textContent = static_cast<TextContent*>(*(result.end() - 1));
+ textContent->Extend(it->Length);
+ } else {
+ TextContent* textContent = new TextContent(it->Content, it->Length);
+ result.push_back(textContent);
+ }
+}
+
+static void extendResult(
+ std::vector<cmGeneratorExpressionEvaluator*>& result,
+ const std::vector<cmGeneratorExpressionEvaluator*>& contents)
+{
+ if (!result.empty() &&
+ (*(result.end() - 1))->GetType() ==
+ cmGeneratorExpressionEvaluator::Text &&
+ (*contents.begin())->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());
+ } else {
+ result.insert(result.end(), contents.begin(), contents.end());
+ }
+}
+
+void cmGeneratorExpressionParser::ParseGeneratorExpression(
+ std::vector<cmGeneratorExpressionEvaluator*>& result)
+{
+ assert(this->it != this->Tokens.end());
+ unsigned int nestedLevel = this->NestingLevel;
+ ++this->NestingLevel;
+
+ std::vector<cmGeneratorExpressionToken>::const_iterator startToken =
+ this->it - 1;
+
+ std::vector<cmGeneratorExpressionEvaluator*> identifier;
+ while (this->it->TokenType != cmGeneratorExpressionToken::EndExpression &&
+ this->it->TokenType != cmGeneratorExpressionToken::ColonSeparator) {
+ if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
+ extendText(identifier, this->it);
+ ++this->it;
+ } else {
+ this->ParseContent(identifier);
+ }
+ if (this->it == this->Tokens.end()) {
+ break;
+ }
+ }
+ if (identifier.empty()) {
+ // ERROR
+ }
+
+ if (this->it != this->Tokens.end() &&
+ this->it->TokenType == cmGeneratorExpressionToken::EndExpression) {
+ GeneratorExpressionContent* content =
+ new GeneratorExpressionContent(startToken->Content, this->it->Content -
+ startToken->Content + this->it->Length);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ --this->NestingLevel;
+ content->SetIdentifier(identifier);
+ result.push_back(content);
+ return;
+ }
+
+ std::vector<std::vector<cmGeneratorExpressionEvaluator*> > parameters;
+ std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator>
+ commaTokens;
+ std::vector<cmGeneratorExpressionToken>::const_iterator colonToken;
+
+ bool emptyParamTermination = false;
+
+ if (this->it != this->Tokens.end() &&
+ this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) {
+ colonToken = this->it;
+ parameters.resize(parameters.size() + 1);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ if (this->it == this->Tokens.end()) {
+ emptyParamTermination = true;
+ }
+
+ while (this->it != this->Tokens.end() &&
+ this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
+ commaTokens.push_back(this->it);
+ parameters.resize(parameters.size() + 1);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ if (this->it == this->Tokens.end()) {
+ emptyParamTermination = true;
+ }
+ }
+ while (this->it != this->Tokens.end() &&
+ this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) {
+ extendText(*(parameters.end() - 1), this->it);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ }
+ while (this->it != this->Tokens.end() &&
+ this->it->TokenType != cmGeneratorExpressionToken::EndExpression) {
+ this->ParseContent(*(parameters.end() - 1));
+ if (this->it == this->Tokens.end()) {
+ break;
+ }
+ while (this->it != this->Tokens.end() &&
+ this->it->TokenType ==
+ cmGeneratorExpressionToken::CommaSeparator) {
+ commaTokens.push_back(this->it);
+ parameters.resize(parameters.size() + 1);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ if (this->it == this->Tokens.end()) {
+ emptyParamTermination = true;
+ }
+ }
+ while (this->it != this->Tokens.end() &&
+ this->it->TokenType ==
+ cmGeneratorExpressionToken::ColonSeparator) {
+ extendText(*(parameters.end() - 1), this->it);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ }
+ }
+ if (this->it != this->Tokens.end() &&
+ this->it->TokenType == cmGeneratorExpressionToken::EndExpression) {
+ --this->NestingLevel;
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ }
+ }
+
+ if (nestedLevel != this->NestingLevel) {
+ // There was a '$<' in the text, but no corresponding '>'. Rebuild to
+ // treat the '$<' as having been plain text, along with the
+ // corresponding : and , tokens that might have been found.
+ extendText(result, startToken);
+ extendResult(result, identifier);
+ if (!parameters.empty()) {
+ extendText(result, colonToken);
+
+ typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector;
+ typedef std::vector<cmGeneratorExpressionToken> TokenVector;
+ std::vector<EvaluatorVector>::const_iterator pit = parameters.begin();
+ const std::vector<EvaluatorVector>::const_iterator pend =
+ parameters.end();
+ std::vector<TokenVector::const_iterator>::const_iterator commaIt =
+ commaTokens.begin();
+ assert(parameters.size() > commaTokens.size());
+ for (; pit != pend; ++pit, ++commaIt) {
+ if (!pit->empty() && !emptyParamTermination) {
+ extendResult(result, *pit);
+ }
+ if (commaIt != commaTokens.end()) {
+ extendText(result, *commaIt);
+ } else {
+ break;
+ }
+ }
+ }
+ return;
+ }
+
+ size_t contentLength =
+ ((this->it - 1)->Content - startToken->Content) + (this->it - 1)->Length;
+ GeneratorExpressionContent* content =
+ new GeneratorExpressionContent(startToken->Content, contentLength);
+ content->SetIdentifier(identifier);
+ content->SetParameters(parameters);
+ result.push_back(content);
+}
+
+void cmGeneratorExpressionParser::ParseContent(
+ std::vector<cmGeneratorExpressionEvaluator*>& result)
+{
+ assert(this->it != this->Tokens.end());
+ switch (this->it->TokenType) {
+ case cmGeneratorExpressionToken::Text: {
+ if (this->NestingLevel == 0) {
+ if (!result.empty() &&
+ (*(result.end() - 1))->GetType() ==
+ cmGeneratorExpressionEvaluator::Text) {
+ // A comma in 'plain text' could have split text that should
+ // otherwise be continuous. Extend the last text content instead of
+ // creating a new one.
+ TextContent* textContent =
+ static_cast<TextContent*>(*(result.end() - 1));
+ textContent->Extend(this->it->Length);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ return;
+ }
+ }
+ cmGeneratorExpressionEvaluator* n =
+ new TextContent(this->it->Content, this->it->Length);
+ result.push_back(n);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ return;
+ }
+ case cmGeneratorExpressionToken::BeginExpression:
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ this->ParseGeneratorExpression(result);
+ return;
+ case cmGeneratorExpressionToken::EndExpression:
+ case cmGeneratorExpressionToken::ColonSeparator:
+ case cmGeneratorExpressionToken::CommaSeparator:
+ if (this->NestingLevel == 0) {
+ extendText(result, this->it);
+ } else {
+ assert(0 && "Got unexpected syntax token.");
+ }
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ return;
+ }
+ assert(0 && "Unhandled token in generator expression.");
+}
diff --git a/Source/cmGeneratorExpressionParser.h b/Source/cmGeneratorExpressionParser.h
new file mode 100644
index 0000000..b0e9ea4
--- /dev/null
+++ b/Source/cmGeneratorExpressionParser.h
@@ -0,0 +1,41 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGeneratorExpressionParser_h
+#define cmGeneratorExpressionParser_h
+
+#include "cmGeneratorExpressionLexer.h"
+
+#include <set>
+#include <vector>
+
+#include "cmListFileCache.h"
+
+struct cmGeneratorExpressionEvaluator;
+
+struct cmGeneratorExpressionParser
+{
+ cmGeneratorExpressionParser(
+ const std::vector<cmGeneratorExpressionToken>& tokens);
+
+ void Parse(std::vector<cmGeneratorExpressionEvaluator*>& result);
+
+private:
+ void ParseContent(std::vector<cmGeneratorExpressionEvaluator*>&);
+ void ParseGeneratorExpression(std::vector<cmGeneratorExpressionEvaluator*>&);
+
+private:
+ std::vector<cmGeneratorExpressionToken>::const_iterator it;
+ const std::vector<cmGeneratorExpressionToken> Tokens;
+ unsigned int NestingLevel;
+};
+
+#endif
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
new file mode 100644
index 0000000..c9cbd00
--- /dev/null
+++ b/Source/cmGeneratorTarget.cxx
@@ -0,0 +1,5189 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGeneratorTarget.h"
+
+#include "cmAlgorithms.h"
+#include "cmComputeLinkInformation.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmTarget.h"
+
+#include <queue>
+
+#include "assert.h"
+#include <errno.h>
+
+#if defined(CMake_HAVE_CXX_UNORDERED_SET)
+#include <unordered_set>
+#define UNORDERED_SET std::unordered_set
+#elif defined(CMAKE_BUILD_WITH_CMAKE)
+#include <cmsys/hash_set.hxx>
+#define UNORDERED_SET cmsys::hash_set
+#else
+#define UNORDERED_SET std::set
+#endif
+
+class cmGeneratorTarget::TargetPropertyEntry
+{
+ static cmLinkImplItem NoLinkImplItem;
+
+public:
+ TargetPropertyEntry(CM_AUTO_PTR<cmCompiledGeneratorExpression> cge,
+ cmLinkImplItem const& item = NoLinkImplItem)
+ : ge(cge)
+ , LinkImplItem(item)
+ {
+ }
+ const CM_AUTO_PTR<cmCompiledGeneratorExpression> ge;
+ cmLinkImplItem const& LinkImplItem;
+};
+cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem;
+
+void reportBadObjLib(std::vector<cmSourceFile*> const& badObjLib,
+ cmGeneratorTarget const* target, cmake* cm)
+{
+ if (!badObjLib.empty()) {
+ std::ostringstream e;
+ e << "OBJECT library \"" << target->GetName() << "\" contains:\n";
+ for (std::vector<cmSourceFile*>::const_iterator i = badObjLib.begin();
+ i != badObjLib.end(); ++i) {
+ e << " " << (*i)->GetLocation().GetName() << "\n";
+ }
+ e << "but may contain only sources that compile, header files, and "
+ "other files that would not affect linking of a normal library.";
+ cm->IssueMessage(cmake::FATAL_ERROR, e.str(), target->GetBacktrace());
+ }
+}
+
+struct ObjectSourcesTag
+{
+};
+struct CustomCommandsTag
+{
+};
+struct ExtraSourcesTag
+{
+};
+struct HeaderSourcesTag
+{
+};
+struct ExternalObjectsTag
+{
+};
+struct IDLSourcesTag
+{
+};
+struct ResxTag
+{
+};
+struct ModuleDefinitionFileTag
+{
+};
+struct AppManifestTag
+{
+};
+struct ManifestsTag
+{
+};
+struct CertificatesTag
+{
+};
+struct XamlTag
+{
+};
+
+template <typename Tag, typename OtherTag>
+struct IsSameTag
+{
+ enum
+ {
+ Result = false
+ };
+};
+
+template <typename Tag>
+struct IsSameTag<Tag, Tag>
+{
+ enum
+ {
+ Result = true
+ };
+};
+
+template <bool>
+struct DoAccept
+{
+ template <typename T>
+ static void Do(T&, cmSourceFile*)
+ {
+ }
+};
+
+template <>
+struct DoAccept<true>
+{
+ static void Do(std::vector<cmSourceFile const*>& files, cmSourceFile* f)
+ {
+ files.push_back(f);
+ }
+ static void Do(cmGeneratorTarget::ResxData& data, cmSourceFile* f)
+ {
+ // Build and save the name of the corresponding .h file
+ // This relationship will be used later when building the project files.
+ // Both names would have been auto generated from Visual Studio
+ // where the user supplied the file name and Visual Studio
+ // appended the suffix.
+ std::string resx = f->GetFullPath();
+ std::string hFileName = resx.substr(0, resx.find_last_of('.')) + ".h";
+ data.ExpectedResxHeaders.insert(hFileName);
+ data.ResxSources.push_back(f);
+ }
+ static void Do(cmGeneratorTarget::XamlData& data, cmSourceFile* f)
+ {
+ // Build and save the name of the corresponding .h and .cpp file
+ // This relationship will be used later when building the project files.
+ // Both names would have been auto generated from Visual Studio
+ // where the user supplied the file name and Visual Studio
+ // appended the suffix.
+ std::string xaml = f->GetFullPath();
+ std::string hFileName = xaml + ".h";
+ std::string cppFileName = xaml + ".cpp";
+ data.ExpectedXamlHeaders.insert(hFileName);
+ data.ExpectedXamlSources.insert(cppFileName);
+ data.XamlSources.push_back(f);
+ }
+ static void Do(std::string& data, cmSourceFile* f)
+ {
+ data = f->GetFullPath();
+ }
+};
+
+template <typename Tag, typename DataType = std::vector<cmSourceFile const*> >
+struct TagVisitor
+{
+ DataType& Data;
+ std::vector<cmSourceFile*> BadObjLibFiles;
+ cmGeneratorTarget const* Target;
+ cmGlobalGenerator* GlobalGenerator;
+ cmsys::RegularExpression Header;
+ bool IsObjLib;
+
+ TagVisitor(cmGeneratorTarget const* target, DataType& data)
+ : Data(data)
+ , Target(target)
+ , GlobalGenerator(target->GetLocalGenerator()->GetGlobalGenerator())
+ , Header(CM_HEADER_REGEX)
+ , IsObjLib(target->GetType() == cmState::OBJECT_LIBRARY)
+ {
+ }
+
+ ~TagVisitor()
+ {
+ reportBadObjLib(this->BadObjLibFiles, this->Target,
+ this->GlobalGenerator->GetCMakeInstance());
+ }
+
+ void Accept(cmSourceFile* sf)
+ {
+ std::string ext = cmSystemTools::LowerCase(sf->GetExtension());
+ if (sf->GetCustomCommand()) {
+ DoAccept<IsSameTag<Tag, CustomCommandsTag>::Result>::Do(this->Data, sf);
+ } else if (this->Target->GetType() == cmState::UTILITY) {
+ DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf);
+ } else if (sf->GetPropertyAsBool("HEADER_FILE_ONLY")) {
+ DoAccept<IsSameTag<Tag, HeaderSourcesTag>::Result>::Do(this->Data, sf);
+ } else if (sf->GetPropertyAsBool("EXTERNAL_OBJECT")) {
+ DoAccept<IsSameTag<Tag, ExternalObjectsTag>::Result>::Do(this->Data, sf);
+ if (this->IsObjLib) {
+ this->BadObjLibFiles.push_back(sf);
+ }
+ } else if (!sf->GetLanguage().empty()) {
+ DoAccept<IsSameTag<Tag, ObjectSourcesTag>::Result>::Do(this->Data, sf);
+ } else if (ext == "def") {
+ DoAccept<IsSameTag<Tag, ModuleDefinitionFileTag>::Result>::Do(this->Data,
+ sf);
+ if (this->IsObjLib) {
+ this->BadObjLibFiles.push_back(sf);
+ }
+ } else if (ext == "idl") {
+ DoAccept<IsSameTag<Tag, IDLSourcesTag>::Result>::Do(this->Data, sf);
+ if (this->IsObjLib) {
+ this->BadObjLibFiles.push_back(sf);
+ }
+ } else if (ext == "resx") {
+ DoAccept<IsSameTag<Tag, ResxTag>::Result>::Do(this->Data, sf);
+ } else if (ext == "appxmanifest") {
+ DoAccept<IsSameTag<Tag, AppManifestTag>::Result>::Do(this->Data, sf);
+ } else if (ext == "manifest") {
+ DoAccept<IsSameTag<Tag, ManifestsTag>::Result>::Do(this->Data, sf);
+ } else if (ext == "pfx") {
+ DoAccept<IsSameTag<Tag, CertificatesTag>::Result>::Do(this->Data, sf);
+ } else if (ext == "xaml") {
+ DoAccept<IsSameTag<Tag, XamlTag>::Result>::Do(this->Data, sf);
+ } else if (this->Header.find(sf->GetFullPath().c_str())) {
+ DoAccept<IsSameTag<Tag, HeaderSourcesTag>::Result>::Do(this->Data, sf);
+ } else if (this->GlobalGenerator->IgnoreFile(sf->GetExtension().c_str())) {
+ DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf);
+ } else {
+ DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf);
+ }
+ }
+};
+
+void CreatePropertyGeneratorExpressions(
+ cmStringRange const& entries, cmBacktraceRange const& backtraces,
+ std::vector<cmGeneratorTarget::TargetPropertyEntry*>& items,
+ bool evaluateForBuildsystem = false)
+{
+ 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);
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(*it);
+ cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
+ items.push_back(new cmGeneratorTarget::TargetPropertyEntry(cge));
+ }
+}
+
+cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
+ : Target(t)
+ , FortranModuleDirectoryCreated(false)
+ , SourceFileFlagsConstructed(false)
+ , PolicyWarnedCMP0022(false)
+ , DebugIncludesDone(false)
+ , DebugCompileOptionsDone(false)
+ , DebugCompileFeaturesDone(false)
+ , DebugCompileDefinitionsDone(false)
+ , DebugSourcesDone(false)
+ , LinkImplementationLanguageIsContextDependent(true)
+ , UtilityItemsDone(false)
+{
+ this->Makefile = this->Target->GetMakefile();
+ this->LocalGenerator = lg;
+ this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
+
+ this->GlobalGenerator->ComputeTargetObjectDirectory(this);
+
+ CreatePropertyGeneratorExpressions(t->GetIncludeDirectoriesEntries(),
+ t->GetIncludeDirectoriesBacktraces(),
+ this->IncludeDirectoriesEntries);
+
+ CreatePropertyGeneratorExpressions(t->GetCompileOptionsEntries(),
+ t->GetCompileOptionsBacktraces(),
+ this->CompileOptionsEntries);
+
+ CreatePropertyGeneratorExpressions(t->GetCompileFeaturesEntries(),
+ t->GetCompileFeaturesBacktraces(),
+ this->CompileFeaturesEntries);
+
+ CreatePropertyGeneratorExpressions(t->GetCompileDefinitionsEntries(),
+ t->GetCompileDefinitionsBacktraces(),
+ this->CompileDefinitionsEntries);
+
+ CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
+ t->GetSourceBacktraces(),
+ this->SourceEntries, true);
+
+ this->DLLPlatform =
+ (this->Makefile->IsOn("WIN32") || this->Makefile->IsOn("CYGWIN") ||
+ this->Makefile->IsOn("MINGW"));
+
+ this->PolicyMap = t->PolicyMap;
+}
+
+cmGeneratorTarget::~cmGeneratorTarget()
+{
+ cmDeleteAll(this->IncludeDirectoriesEntries);
+ cmDeleteAll(this->CompileOptionsEntries);
+ cmDeleteAll(this->CompileFeaturesEntries);
+ cmDeleteAll(this->CompileDefinitionsEntries);
+ cmDeleteAll(this->SourceEntries);
+ cmDeleteAll(this->LinkInformation);
+ this->LinkInformation.clear();
+}
+
+cmLocalGenerator* cmGeneratorTarget::GetLocalGenerator() const
+{
+ return this->LocalGenerator;
+}
+
+cmState::TargetType cmGeneratorTarget::GetType() const
+{
+ return this->Target->GetType();
+}
+
+const std::string& cmGeneratorTarget::GetName() const
+{
+ return this->Target->GetName();
+}
+
+std::string cmGeneratorTarget::GetExportName() const
+{
+ const char* exportName = this->GetProperty("EXPORT_NAME");
+
+ if (exportName && *exportName) {
+ if (!cmGeneratorExpression::IsValidTargetName(exportName)) {
+ std::ostringstream e;
+ e << "EXPORT_NAME property \"" << exportName << "\" for \""
+ << this->GetName() << "\": is not valid.";
+ cmSystemTools::Error(e.str().c_str());
+ return "";
+ }
+ return exportName;
+ }
+ return this->GetName();
+}
+
+const char* cmGeneratorTarget::GetProperty(const std::string& prop) const
+{
+ return this->Target->GetProperty(prop);
+}
+
+const char* cmGeneratorTarget::GetOutputTargetType(bool implib) const
+{
+ switch (this->GetType()) {
+ case cmState::SHARED_LIBRARY:
+ if (this->IsDLLPlatform()) {
+ if (implib) {
+ // A DLL import library is treated as an archive target.
+ return "ARCHIVE";
+ } else {
+ // A DLL shared library is treated as a runtime target.
+ return "RUNTIME";
+ }
+ } else {
+ // For non-DLL platforms shared libraries are treated as
+ // library targets.
+ return "LIBRARY";
+ }
+ case cmState::STATIC_LIBRARY:
+ // Static libraries are always treated as archive targets.
+ return "ARCHIVE";
+ case cmState::MODULE_LIBRARY:
+ if (implib) {
+ // Module libraries are always treated as library targets.
+ return "ARCHIVE";
+ } else {
+ // Module import libraries are treated as archive targets.
+ return "LIBRARY";
+ }
+ case cmState::EXECUTABLE:
+ if (implib) {
+ // Executable import libraries are treated as archive targets.
+ return "ARCHIVE";
+ } else {
+ // Executables are always treated as runtime targets.
+ return "RUNTIME";
+ }
+ default:
+ break;
+ }
+ return "";
+}
+
+std::string cmGeneratorTarget::GetOutputName(const std::string& config,
+ bool implib) const
+{
+ // Lookup/compute/cache the output name for this configuration.
+ OutputNameKey key(config, implib);
+ cmGeneratorTarget::OutputNameMapType::iterator i =
+ this->OutputNameMap.find(key);
+ if (i == this->OutputNameMap.end()) {
+ // Add empty name in map to detect potential recursion.
+ OutputNameMapType::value_type entry(key, "");
+ i = this->OutputNameMap.insert(entry).first;
+
+ // Compute output name.
+ std::vector<std::string> props;
+ std::string type = this->GetOutputTargetType(implib);
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ if (!type.empty() && !configUpper.empty()) {
+ // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
+ props.push_back(type + "_OUTPUT_NAME_" + configUpper);
+ }
+ if (!type.empty()) {
+ // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
+ props.push_back(type + "_OUTPUT_NAME");
+ }
+ if (!configUpper.empty()) {
+ // OUTPUT_NAME_<CONFIG>
+ props.push_back("OUTPUT_NAME_" + configUpper);
+ // <CONFIG>_OUTPUT_NAME
+ props.push_back(configUpper + "_OUTPUT_NAME");
+ }
+ // OUTPUT_NAME
+ props.push_back("OUTPUT_NAME");
+
+ std::string outName;
+ for (std::vector<std::string>::const_iterator it = props.begin();
+ it != props.end(); ++it) {
+ if (const char* outNameProp = this->GetProperty(*it)) {
+ outName = outNameProp;
+ break;
+ }
+ }
+
+ if (outName.empty()) {
+ outName = this->GetName();
+ }
+
+ // Now evaluate genex and update the previously-prepared map entry.
+ cmGeneratorExpression ge;
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(outName);
+ i->second = cge->Evaluate(this->LocalGenerator, config);
+ } else if (i->second.empty()) {
+ // An empty map entry indicates we have been called recursively
+ // from the above block.
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(
+ cmake::FATAL_ERROR,
+ "Target '" + this->GetName() + "' OUTPUT_NAME depends on itself.",
+ this->GetBacktrace());
+ }
+ return i->second;
+}
+
+void cmGeneratorTarget::AddSource(const std::string& src)
+{
+ this->Target->AddSource(src);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ cmGeneratorExpression ge(lfbt);
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(src);
+ cge->SetEvaluateForBuildsystem(true);
+ this->SourceEntries.push_back(new TargetPropertyEntry(cge));
+ this->SourceFilesMap.clear();
+ this->LinkImplementationLanguageIsContextDependent = true;
+}
+
+void cmGeneratorTarget::AddTracedSources(std::vector<std::string> const& srcs)
+{
+ this->Target->AddTracedSources(srcs);
+ if (!srcs.empty()) {
+ std::string srcFiles = cmJoin(srcs, ";");
+ this->SourceFilesMap.clear();
+ this->LinkImplementationLanguageIsContextDependent = true;
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ cmGeneratorExpression ge(lfbt);
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(srcFiles);
+ cge->SetEvaluateForBuildsystem(true);
+ this->SourceEntries.push_back(
+ new cmGeneratorTarget::TargetPropertyEntry(cge));
+ }
+}
+
+std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
+ cmSourceFile const* sf) const
+{
+ SourceEntriesType::const_iterator i = this->SourceDepends.find(sf);
+ if (i != this->SourceDepends.end()) {
+ return &i->second.Depends;
+ }
+ return CM_NULLPTR;
+}
+
+static void handleSystemIncludesDep(
+ cmLocalGenerator* lg, cmGeneratorTarget const* depTgt,
+ const std::string& config, cmGeneratorTarget const* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::vector<std::string>& result, bool excludeImported)
+{
+ if (const char* dirs =
+ depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) {
+ cmGeneratorExpression ge;
+ cmSystemTools::ExpandListArgument(
+ ge.Parse(dirs)->Evaluate(lg, config, false, headTarget, depTgt,
+ dagChecker),
+ result);
+ }
+ if (!depTgt->IsImported() || excludeImported) {
+ return;
+ }
+
+ if (const char* dirs =
+ depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
+ cmGeneratorExpression ge;
+ cmSystemTools::ExpandListArgument(
+ ge.Parse(dirs)->Evaluate(lg, config, false, headTarget, depTgt,
+ dagChecker),
+ result);
+ }
+}
+
+/* clang-format off */
+#define IMPLEMENT_VISIT_IMPL(DATA, DATATYPE) \
+ { \
+ std::vector<cmSourceFile*> sourceFiles; \
+ this->GetSourceFiles(sourceFiles, config); \
+ TagVisitor< DATA##Tag DATATYPE > visitor(this, data); \
+ for (std::vector<cmSourceFile*>::const_iterator si = sourceFiles.begin(); \
+ si != sourceFiles.end(); ++si) { \
+ visitor.Accept(*si); \
+ } \
+ }
+/* clang-format on */
+
+#define IMPLEMENT_VISIT(DATA) IMPLEMENT_VISIT_IMPL(DATA, EMPTY)
+
+#define EMPTY
+#define COMMA ,
+
+void cmGeneratorTarget::GetObjectSources(
+ std::vector<cmSourceFile const*>& data, const std::string& config) const
+{
+ IMPLEMENT_VISIT(ObjectSources);
+
+ if (!this->Objects.empty()) {
+ return;
+ }
+
+ for (std::vector<cmSourceFile const*>::const_iterator it = data.begin();
+ it != data.end(); ++it) {
+ this->Objects[*it];
+ }
+
+ this->LocalGenerator->ComputeObjectFilenames(this->Objects, this);
+}
+
+void cmGeneratorTarget::ComputeObjectMapping()
+{
+ if (!this->Objects.empty()) {
+ return;
+ }
+
+ std::vector<std::string> configs;
+ this->Makefile->GetConfigurations(configs);
+ if (configs.empty()) {
+ configs.push_back("");
+ }
+ for (std::vector<std::string>::const_iterator ci = configs.begin();
+ ci != configs.end(); ++ci) {
+ std::vector<cmSourceFile const*> sourceFiles;
+ this->GetObjectSources(sourceFiles, *ci);
+ }
+}
+
+const char* cmGeneratorTarget::GetFeature(const std::string& feature,
+ const std::string& config) const
+{
+ if (!config.empty()) {
+ std::string featureConfig = feature;
+ featureConfig += "_";
+ featureConfig += cmSystemTools::UpperCase(config);
+ if (const char* value = this->GetProperty(featureConfig)) {
+ return value;
+ }
+ }
+ if (const char* value = this->GetProperty(feature)) {
+ return value;
+ }
+ return this->LocalGenerator->GetFeature(feature, config);
+}
+
+bool cmGeneratorTarget::GetFeatureAsBool(const std::string& feature,
+ const std::string& config) const
+{
+ return cmSystemTools::IsOn(this->GetFeature(feature, config));
+}
+
+const std::string& cmGeneratorTarget::GetObjectName(cmSourceFile const* file)
+{
+ this->ComputeObjectMapping();
+ return this->Objects[file];
+}
+
+void cmGeneratorTarget::AddExplicitObjectName(cmSourceFile const* sf)
+{
+ this->ExplicitObjectName.insert(sf);
+}
+
+bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const
+{
+ const_cast<cmGeneratorTarget*>(this)->ComputeObjectMapping();
+ std::set<cmSourceFile const*>::const_iterator it =
+ this->ExplicitObjectName.find(file);
+ return it != this->ExplicitObjectName.end();
+}
+
+void cmGeneratorTarget::GetIDLSources(std::vector<cmSourceFile const*>& data,
+ const std::string& config) const
+{
+ IMPLEMENT_VISIT(IDLSources);
+}
+
+void cmGeneratorTarget::GetHeaderSources(
+ std::vector<cmSourceFile const*>& data, const std::string& config) const
+{
+ IMPLEMENT_VISIT(HeaderSources);
+}
+
+void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile const*>& data,
+ const std::string& config) const
+{
+ IMPLEMENT_VISIT(ExtraSources);
+}
+
+void cmGeneratorTarget::GetCustomCommands(
+ std::vector<cmSourceFile const*>& data, const std::string& config) const
+{
+ IMPLEMENT_VISIT(CustomCommands);
+}
+
+void cmGeneratorTarget::GetExternalObjects(
+ std::vector<cmSourceFile const*>& data, const std::string& config) const
+{
+ IMPLEMENT_VISIT(ExternalObjects);
+}
+
+void cmGeneratorTarget::GetExpectedResxHeaders(std::set<std::string>& srcs,
+ const std::string& config) const
+{
+ ResxData data;
+ IMPLEMENT_VISIT_IMPL(Resx, COMMA cmGeneratorTarget::ResxData)
+ srcs = data.ExpectedResxHeaders;
+}
+
+void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile const*>& srcs,
+ const std::string& config) const
+{
+ ResxData data;
+ IMPLEMENT_VISIT_IMPL(Resx, COMMA cmGeneratorTarget::ResxData)
+ srcs = data.ResxSources;
+}
+
+void cmGeneratorTarget::GetAppManifest(std::vector<cmSourceFile const*>& data,
+ const std::string& config) const
+{
+ IMPLEMENT_VISIT(AppManifest);
+}
+
+void cmGeneratorTarget::GetManifests(std::vector<cmSourceFile const*>& data,
+ const std::string& config) const
+{
+ IMPLEMENT_VISIT(Manifests);
+}
+
+void cmGeneratorTarget::GetCertificates(std::vector<cmSourceFile const*>& data,
+ const std::string& config) const
+{
+ IMPLEMENT_VISIT(Certificates);
+}
+
+void cmGeneratorTarget::GetExpectedXamlHeaders(std::set<std::string>& headers,
+ const std::string& config) const
+{
+ XamlData data;
+ IMPLEMENT_VISIT_IMPL(Xaml, COMMA cmGeneratorTarget::XamlData)
+ headers = data.ExpectedXamlHeaders;
+}
+
+void cmGeneratorTarget::GetExpectedXamlSources(std::set<std::string>& srcs,
+ const std::string& config) const
+{
+ XamlData data;
+ IMPLEMENT_VISIT_IMPL(Xaml, COMMA cmGeneratorTarget::XamlData)
+ srcs = data.ExpectedXamlSources;
+}
+
+std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const
+{
+ if (!this->UtilityItemsDone) {
+ this->UtilityItemsDone = true;
+ std::set<std::string> const& utilities = this->GetUtilities();
+ for (std::set<std::string>::const_iterator i = utilities.begin();
+ i != utilities.end(); ++i) {
+ cmGeneratorTarget* gt =
+ this->LocalGenerator->FindGeneratorTargetToUse(*i);
+ this->UtilityItems.insert(cmLinkItem(*i, gt));
+ }
+ }
+ return this->UtilityItems;
+}
+
+void cmGeneratorTarget::GetXamlSources(std::vector<cmSourceFile const*>& srcs,
+ const std::string& config) const
+{
+ XamlData data;
+ IMPLEMENT_VISIT_IMPL(Xaml, COMMA cmGeneratorTarget::XamlData)
+ srcs = data.XamlSources;
+}
+
+const char* cmGeneratorTarget::GetLocation(const std::string& config) const
+{
+ static std::string location;
+ if (this->IsImported()) {
+ location = this->Target->ImportedGetFullPath(config, false);
+ } else {
+ location = this->GetFullPath(config, false);
+ }
+ return location.c_str();
+}
+
+std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreBuildCommands()
+ const
+{
+ return this->Target->GetPreBuildCommands();
+}
+
+std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreLinkCommands()
+ const
+{
+ return this->Target->GetPreLinkCommands();
+}
+
+std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPostBuildCommands()
+ const
+{
+ return this->Target->GetPostBuildCommands();
+}
+
+bool cmGeneratorTarget::IsImported() const
+{
+ return this->Target->IsImported();
+}
+
+bool cmGeneratorTarget::IsImportedGloballyVisible() const
+{
+ return this->Target->IsImportedGloballyVisible();
+}
+
+const char* cmGeneratorTarget::GetLocationForBuild() const
+{
+ static std::string location;
+ if (this->IsImported()) {
+ location = this->Target->ImportedGetFullPath("", false);
+ return location.c_str();
+ }
+
+ // Now handle the deprecated build-time configuration location.
+ location = this->GetDirectory();
+ const char* cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR");
+ if (cfgid && strcmp(cfgid, ".") != 0) {
+ location += "/";
+ location += cfgid;
+ }
+
+ if (this->IsAppBundleOnApple()) {
+ std::string macdir = this->BuildMacContentDirectory("", "", false);
+ if (!macdir.empty()) {
+ location += "/";
+ location += macdir;
+ }
+ }
+ location += "/";
+ location += this->GetFullName("", false);
+ return location.c_str();
+}
+
+bool cmGeneratorTarget::IsSystemIncludeDirectory(
+ const std::string& dir, const std::string& config) const
+{
+ assert(this->GetType() != cmState::INTERFACE_LIBRARY);
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+
+ typedef std::map<std::string, std::vector<std::string> > IncludeCacheType;
+ IncludeCacheType::const_iterator iter =
+ this->SystemIncludesCache.find(config_upper);
+
+ if (iter == this->SystemIncludesCache.end()) {
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this->GetName(), "SYSTEM_INCLUDE_DIRECTORIES", CM_NULLPTR, CM_NULLPTR);
+
+ bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
+
+ std::vector<std::string> result;
+ for (std::set<std::string>::const_iterator it =
+ this->Target->GetSystemIncludeDirectories().begin();
+ it != this->Target->GetSystemIncludeDirectories().end(); ++it) {
+ cmGeneratorExpression ge;
+ cmSystemTools::ExpandListArgument(
+ ge.Parse(*it)->Evaluate(this->LocalGenerator, config, false, this,
+ &dagChecker),
+ result);
+ }
+
+ std::vector<cmGeneratorTarget const*> const& deps =
+ this->GetLinkImplementationClosure(config);
+ for (std::vector<cmGeneratorTarget const *>::const_iterator
+ li = deps.begin(),
+ le = deps.end();
+ li != le; ++li) {
+ handleSystemIncludesDep(this->LocalGenerator, *li, config, this,
+ &dagChecker, result, excludeImported);
+ }
+
+ std::set<std::string> unique;
+ for (std::vector<std::string>::iterator li = result.begin();
+ li != result.end(); ++li) {
+ cmSystemTools::ConvertToUnixSlashes(*li);
+ unique.insert(*li);
+ }
+ result.clear();
+ result.insert(result.end(), unique.begin(), unique.end());
+
+ IncludeCacheType::value_type entry(config_upper, result);
+ iter = this->SystemIncludesCache.insert(entry).first;
+ }
+
+ return std::binary_search(iter->second.begin(), iter->second.end(), dir);
+}
+
+bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const
+{
+ return this->Target->GetPropertyAsBool(prop);
+}
+
+static void AddInterfaceEntries(
+ cmGeneratorTarget const* thisTarget, std::string const& config,
+ std::string const& prop,
+ std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries)
+{
+ if (cmLinkImplementationLibraries const* impl =
+ thisTarget->GetLinkImplementationLibraries(config)) {
+ for (std::vector<cmLinkImplItem>::const_iterator
+ it = impl->Libraries.begin(),
+ end = impl->Libraries.end();
+ it != end; ++it) {
+ if (it->Target) {
+ std::string genex = "$<TARGET_PROPERTY:" + *it + "," + prop + ">";
+ cmGeneratorExpression ge(it->Backtrace);
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
+ cge->SetEvaluateForBuildsystem(true);
+ entries.push_back(
+ new cmGeneratorTarget::TargetPropertyEntry(cge, *it));
+ }
+ }
+ }
+}
+
+static bool processSources(
+ cmGeneratorTarget const* tgt,
+ const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
+ std::vector<std::string>& srcs, UNORDERED_SET<std::string>& uniqueSrcs,
+ cmGeneratorExpressionDAGChecker* dagChecker, std::string const& config,
+ bool debugSources)
+{
+ cmMakefile* mf = tgt->Target->GetMakefile();
+
+ bool contextDependent = false;
+
+ for (std::vector<cmGeneratorTarget::TargetPropertyEntry *>::const_iterator
+ it = entries.begin(),
+ end = entries.end();
+ it != end; ++it) {
+ cmLinkImplItem const& item = (*it)->LinkImplItem;
+ std::string const& targetName = item;
+ std::vector<std::string> entrySources;
+ cmSystemTools::ExpandListArgument(
+ (*it)->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt, tgt,
+ dagChecker),
+ entrySources);
+
+ if ((*it)->ge->GetHadContextSensitiveCondition()) {
+ contextDependent = true;
+ }
+
+ for (std::vector<std::string>::iterator i = entrySources.begin();
+ i != entrySources.end(); ++i) {
+ std::string& src = *i;
+ cmSourceFile* sf = mf->GetOrCreateSource(src);
+ std::string e;
+ std::string fullPath = sf->GetFullPath(&e);
+ if (fullPath.empty()) {
+ if (!e.empty()) {
+ cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
+ cm->IssueMessage(cmake::FATAL_ERROR, e, tgt->GetBacktrace());
+ }
+ return contextDependent;
+ }
+
+ if (!targetName.empty() && !cmSystemTools::FileIsFullPath(src.c_str())) {
+ std::ostringstream err;
+ if (!targetName.empty()) {
+ err << "Target \"" << targetName
+ << "\" contains relative "
+ "path in its INTERFACE_SOURCES:\n"
+ " \""
+ << src << "\"";
+ } else {
+ err << "Found relative path while evaluating sources of "
+ "\""
+ << tgt->GetName() << "\":\n \"" << src << "\"\n";
+ }
+ tgt->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, err.str());
+ return contextDependent;
+ }
+ src = fullPath;
+ }
+ std::string usedSources;
+ for (std::vector<std::string>::iterator li = entrySources.begin();
+ li != entrySources.end(); ++li) {
+ std::string src = *li;
+
+ if (uniqueSrcs.insert(src).second) {
+ srcs.push_back(src);
+ if (debugSources) {
+ usedSources += " * " + src + "\n";
+ }
+ }
+ }
+ if (!usedSources.empty()) {
+ tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+ cmake::LOG, std::string("Used sources for target ") + tgt->GetName() +
+ ":\n" + usedSources,
+ (*it)->ge->GetBacktrace());
+ }
+ }
+ return contextDependent;
+}
+
+void cmGeneratorTarget::GetSourceFiles(std::vector<std::string>& files,
+ const std::string& config) const
+{
+ assert(this->GetType() != cmState::INTERFACE_LIBRARY);
+
+ if (!this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
+ // At configure-time, this method can be called as part of getting the
+ // LOCATION property or to export() a file to be include()d. However
+ // there is no cmGeneratorTarget at configure-time, so search the SOURCES
+ // for TARGET_OBJECTS instead for backwards compatibility with OLD
+ // behavior of CMP0024 and CMP0026 only.
+
+ cmStringRange sourceEntries = this->Target->GetSourceEntries();
+ for (cmStringRange::const_iterator i = sourceEntries.begin();
+ i != sourceEntries.end(); ++i) {
+ std::string const& entry = *i;
+
+ std::vector<std::string> items;
+ cmSystemTools::ExpandListArgument(entry, items);
+ for (std::vector<std::string>::const_iterator li = items.begin();
+ li != items.end(); ++li) {
+ if (cmHasLiteralPrefix(*li, "$<TARGET_OBJECTS:") &&
+ (*li)[li->size() - 1] == '>') {
+ continue;
+ }
+ files.push_back(*li);
+ }
+ }
+ return;
+ }
+
+ std::vector<std::string> debugProperties;
+ const char* debugProp =
+ this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
+ if (debugProp) {
+ cmSystemTools::ExpandListArgument(debugProp, debugProperties);
+ }
+
+ bool debugSources = !this->DebugSourcesDone &&
+ std::find(debugProperties.begin(), debugProperties.end(), "SOURCES") !=
+ debugProperties.end();
+
+ if (this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
+ this->DebugSourcesDone = true;
+ }
+
+ cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), "SOURCES",
+ CM_NULLPTR, CM_NULLPTR);
+
+ UNORDERED_SET<std::string> uniqueSrcs;
+ bool contextDependentDirectSources =
+ processSources(this, this->SourceEntries, files, uniqueSrcs, &dagChecker,
+ config, debugSources);
+
+ std::vector<cmGeneratorTarget::TargetPropertyEntry*>
+ linkInterfaceSourcesEntries;
+
+ AddInterfaceEntries(this, config, "INTERFACE_SOURCES",
+ linkInterfaceSourcesEntries);
+
+ std::vector<std::string>::size_type numFilesBefore = files.size();
+ bool contextDependentInterfaceSources =
+ processSources(this, linkInterfaceSourcesEntries, files, uniqueSrcs,
+ &dagChecker, config, debugSources);
+
+ if (!contextDependentDirectSources &&
+ !(contextDependentInterfaceSources && numFilesBefore < files.size())) {
+ this->LinkImplementationLanguageIsContextDependent = false;
+ }
+
+ cmDeleteAll(linkInterfaceSourcesEntries);
+}
+
+void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files,
+ const std::string& config) const
+{
+
+ // Lookup any existing link implementation for this configuration.
+ std::string key = cmSystemTools::UpperCase(config);
+
+ if (!this->LinkImplementationLanguageIsContextDependent) {
+ files = this->SourceFilesMap.begin()->second;
+ return;
+ }
+
+ SourceFilesMapType::iterator it = this->SourceFilesMap.find(key);
+ if (it != this->SourceFilesMap.end()) {
+ files = it->second;
+ } else {
+ std::vector<std::string> srcs;
+ this->GetSourceFiles(srcs, config);
+
+ std::set<cmSourceFile*> emitted;
+
+ for (std::vector<std::string>::const_iterator i = srcs.begin();
+ i != srcs.end(); ++i) {
+ cmSourceFile* sf = this->Makefile->GetOrCreateSource(*i);
+ if (emitted.insert(sf).second) {
+ files.push_back(sf);
+ }
+ }
+ this->SourceFilesMap[key] = files;
+ }
+}
+
+std::string cmGeneratorTarget::GetCompilePDBName(
+ const std::string& config) const
+{
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(config, false, prefix, base, suffix);
+
+ // Check for a per-configuration output directory target property.
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ std::string configProp = "COMPILE_PDB_NAME_";
+ configProp += configUpper;
+ const char* config_name = this->GetProperty(configProp);
+ if (config_name && *config_name) {
+ return prefix + config_name + ".pdb";
+ }
+
+ const char* name = this->GetProperty("COMPILE_PDB_NAME");
+ if (name && *name) {
+ return prefix + name + ".pdb";
+ }
+
+ return "";
+}
+
+std::string cmGeneratorTarget::GetCompilePDBPath(
+ const std::string& config) const
+{
+ std::string dir = this->GetCompilePDBDirectory(config);
+ std::string name = this->GetCompilePDBName(config);
+ if (dir.empty() && !name.empty()) {
+ dir = this->GetPDBDirectory(config);
+ }
+ if (!dir.empty()) {
+ dir += "/";
+ }
+ return dir + name;
+}
+
+bool cmGeneratorTarget::HasSOName(const std::string& config) const
+{
+ // soname is supported only for shared libraries and modules,
+ // and then only when the platform supports an soname flag.
+ return ((this->GetType() == cmState::SHARED_LIBRARY) &&
+ !this->GetPropertyAsBool("NO_SONAME") &&
+ this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config)));
+}
+
+bool cmGeneratorTarget::NeedRelinkBeforeInstall(
+ const std::string& config) const
+{
+ // Only executables and shared libraries can have an rpath and may
+ // need relinking.
+ if (this->GetType() != cmState::EXECUTABLE &&
+ this->GetType() != cmState::SHARED_LIBRARY &&
+ this->GetType() != cmState::MODULE_LIBRARY) {
+ return false;
+ }
+
+ // If there is no install location this target will not be installed
+ // and therefore does not need relinking.
+ if (!this->Target->GetHaveInstallRule()) {
+ return false;
+ }
+
+ // If skipping all rpaths completely then no relinking is needed.
+ if (this->Makefile->IsOn("CMAKE_SKIP_RPATH")) {
+ return false;
+ }
+
+ // If building with the install-tree rpath no relinking is needed.
+ if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
+ return false;
+ }
+
+ // If chrpath is going to be used no relinking is needed.
+ if (this->IsChrpathUsed(config)) {
+ return false;
+ }
+
+ // Check for rpath support on this platform.
+ std::string ll = this->GetLinkerLanguage(config);
+ if (!ll.empty()) {
+ std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
+ flagVar += ll;
+ flagVar += "_FLAG";
+ if (!this->Makefile->IsSet(flagVar)) {
+ // There is no rpath support on this platform so nothing needs
+ // relinking.
+ return false;
+ }
+ } else {
+ // No linker language is known. This error will be reported by
+ // other code.
+ return false;
+ }
+
+ // If either a build or install tree rpath is set then the rpath
+ // will likely change between the build tree and install tree and
+ // this target must be relinked.
+ return this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH();
+}
+
+bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const
+{
+ // Only certain target types have an rpath.
+ if (!(this->GetType() == cmState::SHARED_LIBRARY ||
+ this->GetType() == cmState::MODULE_LIBRARY ||
+ this->GetType() == cmState::EXECUTABLE)) {
+ return false;
+ }
+
+ // If the target will not be installed we do not need to change its
+ // rpath.
+ if (!this->Target->GetHaveInstallRule()) {
+ return false;
+ }
+
+ // Skip chrpath if skipping rpath altogether.
+ if (this->Makefile->IsOn("CMAKE_SKIP_RPATH")) {
+ return false;
+ }
+
+ // Skip chrpath if it does not need to be changed at install time.
+ if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
+ return false;
+ }
+
+ // Allow the user to disable builtin chrpath explicitly.
+ if (this->Makefile->IsOn("CMAKE_NO_BUILTIN_CHRPATH")) {
+ return false;
+ }
+
+ if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ return true;
+ }
+
+#if defined(CMAKE_USE_ELF_PARSER)
+ // Enable if the rpath flag uses a separator and the target uses ELF
+ // binaries.
+ std::string ll = this->GetLinkerLanguage(config);
+ if (!ll.empty()) {
+ std::string sepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
+ sepVar += ll;
+ sepVar += "_FLAG_SEP";
+ const char* sep = this->Makefile->GetDefinition(sepVar);
+ if (sep && *sep) {
+ // TODO: Add ELF check to ABI detection and get rid of
+ // CMAKE_EXECUTABLE_FORMAT.
+ if (const char* fmt =
+ this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) {
+ return strcmp(fmt, "ELF") == 0;
+ }
+ }
+ }
+#endif
+ static_cast<void>(config);
+ return false;
+}
+
+bool cmGeneratorTarget::IsImportedSharedLibWithoutSOName(
+ const std::string& config) const
+{
+ if (this->IsImported() && this->GetType() == cmState::SHARED_LIBRARY) {
+ if (cmGeneratorTarget::ImportInfo const* info =
+ this->GetImportInfo(config)) {
+ return info->NoSOName;
+ }
+ }
+ return false;
+}
+
+bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir(
+ const std::string& config) const
+{
+ bool install_name_is_rpath = false;
+ bool macosx_rpath = false;
+
+ if (!this->IsImported()) {
+ if (this->GetType() != cmState::SHARED_LIBRARY) {
+ return false;
+ }
+ const char* install_name = this->GetProperty("INSTALL_NAME_DIR");
+ bool use_install_name =
+ this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH");
+ if (install_name && use_install_name &&
+ std::string(install_name) == "@rpath") {
+ install_name_is_rpath = true;
+ } else if (install_name && use_install_name) {
+ return false;
+ }
+ if (!install_name_is_rpath) {
+ macosx_rpath = this->MacOSXRpathInstallNameDirDefault();
+ }
+ } else {
+ // Lookup the imported soname.
+ if (cmGeneratorTarget::ImportInfo const* info =
+ this->GetImportInfo(config)) {
+ if (!info->NoSOName && !info->SOName.empty()) {
+ if (info->SOName.find("@rpath/") == 0) {
+ install_name_is_rpath = true;
+ }
+ } else {
+ std::string install_name;
+ cmSystemTools::GuessLibraryInstallName(info->Location, install_name);
+ if (install_name.find("@rpath") != std::string::npos) {
+ install_name_is_rpath = true;
+ }
+ }
+ }
+ }
+
+ if (!install_name_is_rpath && !macosx_rpath) {
+ return false;
+ }
+
+ if (!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
+ std::ostringstream w;
+ w << "Attempting to use";
+ if (macosx_rpath) {
+ w << " MACOSX_RPATH";
+ } else {
+ w << " @rpath";
+ }
+ w << " without CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG being set.";
+ w << " This could be because you are using a Mac OS X version";
+ w << " less than 10.5 or because CMake's platform configuration is";
+ w << " corrupt.";
+ cmake* cm = this->LocalGenerator->GetCMakeInstance();
+ cm->IssueMessage(cmake::FATAL_ERROR, w.str(), this->GetBacktrace());
+ }
+
+ return true;
+}
+
+bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const
+{
+ // we can't do rpaths when unsupported
+ if (!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
+ return false;
+ }
+
+ const char* macosx_rpath_str = this->GetProperty("MACOSX_RPATH");
+ if (macosx_rpath_str) {
+ return this->GetPropertyAsBool("MACOSX_RPATH");
+ }
+
+ cmPolicies::PolicyStatus cmp0042 = this->GetPolicyStatusCMP0042();
+
+ if (cmp0042 == cmPolicies::WARN) {
+ this->LocalGenerator->GetGlobalGenerator()->AddCMP0042WarnTarget(
+ this->GetName());
+ }
+
+ return cmp0042 == cmPolicies::NEW;
+}
+
+std::string cmGeneratorTarget::GetSOName(const std::string& config) const
+{
+ if (this->IsImported()) {
+ // Lookup the imported soname.
+ if (cmGeneratorTarget::ImportInfo const* info =
+ this->GetImportInfo(config)) {
+ if (info->NoSOName) {
+ // The imported library has no builtin soname so the name
+ // searched at runtime will be just the filename.
+ return cmSystemTools::GetFilenameName(info->Location);
+ } else {
+ // Use the soname given if any.
+ if (info->SOName.find("@rpath/") == 0) {
+ return info->SOName.substr(6);
+ }
+ return info->SOName;
+ }
+ } else {
+ return "";
+ }
+ } else {
+ // 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;
+ }
+}
+
+std::string cmGeneratorTarget::GetAppBundleDirectory(const std::string& config,
+ bool contentOnly) const
+{
+ std::string fpath = this->GetFullName(config, false);
+ fpath += ".app";
+ if (!this->Makefile->PlatformIsAppleIos()) {
+ fpath += "/Contents";
+ if (!contentOnly) {
+ fpath += "/MacOS";
+ }
+ }
+ return fpath;
+}
+
+bool cmGeneratorTarget::IsBundleOnApple() const
+{
+ return this->IsFrameworkOnApple() || this->IsAppBundleOnApple() ||
+ this->IsCFBundleOnApple();
+}
+
+std::string cmGeneratorTarget::GetCFBundleDirectory(const std::string& config,
+ bool contentOnly) const
+{
+ std::string fpath;
+ fpath += this->GetOutputName(config, false);
+ fpath += ".";
+ const char* ext = this->GetProperty("BUNDLE_EXTENSION");
+ if (!ext) {
+ if (this->IsXCTestOnApple()) {
+ ext = "xctest";
+ } else {
+ ext = "bundle";
+ }
+ }
+ fpath += ext;
+ if (!this->Makefile->PlatformIsAppleIos()) {
+ fpath += "/Contents";
+ if (!contentOnly) {
+ fpath += "/MacOS";
+ }
+ }
+ return fpath;
+}
+
+std::string cmGeneratorTarget::GetFrameworkDirectory(const std::string& config,
+ bool rootDir) const
+{
+ std::string fpath;
+ fpath += this->GetOutputName(config, false);
+ fpath += ".framework";
+ if (!rootDir && !this->Makefile->PlatformIsAppleIos()) {
+ fpath += "/Versions/";
+ fpath += this->GetFrameworkVersion();
+ }
+ return fpath;
+}
+
+std::string cmGeneratorTarget::GetFullName(const std::string& config,
+ bool implib) const
+{
+ if (this->IsImported()) {
+ return this->GetFullNameImported(config, implib);
+ } else {
+ return this->GetFullNameInternal(config, implib);
+ }
+}
+
+std::string cmGeneratorTarget::GetInstallNameDirForBuildTree(
+ const std::string& config) const
+{
+ // If building directly for installation then the build tree install_name
+ // is the same as the install tree.
+ if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
+ return this->GetInstallNameDirForInstallTree();
+ }
+
+ // Use the build tree directory for the target.
+ if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME") &&
+ !this->Makefile->IsOn("CMAKE_SKIP_RPATH") &&
+ !this->GetPropertyAsBool("SKIP_BUILD_RPATH")) {
+ std::string dir;
+ if (this->MacOSXRpathInstallNameDirDefault()) {
+ dir = "@rpath";
+ } else {
+ dir = this->GetDirectory(config);
+ }
+ dir += "/";
+ return dir;
+ } else {
+ return "";
+ }
+}
+
+std::string cmGeneratorTarget::GetInstallNameDirForInstallTree() const
+{
+ if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ std::string dir;
+ const char* install_name_dir = this->GetProperty("INSTALL_NAME_DIR");
+
+ if (!this->Makefile->IsOn("CMAKE_SKIP_RPATH") &&
+ !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH")) {
+ if (install_name_dir && *install_name_dir) {
+ dir = install_name_dir;
+ dir += "/";
+ }
+ }
+ if (!install_name_dir) {
+ if (this->MacOSXRpathInstallNameDirDefault()) {
+ dir = "@rpath/";
+ }
+ }
+ return dir;
+ } else {
+ return "";
+ }
+}
+
+cmListFileBacktrace cmGeneratorTarget::GetBacktrace() const
+{
+ return this->Target->GetBacktrace();
+}
+
+const std::vector<std::string>& cmGeneratorTarget::GetLinkDirectories() const
+{
+ return this->Target->GetLinkDirectories();
+}
+
+const std::set<std::string>& cmGeneratorTarget::GetUtilities() const
+{
+ return this->Target->GetUtilities();
+}
+
+const cmListFileBacktrace* cmGeneratorTarget::GetUtilityBacktrace(
+ const std::string& u) const
+{
+ return this->Target->GetUtilityBacktrace(u);
+}
+
+bool cmGeneratorTarget::HaveWellDefinedOutputFiles() const
+{
+ return this->GetType() == cmState::STATIC_LIBRARY ||
+ this->GetType() == cmState::SHARED_LIBRARY ||
+ this->GetType() == cmState::MODULE_LIBRARY ||
+ this->GetType() == cmState::EXECUTABLE;
+}
+
+const char* cmGeneratorTarget::GetExportMacro() const
+{
+ // Define the symbol for targets that export symbols.
+ if (this->GetType() == cmState::SHARED_LIBRARY ||
+ this->GetType() == cmState::MODULE_LIBRARY ||
+ this->IsExecutableWithExports()) {
+ if (const char* custom_export_name = this->GetProperty("DEFINE_SYMBOL")) {
+ this->ExportMacro = custom_export_name;
+ } else {
+ std::string in = this->GetName();
+ in += "_EXPORTS";
+ this->ExportMacro = cmSystemTools::MakeCidentifier(in);
+ }
+ return this->ExportMacro.c_str();
+ } else {
+ return CM_NULLPTR;
+ }
+}
+
+class cmTargetCollectLinkLanguages
+{
+public:
+ cmTargetCollectLinkLanguages(cmGeneratorTarget const* target,
+ const std::string& config,
+ UNORDERED_SET<std::string>& languages,
+ cmGeneratorTarget const* head)
+ : Config(config)
+ , Languages(languages)
+ , HeadTarget(head)
+ , Target(target)
+ {
+ this->Visited.insert(target);
+ }
+
+ void Visit(cmLinkItem const& item)
+ {
+ if (!item.Target) {
+ if (item.find("::") != std::string::npos) {
+ bool noMessage = false;
+ cmake::MessageType messageType = cmake::FATAL_ERROR;
+ std::ostringstream e;
+ switch (this->Target->GetLocalGenerator()->GetPolicyStatus(
+ cmPolicies::CMP0028)) {
+ case cmPolicies::WARN: {
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0028) << "\n";
+ messageType = cmake::AUTHOR_WARNING;
+ } break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Issue the fatal message.
+ break;
+ }
+
+ if (!noMessage) {
+ e << "Target \"" << this->Target->GetName()
+ << "\" links to target \"" << item
+ << "\" but the target was not found. Perhaps a find_package() "
+ "call is missing for an IMPORTED target, or an ALIAS target is "
+ "missing?";
+ this->Target->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+ messageType, e.str(), this->Target->GetBacktrace());
+ }
+ }
+ return;
+ }
+ if (!this->Visited.insert(item.Target).second) {
+ return;
+ }
+ cmLinkInterface const* iface =
+ item.Target->GetLinkInterface(this->Config, this->HeadTarget);
+ if (!iface) {
+ return;
+ }
+
+ for (std::vector<std::string>::const_iterator li =
+ iface->Languages.begin();
+ li != iface->Languages.end(); ++li) {
+ this->Languages.insert(*li);
+ }
+
+ for (std::vector<cmLinkItem>::const_iterator li = iface->Libraries.begin();
+ li != iface->Libraries.end(); ++li) {
+ this->Visit(*li);
+ }
+ }
+
+private:
+ std::string Config;
+ UNORDERED_SET<std::string>& Languages;
+ cmGeneratorTarget const* HeadTarget;
+ const cmGeneratorTarget* Target;
+ std::set<cmGeneratorTarget const*> Visited;
+};
+
+cmGeneratorTarget::LinkClosure const* cmGeneratorTarget::GetLinkClosure(
+ const std::string& config) const
+{
+ std::string key(cmSystemTools::UpperCase(config));
+ LinkClosureMapType::iterator i = this->LinkClosureMap.find(key);
+ if (i == this->LinkClosureMap.end()) {
+ LinkClosure lc;
+ this->ComputeLinkClosure(config, lc);
+ LinkClosureMapType::value_type entry(key, lc);
+ i = this->LinkClosureMap.insert(entry).first;
+ }
+ return &i->second;
+}
+
+class cmTargetSelectLinker
+{
+ int Preference;
+ cmGeneratorTarget const* Target;
+ cmGlobalGenerator* GG;
+ std::set<std::string> Preferred;
+
+public:
+ cmTargetSelectLinker(cmGeneratorTarget const* target)
+ : Preference(0)
+ , Target(target)
+ {
+ this->GG = this->Target->GetLocalGenerator()->GetGlobalGenerator();
+ }
+ void Consider(const char* lang)
+ {
+ int preference = this->GG->GetLinkerPreference(lang);
+ if (preference > this->Preference) {
+ this->Preference = preference;
+ this->Preferred.clear();
+ }
+ if (preference == this->Preference) {
+ this->Preferred.insert(lang);
+ }
+ }
+ std::string Choose()
+ {
+ if (this->Preferred.empty()) {
+ return "";
+ } else if (this->Preferred.size() > 1) {
+ std::ostringstream e;
+ e << "Target " << this->Target->GetName()
+ << " contains multiple languages with the highest linker preference"
+ << " (" << this->Preference << "):\n";
+ for (std::set<std::string>::const_iterator li = this->Preferred.begin();
+ li != this->Preferred.end(); ++li) {
+ e << " " << *li << "\n";
+ }
+ e << "Set the LINKER_LANGUAGE property for this target.";
+ cmake* cm = this->Target->GetLocalGenerator()->GetCMakeInstance();
+ cm->IssueMessage(cmake::FATAL_ERROR, e.str(),
+ this->Target->GetBacktrace());
+ }
+ return *this->Preferred.begin();
+ }
+};
+
+void cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
+ LinkClosure& lc) const
+{
+ // Get languages built in this target.
+ UNORDERED_SET<std::string> languages;
+ cmLinkImplementation const* impl = this->GetLinkImplementation(config);
+ assert(impl);
+ for (std::vector<std::string>::const_iterator li = impl->Languages.begin();
+ li != impl->Languages.end(); ++li) {
+ languages.insert(*li);
+ }
+
+ // Add interface languages from linked targets.
+ cmTargetCollectLinkLanguages cll(this, config, languages, this);
+ for (std::vector<cmLinkImplItem>::const_iterator li =
+ impl->Libraries.begin();
+ li != impl->Libraries.end(); ++li) {
+ cll.Visit(*li);
+ }
+
+ // Store the transitive closure of languages.
+ for (UNORDERED_SET<std::string>::const_iterator li = languages.begin();
+ li != languages.end(); ++li) {
+ lc.Languages.push_back(*li);
+ }
+
+ // Choose the language whose linker should be used.
+ if (this->GetProperty("HAS_CXX")) {
+ lc.LinkerLanguage = "CXX";
+ } else if (const char* linkerLang = this->GetProperty("LINKER_LANGUAGE")) {
+ lc.LinkerLanguage = linkerLang;
+ } else {
+ // Find the language with the highest preference value.
+ cmTargetSelectLinker tsl(this);
+
+ // First select from the languages compiled directly in this target.
+ for (std::vector<std::string>::const_iterator li = impl->Languages.begin();
+ li != impl->Languages.end(); ++li) {
+ tsl.Consider(li->c_str());
+ }
+
+ // Now consider languages that propagate from linked targets.
+ for (UNORDERED_SET<std::string>::const_iterator sit = languages.begin();
+ sit != languages.end(); ++sit) {
+ std::string propagates =
+ "CMAKE_" + *sit + "_LINKER_PREFERENCE_PROPAGATES";
+ if (this->Makefile->IsOn(propagates)) {
+ tsl.Consider(sit->c_str());
+ }
+ }
+
+ lc.LinkerLanguage = tsl.Choose();
+ }
+}
+
+void cmGeneratorTarget::GetFullNameComponents(std::string& prefix,
+ std::string& base,
+ std::string& suffix,
+ const std::string& config,
+ bool implib) const
+{
+ this->GetFullNameInternal(config, implib, prefix, base, suffix);
+}
+
+std::string cmGeneratorTarget::BuildMacContentDirectory(
+ const std::string& base, const std::string& config, bool contentOnly) const
+{
+ std::string fpath = base;
+ if (this->IsAppBundleOnApple()) {
+ fpath += this->GetAppBundleDirectory(config, contentOnly);
+ }
+ if (this->IsFrameworkOnApple()) {
+ fpath += this->GetFrameworkDirectory(config, contentOnly);
+ }
+ if (this->IsCFBundleOnApple()) {
+ fpath += this->GetCFBundleDirectory(config, contentOnly);
+ }
+ return fpath;
+}
+
+std::string cmGeneratorTarget::GetMacContentDirectory(
+ const std::string& config, bool implib) const
+{
+ // Start with the output directory for the target.
+ std::string fpath = this->GetDirectory(config, implib);
+ fpath += "/";
+ bool contentOnly = true;
+ if (this->IsFrameworkOnApple()) {
+ // additional files with a framework go into the version specific
+ // directory
+ contentOnly = false;
+ }
+ fpath = this->BuildMacContentDirectory(fpath, config, contentOnly);
+ return fpath;
+}
+
+cmGeneratorTarget::CompileInfo const* cmGeneratorTarget::GetCompileInfo(
+ const std::string& config) const
+{
+ // There is no compile information for imported targets.
+ if (this->IsImported()) {
+ return CM_NULLPTR;
+ }
+
+ if (this->GetType() > cmState::OBJECT_LIBRARY) {
+ std::string msg = "cmTarget::GetCompileInfo called for ";
+ msg += this->GetName();
+ msg += " which has type ";
+ msg += cmState::GetTargetTypeName(this->GetType());
+ this->LocalGenerator->IssueMessage(cmake::INTERNAL_ERROR, msg);
+ return CM_NULLPTR;
+ }
+
+ // Lookup/compute/cache the compile information for this configuration.
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+ CompileInfoMapType::const_iterator i =
+ this->CompileInfoMap.find(config_upper);
+ if (i == this->CompileInfoMap.end()) {
+ CompileInfo info;
+ this->ComputePDBOutputDir("COMPILE_PDB", config, info.CompilePdbDir);
+ CompileInfoMapType::value_type entry(config_upper, info);
+ i = this->CompileInfoMap.insert(entry).first;
+ }
+ return &i->second;
+}
+
+cmSourceFile const* cmGeneratorTarget::GetModuleDefinitionFile(
+ const std::string& config) const
+{
+ std::vector<cmSourceFile const*> data;
+ IMPLEMENT_VISIT_IMPL(ModuleDefinitionFile,
+ COMMA std::vector<cmSourceFile const*>)
+ if (!data.empty()) {
+ return data.front();
+ }
+
+ return CM_NULLPTR;
+}
+
+bool cmGeneratorTarget::IsDLLPlatform() const
+{
+ return this->DLLPlatform;
+}
+
+void cmGeneratorTarget::UseObjectLibraries(std::vector<std::string>& objs,
+ const std::string& config) const
+{
+ std::vector<cmSourceFile const*> objectFiles;
+ this->GetExternalObjects(objectFiles, config);
+ std::vector<cmGeneratorTarget*> objectLibraries;
+ for (std::vector<cmSourceFile const*>::const_iterator it =
+ objectFiles.begin();
+ it != objectFiles.end(); ++it) {
+ std::string objLib = (*it)->GetObjectLibrary();
+ if (cmGeneratorTarget* tgt =
+ this->LocalGenerator->FindGeneratorTargetToUse(objLib)) {
+ objectLibraries.push_back(tgt);
+ }
+ }
+
+ std::vector<cmGeneratorTarget*>::const_iterator end =
+ cmRemoveDuplicates(objectLibraries);
+
+ for (std::vector<cmGeneratorTarget*>::const_iterator ti =
+ objectLibraries.begin();
+ ti != end; ++ti) {
+ cmGeneratorTarget* ogt = *ti;
+ std::vector<cmSourceFile const*> objectSources;
+ ogt->GetObjectSources(objectSources, config);
+ for (std::vector<cmSourceFile const*>::const_iterator si =
+ objectSources.begin();
+ si != objectSources.end(); ++si) {
+ std::string obj = ogt->ObjectDirectory;
+ obj += ogt->Objects[*si];
+ objs.push_back(obj);
+ }
+ }
+}
+
+void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result,
+ const std::string& config) const
+{
+ const char* prop =
+ this->GetLinkInterfaceDependentStringProperty("AUTOUIC_OPTIONS", config);
+ if (!prop) {
+ return;
+ }
+ cmGeneratorExpression ge;
+
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this->GetName(), "AUTOUIC_OPTIONS", CM_NULLPTR, CM_NULLPTR);
+ cmSystemTools::ExpandListArgument(
+ ge.Parse(prop)->Evaluate(this->LocalGenerator, config, false, this,
+ &dagChecker),
+ result);
+}
+
+void processILibs(const std::string& config,
+ cmGeneratorTarget const* headTarget, cmLinkItem const& item,
+ cmGlobalGenerator* gg,
+ std::vector<cmGeneratorTarget const*>& tgts,
+ std::set<cmGeneratorTarget const*>& emitted)
+{
+ if (item.Target && emitted.insert(item.Target).second) {
+ tgts.push_back(item.Target);
+ if (cmLinkInterfaceLibraries const* iface =
+ item.Target->GetLinkInterfaceLibraries(config, headTarget, true)) {
+ for (std::vector<cmLinkItem>::const_iterator it =
+ iface->Libraries.begin();
+ it != iface->Libraries.end(); ++it) {
+ processILibs(config, headTarget, *it, gg, tgts, emitted);
+ }
+ }
+ }
+}
+
+const std::vector<const cmGeneratorTarget*>&
+cmGeneratorTarget::GetLinkImplementationClosure(
+ const std::string& config) const
+{
+ LinkImplClosure& tgts = this->LinkImplClosureMap[config];
+ if (!tgts.Done) {
+ tgts.Done = true;
+ std::set<cmGeneratorTarget const*> emitted;
+
+ cmLinkImplementationLibraries const* impl =
+ this->GetLinkImplementationLibraries(config);
+
+ for (std::vector<cmLinkImplItem>::const_iterator it =
+ impl->Libraries.begin();
+ it != impl->Libraries.end(); ++it) {
+ processILibs(config, this, *it,
+ this->LocalGenerator->GetGlobalGenerator(), tgts, emitted);
+ }
+ }
+ return tgts;
+}
+
+class cmTargetTraceDependencies
+{
+public:
+ cmTargetTraceDependencies(cmGeneratorTarget* target);
+ void Trace();
+
+private:
+ cmGeneratorTarget* GeneratorTarget;
+ cmMakefile* Makefile;
+ cmLocalGenerator* LocalGenerator;
+ cmGlobalGenerator const* GlobalGenerator;
+ typedef cmGeneratorTarget::SourceEntry SourceEntry;
+ SourceEntry* CurrentEntry;
+ std::queue<cmSourceFile*> SourceQueue;
+ std::set<cmSourceFile*> SourcesQueued;
+ typedef std::map<std::string, cmSourceFile*> NameMapType;
+ NameMapType NameMap;
+ std::vector<std::string> NewSources;
+
+ void QueueSource(cmSourceFile* sf);
+ void FollowName(std::string const& name);
+ void FollowNames(std::vector<std::string> const& names);
+ bool IsUtility(std::string const& dep);
+ void CheckCustomCommand(cmCustomCommand const& cc);
+ void CheckCustomCommands(const std::vector<cmCustomCommand>& commands);
+ void FollowCommandDepends(cmCustomCommand const& cc,
+ const std::string& config,
+ std::set<std::string>& emitted);
+};
+
+cmTargetTraceDependencies::cmTargetTraceDependencies(cmGeneratorTarget* target)
+ : GeneratorTarget(target)
+{
+ // Convenience.
+ this->Makefile = target->Target->GetMakefile();
+ this->LocalGenerator = target->GetLocalGenerator();
+ this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
+ this->CurrentEntry = CM_NULLPTR;
+
+ // Queue all the source files already specified for the target.
+ if (target->GetType() != cmState::INTERFACE_LIBRARY) {
+ std::vector<std::string> configs;
+ this->Makefile->GetConfigurations(configs);
+ if (configs.empty()) {
+ configs.push_back("");
+ }
+ std::set<cmSourceFile*> emitted;
+ for (std::vector<std::string>::const_iterator ci = configs.begin();
+ ci != configs.end(); ++ci) {
+ std::vector<cmSourceFile*> sources;
+ this->GeneratorTarget->GetSourceFiles(sources, *ci);
+ for (std::vector<cmSourceFile*>::const_iterator si = sources.begin();
+ si != sources.end(); ++si) {
+ cmSourceFile* sf = *si;
+ const std::set<cmGeneratorTarget const*> tgts =
+ this->GlobalGenerator->GetFilenameTargetDepends(sf);
+ if (tgts.find(this->GeneratorTarget) != tgts.end()) {
+ std::ostringstream e;
+ e << "Evaluation output file\n \"" << sf->GetFullPath()
+ << "\"\ndepends on the sources of a target it is used in. This "
+ "is a dependency loop and is not allowed.";
+ this->GeneratorTarget->LocalGenerator->IssueMessage(
+ cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ if (emitted.insert(sf).second &&
+ this->SourcesQueued.insert(sf).second) {
+ this->SourceQueue.push(sf);
+ }
+ }
+ }
+ }
+
+ // Queue pre-build, pre-link, and post-build rule dependencies.
+ this->CheckCustomCommands(this->GeneratorTarget->GetPreBuildCommands());
+ this->CheckCustomCommands(this->GeneratorTarget->GetPreLinkCommands());
+ this->CheckCustomCommands(this->GeneratorTarget->GetPostBuildCommands());
+}
+
+void cmTargetTraceDependencies::Trace()
+{
+ // Process one dependency at a time until the queue is empty.
+ while (!this->SourceQueue.empty()) {
+ // Get the next source from the queue.
+ cmSourceFile* sf = this->SourceQueue.front();
+ this->SourceQueue.pop();
+ this->CurrentEntry = &this->GeneratorTarget->SourceDepends[sf];
+
+ // Queue dependencies added explicitly by the user.
+ if (const char* additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) {
+ std::vector<std::string> objDeps;
+ cmSystemTools::ExpandListArgument(additionalDeps, objDeps);
+ for (std::vector<std::string>::iterator odi = objDeps.begin();
+ odi != objDeps.end(); ++odi) {
+ if (cmSystemTools::FileIsFullPath(*odi)) {
+ *odi = cmSystemTools::CollapseFullPath(*odi);
+ }
+ }
+ this->FollowNames(objDeps);
+ }
+
+ // Queue the source needed to generate this file, if any.
+ this->FollowName(sf->GetFullPath());
+
+ // Queue dependencies added programatically by commands.
+ this->FollowNames(sf->GetDepends());
+
+ // Queue custom command dependencies.
+ if (cmCustomCommand const* cc = sf->GetCustomCommand()) {
+ this->CheckCustomCommand(*cc);
+ }
+ }
+ this->CurrentEntry = CM_NULLPTR;
+
+ this->GeneratorTarget->AddTracedSources(this->NewSources);
+}
+
+void cmTargetTraceDependencies::QueueSource(cmSourceFile* sf)
+{
+ if (this->SourcesQueued.insert(sf).second) {
+ this->SourceQueue.push(sf);
+
+ // Make sure this file is in the target at the end.
+ this->NewSources.push_back(sf->GetFullPath());
+ }
+}
+
+void cmTargetTraceDependencies::FollowName(std::string const& name)
+{
+ NameMapType::iterator i = this->NameMap.find(name);
+ if (i == this->NameMap.end()) {
+ // Check if we know how to generate this file.
+ cmSourceFile* sf = this->Makefile->GetSourceFileWithOutput(name);
+ NameMapType::value_type entry(name, sf);
+ i = this->NameMap.insert(entry).first;
+ }
+ if (cmSourceFile* sf = i->second) {
+ // Record the dependency we just followed.
+ if (this->CurrentEntry) {
+ this->CurrentEntry->Depends.push_back(sf);
+ }
+ this->QueueSource(sf);
+ }
+}
+
+void cmTargetTraceDependencies::FollowNames(
+ std::vector<std::string> const& names)
+{
+ for (std::vector<std::string>::const_iterator i = names.begin();
+ i != names.end(); ++i) {
+ this->FollowName(*i);
+ }
+}
+
+bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
+{
+ // Dependencies on targets (utilities) are supposed to be named by
+ // just the target name. However for compatibility we support
+ // naming the output file generated by the target (assuming there is
+ // no output-name property which old code would not have set). In
+ // that case the target name will be the file basename of the
+ // dependency.
+ std::string util = cmSystemTools::GetFilenameName(dep);
+ if (cmSystemTools::GetFilenameLastExtension(util) == ".exe") {
+ util = cmSystemTools::GetFilenameWithoutLastExtension(util);
+ }
+
+ // Check for a target with this name.
+ if (cmGeneratorTarget* t =
+ this->GeneratorTarget->GetLocalGenerator()->FindGeneratorTargetToUse(
+ util)) {
+ // If we find the target and the dep was given as a full path,
+ // then make sure it was not a full path to something else, and
+ // the fact that the name matched a target was just a coincidence.
+ if (cmSystemTools::FileIsFullPath(dep.c_str())) {
+ if (t->GetType() >= cmState::EXECUTABLE &&
+ t->GetType() <= cmState::MODULE_LIBRARY) {
+ // This is really only for compatibility so we do not need to
+ // worry about configuration names and output names.
+ std::string tLocation = t->GetLocationForBuild();
+ tLocation = cmSystemTools::GetFilenamePath(tLocation);
+ std::string depLocation = cmSystemTools::GetFilenamePath(dep);
+ depLocation = cmSystemTools::CollapseFullPath(depLocation);
+ tLocation = cmSystemTools::CollapseFullPath(tLocation);
+ if (depLocation == tLocation) {
+ this->GeneratorTarget->Target->AddUtility(util);
+ return true;
+ }
+ }
+ } else {
+ // The original name of the dependency was not a full path. It
+ // must name a target, so add the target-level dependency.
+ this->GeneratorTarget->Target->AddUtility(util);
+ return true;
+ }
+ }
+
+ // The dependency does not name a target built in this project.
+ return false;
+}
+
+void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc)
+{
+ // Transform command names that reference targets built in this
+ // project to corresponding target-level dependencies.
+ cmGeneratorExpression ge(cc.GetBacktrace());
+
+ // Add target-level dependencies referenced by generator expressions.
+ std::set<cmGeneratorTarget*> targets;
+
+ for (cmCustomCommandLines::const_iterator cit = cc.GetCommandLines().begin();
+ cit != cc.GetCommandLines().end(); ++cit) {
+ std::string const& command = *cit->begin();
+ // Check for a target with this name.
+ if (cmGeneratorTarget* t =
+ this->LocalGenerator->FindGeneratorTargetToUse(command)) {
+ if (t->GetType() == cmState::EXECUTABLE) {
+ // The command refers to an executable target built in
+ // this project. Add the target-level dependency to make
+ // sure the executable is up to date before this custom
+ // command possibly runs.
+ this->GeneratorTarget->Target->AddUtility(command);
+ }
+ }
+
+ // Check for target references in generator expressions.
+ for (cmCustomCommandLine::const_iterator cli = cit->begin();
+ cli != cit->end(); ++cli) {
+ const CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(*cli);
+ cge->Evaluate(this->GeneratorTarget->GetLocalGenerator(), "", true);
+ std::set<cmGeneratorTarget*> geTargets = cge->GetTargets();
+ targets.insert(geTargets.begin(), geTargets.end());
+ }
+ }
+
+ for (std::set<cmGeneratorTarget*>::iterator ti = targets.begin();
+ ti != targets.end(); ++ti) {
+ this->GeneratorTarget->Target->AddUtility((*ti)->GetName());
+ }
+
+ // Queue the custom command dependencies.
+ std::vector<std::string> configs;
+ std::set<std::string> emitted;
+ this->Makefile->GetConfigurations(configs);
+ if (configs.empty()) {
+ configs.push_back("");
+ }
+ for (std::vector<std::string>::const_iterator ci = configs.begin();
+ ci != configs.end(); ++ci) {
+ this->FollowCommandDepends(cc, *ci, emitted);
+ }
+}
+
+void cmTargetTraceDependencies::FollowCommandDepends(
+ cmCustomCommand const& cc, const std::string& config,
+ std::set<std::string>& emitted)
+{
+ cmCustomCommandGenerator ccg(cc, config,
+ this->GeneratorTarget->LocalGenerator);
+
+ const std::vector<std::string>& depends = ccg.GetDepends();
+
+ for (std::vector<std::string>::const_iterator di = depends.begin();
+ di != depends.end(); ++di) {
+ std::string const& dep = *di;
+ if (emitted.insert(dep).second) {
+ if (!this->IsUtility(dep)) {
+ // The dependency does not name a target and may be a file we
+ // know how to generate. Queue it.
+ this->FollowName(dep);
+ }
+ }
+ }
+}
+
+void cmTargetTraceDependencies::CheckCustomCommands(
+ const std::vector<cmCustomCommand>& commands)
+{
+ for (std::vector<cmCustomCommand>::const_iterator cli = commands.begin();
+ cli != commands.end(); ++cli) {
+ this->CheckCustomCommand(*cli);
+ }
+}
+
+void cmGeneratorTarget::TraceDependencies()
+{
+ // CMake-generated targets have no dependencies to trace. Normally tracing
+ // would find nothing anyway, but when building CMake itself the "install"
+ // target command ends up referencing the "cmake" target but we do not
+ // really want the dependency because "install" depend on "all" anyway.
+ if (this->GetType() == cmState::GLOBAL_TARGET) {
+ return;
+ }
+
+ // Use a helper object to trace the dependencies.
+ cmTargetTraceDependencies tracer(this);
+ tracer.Trace();
+}
+
+std::string cmGeneratorTarget::GetCompilePDBDirectory(
+ const std::string& config) const
+{
+ if (CompileInfo const* info = this->GetCompileInfo(config)) {
+ return info->CompilePdbDir;
+ }
+ return "";
+}
+
+void cmGeneratorTarget::GetAppleArchs(const std::string& config,
+ std::vector<std::string>& archVec) const
+{
+ const char* archs = CM_NULLPTR;
+ if (!config.empty()) {
+ std::string defVarName = "OSX_ARCHITECTURES_";
+ defVarName += cmSystemTools::UpperCase(config);
+ archs = this->GetProperty(defVarName);
+ }
+ if (!archs) {
+ archs = this->GetProperty("OSX_ARCHITECTURES");
+ }
+ if (archs) {
+ cmSystemTools::ExpandListArgument(std::string(archs), archVec);
+ }
+}
+
+std::string cmGeneratorTarget::GetCreateRuleVariable(
+ std::string const& lang, std::string const& config) const
+{
+ switch (this->GetType()) {
+ case cmState::STATIC_LIBRARY: {
+ std::string var = "CMAKE_" + lang + "_CREATE_STATIC_LIBRARY";
+ if (this->GetFeatureAsBool("INTERPROCEDURAL_OPTIMIZATION", config)) {
+ std::string varIPO = var + "_IPO";
+ if (this->Makefile->GetDefinition(varIPO)) {
+ return varIPO;
+ }
+ }
+ return var;
+ }
+ case cmState::SHARED_LIBRARY:
+ return "CMAKE_" + lang + "_CREATE_SHARED_LIBRARY";
+ case cmState::MODULE_LIBRARY:
+ return "CMAKE_" + lang + "_CREATE_SHARED_MODULE";
+ case cmState::EXECUTABLE:
+ return "CMAKE_" + lang + "_LINK_EXECUTABLE";
+ default:
+ break;
+ }
+ return "";
+}
+static void processIncludeDirectories(
+ cmGeneratorTarget const* tgt,
+ const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
+ std::vector<std::string>& includes,
+ UNORDERED_SET<std::string>& uniqueIncludes,
+ cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
+ bool debugIncludes, const std::string& language)
+{
+ for (std::vector<cmGeneratorTarget::TargetPropertyEntry *>::const_iterator
+ it = entries.begin(),
+ end = entries.end();
+ it != end; ++it) {
+ cmLinkImplItem const& item = (*it)->LinkImplItem;
+ std::string const& targetName = item;
+ bool const fromImported = item.Target && item.Target->IsImported();
+ bool const checkCMP0027 = item.FromGenex;
+ std::vector<std::string> entryIncludes;
+ cmSystemTools::ExpandListArgument(
+ (*it)->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
+ dagChecker, language),
+ entryIncludes);
+
+ std::string usedIncludes;
+ for (std::vector<std::string>::iterator li = entryIncludes.begin();
+ li != entryIncludes.end(); ++li) {
+ if (fromImported && !cmSystemTools::FileExists(li->c_str())) {
+ std::ostringstream e;
+ cmake::MessageType messageType = cmake::FATAL_ERROR;
+ if (checkCMP0027) {
+ switch (tgt->GetPolicyStatusCMP0027()) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0027) << "\n";
+ case cmPolicies::OLD:
+ messageType = cmake::AUTHOR_WARNING;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ break;
+ }
+ }
+ /* clang-format off */
+ e << "Imported target \"" << targetName << "\" includes "
+ "non-existent path\n \"" << *li << "\"\nin its "
+ "INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:\n"
+ "* The path was deleted, renamed, or moved to another "
+ "location.\n"
+ "* An install or uninstall procedure did not complete "
+ "successfully.\n"
+ "* The installation package was faulty and references files it "
+ "does not provide.\n";
+ /* clang-format on */
+ tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
+ return;
+ }
+
+ if (!cmSystemTools::FileIsFullPath(li->c_str())) {
+ std::ostringstream e;
+ bool noMessage = false;
+ cmake::MessageType messageType = cmake::FATAL_ERROR;
+ if (!targetName.empty()) {
+ /* clang-format off */
+ e << "Target \"" << targetName << "\" contains relative "
+ "path in its INTERFACE_INCLUDE_DIRECTORIES:\n"
+ " \"" << *li << "\"";
+ /* clang-format on */
+ } else {
+ switch (tgt->GetPolicyStatusCMP0021()) {
+ case cmPolicies::WARN: {
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0021) << "\n";
+ messageType = cmake::AUTHOR_WARNING;
+ } break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Issue the fatal message.
+ break;
+ }
+ e << "Found relative path while evaluating include directories of "
+ "\""
+ << tgt->GetName() << "\":\n \"" << *li << "\"\n";
+ }
+ if (!noMessage) {
+ tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
+ if (messageType == cmake::FATAL_ERROR) {
+ return;
+ }
+ }
+ }
+
+ if (!cmSystemTools::IsOff(li->c_str())) {
+ cmSystemTools::ConvertToUnixSlashes(*li);
+ }
+ std::string inc = *li;
+
+ if (uniqueIncludes.insert(inc).second) {
+ includes.push_back(inc);
+ if (debugIncludes) {
+ usedIncludes += " * " + inc + "\n";
+ }
+ }
+ }
+ if (!usedIncludes.empty()) {
+ tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+ cmake::LOG, std::string("Used includes for target ") + tgt->GetName() +
+ ":\n" + usedIncludes,
+ (*it)->ge->GetBacktrace());
+ }
+ }
+}
+
+std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories(
+ const std::string& config, const std::string& lang) const
+{
+ std::vector<std::string> includes;
+ UNORDERED_SET<std::string> uniqueIncludes;
+
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this->GetName(), "INCLUDE_DIRECTORIES", CM_NULLPTR, CM_NULLPTR);
+
+ std::vector<std::string> debugProperties;
+ const char* debugProp =
+ this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
+ if (debugProp) {
+ cmSystemTools::ExpandListArgument(debugProp, debugProperties);
+ }
+
+ bool debugIncludes = !this->DebugIncludesDone &&
+ std::find(debugProperties.begin(), debugProperties.end(),
+ "INCLUDE_DIRECTORIES") != debugProperties.end();
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugIncludesDone = true;
+ }
+
+ processIncludeDirectories(this, this->IncludeDirectoriesEntries, includes,
+ uniqueIncludes, &dagChecker, config, debugIncludes,
+ lang);
+
+ std::vector<cmGeneratorTarget::TargetPropertyEntry*>
+ linkInterfaceIncludeDirectoriesEntries;
+ AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES",
+ linkInterfaceIncludeDirectoriesEntries);
+
+ if (this->Makefile->IsOn("APPLE")) {
+ cmLinkImplementationLibraries const* impl =
+ this->GetLinkImplementationLibraries(config);
+ for (std::vector<cmLinkImplItem>::const_iterator it =
+ impl->Libraries.begin();
+ it != impl->Libraries.end(); ++it) {
+ std::string libDir = cmSystemTools::CollapseFullPath(*it);
+
+ static cmsys::RegularExpression frameworkCheck(
+ "(.*\\.framework)(/Versions/[^/]+)?/[^/]+$");
+ if (!frameworkCheck.find(libDir)) {
+ continue;
+ }
+
+ libDir = frameworkCheck.match(1);
+
+ cmGeneratorExpression ge;
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge =
+ ge.Parse(libDir.c_str());
+ linkInterfaceIncludeDirectoriesEntries.push_back(
+ new cmGeneratorTarget::TargetPropertyEntry(cge));
+ }
+ }
+
+ processIncludeDirectories(this, linkInterfaceIncludeDirectoriesEntries,
+ includes, uniqueIncludes, &dagChecker, config,
+ debugIncludes, lang);
+
+ cmDeleteAll(linkInterfaceIncludeDirectoriesEntries);
+
+ // Add standard include directories for this language.
+ std::string const standardIncludesVar =
+ "CMAKE_" + lang + "_STANDARD_INCLUDE_DIRECTORIES";
+ std::string const standardIncludes =
+ this->Makefile->GetSafeDefinition(standardIncludesVar);
+ std::vector<std::string>::size_type const before = includes.size();
+ cmSystemTools::ExpandListArgument(standardIncludes, includes);
+ for (std::vector<std::string>::iterator i = includes.begin() + before;
+ i != includes.end(); ++i) {
+ cmSystemTools::ConvertToUnixSlashes(*i);
+ }
+
+ return includes;
+}
+
+static void processCompileOptionsInternal(
+ cmGeneratorTarget const* tgt,
+ const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
+ std::vector<std::string>& options, UNORDERED_SET<std::string>& uniqueOptions,
+ cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
+ bool debugOptions, const char* logName, std::string const& language)
+{
+ for (std::vector<cmGeneratorTarget::TargetPropertyEntry *>::const_iterator
+ it = entries.begin(),
+ end = entries.end();
+ it != end; ++it) {
+ std::vector<std::string> entryOptions;
+ cmSystemTools::ExpandListArgument(
+ (*it)->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
+ dagChecker, language),
+ entryOptions);
+ std::string usedOptions;
+ for (std::vector<std::string>::iterator li = entryOptions.begin();
+ li != entryOptions.end(); ++li) {
+ std::string const& opt = *li;
+
+ if (uniqueOptions.insert(opt).second) {
+ options.push_back(opt);
+ if (debugOptions) {
+ usedOptions += " * " + opt + "\n";
+ }
+ }
+ }
+ if (!usedOptions.empty()) {
+ tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+ cmake::LOG, std::string("Used compile ") + logName +
+ std::string(" for target ") + tgt->GetName() + ":\n" + usedOptions,
+ (*it)->ge->GetBacktrace());
+ }
+ }
+}
+
+static void processCompileOptions(
+ cmGeneratorTarget const* tgt,
+ const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
+ std::vector<std::string>& options, UNORDERED_SET<std::string>& uniqueOptions,
+ cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
+ bool debugOptions, std::string const& language)
+{
+ processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
+ dagChecker, config, debugOptions, "options",
+ language);
+}
+
+void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const
+{
+ UNORDERED_SET<std::string> uniqueOptions;
+
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this->GetName(), "COMPILE_OPTIONS", CM_NULLPTR, CM_NULLPTR);
+
+ std::vector<std::string> debugProperties;
+ const char* debugProp =
+ this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
+ if (debugProp) {
+ cmSystemTools::ExpandListArgument(debugProp, debugProperties);
+ }
+
+ bool debugOptions = !this->DebugCompileOptionsDone &&
+ std::find(debugProperties.begin(), debugProperties.end(),
+ "COMPILE_OPTIONS") != debugProperties.end();
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugCompileOptionsDone = true;
+ }
+
+ processCompileOptions(this, this->CompileOptionsEntries, result,
+ uniqueOptions, &dagChecker, config, debugOptions,
+ language);
+
+ std::vector<cmGeneratorTarget::TargetPropertyEntry*>
+ linkInterfaceCompileOptionsEntries;
+
+ AddInterfaceEntries(this, config, "INTERFACE_COMPILE_OPTIONS",
+ linkInterfaceCompileOptionsEntries);
+
+ processCompileOptions(this, linkInterfaceCompileOptionsEntries, result,
+ uniqueOptions, &dagChecker, config, debugOptions,
+ language);
+
+ cmDeleteAll(linkInterfaceCompileOptionsEntries);
+}
+
+static void processCompileFeatures(
+ cmGeneratorTarget const* tgt,
+ const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
+ std::vector<std::string>& options, UNORDERED_SET<std::string>& uniqueOptions,
+ cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
+ bool debugOptions)
+{
+ processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
+ dagChecker, config, debugOptions, "features",
+ std::string());
+}
+
+void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result,
+ const std::string& config) const
+{
+ UNORDERED_SET<std::string> uniqueFeatures;
+
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this->GetName(), "COMPILE_FEATURES", CM_NULLPTR, CM_NULLPTR);
+
+ std::vector<std::string> debugProperties;
+ const char* debugProp =
+ this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
+ if (debugProp) {
+ cmSystemTools::ExpandListArgument(debugProp, debugProperties);
+ }
+
+ bool debugFeatures = !this->DebugCompileFeaturesDone &&
+ std::find(debugProperties.begin(), debugProperties.end(),
+ "COMPILE_FEATURES") != debugProperties.end();
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugCompileFeaturesDone = true;
+ }
+
+ processCompileFeatures(this, this->CompileFeaturesEntries, result,
+ uniqueFeatures, &dagChecker, config, debugFeatures);
+
+ std::vector<cmGeneratorTarget::TargetPropertyEntry*>
+ linkInterfaceCompileFeaturesEntries;
+ AddInterfaceEntries(this, config, "INTERFACE_COMPILE_FEATURES",
+ linkInterfaceCompileFeaturesEntries);
+
+ processCompileFeatures(this, linkInterfaceCompileFeaturesEntries, result,
+ uniqueFeatures, &dagChecker, config, debugFeatures);
+
+ cmDeleteAll(linkInterfaceCompileFeaturesEntries);
+}
+
+static void processCompileDefinitions(
+ cmGeneratorTarget const* tgt,
+ const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
+ std::vector<std::string>& options, UNORDERED_SET<std::string>& uniqueOptions,
+ cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
+ bool debugOptions, std::string const& language)
+{
+ processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
+ dagChecker, config, debugOptions,
+ "definitions", language);
+}
+
+void cmGeneratorTarget::GetCompileDefinitions(
+ std::vector<std::string>& list, const std::string& config,
+ const std::string& language) const
+{
+ UNORDERED_SET<std::string> uniqueOptions;
+
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this->GetName(), "COMPILE_DEFINITIONS", CM_NULLPTR, CM_NULLPTR);
+
+ std::vector<std::string> debugProperties;
+ const char* debugProp =
+ this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
+ if (debugProp) {
+ cmSystemTools::ExpandListArgument(debugProp, debugProperties);
+ }
+
+ bool debugDefines = !this->DebugCompileDefinitionsDone &&
+ std::find(debugProperties.begin(), debugProperties.end(),
+ "COMPILE_DEFINITIONS") != debugProperties.end();
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugCompileDefinitionsDone = true;
+ }
+
+ processCompileDefinitions(this, this->CompileDefinitionsEntries, list,
+ uniqueOptions, &dagChecker, config, debugDefines,
+ language);
+
+ std::vector<cmGeneratorTarget::TargetPropertyEntry*>
+ linkInterfaceCompileDefinitionsEntries;
+ AddInterfaceEntries(this, config, "INTERFACE_COMPILE_DEFINITIONS",
+ linkInterfaceCompileDefinitionsEntries);
+ if (!config.empty()) {
+ std::string configPropName =
+ "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
+ const char* configProp = this->GetProperty(configPropName);
+ if (configProp) {
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0043)) {
+ case cmPolicies::WARN: {
+ std::ostringstream e;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0043);
+ this->LocalGenerator->IssueMessage(cmake::AUTHOR_WARNING, e.str());
+ }
+ case cmPolicies::OLD: {
+ cmGeneratorExpression ge;
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge =
+ ge.Parse(configProp);
+ linkInterfaceCompileDefinitionsEntries.push_back(
+ new cmGeneratorTarget::TargetPropertyEntry(cge));
+ } break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ break;
+ }
+ }
+ }
+
+ processCompileDefinitions(this, linkInterfaceCompileDefinitionsEntries, list,
+ uniqueOptions, &dagChecker, config, debugDefines,
+ language);
+
+ cmDeleteAll(linkInterfaceCompileDefinitionsEntries);
+}
+
+void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
+{
+ if (this->IsImported()) {
+ return;
+ }
+ cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator();
+
+ // Get the names.
+ std::string name;
+ std::string soName;
+ std::string realName;
+ std::string impName;
+ std::string pdbName;
+ if (this->GetType() == cmState::EXECUTABLE) {
+ this->GetExecutableNames(name, realName, impName, pdbName, config);
+ } else if (this->GetType() == cmState::STATIC_LIBRARY ||
+ this->GetType() == cmState::SHARED_LIBRARY ||
+ this->GetType() == cmState::MODULE_LIBRARY) {
+ this->GetLibraryNames(name, soName, realName, impName, pdbName, config);
+ } else {
+ return;
+ }
+
+ // Get the directory.
+ std::string dir = this->GetDirectory(config, false);
+
+ // Add each name.
+ std::string f;
+ if (!name.empty()) {
+ f = dir;
+ f += "/";
+ f += name;
+ gg->AddToManifest(f);
+ }
+ if (!soName.empty()) {
+ f = dir;
+ f += "/";
+ f += soName;
+ gg->AddToManifest(f);
+ }
+ if (!realName.empty()) {
+ f = dir;
+ f += "/";
+ f += realName;
+ gg->AddToManifest(f);
+ }
+ if (!pdbName.empty()) {
+ f = dir;
+ f += "/";
+ f += pdbName;
+ gg->AddToManifest(f);
+ }
+ if (!impName.empty()) {
+ f = this->GetDirectory(config, true);
+ f += "/";
+ f += impName;
+ gg->AddToManifest(f);
+ }
+}
+
+std::string cmGeneratorTarget::GetFullPath(const std::string& config,
+ bool implib, bool realname) const
+{
+ if (this->IsImported()) {
+ return this->Target->ImportedGetFullPath(config, implib);
+ } else {
+ return this->NormalGetFullPath(config, implib, realname);
+ }
+}
+
+std::string cmGeneratorTarget::NormalGetFullPath(const std::string& config,
+ bool implib,
+ bool realname) const
+{
+ std::string fpath = this->GetDirectory(config, implib);
+ fpath += "/";
+ if (this->IsAppBundleOnApple()) {
+ fpath = this->BuildMacContentDirectory(fpath, config, false);
+ fpath += "/";
+ }
+
+ // Add the full name of the target.
+ if (implib) {
+ fpath += this->GetFullName(config, true);
+ } else if (realname) {
+ fpath += this->NormalGetRealName(config);
+ } else {
+ fpath += this->GetFullName(config, false);
+ }
+ return fpath;
+}
+
+std::string cmGeneratorTarget::NormalGetRealName(
+ const std::string& config) const
+{
+ // 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.
+ if (this->IsImported()) {
+ std::string msg = "NormalGetRealName called on imported target: ";
+ msg += this->GetName();
+ this->LocalGenerator->IssueMessage(cmake::INTERNAL_ERROR, msg);
+ }
+
+ if (this->GetType() == cmState::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;
+ } else {
+ // 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
+{
+ // 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.
+ if (this->IsImported()) {
+ std::string msg = "GetLibraryNames called on imported target: ";
+ msg += this->GetName();
+ this->LocalGenerator->IssueMessage(cmake::INTERNAL_ERROR, msg);
+ return;
+ }
+
+ // Check for library version properties.
+ const char* version = this->GetProperty("VERSION");
+ const char* soversion = this->GetProperty("SOVERSION");
+ if (!this->HasSOName(config) ||
+ this->Makefile->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") ||
+ this->IsFrameworkOnApple()) {
+ // Versioning is supported only for shared libraries and modules,
+ // and then only when the platform supports an soname flag.
+ version = CM_NULLPTR;
+ soversion = CM_NULLPTR;
+ }
+ if (version && !soversion) {
+ // The soversion must be set if the library version is set. Use
+ // the library version as the soversion.
+ soversion = version;
+ }
+ if (!version && soversion) {
+ // Use the soversion as the library version.
+ version = soversion;
+ }
+
+ // Get the components of the library name.
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(config, false, prefix, base, suffix);
+
+ // The library name.
+ name = prefix + base + suffix;
+
+ if (this->IsFrameworkOnApple()) {
+ realName = prefix;
+ if (!this->Makefile->PlatformIsAppleIos()) {
+ realName += "Versions/";
+ realName += this->GetFrameworkVersion();
+ realName += "/";
+ }
+ realName += base;
+ soName = realName;
+ } else {
+ // The library's soname.
+ this->ComputeVersionedName(soName, prefix, base, suffix, name, soversion);
+
+ // The library's real name on disk.
+ this->ComputeVersionedName(realName, prefix, base, suffix, name, version);
+ }
+
+ // The import library name.
+ if (this->GetType() == cmState::SHARED_LIBRARY ||
+ this->GetType() == cmState::MODULE_LIBRARY) {
+ impName = this->GetFullNameInternal(config, true);
+ } else {
+ impName = "";
+ }
+
+ // The program database file name.
+ pdbName = this->GetPDBName(config);
+}
+
+void cmGeneratorTarget::GetExecutableNames(std::string& name,
+ std::string& realName,
+ std::string& impName,
+ std::string& pdbName,
+ const std::string& config) const
+{
+ // 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.
+ if (this->IsImported()) {
+ std::string msg = "GetExecutableNames called on imported target: ";
+ msg += this->GetName();
+ this->LocalGenerator->IssueMessage(cmake::INTERNAL_ERROR, msg);
+ }
+
+// This versioning is supported only for executables and then only
+// when the platform supports symbolic links.
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ const char* version = 0;
+#else
+ // Check for executable version properties.
+ const char* version = this->GetProperty("VERSION");
+ if (this->GetType() != cmState::EXECUTABLE ||
+ this->Makefile->IsOn("XCODE")) {
+ version = CM_NULLPTR;
+ }
+#endif
+
+ // Get the components of the executable name.
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(config, false, prefix, base, suffix);
+
+ // The executable name.
+ name = prefix + base + suffix;
+
+// The executable's real name on disk.
+#if defined(__CYGWIN__)
+ realName = prefix + base;
+#else
+ realName = name;
+#endif
+ if (version) {
+ realName += "-";
+ realName += version;
+ }
+#if defined(__CYGWIN__)
+ realName += suffix;
+#endif
+
+ // The import library name.
+ impName = this->GetFullNameInternal(config, true);
+
+ // The program database file name.
+ pdbName = this->GetPDBName(config);
+}
+
+std::string cmGeneratorTarget::GetFullNameInternal(const std::string& config,
+ bool implib) const
+{
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(config, implib, prefix, base, suffix);
+ return prefix + base + suffix;
+}
+
+const char* cmGeneratorTarget::ImportedGetLocation(
+ const std::string& config) const
+{
+ static std::string location;
+ assert(this->IsImported());
+ location = this->Target->ImportedGetFullPath(config, false);
+ return location.c_str();
+}
+
+std::string cmGeneratorTarget::GetFullNameImported(const std::string& config,
+ bool implib) const
+{
+ return cmSystemTools::GetFilenameName(
+ this->Target->ImportedGetFullPath(config, implib));
+}
+
+void cmGeneratorTarget::GetFullNameInternal(const std::string& config,
+ bool implib,
+ std::string& outPrefix,
+ std::string& outBase,
+ std::string& outSuffix) const
+{
+ // Use just the target name for non-main target types.
+ if (this->GetType() != cmState::STATIC_LIBRARY &&
+ this->GetType() != cmState::SHARED_LIBRARY &&
+ this->GetType() != cmState::MODULE_LIBRARY &&
+ this->GetType() != cmState::EXECUTABLE) {
+ outPrefix = "";
+ outBase = this->GetName();
+ outSuffix = "";
+ return;
+ }
+
+ // Return an empty name for the import library if this platform
+ // does not support import libraries.
+ if (implib &&
+ !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
+ outPrefix = "";
+ outBase = "";
+ outSuffix = "";
+ return;
+ }
+
+ // The implib option is only allowed for shared libraries, module
+ // libraries, and executables.
+ if (this->GetType() != cmState::SHARED_LIBRARY &&
+ this->GetType() != cmState::MODULE_LIBRARY &&
+ this->GetType() != cmState::EXECUTABLE) {
+ implib = false;
+ }
+
+ // Compute the full name for main target types.
+ const char* targetPrefix = (implib ? this->GetProperty("IMPORT_PREFIX")
+ : this->GetProperty("PREFIX"));
+ const char* targetSuffix = (implib ? this->GetProperty("IMPORT_SUFFIX")
+ : this->GetProperty("SUFFIX"));
+ const char* configPostfix = CM_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 = CM_NULLPTR;
+ }
+ }
+ const char* prefixVar = this->Target->GetPrefixVariableInternal(implib);
+ const char* suffixVar = this->Target->GetSuffixVariableInternal(implib);
+
+ // 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);
+ }
+ // if there is no suffix on the target use the cmake definition
+ if (!targetSuffix && suffixVar) {
+ targetSuffix = this->Makefile->GetSafeDefinition(suffixVar);
+ }
+
+ // frameworks have directory prefix but no suffix
+ std::string fw_prefix;
+ if (this->IsFrameworkOnApple()) {
+ fw_prefix = this->GetOutputName(config, false);
+ fw_prefix += ".framework/";
+ targetPrefix = fw_prefix.c_str();
+ targetSuffix = CM_NULLPTR;
+ }
+
+ if (this->IsCFBundleOnApple()) {
+ fw_prefix = this->GetCFBundleDirectory(config, false);
+ fw_prefix += "/";
+ targetPrefix = fw_prefix.c_str();
+ targetSuffix = CM_NULLPTR;
+ }
+
+ // Begin the final name with the prefix.
+ outPrefix = targetPrefix ? targetPrefix : "";
+
+ // Append the target name or property-specified name.
+ outBase += this->GetOutputName(config, implib);
+
+ // Append the per-configuration postfix.
+ outBase += configPostfix ? configPostfix : "";
+
+ // Name shared libraries with their version number on some platforms.
+ if (const char* soversion = this->GetProperty("SOVERSION")) {
+ if (this->GetType() == cmState::SHARED_LIBRARY && !implib &&
+ this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION")) {
+ outBase += "-";
+ outBase += soversion;
+ }
+ }
+
+ // Append the suffix.
+ outSuffix = targetSuffix ? targetSuffix : "";
+}
+
+std::string cmGeneratorTarget::GetLinkerLanguage(
+ const std::string& config) const
+{
+ return this->GetLinkClosure(config)->LinkerLanguage;
+}
+
+std::string cmGeneratorTarget::GetPDBName(const std::string& config) const
+{
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(config, false, prefix, base, suffix);
+
+ 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.push_back("PDB_NAME");
+
+ for (std::vector<std::string>::const_iterator i = props.begin();
+ i != props.end(); ++i) {
+ if (const char* outName = this->GetProperty(*i)) {
+ base = outName;
+ break;
+ }
+ }
+ return prefix + base + ".pdb";
+}
+
+bool cmGeneratorTarget::StrictTargetComparison::operator()(
+ cmGeneratorTarget const* t1, cmGeneratorTarget const* t2) const
+{
+ int nameResult = strcmp(t1->GetName().c_str(), t2->GetName().c_str());
+ if (nameResult == 0) {
+ return strcmp(t1->GetLocalGenerator()->GetCurrentBinaryDirectory(),
+ t2->GetLocalGenerator()->GetCurrentBinaryDirectory()) < 0;
+ }
+ return nameResult < 0;
+}
+
+struct cmGeneratorTarget::SourceFileFlags
+cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const
+{
+ struct SourceFileFlags flags;
+ this->ConstructSourceFileFlags();
+ std::map<cmSourceFile const*, SourceFileFlags>::iterator si =
+ this->SourceFlagsMap.find(sf);
+ if (si != this->SourceFlagsMap.end()) {
+ flags = si->second;
+ } else {
+ // Handle the MACOSX_PACKAGE_LOCATION property on source files that
+ // were not listed in one of the other lists.
+ if (const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) {
+ flags.MacFolder = location;
+ if (strcmp(location, "Resources") == 0) {
+ flags.Type = cmGeneratorTarget::SourceFileTypeResource;
+ } else {
+ flags.Type = cmGeneratorTarget::SourceFileTypeMacContent;
+ }
+ }
+ }
+ return flags;
+}
+
+void cmGeneratorTarget::ConstructSourceFileFlags() const
+{
+ if (this->SourceFileFlagsConstructed) {
+ return;
+ }
+ this->SourceFileFlagsConstructed = true;
+
+ // Process public headers to mark the source files.
+ if (const char* files = this->GetProperty("PUBLIC_HEADER")) {
+ std::vector<std::string> relFiles;
+ cmSystemTools::ExpandListArgument(files, relFiles);
+ for (std::vector<std::string>::iterator it = relFiles.begin();
+ it != relFiles.end(); ++it) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(*it)) {
+ SourceFileFlags& flags = this->SourceFlagsMap[sf];
+ flags.MacFolder = "Headers";
+ flags.Type = cmGeneratorTarget::SourceFileTypePublicHeader;
+ }
+ }
+ }
+
+ // Process private headers after public headers so that they take
+ // precedence if a file is listed in both.
+ if (const char* files = this->GetProperty("PRIVATE_HEADER")) {
+ std::vector<std::string> relFiles;
+ cmSystemTools::ExpandListArgument(files, relFiles);
+ for (std::vector<std::string>::iterator it = relFiles.begin();
+ it != relFiles.end(); ++it) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(*it)) {
+ SourceFileFlags& flags = this->SourceFlagsMap[sf];
+ flags.MacFolder = "PrivateHeaders";
+ flags.Type = cmGeneratorTarget::SourceFileTypePrivateHeader;
+ }
+ }
+ }
+
+ // Mark sources listed as resources.
+ if (const char* files = this->GetProperty("RESOURCE")) {
+ std::vector<std::string> relFiles;
+ cmSystemTools::ExpandListArgument(files, relFiles);
+ for (std::vector<std::string>::iterator it = relFiles.begin();
+ it != relFiles.end(); ++it) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(*it)) {
+ SourceFileFlags& flags = this->SourceFlagsMap[sf];
+ flags.MacFolder = "";
+ if (!this->Makefile->PlatformIsAppleIos()) {
+ flags.MacFolder = "Resources";
+ }
+ flags.Type = cmGeneratorTarget::SourceFileTypeResource;
+ }
+ }
+ }
+}
+
+const cmGeneratorTarget::CompatibleInterfacesBase&
+cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const
+{
+ cmGeneratorTarget::CompatibleInterfaces& compat =
+ this->CompatibleInterfacesMap[config];
+ if (!compat.Done) {
+ compat.Done = true;
+ compat.PropsBool.insert("POSITION_INDEPENDENT_CODE");
+ compat.PropsString.insert("AUTOUIC_OPTIONS");
+ std::vector<cmGeneratorTarget const*> const& deps =
+ this->GetLinkImplementationClosure(config);
+ for (std::vector<cmGeneratorTarget const*>::const_iterator li =
+ deps.begin();
+ li != deps.end(); ++li) {
+#define CM_READ_COMPATIBLE_INTERFACE(X, x) \
+ if (const char* prop = (*li)->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \
+ std::vector<std::string> props; \
+ cmSystemTools::ExpandListArgument(prop, props); \
+ compat.Props##x.insert(props.begin(), props.end()); \
+ }
+ CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool)
+ CM_READ_COMPATIBLE_INTERFACE(STRING, String)
+ CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin)
+ CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax)
+#undef CM_READ_COMPATIBLE_INTERFACE
+ }
+ }
+ return compat;
+}
+
+bool cmGeneratorTarget::IsLinkInterfaceDependentBoolProperty(
+ const std::string& p, const std::string& config) const
+{
+ if (this->GetType() == cmState::OBJECT_LIBRARY ||
+ this->GetType() == cmState::INTERFACE_LIBRARY) {
+ return false;
+ }
+ return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0;
+}
+
+bool cmGeneratorTarget::IsLinkInterfaceDependentStringProperty(
+ const std::string& p, const std::string& config) const
+{
+ if (this->GetType() == cmState::OBJECT_LIBRARY ||
+ this->GetType() == cmState::INTERFACE_LIBRARY) {
+ return false;
+ }
+ return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0;
+}
+
+bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMinProperty(
+ const std::string& p, const std::string& config) const
+{
+ if (this->GetType() == cmState::OBJECT_LIBRARY ||
+ this->GetType() == cmState::INTERFACE_LIBRARY) {
+ return false;
+ }
+ return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0;
+}
+
+bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMaxProperty(
+ const std::string& p, const std::string& config) const
+{
+ if (this->GetType() == cmState::OBJECT_LIBRARY ||
+ this->GetType() == cmState::INTERFACE_LIBRARY) {
+ return false;
+ }
+ return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0;
+}
+
+enum CompatibleType
+{
+ BoolType,
+ StringType,
+ NumberMinType,
+ NumberMaxType
+};
+
+template <typename PropertyType>
+PropertyType getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
+ const std::string& prop,
+ const std::string& config,
+ CompatibleType, PropertyType*);
+
+template <>
+bool getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
+ const std::string& prop,
+ const std::string& config,
+ CompatibleType, bool*)
+{
+ return tgt->GetLinkInterfaceDependentBoolProperty(prop, config);
+}
+
+template <>
+const char* getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
+ const std::string& prop,
+ const std::string& config,
+ CompatibleType t, const char**)
+{
+ switch (t) {
+ case BoolType:
+ assert(0 && "String compatibility check function called for boolean");
+ return CM_NULLPTR;
+ case StringType:
+ return tgt->GetLinkInterfaceDependentStringProperty(prop, config);
+ case NumberMinType:
+ return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config);
+ case NumberMaxType:
+ return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config);
+ }
+ assert(0 && "Unreachable!");
+ return CM_NULLPTR;
+}
+
+template <typename PropertyType>
+void checkPropertyConsistency(cmGeneratorTarget const* depender,
+ cmGeneratorTarget const* dependee,
+ const std::string& propName,
+ std::set<std::string>& emitted,
+ const std::string& config, CompatibleType t,
+ PropertyType*)
+{
+ const char* prop = dependee->GetProperty(propName);
+ if (!prop) {
+ return;
+ }
+
+ std::vector<std::string> props;
+ cmSystemTools::ExpandListArgument(prop, props);
+ std::string pdir = cmSystemTools::GetCMakeRoot();
+ pdir += "/Help/prop_tgt/";
+
+ for (std::vector<std::string>::iterator pi = props.begin();
+ pi != props.end(); ++pi) {
+ std::string pname = cmSystemTools::HelpFileName(*pi);
+ std::string pfile = pdir + pname + ".rst";
+ if (cmSystemTools::FileExists(pfile.c_str(), true)) {
+ std::ostringstream e;
+ e << "Target \"" << dependee->GetName() << "\" has property \"" << *pi
+ << "\" listed in its " << propName
+ << " property. "
+ "This is not allowed. Only user-defined properties may appear "
+ "listed in the "
+ << propName << " property.";
+ depender->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ if (emitted.insert(*pi).second) {
+ getLinkInterfaceDependentProperty<PropertyType>(depender, *pi, config, t,
+ CM_NULLPTR);
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+ }
+ }
+}
+
+static std::string intersect(const std::set<std::string>& s1,
+ const std::set<std::string>& s2)
+{
+ std::set<std::string> intersect;
+ std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
+ std::inserter(intersect, intersect.begin()));
+ if (!intersect.empty()) {
+ return *intersect.begin();
+ }
+ return "";
+}
+
+static std::string intersect(const std::set<std::string>& s1,
+ const std::set<std::string>& s2,
+ const std::set<std::string>& s3)
+{
+ std::string result;
+ result = intersect(s1, s2);
+ if (!result.empty()) {
+ return result;
+ }
+ result = intersect(s1, s3);
+ if (!result.empty()) {
+ return result;
+ }
+ return intersect(s2, s3);
+}
+
+static std::string intersect(const std::set<std::string>& s1,
+ const std::set<std::string>& s2,
+ const std::set<std::string>& s3,
+ const std::set<std::string>& s4)
+{
+ std::string result;
+ result = intersect(s1, s2);
+ if (!result.empty()) {
+ return result;
+ }
+ result = intersect(s1, s3);
+ if (!result.empty()) {
+ return result;
+ }
+ result = intersect(s1, s4);
+ if (!result.empty()) {
+ return result;
+ }
+ return intersect(s2, s3, s4);
+}
+
+void cmGeneratorTarget::CheckPropertyCompatibility(
+ cmComputeLinkInformation* info, const std::string& config) const
+{
+ const cmComputeLinkInformation::ItemVector& deps = info->GetItems();
+
+ std::set<std::string> emittedBools;
+ static std::string strBool = "COMPATIBLE_INTERFACE_BOOL";
+ std::set<std::string> emittedStrings;
+ static std::string strString = "COMPATIBLE_INTERFACE_STRING";
+ std::set<std::string> emittedMinNumbers;
+ static std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN";
+ std::set<std::string> emittedMaxNumbers;
+ static std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX";
+
+ for (cmComputeLinkInformation::ItemVector::const_iterator li = deps.begin();
+ li != deps.end(); ++li) {
+ if (!li->Target) {
+ continue;
+ }
+
+ checkPropertyConsistency<bool>(this, li->Target, strBool, emittedBools,
+ config, BoolType, CM_NULLPTR);
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+ checkPropertyConsistency<const char*>(this, li->Target, strString,
+ emittedStrings, config, StringType,
+ CM_NULLPTR);
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+ checkPropertyConsistency<const char*>(this, li->Target, strNumMin,
+ emittedMinNumbers, config,
+ NumberMinType, CM_NULLPTR);
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+ checkPropertyConsistency<const char*>(this, li->Target, strNumMax,
+ emittedMaxNumbers, config,
+ NumberMaxType, CM_NULLPTR);
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+ }
+
+ std::string prop = intersect(emittedBools, emittedStrings, emittedMinNumbers,
+ emittedMaxNumbers);
+
+ if (!prop.empty()) {
+ // Use a sorted std::vector to keep the error message sorted.
+ std::vector<std::string> props;
+ std::set<std::string>::const_iterator i = emittedBools.find(prop);
+ if (i != emittedBools.end()) {
+ props.push_back(strBool);
+ }
+ i = emittedStrings.find(prop);
+ if (i != emittedStrings.end()) {
+ props.push_back(strString);
+ }
+ i = emittedMinNumbers.find(prop);
+ if (i != emittedMinNumbers.end()) {
+ props.push_back(strNumMin);
+ }
+ i = emittedMaxNumbers.find(prop);
+ if (i != emittedMaxNumbers.end()) {
+ props.push_back(strNumMax);
+ }
+ std::sort(props.begin(), props.end());
+
+ std::string propsString = cmJoin(cmMakeRange(props).retreat(1), ", ");
+ propsString += " and the " + props.back();
+
+ std::ostringstream e;
+ e << "Property \"" << prop << "\" appears in both the " << propsString
+ << " property in the dependencies of target \"" << this->GetName()
+ << "\". This is not allowed. A property may only require compatibility "
+ "in a boolean interpretation, a numeric minimum, a numeric maximum "
+ "or a "
+ "string interpretation, but not a mixture.";
+ this->LocalGenerator->IssueMessage(cmake::FATAL_ERROR, e.str());
+ }
+}
+
+std::string compatibilityType(CompatibleType t)
+{
+ switch (t) {
+ case BoolType:
+ return "Boolean compatibility";
+ case StringType:
+ return "String compatibility";
+ case NumberMaxType:
+ return "Numeric maximum compatibility";
+ case NumberMinType:
+ return "Numeric minimum compatibility";
+ }
+ assert(0 && "Unreachable!");
+ return "";
+}
+
+std::string compatibilityAgree(CompatibleType t, bool dominant)
+{
+ switch (t) {
+ case BoolType:
+ case StringType:
+ return dominant ? "(Disagree)\n" : "(Agree)\n";
+ case NumberMaxType:
+ case NumberMinType:
+ return dominant ? "(Dominant)\n" : "(Ignored)\n";
+ }
+ assert(0 && "Unreachable!");
+ return "";
+}
+
+template <typename PropertyType>
+PropertyType getTypedProperty(cmGeneratorTarget const* tgt,
+ const std::string& prop);
+
+template <>
+bool getTypedProperty<bool>(cmGeneratorTarget const* tgt,
+ const std::string& prop)
+{
+ return tgt->GetPropertyAsBool(prop);
+}
+
+template <>
+const char* getTypedProperty<const char*>(cmGeneratorTarget const* tgt,
+ const std::string& prop)
+{
+ return tgt->GetProperty(prop);
+}
+
+template <typename PropertyType>
+std::string valueAsString(PropertyType);
+template <>
+std::string valueAsString<bool>(bool value)
+{
+ return value ? "TRUE" : "FALSE";
+}
+template <>
+std::string valueAsString<const char*>(const char* value)
+{
+ return value ? value : "(unset)";
+}
+
+template <typename PropertyType>
+PropertyType impliedValue(PropertyType);
+template <>
+bool impliedValue<bool>(bool)
+{
+ return false;
+}
+template <>
+const char* impliedValue<const char*>(const char*)
+{
+ return "";
+}
+
+template <typename PropertyType>
+std::pair<bool, PropertyType> consistentProperty(PropertyType lhs,
+ PropertyType rhs,
+ CompatibleType t);
+
+template <>
+std::pair<bool, bool> consistentProperty(bool lhs, bool rhs, CompatibleType)
+{
+ return std::make_pair(lhs == rhs, lhs);
+}
+
+std::pair<bool, const char*> consistentStringProperty(const char* lhs,
+ const char* rhs)
+{
+ const bool b = strcmp(lhs, rhs) == 0;
+ return std::make_pair(b, b ? lhs : CM_NULLPTR);
+}
+
+std::pair<bool, const char*> consistentNumberProperty(const char* lhs,
+ const char* rhs,
+ CompatibleType t)
+{
+ char* pEnd;
+
+ const char* const null_ptr = CM_NULLPTR;
+
+ long lnum = strtol(lhs, &pEnd, 0);
+ if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) {
+ return std::pair<bool, const char*>(false, null_ptr);
+ }
+
+ long rnum = strtol(rhs, &pEnd, 0);
+ if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) {
+ return std::pair<bool, const char*>(false, null_ptr);
+ }
+
+ if (t == NumberMaxType) {
+ return std::make_pair(true, std::max(lnum, rnum) == lnum ? lhs : rhs);
+ } else {
+ return std::make_pair(true, std::min(lnum, rnum) == lnum ? lhs : rhs);
+ }
+}
+
+template <>
+std::pair<bool, const char*> consistentProperty(const char* lhs,
+ const char* rhs,
+ CompatibleType t)
+{
+ if (!lhs && !rhs) {
+ return std::make_pair(true, lhs);
+ }
+ if (!lhs) {
+ return std::make_pair(true, rhs);
+ }
+ if (!rhs) {
+ return std::make_pair(true, lhs);
+ }
+
+ const char* const null_ptr = CM_NULLPTR;
+
+ switch (t) {
+ case BoolType:
+ assert(0 && "consistentProperty for strings called with BoolType");
+ return std::pair<bool, const char*>(false, null_ptr);
+ case StringType:
+ return consistentStringProperty(lhs, rhs);
+ case NumberMinType:
+ case NumberMaxType:
+ return consistentNumberProperty(lhs, rhs, t);
+ }
+ assert(0 && "Unreachable!");
+ return std::pair<bool, const char*>(false, null_ptr);
+}
+
+template <typename PropertyType>
+PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt,
+ const std::string& p,
+ const std::string& config,
+ const char* defaultValue,
+ CompatibleType t,
+ PropertyType*)
+{
+ PropertyType propContent = getTypedProperty<PropertyType>(tgt, p);
+ std::vector<std::string> headPropKeys = tgt->GetPropertyKeys();
+ const bool explicitlySet =
+ std::find(headPropKeys.begin(), headPropKeys.end(), p) !=
+ headPropKeys.end();
+
+ const bool impliedByUse = tgt->IsNullImpliedByLinkLibraries(p);
+ assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet));
+
+ std::vector<cmGeneratorTarget const*> const& deps =
+ tgt->GetLinkImplementationClosure(config);
+
+ if (deps.empty()) {
+ return propContent;
+ }
+ bool propInitialized = explicitlySet;
+
+ std::string report = " * Target \"";
+ report += tgt->GetName();
+ if (explicitlySet) {
+ report += "\" has property content \"";
+ report += valueAsString<PropertyType>(propContent);
+ report += "\"\n";
+ } else if (impliedByUse) {
+ report += "\" property is implied by use.\n";
+ } else {
+ report += "\" property not set.\n";
+ }
+
+ std::string interfaceProperty = "INTERFACE_" + p;
+ for (std::vector<cmGeneratorTarget const*>::const_iterator li = deps.begin();
+ li != deps.end(); ++li) {
+ // An error should be reported if one dependency
+ // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
+ // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
+ // target itself has a POSITION_INDEPENDENT_CODE which disagrees
+ // with a dependency.
+
+ cmGeneratorTarget const* theTarget = *li;
+
+ std::vector<std::string> propKeys = theTarget->GetPropertyKeys();
+
+ const bool ifaceIsSet = std::find(propKeys.begin(), propKeys.end(),
+ interfaceProperty) != propKeys.end();
+ PropertyType ifacePropContent =
+ getTypedProperty<PropertyType>(theTarget, interfaceProperty);
+
+ std::string reportEntry;
+ if (ifaceIsSet) {
+ reportEntry += " * Target \"";
+ reportEntry += theTarget->GetName();
+ reportEntry += "\" property value \"";
+ reportEntry += valueAsString<PropertyType>(ifacePropContent);
+ reportEntry += "\" ";
+ }
+
+ if (explicitlySet) {
+ if (ifaceIsSet) {
+ std::pair<bool, PropertyType> consistent =
+ consistentProperty(propContent, ifacePropContent, t);
+ report += reportEntry;
+ report += compatibilityAgree(t, propContent != consistent.second);
+ if (!consistent.first) {
+ std::ostringstream e;
+ e << "Property " << p << " on target \"" << tgt->GetName()
+ << "\" does\nnot match the "
+ "INTERFACE_"
+ << p << " property requirement\nof "
+ "dependency \""
+ << theTarget->GetName() << "\".\n";
+ cmSystemTools::Error(e.str().c_str());
+ break;
+ } else {
+ propContent = consistent.second;
+ continue;
+ }
+ } else {
+ // Explicitly set on target and not set in iface. Can't disagree.
+ continue;
+ }
+ } else if (impliedByUse) {
+ propContent = impliedValue<PropertyType>(propContent);
+
+ if (ifaceIsSet) {
+ std::pair<bool, PropertyType> consistent =
+ consistentProperty(propContent, ifacePropContent, t);
+ report += reportEntry;
+ report += compatibilityAgree(t, propContent != consistent.second);
+ if (!consistent.first) {
+ std::ostringstream e;
+ e << "Property " << p << " on target \"" << tgt->GetName()
+ << "\" is\nimplied to be " << defaultValue
+ << " because it was used to determine the link libraries\n"
+ "already. The INTERFACE_"
+ << p << " property on\ndependency \"" << theTarget->GetName()
+ << "\" is in conflict.\n";
+ cmSystemTools::Error(e.str().c_str());
+ break;
+ } else {
+ propContent = consistent.second;
+ continue;
+ }
+ } else {
+ // Implicitly set on target and not set in iface. Can't disagree.
+ continue;
+ }
+ } else {
+ if (ifaceIsSet) {
+ if (propInitialized) {
+ std::pair<bool, PropertyType> consistent =
+ consistentProperty(propContent, ifacePropContent, t);
+ report += reportEntry;
+ report += compatibilityAgree(t, propContent != consistent.second);
+ if (!consistent.first) {
+ std::ostringstream e;
+ e << "The INTERFACE_" << p << " property of \""
+ << theTarget->GetName() << "\" does\nnot agree with the value "
+ "of "
+ << p << " already determined\nfor \"" << tgt->GetName()
+ << "\".\n";
+ cmSystemTools::Error(e.str().c_str());
+ break;
+ } else {
+ propContent = consistent.second;
+ continue;
+ }
+ } else {
+ report += reportEntry + "(Interface set)\n";
+ propContent = ifacePropContent;
+ propInitialized = true;
+ }
+ } else {
+ // Not set. Nothing to agree on.
+ continue;
+ }
+ }
+ }
+
+ tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent),
+ report, compatibilityType(t));
+ return propContent;
+}
+
+bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty(
+ const std::string& p, const std::string& config) const
+{
+ return checkInterfacePropertyCompatibility<bool>(this, p, config, "FALSE",
+ BoolType, CM_NULLPTR);
+}
+
+const char* cmGeneratorTarget::GetLinkInterfaceDependentStringProperty(
+ const std::string& p, const std::string& config) const
+{
+ return checkInterfacePropertyCompatibility<const char*>(
+ this, p, config, "empty", StringType, CM_NULLPTR);
+}
+
+const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMinProperty(
+ const std::string& p, const std::string& config) const
+{
+ return checkInterfacePropertyCompatibility<const char*>(
+ this, p, config, "empty", NumberMinType, CM_NULLPTR);
+}
+
+const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMaxProperty(
+ const std::string& p, const std::string& config) const
+{
+ return checkInterfacePropertyCompatibility<const char*>(
+ this, p, config, "empty", NumberMaxType, CM_NULLPTR);
+}
+
+cmComputeLinkInformation* cmGeneratorTarget::GetLinkInformation(
+ const std::string& config) const
+{
+ // Lookup any existing information for this configuration.
+ std::string key(cmSystemTools::UpperCase(config));
+ cmTargetLinkInformationMap::iterator i = this->LinkInformation.find(key);
+ if (i == this->LinkInformation.end()) {
+ // Compute information for this configuration.
+ cmComputeLinkInformation* info =
+ new cmComputeLinkInformation(this, config);
+ if (!info || !info->Compute()) {
+ delete info;
+ info = CM_NULLPTR;
+ }
+
+ // Store the information for this configuration.
+ cmTargetLinkInformationMap::value_type entry(key, info);
+ i = this->LinkInformation.insert(entry).first;
+
+ if (info) {
+ this->CheckPropertyCompatibility(info, config);
+ }
+ }
+ return i->second;
+}
+
+void cmGeneratorTarget::GetTargetVersion(int& major, int& minor) const
+{
+ int patch;
+ this->GetTargetVersion(false, major, minor, patch);
+}
+
+void cmGeneratorTarget::GetTargetVersion(bool soversion, int& major,
+ int& minor, int& patch) const
+{
+ // Set the default values.
+ major = 0;
+ minor = 0;
+ patch = 0;
+
+ assert(this->GetType() != cmState::INTERFACE_LIBRARY);
+
+ // Look for a VERSION or SOVERSION property.
+ const char* prop = soversion ? "SOVERSION" : "VERSION";
+ if (const char* version = this->GetProperty(prop)) {
+ // Try to parse the version number and store the results that were
+ // successfully parsed.
+ int parsed_major;
+ int parsed_minor;
+ int parsed_patch;
+ switch (sscanf(version, "%d.%d.%d", &parsed_major, &parsed_minor,
+ &parsed_patch)) {
+ case 3:
+ patch = parsed_patch; // no break!
+ case 2:
+ minor = parsed_minor; // no break!
+ case 1:
+ major = parsed_major; // no break!
+ default:
+ break;
+ }
+ }
+}
+
+std::string cmGeneratorTarget::GetFortranModuleDirectory() const
+{
+ if (!this->FortranModuleDirectoryCreated) {
+ this->FortranModuleDirectory = true;
+ this->FortranModuleDirectory = this->CreateFortranModuleDirectory();
+ }
+
+ return this->FortranModuleDirectory;
+}
+
+std::string cmGeneratorTarget::CreateFortranModuleDirectory() const
+{
+ std::string mod_dir;
+ const char* target_mod_dir = this->GetProperty("Fortran_MODULE_DIRECTORY");
+ const char* moddir_flag =
+ this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG");
+ if (target_mod_dir && moddir_flag) {
+ // Compute the full path to the module directory.
+ if (cmSystemTools::FileIsFullPath(target_mod_dir)) {
+ // Already a full path.
+ mod_dir = target_mod_dir;
+ } else {
+ // Interpret relative to the current output directory.
+ mod_dir = this->LocalGenerator->GetCurrentBinaryDirectory();
+ mod_dir += "/";
+ mod_dir += target_mod_dir;
+ }
+
+ // Make sure the module output directory exists.
+ cmSystemTools::MakeDirectory(mod_dir);
+ }
+ return mod_dir;
+}
+
+std::string cmGeneratorTarget::GetFrameworkVersion() const
+{
+ assert(this->GetType() != cmState::INTERFACE_LIBRARY);
+
+ if (const char* fversion = this->GetProperty("FRAMEWORK_VERSION")) {
+ return fversion;
+ } else if (const char* tversion = this->GetProperty("VERSION")) {
+ return tversion;
+ } else {
+ return "A";
+ }
+}
+
+void cmGeneratorTarget::ComputeVersionedName(std::string& vName,
+ std::string const& prefix,
+ std::string const& base,
+ std::string const& suffix,
+ std::string const& name,
+ const char* version) const
+{
+ vName = this->Makefile->IsOn("APPLE") ? (prefix + base) : name;
+ if (version) {
+ vName += ".";
+ vName += version;
+ }
+ vName += this->Makefile->IsOn("APPLE") ? suffix : std::string();
+}
+
+std::vector<std::string> cmGeneratorTarget::GetPropertyKeys() const
+{
+ cmPropertyMap propsObject = this->Target->GetProperties();
+ std::vector<std::string> props;
+ props.reserve(propsObject.size());
+ for (cmPropertyMap::const_iterator it = propsObject.begin();
+ it != propsObject.end(); ++it) {
+ props.push_back(it->first);
+ }
+ return props;
+}
+
+void cmGeneratorTarget::ReportPropertyOrigin(
+ const std::string& p, const std::string& result, const std::string& report,
+ const std::string& compatibilityType) const
+{
+ std::vector<std::string> debugProperties;
+ const char* debugProp = this->Target->GetMakefile()->GetDefinition(
+ "CMAKE_DEBUG_TARGET_PROPERTIES");
+ if (debugProp) {
+ cmSystemTools::ExpandListArgument(debugProp, debugProperties);
+ }
+
+ bool debugOrigin = !this->DebugCompatiblePropertiesDone[p] &&
+ std::find(debugProperties.begin(), debugProperties.end(), p) !=
+ debugProperties.end();
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugCompatiblePropertiesDone[p] = true;
+ }
+ if (!debugOrigin) {
+ return;
+ }
+
+ std::string areport = compatibilityType;
+ areport += std::string(" of property \"") + p + "\" for target \"";
+ areport += std::string(this->GetName());
+ areport += "\" (result: \"";
+ areport += result;
+ areport += "\"):\n" + report;
+
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(cmake::LOG, areport);
+}
+
+void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names,
+ std::vector<cmLinkItem>& items) const
+{
+ for (std::vector<std::string>::const_iterator i = names.begin();
+ i != names.end(); ++i) {
+ std::string name = this->CheckCMP0004(*i);
+ if (name == this->GetName() || name.empty()) {
+ continue;
+ }
+ items.push_back(cmLinkItem(name, this->FindTargetToLink(name)));
+ }
+}
+
+void cmGeneratorTarget::ExpandLinkItems(
+ std::string const& prop, std::string const& value, std::string const& config,
+ cmGeneratorTarget const* headTarget, bool usage_requirements_only,
+ std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition) const
+{
+ cmGeneratorExpression ge;
+ cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), prop, CM_NULLPTR,
+ CM_NULLPTR);
+ // The $<LINK_ONLY> expression may be in a link interface to specify private
+ // link dependencies that are otherwise excluded from usage requirements.
+ if (usage_requirements_only) {
+ dagChecker.SetTransitivePropertiesOnly();
+ }
+ std::vector<std::string> libs;
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(value);
+ cmSystemTools::ExpandListArgument(cge->Evaluate(this->LocalGenerator, config,
+ false, headTarget, this,
+ &dagChecker),
+ libs);
+ this->LookupLinkItems(libs, items);
+ hadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition();
+}
+
+cmLinkInterface const* cmGeneratorTarget::GetLinkInterface(
+ const std::string& config, cmGeneratorTarget const* head) const
+{
+ // Imported targets have their own link interface.
+ if (this->IsImported()) {
+ return this->GetImportLinkInterface(config, head, false);
+ }
+
+ // Link interfaces are not supported for executables that do not
+ // export symbols.
+ if (this->GetType() == cmState::EXECUTABLE &&
+ !this->IsExecutableWithExports()) {
+ return CM_NULLPTR;
+ }
+
+ // Lookup any existing link interface for this configuration.
+ cmHeadToLinkInterfaceMap& hm = this->GetHeadToLinkInterfaceMap(config);
+
+ // If the link interface does not depend on the head target
+ // then return the one we computed first.
+ if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
+ return &hm.begin()->second;
+ }
+
+ cmOptionalLinkInterface& iface = hm[head];
+ if (!iface.LibrariesDone) {
+ iface.LibrariesDone = true;
+ this->ComputeLinkInterfaceLibraries(config, iface, head, false);
+ }
+ if (!iface.AllDone) {
+ iface.AllDone = true;
+ if (iface.Exists) {
+ this->ComputeLinkInterface(config, iface, head);
+ }
+ }
+
+ return iface.Exists ? &iface : CM_NULLPTR;
+}
+
+void cmGeneratorTarget::ComputeLinkInterface(
+ const std::string& config, cmOptionalLinkInterface& iface,
+ cmGeneratorTarget const* headTarget) const
+{
+ if (iface.ExplicitLibraries) {
+ if (this->GetType() == cmState::SHARED_LIBRARY ||
+ this->GetType() == cmState::STATIC_LIBRARY ||
+ this->GetType() == cmState::INTERFACE_LIBRARY) {
+ // Shared libraries may have runtime implementation dependencies
+ // on other shared libraries that are not in the interface.
+ UNORDERED_SET<std::string> emitted;
+ for (std::vector<cmLinkItem>::const_iterator li =
+ iface.Libraries.begin();
+ li != iface.Libraries.end(); ++li) {
+ emitted.insert(*li);
+ }
+ if (this->GetType() != cmState::INTERFACE_LIBRARY) {
+ cmLinkImplementation const* impl = this->GetLinkImplementation(config);
+ for (std::vector<cmLinkImplItem>::const_iterator li =
+ impl->Libraries.begin();
+ li != impl->Libraries.end(); ++li) {
+ if (emitted.insert(*li).second) {
+ if (li->Target) {
+ // This is a runtime dependency on another shared library.
+ if (li->Target->GetType() == cmState::SHARED_LIBRARY) {
+ iface.SharedDeps.push_back(*li);
+ }
+ } else {
+ // TODO: Recognize shared library file names. Perhaps this
+ // should be moved to cmComputeLinkInformation, but that creates
+ // a chicken-and-egg problem since this list is needed for its
+ // construction.
+ }
+ }
+ }
+ }
+ }
+ } else if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN ||
+ this->GetPolicyStatusCMP0022() == cmPolicies::OLD) {
+ // The link implementation is the default link interface.
+ cmLinkImplementationLibraries const* impl =
+ this->GetLinkImplementationLibrariesInternal(config, headTarget);
+ iface.ImplementationIsInterface = true;
+ iface.WrongConfigLibraries = impl->WrongConfigLibraries;
+ }
+
+ if (this->LinkLanguagePropagatesToDependents()) {
+ // Targets using this archive need its language runtime libraries.
+ if (cmLinkImplementation const* impl =
+ this->GetLinkImplementation(config)) {
+ iface.Languages = impl->Languages;
+ }
+ }
+
+ if (this->GetType() == cmState::STATIC_LIBRARY) {
+ // Construct the property name suffix for this configuration.
+ std::string suffix = "_";
+ if (!config.empty()) {
+ suffix += cmSystemTools::UpperCase(config);
+ } else {
+ suffix += "NOCONFIG";
+ }
+
+ // How many repetitions are needed if this library has cyclic
+ // dependencies?
+ std::string propName = "LINK_INTERFACE_MULTIPLICITY";
+ propName += suffix;
+ if (const char* config_reps = this->GetProperty(propName)) {
+ sscanf(config_reps, "%u", &iface.Multiplicity);
+ } else if (const char* reps =
+ this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) {
+ sscanf(reps, "%u", &iface.Multiplicity);
+ }
+ }
+}
+
+const cmLinkInterfaceLibraries* cmGeneratorTarget::GetLinkInterfaceLibraries(
+ const std::string& config, cmGeneratorTarget const* head,
+ bool usage_requirements_only) const
+{
+ // Imported targets have their own link interface.
+ if (this->IsImported()) {
+ return this->GetImportLinkInterface(config, head, usage_requirements_only);
+ }
+
+ // Link interfaces are not supported for executables that do not
+ // export symbols.
+ if (this->GetType() == cmState::EXECUTABLE &&
+ !this->IsExecutableWithExports()) {
+ return CM_NULLPTR;
+ }
+
+ // Lookup any existing link interface for this configuration.
+ std::string CONFIG = cmSystemTools::UpperCase(config);
+ cmHeadToLinkInterfaceMap& hm =
+ (usage_requirements_only
+ ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config)
+ : this->GetHeadToLinkInterfaceMap(config));
+
+ // If the link interface does not depend on the head target
+ // then return the one we computed first.
+ if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
+ return &hm.begin()->second;
+ }
+
+ cmOptionalLinkInterface& iface = hm[head];
+ if (!iface.LibrariesDone) {
+ iface.LibrariesDone = true;
+ this->ComputeLinkInterfaceLibraries(config, iface, head,
+ usage_requirements_only);
+ }
+
+ return iface.Exists ? &iface : CM_NULLPTR;
+}
+
+std::string cmGeneratorTarget::GetDirectory(const std::string& config,
+ bool implib) const
+{
+ if (this->IsImported()) {
+ // Return the directory from which the target is imported.
+ return cmSystemTools::GetFilenamePath(
+ this->Target->ImportedGetFullPath(config, implib));
+ } else if (OutputInfo const* info = this->GetOutputInfo(config)) {
+ // Return the directory in which the target will be built.
+ return implib ? info->ImpDir : info->OutDir;
+ }
+ return "";
+}
+
+bool cmGeneratorTarget::UsesDefaultOutputDir(const std::string& config,
+ bool implib) const
+{
+ std::string dir;
+ return this->ComputeOutputDir(config, implib, dir);
+}
+
+cmGeneratorTarget::OutputInfo const* cmGeneratorTarget::GetOutputInfo(
+ const std::string& config) const
+{
+ // There is no output information for imported targets.
+ if (this->IsImported()) {
+ return CM_NULLPTR;
+ }
+
+ // Only libraries and executables have well-defined output files.
+ if (!this->HaveWellDefinedOutputFiles()) {
+ std::string msg = "cmGeneratorTarget::GetOutputInfo called for ";
+ msg += this->GetName();
+ msg += " which has type ";
+ msg += cmState::GetTargetTypeName(this->GetType());
+ this->LocalGenerator->IssueMessage(cmake::INTERNAL_ERROR, msg);
+ return CM_NULLPTR;
+ }
+
+ // Lookup/compute/cache the output information for this configuration.
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+ OutputInfoMapType::iterator i = this->OutputInfoMap.find(config_upper);
+ if (i == this->OutputInfoMap.end()) {
+ // Add empty info in map to detect potential recursion.
+ OutputInfo info;
+ OutputInfoMapType::value_type entry(config_upper, info);
+ i = this->OutputInfoMap.insert(entry).first;
+
+ // Compute output directories.
+ this->ComputeOutputDir(config, false, info.OutDir);
+ this->ComputeOutputDir(config, true, info.ImpDir);
+ if (!this->ComputePDBOutputDir("PDB", config, info.PdbDir)) {
+ info.PdbDir = info.OutDir;
+ }
+
+ // Now update the previously-prepared map entry.
+ i->second = info;
+ } else if (i->second.empty()) {
+ // An empty map entry indicates we have been called recursively
+ // from the above block.
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(
+ cmake::FATAL_ERROR,
+ "Target '" + this->GetName() + "' OUTPUT_DIRECTORY depends on itself.",
+ this->GetBacktrace());
+ return CM_NULLPTR;
+ }
+ return &i->second;
+}
+
+bool cmGeneratorTarget::ComputeOutputDir(const std::string& config,
+ bool implib, std::string& out) const
+{
+ bool usesDefaultOutputDir = false;
+ std::string conf = config;
+
+ // Look for a target property defining the target output directory
+ // based on the target type.
+ std::string targetTypeName = this->GetOutputTargetType(implib);
+ const char* propertyName = CM_NULLPTR;
+ std::string propertyNameStr = targetTypeName;
+ if (!propertyNameStr.empty()) {
+ propertyNameStr += "_OUTPUT_DIRECTORY";
+ propertyName = propertyNameStr.c_str();
+ }
+
+ // Check for a per-configuration output directory target property.
+ std::string configUpper = cmSystemTools::UpperCase(conf);
+ const char* configProp = CM_NULLPTR;
+ std::string configPropStr = targetTypeName;
+ if (!configPropStr.empty()) {
+ configPropStr += "_OUTPUT_DIRECTORY_";
+ configPropStr += configUpper;
+ configProp = configPropStr.c_str();
+ }
+
+ // Select an output directory.
+ if (const char* config_outdir = this->GetProperty(configProp)) {
+ // Use the user-specified per-configuration output directory.
+ cmGeneratorExpression ge;
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(config_outdir);
+ out = cge->Evaluate(this->LocalGenerator, config);
+
+ // Skip per-configuration subdirectory.
+ conf = "";
+ } else if (const char* outdir = this->GetProperty(propertyName)) {
+ // Use the user-specified output directory.
+ cmGeneratorExpression ge;
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(outdir);
+ out = cge->Evaluate(this->LocalGenerator, config);
+
+ // Skip per-configuration subdirectory if the value contained a
+ // generator expression.
+ if (out != outdir) {
+ conf = "";
+ }
+ } else if (this->GetType() == cmState::EXECUTABLE) {
+ // Lookup the output path for executables.
+ out = this->Makefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
+ } else if (this->GetType() == cmState::STATIC_LIBRARY ||
+ this->GetType() == cmState::SHARED_LIBRARY ||
+ this->GetType() == cmState::MODULE_LIBRARY) {
+ // Lookup the output path for libraries.
+ out = this->Makefile->GetSafeDefinition("LIBRARY_OUTPUT_PATH");
+ }
+ if (out.empty()) {
+ // Default to the current output directory.
+ usesDefaultOutputDir = true;
+ out = ".";
+ }
+
+ // Convert the output path to a full path in case it is
+ // specified as a relative path. Treat a relative path as
+ // relative to the current output directory for this makefile.
+ out = (cmSystemTools::CollapseFullPath(
+ out, this->LocalGenerator->GetCurrentBinaryDirectory()));
+
+ // The generator may add the configuration's subdirectory.
+ if (!conf.empty()) {
+ bool iosPlatform = this->Makefile->PlatformIsAppleIos();
+ std::string suffix =
+ usesDefaultOutputDir && iosPlatform ? "${EFFECTIVE_PLATFORM_NAME}" : "";
+ this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
+ "/", conf, suffix, out);
+ }
+
+ return usesDefaultOutputDir;
+}
+
+bool cmGeneratorTarget::ComputePDBOutputDir(const std::string& kind,
+ const std::string& config,
+ std::string& out) const
+{
+ // Look for a target property defining the target output directory
+ // based on the target type.
+ const char* propertyName = CM_NULLPTR;
+ std::string propertyNameStr = kind;
+ if (!propertyNameStr.empty()) {
+ propertyNameStr += "_OUTPUT_DIRECTORY";
+ propertyName = propertyNameStr.c_str();
+ }
+ std::string conf = config;
+
+ // Check for a per-configuration output directory target property.
+ std::string configUpper = cmSystemTools::UpperCase(conf);
+ const char* configProp = CM_NULLPTR;
+ std::string configPropStr = kind;
+ if (!configPropStr.empty()) {
+ configPropStr += "_OUTPUT_DIRECTORY_";
+ configPropStr += configUpper;
+ configProp = configPropStr.c_str();
+ }
+
+ // Select an output directory.
+ if (const char* config_outdir = this->GetProperty(configProp)) {
+ // Use the user-specified per-configuration output directory.
+ out = config_outdir;
+
+ // Skip per-configuration subdirectory.
+ conf = "";
+ } else if (const char* outdir = this->GetProperty(propertyName)) {
+ // Use the user-specified output directory.
+ out = outdir;
+ }
+ if (out.empty()) {
+ return false;
+ }
+
+ // Convert the output path to a full path in case it is
+ // specified as a relative path. Treat a relative path as
+ // relative to the current output directory for this makefile.
+ out = (cmSystemTools::CollapseFullPath(
+ out, this->LocalGenerator->GetCurrentBinaryDirectory()));
+
+ // The generator may add the configuration's subdirectory.
+ if (!conf.empty()) {
+ this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
+ "/", conf, "", out);
+ }
+ return true;
+}
+
+bool cmGeneratorTarget::HaveInstallTreeRPATH() const
+{
+ const char* install_rpath = this->GetProperty("INSTALL_RPATH");
+ return (install_rpath && *install_rpath) &&
+ !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH");
+}
+
+void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
+ const std::string& config, cmOptionalLinkInterface& iface,
+ cmGeneratorTarget const* headTarget, bool usage_requirements_only) const
+{
+ // Construct the property name suffix for this configuration.
+ std::string suffix = "_";
+ if (!config.empty()) {
+ suffix += cmSystemTools::UpperCase(config);
+ } else {
+ suffix += "NOCONFIG";
+ }
+
+ // An explicit list of interface libraries may be set for shared
+ // libraries and executables that export symbols.
+ const char* explicitLibraries = CM_NULLPTR;
+ std::string linkIfaceProp;
+ if (this->GetPolicyStatusCMP0022() != cmPolicies::OLD &&
+ this->GetPolicyStatusCMP0022() != cmPolicies::WARN) {
+ // CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES.
+ linkIfaceProp = "INTERFACE_LINK_LIBRARIES";
+ explicitLibraries = this->GetProperty(linkIfaceProp);
+ } else if (this->GetType() == cmState::SHARED_LIBRARY ||
+ this->IsExecutableWithExports()) {
+ // CMP0022 OLD behavior is to use LINK_INTERFACE_LIBRARIES if set on a
+ // shared lib or executable.
+
+ // Lookup the per-configuration property.
+ linkIfaceProp = "LINK_INTERFACE_LIBRARIES";
+ linkIfaceProp += suffix;
+ explicitLibraries = this->GetProperty(linkIfaceProp);
+
+ // If not set, try the generic property.
+ if (!explicitLibraries) {
+ linkIfaceProp = "LINK_INTERFACE_LIBRARIES";
+ explicitLibraries = this->GetProperty(linkIfaceProp);
+ }
+ }
+
+ if (explicitLibraries &&
+ this->GetPolicyStatusCMP0022() == cmPolicies::WARN &&
+ !this->PolicyWarnedCMP0022) {
+ // Compare the explicitly set old link interface properties to the
+ // preferred new link interface property one and warn if different.
+ const char* newExplicitLibraries =
+ this->GetProperty("INTERFACE_LINK_LIBRARIES");
+ if (newExplicitLibraries &&
+ strcmp(newExplicitLibraries, explicitLibraries) != 0) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n"
+ "Target \"" << this->GetName() << "\" has an "
+ "INTERFACE_LINK_LIBRARIES property which differs from its " <<
+ linkIfaceProp << " properties."
+ "\n"
+ "INTERFACE_LINK_LIBRARIES:\n"
+ " " << newExplicitLibraries << "\n" <<
+ linkIfaceProp << ":\n"
+ " " << (explicitLibraries ? explicitLibraries : "(empty)") << "\n";
+ /* clang-format on */
+ this->LocalGenerator->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ this->PolicyWarnedCMP0022 = true;
+ }
+ }
+
+ // There is no implicit link interface for executables or modules
+ // so if none was explicitly set then there is no link interface.
+ if (!explicitLibraries && (this->GetType() == cmState::EXECUTABLE ||
+ (this->GetType() == cmState::MODULE_LIBRARY))) {
+ return;
+ }
+ iface.Exists = true;
+ iface.ExplicitLibraries = explicitLibraries;
+
+ if (explicitLibraries) {
+ // The interface libraries have been explicitly set.
+ this->ExpandLinkItems(linkIfaceProp, explicitLibraries, config, headTarget,
+ usage_requirements_only, iface.Libraries,
+ iface.HadHeadSensitiveCondition);
+ } else if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN ||
+ this->GetPolicyStatusCMP0022() == cmPolicies::OLD)
+ // If CMP0022 is NEW then the plain tll signature sets the
+ // INTERFACE_LINK_LIBRARIES, so if we get here then the project
+ // cleared the property explicitly and we should not fall back
+ // to the link implementation.
+ {
+ // The link implementation is the default link interface.
+ cmLinkImplementationLibraries const* impl =
+ this->GetLinkImplementationLibrariesInternal(config, headTarget);
+ iface.Libraries.insert(iface.Libraries.end(), impl->Libraries.begin(),
+ impl->Libraries.end());
+ if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN &&
+ !this->PolicyWarnedCMP0022 && !usage_requirements_only) {
+ // Compare the link implementation fallback link interface to the
+ // preferred new link interface property and warn if different.
+ std::vector<cmLinkItem> ifaceLibs;
+ static const std::string newProp = "INTERFACE_LINK_LIBRARIES";
+ if (const char* newExplicitLibraries = this->GetProperty(newProp)) {
+ bool hadHeadSensitiveConditionDummy = false;
+ this->ExpandLinkItems(newProp, newExplicitLibraries, config,
+ headTarget, usage_requirements_only, ifaceLibs,
+ hadHeadSensitiveConditionDummy);
+ }
+ if (ifaceLibs != iface.Libraries) {
+ std::string oldLibraries = cmJoin(impl->Libraries, ";");
+ std::string newLibraries = cmJoin(ifaceLibs, ";");
+ if (oldLibraries.empty()) {
+ oldLibraries = "(empty)";
+ }
+ if (newLibraries.empty()) {
+ newLibraries = "(empty)";
+ }
+
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n"
+ "Target \"" << this->GetName() << "\" has an "
+ "INTERFACE_LINK_LIBRARIES property. "
+ "This should be preferred as the source of the link interface "
+ "for this library but because CMP0022 is not set CMake is "
+ "ignoring the property and using the link implementation "
+ "as the link interface instead."
+ "\n"
+ "INTERFACE_LINK_LIBRARIES:\n"
+ " " << newLibraries << "\n"
+ "Link implementation:\n"
+ " " << oldLibraries << "\n";
+ /* clang-format on */
+ this->LocalGenerator->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ this->PolicyWarnedCMP0022 = true;
+ }
+ }
+ }
+}
+
+const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface(
+ const std::string& config, cmGeneratorTarget const* headTarget,
+ bool usage_requirements_only) const
+{
+ cmGeneratorTarget::ImportInfo const* info = this->GetImportInfo(config);
+ if (!info) {
+ return CM_NULLPTR;
+ }
+
+ std::string CONFIG = cmSystemTools::UpperCase(config);
+ cmHeadToLinkInterfaceMap& hm =
+ (usage_requirements_only
+ ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config)
+ : this->GetHeadToLinkInterfaceMap(config));
+
+ // If the link interface does not depend on the head target
+ // then return the one we computed first.
+ if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
+ return &hm.begin()->second;
+ }
+
+ cmOptionalLinkInterface& iface = hm[headTarget];
+ if (!iface.AllDone) {
+ iface.AllDone = true;
+ iface.Multiplicity = info->Multiplicity;
+ cmSystemTools::ExpandListArgument(info->Languages, iface.Languages);
+ this->ExpandLinkItems(info->LibrariesProp, info->Libraries, config,
+ headTarget, usage_requirements_only, iface.Libraries,
+ iface.HadHeadSensitiveCondition);
+ std::vector<std::string> deps;
+ cmSystemTools::ExpandListArgument(info->SharedDeps, deps);
+ this->LookupLinkItems(deps, iface.SharedDeps);
+ }
+
+ return &iface;
+}
+
+cmGeneratorTarget::ImportInfo const* cmGeneratorTarget::GetImportInfo(
+ const std::string& config) const
+{
+ // There is no imported information for non-imported targets.
+ if (!this->IsImported()) {
+ return CM_NULLPTR;
+ }
+
+ // Lookup/compute/cache the import information for this
+ // configuration.
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ } else {
+ config_upper = "NOCONFIG";
+ }
+
+ ImportInfoMapType::const_iterator i = this->ImportInfoMap.find(config_upper);
+ if (i == this->ImportInfoMap.end()) {
+ ImportInfo info;
+ this->ComputeImportInfo(config_upper, info);
+ ImportInfoMapType::value_type entry(config_upper, info);
+ i = this->ImportInfoMap.insert(entry).first;
+ }
+
+ if (this->GetType() == cmState::INTERFACE_LIBRARY) {
+ return &i->second;
+ }
+ // If the location is empty then the target is not available for
+ // this configuration.
+ if (i->second.Location.empty() && i->second.ImportLibrary.empty()) {
+ return CM_NULLPTR;
+ }
+
+ // Return the import information.
+ return &i->second;
+}
+
+void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
+ ImportInfo& info) const
+{
+ // This method finds information about an imported target from its
+ // properties. The "IMPORTED_" namespace is reserved for properties
+ // defined by the project exporting the target.
+
+ // Initialize members.
+ info.NoSOName = false;
+
+ const char* loc = CM_NULLPTR;
+ const char* imp = CM_NULLPTR;
+ std::string suffix;
+ if (!this->Target->GetMappedConfig(desired_config, &loc, &imp, suffix)) {
+ return;
+ }
+
+ // Get the link interface.
+ {
+ std::string linkProp = "INTERFACE_LINK_LIBRARIES";
+ const char* propertyLibs = this->GetProperty(linkProp);
+
+ if (this->GetType() != cmState::INTERFACE_LIBRARY) {
+ if (!propertyLibs) {
+ linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
+ linkProp += suffix;
+ propertyLibs = this->GetProperty(linkProp);
+ }
+
+ if (!propertyLibs) {
+ linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
+ propertyLibs = this->GetProperty(linkProp);
+ }
+ }
+ if (propertyLibs) {
+ info.LibrariesProp = linkProp;
+ info.Libraries = propertyLibs;
+ }
+ }
+ if (this->GetType() == cmState::INTERFACE_LIBRARY) {
+ return;
+ }
+
+ // A provided configuration has been chosen. Load the
+ // configuration's properties.
+
+ // Get the location.
+ if (loc) {
+ info.Location = loc;
+ } else {
+ std::string impProp = "IMPORTED_LOCATION";
+ impProp += suffix;
+ if (const char* config_location = this->GetProperty(impProp)) {
+ info.Location = config_location;
+ } else if (const char* location = this->GetProperty("IMPORTED_LOCATION")) {
+ info.Location = location;
+ }
+ }
+
+ // Get the soname.
+ if (this->GetType() == cmState::SHARED_LIBRARY) {
+ std::string soProp = "IMPORTED_SONAME";
+ soProp += suffix;
+ if (const char* config_soname = this->GetProperty(soProp)) {
+ info.SOName = config_soname;
+ } else if (const char* soname = this->GetProperty("IMPORTED_SONAME")) {
+ info.SOName = soname;
+ }
+ }
+
+ // Get the "no-soname" mark.
+ if (this->GetType() == cmState::SHARED_LIBRARY) {
+ std::string soProp = "IMPORTED_NO_SONAME";
+ soProp += suffix;
+ if (const char* config_no_soname = this->GetProperty(soProp)) {
+ info.NoSOName = cmSystemTools::IsOn(config_no_soname);
+ } else if (const char* no_soname =
+ this->GetProperty("IMPORTED_NO_SONAME")) {
+ info.NoSOName = cmSystemTools::IsOn(no_soname);
+ }
+ }
+
+ // Get the import library.
+ if (imp) {
+ info.ImportLibrary = imp;
+ } else if (this->GetType() == cmState::SHARED_LIBRARY ||
+ this->IsExecutableWithExports()) {
+ std::string impProp = "IMPORTED_IMPLIB";
+ impProp += suffix;
+ if (const char* config_implib = this->GetProperty(impProp)) {
+ info.ImportLibrary = config_implib;
+ } else if (const char* implib = this->GetProperty("IMPORTED_IMPLIB")) {
+ info.ImportLibrary = implib;
+ }
+ }
+
+ // Get the link dependencies.
+ {
+ std::string linkProp = "IMPORTED_LINK_DEPENDENT_LIBRARIES";
+ linkProp += suffix;
+ if (const char* config_libs = this->GetProperty(linkProp)) {
+ info.SharedDeps = config_libs;
+ } else if (const char* libs =
+ this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES")) {
+ info.SharedDeps = libs;
+ }
+ }
+
+ // Get the link languages.
+ if (this->LinkLanguagePropagatesToDependents()) {
+ std::string linkProp = "IMPORTED_LINK_INTERFACE_LANGUAGES";
+ linkProp += suffix;
+ if (const char* config_libs = this->GetProperty(linkProp)) {
+ info.Languages = config_libs;
+ } else if (const char* libs =
+ this->GetProperty("IMPORTED_LINK_INTERFACE_LANGUAGES")) {
+ info.Languages = libs;
+ }
+ }
+
+ // Get the cyclic repetition count.
+ if (this->GetType() == cmState::STATIC_LIBRARY) {
+ std::string linkProp = "IMPORTED_LINK_INTERFACE_MULTIPLICITY";
+ linkProp += suffix;
+ if (const char* config_reps = this->GetProperty(linkProp)) {
+ sscanf(config_reps, "%u", &info.Multiplicity);
+ } else if (const char* reps =
+ this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY")) {
+ sscanf(reps, "%u", &info.Multiplicity);
+ }
+ }
+}
+
+cmHeadToLinkInterfaceMap& cmGeneratorTarget::GetHeadToLinkInterfaceMap(
+ const std::string& config) const
+{
+ std::string CONFIG = cmSystemTools::UpperCase(config);
+ return this->LinkInterfaceMap[CONFIG];
+}
+
+cmHeadToLinkInterfaceMap&
+cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap(
+ const std::string& config) const
+{
+ std::string CONFIG = cmSystemTools::UpperCase(config);
+ return this->LinkInterfaceUsageRequirementsOnlyMap[CONFIG];
+}
+
+const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
+ const std::string& config) const
+{
+ // There is no link implementation for imported targets.
+ if (this->IsImported()) {
+ return CM_NULLPTR;
+ }
+
+ std::string CONFIG = cmSystemTools::UpperCase(config);
+ cmOptionalLinkImplementation& impl = this->LinkImplMap[CONFIG][this];
+ if (!impl.LibrariesDone) {
+ impl.LibrariesDone = true;
+ this->ComputeLinkImplementationLibraries(config, impl, this);
+ }
+ if (!impl.LanguagesDone) {
+ impl.LanguagesDone = true;
+ this->ComputeLinkImplementationLanguages(config, impl);
+ }
+ return &impl;
+}
+
+bool cmGeneratorTarget::GetConfigCommonSourceFiles(
+ std::vector<cmSourceFile*>& files) const
+{
+ std::vector<std::string> configs;
+ this->Makefile->GetConfigurations(configs);
+ if (configs.empty()) {
+ configs.push_back("");
+ }
+
+ std::vector<std::string>::const_iterator it = configs.begin();
+ const std::string& firstConfig = *it;
+ this->GetSourceFiles(files, firstConfig);
+
+ for (; it != configs.end(); ++it) {
+ std::vector<cmSourceFile*> configFiles;
+ this->GetSourceFiles(configFiles, *it);
+ if (configFiles != files) {
+ std::string firstConfigFiles;
+ const char* sep = "";
+ for (std::vector<cmSourceFile*>::const_iterator fi = files.begin();
+ fi != files.end(); ++fi) {
+ firstConfigFiles += sep;
+ firstConfigFiles += (*fi)->GetFullPath();
+ sep = "\n ";
+ }
+
+ std::string thisConfigFiles;
+ sep = "";
+ for (std::vector<cmSourceFile*>::const_iterator fi = configFiles.begin();
+ fi != configFiles.end(); ++fi) {
+ thisConfigFiles += sep;
+ thisConfigFiles += (*fi)->GetFullPath();
+ sep = "\n ";
+ }
+ std::ostringstream e;
+ /* clang-format off */
+ e << "Target \"" << this->GetName()
+ << "\" has source files which vary by "
+ "configuration. This is not supported by the \""
+ << this->GlobalGenerator->GetName()
+ << "\" generator.\n"
+ "Config \"" << firstConfig << "\":\n"
+ " " << firstConfigFiles << "\n"
+ "Config \"" << *it << "\":\n"
+ " " << thisConfigFiles << "\n";
+ /* clang-format on */
+ this->LocalGenerator->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ }
+ return true;
+}
+
+void cmGeneratorTarget::GetObjectLibrariesCMP0026(
+ std::vector<cmGeneratorTarget*>& objlibs) const
+{
+ // At configure-time, this method can be called as part of getting the
+ // LOCATION property or to export() a file to be include()d. However
+ // there is no cmGeneratorTarget at configure-time, so search the SOURCES
+ // for TARGET_OBJECTS instead for backwards compatibility with OLD
+ // behavior of CMP0024 and CMP0026 only.
+ cmStringRange rng = this->Target->GetSourceEntries();
+ for (std::vector<std::string>::const_iterator i = rng.begin();
+ i != rng.end(); ++i) {
+ std::string const& entry = *i;
+
+ std::vector<std::string> files;
+ cmSystemTools::ExpandListArgument(entry, files);
+ for (std::vector<std::string>::const_iterator li = files.begin();
+ li != files.end(); ++li) {
+ if (cmHasLiteralPrefix(*li, "$<TARGET_OBJECTS:") &&
+ (*li)[li->size() - 1] == '>') {
+ std::string objLibName = li->substr(17, li->size() - 18);
+
+ if (cmGeneratorExpression::Find(objLibName) != std::string::npos) {
+ continue;
+ }
+ cmGeneratorTarget* objLib =
+ this->LocalGenerator->FindGeneratorTargetToUse(objLibName);
+ if (objLib) {
+ objlibs.push_back(objLib);
+ }
+ }
+ }
+ }
+}
+
+std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const
+{
+ // Strip whitespace off the library names because we used to do this
+ // in case variables were expanded at generate time. We no longer
+ // do the expansion but users link to libraries like " ${VAR} ".
+ std::string lib = item;
+ std::string::size_type pos = lib.find_first_not_of(" \t\r\n");
+ if (pos != lib.npos) {
+ lib = lib.substr(pos, lib.npos);
+ }
+ pos = lib.find_last_not_of(" \t\r\n");
+ if (pos != lib.npos) {
+ lib = lib.substr(0, pos + 1);
+ }
+ if (lib != item) {
+ cmake* cm = this->LocalGenerator->GetCMakeInstance();
+ switch (this->GetPolicyStatusCMP0004()) {
+ case cmPolicies::WARN: {
+ std::ostringstream w;
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0004) << "\n"
+ << "Target \"" << this->GetName() << "\" links to item \"" << item
+ << "\" which has leading or trailing whitespace.";
+ cm->IssueMessage(cmake::AUTHOR_WARNING, w.str(), this->GetBacktrace());
+ }
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::NEW: {
+ std::ostringstream e;
+ e << "Target \"" << this->GetName() << "\" links to item \"" << item
+ << "\" which has leading or trailing whitespace. "
+ << "This is now an error according to policy CMP0004.";
+ cm->IssueMessage(cmake::FATAL_ERROR, e.str(), this->GetBacktrace());
+ } break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS: {
+ std::ostringstream e;
+ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0004) << "\n"
+ << "Target \"" << this->GetName() << "\" links to item \"" << item
+ << "\" which has leading or trailing whitespace.";
+ cm->IssueMessage(cmake::FATAL_ERROR, e.str(), this->GetBacktrace());
+ } break;
+ }
+ }
+ return lib;
+}
+
+void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages,
+ const std::string& config) const
+{
+ std::vector<cmSourceFile*> sourceFiles;
+ this->GetSourceFiles(sourceFiles, config);
+ for (std::vector<cmSourceFile*>::const_iterator i = sourceFiles.begin();
+ i != sourceFiles.end(); ++i) {
+ const std::string& lang = (*i)->GetLanguage();
+ if (!lang.empty()) {
+ languages.insert(lang);
+ }
+ }
+
+ std::vector<cmGeneratorTarget*> objectLibraries;
+ std::vector<cmSourceFile const*> externalObjects;
+ if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ std::vector<cmGeneratorTarget*> objectTargets;
+ this->GetObjectLibrariesCMP0026(objectTargets);
+ objectLibraries.reserve(objectTargets.size());
+ for (std::vector<cmGeneratorTarget*>::const_iterator it =
+ objectTargets.begin();
+ it != objectTargets.end(); ++it) {
+ objectLibraries.push_back(*it);
+ }
+ } else {
+ this->GetExternalObjects(externalObjects, config);
+ for (std::vector<cmSourceFile const*>::const_iterator i =
+ externalObjects.begin();
+ i != externalObjects.end(); ++i) {
+ std::string objLib = (*i)->GetObjectLibrary();
+ if (cmGeneratorTarget* tgt =
+ this->LocalGenerator->FindGeneratorTargetToUse(objLib)) {
+ objectLibraries.push_back(tgt);
+ }
+ }
+ }
+ for (std::vector<cmGeneratorTarget*>::const_iterator i =
+ objectLibraries.begin();
+ i != objectLibraries.end(); ++i) {
+ (*i)->GetLanguages(languages, config);
+ }
+}
+
+void cmGeneratorTarget::ComputeLinkImplementationLanguages(
+ const std::string& config, cmOptionalLinkImplementation& impl) const
+{
+ // This target needs runtime libraries for its source languages.
+ std::set<std::string> languages;
+ // Get languages used in our source files.
+ this->GetLanguages(languages, config);
+ // Copy the set of langauges to the link implementation.
+ impl.Languages.insert(impl.Languages.begin(), languages.begin(),
+ languages.end());
+}
+
+bool cmGeneratorTarget::HaveBuildTreeRPATH(const std::string& config) const
+{
+ if (this->GetPropertyAsBool("SKIP_BUILD_RPATH")) {
+ return false;
+ }
+ if (cmLinkImplementationLibraries const* impl =
+ this->GetLinkImplementationLibraries(config)) {
+ return !impl->Libraries.empty();
+ }
+ return false;
+}
+
+cmLinkImplementationLibraries const*
+cmGeneratorTarget::GetLinkImplementationLibraries(
+ const std::string& config) const
+{
+ return this->GetLinkImplementationLibrariesInternal(config, this);
+}
+
+cmLinkImplementationLibraries const*
+cmGeneratorTarget::GetLinkImplementationLibrariesInternal(
+ const std::string& config, cmGeneratorTarget const* head) const
+{
+ // There is no link implementation for imported targets.
+ if (this->IsImported()) {
+ return CM_NULLPTR;
+ }
+
+ // Populate the link implementation libraries for this configuration.
+ std::string CONFIG = cmSystemTools::UpperCase(config);
+ HeadToLinkImplementationMap& hm = this->LinkImplMap[CONFIG];
+
+ // If the link implementation does not depend on the head target
+ // then return the one we computed first.
+ if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
+ return &hm.begin()->second;
+ }
+
+ cmOptionalLinkImplementation& impl = hm[head];
+ if (!impl.LibrariesDone) {
+ impl.LibrariesDone = true;
+ this->ComputeLinkImplementationLibraries(config, impl, head);
+ }
+ return &impl;
+}
+
+bool cmGeneratorTarget::IsNullImpliedByLinkLibraries(
+ const std::string& p) const
+{
+ return this->LinkImplicitNullProperties.find(p) !=
+ this->LinkImplicitNullProperties.end();
+}
+
+void cmGeneratorTarget::ComputeLinkImplementationLibraries(
+ const std::string& config, cmOptionalLinkImplementation& impl,
+ cmGeneratorTarget const* head) const
+{
+ cmStringRange entryRange = this->Target->GetLinkImplementationEntries();
+ cmBacktraceRange btRange = this->Target->GetLinkImplementationBacktraces();
+ cmBacktraceRange::const_iterator btIt = btRange.begin();
+ // Collect libraries directly linked in this configuration.
+ for (cmStringRange::const_iterator le = entryRange.begin(),
+ end = entryRange.end();
+ le != end; ++le, ++btIt) {
+ std::vector<std::string> llibs;
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this->GetName(), "LINK_LIBRARIES", CM_NULLPTR, CM_NULLPTR);
+ cmGeneratorExpression ge(*btIt);
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> const cge = ge.Parse(*le);
+ std::string const evaluated =
+ cge->Evaluate(this->LocalGenerator, config, false, head, &dagChecker);
+ cmSystemTools::ExpandListArgument(evaluated, llibs);
+ if (cge->GetHadHeadSensitiveCondition()) {
+ impl.HadHeadSensitiveCondition = true;
+ }
+
+ for (std::vector<std::string>::const_iterator li = llibs.begin();
+ li != llibs.end(); ++li) {
+ // Skip entries that resolve to the target itself or are empty.
+ std::string name = this->CheckCMP0004(*li);
+ if (name == this->GetName() || name.empty()) {
+ if (name == this->GetName()) {
+ bool noMessage = false;
+ cmake::MessageType messageType = cmake::FATAL_ERROR;
+ std::ostringstream e;
+ switch (this->GetPolicyStatusCMP0038()) {
+ case cmPolicies::WARN: {
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0038) << "\n";
+ messageType = cmake::AUTHOR_WARNING;
+ } break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Issue the fatal message.
+ break;
+ }
+
+ if (!noMessage) {
+ e << "Target \"" << this->GetName() << "\" links to itself.";
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(
+ messageType, e.str(), this->GetBacktrace());
+ if (messageType == cmake::FATAL_ERROR) {
+ return;
+ }
+ }
+ }
+ continue;
+ }
+
+ // The entry is meant for this configuration.
+ impl.Libraries.push_back(cmLinkImplItem(
+ name, this->FindTargetToLink(name), *btIt, evaluated != *le));
+ }
+
+ std::set<std::string> const& seenProps = cge->GetSeenTargetProperties();
+ for (std::set<std::string>::const_iterator it = seenProps.begin();
+ it != seenProps.end(); ++it) {
+ if (!this->GetProperty(*it)) {
+ this->LinkImplicitNullProperties.insert(*it);
+ }
+ }
+ cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards);
+ }
+
+ // Get the list of configurations considered to be DEBUG.
+ std::vector<std::string> debugConfigs =
+ this->Makefile->GetCMakeInstance()->GetDebugConfigs();
+
+ cmTargetLinkLibraryType linkType =
+ CMP0003_ComputeLinkType(config, debugConfigs);
+ cmTarget::LinkLibraryVectorType const& oldllibs =
+ this->Target->GetOriginalLinkLibraries();
+ for (cmTarget::LinkLibraryVectorType::const_iterator li = oldllibs.begin();
+ li != oldllibs.end(); ++li) {
+ if (li->second != GENERAL_LibraryType && li->second != linkType) {
+ std::string name = this->CheckCMP0004(li->first);
+ if (name == this->GetName() || name.empty()) {
+ continue;
+ }
+ // Support OLD behavior for CMP0003.
+ impl.WrongConfigLibraries.push_back(
+ cmLinkItem(name, this->FindTargetToLink(name)));
+ }
+ }
+}
+
+cmGeneratorTarget* cmGeneratorTarget::FindTargetToLink(
+ std::string const& name) const
+{
+ cmGeneratorTarget* tgt =
+ this->LocalGenerator->FindGeneratorTargetToUse(name);
+
+ // Skip targets that will not really be linked. This is probably a
+ // name conflict between an external library and an executable
+ // within the project.
+ if (tgt && tgt->GetType() == cmState::EXECUTABLE &&
+ !tgt->IsExecutableWithExports()) {
+ tgt = CM_NULLPTR;
+ }
+
+ if (tgt && tgt->GetType() == cmState::OBJECT_LIBRARY) {
+ std::ostringstream e;
+ e << "Target \"" << this->GetName() << "\" links to "
+ "OBJECT library \""
+ << tgt->GetName()
+ << "\" but this is not "
+ "allowed. "
+ "One may link only to STATIC or SHARED libraries, or to executables "
+ "with the ENABLE_EXPORTS property set.";
+ cmake* cm = this->LocalGenerator->GetCMakeInstance();
+ cm->IssueMessage(cmake::FATAL_ERROR, e.str(), this->GetBacktrace());
+ tgt = CM_NULLPTR;
+ }
+
+ return tgt;
+}
+
+std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const
+{
+ if (OutputInfo const* info = this->GetOutputInfo(config)) {
+ // Return the directory in which the target will be built.
+ return info->PdbDir;
+ }
+ return "";
+}
+
+bool cmGeneratorTarget::HasImplibGNUtoMS() const
+{
+ return this->HasImportLibrary() && this->GetPropertyAsBool("GNUtoMS");
+}
+
+bool cmGeneratorTarget::GetImplibGNUtoMS(std::string const& gnuName,
+ std::string& out,
+ const char* newExt) const
+{
+ if (this->HasImplibGNUtoMS() && gnuName.size() > 6 &&
+ gnuName.substr(gnuName.size() - 6) == ".dll.a") {
+ out = gnuName.substr(0, gnuName.size() - 6);
+ out += newExt ? newExt : ".lib";
+ return true;
+ }
+ return false;
+}
+
+bool cmGeneratorTarget::IsExecutableWithExports() const
+{
+ return (this->GetType() == cmState::EXECUTABLE &&
+ this->GetPropertyAsBool("ENABLE_EXPORTS"));
+}
+
+bool cmGeneratorTarget::HasImportLibrary() const
+{
+ return (this->IsDLLPlatform() &&
+ (this->GetType() == cmState::SHARED_LIBRARY ||
+ this->IsExecutableWithExports()));
+}
+
+std::string cmGeneratorTarget::GetSupportDirectory() const
+{
+ std::string dir = this->LocalGenerator->GetCurrentBinaryDirectory();
+ dir += cmake::GetCMakeFilesDirectory();
+ dir += "/";
+ dir += this->GetName();
+#if defined(__VMS)
+ dir += "_dir";
+#else
+ dir += ".dir";
+#endif
+ return dir;
+}
+
+bool cmGeneratorTarget::IsLinkable() const
+{
+ return (this->GetType() == cmState::STATIC_LIBRARY ||
+ this->GetType() == cmState::SHARED_LIBRARY ||
+ this->GetType() == cmState::MODULE_LIBRARY ||
+ this->GetType() == cmState::UNKNOWN_LIBRARY ||
+ this->GetType() == cmState::INTERFACE_LIBRARY ||
+ this->IsExecutableWithExports());
+}
+
+bool cmGeneratorTarget::IsFrameworkOnApple() const
+{
+ return (this->GetType() == cmState::SHARED_LIBRARY &&
+ this->Makefile->IsOn("APPLE") &&
+ this->GetPropertyAsBool("FRAMEWORK"));
+}
+
+bool cmGeneratorTarget::IsAppBundleOnApple() const
+{
+ return (this->GetType() == cmState::EXECUTABLE &&
+ this->Makefile->IsOn("APPLE") &&
+ this->GetPropertyAsBool("MACOSX_BUNDLE"));
+}
+
+bool cmGeneratorTarget::IsXCTestOnApple() const
+{
+ return (this->IsCFBundleOnApple() && this->GetPropertyAsBool("XCTEST"));
+}
+
+bool cmGeneratorTarget::IsCFBundleOnApple() const
+{
+ return (this->GetType() == cmState::MODULE_LIBRARY &&
+ this->Makefile->IsOn("APPLE") && this->GetPropertyAsBool("BUNDLE"));
+}
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
new file mode 100644
index 0000000..f9987aa
--- /dev/null
+++ b/Source/cmGeneratorTarget.h
@@ -0,0 +1,727 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGeneratorTarget_h
+#define cmGeneratorTarget_h
+
+#include "cmLinkItem.h"
+
+class cmCustomCommand;
+class cmGlobalGenerator;
+class cmLocalGenerator;
+class cmMakefile;
+class cmSourceFile;
+class cmTarget;
+class cmComputeLinkInformation;
+
+class cmGeneratorTarget
+{
+public:
+ cmGeneratorTarget(cmTarget*, cmLocalGenerator* lg);
+ ~cmGeneratorTarget();
+
+ cmLocalGenerator* GetLocalGenerator() const;
+
+ bool IsImported() const;
+ bool IsImportedGloballyVisible() const;
+ const char* GetLocation(const std::string& config) const;
+
+ std::vector<cmCustomCommand> const& GetPreBuildCommands() const;
+ std::vector<cmCustomCommand> const& GetPreLinkCommands() const;
+ std::vector<cmCustomCommand> const& GetPostBuildCommands() const;
+
+#define DECLARE_TARGET_POLICY(POLICY) \
+ cmPolicies::PolicyStatus GetPolicyStatus##POLICY() const \
+ { \
+ return this->PolicyMap.Get(cmPolicies::POLICY); \
+ }
+
+ CM_FOR_EACH_TARGET_POLICY(DECLARE_TARGET_POLICY)
+
+#undef DECLARE_TARGET_POLICY
+
+ /** Get the location of the target in the build tree with a placeholder
+ referencing the configuration in the native build system. This
+ location is suitable for use as the LOCATION target property. */
+ const char* GetLocationForBuild() const;
+
+ cmComputeLinkInformation* GetLinkInformation(
+ const std::string& config) const;
+
+ cmState::TargetType GetType() const;
+ const std::string& GetName() const;
+ std::string GetExportName() const;
+
+ std::vector<std::string> GetPropertyKeys() const;
+ const char* GetProperty(const std::string& prop) const;
+ bool GetPropertyAsBool(const std::string& prop) const;
+ void GetSourceFiles(std::vector<cmSourceFile*>& files,
+ const std::string& config) const;
+
+ void GetObjectSources(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ const std::string& GetObjectName(cmSourceFile const* file);
+
+ bool HasExplicitObjectName(cmSourceFile const* file) const;
+ void AddExplicitObjectName(cmSourceFile const* sf);
+
+ void GetResxSources(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetIDLSources(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetExternalObjects(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetHeaderSources(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetExtraSources(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetCustomCommands(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetExpectedResxHeaders(std::set<std::string>&,
+ const std::string& config) const;
+ void GetAppManifest(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetManifests(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetCertificates(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetXamlSources(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetExpectedXamlHeaders(std::set<std::string>&,
+ const std::string& config) const;
+ void GetExpectedXamlSources(std::set<std::string>&,
+ const std::string& config) const;
+
+ std::set<cmLinkItem> const& GetUtilityItems() const;
+
+ void ComputeObjectMapping();
+
+ const char* GetFeature(const std::string& feature,
+ const std::string& config) const;
+ bool GetFeatureAsBool(const std::string& feature,
+ const std::string& config) const;
+
+ bool IsLinkInterfaceDependentBoolProperty(const std::string& p,
+ const std::string& config) const;
+ bool IsLinkInterfaceDependentStringProperty(const std::string& p,
+ const std::string& config) const;
+ bool IsLinkInterfaceDependentNumberMinProperty(
+ const std::string& p, const std::string& config) const;
+ bool IsLinkInterfaceDependentNumberMaxProperty(
+ const std::string& p, const std::string& config) const;
+
+ bool GetLinkInterfaceDependentBoolProperty(const std::string& p,
+ const std::string& config) const;
+
+ const char* GetLinkInterfaceDependentStringProperty(
+ const std::string& p, const std::string& config) const;
+ const char* GetLinkInterfaceDependentNumberMinProperty(
+ const std::string& p, const std::string& config) const;
+ const char* GetLinkInterfaceDependentNumberMaxProperty(
+ const std::string& p, const std::string& config) const;
+
+ cmLinkInterface const* GetLinkInterface(
+ const std::string& config, const cmGeneratorTarget* headTarget) const;
+ void ComputeLinkInterface(const std::string& config,
+ cmOptionalLinkInterface& iface,
+ const cmGeneratorTarget* head) const;
+
+ cmLinkInterfaceLibraries const* GetLinkInterfaceLibraries(
+ const std::string& config, const cmGeneratorTarget* headTarget,
+ bool usage_requirements_only) const;
+
+ void ComputeLinkInterfaceLibraries(const std::string& config,
+ cmOptionalLinkInterface& iface,
+ const cmGeneratorTarget* head,
+ bool usage_requirements_only) const;
+
+ /** Get the full path to the target according to the settings in its
+ makefile and the configuration type. */
+ std::string GetFullPath(const std::string& config = "", bool implib = false,
+ bool realname = false) const;
+ std::string NormalGetFullPath(const std::string& config, bool implib,
+ bool realname) const;
+ std::string NormalGetRealName(const std::string& config) const;
+
+ /** @return the Mac App directory without the base */
+ std::string GetAppBundleDirectory(const std::string& config,
+ bool contentOnly) const;
+
+ /** Return whether this target is an executable Bundle, a framework
+ or CFBundle on Apple. */
+ bool IsBundleOnApple() const;
+
+ /** Get the full name of the target according to the settings in its
+ makefile. */
+ std::string GetFullName(const std::string& config = "",
+ bool implib = false) const;
+
+ /** @return the Mac framework directory without the base. */
+ std::string GetFrameworkDirectory(const std::string& config,
+ bool rootDir) const;
+
+ /** Return the framework version string. Undefined if
+ IsFrameworkOnApple returns false. */
+ std::string GetFrameworkVersion() const;
+
+ /** @return the Mac CFBundle directory without the base */
+ std::string GetCFBundleDirectory(const std::string& config,
+ bool contentOnly) const;
+
+ /** Return the install name directory for the target in the
+ * build tree. For example: "\@rpath/", "\@loader_path/",
+ * or "/full/path/to/library". */
+ std::string GetInstallNameDirForBuildTree(const std::string& config) const;
+
+ /** Return the install name directory for the target in the
+ * install tree. For example: "\@rpath/" or "\@loader_path/". */
+ std::string GetInstallNameDirForInstallTree() const;
+
+ cmListFileBacktrace GetBacktrace() const;
+
+ const std::vector<std::string>& GetLinkDirectories() const;
+
+ std::set<std::string> const& GetUtilities() const;
+ cmListFileBacktrace const* GetUtilityBacktrace(const std::string& u) const;
+
+ bool LinkLanguagePropagatesToDependents() const
+ {
+ return this->GetType() == cmState::STATIC_LIBRARY;
+ }
+
+ /** Get the macro to define when building sources in this target.
+ If no macro should be defined null is returned. */
+ const char* GetExportMacro() const;
+
+ /** Get the soname of the target. Allowed only for a shared library. */
+ std::string GetSOName(const std::string& config) const;
+
+ void GetFullNameComponents(std::string& prefix, std::string& base,
+ std::string& suffix,
+ const std::string& config = "",
+ bool implib = false) const;
+
+ /** Append to @a base the mac content directory and return it. */
+ std::string BuildMacContentDirectory(const std::string& base,
+ const std::string& config = "",
+ bool contentOnly = true) const;
+
+ /** @return the mac content directory for this target. */
+ std::string GetMacContentDirectory(const std::string& config = CM_NULLPTR,
+ bool implib = false) const;
+
+ cmTarget* Target;
+ cmMakefile* Makefile;
+ cmLocalGenerator* LocalGenerator;
+ cmGlobalGenerator const* GlobalGenerator;
+
+ cmSourceFile const* GetModuleDefinitionFile(const std::string& config) const;
+
+ /** Return whether or not the target is for a DLL platform. */
+ bool IsDLLPlatform() const;
+
+ /** @return whether this target have a well defined output file name. */
+ bool HaveWellDefinedOutputFiles() const;
+
+ /** Link information from the transitive closure of the link
+ implementation and the interfaces of its dependencies. */
+ struct LinkClosure
+ {
+ // The preferred linker language.
+ std::string LinkerLanguage;
+
+ // Languages whose runtime libraries must be linked.
+ std::vector<std::string> Languages;
+ };
+
+ LinkClosure const* GetLinkClosure(const std::string& config) const;
+ void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const;
+
+ cmLinkImplementation const* GetLinkImplementation(
+ const std::string& config) const;
+
+ void ComputeLinkImplementationLanguages(
+ const std::string& config, cmOptionalLinkImplementation& impl) const;
+
+ cmLinkImplementationLibraries const* GetLinkImplementationLibraries(
+ const std::string& config) const;
+
+ void ComputeLinkImplementationLibraries(const std::string& config,
+ cmOptionalLinkImplementation& impl,
+ const cmGeneratorTarget* head) const;
+
+ cmGeneratorTarget* FindTargetToLink(std::string const& name) const;
+
+ // Compute the set of languages compiled by the target. This is
+ // computed every time it is called because the languages can change
+ // when source file properties are changed and we do not have enough
+ // information to forward these property changes to the targets
+ // until we have per-target object file properties.
+ void GetLanguages(std::set<std::string>& languages,
+ std::string const& config) const;
+
+ void GetObjectLibrariesCMP0026(
+ std::vector<cmGeneratorTarget*>& objlibs) const;
+
+ std::string GetFullNameImported(const std::string& config,
+ bool implib) const;
+
+ bool GetConfigCommonSourceFiles(std::vector<cmSourceFile*>& files) const;
+
+ bool HaveBuildTreeRPATH(const std::string& config) const;
+
+ /** Full path with trailing slash to the top-level directory
+ holding object files for this target. Includes the build
+ time config name placeholder if needed for the generator. */
+ std::string ObjectDirectory;
+
+ void UseObjectLibraries(std::vector<std::string>& objs,
+ const std::string& config) const;
+
+ void GetAppleArchs(const std::string& config,
+ std::vector<std::string>& archVec) const;
+
+ /** Return the rule variable used to create this type of target. */
+ std::string GetCreateRuleVariable(std::string const& lang,
+ std::string const& config) const;
+
+ /** Get the include directories for this target. */
+ std::vector<std::string> GetIncludeDirectories(
+ const std::string& config, const std::string& lang) const;
+
+ void GetCompileOptions(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const;
+
+ void GetCompileFeatures(std::vector<std::string>& features,
+ const std::string& config) const;
+
+ void GetCompileDefinitions(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const;
+
+ bool IsSystemIncludeDirectory(const std::string& dir,
+ const std::string& config) const;
+
+ /** Add the target output files to the global generator manifest. */
+ void ComputeTargetManifest(const std::string& config) const;
+
+ /**
+ * Trace through the source files in this target and add al source files
+ * that they depend on, used by all generators
+ */
+ void TraceDependencies();
+
+ /** Get the directory in which this target will be built. If the
+ configuration name is given then the generator will add its
+ subdirectory for that configuration. Otherwise just the canonical
+ output directory is given. */
+ std::string GetDirectory(const std::string& config = "",
+ bool implib = false) const;
+
+ /** Get the directory in which to place the target compiler .pdb file.
+ If the configuration name is given then the generator will add its
+ subdirectory for that configuration. Otherwise just the canonical
+ compiler pdb output directory is given. */
+ std::string GetCompilePDBDirectory(const std::string& config = "") const;
+
+ /** Get sources that must be built before the given source. */
+ std::vector<cmSourceFile*> const* GetSourceDepends(
+ cmSourceFile const* sf) const;
+
+ /** Return whether this target uses the default value for its output
+ directory. */
+ bool UsesDefaultOutputDir(const std::string& config, bool implib) const;
+
+ // Cache target output paths for each configuration.
+ struct OutputInfo
+ {
+ std::string OutDir;
+ std::string ImpDir;
+ std::string PdbDir;
+ bool empty() const
+ {
+ return OutDir.empty() && ImpDir.empty() && PdbDir.empty();
+ }
+ };
+
+ OutputInfo const* GetOutputInfo(const std::string& config) const;
+
+ /** Get the name of the pdb file for the target. */
+ std::string GetPDBName(const std::string& config = "") const;
+
+ /** Whether this library has soname enabled and platform supports it. */
+ bool HasSOName(const std::string& config) const;
+
+ struct CompileInfo
+ {
+ std::string CompilePdbDir;
+ };
+
+ CompileInfo const* GetCompileInfo(const std::string& config) const;
+
+ typedef std::map<std::string, CompileInfo> CompileInfoMapType;
+ mutable CompileInfoMapType CompileInfoMap;
+
+ bool IsNullImpliedByLinkLibraries(const std::string& p) const;
+
+ /** Get the name of the compiler pdb file for the target. */
+ std::string GetCompilePDBName(const std::string& config = "") const;
+
+ /** Get the path for the MSVC /Fd option for this target. */
+ std::string GetCompilePDBPath(const std::string& config = "") const;
+
+ // Get the target base name.
+ std::string GetOutputName(const std::string& config, bool implib) const;
+
+ void AddSource(const std::string& src);
+ void AddTracedSources(std::vector<std::string> const& srcs);
+
+ /**
+ * Flags for a given source file as used in this target. Typically assigned
+ * via SET_TARGET_PROPERTIES when the property is a list of source files.
+ */
+ enum SourceFileType
+ {
+ SourceFileTypeNormal,
+ SourceFileTypePrivateHeader, // is in "PRIVATE_HEADER" target property
+ SourceFileTypePublicHeader, // is in "PUBLIC_HEADER" target property
+ SourceFileTypeResource, // is in "RESOURCE" target property *or*
+ // has MACOSX_PACKAGE_LOCATION=="Resources"
+ SourceFileTypeMacContent // has MACOSX_PACKAGE_LOCATION!="Resources"
+ };
+ struct SourceFileFlags
+ {
+ SourceFileFlags()
+ : Type(SourceFileTypeNormal)
+ , MacFolder(CM_NULLPTR)
+ {
+ }
+ SourceFileFlags(SourceFileFlags const& r)
+ : Type(r.Type)
+ , MacFolder(r.MacFolder)
+ {
+ }
+ SourceFileType Type;
+ const char* MacFolder; // location inside Mac content folders
+ };
+ void GetAutoUicOptions(std::vector<std::string>& result,
+ const std::string& config) const;
+
+ /** 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;
+
+ /** 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;
+
+ /**
+ * Compute whether this target must be relinked before installing.
+ */
+ bool NeedRelinkBeforeInstall(const std::string& config) const;
+
+ /** Return true if builtin chrpath will work for this target */
+ bool IsChrpathUsed(const std::string& config) const;
+
+ /** Get the directory in which this targets .pdb files will be placed.
+ If the configuration name is given then the generator will add its
+ subdirectory for that configuration. Otherwise just the canonical
+ pdb output directory is given. */
+ std::string GetPDBDirectory(const std::string& config) const;
+
+ ///! 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? */
+ bool HasImplibGNUtoMS() const;
+
+ /** Convert the given GNU import library name (.dll.a) to a name with a new
+ extension (.lib or ${CMAKE_IMPORT_LIBRARY_SUFFIX}). */
+ bool GetImplibGNUtoMS(std::string const& gnuName, std::string& out,
+ const char* newExt = CM_NULLPTR) const;
+
+ bool IsExecutableWithExports() const;
+
+ /** Return whether or not the target has a DLL import library. */
+ bool HasImportLibrary() const;
+
+ /** Get a build-tree directory in which to place target support files. */
+ std::string GetSupportDirectory() const;
+
+ /** Return whether this target may be used to link another target. */
+ bool IsLinkable() const;
+
+ /** Return whether this target is a shared library Framework on
+ Apple. */
+ bool IsFrameworkOnApple() const;
+
+ /** Return whether this target is an executable Bundle on Apple. */
+ bool IsAppBundleOnApple() const;
+
+ /** Return whether this target is a XCTest on Apple. */
+ bool IsXCTestOnApple() const;
+
+ /** Return whether this target is a CFBundle (plugin) on Apple. */
+ bool IsCFBundleOnApple() const;
+
+ struct SourceFileFlags GetTargetSourceFileFlags(
+ const cmSourceFile* sf) const;
+
+ struct ResxData
+ {
+ mutable std::set<std::string> ExpectedResxHeaders;
+ mutable std::vector<cmSourceFile const*> ResxSources;
+ };
+
+ struct XamlData
+ {
+ std::set<std::string> ExpectedXamlHeaders;
+ std::set<std::string> ExpectedXamlSources;
+ std::vector<cmSourceFile const*> XamlSources;
+ };
+
+ void ReportPropertyOrigin(const std::string& p, const std::string& result,
+ const std::string& report,
+ const std::string& compatibilityType) const;
+
+ class TargetPropertyEntry;
+
+ bool HaveInstallTreeRPATH() const;
+
+ /** Whether this library has \@rpath and platform supports it. */
+ bool HasMacOSXRpathInstallNameDir(const std::string& config) const;
+
+ /** Whether this library defaults to \@rpath. */
+ bool MacOSXRpathInstallNameDirDefault() const;
+
+ /** Test for special case of a third-party shared library that has
+ no soname at all. */
+ bool IsImportedSharedLibWithoutSOName(const std::string& config) const;
+
+ const char* ImportedGetLocation(const std::string& config) const;
+
+ /** Get the target major and minor version numbers interpreted from
+ the VERSION property. Version 0 is returned if the property is
+ not set or cannot be parsed. */
+ void GetTargetVersion(int& major, int& minor) const;
+
+ /** Get the target major, minor, and patch version numbers
+ interpreted from the VERSION or SOVERSION property. Version 0
+ is returned if the property is not set or cannot be parsed. */
+ void GetTargetVersion(bool soversion, int& major, int& minor,
+ int& patch) const;
+
+ std::string GetFortranModuleDirectory() const;
+
+private:
+ std::string CreateFortranModuleDirectory() const;
+ mutable bool FortranModuleDirectoryCreated;
+ mutable std::string FortranModuleDirectory;
+
+ friend class cmTargetTraceDependencies;
+ struct SourceEntry
+ {
+ std::vector<cmSourceFile*> Depends;
+ };
+ typedef std::map<cmSourceFile const*, SourceEntry> SourceEntriesType;
+ SourceEntriesType SourceDepends;
+ mutable std::map<cmSourceFile const*, std::string> Objects;
+ std::set<cmSourceFile const*> ExplicitObjectName;
+ mutable std::map<std::string, std::vector<std::string> > SystemIncludesCache;
+
+ mutable std::string ExportMacro;
+
+ void ConstructSourceFileFlags() const;
+ mutable bool SourceFileFlagsConstructed;
+ mutable std::map<cmSourceFile const*, SourceFileFlags> SourceFlagsMap;
+
+ mutable std::map<std::string, bool> DebugCompatiblePropertiesDone;
+
+ std::string GetFullNameInternal(const std::string& config,
+ bool implib) const;
+ void GetFullNameInternal(const std::string& config, bool implib,
+ std::string& outPrefix, std::string& outBase,
+ std::string& outSuffix) const;
+
+ typedef std::map<std::string, LinkClosure> LinkClosureMapType;
+ mutable LinkClosureMapType LinkClosureMap;
+
+ // Returns ARCHIVE, LIBRARY, or RUNTIME based on platform and type.
+ const char* GetOutputTargetType(bool implib) const;
+
+ void ComputeVersionedName(std::string& vName, std::string const& prefix,
+ std::string const& base, std::string const& suffix,
+ std::string const& name,
+ const char* version) const;
+
+ struct CompatibleInterfacesBase
+ {
+ std::set<std::string> PropsBool;
+ std::set<std::string> PropsString;
+ std::set<std::string> PropsNumberMax;
+ std::set<std::string> PropsNumberMin;
+ };
+ CompatibleInterfacesBase const& GetCompatibleInterfaces(
+ std::string const& config) const;
+
+ struct CompatibleInterfaces : public CompatibleInterfacesBase
+ {
+ CompatibleInterfaces()
+ : Done(false)
+ {
+ }
+ bool Done;
+ };
+ mutable std::map<std::string, CompatibleInterfaces> CompatibleInterfacesMap;
+
+ typedef std::map<std::string, cmComputeLinkInformation*>
+ cmTargetLinkInformationMap;
+ mutable cmTargetLinkInformationMap LinkInformation;
+
+ void CheckPropertyCompatibility(cmComputeLinkInformation* info,
+ const std::string& config) const;
+
+ cmGeneratorTarget(cmGeneratorTarget const&);
+ void operator=(cmGeneratorTarget const&);
+
+ struct LinkImplClosure : public std::vector<cmGeneratorTarget const*>
+ {
+ LinkImplClosure()
+ : Done(false)
+ {
+ }
+ bool Done;
+ };
+ mutable std::map<std::string, LinkImplClosure> LinkImplClosureMap;
+
+ typedef std::map<std::string, cmHeadToLinkInterfaceMap> LinkInterfaceMapType;
+ mutable LinkInterfaceMapType LinkInterfaceMap;
+ mutable LinkInterfaceMapType LinkInterfaceUsageRequirementsOnlyMap;
+
+ cmHeadToLinkInterfaceMap& GetHeadToLinkInterfaceMap(
+ std::string const& config) const;
+ cmHeadToLinkInterfaceMap& GetHeadToLinkInterfaceUsageRequirementsMap(
+ std::string const& config) const;
+
+ // Cache import information from properties for each configuration.
+ struct ImportInfo
+ {
+ ImportInfo()
+ : NoSOName(false)
+ , Multiplicity(0)
+ {
+ }
+ bool NoSOName;
+ unsigned int Multiplicity;
+ std::string Location;
+ std::string SOName;
+ std::string ImportLibrary;
+ std::string Languages;
+ std::string Libraries;
+ std::string LibrariesProp;
+ std::string SharedDeps;
+ };
+
+ typedef std::map<std::string, ImportInfo> ImportInfoMapType;
+ mutable ImportInfoMapType ImportInfoMap;
+ void ComputeImportInfo(std::string const& desired_config,
+ ImportInfo& info) const;
+ ImportInfo const* GetImportInfo(const std::string& config) const;
+
+ /** Strip off leading and trailing whitespace from an item named in
+ the link dependencies of this target. */
+ std::string CheckCMP0004(std::string const& item) const;
+
+ cmLinkInterface const* GetImportLinkInterface(
+ const std::string& config, const cmGeneratorTarget* head,
+ bool usage_requirements_only) const;
+
+ typedef std::map<std::string, std::vector<cmSourceFile*> >
+ SourceFilesMapType;
+ mutable SourceFilesMapType SourceFilesMap;
+
+ std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries;
+ std::vector<TargetPropertyEntry*> CompileOptionsEntries;
+ std::vector<TargetPropertyEntry*> CompileFeaturesEntries;
+ std::vector<TargetPropertyEntry*> CompileDefinitionsEntries;
+ std::vector<TargetPropertyEntry*> SourceEntries;
+ mutable std::set<std::string> LinkImplicitNullProperties;
+
+ void ExpandLinkItems(std::string const& prop, std::string const& value,
+ std::string const& config,
+ const cmGeneratorTarget* headTarget,
+ bool usage_requirements_only,
+ std::vector<cmLinkItem>& items,
+ bool& hadHeadSensitiveCondition) const;
+ void LookupLinkItems(std::vector<std::string> const& names,
+ std::vector<cmLinkItem>& items) const;
+
+ void GetSourceFiles(std::vector<std::string>& files,
+ const std::string& config) const;
+
+ struct HeadToLinkImplementationMap
+ : public std::map<cmGeneratorTarget const*, cmOptionalLinkImplementation>
+ {
+ };
+ typedef std::map<std::string, HeadToLinkImplementationMap> LinkImplMapType;
+ mutable LinkImplMapType LinkImplMap;
+
+ cmLinkImplementationLibraries const* GetLinkImplementationLibrariesInternal(
+ const std::string& config, const cmGeneratorTarget* head) const;
+ bool ComputeOutputDir(const std::string& config, bool implib,
+ std::string& out) const;
+
+ typedef std::map<std::string, OutputInfo> OutputInfoMapType;
+ mutable OutputInfoMapType OutputInfoMap;
+
+ typedef std::pair<std::string, bool> OutputNameKey;
+ typedef std::map<OutputNameKey, std::string> OutputNameMapType;
+ mutable OutputNameMapType OutputNameMap;
+ mutable std::set<cmLinkItem> UtilityItems;
+ cmPolicies::PolicyMap PolicyMap;
+ mutable bool PolicyWarnedCMP0022;
+ mutable bool DebugIncludesDone;
+ mutable bool DebugCompileOptionsDone;
+ mutable bool DebugCompileFeaturesDone;
+ mutable bool DebugCompileDefinitionsDone;
+ mutable bool DebugSourcesDone;
+ mutable bool LinkImplementationLanguageIsContextDependent;
+ mutable bool UtilityItemsDone;
+ bool DLLPlatform;
+
+ bool ComputePDBOutputDir(const std::string& kind, const std::string& config,
+ std::string& out) const;
+
+public:
+ const std::vector<const cmGeneratorTarget*>& GetLinkImplementationClosure(
+ const std::string& config) const;
+
+ mutable std::map<std::string, std::string> MaxLanguageStandards;
+ std::map<std::string, std::string> const& GetMaxLanguageStandards() const
+ {
+ return this->MaxLanguageStandards;
+ }
+
+ struct StrictTargetComparison
+ {
+ bool operator()(cmGeneratorTarget const* t1,
+ cmGeneratorTarget const* t2) const;
+ };
+};
+
+#endif
diff --git a/Source/cmGetCMakePropertyCommand.cxx b/Source/cmGetCMakePropertyCommand.cxx
new file mode 100644
index 0000000..c89d030
--- /dev/null
+++ b/Source/cmGetCMakePropertyCommand.cxx
@@ -0,0 +1,57 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGetCMakePropertyCommand.h"
+
+#include "cmAlgorithms.h"
+#include "cmGlobalGenerator.h"
+#include "cmState.h"
+#include "cmake.h"
+
+// cmGetCMakePropertyCommand
+bool cmGetCMakePropertyCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string variable = args[0];
+ std::string output = "NOTFOUND";
+
+ if (args[1] == "VARIABLES") {
+ if (const char* varsProp = this->Makefile->GetProperty("VARIABLES")) {
+ output = varsProp;
+ }
+ } else if (args[1] == "MACROS") {
+ output.clear();
+ if (const char* macrosProp = this->Makefile->GetProperty("MACROS")) {
+ output = macrosProp;
+ }
+ } else if (args[1] == "COMPONENTS") {
+ const std::set<std::string>* components =
+ this->Makefile->GetGlobalGenerator()->GetInstallComponents();
+ output = cmJoin(*components, ";");
+ } else {
+ const char* prop = CM_NULLPTR;
+ if (!args[1].empty()) {
+ prop = this->Makefile->GetState()->GetGlobalProperty(args[1]);
+ }
+ if (prop) {
+ output = prop;
+ }
+ }
+
+ this->Makefile->AddDefinition(variable, output.c_str());
+
+ return true;
+}
diff --git a/Source/cmGetCMakePropertyCommand.h b/Source/cmGetCMakePropertyCommand.h
new file mode 100644
index 0000000..7df9cc1
--- /dev/null
+++ b/Source/cmGetCMakePropertyCommand.h
@@ -0,0 +1,42 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGetCMakePropertyCommand_h
+#define cmGetCMakePropertyCommand_h
+
+#include "cmCommand.h"
+
+class cmGetCMakePropertyCommand : public cmCommand
+{
+public:
+ cmCommand* Clone() CM_OVERRIDE { return new cmGetCMakePropertyCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "get_cmake_property"; }
+
+ cmTypeMacro(cmGetCMakePropertyCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmGetDirectoryPropertyCommand.cxx b/Source/cmGetDirectoryPropertyCommand.cxx
new file mode 100644
index 0000000..a331e78
--- /dev/null
+++ b/Source/cmGetDirectoryPropertyCommand.cxx
@@ -0,0 +1,107 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGetDirectoryPropertyCommand.h"
+
+#include "cmake.h"
+
+// cmGetDirectoryPropertyCommand
+bool cmGetDirectoryPropertyCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::vector<std::string>::const_iterator i = args.begin();
+ std::string variable = *i;
+ ++i;
+
+ // get the directory argument if there is one
+ cmMakefile* dir = this->Makefile;
+ if (*i == "DIRECTORY") {
+ ++i;
+ if (i == args.end()) {
+ this->SetError(
+ "DIRECTORY argument provided without subsequent arguments");
+ return false;
+ }
+ std::string sd = *i;
+ // make sure the start dir is a full path
+ if (!cmSystemTools::FileIsFullPath(sd.c_str())) {
+ sd = this->Makefile->GetCurrentSourceDirectory();
+ sd += "/";
+ sd += *i;
+ }
+
+ // The local generators are associated with collapsed paths.
+ sd = cmSystemTools::CollapseFullPath(sd);
+
+ // lookup the makefile from the directory name
+ dir = this->Makefile->GetGlobalGenerator()->FindMakefile(sd);
+ if (!dir) {
+ this->SetError(
+ "DIRECTORY argument provided but requested directory not found. "
+ "This could be because the directory argument was invalid or, "
+ "it is valid but has not been processed yet.");
+ return false;
+ }
+ ++i;
+ }
+
+ // OK, now we have the directory to process, we just get the requested
+ // information out of it
+
+ if (*i == "DEFINITION") {
+ ++i;
+ if (i == args.end()) {
+ this->SetError("A request for a variable definition was made without "
+ "providing the name of the variable to get.");
+ return false;
+ }
+ std::string output = dir->GetSafeDefinition(*i);
+ this->Makefile->AddDefinition(variable, output.c_str());
+ return true;
+ }
+
+ const char* prop = CM_NULLPTR;
+ if (!i->empty()) {
+ if (*i == "DEFINITIONS") {
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0059)) {
+ case cmPolicies::WARN:
+ this->Makefile->IssueMessage(
+ cmake::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0059));
+ case cmPolicies::OLD:
+ this->StoreResult(variable, this->Makefile->GetDefineFlagsCMP0059());
+ return true;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ break;
+ }
+ }
+ prop = dir->GetProperty(*i);
+ }
+ this->StoreResult(variable, prop);
+ return true;
+}
+
+void cmGetDirectoryPropertyCommand::StoreResult(std::string const& variable,
+ const char* prop)
+{
+ if (prop) {
+ this->Makefile->AddDefinition(variable, prop);
+ return;
+ }
+ this->Makefile->AddDefinition(variable, "");
+}
diff --git a/Source/cmGetDirectoryPropertyCommand.h b/Source/cmGetDirectoryPropertyCommand.h
new file mode 100644
index 0000000..1be9aa4
--- /dev/null
+++ b/Source/cmGetDirectoryPropertyCommand.h
@@ -0,0 +1,45 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGetDirectoryPropertyCommand_h
+#define cmGetDirectoryPropertyCommand_h
+
+#include "cmCommand.h"
+
+class cmGetDirectoryPropertyCommand : public cmCommand
+{
+public:
+ cmCommand* Clone() CM_OVERRIDE { return new cmGetDirectoryPropertyCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "get_directory_property"; }
+
+ cmTypeMacro(cmGetDirectoryPropertyCommand, cmCommand);
+
+private:
+ void StoreResult(const std::string& variable, const char* prop);
+};
+
+#endif
diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx
new file mode 100644
index 0000000..1830b0c
--- /dev/null
+++ b/Source/cmGetFilenameComponentCommand.cxx
@@ -0,0 +1,115 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGetFilenameComponentCommand.h"
+
+#include "cmSystemTools.h"
+
+// cmGetFilenameComponentCommand
+bool cmGetFilenameComponentCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Check and see if the value has been stored in the cache
+ // already, if so use that value
+ if (args.size() >= 4 && args[args.size() - 1] == "CACHE") {
+ const char* cacheValue = this->Makefile->GetDefinition(args[0]);
+ if (cacheValue && !cmSystemTools::IsNOTFOUND(cacheValue)) {
+ return true;
+ }
+ }
+
+ std::string result;
+ std::string filename = args[1];
+ if (filename.find("[HKEY") != filename.npos) {
+ // Check the registry as the target application would view it.
+ cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32;
+ cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64;
+ if (this->Makefile->PlatformIs64Bit()) {
+ view = cmSystemTools::KeyWOW64_64;
+ other_view = cmSystemTools::KeyWOW64_32;
+ }
+ cmSystemTools::ExpandRegistryValues(filename, view);
+ if (filename.find("/registry") != filename.npos) {
+ std::string other = args[1];
+ cmSystemTools::ExpandRegistryValues(other, other_view);
+ if (other.find("/registry") == other.npos) {
+ filename = other;
+ }
+ }
+ }
+ std::string storeArgs;
+ std::string programArgs;
+ if (args[2] == "DIRECTORY" || args[2] == "PATH") {
+ result = cmSystemTools::GetFilenamePath(filename);
+ } else if (args[2] == "NAME") {
+ result = cmSystemTools::GetFilenameName(filename);
+ } else if (args[2] == "PROGRAM") {
+ for (unsigned int i = 2; i < args.size(); ++i) {
+ if (args[i] == "PROGRAM_ARGS") {
+ i++;
+ if (i < args.size()) {
+ storeArgs = args[i];
+ }
+ }
+ }
+ cmSystemTools::SplitProgramFromArgs(filename, result, programArgs);
+ } else if (args[2] == "EXT") {
+ result = cmSystemTools::GetFilenameExtension(filename);
+ } else if (args[2] == "NAME_WE") {
+ result = cmSystemTools::GetFilenameWithoutExtension(filename);
+ } else if (args[2] == "ABSOLUTE" || args[2] == "REALPATH") {
+ // If the path given is relative, evaluate it relative to the
+ // current source directory unless the user passes a different
+ // base directory.
+ std::string baseDir = this->Makefile->GetCurrentSourceDirectory();
+ for (unsigned int i = 3; i < args.size(); ++i) {
+ if (args[i] == "BASE_DIR") {
+ ++i;
+ if (i < args.size()) {
+ baseDir = args[i];
+ }
+ }
+ }
+ // Collapse the path to its simplest form.
+ result = cmSystemTools::CollapseFullPath(filename, baseDir);
+ if (args[2] == "REALPATH") {
+ // Resolve symlinks if possible
+ result = cmSystemTools::GetRealPath(result);
+ }
+ } else {
+ std::string err = "unknown component " + args[2];
+ this->SetError(err);
+ return false;
+ }
+
+ if (args.size() >= 4 && args[args.size() - 1] == "CACHE") {
+ if (!programArgs.empty() && !storeArgs.empty()) {
+ this->Makefile->AddCacheDefinition(storeArgs, programArgs.c_str(), "",
+ args[2] == "PATH" ? cmState::FILEPATH
+ : cmState::STRING);
+ }
+ this->Makefile->AddCacheDefinition(args[0], result.c_str(), "",
+ args[2] == "PATH" ? cmState::FILEPATH
+ : cmState::STRING);
+ } else {
+ if (!programArgs.empty() && !storeArgs.empty()) {
+ this->Makefile->AddDefinition(storeArgs, programArgs.c_str());
+ }
+ this->Makefile->AddDefinition(args[0], result.c_str());
+ }
+
+ return true;
+}
diff --git a/Source/cmGetFilenameComponentCommand.h b/Source/cmGetFilenameComponentCommand.h
new file mode 100644
index 0000000..d8609fe
--- /dev/null
+++ b/Source/cmGetFilenameComponentCommand.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGetFilenameComponentCommand_h
+#define cmGetFilenameComponentCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmGetFilenameComponentCommand
+ * \brief Get a specific component of a filename.
+ *
+ * cmGetFilenameComponentCommand is a utility command used to get the path,
+ * name, extension or name without extension of a full filename.
+ */
+class cmGetFilenameComponentCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmGetFilenameComponentCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "get_filename_component"; }
+
+ cmTypeMacro(cmGetFilenameComponentCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx
new file mode 100644
index 0000000..854fdb8
--- /dev/null
+++ b/Source/cmGetPropertyCommand.cxx
@@ -0,0 +1,357 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGetPropertyCommand.h"
+
+#include "cmGlobalGenerator.h"
+#include "cmPropertyDefinition.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmTest.h"
+#include "cmake.h"
+
+cmGetPropertyCommand::cmGetPropertyCommand()
+{
+ this->InfoType = OutValue;
+}
+
+bool cmGetPropertyCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // The cmake variable in which to store the result.
+ this->Variable = args[0];
+
+ // Get the scope from which to get the property.
+ cmProperty::ScopeType scope;
+ if (args[1] == "GLOBAL") {
+ scope = cmProperty::GLOBAL;
+ } else if (args[1] == "DIRECTORY") {
+ scope = cmProperty::DIRECTORY;
+ } else if (args[1] == "TARGET") {
+ scope = cmProperty::TARGET;
+ } else if (args[1] == "SOURCE") {
+ scope = cmProperty::SOURCE_FILE;
+ } else if (args[1] == "TEST") {
+ scope = cmProperty::TEST;
+ } else if (args[1] == "VARIABLE") {
+ scope = cmProperty::VARIABLE;
+ } else if (args[1] == "CACHE") {
+ scope = cmProperty::CACHE;
+ } else if (args[1] == "INSTALL") {
+ scope = cmProperty::INSTALL;
+ } else {
+ std::ostringstream e;
+ e << "given invalid scope " << args[1] << ". "
+ << "Valid scopes are "
+ << "GLOBAL, DIRECTORY, TARGET, SOURCE, TEST, VARIABLE, CACHE, INSTALL.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Parse remaining arguments.
+ enum Doing
+ {
+ DoingNone,
+ DoingName,
+ DoingProperty,
+ DoingType
+ };
+ Doing doing = DoingName;
+ for (unsigned int i = 2; i < args.size(); ++i) {
+ if (args[i] == "PROPERTY") {
+ doing = DoingProperty;
+ } else if (args[i] == "BRIEF_DOCS") {
+ doing = DoingNone;
+ this->InfoType = OutBriefDoc;
+ } else if (args[i] == "FULL_DOCS") {
+ doing = DoingNone;
+ this->InfoType = OutFullDoc;
+ } else if (args[i] == "SET") {
+ doing = DoingNone;
+ this->InfoType = OutSet;
+ } else if (args[i] == "DEFINED") {
+ doing = DoingNone;
+ this->InfoType = OutDefined;
+ } else if (doing == DoingName) {
+ doing = DoingNone;
+ this->Name = args[i];
+ } else if (doing == DoingProperty) {
+ doing = DoingNone;
+ this->PropertyName = args[i];
+ } else {
+ std::ostringstream e;
+ e << "given invalid argument \"" << args[i] << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ // Make sure a property name was found.
+ if (this->PropertyName.empty()) {
+ this->SetError("not given a PROPERTY <name> argument.");
+ return false;
+ }
+
+ // Compute requested output.
+ if (this->InfoType == OutBriefDoc) {
+ // Lookup brief documentation.
+ std::string output;
+ if (cmPropertyDefinition const* def =
+ this->Makefile->GetState()->GetPropertyDefinition(this->PropertyName,
+ scope)) {
+ output = def->GetShortDescription();
+ } else {
+ output = "NOTFOUND";
+ }
+ this->Makefile->AddDefinition(this->Variable, output.c_str());
+ } else if (this->InfoType == OutFullDoc) {
+ // Lookup full documentation.
+ std::string output;
+ if (cmPropertyDefinition const* def =
+ this->Makefile->GetState()->GetPropertyDefinition(this->PropertyName,
+ scope)) {
+ output = def->GetFullDescription();
+ } else {
+ output = "NOTFOUND";
+ }
+ this->Makefile->AddDefinition(this->Variable, output.c_str());
+ } else if (this->InfoType == OutDefined) {
+ // Lookup if the property is defined
+ if (this->Makefile->GetState()->GetPropertyDefinition(this->PropertyName,
+ scope)) {
+ this->Makefile->AddDefinition(this->Variable, "1");
+ } else {
+ this->Makefile->AddDefinition(this->Variable, "0");
+ }
+ } else {
+ // Dispatch property getting.
+ switch (scope) {
+ case cmProperty::GLOBAL:
+ return this->HandleGlobalMode();
+ case cmProperty::DIRECTORY:
+ return this->HandleDirectoryMode();
+ case cmProperty::TARGET:
+ return this->HandleTargetMode();
+ case cmProperty::SOURCE_FILE:
+ return this->HandleSourceMode();
+ case cmProperty::TEST:
+ return this->HandleTestMode();
+ case cmProperty::VARIABLE:
+ return this->HandleVariableMode();
+ case cmProperty::CACHE:
+ return this->HandleCacheMode();
+ case cmProperty::INSTALL:
+ return this->HandleInstallMode();
+
+ case cmProperty::CACHED_VARIABLE:
+ break; // should never happen
+ }
+ }
+
+ return true;
+}
+
+bool cmGetPropertyCommand::StoreResult(const char* value)
+{
+ if (this->InfoType == OutSet) {
+ this->Makefile->AddDefinition(this->Variable, value ? "1" : "0");
+ } else // if(this->InfoType == OutValue)
+ {
+ if (value) {
+ this->Makefile->AddDefinition(this->Variable, value);
+ } else {
+ this->Makefile->RemoveDefinition(this->Variable);
+ }
+ }
+ return true;
+}
+
+bool cmGetPropertyCommand::HandleGlobalMode()
+{
+ if (!this->Name.empty()) {
+ this->SetError("given name for GLOBAL scope.");
+ return false;
+ }
+
+ // Get the property.
+ cmake* cm = this->Makefile->GetCMakeInstance();
+ return this->StoreResult(
+ cm->GetState()->GetGlobalProperty(this->PropertyName));
+}
+
+bool cmGetPropertyCommand::HandleDirectoryMode()
+{
+ // Default to the current directory.
+ cmMakefile* mf = this->Makefile;
+
+ // Lookup the directory if given.
+ if (!this->Name.empty()) {
+ // Construct the directory name. Interpret relative paths with
+ // respect to the current directory.
+ std::string dir = this->Name;
+ if (!cmSystemTools::FileIsFullPath(dir.c_str())) {
+ dir = this->Makefile->GetCurrentSourceDirectory();
+ dir += "/";
+ dir += this->Name;
+ }
+
+ // The local generators are associated with collapsed paths.
+ dir = cmSystemTools::CollapseFullPath(dir);
+
+ // Lookup the generator.
+ mf = this->Makefile->GetGlobalGenerator()->FindMakefile(dir);
+ if (!mf) {
+ // Could not find the directory.
+ this->SetError(
+ "DIRECTORY scope provided but requested directory was not found. "
+ "This could be because the directory argument was invalid or, "
+ "it is valid but has not been processed yet.");
+ return false;
+ }
+ }
+
+ if (this->PropertyName == "DEFINITIONS") {
+ switch (mf->GetPolicyStatus(cmPolicies::CMP0059)) {
+ case cmPolicies::WARN:
+ mf->IssueMessage(cmake::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0059));
+ case cmPolicies::OLD:
+ return this->StoreResult(mf->GetDefineFlagsCMP0059());
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ break;
+ }
+ }
+
+ // Get the property.
+ return this->StoreResult(mf->GetProperty(this->PropertyName));
+}
+
+bool cmGetPropertyCommand::HandleTargetMode()
+{
+ if (this->Name.empty()) {
+ this->SetError("not given name for TARGET scope.");
+ return false;
+ }
+
+ if (cmTarget* target = this->Makefile->FindTargetToUse(this->Name)) {
+ if (this->PropertyName == "ALIASED_TARGET") {
+ if (this->Makefile->IsAlias(this->Name)) {
+ return this->StoreResult(target->GetName().c_str());
+ } else {
+ return this->StoreResult((this->Variable + "-NOTFOUND").c_str());
+ }
+ }
+ return this->StoreResult(
+ target->GetProperty(this->PropertyName, this->Makefile));
+ } else {
+ std::ostringstream e;
+ e << "could not find TARGET " << this->Name
+ << ". Perhaps it has not yet been created.";
+ this->SetError(e.str());
+ return false;
+ }
+}
+
+bool cmGetPropertyCommand::HandleSourceMode()
+{
+ if (this->Name.empty()) {
+ this->SetError("not given name for SOURCE scope.");
+ return false;
+ }
+
+ // Get the source file.
+ if (cmSourceFile* sf = this->Makefile->GetOrCreateSource(this->Name)) {
+ return this->StoreResult(sf->GetPropertyForUser(this->PropertyName));
+ } else {
+ std::ostringstream e;
+ e << "given SOURCE name that could not be found or created: "
+ << this->Name;
+ this->SetError(e.str());
+ return false;
+ }
+}
+
+bool cmGetPropertyCommand::HandleTestMode()
+{
+ if (this->Name.empty()) {
+ this->SetError("not given name for TEST scope.");
+ return false;
+ }
+
+ // Loop over all tests looking for matching names.
+ if (cmTest* test = this->Makefile->GetTest(this->Name)) {
+ return this->StoreResult(test->GetProperty(this->PropertyName));
+ }
+
+ // If not found it is an error.
+ std::ostringstream e;
+ e << "given TEST name that does not exist: " << this->Name;
+ this->SetError(e.str());
+ return false;
+}
+
+bool cmGetPropertyCommand::HandleVariableMode()
+{
+ if (!this->Name.empty()) {
+ this->SetError("given name for VARIABLE scope.");
+ return false;
+ }
+
+ return this->StoreResult(this->Makefile->GetDefinition(this->PropertyName));
+}
+
+bool cmGetPropertyCommand::HandleCacheMode()
+{
+ if (this->Name.empty()) {
+ this->SetError("not given name for CACHE scope.");
+ return false;
+ }
+
+ const char* value = CM_NULLPTR;
+ if (this->Makefile->GetState()->GetCacheEntryValue(this->Name)) {
+ value = this->Makefile->GetState()->GetCacheEntryProperty(
+ this->Name, this->PropertyName);
+ }
+ this->StoreResult(value);
+ return true;
+}
+
+bool cmGetPropertyCommand::HandleInstallMode()
+{
+ if (this->Name.empty()) {
+ this->SetError("not given name for INSTALL scope.");
+ return false;
+ }
+
+ // Get the installed file.
+ cmake* cm = this->Makefile->GetCMakeInstance();
+
+ if (cmInstalledFile* file =
+ cm->GetOrCreateInstalledFile(this->Makefile, this->Name)) {
+ std::string value;
+ bool isSet = file->GetProperty(this->PropertyName, value);
+
+ return this->StoreResult(isSet ? value.c_str() : CM_NULLPTR);
+ } else {
+ std::ostringstream e;
+ e << "given INSTALL name that could not be found or created: "
+ << this->Name;
+ this->SetError(e.str());
+ return false;
+ }
+}
diff --git a/Source/cmGetPropertyCommand.h b/Source/cmGetPropertyCommand.h
new file mode 100644
index 0000000..558226b
--- /dev/null
+++ b/Source/cmGetPropertyCommand.h
@@ -0,0 +1,71 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGetPropertyCommand_h
+#define cmGetPropertyCommand_h
+
+#include "cmCommand.h"
+
+class cmGetPropertyCommand : public cmCommand
+{
+public:
+ cmGetPropertyCommand();
+
+ cmCommand* Clone() CM_OVERRIDE { return new cmGetPropertyCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "get_property"; }
+
+ cmTypeMacro(cmGetPropertyCommand, cmCommand);
+
+private:
+ enum OutType
+ {
+ OutValue,
+ OutDefined,
+ OutBriefDoc,
+ OutFullDoc,
+ OutSet
+ };
+ std::string Variable;
+ std::string Name;
+ std::string PropertyName;
+ OutType InfoType;
+
+ // Implementation of result storage.
+ bool StoreResult(const char* value);
+
+ // Implementation of each property type.
+ bool HandleGlobalMode();
+ bool HandleDirectoryMode();
+ bool HandleTargetMode();
+ bool HandleSourceMode();
+ bool HandleTestMode();
+ bool HandleVariableMode();
+ bool HandleCacheMode();
+ bool HandleInstallMode();
+};
+
+#endif
diff --git a/Source/cmGetSourceFilePropertyCommand.cxx b/Source/cmGetSourceFilePropertyCommand.cxx
new file mode 100644
index 0000000..7b30a7d
--- /dev/null
+++ b/Source/cmGetSourceFilePropertyCommand.cxx
@@ -0,0 +1,49 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGetSourceFilePropertyCommand.h"
+
+#include "cmSourceFile.h"
+
+// cmSetSourceFilePropertyCommand
+bool cmGetSourceFilePropertyCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() != 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ const char* var = args[0].c_str();
+ const char* file = args[1].c_str();
+ cmSourceFile* sf = this->Makefile->GetSource(file);
+
+ // for the location we must create a source file first
+ if (!sf && args[2] == "LOCATION") {
+ sf = this->Makefile->CreateSource(file);
+ }
+ if (sf) {
+ if (args[2] == "LANGUAGE") {
+ this->Makefile->AddDefinition(var, sf->GetLanguage().c_str());
+ return true;
+ }
+ const char* prop = CM_NULLPTR;
+ if (!args[2].empty()) {
+ prop = sf->GetPropertyForUser(args[2]);
+ }
+ if (prop) {
+ this->Makefile->AddDefinition(var, prop);
+ return true;
+ }
+ }
+
+ this->Makefile->AddDefinition(var, "NOTFOUND");
+ return true;
+}
diff --git a/Source/cmGetSourceFilePropertyCommand.h b/Source/cmGetSourceFilePropertyCommand.h
new file mode 100644
index 0000000..2d2477c
--- /dev/null
+++ b/Source/cmGetSourceFilePropertyCommand.h
@@ -0,0 +1,40 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGetSourceFilePropertyCommand_h
+#define cmGetSourceFilePropertyCommand_h
+
+#include "cmCommand.h"
+
+class cmGetSourceFilePropertyCommand : public cmCommand
+{
+public:
+ cmCommand* Clone() CM_OVERRIDE { return new cmGetSourceFilePropertyCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE
+ {
+ return "get_source_file_property";
+ }
+
+ cmTypeMacro(cmGetSourceFilePropertyCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmGetTargetPropertyCommand.cxx b/Source/cmGetTargetPropertyCommand.cxx
new file mode 100644
index 0000000..073cf32
--- /dev/null
+++ b/Source/cmGetTargetPropertyCommand.cxx
@@ -0,0 +1,71 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGetTargetPropertyCommand.h"
+
+// cmSetTargetPropertyCommand
+bool cmGetTargetPropertyCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() != 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ std::string var = args[0];
+ const std::string& targetName = args[1];
+ std::string prop;
+ bool prop_exists = false;
+
+ if (cmTarget* tgt = this->Makefile->FindTargetToUse(targetName)) {
+ if (args[2] == "ALIASED_TARGET") {
+ if (this->Makefile->IsAlias(targetName)) {
+ prop = tgt->GetName();
+ prop_exists = true;
+ }
+ } else if (!args[2].empty()) {
+ const char* prop_cstr = tgt->GetProperty(args[2], this->Makefile);
+ if (prop_cstr) {
+ prop = prop_cstr;
+ prop_exists = true;
+ }
+ }
+ } else {
+ bool issueMessage = false;
+ std::ostringstream e;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0045)) {
+ case cmPolicies::WARN:
+ issueMessage = true;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0045) << "\n";
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ issueMessage = true;
+ messageType = cmake::FATAL_ERROR;
+ }
+ if (issueMessage) {
+ e << "get_target_property() called with non-existent target \""
+ << targetName << "\".";
+ this->Makefile->IssueMessage(messageType, e.str());
+ if (messageType == cmake::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+ if (prop_exists) {
+ this->Makefile->AddDefinition(var, prop.c_str());
+ return true;
+ }
+ this->Makefile->AddDefinition(var, (var + "-NOTFOUND").c_str());
+ return true;
+}
diff --git a/Source/cmGetTargetPropertyCommand.h b/Source/cmGetTargetPropertyCommand.h
new file mode 100644
index 0000000..3e0fe36
--- /dev/null
+++ b/Source/cmGetTargetPropertyCommand.h
@@ -0,0 +1,37 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGetTargetPropertyCommand_h
+#define cmGetTargetPropertyCommand_h
+
+#include "cmCommand.h"
+
+class cmGetTargetPropertyCommand : public cmCommand
+{
+public:
+ cmCommand* Clone() CM_OVERRIDE { return new cmGetTargetPropertyCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "get_target_property"; }
+
+ cmTypeMacro(cmGetTargetPropertyCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmGetTestPropertyCommand.cxx b/Source/cmGetTestPropertyCommand.cxx
new file mode 100644
index 0000000..5eaf872
--- /dev/null
+++ b/Source/cmGetTestPropertyCommand.cxx
@@ -0,0 +1,41 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGetTestPropertyCommand.h"
+
+#include "cmTest.h"
+#include "cmake.h"
+
+// cmGetTestPropertyCommand
+bool cmGetTestPropertyCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string testName = args[0];
+ std::string var = args[2];
+ cmTest* test = this->Makefile->GetTest(testName);
+ if (test) {
+ const char* prop = CM_NULLPTR;
+ if (!args[1].empty()) {
+ prop = test->GetProperty(args[1]);
+ }
+ if (prop) {
+ this->Makefile->AddDefinition(var, prop);
+ return true;
+ }
+ }
+ this->Makefile->AddDefinition(var, "NOTFOUND");
+ return true;
+}
diff --git a/Source/cmGetTestPropertyCommand.h b/Source/cmGetTestPropertyCommand.h
new file mode 100644
index 0000000..e419c98
--- /dev/null
+++ b/Source/cmGetTestPropertyCommand.h
@@ -0,0 +1,37 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGetTestPropertyCommand_h
+#define cmGetTestPropertyCommand_h
+
+#include "cmCommand.h"
+
+class cmGetTestPropertyCommand : public cmCommand
+{
+public:
+ cmCommand* Clone() CM_OVERRIDE { return new cmGetTestPropertyCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "get_test_property"; }
+
+ cmTypeMacro(cmGetTestPropertyCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmGhsMultiGpj.cxx b/Source/cmGhsMultiGpj.cxx
new file mode 100644
index 0000000..ca88578
--- /dev/null
+++ b/Source/cmGhsMultiGpj.cxx
@@ -0,0 +1,43 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Geoffrey Viola <geoffrey.viola@asirobots.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGhsMultiGpj.h"
+
+#include "cmGeneratedFileStream.h"
+
+void GhsMultiGpj::WriteGpjTag(Types const gpjType,
+ cmGeneratedFileStream* const filestream)
+{
+ char const* tag;
+ switch (gpjType) {
+ case INTERGRITY_APPLICATION:
+ tag = "INTEGRITY Application";
+ break;
+ case LIBRARY:
+ tag = "Library";
+ break;
+ case PROJECT:
+ tag = "Project";
+ break;
+ case PROGRAM:
+ tag = "Program";
+ break;
+ case REFERENCE:
+ tag = "Reference";
+ break;
+ case SUBPROJECT:
+ tag = "Subproject";
+ break;
+ default:
+ tag = "";
+ }
+ *filestream << "[" << tag << "]" << std::endl;
+}
diff --git a/Source/cmGhsMultiGpj.h b/Source/cmGhsMultiGpj.h
new file mode 100644
index 0000000..b388455
--- /dev/null
+++ b/Source/cmGhsMultiGpj.h
@@ -0,0 +1,36 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Geoffrey Viola <geoffrey.viola@asirobots.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGhsMultiGpj_h
+#define cmGhsMultiGpj_h
+
+#include "cmStandardIncludes.h"
+
+class cmGeneratedFileStream;
+
+class GhsMultiGpj
+{
+public:
+ enum Types
+ {
+ INTERGRITY_APPLICATION,
+ LIBRARY,
+ PROJECT,
+ PROGRAM,
+ REFERENCE,
+ SUBPROJECT
+ };
+
+ static void WriteGpjTag(Types const gpjType,
+ cmGeneratedFileStream* filestream);
+};
+
+#endif // ! cmGhsMultiGpjType_h
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
new file mode 100644
index 0000000..3d35114
--- /dev/null
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -0,0 +1,662 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Geoffrey Viola <geoffrey.viola@asirobots.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGhsMultiTargetGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGhsMultiGenerator.h"
+#include "cmLocalGhsMultiGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmTarget.h"
+#include <assert.h>
+
+std::string const cmGhsMultiTargetGenerator::DDOption("-dynamic");
+
+cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
+ : GeneratorTarget(target)
+ , LocalGenerator(
+ static_cast<cmLocalGhsMultiGenerator*>(target->GetLocalGenerator()))
+ , Makefile(target->Target->GetMakefile())
+ , TargetGroup(DetermineIfTargetGroup(target))
+ , DynamicDownload(false)
+{
+ this->RelBuildFilePath = this->GetRelBuildFilePath(target);
+
+ this->RelOutputFileName = this->RelBuildFilePath + target->GetName() + ".a";
+
+ this->RelBuildFileName = this->RelBuildFilePath;
+ this->RelBuildFileName += this->GetBuildFileName(target);
+
+ std::string absPathToRoot = this->GetAbsPathToRoot(target);
+ absPathToRoot = this->AddSlashIfNeededToPath(absPathToRoot);
+ this->AbsBuildFilePath = absPathToRoot + this->RelBuildFilePath;
+ this->AbsBuildFileName = absPathToRoot + this->RelBuildFileName;
+ this->AbsOutputFileName = absPathToRoot + this->RelOutputFileName;
+}
+
+cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator()
+{
+ cmDeleteAll(this->FolderBuildStreams);
+}
+
+std::string cmGhsMultiTargetGenerator::GetRelBuildFilePath(
+ const cmGeneratorTarget* target)
+{
+ std::string output;
+ char const* folderProp = target->GetProperty("FOLDER");
+ output = NULL == folderProp ? "" : folderProp;
+ cmSystemTools::ConvertToUnixSlashes(output);
+ if (!output.empty()) {
+ output += "/";
+ }
+ output += target->GetName() + "/";
+ return output;
+}
+
+std::string cmGhsMultiTargetGenerator::GetAbsPathToRoot(
+ const cmGeneratorTarget* target)
+{
+ return target->GetLocalGenerator()->GetBinaryDirectory();
+}
+
+std::string cmGhsMultiTargetGenerator::GetAbsBuildFilePath(
+ const cmGeneratorTarget* target)
+{
+ std::string output;
+ output = cmGhsMultiTargetGenerator::GetAbsPathToRoot(target);
+ output = cmGhsMultiTargetGenerator::AddSlashIfNeededToPath(output);
+ output += cmGhsMultiTargetGenerator::GetRelBuildFilePath(target);
+ return output;
+}
+
+std::string cmGhsMultiTargetGenerator::GetRelBuildFileName(
+ const cmGeneratorTarget* target)
+{
+ std::string output;
+ output = cmGhsMultiTargetGenerator::GetRelBuildFilePath(target);
+ output = cmGhsMultiTargetGenerator::AddSlashIfNeededToPath(output);
+ output += cmGhsMultiTargetGenerator::GetBuildFileName(target);
+ return output;
+}
+
+std::string cmGhsMultiTargetGenerator::GetBuildFileName(
+ const cmGeneratorTarget* target)
+{
+ std::string output;
+ output = target->GetName();
+ output += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+ return output;
+}
+
+std::string cmGhsMultiTargetGenerator::AddSlashIfNeededToPath(
+ std::string const& input)
+{
+ std::string output(input);
+ if (!cmHasLiteralSuffix(output, "/")) {
+ output += "/";
+ }
+ return output;
+}
+
+void cmGhsMultiTargetGenerator::Generate()
+{
+ std::vector<cmSourceFile*> objectSources = this->GetSources();
+ if (!objectSources.empty() && this->IncludeThisTarget()) {
+ if (!cmSystemTools::FileExists(this->AbsBuildFilePath.c_str())) {
+ cmSystemTools::MakeDirectory(this->AbsBuildFilePath.c_str());
+ }
+ cmGlobalGhsMultiGenerator::Open(std::string(""), this->AbsBuildFileName,
+ &this->FolderBuildStreams);
+ cmGlobalGhsMultiGenerator::OpenBuildFileStream(
+ this->GetFolderBuildStreams());
+ std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ if (0 == config.length()) {
+ config = "RELEASE";
+ }
+ const std::string language(
+ this->GeneratorTarget->GetLinkerLanguage(config));
+ config = cmSystemTools::UpperCase(config);
+ this->DynamicDownload = this->DetermineIfDynamicDownload(config, language);
+ if (this->DynamicDownload) {
+ *this->GetFolderBuildStreams() << "#component integrity_dynamic_download"
+ << std::endl;
+ }
+ GhsMultiGpj::WriteGpjTag(this->GetGpjTag(), this->GetFolderBuildStreams());
+ cmGlobalGhsMultiGenerator::WriteDisclaimer(this->GetFolderBuildStreams());
+
+ bool const notKernel = this->IsNotKernel(config, language);
+ this->WriteTypeSpecifics(config, notKernel);
+ this->SetCompilerFlags(config, language, notKernel);
+ this->WriteCompilerFlags(config, language);
+ this->WriteCompilerDefinitions(config, language);
+ this->WriteIncludes(config, language);
+ if (this->GeneratorTarget->GetType() == cmState::EXECUTABLE) {
+ this->WriteTargetLinkLibraries(config, language);
+ }
+ this->WriteCustomCommands();
+
+ std::map<const cmSourceFile*, std::string> objectNames =
+ cmGhsMultiTargetGenerator::GetObjectNames(
+ &objectSources, this->LocalGenerator, this->GeneratorTarget);
+
+ this->WriteSources(objectSources, objectNames);
+ }
+}
+
+bool cmGhsMultiTargetGenerator::IncludeThisTarget()
+{
+ bool output = true;
+ char const* excludeFromAll =
+ this->GeneratorTarget->GetProperty("EXCLUDE_FROM_ALL");
+ if (NULL != excludeFromAll && '1' == excludeFromAll[0] &&
+ '\0' == excludeFromAll[1]) {
+ output = false;
+ }
+ return output;
+}
+
+std::vector<cmSourceFile*> cmGhsMultiTargetGenerator::GetSources() const
+{
+ std::vector<cmSourceFile*> output;
+ std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ this->GeneratorTarget->GetSourceFiles(output, config);
+ return output;
+}
+
+GhsMultiGpj::Types cmGhsMultiTargetGenerator::GetGpjTag() const
+{
+ return cmGhsMultiTargetGenerator::GetGpjTag(this->GeneratorTarget);
+}
+
+GhsMultiGpj::Types cmGhsMultiTargetGenerator::GetGpjTag(
+ const cmGeneratorTarget* target)
+{
+ GhsMultiGpj::Types output;
+ if (cmGhsMultiTargetGenerator::DetermineIfTargetGroup(target)) {
+ output = GhsMultiGpj::INTERGRITY_APPLICATION;
+ } else if (target->GetType() == cmState::STATIC_LIBRARY) {
+ output = GhsMultiGpj::LIBRARY;
+ } else {
+ output = GhsMultiGpj::PROGRAM;
+ }
+ return output;
+}
+
+cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator()
+ const
+{
+ return static_cast<cmGlobalGhsMultiGenerator*>(
+ this->LocalGenerator->GetGlobalGenerator());
+}
+
+void cmGhsMultiTargetGenerator::WriteTypeSpecifics(const std::string& config,
+ bool const notKernel)
+{
+ std::string outputDir(this->GetOutputDirectory(config));
+ std::string outputFilename(this->GetOutputFilename(config));
+
+ if (this->GeneratorTarget->GetType() == cmState::STATIC_LIBRARY) {
+ std::string const static_library_suffix =
+ this->Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX");
+ *this->GetFolderBuildStreams() << " -o \"" << outputDir
+ << outputFilename << static_library_suffix
+ << "\"" << std::endl;
+ } else if (this->GeneratorTarget->GetType() == cmState::EXECUTABLE) {
+ if (notKernel && !this->IsTargetGroup()) {
+ *this->GetFolderBuildStreams() << " -relprog" << std::endl;
+ }
+ if (this->IsTargetGroup()) {
+ *this->GetFolderBuildStreams()
+ << " -o \"" << outputDir << outputFilename << ".elf\"" << std::endl;
+ *this->GetFolderBuildStreams() << " :extraOutputFile=\"" << outputDir
+ << outputFilename << ".elf.ael\""
+ << std::endl;
+ } else {
+ std::string const executable_suffix =
+ this->Makefile->GetSafeDefinition("CMAKE_EXECUTABLE_SUFFIX");
+ *this->GetFolderBuildStreams() << " -o \"" << outputDir
+ << outputFilename << executable_suffix
+ << "\"" << std::endl;
+ }
+ }
+}
+
+void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config,
+ const std::string& language,
+ bool const notKernel)
+{
+ std::map<std::string, std::string>::iterator i =
+ this->FlagsByLanguage.find(language);
+ if (i == this->FlagsByLanguage.end()) {
+ std::string flags;
+ const char* lang = language.c_str();
+
+ if (notKernel) {
+ this->LocalGenerator->AddLanguageFlags(flags, lang, config);
+ } else {
+ this->LocalGenerator->AddLanguageFlags(
+ flags, lang + std::string("_GHS_KERNEL"), config);
+ }
+ this->LocalGenerator->AddCMP0018Flags(flags, this->GeneratorTarget, lang,
+ config);
+ this->LocalGenerator->AddVisibilityPresetFlags(
+ flags, this->GeneratorTarget, lang);
+
+ // Append old-style preprocessor definition flags.
+ if (std::string(" ") != std::string(this->Makefile->GetDefineFlags())) {
+ this->LocalGenerator->AppendFlags(flags,
+ this->Makefile->GetDefineFlags());
+ }
+
+ // Add target-specific flags.
+ this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, lang,
+ config);
+
+ std::map<std::string, std::string>::value_type entry(language, flags);
+ i = this->FlagsByLanguage.insert(entry).first;
+ }
+}
+
+std::string cmGhsMultiTargetGenerator::GetDefines(const std::string& language,
+ std::string const& config)
+{
+ std::map<std::string, std::string>::iterator i =
+ this->DefinesByLanguage.find(language);
+ if (i == this->DefinesByLanguage.end()) {
+ std::set<std::string> defines;
+ const char* lang = language.c_str();
+ // Add the export symbol definition for shared library objects.
+ if (const char* exportMacro = this->GeneratorTarget->GetExportMacro()) {
+ this->LocalGenerator->AppendDefines(defines, exportMacro);
+ }
+
+ // Add preprocessor definitions for this target and configuration.
+ this->LocalGenerator->AddCompileDefinitions(defines, this->GeneratorTarget,
+ config, language);
+
+ std::string definesString;
+ this->LocalGenerator->JoinDefines(defines, definesString, lang);
+
+ std::map<std::string, std::string>::value_type entry(language,
+ definesString);
+ i = this->DefinesByLanguage.insert(entry).first;
+ }
+ return i->second;
+}
+
+void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::string const&,
+ const std::string& language)
+{
+ std::map<std::string, std::string>::iterator flagsByLangI =
+ this->FlagsByLanguage.find(language);
+ if (flagsByLangI != this->FlagsByLanguage.end()) {
+ if (!flagsByLangI->second.empty()) {
+ *this->GetFolderBuildStreams() << " " << flagsByLangI->second
+ << std::endl;
+ }
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteCompilerDefinitions(
+ const std::string& config, const std::string& language)
+{
+ 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) {
+ *this->GetFolderBuildStreams() << " -D" << (*cdI) << std::endl;
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteIncludes(const std::string& config,
+ const std::string& language)
+{
+ std::vector<std::string> includes;
+ 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) {
+ *this->GetFolderBuildStreams() << " -I\"" << *includes_i << "\""
+ << std::endl;
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteTargetLinkLibraries(
+ std::string const& config, std::string const& language)
+{
+ // library directories
+ cmTargetDependSet tds =
+ this->GetGlobalGenerator()->GetTargetDirectDepends(this->GeneratorTarget);
+ for (cmTargetDependSet::iterator tdsI = tds.begin(); tdsI != tds.end();
+ ++tdsI) {
+ const cmGeneratorTarget* tg = *tdsI;
+ *this->GetFolderBuildStreams() << " -L\"" << GetAbsBuildFilePath(tg)
+ << "\"" << std::endl;
+ }
+ // library targets
+ cmTarget::LinkLibraryVectorType llv =
+ this->GeneratorTarget->Target->GetOriginalLinkLibraries();
+ for (cmTarget::LinkLibraryVectorType::const_iterator llvI = llv.begin();
+ llvI != llv.end(); ++llvI) {
+ std::string libName = llvI->first;
+ // if it is a user defined target get the full path to the lib
+ cmTarget* tg(GetGlobalGenerator()->FindTarget(libName));
+ if (NULL != tg) {
+ libName = tg->GetName() + ".a";
+ }
+ *this->GetFolderBuildStreams() << " -l\"" << libName << "\""
+ << std::endl;
+ }
+
+ if (!this->TargetGroup) {
+ std::string linkLibraries;
+ std::string flags;
+ std::string linkFlags;
+ std::string frameworkPath;
+ std::string linkPath;
+ std::string createRule =
+ this->GeneratorTarget->GetCreateRuleVariable(language, config);
+ bool useWatcomQuote =
+ this->Makefile->IsOn(createRule + "_USE_WATCOM_QUOTE");
+ this->LocalGenerator->GetTargetFlags(
+ config, linkLibraries, flags, linkFlags, frameworkPath, linkPath,
+ this->GeneratorTarget, useWatcomQuote);
+ linkFlags = cmSystemTools::TrimWhitespace(linkFlags);
+
+ if (!linkPath.empty()) {
+ linkPath = " " + linkPath.substr(0U, linkPath.size() - 1U);
+ *this->GetFolderBuildStreams() << linkPath;
+ }
+
+ if (!linkFlags.empty()) {
+ *this->GetFolderBuildStreams() << " " << linkFlags << std::endl;
+ }
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteCustomCommands()
+{
+ WriteCustomCommandsHelper(this->GeneratorTarget->GetPreBuildCommands(),
+ cmTarget::PRE_BUILD);
+ WriteCustomCommandsHelper(this->GeneratorTarget->GetPostBuildCommands(),
+ cmTarget::POST_BUILD);
+}
+
+void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
+ std::vector<cmCustomCommand> const& commandsSet,
+ cmTarget::CustomCommandType const commandType)
+{
+ 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:
+ *this->GetFolderBuildStreams() << " :preexecShellSafe=";
+ break;
+ case cmTarget::POST_BUILD:
+ *this->GetFolderBuildStreams() << " :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()) {
+ *this->GetFolderBuildStreams()
+ << (command.begin() == commandLineI ? "'" : " ");
+ // Need to double escape backslashes
+ cmSystemTools::ReplaceString(subCommandE, "\\", "\\\\");
+ }
+ *this->GetFolderBuildStreams() << subCommandE;
+ }
+ if (!command.empty()) {
+ *this->GetFolderBuildStreams() << "'" << std::endl;
+ }
+ }
+ }
+}
+
+std::map<const cmSourceFile*, std::string>
+cmGhsMultiTargetGenerator::GetObjectNames(
+ std::vector<cmSourceFile*>* const objectSources,
+ cmLocalGhsMultiGenerator* const localGhsMultiGenerator,
+ cmGeneratorTarget* const generatorTarget)
+{
+ std::map<std::string, std::vector<cmSourceFile*> > filenameToSource;
+ std::map<cmSourceFile*, std::string> sourceToFilename;
+ for (std::vector<cmSourceFile*>::const_iterator sf = objectSources->begin();
+ sf != objectSources->end(); ++sf) {
+ const std::string filename =
+ cmSystemTools::GetFilenameName((*sf)->GetFullPath());
+ const std::string lower_filename = cmSystemTools::LowerCase(filename);
+ filenameToSource[lower_filename].push_back(*sf);
+ sourceToFilename[*sf] = lower_filename;
+ }
+
+ std::vector<cmSourceFile*> duplicateSources;
+ for (std::map<std::string, std::vector<cmSourceFile*> >::const_iterator
+ msvSourceI = filenameToSource.begin();
+ msvSourceI != filenameToSource.end(); ++msvSourceI) {
+ if (msvSourceI->second.size() > 1) {
+ duplicateSources.insert(duplicateSources.end(),
+ msvSourceI->second.begin(),
+ msvSourceI->second.end());
+ }
+ }
+
+ std::map<const cmSourceFile*, std::string> objectNamesCorrected;
+
+ for (std::vector<cmSourceFile*>::const_iterator sf =
+ duplicateSources.begin();
+ sf != duplicateSources.end(); ++sf) {
+ std::string const longestObjectDirectory(
+ cmGhsMultiTargetGenerator::ComputeLongestObjectDirectory(
+ localGhsMultiGenerator, generatorTarget, *sf));
+ std::string objFilenameName =
+ localGhsMultiGenerator->GetObjectFileNameWithoutTarget(
+ **sf, longestObjectDirectory);
+ cmsys::SystemTools::ReplaceString(objFilenameName, "/", "_");
+ objectNamesCorrected[*sf] = objFilenameName;
+ }
+
+ return objectNamesCorrected;
+}
+
+void cmGhsMultiTargetGenerator::WriteSources(
+ std::vector<cmSourceFile*> const& objectSources,
+ std::map<const cmSourceFile*, std::string> const& objectNames)
+{
+ for (std::vector<cmSourceFile*>::const_iterator si = objectSources.begin();
+ si != objectSources.end(); ++si) {
+ std::vector<cmSourceGroup> sourceGroups(this->Makefile->GetSourceGroups());
+ char const* sourceFullPath = (*si)->GetFullPath().c_str();
+ cmSourceGroup* sourceGroup =
+ this->Makefile->FindSourceGroup(sourceFullPath, sourceGroups);
+ std::string sgPath(sourceGroup->GetFullName());
+ cmSystemTools::ConvertToUnixSlashes(sgPath);
+ cmGlobalGhsMultiGenerator::AddFilesUpToPath(
+ this->GetFolderBuildStreams(), &this->FolderBuildStreams,
+ this->LocalGenerator->GetBinaryDirectory(), sgPath,
+ GhsMultiGpj::SUBPROJECT, this->RelBuildFilePath);
+
+ std::string fullSourcePath((*si)->GetFullPath());
+ if ((*si)->GetExtension() == "int" || (*si)->GetExtension() == "bsp") {
+ *this->FolderBuildStreams[sgPath] << fullSourcePath << std::endl;
+ } else {
+ // WORKAROUND: GHS MULTI needs the path to use backslashes without quotes
+ // to open files in search as of version 6.1.6
+ cmsys::SystemTools::ReplaceString(fullSourcePath, "/", "\\");
+ *this->FolderBuildStreams[sgPath] << fullSourcePath << std::endl;
+ }
+
+ if ("ld" != (*si)->GetExtension() && "int" != (*si)->GetExtension() &&
+ "bsp" != (*si)->GetExtension()) {
+ this->WriteObjectLangOverride(this->FolderBuildStreams[sgPath], (*si));
+ if (objectNames.end() != objectNames.find(*si)) {
+ *this->FolderBuildStreams[sgPath]
+ << " -o \"" << objectNames.find(*si)->second << "\"" << std::endl;
+ }
+
+ this->WriteObjectDir(this->FolderBuildStreams[sgPath],
+ this->AbsBuildFilePath + sgPath);
+ }
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
+ cmGeneratedFileStream* fileStream, cmSourceFile* sourceFile)
+{
+ const char* rawLangProp = sourceFile->GetProperty("LANGUAGE");
+ if (NULL != rawLangProp) {
+ std::string sourceLangProp(rawLangProp);
+ std::string extension(sourceFile->GetExtension());
+ if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) {
+ *fileStream << " -dotciscxx" << std::endl;
+ }
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteObjectDir(
+ cmGeneratedFileStream* fileStream, std::string const& dir)
+{
+ std::string workingDir(dir);
+ cmSystemTools::ConvertToUnixSlashes(workingDir);
+ if (!workingDir.empty()) {
+ workingDir += "/";
+ }
+ workingDir += "Objs";
+ *fileStream << " -object_dir=\"" << workingDir << "\"" << std::endl;
+}
+
+std::string cmGhsMultiTargetGenerator::GetOutputDirectory(
+ const std::string& config) const
+{
+ std::string outputDir(AbsBuildFilePath);
+
+ const char* runtimeOutputProp =
+ this->GeneratorTarget->GetProperty("RUNTIME_OUTPUT_DIRECTORY");
+ if (NULL != runtimeOutputProp) {
+ outputDir = runtimeOutputProp;
+ }
+
+ std::string configCapped(cmSystemTools::UpperCase(config));
+ const char* runtimeOutputSProp = this->GeneratorTarget->GetProperty(
+ "RUNTIME_OUTPUT_DIRECTORY_" + configCapped);
+ if (NULL != runtimeOutputSProp) {
+ outputDir = runtimeOutputSProp;
+ }
+ cmSystemTools::ConvertToUnixSlashes(outputDir);
+
+ if (!outputDir.empty()) {
+ outputDir += "/";
+ }
+
+ return outputDir;
+}
+
+std::string cmGhsMultiTargetGenerator::GetOutputFilename(
+ const std::string& config) const
+{
+ std::string outputFilename(this->GeneratorTarget->GetName());
+
+ const char* outputNameProp =
+ this->GeneratorTarget->GetProperty("OUTPUT_NAME");
+ if (NULL != outputNameProp) {
+ outputFilename = outputNameProp;
+ }
+
+ std::string configCapped(cmSystemTools::UpperCase(config));
+ const char* outputNameSProp =
+ this->GeneratorTarget->GetProperty(configCapped + "_OUTPUT_NAME");
+ if (NULL != outputNameSProp) {
+ outputFilename = outputNameSProp;
+ }
+
+ return outputFilename;
+}
+
+std::string cmGhsMultiTargetGenerator::ComputeLongestObjectDirectory(
+ cmLocalGhsMultiGenerator const* localGhsMultiGenerator,
+ cmGeneratorTarget* const generatorTarget, cmSourceFile* const sourceFile)
+{
+ std::string dir_max;
+ dir_max +=
+ localGhsMultiGenerator->GetMakefile()->GetCurrentBinaryDirectory();
+ dir_max += "/";
+ dir_max += generatorTarget->Target->GetName();
+ dir_max += "/";
+ std::vector<cmSourceGroup> sourceGroups(
+ localGhsMultiGenerator->GetMakefile()->GetSourceGroups());
+ char const* const sourceFullPath = sourceFile->GetFullPath().c_str();
+ cmSourceGroup* sourceGroup =
+ localGhsMultiGenerator->GetMakefile()->FindSourceGroup(sourceFullPath,
+ sourceGroups);
+ std::string const sgPath(sourceGroup->GetFullName());
+ dir_max += sgPath;
+ dir_max += "/Objs/libs/";
+ dir_max += generatorTarget->Target->GetName();
+ dir_max += "/";
+ return dir_max;
+}
+
+bool cmGhsMultiTargetGenerator::IsNotKernel(std::string const& config,
+ const std::string& language)
+{
+ bool output;
+ std::vector<std::string> options;
+ this->GeneratorTarget->GetCompileOptions(options, config, language);
+ output =
+ options.end() == std::find(options.begin(), options.end(), "-kernel");
+ return output;
+}
+
+bool cmGhsMultiTargetGenerator::DetermineIfTargetGroup(
+ const cmGeneratorTarget* target)
+{
+ bool output = false;
+ std::vector<cmSourceFile*> sources;
+ std::string config =
+ target->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ target->GetSourceFiles(sources, config);
+ for (std::vector<cmSourceFile*>::const_iterator sources_i = sources.begin();
+ sources.end() != sources_i; ++sources_i) {
+ if ("int" == (*sources_i)->GetExtension()) {
+ output = true;
+ }
+ }
+ return output;
+}
+
+bool cmGhsMultiTargetGenerator::DetermineIfDynamicDownload(
+ std::string const& config, const std::string& language)
+{
+ std::vector<std::string> options;
+ bool output = false;
+ this->GeneratorTarget->GetCompileOptions(options, config, language);
+ for (std::vector<std::string>::const_iterator options_i = options.begin();
+ options_i != options.end(); ++options_i) {
+ std::string option = *options_i;
+ if (this->DDOption == option) {
+ output = true;
+ }
+ }
+ return output;
+}
diff --git a/Source/cmGhsMultiTargetGenerator.h b/Source/cmGhsMultiTargetGenerator.h
new file mode 100644
index 0000000..92a1109
--- /dev/null
+++ b/Source/cmGhsMultiTargetGenerator.h
@@ -0,0 +1,129 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Geoffrey Viola <geoffrey.viola@asirobots.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGhsMultiTargetGenerator_h
+#define cmGhsMultiTargetGenerator_h
+
+#include "cmGhsMultiGpj.h"
+
+#include "cmTarget.h"
+
+class cmGeneratedFileStream;
+class cmGlobalGhsMultiGenerator;
+class cmLocalGhsMultiGenerator;
+class cmMakefile;
+class cmSourceFile;
+class cmGeneratedFileStream;
+class cmCustomCommand;
+
+class cmGhsMultiTargetGenerator
+{
+public:
+ cmGhsMultiTargetGenerator(cmGeneratorTarget* target);
+
+ virtual ~cmGhsMultiTargetGenerator();
+
+ virtual void Generate();
+
+ bool IncludeThisTarget();
+ std::vector<cmSourceFile*> GetSources() const;
+ GhsMultiGpj::Types GetGpjTag() const;
+ static GhsMultiGpj::Types GetGpjTag(const cmGeneratorTarget* target);
+ const char* GetAbsBuildFilePath() const
+ {
+ return this->AbsBuildFilePath.c_str();
+ }
+ const char* GetRelBuildFileName() const
+ {
+ return this->RelBuildFileName.c_str();
+ }
+ const char* GetAbsBuildFileName() const
+ {
+ return this->AbsBuildFileName.c_str();
+ }
+ const char* GetAbsOutputFileName() const
+ {
+ return this->AbsOutputFileName.c_str();
+ }
+
+ static std::string GetRelBuildFilePath(const cmGeneratorTarget* target);
+ static std::string GetAbsPathToRoot(const cmGeneratorTarget* target);
+ static std::string GetAbsBuildFilePath(const cmGeneratorTarget* target);
+ static std::string GetRelBuildFileName(const cmGeneratorTarget* target);
+ static std::string GetBuildFileName(const cmGeneratorTarget* target);
+ static std::string AddSlashIfNeededToPath(std::string const& input);
+
+private:
+ cmGlobalGhsMultiGenerator* GetGlobalGenerator() const;
+ cmGeneratedFileStream* GetFolderBuildStreams()
+ {
+ return this->FolderBuildStreams[""];
+ };
+ bool IsTargetGroup() const { return this->TargetGroup; }
+
+ void WriteTypeSpecifics(const std::string& config, bool notKernel);
+ void WriteCompilerFlags(const std::string& config,
+ const std::string& language);
+ void WriteCompilerDefinitions(const std::string& config,
+ const std::string& language);
+
+ void SetCompilerFlags(std::string const& config, const std::string& language,
+ bool const notKernel);
+ std::string GetDefines(const std::string& langugae,
+ std::string const& config);
+
+ void WriteIncludes(const std::string& config, const std::string& language);
+ void WriteTargetLinkLibraries(std::string const& config,
+ std::string const& language);
+ void WriteCustomCommands();
+ void WriteCustomCommandsHelper(
+ std::vector<cmCustomCommand> const& commandsSet,
+ cmTarget::CustomCommandType commandType);
+ void WriteSources(
+ std::vector<cmSourceFile*> const& objectSources,
+ std::map<const cmSourceFile*, std::string> const& objectNames);
+ static std::map<const cmSourceFile*, std::string> GetObjectNames(
+ std::vector<cmSourceFile*>* objectSources,
+ cmLocalGhsMultiGenerator* localGhsMultiGenerator,
+ cmGeneratorTarget* generatorTarget);
+ static void WriteObjectLangOverride(cmGeneratedFileStream* fileStream,
+ cmSourceFile* sourceFile);
+ static void WriteObjectDir(cmGeneratedFileStream* fileStream,
+ std::string const& dir);
+ std::string GetOutputDirectory(const std::string& config) const;
+ std::string GetOutputFilename(const std::string& config) const;
+ static std::string ComputeLongestObjectDirectory(
+ cmLocalGhsMultiGenerator const* localGhsMultiGenerator,
+ cmGeneratorTarget* generatorTarget, cmSourceFile* const sourceFile);
+
+ bool IsNotKernel(std::string const& config, const std::string& language);
+ static bool DetermineIfTargetGroup(const cmGeneratorTarget* target);
+ bool DetermineIfDynamicDownload(std::string const& config,
+ const std::string& language);
+
+ cmGeneratorTarget* GeneratorTarget;
+ cmLocalGhsMultiGenerator* LocalGenerator;
+ cmMakefile* Makefile;
+ std::string AbsBuildFilePath;
+ std::string RelBuildFilePath;
+ std::string AbsBuildFileName;
+ std::string RelBuildFileName;
+ std::string RelOutputFileName;
+ std::string AbsOutputFileName;
+ std::map<std::string, cmGeneratedFileStream*> FolderBuildStreams;
+ bool TargetGroup;
+ bool DynamicDownload;
+ static std::string const DDOption;
+ std::map<std::string, std::string> FlagsByLanguage;
+ std::map<std::string, std::string> DefinesByLanguage;
+};
+
+#endif // ! cmGhsMultiTargetGenerator_h
diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx
new file mode 100644
index 0000000..0f4de73
--- /dev/null
+++ b/Source/cmGlobalBorlandMakefileGenerator.cxx
@@ -0,0 +1,60 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalBorlandMakefileGenerator.h"
+
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmake.h"
+
+cmGlobalBorlandMakefileGenerator::cmGlobalBorlandMakefileGenerator(cmake* cm)
+ : cmGlobalUnixMakefileGenerator3(cm)
+{
+ this->EmptyRuleHackDepends = "NUL";
+ this->FindMakeProgramFile = "CMakeBorlandFindMake.cmake";
+ this->ForceUnixPaths = false;
+ this->ToolSupportsColor = true;
+ this->UseLinkScript = false;
+ cm->GetState()->SetWindowsShell(true);
+ this->IncludeDirective = "!include";
+ this->DefineWindowsNULL = true;
+ this->PassMakeflags = true;
+ this->UnixCD = false;
+}
+
+void cmGlobalBorlandMakefileGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ std::string outdir = this->CMakeInstance->GetHomeOutputDirectory();
+ mf->AddDefinition("BORLAND", "1");
+ mf->AddDefinition("CMAKE_GENERATOR_CC", "bcc32");
+ mf->AddDefinition("CMAKE_GENERATOR_CXX", "bcc32");
+ this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
+}
+
+///! Create a local generator appropriate to this Global Generator
+cmLocalGenerator* cmGlobalBorlandMakefileGenerator::CreateLocalGenerator(
+ cmMakefile* mf)
+{
+ cmLocalUnixMakefileGenerator3* lg =
+ new cmLocalUnixMakefileGenerator3(this, mf);
+ lg->SetMakefileVariableSize(32);
+ lg->SetMakeCommandEscapeTargetTwice(true);
+ lg->SetBorlandMakeCurlyHack(true);
+ return lg;
+}
+
+void cmGlobalBorlandMakefileGenerator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalBorlandMakefileGenerator::GetActualName();
+ entry.Brief = "Generates Borland makefiles.";
+}
diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h
new file mode 100644
index 0000000..4e10f10
--- /dev/null
+++ b/Source/cmGlobalBorlandMakefileGenerator.h
@@ -0,0 +1,56 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalBorlandMakefileGenerator_h
+#define cmGlobalBorlandMakefileGenerator_h
+
+#include "cmGlobalNMakeMakefileGenerator.h"
+
+/** \class cmGlobalBorlandMakefileGenerator
+ * \brief Write a Borland makefiles.
+ *
+ * cmGlobalBorlandMakefileGenerator manages nmake build process for a tree
+ */
+class cmGlobalBorlandMakefileGenerator : public cmGlobalUnixMakefileGenerator3
+{
+public:
+ cmGlobalBorlandMakefileGenerator(cmake* cm);
+ static cmGlobalGeneratorFactory* NewFactory()
+ {
+ return new cmGlobalGeneratorSimpleFactory<
+ cmGlobalBorlandMakefileGenerator>();
+ }
+
+ ///! Get the name for the generator.
+ virtual std::string GetName() const
+ {
+ return cmGlobalBorlandMakefileGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "Borland Makefiles"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ ///! Create a local generator appropriate to this Global Generator
+ virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf);
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+
+ virtual bool AllowNotParallel() const { return false; }
+ virtual bool AllowDeleteOnError() const { return false; }
+};
+
+#endif
diff --git a/Source/cmGlobalCommonGenerator.cxx b/Source/cmGlobalCommonGenerator.cxx
new file mode 100644
index 0000000..900b08e
--- /dev/null
+++ b/Source/cmGlobalCommonGenerator.cxx
@@ -0,0 +1,21 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalCommonGenerator.h"
+
+cmGlobalCommonGenerator::cmGlobalCommonGenerator(cmake* cm)
+ : cmGlobalGenerator(cm)
+{
+}
+
+cmGlobalCommonGenerator::~cmGlobalCommonGenerator()
+{
+}
diff --git a/Source/cmGlobalCommonGenerator.h b/Source/cmGlobalCommonGenerator.h
new file mode 100644
index 0000000..a48ff4f
--- /dev/null
+++ b/Source/cmGlobalCommonGenerator.h
@@ -0,0 +1,27 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalCommonGenerator_h
+#define cmGlobalCommonGenerator_h
+
+#include "cmGlobalGenerator.h"
+
+/** \class cmGlobalCommonGenerator
+ * \brief Common infrastructure for Makefile and Ninja global generators.
+ */
+class cmGlobalCommonGenerator : public cmGlobalGenerator
+{
+public:
+ cmGlobalCommonGenerator(cmake* cm);
+ ~cmGlobalCommonGenerator() CM_OVERRIDE;
+};
+
+#endif
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
new file mode 100644
index 0000000..3ec16c0
--- /dev/null
+++ b/Source/cmGlobalGenerator.cxx
@@ -0,0 +1,2818 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include "windows.h" // this must be first to define GetCurrentDirectory
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#endif
+#endif
+
+#include "cmGlobalGenerator.h"
+
+#include "cmAlgorithms.h"
+#include "cmCPackPropertiesGenerator.h"
+#include "cmComputeTargetDepends.h"
+#include "cmExportBuildFileGenerator.h"
+#include "cmExternalMakefileProjectGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmInstallGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmQtAutoGeneratorInitializer.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmTargetExport.h"
+#include "cmVersion.h"
+#include "cmake.h"
+
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cm_jsoncpp_value.h"
+#include "cm_jsoncpp_writer.h"
+#include <cmsys/MD5.h>
+#endif
+
+#include <stdlib.h> // required for atof
+
+#include <assert.h>
+
+bool cmTarget::StrictTargetComparison::operator()(cmTarget const* t1,
+ cmTarget const* t2) const
+{
+ int nameResult = strcmp(t1->GetName().c_str(), t2->GetName().c_str());
+ if (nameResult == 0) {
+ return strcmp(t1->GetMakefile()->GetCurrentBinaryDirectory(),
+ t2->GetMakefile()->GetCurrentBinaryDirectory()) < 0;
+ }
+ return nameResult < 0;
+}
+
+cmGlobalGenerator::cmGlobalGenerator(cmake* cm)
+ : CMakeInstance(cm)
+{
+ // By default the .SYMBOLIC dependency is not needed on symbolic rules.
+ this->NeedSymbolicMark = false;
+
+ // by default use the native paths
+ this->ForceUnixPaths = false;
+
+ // By default do not try to support color.
+ this->ToolSupportsColor = false;
+
+ // By default do not use link scripts.
+ this->UseLinkScript = false;
+
+ // Whether an install target is needed.
+ this->InstallTargetEnabled = false;
+
+ // how long to let try compiles run
+ this->TryCompileTimeout = 0;
+
+ this->ExtraGenerator = CM_NULLPTR;
+ this->CurrentMakefile = CM_NULLPTR;
+ this->TryCompileOuterMakefile = CM_NULLPTR;
+
+ this->ConfigureDoneCMP0026AndCMP0024 = false;
+
+ cm->GetState()->SetMinGWMake(false);
+ cm->GetState()->SetMSYSShell(false);
+ cm->GetState()->SetNMake(false);
+ cm->GetState()->SetWatcomWMake(false);
+ cm->GetState()->SetWindowsShell(false);
+ cm->GetState()->SetWindowsVSIDE(false);
+}
+
+cmGlobalGenerator::~cmGlobalGenerator()
+{
+ this->ClearGeneratorMembers();
+ delete this->ExtraGenerator;
+}
+
+bool cmGlobalGenerator::SetGeneratorPlatform(std::string const& p,
+ cmMakefile* mf)
+{
+ if (p.empty()) {
+ return true;
+ }
+
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "does not support platform specification, but platform\n"
+ " " << p << "\n"
+ "was specified.";
+ /* clang-format on */
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+}
+
+bool cmGlobalGenerator::SetGeneratorToolset(std::string const& ts,
+ cmMakefile* mf)
+{
+ if (ts.empty()) {
+ return true;
+ }
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "does not support toolset specification, but toolset\n"
+ " " << ts << "\n"
+ "was specified.";
+ /* clang-format on */
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+}
+
+std::string cmGlobalGenerator::SelectMakeProgram(
+ const std::string& inMakeProgram, const std::string& makeDefault) const
+{
+ std::string makeProgram = inMakeProgram;
+ if (cmSystemTools::IsOff(makeProgram.c_str())) {
+ const char* makeProgramCSTR =
+ this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
+ if (cmSystemTools::IsOff(makeProgramCSTR)) {
+ makeProgram = makeDefault;
+ } else {
+ makeProgram = makeProgramCSTR;
+ }
+ if (cmSystemTools::IsOff(makeProgram.c_str()) && !makeProgram.empty()) {
+ makeProgram = "CMAKE_MAKE_PROGRAM-NOTFOUND";
+ }
+ }
+ return makeProgram;
+}
+
+void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang,
+ cmMakefile* mf,
+ bool optional) const
+{
+ std::string langComp = "CMAKE_";
+ langComp += lang;
+ langComp += "_COMPILER";
+
+ if (!mf->GetDefinition(langComp)) {
+ if (!optional) {
+ cmSystemTools::Error(langComp.c_str(), " not set, after EnableLanguage");
+ }
+ return;
+ }
+ const char* name = mf->GetRequiredDefinition(langComp);
+ std::string path;
+ if (!cmSystemTools::FileIsFullPath(name)) {
+ path = cmSystemTools::FindProgram(name);
+ } else {
+ path = name;
+ }
+ if (!optional && (path.empty() || !cmSystemTools::FileExists(path))) {
+ return;
+ }
+ const char* cname =
+ this->GetCMakeInstance()->GetState()->GetInitializedCacheValue(langComp);
+ std::string changeVars;
+ if (cname && !optional) {
+ std::string cnameString;
+ if (!cmSystemTools::FileIsFullPath(cname)) {
+ cnameString = cmSystemTools::FindProgram(cname);
+ } else {
+ cnameString = cname;
+ }
+ std::string pathString = path;
+ // get rid of potentially multiple slashes:
+ cmSystemTools::ConvertToUnixSlashes(cnameString);
+ cmSystemTools::ConvertToUnixSlashes(pathString);
+ if (cnameString != pathString) {
+ const char* cvars =
+ this->GetCMakeInstance()->GetState()->GetGlobalProperty(
+ "__CMAKE_DELETE_CACHE_CHANGE_VARS_");
+ if (cvars) {
+ changeVars += cvars;
+ changeVars += ";";
+ }
+ changeVars += langComp;
+ changeVars += ";";
+ changeVars += cname;
+ this->GetCMakeInstance()->GetState()->SetGlobalProperty(
+ "__CMAKE_DELETE_CACHE_CHANGE_VARS_", changeVars.c_str());
+ }
+ }
+}
+
+void cmGlobalGenerator::AddBuildExportSet(cmExportBuildFileGenerator* gen)
+{
+ this->BuildExportSets[gen->GetMainExportFileName()] = gen;
+}
+
+void cmGlobalGenerator::AddBuildExportExportSet(
+ cmExportBuildFileGenerator* gen)
+{
+ this->BuildExportSets[gen->GetMainExportFileName()] = gen;
+ this->BuildExportExportSets[gen->GetMainExportFileName()] = gen;
+}
+
+bool cmGlobalGenerator::GenerateImportFile(const std::string& file)
+{
+ std::map<std::string, cmExportBuildFileGenerator*>::iterator it =
+ this->BuildExportSets.find(file);
+ if (it != this->BuildExportSets.end()) {
+ bool result = it->second->GenerateImportFile();
+
+ if (!this->ConfigureDoneCMP0026AndCMP0024) {
+ for (std::vector<cmMakefile*>::const_iterator mit =
+ this->Makefiles.begin();
+ mit != this->Makefiles.end(); ++mit) {
+ (*mit)->RemoveExportBuildFileGeneratorCMP0024(it->second);
+ }
+ }
+
+ delete it->second;
+ it->second = CM_NULLPTR;
+ this->BuildExportSets.erase(it);
+ return result;
+ }
+ return false;
+}
+
+void cmGlobalGenerator::ForceLinkerLanguages()
+{
+}
+
+bool cmGlobalGenerator::IsExportedTargetsFile(
+ const std::string& filename) const
+{
+ const std::map<std::string, cmExportBuildFileGenerator*>::const_iterator it =
+ this->BuildExportSets.find(filename);
+ if (it == this->BuildExportSets.end()) {
+ return false;
+ }
+ return this->BuildExportExportSets.find(filename) ==
+ this->BuildExportExportSets.end();
+}
+
+// Find the make program for the generator, required for try compiles
+void cmGlobalGenerator::FindMakeProgram(cmMakefile* mf)
+{
+ if (this->FindMakeProgramFile.empty()) {
+ cmSystemTools::Error(
+ "Generator implementation error, "
+ "all generators must specify this->FindMakeProgramFile");
+ }
+ if (!mf->GetDefinition("CMAKE_MAKE_PROGRAM") ||
+ cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
+ std::string setMakeProgram =
+ mf->GetModulesFile(this->FindMakeProgramFile.c_str());
+ if (!setMakeProgram.empty()) {
+ mf->ReadListFile(setMakeProgram.c_str());
+ }
+ }
+ if (!mf->GetDefinition("CMAKE_MAKE_PROGRAM") ||
+ cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
+ std::ostringstream err;
+ err << "CMake was unable to find a build program corresponding to \""
+ << this->GetName() << "\". CMAKE_MAKE_PROGRAM is not set. You "
+ << "probably need to select a different build tool.";
+ cmSystemTools::Error(err.str().c_str());
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+ std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ // if there are spaces in the make program use short path
+ // but do not short path the actual program name, as
+ // this can cause trouble with VSExpress
+ if (makeProgram.find(' ') != makeProgram.npos) {
+ std::string dir;
+ std::string file;
+ cmSystemTools::SplitProgramPath(makeProgram, dir, file);
+ std::string saveFile = file;
+ cmSystemTools::GetShortPath(makeProgram, makeProgram);
+ cmSystemTools::SplitProgramPath(makeProgram, dir, file);
+ makeProgram = dir;
+ makeProgram += "/";
+ makeProgram += saveFile;
+ mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", makeProgram.c_str(),
+ "make program", cmState::FILEPATH);
+ }
+}
+
+// enable the given language
+//
+// The following files are loaded in this order:
+//
+// First figure out what OS we are running on:
+//
+// CMakeSystem.cmake - configured file created by CMakeDetermineSystem.cmake
+// CMakeDetermineSystem.cmake - figure out os info and create
+// CMakeSystem.cmake IF CMAKE_SYSTEM
+// not set
+// CMakeSystem.cmake - configured file created by
+// CMakeDetermineSystem.cmake IF CMAKE_SYSTEM_LOADED
+
+// CMakeSystemSpecificInitialize.cmake
+// - includes Platform/${CMAKE_SYSTEM_NAME}-Initialize.cmake
+
+// Next try and enable all languages found in the languages vector
+//
+// FOREACH LANG in languages
+// CMake(LANG)Compiler.cmake - configured file create by
+// CMakeDetermine(LANG)Compiler.cmake
+// CMakeDetermine(LANG)Compiler.cmake - Finds compiler for LANG and
+// creates CMake(LANG)Compiler.cmake
+// CMake(LANG)Compiler.cmake - configured file created by
+// CMakeDetermine(LANG)Compiler.cmake
+//
+// CMakeSystemSpecificInformation.cmake
+// - includes Platform/${CMAKE_SYSTEM_NAME}.cmake
+// may use compiler stuff
+
+// FOREACH LANG in languages
+// CMake(LANG)Information.cmake
+// - loads Platform/${CMAKE_SYSTEM_NAME}-${COMPILER}.cmake
+// CMakeTest(LANG)Compiler.cmake
+// - Make sure the compiler works with a try compile if
+// CMakeDetermine(LANG) was loaded
+//
+// Now load a few files that can override values set in any of the above
+// (PROJECTNAME)Compatibility.cmake
+// - load any backwards compatibility stuff for current project
+// ${CMAKE_USER_MAKE_RULES_OVERRIDE}
+// - allow users a chance to override system variables
+//
+//
+
+void cmGlobalGenerator::EnableLanguage(
+ std::vector<std::string> const& languages, cmMakefile* mf, bool optional)
+{
+ if (languages.empty()) {
+ cmSystemTools::Error("EnableLanguage must have a lang specified!");
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+
+ std::set<std::string> cur_languages(languages.begin(), languages.end());
+ for (std::set<std::string>::iterator li = cur_languages.begin();
+ li != cur_languages.end(); ++li) {
+ if (!this->LanguagesInProgress.insert(*li).second) {
+ std::ostringstream e;
+ e << "Language '" << *li << "' is currently being enabled. "
+ "Recursive call not allowed.";
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+ }
+
+ if (this->TryCompileOuterMakefile) {
+ // In a try-compile we can only enable languages provided by caller.
+ for (std::vector<std::string>::const_iterator li = languages.begin();
+ li != languages.end(); ++li) {
+ if (*li == "NONE") {
+ this->SetLanguageEnabled("NONE", mf);
+ } else {
+ const char* lang = li->c_str();
+ if (this->LanguagesReady.find(lang) == this->LanguagesReady.end()) {
+ std::ostringstream e;
+ e << "The test project needs language " << lang
+ << " which is not enabled.";
+ this->TryCompileOuterMakefile->IssueMessage(cmake::FATAL_ERROR,
+ e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+ }
+ }
+ }
+
+ bool fatalError = false;
+
+ mf->AddDefinition("RUN_CONFIGURE", true);
+ std::string rootBin = this->CMakeInstance->GetHomeOutputDirectory();
+ rootBin += cmake::GetCMakeFilesDirectory();
+
+ // If the configuration files path has been set,
+ // then we are in a try compile and need to copy the enable language
+ // files from the parent cmake bin dir, into the try compile bin dir
+ if (!this->ConfiguredFilesPath.empty()) {
+ rootBin = this->ConfiguredFilesPath;
+ }
+ rootBin += "/";
+ rootBin += cmVersion::GetCMakeVersion();
+
+ // set the dir for parent files so they can be used by modules
+ mf->AddDefinition("CMAKE_PLATFORM_INFO_DIR", rootBin.c_str());
+
+ // find and make sure CMAKE_MAKE_PROGRAM is defined
+ this->FindMakeProgram(mf);
+
+ // try and load the CMakeSystem.cmake if it is there
+ std::string fpath = rootBin;
+ bool const readCMakeSystem = !mf->GetDefinition("CMAKE_SYSTEM_LOADED");
+ if (readCMakeSystem) {
+ fpath += "/CMakeSystem.cmake";
+ if (cmSystemTools::FileExists(fpath.c_str())) {
+ mf->ReadListFile(fpath.c_str());
+ }
+ }
+ // Load the CMakeDetermineSystem.cmake file and find out
+ // what platform we are running on
+ if (!mf->GetDefinition("CMAKE_SYSTEM")) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ /* Windows version number data. */
+ OSVERSIONINFOEXW osviex;
+ ZeroMemory(&osviex, sizeof(osviex));
+ osviex.dwOSVersionInfoSize = sizeof(osviex);
+
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#pragma warning(push)
+#pragma warning(disable : 4996)
+#endif
+ GetVersionExW((OSVERSIONINFOW*)&osviex);
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#pragma warning(pop)
+#endif
+ std::ostringstream windowsVersionString;
+ windowsVersionString << osviex.dwMajorVersion << "."
+ << osviex.dwMinorVersion << "."
+ << osviex.dwBuildNumber;
+ windowsVersionString.str();
+ mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION",
+ windowsVersionString.str().c_str());
+#endif
+ // Read the DetermineSystem file
+ std::string systemFile = mf->GetModulesFile("CMakeDetermineSystem.cmake");
+ mf->ReadListFile(systemFile.c_str());
+ // load the CMakeSystem.cmake from the binary directory
+ // this file is configured by the CMakeDetermineSystem.cmake file
+ fpath = rootBin;
+ fpath += "/CMakeSystem.cmake";
+ mf->ReadListFile(fpath.c_str());
+ }
+
+ if (readCMakeSystem) {
+ // Tell the generator about the target system.
+ std::string system = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME");
+ if (!this->SetSystemName(system, mf)) {
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+
+ // Tell the generator about the platform, if any.
+ std::string platform = mf->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM");
+ if (!this->SetGeneratorPlatform(platform, mf)) {
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+
+ // Tell the generator about the toolset, if any.
+ std::string toolset = mf->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET");
+ if (!this->SetGeneratorToolset(toolset, mf)) {
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+ }
+
+ // **** Load the system specific initialization if not yet loaded
+ if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INITIALIZE_LOADED")) {
+ fpath = mf->GetModulesFile("CMakeSystemSpecificInitialize.cmake");
+ if (!mf->ReadListFile(fpath.c_str())) {
+ cmSystemTools::Error("Could not find cmake module file: "
+ "CMakeSystemSpecificInitialize.cmake");
+ }
+ }
+
+ std::map<std::string, bool> needTestLanguage;
+ std::map<std::string, bool> needSetLanguageEnabledMaps;
+ // foreach language
+ // load the CMakeDetermine(LANG)Compiler.cmake file to find
+ // the compiler
+
+ for (std::vector<std::string>::const_iterator l = languages.begin();
+ l != languages.end(); ++l) {
+ const char* lang = l->c_str();
+ needSetLanguageEnabledMaps[lang] = false;
+ if (*l == "NONE") {
+ this->SetLanguageEnabled("NONE", mf);
+ continue;
+ }
+ std::string loadedLang = "CMAKE_";
+ loadedLang += lang;
+ loadedLang += "_COMPILER_LOADED";
+ if (!mf->GetDefinition(loadedLang)) {
+ fpath = rootBin;
+ fpath += "/CMake";
+ fpath += lang;
+ fpath += "Compiler.cmake";
+
+ // If the existing build tree was already configured with this
+ // version of CMake then try to load the configured file first
+ // to avoid duplicate compiler tests.
+ if (cmSystemTools::FileExists(fpath.c_str())) {
+ if (!mf->ReadListFile(fpath.c_str())) {
+ cmSystemTools::Error("Could not find cmake module file: ",
+ fpath.c_str());
+ }
+ // if this file was found then the language was already determined
+ // to be working
+ needTestLanguage[lang] = false;
+ this->SetLanguageEnabledFlag(lang, mf);
+ needSetLanguageEnabledMaps[lang] = true;
+ // this can only be called after loading CMake(LANG)Compiler.cmake
+ }
+ }
+
+ if (!this->GetLanguageEnabled(lang)) {
+ if (this->CMakeInstance->GetIsInTryCompile()) {
+ cmSystemTools::Error("This should not have happened. "
+ "If you see this message, you are probably "
+ "using a broken CMakeLists.txt file or a "
+ "problematic release of CMake");
+ }
+ // if the CMake(LANG)Compiler.cmake file was not found then
+ // load CMakeDetermine(LANG)Compiler.cmake
+ std::string determineCompiler = "CMakeDetermine";
+ determineCompiler += lang;
+ determineCompiler += "Compiler.cmake";
+ std::string determineFile =
+ mf->GetModulesFile(determineCompiler.c_str());
+ if (!mf->ReadListFile(determineFile.c_str())) {
+ cmSystemTools::Error("Could not find cmake module file: ",
+ determineCompiler.c_str());
+ }
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return;
+ }
+ needTestLanguage[lang] = true;
+ // Some generators like visual studio should not use the env variables
+ // So the global generator can specify that in this variable
+ if (!mf->GetDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV")) {
+ // put ${CMake_(LANG)_COMPILER_ENV_VAR}=${CMAKE_(LANG)_COMPILER
+ // into the environment, in case user scripts want to run
+ // configure, or sub cmakes
+ std::string compilerName = "CMAKE_";
+ compilerName += lang;
+ compilerName += "_COMPILER";
+ std::string compilerEnv = "CMAKE_";
+ compilerEnv += lang;
+ compilerEnv += "_COMPILER_ENV_VAR";
+ std::string envVar = mf->GetRequiredDefinition(compilerEnv);
+ std::string envVarValue = mf->GetRequiredDefinition(compilerName);
+ std::string env = envVar;
+ env += "=";
+ env += envVarValue;
+ cmSystemTools::PutEnv(env);
+ }
+
+ // if determineLanguage was called then load the file it
+ // configures CMake(LANG)Compiler.cmake
+ fpath = rootBin;
+ fpath += "/CMake";
+ fpath += lang;
+ fpath += "Compiler.cmake";
+ if (!mf->ReadListFile(fpath.c_str())) {
+ cmSystemTools::Error("Could not find cmake module file: ",
+ fpath.c_str());
+ }
+ this->SetLanguageEnabledFlag(lang, mf);
+ needSetLanguageEnabledMaps[lang] = true;
+ // this can only be called after loading CMake(LANG)Compiler.cmake
+ // the language must be enabled for try compile to work, but we do
+ // not know if it is a working compiler yet so set the test language
+ // flag
+ needTestLanguage[lang] = true;
+ } // end if(!this->GetLanguageEnabled(lang) )
+ } // end loop over languages
+
+ // **** Load the system specific information if not yet loaded
+ if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INFORMATION_LOADED")) {
+ fpath = mf->GetModulesFile("CMakeSystemSpecificInformation.cmake");
+ if (!mf->ReadListFile(fpath.c_str())) {
+ cmSystemTools::Error("Could not find cmake module file: "
+ "CMakeSystemSpecificInformation.cmake");
+ }
+ }
+ // loop over languages again loading CMake(LANG)Information.cmake
+ //
+ for (std::vector<std::string>::const_iterator l = languages.begin();
+ l != languages.end(); ++l) {
+ const char* lang = l->c_str();
+ if (*l == "NONE") {
+ this->SetLanguageEnabled("NONE", mf);
+ continue;
+ }
+
+ // Check that the compiler was found.
+ std::string compilerName = "CMAKE_";
+ compilerName += lang;
+ compilerName += "_COMPILER";
+ std::string compilerEnv = "CMAKE_";
+ compilerEnv += lang;
+ compilerEnv += "_COMPILER_ENV_VAR";
+ std::ostringstream noCompiler;
+ const char* compilerFile = mf->GetDefinition(compilerName);
+ if (!compilerFile || !*compilerFile ||
+ cmSystemTools::IsNOTFOUND(compilerFile)) {
+ /* clang-format off */
+ noCompiler <<
+ "No " << compilerName << " could be found.\n"
+ ;
+ /* clang-format on */
+ } else if (strcmp(lang, "RC") != 0 && strcmp(lang, "ASM_MASM") != 0) {
+ if (!cmSystemTools::FileIsFullPath(compilerFile)) {
+ /* clang-format off */
+ noCompiler <<
+ "The " << compilerName << ":\n"
+ " " << compilerFile << "\n"
+ "is not a full path and was not found in the PATH.\n"
+ ;
+ /* clang-format on */
+ } else if (!cmSystemTools::FileExists(compilerFile)) {
+ /* clang-format off */
+ noCompiler <<
+ "The " << compilerName << ":\n"
+ " " << compilerFile << "\n"
+ "is not a full path to an existing compiler tool.\n"
+ ;
+ /* clang-format on */
+ }
+ }
+ if (!noCompiler.str().empty()) {
+ // Skip testing this language since the compiler is not found.
+ needTestLanguage[lang] = false;
+ if (!optional) {
+ // The compiler was not found and it is not optional. Remove
+ // CMake(LANG)Compiler.cmake so we try again next time CMake runs.
+ std::string compilerLangFile = rootBin;
+ compilerLangFile += "/CMake";
+ compilerLangFile += lang;
+ compilerLangFile += "Compiler.cmake";
+ cmSystemTools::RemoveFile(compilerLangFile);
+ if (!this->CMakeInstance->GetIsInTryCompile()) {
+ this->PrintCompilerAdvice(noCompiler, lang,
+ mf->GetDefinition(compilerEnv));
+ mf->IssueMessage(cmake::FATAL_ERROR, noCompiler.str());
+ fatalError = true;
+ }
+ }
+ }
+
+ std::string langLoadedVar = "CMAKE_";
+ langLoadedVar += lang;
+ langLoadedVar += "_INFORMATION_LOADED";
+ if (!mf->GetDefinition(langLoadedVar)) {
+ fpath = "CMake";
+ fpath += lang;
+ fpath += "Information.cmake";
+ std::string informationFile = mf->GetModulesFile(fpath.c_str());
+ if (informationFile.empty()) {
+ cmSystemTools::Error("Could not find cmake module file: ",
+ fpath.c_str());
+ } else if (!mf->ReadListFile(informationFile.c_str())) {
+ cmSystemTools::Error("Could not process cmake module file: ",
+ informationFile.c_str());
+ }
+ }
+ if (needSetLanguageEnabledMaps[lang]) {
+ this->SetLanguageEnabledMaps(lang, mf);
+ }
+ this->LanguagesReady.insert(lang);
+
+ // Test the compiler for the language just setup
+ // (but only if a compiler has been actually found)
+ // At this point we should have enough info for a try compile
+ // which is used in the backward stuff
+ // If the language is untested then test it now with a try compile.
+ if (needTestLanguage[lang]) {
+ if (!this->CMakeInstance->GetIsInTryCompile()) {
+ std::string testLang = "CMakeTest";
+ testLang += lang;
+ testLang += "Compiler.cmake";
+ std::string ifpath = mf->GetModulesFile(testLang.c_str());
+ if (!mf->ReadListFile(ifpath.c_str())) {
+ cmSystemTools::Error("Could not find cmake module file: ",
+ testLang.c_str());
+ }
+ std::string compilerWorks = "CMAKE_";
+ compilerWorks += lang;
+ compilerWorks += "_COMPILER_WORKS";
+ // if the compiler did not work, then remove the
+ // CMake(LANG)Compiler.cmake file so that it will get tested the
+ // next time cmake is run
+ if (!mf->IsOn(compilerWorks)) {
+ std::string compilerLangFile = rootBin;
+ compilerLangFile += "/CMake";
+ compilerLangFile += lang;
+ compilerLangFile += "Compiler.cmake";
+ cmSystemTools::RemoveFile(compilerLangFile);
+ }
+ } // end if in try compile
+ } // end need test language
+ // Store the shared library flags so that we can satisfy CMP0018
+ std::string sharedLibFlagsVar = "CMAKE_SHARED_LIBRARY_";
+ sharedLibFlagsVar += lang;
+ sharedLibFlagsVar += "_FLAGS";
+ const char* sharedLibFlags = mf->GetSafeDefinition(sharedLibFlagsVar);
+ if (sharedLibFlags) {
+ this->LanguageToOriginalSharedLibFlags[lang] = sharedLibFlags;
+ }
+
+ // Translate compiler ids for compatibility.
+ this->CheckCompilerIdCompatibility(mf, lang);
+ } // end for each language
+
+ // Now load files that can override any settings on the platform or for
+ // the project First load the project compatibility file if it is in
+ // cmake
+ std::string projectCompatibility = cmSystemTools::GetCMakeRoot();
+ projectCompatibility += "/Modules/";
+ projectCompatibility += mf->GetSafeDefinition("PROJECT_NAME");
+ projectCompatibility += "Compatibility.cmake";
+ if (cmSystemTools::FileExists(projectCompatibility.c_str())) {
+ mf->ReadListFile(projectCompatibility.c_str());
+ }
+ // Inform any extra generator of the new language.
+ if (this->ExtraGenerator) {
+ this->ExtraGenerator->EnableLanguage(languages, mf, false);
+ }
+
+ if (fatalError) {
+ cmSystemTools::SetFatalErrorOccured();
+ }
+
+ for (std::set<std::string>::iterator li = cur_languages.begin();
+ li != cur_languages.end(); ++li) {
+ this->LanguagesInProgress.erase(*li);
+ }
+}
+
+void cmGlobalGenerator::PrintCompilerAdvice(std::ostream& os,
+ std::string const& lang,
+ const char* envVar) const
+{
+ // Subclasses override this method if they do not support this advice.
+ os << "Tell CMake where to find the compiler by setting ";
+ if (envVar) {
+ os << "either the environment variable \"" << envVar << "\" or ";
+ }
+ os << "the CMake cache entry CMAKE_" << lang
+ << "_COMPILER "
+ "to the full path to the compiler, or to the compiler name "
+ "if it is in the PATH.";
+}
+
+void cmGlobalGenerator::CheckCompilerIdCompatibility(
+ cmMakefile* mf, std::string const& lang) const
+{
+ std::string compilerIdVar = "CMAKE_" + lang + "_COMPILER_ID";
+ const char* compilerId = mf->GetDefinition(compilerIdVar);
+ if (!compilerId) {
+ return;
+ }
+
+ if (strcmp(compilerId, "AppleClang") == 0) {
+ switch (mf->GetPolicyStatus(cmPolicies::CMP0025)) {
+ case cmPolicies::WARN:
+ if (!this->CMakeInstance->GetIsInTryCompile() &&
+ mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0025")) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0025) << "\n"
+ "Converting " << lang <<
+ " compiler id \"AppleClang\" to \"Clang\" for compatibility."
+ ;
+ /* clang-format on */
+ mf->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ }
+ case cmPolicies::OLD:
+ // OLD behavior is to convert AppleClang to Clang.
+ mf->AddDefinition(compilerIdVar, "Clang");
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ mf->IssueMessage(
+ cmake::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0025));
+ case cmPolicies::NEW:
+ // NEW behavior is to keep AppleClang.
+ break;
+ }
+ }
+
+ if (strcmp(compilerId, "QCC") == 0) {
+ switch (mf->GetPolicyStatus(cmPolicies::CMP0047)) {
+ case cmPolicies::WARN:
+ if (!this->CMakeInstance->GetIsInTryCompile() &&
+ mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0047")) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0047) << "\n"
+ "Converting " << lang <<
+ " compiler id \"QCC\" to \"GNU\" for compatibility."
+ ;
+ /* clang-format on */
+ mf->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ }
+ case cmPolicies::OLD:
+ // OLD behavior is to convert QCC to GNU.
+ mf->AddDefinition(compilerIdVar, "GNU");
+ if (lang == "C") {
+ mf->AddDefinition("CMAKE_COMPILER_IS_GNUCC", "1");
+ } else if (lang == "CXX") {
+ mf->AddDefinition("CMAKE_COMPILER_IS_GNUCXX", "1");
+ }
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ mf->IssueMessage(
+ cmake::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0047));
+ case cmPolicies::NEW:
+ // NEW behavior is to keep QCC.
+ break;
+ }
+ }
+}
+
+std::string cmGlobalGenerator::GetLanguageOutputExtension(
+ cmSourceFile const& source) const
+{
+ const std::string& lang = source.GetLanguage();
+ if (!lang.empty()) {
+ std::map<std::string, std::string>::const_iterator it =
+ this->LanguageToOutputExtension.find(lang);
+
+ if (it != this->LanguageToOutputExtension.end()) {
+ return it->second;
+ }
+ } else {
+ // if no language is found then check to see if it is already an
+ // ouput extension for some language. In that case it should be ignored
+ // and in this map, so it will not be compiled but will just be used.
+ std::string const& ext = source.GetExtension();
+ if (!ext.empty()) {
+ if (this->OutputExtensions.count(ext)) {
+ return ext;
+ }
+ }
+ }
+ return "";
+}
+
+std::string cmGlobalGenerator::GetLanguageFromExtension(const char* ext) const
+{
+ // if there is an extension and it starts with . then move past the
+ // . because the extensions are not stored with a . in the map
+ if (ext && *ext == '.') {
+ ++ext;
+ }
+ std::map<std::string, std::string>::const_iterator it =
+ this->ExtensionToLanguage.find(ext);
+ if (it != this->ExtensionToLanguage.end()) {
+ return it->second;
+ }
+ return "";
+}
+
+/* SetLanguageEnabled() is now split in two parts:
+at first the enabled-flag is set. This can then be used in EnabledLanguage()
+for checking whether the language is already enabled. After setting this
+flag still the values from the cmake variables have to be copied into the
+internal maps, this is done in SetLanguageEnabledMaps() which is called
+after the system- and compiler specific files have been loaded.
+
+This split was done originally so that compiler-specific configuration
+files could change the object file extension
+(CMAKE_<LANG>_OUTPUT_EXTENSION) before the CMake variables were copied
+to the C++ maps.
+*/
+void cmGlobalGenerator::SetLanguageEnabled(const std::string& l,
+ cmMakefile* mf)
+{
+ this->SetLanguageEnabledFlag(l, mf);
+ this->SetLanguageEnabledMaps(l, mf);
+}
+
+void cmGlobalGenerator::SetLanguageEnabledFlag(const std::string& l,
+ cmMakefile* mf)
+{
+ this->CMakeInstance->GetState()->SetLanguageEnabled(l);
+
+ // Fill the language-to-extension map with the current variable
+ // settings to make sure it is available for the try_compile()
+ // command source file signature. In SetLanguageEnabledMaps this
+ // will be done again to account for any compiler- or
+ // platform-specific entries.
+ this->FillExtensionToLanguageMap(l, mf);
+}
+
+void cmGlobalGenerator::SetLanguageEnabledMaps(const std::string& l,
+ cmMakefile* mf)
+{
+ // use LanguageToLinkerPreference to detect whether this functions has
+ // run before
+ if (this->LanguageToLinkerPreference.find(l) !=
+ this->LanguageToLinkerPreference.end()) {
+ return;
+ }
+
+ std::string linkerPrefVar =
+ std::string("CMAKE_") + std::string(l) + std::string("_LINKER_PREFERENCE");
+ const char* linkerPref = mf->GetDefinition(linkerPrefVar);
+ int preference = 0;
+ if (linkerPref) {
+ if (sscanf(linkerPref, "%d", &preference) != 1) {
+ // backward compatibility: before 2.6 LINKER_PREFERENCE
+ // was either "None" or "Preferred", and only the first character was
+ // tested. So if there is a custom language out there and it is
+ // "Preferred", set its preference high
+ if (linkerPref[0] == 'P') {
+ preference = 100;
+ } else {
+ preference = 0;
+ }
+ }
+ }
+
+ if (preference < 0) {
+ std::string msg = linkerPrefVar;
+ msg += " is negative, adjusting it to 0";
+ cmSystemTools::Message(msg.c_str(), "Warning");
+ preference = 0;
+ }
+
+ this->LanguageToLinkerPreference[l] = preference;
+
+ std::string outputExtensionVar =
+ std::string("CMAKE_") + std::string(l) + std::string("_OUTPUT_EXTENSION");
+ const char* outputExtension = mf->GetDefinition(outputExtensionVar);
+ if (outputExtension) {
+ this->LanguageToOutputExtension[l] = outputExtension;
+ this->OutputExtensions[outputExtension] = outputExtension;
+ if (outputExtension[0] == '.') {
+ this->OutputExtensions[outputExtension + 1] = outputExtension + 1;
+ }
+ }
+
+ // The map was originally filled by SetLanguageEnabledFlag, but
+ // since then the compiler- and platform-specific files have been
+ // loaded which might have added more entries.
+ this->FillExtensionToLanguageMap(l, mf);
+
+ std::string ignoreExtensionsVar =
+ std::string("CMAKE_") + std::string(l) + std::string("_IGNORE_EXTENSIONS");
+ std::string ignoreExts = mf->GetSafeDefinition(ignoreExtensionsVar);
+ std::vector<std::string> extensionList;
+ cmSystemTools::ExpandListArgument(ignoreExts, extensionList);
+ for (std::vector<std::string>::iterator i = extensionList.begin();
+ i != extensionList.end(); ++i) {
+ this->IgnoreExtensions[*i] = true;
+ }
+}
+
+void cmGlobalGenerator::FillExtensionToLanguageMap(const std::string& l,
+ cmMakefile* mf)
+{
+ std::string extensionsVar = std::string("CMAKE_") + std::string(l) +
+ std::string("_SOURCE_FILE_EXTENSIONS");
+ std::string exts = mf->GetSafeDefinition(extensionsVar);
+ std::vector<std::string> extensionList;
+ cmSystemTools::ExpandListArgument(exts, extensionList);
+ for (std::vector<std::string>::iterator i = extensionList.begin();
+ i != extensionList.end(); ++i) {
+ this->ExtensionToLanguage[*i] = l;
+ }
+}
+
+bool cmGlobalGenerator::IgnoreFile(const char* ext) const
+{
+ if (!this->GetLanguageFromExtension(ext).empty()) {
+ return false;
+ }
+ return (this->IgnoreExtensions.count(ext) > 0);
+}
+
+bool cmGlobalGenerator::GetLanguageEnabled(const std::string& l) const
+{
+ return this->CMakeInstance->GetState()->GetLanguageEnabled(l);
+}
+
+void cmGlobalGenerator::ClearEnabledLanguages()
+{
+ return this->CMakeInstance->GetState()->ClearEnabledLanguages();
+}
+
+void cmGlobalGenerator::CreateLocalGenerators()
+{
+ cmDeleteAll(this->LocalGenerators);
+ this->LocalGenerators.clear();
+ this->LocalGenerators.reserve(this->Makefiles.size());
+ for (std::vector<cmMakefile*>::const_iterator it = this->Makefiles.begin();
+ it != this->Makefiles.end(); ++it) {
+ this->LocalGenerators.push_back(this->CreateLocalGenerator(*it));
+ }
+}
+
+void cmGlobalGenerator::Configure()
+{
+ this->FirstTimeProgress = 0.0f;
+ this->ClearGeneratorMembers();
+
+ cmState::Snapshot snapshot = this->CMakeInstance->GetCurrentSnapshot();
+
+ snapshot.GetDirectory().SetCurrentSource(
+ this->CMakeInstance->GetHomeDirectory());
+ snapshot.GetDirectory().SetCurrentBinary(
+ this->CMakeInstance->GetHomeOutputDirectory());
+
+ cmMakefile* dirMf = new cmMakefile(this, snapshot);
+ this->Makefiles.push_back(dirMf);
+
+ this->BinaryDirectories.insert(
+ this->CMakeInstance->GetHomeOutputDirectory());
+
+ // now do it
+ this->ConfigureDoneCMP0026AndCMP0024 = false;
+ dirMf->Configure();
+ dirMf->EnforceDirectoryLevelRules();
+
+ this->ConfigureDoneCMP0026AndCMP0024 = true;
+
+ // Put a copy of each global target in every directory.
+ cmTargets globalTargets;
+ this->CreateDefaultGlobalTargets(&globalTargets);
+
+ for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
+ cmMakefile* mf = this->Makefiles[i];
+ cmTargets* targets = &(mf->GetTargets());
+ cmTargets::iterator tit;
+ for (tit = globalTargets.begin(); tit != globalTargets.end(); ++tit) {
+ (*targets)[tit->first] = tit->second;
+ (*targets)[tit->first].SetMakefile(mf);
+ }
+ }
+
+ // update the cache entry for the number of local generators, this is used
+ // for progress
+ char num[100];
+ sprintf(num, "%d", static_cast<int>(this->Makefiles.size()));
+ this->GetCMakeInstance()->AddCacheEntry("CMAKE_NUMBER_OF_MAKEFILES", num,
+ "number of local generators",
+ cmState::INTERNAL);
+
+ // check for link libraries and include directories containing "NOTFOUND"
+ // and for infinite loops
+ this->CheckTargetProperties();
+
+ if (this->CMakeInstance->GetWorkingMode() == cmake::NORMAL_MODE) {
+ std::ostringstream msg;
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ msg << "Configuring incomplete, errors occurred!";
+ const char* logs[] = { "CMakeOutput.log", "CMakeError.log", CM_NULLPTR };
+ for (const char** log = logs; *log; ++log) {
+ std::string f = this->CMakeInstance->GetHomeOutputDirectory();
+ f += this->CMakeInstance->GetCMakeFilesDirectory();
+ f += "/";
+ f += *log;
+ if (cmSystemTools::FileExists(f.c_str())) {
+ msg << "\nSee also \"" << f << "\".";
+ }
+ }
+ } else {
+ msg << "Configuring done";
+ }
+ this->CMakeInstance->UpdateProgress(msg.str().c_str(), -1);
+ }
+}
+
+void cmGlobalGenerator::CreateGenerationObjects(TargetTypes targetTypes)
+{
+ this->CreateLocalGenerators();
+ this->CreateGeneratorTargets(targetTypes);
+ this->ComputeBuildFileGenerators();
+}
+
+void cmGlobalGenerator::CreateImportedGenerationObjects(
+ cmMakefile* mf, const std::vector<std::string>& targets,
+ std::vector<const cmGeneratorTarget*>& exports)
+{
+ this->CreateGenerationObjects(ImportedOnly);
+ std::vector<cmMakefile*>::iterator mfit =
+ std::find(this->Makefiles.begin(), this->Makefiles.end(), mf);
+ cmLocalGenerator* lg =
+ this->LocalGenerators[std::distance(this->Makefiles.begin(), mfit)];
+ for (std::vector<std::string>::const_iterator it = targets.begin();
+ it != targets.end(); ++it) {
+ cmGeneratorTarget* gt = lg->FindGeneratorTargetToUse(*it);
+ if (gt) {
+ exports.push_back(gt);
+ }
+ }
+}
+
+cmExportBuildFileGenerator* cmGlobalGenerator::GetExportedTargetsFile(
+ const std::string& filename) const
+{
+ std::map<std::string, cmExportBuildFileGenerator*>::const_iterator it =
+ this->BuildExportSets.find(filename);
+ return it == this->BuildExportSets.end() ? CM_NULLPTR : it->second;
+}
+
+void cmGlobalGenerator::AddCMP0042WarnTarget(const std::string& target)
+{
+ this->CMP0042WarnTargets.insert(target);
+}
+
+bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const
+{
+ // If the property is not enabled then okay.
+ if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
+ "ALLOW_DUPLICATE_CUSTOM_TARGETS")) {
+ return true;
+ }
+
+ // This generator does not support duplicate custom targets.
+ std::ostringstream e;
+ e << "This project has enabled the ALLOW_DUPLICATE_CUSTOM_TARGETS "
+ << "global property. "
+ << "The \"" << this->GetName() << "\" generator does not support "
+ << "duplicate custom targets. "
+ << "Consider using a Makefiles generator or fix the project to not "
+ << "use duplicate target names.";
+ cmSystemTools::Error(e.str().c_str());
+ return false;
+}
+
+void cmGlobalGenerator::ComputeBuildFileGenerators()
+{
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ std::vector<cmExportBuildFileGenerator*> gens =
+ this->Makefiles[i]->GetExportBuildFileGenerators();
+ for (std::vector<cmExportBuildFileGenerator*>::const_iterator it =
+ gens.begin();
+ it != gens.end(); ++it) {
+ (*it)->Compute(this->LocalGenerators[i]);
+ }
+ }
+}
+
+bool cmGlobalGenerator::Compute()
+{
+ // Some generators track files replaced during the Generate.
+ // Start with an empty vector:
+ this->FilesReplacedDuringGenerate.clear();
+
+ // clear targets to issue warning CMP0042 for
+ this->CMP0042WarnTargets.clear();
+
+ // Check whether this generator is allowed to run.
+ if (!this->CheckALLOW_DUPLICATE_CUSTOM_TARGETS()) {
+ return false;
+ }
+ this->FinalizeTargetCompileInfo();
+
+ this->CreateGenerationObjects();
+
+ // at this point this->LocalGenerators has been filled,
+ // so create the map from project name to vector of local generators
+ this->FillProjectMap();
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ // Iterate through all targets and set up automoc for those which have
+ // the AUTOMOC, AUTOUIC or AUTORCC property set
+ std::vector<cmGeneratorTarget const*> autogenTargets =
+ this->CreateQtAutoGeneratorsTargets();
+#endif
+
+ unsigned int i;
+
+ // Add generator specific helper commands
+ for (i = 0; i < this->LocalGenerators.size(); ++i) {
+ this->LocalGenerators[i]->AddHelperCommands();
+ }
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ for (std::vector<cmGeneratorTarget const*>::iterator it =
+ autogenTargets.begin();
+ it != autogenTargets.end(); ++it) {
+ cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(*it);
+ }
+#endif
+
+ for (i = 0; i < this->LocalGenerators.size(); ++i) {
+ cmMakefile* mf = this->LocalGenerators[i]->GetMakefile();
+ std::vector<cmInstallGenerator*>& gens = mf->GetInstallGenerators();
+ for (std::vector<cmInstallGenerator*>::const_iterator git = gens.begin();
+ git != gens.end(); ++git) {
+ (*git)->Compute(this->LocalGenerators[i]);
+ }
+ }
+
+ this->AddExtraIDETargets();
+
+ // Trace the dependencies, after that no custom commands should be added
+ // because their dependencies might not be handled correctly
+ for (i = 0; i < this->LocalGenerators.size(); ++i) {
+ this->LocalGenerators[i]->TraceDependencies();
+ }
+
+ this->ForceLinkerLanguages();
+
+ // Compute the manifest of main targets generated.
+ for (i = 0; i < this->LocalGenerators.size(); ++i) {
+ this->LocalGenerators[i]->ComputeTargetManifest();
+ }
+
+ // Compute the inter-target dependencies.
+ if (!this->ComputeTargetDepends()) {
+ return false;
+ }
+
+ for (i = 0; i < this->LocalGenerators.size(); ++i) {
+ this->LocalGenerators[i]->ComputeHomeRelativeOutputPath();
+ }
+
+ return true;
+}
+
+void cmGlobalGenerator::Generate()
+{
+ // Create a map from local generator to the complete set of targets
+ // it builds by default.
+ this->InitializeProgressMarks();
+
+ this->ProcessEvaluationFiles();
+
+ // Generate project files
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ this->SetCurrentMakefile(this->LocalGenerators[i]->GetMakefile());
+ this->LocalGenerators[i]->Generate();
+ if (!this->LocalGenerators[i]->GetMakefile()->IsOn(
+ "CMAKE_SKIP_INSTALL_RULES")) {
+ this->LocalGenerators[i]->GenerateInstallRules();
+ }
+ this->LocalGenerators[i]->GenerateTestFiles();
+ this->CMakeInstance->UpdateProgress(
+ "Generating", (static_cast<float>(i) + 1.0f) /
+ static_cast<float>(this->LocalGenerators.size()));
+ }
+ this->SetCurrentMakefile(CM_NULLPTR);
+
+ if (!this->GenerateCPackPropertiesFile()) {
+ this->GetCMakeInstance()->IssueMessage(
+ cmake::FATAL_ERROR, "Could not write CPack properties file.");
+ }
+
+ for (std::map<std::string, cmExportBuildFileGenerator*>::iterator it =
+ this->BuildExportSets.begin();
+ it != this->BuildExportSets.end(); ++it) {
+ if (!it->second->GenerateImportFile() &&
+ !cmSystemTools::GetErrorOccuredFlag()) {
+ this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR,
+ "Could not write export file.");
+ return;
+ }
+ }
+ // Update rule hashes.
+ this->CheckRuleHashes();
+
+ this->WriteSummary();
+
+ if (this->ExtraGenerator != CM_NULLPTR) {
+ this->ExtraGenerator->Generate();
+ }
+
+ if (!this->CMP0042WarnTargets.empty()) {
+ std::ostringstream w;
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0042) << "\n";
+ w << "MACOSX_RPATH is not specified for"
+ " the following targets:\n";
+ for (std::set<std::string>::iterator iter =
+ this->CMP0042WarnTargets.begin();
+ iter != this->CMP0042WarnTargets.end(); ++iter) {
+ w << " " << *iter << "\n";
+ }
+ this->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ }
+
+ this->CMakeInstance->UpdateProgress("Generating done", -1);
+}
+
+bool cmGlobalGenerator::ComputeTargetDepends()
+{
+ cmComputeTargetDepends ctd(this);
+ if (!ctd.Compute()) {
+ return false;
+ }
+ std::vector<cmGeneratorTarget const*> const& targets = ctd.GetTargets();
+ for (std::vector<cmGeneratorTarget const*>::const_iterator ti =
+ targets.begin();
+ ti != targets.end(); ++ti) {
+ ctd.GetTargetDirectDepends(*ti, this->TargetDependencies[*ti]);
+ }
+ return true;
+}
+
+std::vector<const cmGeneratorTarget*>
+cmGlobalGenerator::CreateQtAutoGeneratorsTargets()
+{
+ std::vector<const cmGeneratorTarget*> autogenTargets;
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ std::vector<cmGeneratorTarget*> targets =
+ this->LocalGenerators[i]->GetGeneratorTargets();
+ std::vector<cmGeneratorTarget*> filteredTargets;
+ filteredTargets.reserve(targets.size());
+ for (std::vector<cmGeneratorTarget*>::iterator ti = targets.begin();
+ ti != targets.end(); ++ti) {
+ if ((*ti)->GetType() == cmState::GLOBAL_TARGET) {
+ continue;
+ }
+ if ((*ti)->GetType() != cmState::EXECUTABLE &&
+ (*ti)->GetType() != cmState::STATIC_LIBRARY &&
+ (*ti)->GetType() != cmState::SHARED_LIBRARY &&
+ (*ti)->GetType() != cmState::MODULE_LIBRARY &&
+ (*ti)->GetType() != cmState::OBJECT_LIBRARY) {
+ continue;
+ }
+ if ((!(*ti)->GetPropertyAsBool("AUTOMOC") &&
+ !(*ti)->GetPropertyAsBool("AUTOUIC") &&
+ !(*ti)->GetPropertyAsBool("AUTORCC")) ||
+ (*ti)->IsImported()) {
+ continue;
+ }
+ // don't do anything if there is no Qt4 or Qt5Core (which contains moc):
+ cmMakefile* mf = (*ti)->Target->GetMakefile();
+ std::string qtMajorVersion = mf->GetSafeDefinition("QT_VERSION_MAJOR");
+ if (qtMajorVersion == "") {
+ qtMajorVersion = mf->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
+ }
+ if (qtMajorVersion != "4" && qtMajorVersion != "5") {
+ continue;
+ }
+
+ cmGeneratorTarget* gt = *ti;
+
+ cmQtAutoGeneratorInitializer::InitializeAutogenSources(gt);
+ filteredTargets.push_back(gt);
+ }
+ for (std::vector<cmGeneratorTarget*>::iterator ti =
+ filteredTargets.begin();
+ ti != filteredTargets.end(); ++ti) {
+ cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
+ this->LocalGenerators[i], *ti);
+ autogenTargets.push_back(*ti);
+ }
+ }
+#endif
+ return autogenTargets;
+}
+
+void cmGlobalGenerator::FinalizeTargetCompileInfo()
+{
+ std::vector<std::string> const langs =
+ this->CMakeInstance->GetState()->GetEnabledLanguages();
+
+ // Construct per-target generator information.
+ for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
+ cmMakefile* mf = this->Makefiles[i];
+
+ const cmStringRange noconfig_compile_definitions =
+ mf->GetCompileDefinitionsEntries();
+ const cmBacktraceRange noconfig_compile_definitions_bts =
+ mf->GetCompileDefinitionsBacktraces();
+
+ cmTargets& targets = mf->GetTargets();
+ for (cmTargets::iterator ti = targets.begin(); ti != targets.end(); ++ti) {
+ cmTarget* t = &ti->second;
+ if (t->GetType() == cmState::GLOBAL_TARGET) {
+ continue;
+ }
+
+ t->AppendBuildInterfaceIncludes();
+
+ if (t->GetType() == cmState::INTERFACE_LIBRARY) {
+ 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);
+ }
+
+ cmPolicies::PolicyStatus polSt =
+ mf->GetPolicyStatus(cmPolicies::CMP0043);
+ if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
+ std::vector<std::string> configs;
+ mf->GetConfigurations(configs);
+
+ for (std::vector<std::string>::const_iterator ci = configs.begin();
+ ci != configs.end(); ++ci) {
+ std::string defPropName = "COMPILE_DEFINITIONS_";
+ defPropName += cmSystemTools::UpperCase(*ci);
+ t->AppendProperty(defPropName, mf->GetProperty(defPropName));
+ }
+ }
+ }
+
+ // The standard include directories for each language
+ // should be treated as system include directories.
+ std::set<std::string> standardIncludesSet;
+ for (std::vector<std::string>::const_iterator li = langs.begin();
+ li != langs.end(); ++li) {
+ std::string const standardIncludesVar =
+ "CMAKE_" + *li + "_STANDARD_INCLUDE_DIRECTORIES";
+ std::string const standardIncludesStr =
+ mf->GetSafeDefinition(standardIncludesVar);
+ std::vector<std::string> standardIncludesVec;
+ cmSystemTools::ExpandListArgument(standardIncludesStr,
+ standardIncludesVec);
+ standardIncludesSet.insert(standardIncludesVec.begin(),
+ standardIncludesVec.end());
+ }
+ mf->AddSystemIncludeDirectories(standardIncludesSet);
+ }
+}
+
+void cmGlobalGenerator::CreateGeneratorTargets(
+ TargetTypes targetTypes, cmMakefile* mf, cmLocalGenerator* lg,
+ std::map<cmTarget*, cmGeneratorTarget*> const& importedMap)
+{
+ if (targetTypes == AllTargets) {
+ cmTargets& targets = mf->GetTargets();
+ for (cmTargets::iterator ti = targets.begin(); ti != targets.end(); ++ti) {
+ cmTarget* t = &ti->second;
+ cmGeneratorTarget* gt = new cmGeneratorTarget(t, lg);
+ lg->AddGeneratorTarget(gt);
+ }
+ }
+
+ std::vector<cmTarget*> itgts = mf->GetImportedTargets();
+
+ for (std::vector<cmTarget*>::const_iterator j = itgts.begin();
+ j != itgts.end(); ++j) {
+ lg->AddImportedGeneratorTarget(importedMap.find(*j)->second);
+ }
+}
+
+void cmGlobalGenerator::CreateGeneratorTargets(TargetTypes targetTypes)
+{
+ std::map<cmTarget*, cmGeneratorTarget*> importedMap;
+ for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
+ cmMakefile* mf = this->Makefiles[i];
+ for (std::vector<cmTarget*>::const_iterator j =
+ mf->GetOwnedImportedTargets().begin();
+ j != mf->GetOwnedImportedTargets().end(); ++j) {
+ cmLocalGenerator* lg = this->LocalGenerators[i];
+ cmGeneratorTarget* gt = new cmGeneratorTarget(*j, lg);
+ lg->AddOwnedImportedGeneratorTarget(gt);
+ importedMap[*j] = gt;
+ }
+ }
+
+ // Construct per-target generator information.
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ this->CreateGeneratorTargets(targetTypes, this->Makefiles[i],
+ this->LocalGenerators[i], importedMap);
+ }
+}
+
+void cmGlobalGenerator::ClearGeneratorMembers()
+{
+ cmDeleteAll(this->BuildExportSets);
+ this->BuildExportSets.clear();
+
+ cmDeleteAll(this->Makefiles);
+ this->Makefiles.clear();
+
+ cmDeleteAll(this->LocalGenerators);
+ this->LocalGenerators.clear();
+
+ this->ExportSets.clear();
+ this->TargetDependencies.clear();
+ this->TargetSearchIndex.clear();
+ this->GeneratorTargetSearchIndex.clear();
+ this->ProjectMap.clear();
+ this->RuleHashes.clear();
+ this->DirectoryContentMap.clear();
+ this->BinaryDirectories.clear();
+}
+
+void cmGlobalGenerator::ComputeTargetObjectDirectory(cmGeneratorTarget*) const
+{
+}
+
+void cmGlobalGenerator::CheckTargetProperties()
+{
+ std::map<std::string, std::string> notFoundMap;
+ // std::set<std::string> notFoundMap;
+ // after it is all done do a ConfigureFinalPass
+ 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 (cmTargets::iterator l = targets.begin(); l != targets.end(); l++) {
+ if (l->second.GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ const cmTarget::LinkLibraryVectorType& libs =
+ l->second.GetOriginalLinkLibraries();
+ for (cmTarget::LinkLibraryVectorType::const_iterator lib = libs.begin();
+ lib != libs.end(); ++lib) {
+ if (lib->first.size() > 9 &&
+ cmSystemTools::IsNOTFOUND(lib->first.c_str())) {
+ std::string varName = lib->first.substr(0, lib->first.size() - 9);
+ if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) {
+ varName += " (ADVANCED)";
+ }
+ std::string text = notFoundMap[varName];
+ text += "\n linked by target \"";
+ text += l->second.GetName();
+ text += "\" in directory ";
+ text += this->Makefiles[i]->GetCurrentSourceDirectory();
+ notFoundMap[varName] = text;
+ }
+ }
+ std::vector<std::string> incs;
+ const char* incDirProp = l->second.GetProperty("INCLUDE_DIRECTORIES");
+ if (!incDirProp) {
+ continue;
+ }
+
+ std::string incDirs = cmGeneratorExpression::Preprocess(
+ incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions);
+
+ cmSystemTools::ExpandListArgument(incDirs, incs);
+
+ for (std::vector<std::string>::const_iterator incDir = incs.begin();
+ incDir != incs.end(); ++incDir) {
+ if (incDir->size() > 9 && cmSystemTools::IsNOTFOUND(incDir->c_str())) {
+ std::string varName = incDir->substr(0, incDir->size() - 9);
+ if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) {
+ varName += " (ADVANCED)";
+ }
+ std::string text = notFoundMap[varName];
+ text += "\n used as include directory in directory ";
+ text += this->Makefiles[i]->GetCurrentSourceDirectory();
+ notFoundMap[varName] = text;
+ }
+ }
+ }
+ this->CMakeInstance->UpdateProgress(
+ "Configuring", 0.9f +
+ 0.1f * (static_cast<float>(i) + 1.0f) /
+ static_cast<float>(this->Makefiles.size()));
+ }
+
+ if (!notFoundMap.empty()) {
+ std::string notFoundVars;
+ for (std::map<std::string, std::string>::const_iterator ii =
+ notFoundMap.begin();
+ ii != notFoundMap.end(); ++ii) {
+ notFoundVars += ii->first;
+ notFoundVars += ii->second;
+ notFoundVars += "\n";
+ }
+ 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());
+ }
+}
+
+int cmGlobalGenerator::TryCompile(const std::string& srcdir,
+ const std::string& bindir,
+ const std::string& projectName,
+ const std::string& target, bool fast,
+ std::string& output, cmMakefile* mf)
+{
+ // if this is not set, then this is a first time configure
+ // and there is a good chance that the try compile stuff will
+ // take the bulk of the time, so try and guess some progress
+ // by getting closer and closer to 100 without actually getting there.
+ if (!this->CMakeInstance->GetState()->GetInitializedCacheValue(
+ "CMAKE_NUMBER_OF_MAKEFILES")) {
+ // If CMAKE_NUMBER_OF_MAKEFILES is not set
+ // we are in the first time progress and we have no
+ // idea how long it will be. So, just move 1/10th of the way
+ // there each time, and don't go over 95%
+ this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f);
+ if (this->FirstTimeProgress > 0.95f) {
+ this->FirstTimeProgress = 0.95f;
+ }
+ this->CMakeInstance->UpdateProgress("Configuring",
+ this->FirstTimeProgress);
+ }
+
+ 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
+ }
+ std::string config =
+ mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
+ return this->Build(srcdir, bindir, projectName, newTarget, output, "",
+ config, false, fast, false, this->TryCompileTimeout);
+}
+
+void cmGlobalGenerator::GenerateBuildCommand(
+ std::vector<std::string>& makeCommand, const std::string&,
+ const std::string&, const std::string&, const std::string&,
+ const std::string&, bool, bool, std::vector<std::string> const&)
+{
+ makeCommand.push_back(
+ "cmGlobalGenerator::GenerateBuildCommand not implemented");
+}
+
+int cmGlobalGenerator::Build(const std::string&, 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, double timeout,
+ cmSystemTools::OutputOption outputflag,
+ std::vector<std::string> const& nativeOptions)
+{
+ /**
+ * Run an executable command and put the stdout in output.
+ */
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::ChangeDirectory(bindir);
+ output += "Change Dir: ";
+ output += bindir;
+ output += "\n";
+
+ int retVal;
+ bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
+ cmSystemTools::SetRunCommandHideConsole(true);
+ std::string outputBuffer;
+ std::string* outputPtr = &outputBuffer;
+
+ std::vector<std::string> makeCommand;
+ this->GenerateBuildCommand(makeCommand, makeCommandCSTR, projectName, bindir,
+ target, config, fast, verbose, nativeOptions);
+
+ // Workaround to convince VCExpress.exe to produce output.
+ if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
+ !makeCommand.empty() &&
+ cmSystemTools::LowerCase(
+ cmSystemTools::GetFilenameName(makeCommand[0])) == "vcexpress.exe") {
+ outputflag = cmSystemTools::OUTPUT_FORWARD;
+ }
+
+ // should we do a clean first?
+ if (clean) {
+ std::vector<std::string> cleanCommand;
+ this->GenerateBuildCommand(cleanCommand, makeCommandCSTR, projectName,
+ bindir, "clean", config, fast, verbose);
+ output += "\nRun Clean Command:";
+ output += cmSystemTools::PrintSingleCommand(cleanCommand);
+ output += "\n";
+
+ if (!cmSystemTools::RunSingleCommand(cleanCommand, outputPtr, outputPtr,
+ &retVal, CM_NULLPTR, outputflag,
+ timeout)) {
+ cmSystemTools::SetRunCommandHideConsole(hideconsole);
+ cmSystemTools::Error("Generator: execution of make clean failed.");
+ output += *outputPtr;
+ output += "\nGenerator: execution of make clean failed.\n";
+
+ // return to the original directory
+ cmSystemTools::ChangeDirectory(cwd);
+ return 1;
+ }
+ output += *outputPtr;
+ }
+
+ // now build
+ std::string makeCommandStr = cmSystemTools::PrintSingleCommand(makeCommand);
+ output += "\nRun Build Command:";
+ output += makeCommandStr;
+ output += "\n";
+
+ if (!cmSystemTools::RunSingleCommand(makeCommand, outputPtr, outputPtr,
+ &retVal, CM_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";
+
+ // return to the original directory
+ cmSystemTools::ChangeDirectory(cwd);
+ return 1;
+ }
+ output += *outputPtr;
+ cmSystemTools::SetRunCommandHideConsole(hideconsole);
+
+ // 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;
+ }
+
+ cmSystemTools::ChangeDirectory(cwd);
+ return retVal;
+}
+
+std::string cmGlobalGenerator::GenerateCMakeBuildCommand(
+ const std::string& target, const std::string& config,
+ const std::string& native, bool ignoreErrors)
+{
+ std::string makeCommand = cmSystemTools::GetCMakeCommand();
+ makeCommand = cmSystemTools::ConvertToOutputPath(makeCommand.c_str());
+ makeCommand += " --build .";
+ if (!config.empty()) {
+ makeCommand += " --config \"";
+ makeCommand += config;
+ makeCommand += "\"";
+ }
+ if (!target.empty()) {
+ makeCommand += " --target \"";
+ makeCommand += target;
+ makeCommand += "\"";
+ }
+ const char* sep = " -- ";
+ if (ignoreErrors) {
+ const char* iflag = this->GetBuildIgnoreErrorsFlag();
+ if (iflag && *iflag) {
+ makeCommand += sep;
+ makeCommand += iflag;
+ sep = " ";
+ }
+ }
+ if (!native.empty()) {
+ makeCommand += sep;
+ makeCommand += native;
+ }
+ return makeCommand;
+}
+
+void cmGlobalGenerator::AddMakefile(cmMakefile* mf)
+{
+ this->Makefiles.push_back(mf);
+
+ // update progress
+ // estimate how many lg there will be
+ const char* numGenC =
+ this->CMakeInstance->GetState()->GetInitializedCacheValue(
+ "CMAKE_NUMBER_OF_MAKEFILES");
+
+ if (!numGenC) {
+ // If CMAKE_NUMBER_OF_MAKEFILES is not set
+ // we are in the first time progress and we have no
+ // idea how long it will be. So, just move half way
+ // there each time, and don't go over 95%
+ this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f);
+ if (this->FirstTimeProgress > 0.95f) {
+ this->FirstTimeProgress = 0.95f;
+ }
+ this->CMakeInstance->UpdateProgress("Configuring",
+ this->FirstTimeProgress);
+ return;
+ }
+
+ int numGen = atoi(numGenC);
+ float prog = 0.9f * static_cast<float>(this->Makefiles.size()) /
+ static_cast<float>(numGen);
+ if (prog > 0.9f) {
+ prog = 0.9f;
+ }
+ this->CMakeInstance->UpdateProgress("Configuring", prog);
+}
+
+void cmGlobalGenerator::AddInstallComponent(const char* component)
+{
+ if (component && *component) {
+ this->InstallComponents.insert(component);
+ }
+}
+
+void cmGlobalGenerator::EnableInstallTarget()
+{
+ this->InstallTargetEnabled = true;
+}
+
+cmLocalGenerator* cmGlobalGenerator::CreateLocalGenerator(cmMakefile* mf)
+{
+ return new cmLocalGenerator(this, mf);
+}
+
+void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator* gen,
+ cmMakefile* mf)
+{
+ this->SetConfiguredFilesPath(gen);
+ this->TryCompileOuterMakefile = mf;
+ const char* make =
+ gen->GetCMakeInstance()->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
+ this->GetCMakeInstance()->AddCacheEntry("CMAKE_MAKE_PROGRAM", make,
+ "make program", cmState::FILEPATH);
+ // copy the enabled languages
+ this->GetCMakeInstance()->GetState()->SetEnabledLanguages(
+ gen->GetCMakeInstance()->GetState()->GetEnabledLanguages());
+ this->LanguagesReady = gen->LanguagesReady;
+ this->ExtensionToLanguage = gen->ExtensionToLanguage;
+ this->IgnoreExtensions = gen->IgnoreExtensions;
+ this->LanguageToOutputExtension = gen->LanguageToOutputExtension;
+ this->LanguageToLinkerPreference = gen->LanguageToLinkerPreference;
+ this->OutputExtensions = gen->OutputExtensions;
+}
+
+void cmGlobalGenerator::SetConfiguredFilesPath(cmGlobalGenerator* gen)
+{
+ if (!gen->ConfiguredFilesPath.empty()) {
+ this->ConfiguredFilesPath = gen->ConfiguredFilesPath;
+ } else {
+ this->ConfiguredFilesPath = gen->CMakeInstance->GetHomeOutputDirectory();
+ this->ConfiguredFilesPath += cmake::GetCMakeFilesDirectory();
+ }
+}
+
+bool cmGlobalGenerator::IsExcluded(cmState::Snapshot const& rootSnp,
+ cmState::Snapshot const& snp_) const
+{
+ cmState::Snapshot snp = snp_;
+ while (snp.IsValid()) {
+ if (snp == rootSnp) {
+ // No directory excludes itself.
+ return false;
+ }
+
+ if (snp.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+ // This directory is excluded from its parent.
+ return true;
+ }
+ snp = snp.GetBuildsystemDirectoryParent();
+ }
+ return false;
+}
+
+bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
+ cmLocalGenerator* gen) const
+{
+ assert(gen);
+
+ cmState::Snapshot rootSnp = root->GetStateSnapshot();
+ cmState::Snapshot snp = gen->GetStateSnapshot();
+
+ return this->IsExcluded(rootSnp, snp);
+}
+
+bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
+ cmGeneratorTarget* target) const
+{
+ if (target->GetType() == cmState::INTERFACE_LIBRARY ||
+ target->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+ // This target is excluded from its directory.
+ return true;
+ }
+ // This target is included in its directory. Check whether the
+ // directory is excluded.
+ return this->IsExcluded(root, target->GetLocalGenerator());
+}
+
+void cmGlobalGenerator::GetEnabledLanguages(
+ std::vector<std::string>& lang) const
+{
+ lang = this->CMakeInstance->GetState()->GetEnabledLanguages();
+}
+
+int cmGlobalGenerator::GetLinkerPreference(const std::string& lang) const
+{
+ std::map<std::string, int>::const_iterator it =
+ this->LanguageToLinkerPreference.find(lang);
+ if (it != this->LanguageToLinkerPreference.end()) {
+ return it->second;
+ }
+ return 0;
+}
+
+void cmGlobalGenerator::FillProjectMap()
+{
+ this->ProjectMap.clear(); // make sure we start with a clean map
+ unsigned int i;
+ for (i = 0; i < this->LocalGenerators.size(); ++i) {
+ // for each local generator add all projects
+ cmState::Snapshot snp = this->LocalGenerators[i]->GetStateSnapshot();
+ std::string name;
+ do {
+ std::string snpProjName = snp.GetProjectName();
+ if (name != snpProjName) {
+ name = snpProjName;
+ this->ProjectMap[name].push_back(this->LocalGenerators[i]);
+ }
+ snp = snp.GetBuildsystemDirectoryParent();
+ } while (snp.IsValid());
+ }
+}
+
+cmMakefile* cmGlobalGenerator::FindMakefile(const std::string& start_dir) const
+{
+ for (std::vector<cmMakefile*>::const_iterator it = this->Makefiles.begin();
+ it != this->Makefiles.end(); ++it) {
+ std::string sd = (*it)->GetCurrentSourceDirectory();
+ if (sd == start_dir) {
+ return *it;
+ }
+ }
+ return CM_NULLPTR;
+}
+
+///! Find a local generator by its startdirectory
+cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(
+ const std::string& start_dir) const
+{
+ for (std::vector<cmLocalGenerator*>::const_iterator it =
+ this->LocalGenerators.begin();
+ it != this->LocalGenerators.end(); ++it) {
+ std::string sd = (*it)->GetCurrentSourceDirectory();
+ if (sd == start_dir) {
+ return *it;
+ }
+ }
+ return CM_NULLPTR;
+}
+
+void cmGlobalGenerator::AddAlias(const std::string& name,
+ std::string const& tgtName)
+{
+ this->AliasTargets[name] = tgtName;
+}
+
+bool cmGlobalGenerator::IsAlias(const std::string& name) const
+{
+ return this->AliasTargets.find(name) != this->AliasTargets.end();
+}
+
+void cmGlobalGenerator::IndexTarget(cmTarget* t)
+{
+ if (!t->IsImported() || t->IsImportedGloballyVisible()) {
+ this->TargetSearchIndex[t->GetName()] = t;
+ }
+}
+
+void cmGlobalGenerator::IndexGeneratorTarget(cmGeneratorTarget* gt)
+{
+ if (!gt->IsImported() || gt->IsImportedGloballyVisible()) {
+ this->GeneratorTargetSearchIndex[gt->GetName()] = gt;
+ }
+}
+
+cmTarget* cmGlobalGenerator::FindTargetImpl(std::string const& name) const
+{
+ TargetMap::const_iterator i = this->TargetSearchIndex.find(name);
+ if (i != this->TargetSearchIndex.end()) {
+ return i->second;
+ }
+ return CM_NULLPTR;
+}
+
+cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTargetImpl(
+ std::string const& name) const
+{
+ GeneratorTargetMap::const_iterator i =
+ this->GeneratorTargetSearchIndex.find(name);
+ if (i != this->GeneratorTargetSearchIndex.end()) {
+ return i->second;
+ }
+ return CM_NULLPTR;
+}
+
+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);
+ if (ai != this->AliasTargets.end()) {
+ return this->FindTargetImpl(ai->second);
+ }
+ }
+ return this->FindTargetImpl(name);
+}
+
+cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTarget(
+ const std::string& name) const
+{
+ std::map<std::string, std::string>::const_iterator ai =
+ this->AliasTargets.find(name);
+ if (ai != this->AliasTargets.end()) {
+ return this->FindGeneratorTargetImpl(ai->second);
+ }
+ return this->FindGeneratorTargetImpl(name);
+}
+
+bool cmGlobalGenerator::NameResolvesToFramework(
+ const std::string& libname) const
+{
+ if (cmSystemTools::IsPathToFramework(libname.c_str())) {
+ return true;
+ }
+
+ if (cmTarget* tgt = this->FindTarget(libname)) {
+ if (tgt->IsFrameworkOnApple()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+inline std::string removeQuotes(const std::string& s)
+{
+ if (s[0] == '\"' && s[s.size() - 1] == '\"') {
+ return s.substr(1, s.size() - 2);
+ }
+ return s;
+}
+
+void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets)
+{
+ cmMakefile* mf = this->Makefiles[0];
+ const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
+
+ // CPack
+ std::string workingDir = mf->GetCurrentBinaryDirectory();
+ cmCustomCommandLines cpackCommandLines;
+ std::vector<std::string> depends;
+ cmCustomCommandLine singleLine;
+ singleLine.push_back(cmSystemTools::GetCPackCommand());
+ if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') {
+ singleLine.push_back("-C");
+ singleLine.push_back(cmakeCfgIntDir);
+ }
+ singleLine.push_back("--config");
+ std::string configFile = mf->GetCurrentBinaryDirectory();
+ ;
+ configFile += "/CPackConfig.cmake";
+ std::string relConfigFile = "./CPackConfig.cmake";
+ singleLine.push_back(relConfigFile);
+ cpackCommandLines.push_back(singleLine);
+ if (this->GetPreinstallTargetName()) {
+ depends.push_back(this->GetPreinstallTargetName());
+ } else {
+ const char* noPackageAll =
+ mf->GetDefinition("CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY");
+ if (!noPackageAll || cmSystemTools::IsOff(noPackageAll)) {
+ depends.push_back(this->GetAllTargetName());
+ }
+ }
+ if (cmSystemTools::FileExists(configFile.c_str())) {
+ (*targets)[this->GetPackageTargetName()] = this->CreateGlobalTarget(
+ this->GetPackageTargetName(), "Run CPack packaging tool...",
+ &cpackCommandLines, depends, workingDir.c_str(), /*uses_terminal*/ true);
+ }
+ // CPack source
+ const char* packageSourceTargetName = this->GetPackageSourceTargetName();
+ if (packageSourceTargetName) {
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ singleLine.erase(singleLine.begin(), singleLine.end());
+ depends.erase(depends.begin(), depends.end());
+ singleLine.push_back(cmSystemTools::GetCPackCommand());
+ singleLine.push_back("--config");
+ configFile = mf->GetCurrentBinaryDirectory();
+ ;
+ configFile += "/CPackSourceConfig.cmake";
+ relConfigFile = "./CPackSourceConfig.cmake";
+ singleLine.push_back(relConfigFile);
+ if (cmSystemTools::FileExists(configFile.c_str())) {
+ singleLine.push_back(configFile);
+ cpackCommandLines.push_back(singleLine);
+ (*targets)[packageSourceTargetName] = this->CreateGlobalTarget(
+ packageSourceTargetName, "Run CPack packaging tool for source...",
+ &cpackCommandLines, depends, workingDir.c_str(),
+ /*uses_terminal*/ true);
+ }
+ }
+
+ // Test
+ if (mf->IsOn("CMAKE_TESTING_ENABLED")) {
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ singleLine.erase(singleLine.begin(), singleLine.end());
+ depends.erase(depends.begin(), depends.end());
+ singleLine.push_back(cmSystemTools::GetCTestCommand());
+ singleLine.push_back("--force-new-ctest-process");
+ if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') {
+ singleLine.push_back("-C");
+ singleLine.push_back(cmakeCfgIntDir);
+ } else // TODO: This is a hack. Should be something to do with the
+ // generator
+ {
+ singleLine.push_back("$(ARGS)");
+ }
+ cpackCommandLines.push_back(singleLine);
+ (*targets)[this->GetTestTargetName()] =
+ this->CreateGlobalTarget(this->GetTestTargetName(), "Running tests...",
+ &cpackCommandLines, depends, CM_NULLPTR,
+ /*uses_terminal*/ true);
+ }
+
+ // Edit Cache
+ const char* editCacheTargetName = this->GetEditCacheTargetName();
+ if (editCacheTargetName) {
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ singleLine.erase(singleLine.begin(), singleLine.end());
+ depends.erase(depends.begin(), depends.end());
+
+ // Use generator preference for the edit_cache rule if it is defined.
+ std::string edit_cmd = this->GetEditCacheCommand();
+ if (!edit_cmd.empty()) {
+ singleLine.push_back(edit_cmd);
+ singleLine.push_back("-H$(CMAKE_SOURCE_DIR)");
+ singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
+ cpackCommandLines.push_back(singleLine);
+ (*targets)[editCacheTargetName] = this->CreateGlobalTarget(
+ editCacheTargetName, "Running CMake cache editor...",
+ &cpackCommandLines, depends, CM_NULLPTR, /*uses_terminal*/ true);
+ } else {
+ singleLine.push_back(cmSystemTools::GetCMakeCommand());
+ singleLine.push_back("-E");
+ singleLine.push_back("echo");
+ singleLine.push_back("No interactive CMake dialog available.");
+ cpackCommandLines.push_back(singleLine);
+ (*targets)[editCacheTargetName] = this->CreateGlobalTarget(
+ editCacheTargetName, "No interactive CMake dialog available...",
+ &cpackCommandLines, depends, CM_NULLPTR, /*uses_terminal*/ false);
+ }
+ }
+
+ // Rebuild Cache
+ const char* rebuildCacheTargetName = this->GetRebuildCacheTargetName();
+ if (rebuildCacheTargetName) {
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ singleLine.erase(singleLine.begin(), singleLine.end());
+ depends.erase(depends.begin(), depends.end());
+ singleLine.push_back(cmSystemTools::GetCMakeCommand());
+ singleLine.push_back("-H$(CMAKE_SOURCE_DIR)");
+ singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
+ cpackCommandLines.push_back(singleLine);
+ (*targets)[rebuildCacheTargetName] = this->CreateGlobalTarget(
+ rebuildCacheTargetName, "Running CMake to regenerate build system...",
+ &cpackCommandLines, depends, CM_NULLPTR, /*uses_terminal*/ true);
+ }
+
+ // Install
+ bool skipInstallRules = mf->IsOn("CMAKE_SKIP_INSTALL_RULES");
+ if (this->InstallTargetEnabled && skipInstallRules) {
+ this->CMakeInstance->IssueMessage(
+ cmake::WARNING, "CMAKE_SKIP_INSTALL_RULES was enabled even though "
+ "installation rules have been specified",
+ mf->GetBacktrace());
+ } else if (this->InstallTargetEnabled && !skipInstallRules) {
+ if (!cmakeCfgIntDir || !*cmakeCfgIntDir || cmakeCfgIntDir[0] == '.') {
+ std::set<std::string>* componentsSet = &this->InstallComponents;
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ depends.erase(depends.begin(), depends.end());
+ std::ostringstream ostr;
+ if (!componentsSet->empty()) {
+ ostr << "Available install components are: ";
+ ostr << cmWrap('"', *componentsSet, '"', " ");
+ } else {
+ ostr << "Only default component available";
+ }
+ singleLine.push_back(ostr.str());
+ (*targets)["list_install_components"] = this->CreateGlobalTarget(
+ "list_install_components", ostr.str().c_str(), &cpackCommandLines,
+ depends, CM_NULLPTR, /*uses_terminal*/ false);
+ }
+ std::string cmd = cmSystemTools::GetCMakeCommand();
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ singleLine.erase(singleLine.begin(), singleLine.end());
+ depends.erase(depends.begin(), depends.end());
+ if (this->GetPreinstallTargetName()) {
+ depends.push_back(this->GetPreinstallTargetName());
+ } else {
+ const char* noall =
+ mf->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
+ if (!noall || cmSystemTools::IsOff(noall)) {
+ depends.push_back(this->GetAllTargetName());
+ }
+ }
+ if (mf->GetDefinition("CMake_BINARY_DIR") &&
+ !mf->IsOn("CMAKE_CROSSCOMPILING")) {
+ // We are building CMake itself. We cannot use the original
+ // executable to install over itself. The generator will
+ // automatically convert this name to the build-time location.
+ cmd = "cmake";
+ }
+ singleLine.push_back(cmd);
+ if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') {
+ std::string cfgArg = "-DBUILD_TYPE=";
+ bool iosPlatform = mf->PlatformIsAppleIos();
+ if (iosPlatform) {
+ cfgArg += "$(CONFIGURATION)";
+ singleLine.push_back(cfgArg);
+ cfgArg = "-DEFFECTIVE_PLATFORM_NAME=$(EFFECTIVE_PLATFORM_NAME)";
+ } else {
+ cfgArg += mf->GetDefinition("CMAKE_CFG_INTDIR");
+ }
+ singleLine.push_back(cfgArg);
+ }
+ singleLine.push_back("-P");
+ singleLine.push_back("cmake_install.cmake");
+ cpackCommandLines.push_back(singleLine);
+ (*targets)[this->GetInstallTargetName()] = this->CreateGlobalTarget(
+ this->GetInstallTargetName(), "Install the project...",
+ &cpackCommandLines, depends, CM_NULLPTR, /*uses_terminal*/ true);
+
+ // install_local
+ if (const char* install_local = this->GetInstallLocalTargetName()) {
+ cmCustomCommandLine localCmdLine = singleLine;
+
+ localCmdLine.insert(localCmdLine.begin() + 1,
+ "-DCMAKE_INSTALL_LOCAL_ONLY=1");
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ cpackCommandLines.push_back(localCmdLine);
+
+ (*targets)[install_local] = this->CreateGlobalTarget(
+ install_local, "Installing only the local directory...",
+ &cpackCommandLines, depends, CM_NULLPTR, /*uses_terminal*/ true);
+ }
+
+ // install_strip
+ const char* install_strip = this->GetInstallStripTargetName();
+ if ((install_strip != CM_NULLPTR) && (mf->IsSet("CMAKE_STRIP"))) {
+ cmCustomCommandLine stripCmdLine = singleLine;
+
+ stripCmdLine.insert(stripCmdLine.begin() + 1,
+ "-DCMAKE_INSTALL_DO_STRIP=1");
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ cpackCommandLines.push_back(stripCmdLine);
+
+ (*targets)[install_strip] = this->CreateGlobalTarget(
+ install_strip, "Installing the project stripped...",
+ &cpackCommandLines, depends, CM_NULLPTR, /*uses_terminal*/ true);
+ }
+ }
+}
+
+const char* cmGlobalGenerator::GetPredefinedTargetsFolder()
+{
+ const char* prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
+ "PREDEFINED_TARGETS_FOLDER");
+
+ if (prop) {
+ return prop;
+ }
+
+ return "CMakePredefinedTargets";
+}
+
+bool cmGlobalGenerator::UseFolderProperty()
+{
+ const char* prop =
+ this->GetCMakeInstance()->GetState()->GetGlobalProperty("USE_FOLDERS");
+
+ // If this property is defined, let the setter turn this on or off...
+ //
+ if (prop) {
+ return cmSystemTools::IsOn(prop);
+ }
+
+ // By default, this feature is OFF, since it is not supported in the
+ // Visual Studio Express editions until VS11:
+ //
+ return false;
+}
+
+cmTarget cmGlobalGenerator::CreateGlobalTarget(
+ const std::string& name, const char* message,
+ const cmCustomCommandLines* commandLines, std::vector<std::string> depends,
+ const char* workingDirectory, bool uses_terminal)
+{
+ // Package
+ cmTarget target;
+ target.SetType(cmState::GLOBAL_TARGET, name);
+ target.SetProperty("EXCLUDE_FROM_ALL", "TRUE");
+
+ std::vector<std::string> no_outputs;
+ std::vector<std::string> no_byproducts;
+ std::vector<std::string> no_depends;
+ // Store the custom command in the target.
+ cmCustomCommand cc(CM_NULLPTR, no_outputs, no_byproducts, no_depends,
+ *commandLines, CM_NULLPTR, workingDirectory);
+ cc.SetUsesTerminal(uses_terminal);
+ target.AddPostBuildCommand(cc);
+ target.SetProperty("EchoString", message);
+ std::vector<std::string>::iterator dit;
+ for (dit = depends.begin(); dit != depends.end(); ++dit) {
+ target.AddUtility(*dit);
+ }
+
+ // Organize in the "predefined targets" folder:
+ //
+ if (this->UseFolderProperty()) {
+ target.SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
+ }
+
+ return target;
+}
+
+std::string cmGlobalGenerator::GenerateRuleFile(
+ std::string const& output) const
+{
+ std::string ruleFile = output;
+ ruleFile += ".rule";
+ const char* dir = this->GetCMakeCFGIntDir();
+ if (dir && dir[0] == '$') {
+ cmSystemTools::ReplaceString(ruleFile, dir,
+ cmake::GetCMakeFilesDirectory());
+ }
+ return ruleFile;
+}
+
+std::string cmGlobalGenerator::GetSharedLibFlagsForLanguage(
+ std::string const& l) const
+{
+ std::map<std::string, std::string>::const_iterator it =
+ this->LanguageToOriginalSharedLibFlags.find(l);
+ if (it != this->LanguageToOriginalSharedLibFlags.end()) {
+ return it->second;
+ }
+ return "";
+}
+
+void cmGlobalGenerator::AppendDirectoryForConfig(const std::string&,
+ const std::string&,
+ const std::string&,
+ std::string&)
+{
+ // Subclasses that support multiple configurations should implement
+ // this method to append the subdirectory for the given build
+ // configuration.
+}
+
+cmGlobalGenerator::TargetDependSet const&
+cmGlobalGenerator::GetTargetDirectDepends(cmGeneratorTarget const* target)
+{
+ return this->TargetDependencies[target];
+}
+
+bool cmGlobalGenerator::IsReservedTarget(std::string const& name)
+{
+ // The following is a list of targets reserved
+ // by one or more of the cmake generators.
+
+ // Adding additional targets to this list will require a policy!
+ const char* reservedTargets[] = {
+ "all", "ALL_BUILD", "help", "install", "INSTALL",
+ "preinstall", "clean", "edit_cache", "rebuild_cache", "test",
+ "RUN_TESTS", "package", "PACKAGE", "package_source", "ZERO_CHECK"
+ };
+
+ return std::find(cmArrayBegin(reservedTargets), cmArrayEnd(reservedTargets),
+ name) != cmArrayEnd(reservedTargets);
+}
+
+void cmGlobalGenerator::SetExternalMakefileProjectGenerator(
+ cmExternalMakefileProjectGenerator* extraGenerator)
+{
+ this->ExtraGenerator = extraGenerator;
+ if (this->ExtraGenerator != CM_NULLPTR) {
+ this->ExtraGenerator->SetGlobalGenerator(this);
+ }
+}
+
+std::string cmGlobalGenerator::GetExtraGeneratorName() const
+{
+ return this->ExtraGenerator ? this->ExtraGenerator->GetName()
+ : std::string();
+}
+
+void cmGlobalGenerator::FileReplacedDuringGenerate(const std::string& filename)
+{
+ this->FilesReplacedDuringGenerate.push_back(filename);
+}
+
+void cmGlobalGenerator::GetFilesReplacedDuringGenerate(
+ std::vector<std::string>& filenames)
+{
+ filenames.clear();
+ std::copy(this->FilesReplacedDuringGenerate.begin(),
+ this->FilesReplacedDuringGenerate.end(),
+ std::back_inserter(filenames));
+}
+
+void cmGlobalGenerator::GetTargetSets(TargetDependSet& projectTargets,
+ TargetDependSet& originalTargets,
+ cmLocalGenerator* root,
+ GeneratorVector const& generators)
+{
+ // loop over all local generators
+ for (std::vector<cmLocalGenerator*>::const_iterator i = generators.begin();
+ i != generators.end(); ++i) {
+ // check to make sure generator is not excluded
+ if (this->IsExcluded(root, *i)) {
+ continue;
+ }
+ // Get the targets in the makefile
+ std::vector<cmGeneratorTarget*> tgts = (*i)->GetGeneratorTargets();
+ // loop over all the targets
+ for (std::vector<cmGeneratorTarget*>::iterator l = tgts.begin();
+ l != tgts.end(); ++l) {
+ cmGeneratorTarget* target = *l;
+ if (this->IsRootOnlyTarget(target) &&
+ target->GetLocalGenerator() != root) {
+ continue;
+ }
+ // put the target in the set of original targets
+ originalTargets.insert(target);
+ // Get the set of targets that depend on target
+ this->AddTargetDepends(target, projectTargets);
+ }
+ }
+}
+
+bool cmGlobalGenerator::IsRootOnlyTarget(cmGeneratorTarget* target) const
+{
+ return (target->GetType() == cmState::GLOBAL_TARGET ||
+ target->GetName() == this->GetAllTargetName());
+}
+
+void cmGlobalGenerator::AddTargetDepends(cmGeneratorTarget const* target,
+ TargetDependSet& projectTargets)
+{
+ // add the target itself
+ 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 (TargetDependSet::const_iterator i = ts.begin(); i != ts.end(); ++i) {
+ this->AddTargetDepends(*i, projectTargets);
+ }
+ }
+}
+
+void cmGlobalGenerator::AddToManifest(std::string const& f)
+{
+ // Add to the content listing for the file's directory.
+ std::string dir = cmSystemTools::GetFilenamePath(f);
+ std::string file = cmSystemTools::GetFilenameName(f);
+ DirectoryContent& dc = this->DirectoryContentMap[dir];
+ dc.Generated.insert(file);
+ dc.All.insert(file);
+}
+
+std::set<std::string> const& cmGlobalGenerator::GetDirectoryContent(
+ std::string const& dir, bool needDisk)
+{
+ DirectoryContent& dc = this->DirectoryContentMap[dir];
+ if (needDisk) {
+ long mt = cmSystemTools::ModifiedTime(dir);
+ if (mt != dc.LastDiskTime) {
+ // Reset to non-loaded directory content.
+ dc.All = dc.Generated;
+
+ // Load the directory content from disk.
+ cmsys::Directory d;
+ if (d.Load(dir)) {
+ unsigned long n = d.GetNumberOfFiles();
+ for (unsigned long i = 0; i < n; ++i) {
+ const char* f = d.GetFile(i);
+ if (strcmp(f, ".") != 0 && strcmp(f, "..") != 0) {
+ dc.All.insert(f);
+ }
+ }
+ }
+ dc.LastDiskTime = mt;
+ }
+ }
+ return dc.All;
+}
+
+void cmGlobalGenerator::AddRuleHash(const std::vector<std::string>& outputs,
+ std::string const& content)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ // Ignore if there are no outputs.
+ if (outputs.empty()) {
+ return;
+ }
+
+ // Compute a hash of the rule.
+ RuleHash hash;
+ {
+ unsigned char const* data =
+ reinterpret_cast<unsigned char const*>(content.c_str());
+ int length = static_cast<int>(content.length());
+ cmsysMD5* sum = cmsysMD5_New();
+ cmsysMD5_Initialize(sum);
+ cmsysMD5_Append(sum, data, length);
+ cmsysMD5_FinalizeHex(sum, hash.Data);
+ cmsysMD5_Delete(sum);
+ }
+
+ // Shorten the output name (in expected use case).
+ cmOutputConverter converter(this->GetMakefiles()[0]->GetStateSnapshot());
+ std::string fname =
+ converter.Convert(outputs[0], cmOutputConverter::HOME_OUTPUT);
+
+ // Associate the hash with this output.
+ this->RuleHashes[fname] = hash;
+#else
+ (void)outputs;
+ (void)content;
+#endif
+}
+
+void cmGlobalGenerator::CheckRuleHashes()
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ std::string home = this->GetCMakeInstance()->GetHomeOutputDirectory();
+ std::string pfile = home;
+ pfile += this->GetCMakeInstance()->GetCMakeFilesDirectory();
+ pfile += "/CMakeRuleHashes.txt";
+ this->CheckRuleHashes(pfile, home);
+ this->WriteRuleHashes(pfile);
+#endif
+}
+
+void cmGlobalGenerator::CheckRuleHashes(std::string const& pfile,
+ std::string const& home)
+{
+#if defined(_WIN32) || defined(__CYGWIN__)
+ cmsys::ifstream fin(pfile.c_str(), std::ios::in | std::ios::binary);
+#else
+ cmsys::ifstream fin(pfile.c_str());
+#endif
+ if (!fin) {
+ return;
+ }
+ std::string line;
+ std::string fname;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ // Line format is a 32-byte hex string followed by a space
+ // followed by a file name (with no escaping).
+
+ // Skip blank and comment lines.
+ if (line.size() < 34 || line[0] == '#') {
+ continue;
+ }
+
+ // Get the filename.
+ fname = line.substr(33, line.npos);
+
+ // Look for a hash for this file's rule.
+ std::map<std::string, RuleHash>::const_iterator 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) {
+ // The rule has changed. Delete the output so it will be
+ // built again.
+ fname = cmSystemTools::CollapseFullPath(fname, home.c_str());
+ cmSystemTools::RemoveFile(fname);
+ }
+ } else {
+ // We have no hash for a rule previously listed. This may be a
+ // case where a user has turned off a build option and might
+ // want to turn it back on later, so do not delete the file.
+ // Instead, we keep the rule hash as long as the file exists so
+ // that if the feature is turned back on and the rule has
+ // changed the file is still rebuilt.
+ std::string fpath = cmSystemTools::CollapseFullPath(fname, home.c_str());
+ if (cmSystemTools::FileExists(fpath.c_str())) {
+ RuleHash hash;
+ strncpy(hash.Data, line.c_str(), 32);
+ this->RuleHashes[fname] = hash;
+ }
+ }
+ }
+}
+
+void cmGlobalGenerator::WriteRuleHashes(std::string const& pfile)
+{
+ // Now generate a new persistence file with the current hashes.
+ if (this->RuleHashes.empty()) {
+ cmSystemTools::RemoveFile(pfile);
+ } else {
+ cmGeneratedFileStream fout(pfile.c_str());
+ fout << "# Hashes of file build rules.\n";
+ for (std::map<std::string, RuleHash>::const_iterator rhi =
+ this->RuleHashes.begin();
+ rhi != this->RuleHashes.end(); ++rhi) {
+ fout.write(rhi->second.Data, 32);
+ fout << " " << rhi->first << "\n";
+ }
+ }
+}
+
+void cmGlobalGenerator::WriteSummary()
+{
+ // Record all target directories in a central location.
+ std::string fname = this->CMakeInstance->GetHomeOutputDirectory();
+ fname += cmake::GetCMakeFilesDirectory();
+ fname += "/TargetDirectories.txt";
+ cmGeneratedFileStream fout(fname.c_str());
+
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ std::vector<cmGeneratorTarget*> tgts =
+ this->LocalGenerators[i]->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator it = tgts.begin();
+ it != tgts.end(); ++it) {
+ if ((*it)->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ this->WriteSummary(*it);
+ fout << (*it)->GetSupportDirectory() << "\n";
+ }
+ }
+}
+
+void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target)
+{
+ // Place the labels file in a per-target support directory.
+ std::string dir = target->GetSupportDirectory();
+ std::string file = dir;
+ file += "/Labels.txt";
+ std::string json_file = dir + "/Labels.json";
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ // Check whether labels are enabled for this target.
+ if (const char* value = target->GetProperty("LABELS")) {
+ Json::Value lj_root(Json::objectValue);
+ Json::Value& lj_target = lj_root["target"] = Json::objectValue;
+ lj_target["name"] = target->GetName();
+ Json::Value& lj_target_labels = lj_target["labels"] = Json::arrayValue;
+ Json::Value& lj_sources = lj_root["sources"] = Json::arrayValue;
+
+ cmSystemTools::MakeDirectory(dir.c_str());
+ cmGeneratedFileStream fout(file.c_str());
+
+ // List the target-wide labels. All sources in the target get
+ // these labels.
+ std::vector<std::string> labels;
+ cmSystemTools::ExpandListArgument(value, labels);
+ if (!labels.empty()) {
+ fout << "# Target labels\n";
+ for (std::vector<std::string>::const_iterator li = labels.begin();
+ li != labels.end(); ++li) {
+ fout << " " << *li << "\n";
+ lj_target_labels.append(*li);
+ }
+ }
+
+ // List the source files with any per-source labels.
+ fout << "# Source files and their labels\n";
+ std::vector<cmSourceFile*> sources;
+ std::vector<std::string> configs;
+ target->Target->GetMakefile()->GetConfigurations(configs);
+ if (configs.empty()) {
+ configs.push_back("");
+ }
+ for (std::vector<std::string>::const_iterator ci = configs.begin();
+ ci != configs.end(); ++ci) {
+ target->GetSourceFiles(sources, *ci);
+ }
+ std::vector<cmSourceFile*>::const_iterator sourcesEnd =
+ cmRemoveDuplicates(sources);
+ for (std::vector<cmSourceFile*>::const_iterator si = sources.begin();
+ si != sourcesEnd; ++si) {
+ 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;
+ if (const char* svalue = sf->GetProperty("LABELS")) {
+ labels.clear();
+ Json::Value& lj_source_labels = lj_source["labels"] = Json::arrayValue;
+ cmSystemTools::ExpandListArgument(svalue, labels);
+ for (std::vector<std::string>::const_iterator li = labels.begin();
+ li != labels.end(); ++li) {
+ fout << " " << *li << "\n";
+ lj_source_labels.append(*li);
+ }
+ }
+ }
+ cmGeneratedFileStream json_fout(json_file.c_str());
+ json_fout << lj_root;
+ } else
+#endif
+ {
+ cmSystemTools::RemoveFile(file);
+ cmSystemTools::RemoveFile(json_file);
+ }
+}
+
+// static
+std::string cmGlobalGenerator::EscapeJSON(const std::string& s)
+{
+ std::string result;
+ for (std::string::size_type i = 0; i < s.size(); ++i) {
+ if (s[i] == '"' || s[i] == '\\') {
+ result += '\\';
+ }
+ result += s[i];
+ }
+ return result;
+}
+
+void cmGlobalGenerator::SetFilenameTargetDepends(
+ cmSourceFile* sf, std::set<cmGeneratorTarget const*> const& tgts)
+{
+ this->FilenameTargetDepends[sf] = tgts;
+}
+
+std::set<cmGeneratorTarget const*> const&
+cmGlobalGenerator::GetFilenameTargetDepends(cmSourceFile* sf) const
+{
+ return this->FilenameTargetDepends[sf];
+}
+
+void cmGlobalGenerator::CreateEvaluationSourceFiles(
+ std::string const& config) const
+{
+ unsigned int i;
+ for (i = 0; i < this->LocalGenerators.size(); ++i) {
+ this->LocalGenerators[i]->CreateEvaluationFileOutputs(config);
+ }
+}
+
+void cmGlobalGenerator::ProcessEvaluationFiles()
+{
+ std::vector<std::string> generatedFiles;
+ unsigned int i;
+ for (i = 0; i < this->LocalGenerators.size(); ++i) {
+ this->LocalGenerators[i]->ProcessEvaluationFiles(generatedFiles);
+ }
+}
+
+std::string cmGlobalGenerator::ExpandCFGIntDir(
+ const std::string& str, const std::string& /*config*/) const
+{
+ return str;
+}
+
+bool cmGlobalGenerator::GenerateCPackPropertiesFile()
+{
+ cmake::InstalledFilesMap const& installedFiles =
+ this->CMakeInstance->GetInstalledFiles();
+
+ cmLocalGenerator* lg = this->LocalGenerators[0];
+ cmMakefile* mf = lg->GetMakefile();
+
+ std::vector<std::string> configs;
+ std::string config = mf->GetConfigurations(configs, false);
+
+ std::string path = this->CMakeInstance->GetHomeOutputDirectory();
+ path += "/CPackProperties.cmake";
+
+ if (!cmSystemTools::FileExists(path.c_str()) && installedFiles.empty()) {
+ return true;
+ }
+
+ cmGeneratedFileStream file(path.c_str());
+ file << "# CPack properties\n";
+
+ for (cmake::InstalledFilesMap::const_iterator i = installedFiles.begin();
+ i != installedFiles.end(); ++i) {
+ cmInstalledFile const& installedFile = i->second;
+
+ cmCPackPropertiesGenerator cpackPropertiesGenerator(lg, installedFile,
+ configs);
+
+ cpackPropertiesGenerator.Generate(file, config, configs);
+ }
+
+ return true;
+}
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
new file mode 100644
index 0000000..089a637
--- /dev/null
+++ b/Source/cmGlobalGenerator.h
@@ -0,0 +1,551 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmGlobalGenerator_h
+#define cmGlobalGenerator_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmExportSetMap.h" // For cmExportSetMap
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmState.h"
+#include "cmSystemTools.h" // for cmSystemTools::OutputOption
+#include "cmTarget.h" // For cmTargets
+#include "cmTargetDepend.h" // For cmTargetDependSet
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmFileLockPool.h"
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+#include <unordered_map>
+#else
+#include <cmsys/hash_map.hxx>
+#endif
+#endif
+
+class cmake;
+class cmGeneratorTarget;
+class cmMakefile;
+class cmLocalGenerator;
+class cmExternalMakefileProjectGenerator;
+class cmTarget;
+class cmInstallTargetGenerator;
+class cmInstallFilesGenerator;
+class cmExportBuildFileGenerator;
+
+/** \class cmGlobalGenerator
+ * \brief Responsible for overseeing the generation process for the entire tree
+ *
+ * Subclasses of this class generate makefiles for various
+ * platforms.
+ */
+class cmGlobalGenerator
+{
+public:
+ ///! Free any memory allocated with the GlobalGenerator
+ cmGlobalGenerator(cmake* cm);
+ virtual ~cmGlobalGenerator();
+
+ virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf);
+
+ ///! Get the name for this generator
+ virtual std::string GetName() const { return "Generic"; }
+
+ /** Check whether the given name matches the current generator. */
+ virtual bool MatchesGeneratorName(const std::string& name) const
+ {
+ return this->GetName() == name;
+ }
+
+ /** Tell the generator about the target system. */
+ virtual bool SetSystemName(std::string const&, cmMakefile*) { return true; }
+
+ /** Set the generator-specific platform name. Returns true if platform
+ is supported and false otherwise. */
+ virtual bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf);
+
+ /** Set the generator-specific toolset name. Returns true if toolset
+ is supported and false otherwise. */
+ virtual bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf);
+
+ /**
+ * Create LocalGenerators and process the CMakeLists files. This does not
+ * actually produce any makefiles, DSPs, etc.
+ */
+ virtual void Configure();
+
+ bool Compute();
+ virtual void AddExtraIDETargets() {}
+
+ enum TargetTypes
+ {
+ AllTargets,
+ ImportedOnly
+ };
+
+ void CreateImportedGenerationObjects(
+ cmMakefile* mf, std::vector<std::string> const& targets,
+ std::vector<cmGeneratorTarget const*>& exports);
+ void CreateGenerationObjects(TargetTypes targetTypes = AllTargets);
+
+ /**
+ * Generate the all required files for building this project/tree. This
+ * basically creates a series of LocalGenerators for each directory and
+ * requests that they Generate.
+ */
+ virtual void Generate();
+
+ /**
+ * Set/Get and Clear the enabled languages.
+ */
+ void SetLanguageEnabled(const std::string&, cmMakefile* mf);
+ bool GetLanguageEnabled(const std::string&) const;
+ void ClearEnabledLanguages();
+ void GetEnabledLanguages(std::vector<std::string>& lang) const;
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+
+ /**
+ * Resolve the CMAKE_<lang>_COMPILER setting for the given language.
+ * Intended to be called from EnableLanguage.
+ */
+ void ResolveLanguageCompiler(const std::string& lang, cmMakefile* mf,
+ bool optional) const;
+
+ /**
+ * Try to determine system information, get it from another generator
+ */
+ void EnableLanguagesFromGenerator(cmGlobalGenerator* gen, cmMakefile* mf);
+
+ /**
+ * Try running cmake and building a file. This is used for dynamically
+ * loaded commands, not as part of the usual build process.
+ */
+ int TryCompile(const std::string& srcdir, const std::string& bindir,
+ const std::string& projectName, const std::string& targetName,
+ bool fast, std::string& output, cmMakefile* mf);
+
+ /**
+ * Build a file given the following information. This is a more direct call
+ * that is used by both CTest and TryCompile. If target name is NULL or
+ * empty then all is assumed. clean indicates if a "make clean" should be
+ * done first.
+ */
+ int Build(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,
+ double timeout, cmSystemTools::OutputOption outputflag =
+ cmSystemTools::OUTPUT_NONE,
+ std::vector<std::string> const& nativeOptions =
+ std::vector<std::string>());
+
+ virtual void GenerateBuildCommand(
+ std::vector<std::string>& makeCommand, const std::string& makeProgram,
+ const std::string& projectName, const std::string& projectDir,
+ const std::string& targetName, const std::string& config, bool fast,
+ bool verbose,
+ std::vector<std::string> const& makeOptions = std::vector<std::string>());
+
+ /** Generate a "cmake --build" call for a given target and config. */
+ std::string GenerateCMakeBuildCommand(const std::string& target,
+ const std::string& config,
+ const std::string& native,
+ bool ignoreErrors);
+
+ ///! Get the CMake instance
+ cmake* GetCMakeInstance() const { return this->CMakeInstance; }
+
+ void SetConfiguredFilesPath(cmGlobalGenerator* gen);
+ const std::vector<cmMakefile*>& GetMakefiles() const
+ {
+ return this->Makefiles;
+ }
+ const std::vector<cmLocalGenerator*>& GetLocalGenerators() const
+ {
+ return this->LocalGenerators;
+ }
+
+ cmMakefile* GetCurrentMakefile() const { return this->CurrentMakefile; }
+
+ void SetCurrentMakefile(cmMakefile* mf) { this->CurrentMakefile = mf; }
+
+ void AddMakefile(cmMakefile* mf);
+
+ ///! Set an generator for an "external makefile based project"
+ void SetExternalMakefileProjectGenerator(
+ cmExternalMakefileProjectGenerator* extraGenerator);
+
+ std::string GetExtraGeneratorName() const;
+
+ void AddInstallComponent(const char* component);
+
+ const std::set<std::string>* GetInstallComponents() const
+ {
+ return &this->InstallComponents;
+ }
+
+ cmExportSetMap& GetExportSets() { return this->ExportSets; }
+
+ /** Add a file to the manifest of generated targets for a configuration. */
+ void AddToManifest(std::string const& f);
+
+ void EnableInstallTarget();
+
+ int TryCompileTimeout;
+
+ bool GetForceUnixPaths() const { return this->ForceUnixPaths; }
+ bool GetToolSupportsColor() const { return this->ToolSupportsColor; }
+
+ ///! return the language for the given extension
+ std::string GetLanguageFromExtension(const char* ext) const;
+ ///! is an extension to be ignored
+ bool IgnoreFile(const char* ext) const;
+ ///! 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?
+ std::string GetLanguageOutputExtension(cmSourceFile const&) const;
+
+ ///! What is the configurations directory variable called?
+ virtual const char* GetCMakeCFGIntDir() const { return "."; }
+
+ ///! expand CFGIntDir for a configuration
+ virtual std::string ExpandCFGIntDir(const std::string& str,
+ const std::string& config) const;
+
+ /** Get whether the generator should use a script for link commands. */
+ bool GetUseLinkScript() const { return this->UseLinkScript; }
+
+ /** Get whether the generator should produce special marks on rules
+ producing symbolic (non-file) outputs. */
+ bool GetNeedSymbolicMark() const { return this->NeedSymbolicMark; }
+
+ /*
+ * Determine what program to use for building the project.
+ */
+ virtual void FindMakeProgram(cmMakefile*);
+
+ ///! Find a target by name by searching the local generators.
+ cmTarget* FindTarget(const std::string& name,
+ bool excludeAliases = false) const;
+
+ cmGeneratorTarget* FindGeneratorTarget(const std::string& name) const;
+
+ void AddAlias(const std::string& name, const std::string& tgtName);
+ bool IsAlias(const std::string& name) const;
+
+ /** Determine if a name resolves to a framework on disk or a built target
+ that is a framework. */
+ bool NameResolvesToFramework(const std::string& libname) const;
+
+ cmMakefile* FindMakefile(const std::string& start_dir) const;
+ ///! Find a local generator by its startdirectory
+ cmLocalGenerator* FindLocalGenerator(const std::string& start_dir) const;
+
+ /** Append the subdirectory for the given configuration. If anything is
+ appended the given prefix and suffix will be appended around it, which
+ is useful for leading or trailing slashes. */
+ virtual void AppendDirectoryForConfig(const std::string& prefix,
+ const std::string& config,
+ const std::string& suffix,
+ std::string& dir);
+
+ /** Get the content of a directory. Directory listings are cached
+ and re-loaded from disk only when modified. During the generation
+ step the content will include the target files to be built even if
+ they do not yet exist. */
+ std::set<std::string> const& GetDirectoryContent(std::string const& dir,
+ bool needDisk = true);
+
+ void IndexTarget(cmTarget* t);
+ void IndexGeneratorTarget(cmGeneratorTarget* gt);
+
+ static bool IsReservedTarget(std::string const& name);
+
+ virtual const char* GetAllTargetName() const { return "ALL_BUILD"; }
+ virtual const char* GetInstallTargetName() const { return "INSTALL"; }
+ virtual const char* GetInstallLocalTargetName() const { return CM_NULLPTR; }
+ virtual const char* GetInstallStripTargetName() const { return CM_NULLPTR; }
+ virtual const char* GetPreinstallTargetName() const { return CM_NULLPTR; }
+ virtual const char* GetTestTargetName() const { return "RUN_TESTS"; }
+ virtual const char* GetPackageTargetName() const { return "PACKAGE"; }
+ virtual const char* GetPackageSourceTargetName() const { return CM_NULLPTR; }
+ virtual const char* GetEditCacheTargetName() const { return CM_NULLPTR; }
+ virtual const char* GetRebuildCacheTargetName() const { return CM_NULLPTR; }
+ virtual const char* GetCleanTargetName() const { return CM_NULLPTR; }
+
+ // Lookup edit_cache target command preferred by this generator.
+ virtual std::string GetEditCacheCommand() const { return ""; }
+
+ // Class to track a set of dependencies.
+ typedef cmTargetDependSet TargetDependSet;
+
+ // what targets does the specified target depend on directly
+ // via a target_link_libraries or add_dependencies
+ TargetDependSet const& GetTargetDirectDepends(
+ const cmGeneratorTarget* target);
+
+ const std::map<std::string, std::vector<cmLocalGenerator*> >& GetProjectMap()
+ const
+ {
+ return this->ProjectMap;
+ }
+
+ // track files replaced during a Generate
+ void FileReplacedDuringGenerate(const std::string& filename);
+ void GetFilesReplacedDuringGenerate(std::vector<std::string>& filenames);
+
+ void AddRuleHash(const std::vector<std::string>& outputs,
+ std::string const& content);
+
+ /** Return whether the given binary directory is unused. */
+ bool BinaryDirectoryIsNew(const std::string& dir)
+ {
+ return this->BinaryDirectories.insert(dir).second;
+ }
+
+ /** Return true if the generated build tree may contain multiple builds.
+ i.e. "Can I build Debug and Release in the same tree?" */
+ virtual bool IsMultiConfig() const { return false; }
+
+ std::string GetSharedLibFlagsForLanguage(std::string const& lang) const;
+
+ /** Generate an <output>.rule file path for a given command output. */
+ virtual std::string GenerateRuleFile(std::string const& output) const;
+
+ static std::string EscapeJSON(const std::string& s);
+
+ void ProcessEvaluationFiles();
+
+ std::map<std::string, cmExportBuildFileGenerator*>& GetBuildExportSets()
+ {
+ return this->BuildExportSets;
+ }
+ void AddBuildExportSet(cmExportBuildFileGenerator*);
+ void AddBuildExportExportSet(cmExportBuildFileGenerator*);
+ bool IsExportedTargetsFile(const std::string& filename) const;
+ bool GenerateImportFile(const std::string& file);
+ cmExportBuildFileGenerator* GetExportedTargetsFile(
+ const std::string& filename) const;
+ void AddCMP0042WarnTarget(const std::string& target);
+
+ virtual void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const;
+
+ bool GenerateCPackPropertiesFile();
+
+ void CreateEvaluationSourceFiles(std::string const& config) const;
+
+ void SetFilenameTargetDepends(
+ cmSourceFile* sf, std::set<cmGeneratorTarget const*> const& tgts);
+ const std::set<const cmGeneratorTarget*>& GetFilenameTargetDepends(
+ cmSourceFile* sf) const;
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ cmFileLockPool& GetFileLockPool() { return FileLockPool; }
+#endif
+
+ bool GetConfigureDoneCMP0026() const
+ {
+ return this->ConfigureDoneCMP0026AndCMP0024;
+ }
+
+ std::string MakeSilentFlag;
+
+protected:
+ typedef std::vector<cmLocalGenerator*> GeneratorVector;
+ // for a project collect all its targets by following depend
+ // information, and also collect all the targets
+ void GetTargetSets(TargetDependSet& projectTargets,
+ TargetDependSet& originalTargets, cmLocalGenerator* root,
+ GeneratorVector const&);
+ bool IsRootOnlyTarget(cmGeneratorTarget* target) const;
+ void AddTargetDepends(const cmGeneratorTarget* target,
+ TargetDependSet& projectTargets);
+ void SetLanguageEnabledFlag(const std::string& l, cmMakefile* mf);
+ void SetLanguageEnabledMaps(const std::string& l, cmMakefile* mf);
+ void FillExtensionToLanguageMap(const std::string& l, cmMakefile* mf);
+ virtual void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
+ const char* envVar) const;
+
+ virtual bool ComputeTargetDepends();
+
+ virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const;
+
+ std::vector<const cmGeneratorTarget*> CreateQtAutoGeneratorsTargets();
+
+ std::string SelectMakeProgram(const std::string& makeProgram,
+ const std::string& makeDefault = "") const;
+
+ // Fill the ProjectMap, this must be called after LocalGenerators
+ // has been populated.
+ void FillProjectMap();
+ void CheckTargetProperties();
+ bool IsExcluded(cmState::Snapshot const& root,
+ cmState::Snapshot const& snp) const;
+ bool IsExcluded(cmLocalGenerator* root, cmLocalGenerator* gen) const;
+ bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target) const;
+ virtual void InitializeProgressMarks() {}
+ void CreateDefaultGlobalTargets(cmTargets* targets);
+ cmTarget CreateGlobalTarget(const std::string& name, const char* message,
+ const cmCustomCommandLines* commandLines,
+ std::vector<std::string> depends,
+ const char* workingDir, bool uses_terminal);
+
+ std::string FindMakeProgramFile;
+ std::string ConfiguredFilesPath;
+ cmake* CMakeInstance;
+ std::vector<cmMakefile*> Makefiles;
+ std::vector<cmLocalGenerator*> LocalGenerators;
+ cmMakefile* CurrentMakefile;
+ // map from project name to vector of local generators in that project
+ std::map<std::string, std::vector<cmLocalGenerator*> > ProjectMap;
+
+ // Set of named installation components requested by the project.
+ std::set<std::string> InstallComponents;
+ // Sets of named target exports
+ cmExportSetMap ExportSets;
+ std::map<std::string, cmExportBuildFileGenerator*> BuildExportSets;
+ std::map<std::string, cmExportBuildFileGenerator*> BuildExportExportSets;
+
+ std::map<std::string, std::string> AliasTargets;
+
+ cmTarget* FindTargetImpl(std::string const& name) const;
+
+ cmGeneratorTarget* FindGeneratorTargetImpl(std::string const& name) const;
+ cmGeneratorTarget* FindImportedGeneratorTargetImpl(
+ std::string const& name) const;
+
+ const char* GetPredefinedTargetsFolder();
+ virtual bool UseFolderProperty();
+
+private:
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+ typedef std::unordered_map<std::string, cmTarget*> TargetMap;
+ typedef std::unordered_map<std::string, cmGeneratorTarget*>
+ GeneratorTargetMap;
+#else
+ typedef cmsys::hash_map<std::string, cmTarget*> TargetMap;
+ typedef cmsys::hash_map<std::string, cmGeneratorTarget*> GeneratorTargetMap;
+#endif
+#else
+ typedef std::map<std::string, cmTarget*> TargetMap;
+ typedef std::map<std::string, cmGeneratorTarget*> GeneratorTargetMap;
+#endif
+ // Map efficiently from target name to cmTarget instance.
+ // Do not use this structure for looping over all targets.
+ // It contains both normal and globally visible imported targets.
+ TargetMap TargetSearchIndex;
+ GeneratorTargetMap GeneratorTargetSearchIndex;
+
+ cmMakefile* TryCompileOuterMakefile;
+ // If you add a new map here, make sure it is copied
+ // in EnableLanguagesFromGenerator
+ std::map<std::string, bool> IgnoreExtensions;
+ std::set<std::string> LanguagesReady; // Ready for try_compile
+ std::set<std::string> LanguagesInProgress;
+ std::map<std::string, std::string> OutputExtensions;
+ std::map<std::string, std::string> LanguageToOutputExtension;
+ std::map<std::string, std::string> ExtensionToLanguage;
+ std::map<std::string, int> LanguageToLinkerPreference;
+ std::map<std::string, std::string> LanguageToOriginalSharedLibFlags;
+
+ // Record hashes for rules and outputs.
+ struct RuleHash
+ {
+ char Data[32];
+ };
+ std::map<std::string, RuleHash> RuleHashes;
+ void CheckRuleHashes();
+ void CheckRuleHashes(std::string const& pfile, std::string const& home);
+ void WriteRuleHashes(std::string const& pfile);
+
+ void WriteSummary();
+ void WriteSummary(cmGeneratorTarget* target);
+ void FinalizeTargetCompileInfo();
+
+ virtual void ForceLinkerLanguages();
+
+ void CreateLocalGenerators();
+
+ void CheckCompilerIdCompatibility(cmMakefile* mf,
+ std::string const& lang) const;
+
+ void ComputeBuildFileGenerators();
+
+ cmExternalMakefileProjectGenerator* ExtraGenerator;
+
+ // track files replaced during a Generate
+ std::vector<std::string> FilesReplacedDuringGenerate;
+
+ // Store computed inter-target dependencies.
+ typedef std::map<cmGeneratorTarget const*, TargetDependSet> TargetDependMap;
+ TargetDependMap TargetDependencies;
+
+ friend class cmake;
+ void CreateGeneratorTargets(
+ TargetTypes targetTypes, cmMakefile* mf, cmLocalGenerator* lg,
+ std::map<cmTarget*, cmGeneratorTarget*> const& importedMap);
+ void CreateGeneratorTargets(TargetTypes targetTypes);
+
+ void ClearGeneratorMembers();
+
+ virtual const char* GetBuildIgnoreErrorsFlag() const { return CM_NULLPTR; }
+
+ // Cache directory content and target files to be built.
+ struct DirectoryContent
+ {
+ long LastDiskTime;
+ std::set<std::string> All;
+ std::set<std::string> Generated;
+ DirectoryContent()
+ : LastDiskTime(-1)
+ {
+ }
+ DirectoryContent(DirectoryContent const& dc)
+ : LastDiskTime(dc.LastDiskTime)
+ , All(dc.All)
+ , Generated(dc.Generated)
+ {
+ }
+ };
+ std::map<std::string, DirectoryContent> DirectoryContentMap;
+
+ // Set of binary directories on disk.
+ std::set<std::string> BinaryDirectories;
+
+ // track targets to issue CMP0042 warning for.
+ std::set<std::string> CMP0042WarnTargets;
+
+ mutable std::map<cmSourceFile*, std::set<cmGeneratorTarget const*> >
+ FilenameTargetDepends;
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ // Pool of file locks
+ cmFileLockPool FileLockPool;
+#endif
+
+protected:
+ float FirstTimeProgress;
+ bool NeedSymbolicMark;
+ bool UseLinkScript;
+ bool ForceUnixPaths;
+ bool ToolSupportsColor;
+ bool InstallTargetEnabled;
+ bool ConfigureDoneCMP0026AndCMP0024;
+};
+
+#endif
diff --git a/Source/cmGlobalGeneratorFactory.h b/Source/cmGlobalGeneratorFactory.h
new file mode 100644
index 0000000..6787519
--- /dev/null
+++ b/Source/cmGlobalGeneratorFactory.h
@@ -0,0 +1,76 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmGlobalGeneratorFactory_h
+#define cmGlobalGeneratorFactory_h
+
+#include "cmStandardIncludes.h"
+
+class cmake;
+class cmGlobalGenerator;
+struct cmDocumentationEntry;
+
+/** \class cmGlobalGeneratorFactory
+ * \brief Responable for creating cmGlobalGenerator instances
+ *
+ * Subclasses of this class generate instances of cmGlobalGenerator.
+ */
+class cmGlobalGeneratorFactory
+{
+public:
+ virtual ~cmGlobalGeneratorFactory() {}
+
+ /** Create a GlobalGenerator */
+ virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& n,
+ cmake* cm) const = 0;
+
+ /** Get the documentation entry for this factory */
+ virtual void GetDocumentation(cmDocumentationEntry& entry) const = 0;
+
+ /** Get the names of the current registered generators */
+ virtual void GetGenerators(std::vector<std::string>& names) const = 0;
+
+ /** Determine whether or not this generator supports toolsets */
+ virtual bool SupportsToolset() const = 0;
+};
+
+template <class T>
+class cmGlobalGeneratorSimpleFactory : public cmGlobalGeneratorFactory
+{
+public:
+ /** Create a GlobalGenerator */
+ cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
+ cmake* cm) const CM_OVERRIDE
+ {
+ if (name != T::GetActualName()) {
+ return CM_NULLPTR;
+ }
+ return new T(cm);
+ }
+
+ /** Get the documentation entry for this factory */
+ void GetDocumentation(cmDocumentationEntry& entry) const CM_OVERRIDE
+ {
+ T::GetDocumentation(entry);
+ }
+
+ /** Get the names of the current registered generators */
+ void GetGenerators(std::vector<std::string>& names) const CM_OVERRIDE
+ {
+ names.push_back(T::GetActualName());
+ }
+
+ /** Determine whether or not this generator supports toolsets */
+ bool SupportsToolset() const CM_OVERRIDE { return T::SupportsToolset(); }
+};
+
+#endif
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
new file mode 100644
index 0000000..0ae913e
--- /dev/null
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -0,0 +1,499 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Geoffrey Viola <geoffrey.viola@asirobots.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalGhsMultiGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGhsMultiTargetGenerator.h"
+#include "cmLocalGhsMultiGenerator.h"
+#include "cmMakefile.h"
+#include "cmVersion.h"
+#include <cmAlgorithms.h>
+#include <cmsys/SystemTools.hxx>
+
+const char* cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj";
+const char* cmGlobalGhsMultiGenerator::DEFAULT_MAKE_PROGRAM = "gbuild";
+
+cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm)
+ : cmGlobalGenerator(cm)
+ , OSDirRelative(false)
+{
+ this->GhsBuildCommandInitialized = false;
+}
+
+cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator()
+{
+ cmDeleteAll(TargetFolderBuildStreams);
+}
+
+cmLocalGenerator* cmGlobalGhsMultiGenerator::CreateLocalGenerator(
+ cmMakefile* mf)
+{
+ return new cmLocalGhsMultiGenerator(this, mf);
+}
+
+void cmGlobalGhsMultiGenerator::GetDocumentation(cmDocumentationEntry& entry)
+{
+ entry.Name = GetActualName();
+ entry.Brief =
+ "Generates Green Hills MULTI files (experimental, work-in-progress).";
+}
+
+void cmGlobalGhsMultiGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ mf->AddDefinition("CMAKE_SYSTEM_NAME", "GHS-MULTI");
+ mf->AddDefinition("CMAKE_SYSTEM_PROCESSOR", "ARM");
+
+ const std::string ghsCompRoot(GetCompRoot());
+ mf->AddDefinition("GHS_COMP_ROOT", ghsCompRoot.c_str());
+ std::string ghsCompRootStart =
+ 0 == ghsCompRootStart.size() ? "" : ghsCompRoot + "/";
+ mf->AddDefinition("CMAKE_C_COMPILER",
+ std::string(ghsCompRootStart + "ccarm.exe").c_str());
+ mf->AddDefinition("CMAKE_C_COMPILER_ID_RUN", "TRUE");
+ mf->AddDefinition("CMAKE_C_COMPILER_ID", "GHS");
+ mf->AddDefinition("CMAKE_C_COMPILER_FORCED", "TRUE");
+
+ mf->AddDefinition("CMAKE_CXX_COMPILER",
+ std::string(ghsCompRootStart + "cxarm.exe").c_str());
+ mf->AddDefinition("CMAKE_CXX_COMPILER_ID_RUN", "TRUE");
+ mf->AddDefinition("CMAKE_CXX_COMPILER_ID", "GHS");
+ mf->AddDefinition("CMAKE_CXX_COMPILER_FORCED", "TRUE");
+
+ if (!ghsCompRoot.empty()) {
+ static const char* compPreFix = "comp_";
+ std::string compFilename =
+ cmsys::SystemTools::FindLastString(ghsCompRoot.c_str(), compPreFix);
+ cmsys::SystemTools::ReplaceString(compFilename, compPreFix, "");
+ mf->AddDefinition("CMAKE_SYSTEM_VERSION", compFilename.c_str());
+ }
+
+ mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files
+ this->cmGlobalGenerator::EnableLanguage(l, mf, optional);
+}
+
+void cmGlobalGhsMultiGenerator::FindMakeProgram(cmMakefile* mf)
+{
+ // The GHS generator knows how to lookup its build tool
+ // directly instead of needing a helper module to do it, so we
+ // do not actually need to put CMAKE_MAKE_PROGRAM into the cache.
+ if (cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
+ mf->AddDefinition("CMAKE_MAKE_PROGRAM",
+ this->GetGhsBuildCommand().c_str());
+ }
+}
+
+std::string const& cmGlobalGhsMultiGenerator::GetGhsBuildCommand()
+{
+ if (!this->GhsBuildCommandInitialized) {
+ this->GhsBuildCommandInitialized = true;
+ this->GhsBuildCommand = this->FindGhsBuildCommand();
+ }
+ return this->GhsBuildCommand;
+}
+
+std::string cmGlobalGhsMultiGenerator::FindGhsBuildCommand()
+{
+ std::vector<std::string> userPaths;
+ userPaths.push_back(this->GetCompRoot());
+ std::string makeProgram =
+ cmSystemTools::FindProgram(DEFAULT_MAKE_PROGRAM, userPaths);
+ if (makeProgram.empty()) {
+ makeProgram = DEFAULT_MAKE_PROGRAM;
+ }
+ return makeProgram;
+}
+
+std::string cmGlobalGhsMultiGenerator::GetCompRoot()
+{
+ std::string output;
+
+ const std::vector<std::string> potentialDirsHardPaths(
+ GetCompRootHardPaths());
+ const std::vector<std::string> potentialDirsRegistry(GetCompRootRegistry());
+
+ std::vector<std::string> potentialDirsComplete;
+ potentialDirsComplete.insert(potentialDirsComplete.end(),
+ potentialDirsHardPaths.begin(),
+ potentialDirsHardPaths.end());
+ potentialDirsComplete.insert(potentialDirsComplete.end(),
+ potentialDirsRegistry.begin(),
+ potentialDirsRegistry.end());
+
+ // Use latest version
+ std::string outputDirName;
+ for (std::vector<std::string>::const_iterator potentialDirsCompleteIt =
+ potentialDirsComplete.begin();
+ potentialDirsCompleteIt != potentialDirsComplete.end();
+ ++potentialDirsCompleteIt) {
+ const std::string dirName(
+ cmsys::SystemTools::GetFilenameName(*potentialDirsCompleteIt));
+ if (dirName.compare(outputDirName) > 0) {
+ output = *potentialDirsCompleteIt;
+ outputDirName = dirName;
+ }
+ }
+
+ return output;
+}
+
+std::vector<std::string> cmGlobalGhsMultiGenerator::GetCompRootHardPaths()
+{
+ std::vector<std::string> output;
+ cmSystemTools::Glob("C:/ghs", "comp_[^;]+", output);
+ for (std::vector<std::string>::iterator outputIt = output.begin();
+ outputIt != output.end(); ++outputIt) {
+ *outputIt = "C:/ghs/" + *outputIt;
+ }
+ return output;
+}
+
+std::vector<std::string> cmGlobalGhsMultiGenerator::GetCompRootRegistry()
+{
+ std::vector<std::string> output(2);
+ cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_"
+ "MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\"
+ "Windows\\CurrentVersion\\Uninstall\\"
+ "GreenHillsSoftwared771f1b4;InstallLocation",
+ output[0]);
+ cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_"
+ "MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\"
+ "Windows\\CurrentVersion\\Uninstall\\"
+ "GreenHillsSoftware9881cef6;InstallLocation",
+ output[1]);
+ return output;
+}
+
+void cmGlobalGhsMultiGenerator::OpenBuildFileStream(
+ std::string const& filepath, cmGeneratedFileStream** filestream)
+{
+ // Get a stream where to generate things.
+ if (NULL == *filestream) {
+ *filestream = new cmGeneratedFileStream(filepath.c_str());
+ if (NULL != *filestream) {
+ OpenBuildFileStream(*filestream);
+ }
+ }
+}
+
+void cmGlobalGhsMultiGenerator::OpenBuildFileStream(
+ cmGeneratedFileStream* filestream)
+{
+ *filestream << "#!gbuild" << std::endl;
+}
+
+void cmGlobalGhsMultiGenerator::OpenBuildFileStream()
+{
+ // Compute GHS MULTI's build file path.
+ std::string buildFilePath =
+ this->GetCMakeInstance()->GetHomeOutputDirectory();
+ buildFilePath += "/";
+ buildFilePath += "default";
+ buildFilePath += FILE_EXTENSION;
+
+ this->Open(std::string(""), buildFilePath, &this->TargetFolderBuildStreams);
+ OpenBuildFileStream(GetBuildFileStream());
+
+ char const* osDir =
+ this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR");
+ if (NULL == osDir) {
+ osDir = "";
+ cmSystemTools::Error("GHS_OS_DIR cache variable must be set");
+ } else {
+ this->GetCMakeInstance()->MarkCliAsUsed("GHS_OS_DIR");
+ }
+ std::string fOSDir(this->trimQuotes(osDir));
+ std::replace(fOSDir.begin(), fOSDir.end(), '\\', '/');
+ if (!fOSDir.empty() && ('c' == fOSDir[0] || 'C' == fOSDir[0])) {
+ this->OSDirRelative = false;
+ } else {
+ this->OSDirRelative = true;
+ }
+
+ char const* bspName =
+ this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME");
+ if (NULL == bspName) {
+ bspName = "";
+ cmSystemTools::Error("GHS_BSP_NAME cache variable must be set");
+ } else {
+ this->GetCMakeInstance()->MarkCliAsUsed("GHS_BSP_NAME");
+ }
+ std::string fBspName(this->trimQuotes(bspName));
+ std::replace(fBspName.begin(), fBspName.end(), '\\', '/');
+ this->WriteMacros();
+ this->WriteHighLevelDirectives();
+
+ GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, this->GetBuildFileStream());
+ this->WriteDisclaimer(this->GetBuildFileStream());
+ *this->GetBuildFileStream() << "# Top Level Project File" << std::endl;
+ if (!fBspName.empty()) {
+ *this->GetBuildFileStream() << " -bsp " << fBspName << std::endl;
+ }
+ this->WriteCompilerOptions(fOSDir);
+}
+
+void cmGlobalGhsMultiGenerator::CloseBuildFileStream(
+ cmGeneratedFileStream** filestream)
+{
+ if (filestream) {
+ delete *filestream;
+ *filestream = NULL;
+ } else {
+ cmSystemTools::Error("Build file stream was not open.");
+ }
+}
+
+void cmGlobalGhsMultiGenerator::Generate()
+{
+ this->cmGlobalGenerator::Generate();
+
+ if (!this->LocalGenerators.empty()) {
+ this->OpenBuildFileStream();
+
+ // Build all the folder build files
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ cmLocalGhsMultiGenerator* lg =
+ static_cast<cmLocalGhsMultiGenerator*>(this->LocalGenerators[i]);
+ std::vector<cmGeneratorTarget*> tgts = lg->GetGeneratorTargets();
+ this->UpdateBuildFiles(tgts);
+ }
+ }
+
+ cmDeleteAll(TargetFolderBuildStreams);
+ this->TargetFolderBuildStreams.clear();
+}
+
+void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
+ std::vector<std::string>& makeCommand, const std::string& makeProgram,
+ const std::string& /*projectName*/, const std::string& /*projectDir*/,
+ const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
+ bool /*verbose*/, std::vector<std::string> const& makeOptions)
+{
+ makeCommand.push_back(
+ this->SelectMakeProgram(makeProgram, this->GetGhsBuildCommand()));
+
+ makeCommand.insert(makeCommand.end(), makeOptions.begin(),
+ makeOptions.end());
+ if (!targetName.empty()) {
+ if (targetName == "clean") {
+ makeCommand.push_back("-clean");
+ } else {
+ makeCommand.push_back(targetName);
+ }
+ }
+}
+
+void cmGlobalGhsMultiGenerator::WriteMacros()
+{
+ char const* ghsGpjMacros =
+ this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
+ if (NULL != 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) {
+ *this->GetBuildFileStream() << "macro " << *expandedListI << std::endl;
+ }
+ }
+}
+
+void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives()
+{
+ *this->GetBuildFileStream() << "primaryTarget=arm_integrity.tgt"
+ << std::endl;
+ char const* const customization =
+ this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
+ if (NULL != customization && strlen(customization) > 0) {
+ *this->GetBuildFileStream()
+ << "customization=" << trimQuotes(customization) << std::endl;
+ this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
+ }
+}
+
+void cmGlobalGhsMultiGenerator::WriteCompilerOptions(std::string const& fOSDir)
+{
+ *this->GetBuildFileStream() << " -os_dir=\"" << fOSDir << "\""
+ << std::endl;
+}
+
+void cmGlobalGhsMultiGenerator::WriteDisclaimer(std::ostream* os)
+{
+ (*os) << "#" << std::endl
+ << "# CMAKE generated file: DO NOT EDIT!" << std::endl
+ << "# Generated by \"" << GetActualName() << "\""
+ << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
+ << cmVersion::GetMinorVersion() << std::endl
+ << "#" << std::endl;
+}
+
+void cmGlobalGhsMultiGenerator::AddFilesUpToPath(
+ cmGeneratedFileStream* mainBuildFile,
+ std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams,
+ char const* homeOutputDirectory, std::string const& path,
+ GhsMultiGpj::Types projType, std::string const& relPath)
+{
+ std::string workingPath(path);
+ cmSystemTools::ConvertToUnixSlashes(workingPath);
+ std::vector<cmsys::String> splitPath =
+ cmSystemTools::SplitString(workingPath);
+ std::string workingRelPath(relPath);
+ cmSystemTools::ConvertToUnixSlashes(workingRelPath);
+ if (!workingRelPath.empty()) {
+ workingRelPath += "/";
+ }
+ std::string pathUpTo;
+ for (std::vector<cmsys::String>::const_iterator splitPathI =
+ splitPath.begin();
+ splitPath.end() != splitPathI; ++splitPathI) {
+ pathUpTo += *splitPathI;
+ if (targetFolderBuildStreams->end() ==
+ targetFolderBuildStreams->find(pathUpTo)) {
+ AddFilesUpToPathNewBuildFile(
+ mainBuildFile, targetFolderBuildStreams, homeOutputDirectory, pathUpTo,
+ splitPath.begin() == splitPathI, workingRelPath, projType);
+ }
+ AddFilesUpToPathAppendNextFile(targetFolderBuildStreams, pathUpTo,
+ splitPathI, splitPath.end(), projType);
+ pathUpTo += "/";
+ }
+}
+
+void cmGlobalGhsMultiGenerator::Open(
+ std::string const& mapKeyName, std::string const& fileName,
+ std::map<std::string, cmGeneratedFileStream*>* fileMap)
+{
+ if (fileMap->end() == fileMap->find(fileName)) {
+ cmGeneratedFileStream* temp(new cmGeneratedFileStream);
+ temp->open(fileName.c_str());
+ (*fileMap)[mapKeyName] = temp;
+ }
+}
+
+void cmGlobalGhsMultiGenerator::AddFilesUpToPathNewBuildFile(
+ cmGeneratedFileStream* mainBuildFile,
+ std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams,
+ char const* homeOutputDirectory, std::string const& pathUpTo,
+ bool const isFirst, std::string const& relPath,
+ GhsMultiGpj::Types const projType)
+{
+ // create folders up to file path
+ std::string absPath = std::string(homeOutputDirectory) + "/" + relPath;
+ std::string newPath = absPath + pathUpTo;
+ if (!cmSystemTools::FileExists(newPath.c_str())) {
+ cmSystemTools::MakeDirectory(newPath.c_str());
+ }
+
+ // Write out to filename for first time
+ std::string relFilename(GetFileNameFromPath(pathUpTo));
+ std::string absFilename = absPath + relFilename;
+ Open(pathUpTo, absFilename, targetFolderBuildStreams);
+ OpenBuildFileStream((*targetFolderBuildStreams)[pathUpTo]);
+ GhsMultiGpj::WriteGpjTag(projType, (*targetFolderBuildStreams)[pathUpTo]);
+ WriteDisclaimer((*targetFolderBuildStreams)[pathUpTo]);
+
+ // Add to main build file
+ if (isFirst) {
+ *mainBuildFile << relFilename << " ";
+ GhsMultiGpj::WriteGpjTag(projType, mainBuildFile);
+ }
+}
+
+void cmGlobalGhsMultiGenerator::AddFilesUpToPathAppendNextFile(
+ std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams,
+ std::string const& pathUpTo,
+ std::vector<cmsys::String>::const_iterator splitPathI,
+ std::vector<cmsys::String>::const_iterator end,
+ GhsMultiGpj::Types const projType)
+{
+ std::vector<cmsys::String>::const_iterator splitPathNextI = splitPathI + 1;
+ if (end != splitPathNextI &&
+ targetFolderBuildStreams->end() ==
+ targetFolderBuildStreams->find(pathUpTo + "/" + *splitPathNextI)) {
+ std::string nextFilename(*splitPathNextI);
+ nextFilename = GetFileNameFromPath(nextFilename);
+ *(*targetFolderBuildStreams)[pathUpTo] << nextFilename << " ";
+ GhsMultiGpj::WriteGpjTag(projType, (*targetFolderBuildStreams)[pathUpTo]);
+ }
+}
+
+std::string cmGlobalGhsMultiGenerator::GetFileNameFromPath(
+ std::string const& path)
+{
+ std::string output(path);
+ if (!path.empty()) {
+ cmSystemTools::ConvertToUnixSlashes(output);
+ std::vector<cmsys::String> splitPath = cmSystemTools::SplitString(output);
+ output += "/" + splitPath.back() + FILE_EXTENSION;
+ }
+ return output;
+}
+
+void cmGlobalGhsMultiGenerator::UpdateBuildFiles(
+ std::vector<cmGeneratorTarget*> tgts)
+{
+ for (std::vector<cmGeneratorTarget*>::iterator tgtsI = tgts.begin();
+ tgtsI != tgts.end(); ++tgtsI) {
+ const cmGeneratorTarget* tgt = *tgtsI;
+ if (IsTgtForBuild(tgt)) {
+ char const* rawFolderName = tgt->GetProperty("FOLDER");
+ if (NULL == rawFolderName) {
+ rawFolderName = "";
+ }
+ std::string folderName(rawFolderName);
+ if (this->TargetFolderBuildStreams.end() ==
+ this->TargetFolderBuildStreams.find(folderName)) {
+ this->AddFilesUpToPath(
+ GetBuildFileStream(), &this->TargetFolderBuildStreams,
+ this->GetCMakeInstance()->GetHomeOutputDirectory(), folderName,
+ GhsMultiGpj::PROJECT);
+ }
+ std::vector<cmsys::String> splitPath = cmSystemTools::SplitString(
+ cmGhsMultiTargetGenerator::GetRelBuildFileName(tgt));
+ std::string foldNameRelBuildFile(*(splitPath.end() - 2) + "/" +
+ splitPath.back());
+ *this->TargetFolderBuildStreams[folderName] << foldNameRelBuildFile
+ << " ";
+ GhsMultiGpj::WriteGpjTag(cmGhsMultiTargetGenerator::GetGpjTag(tgt),
+ this->TargetFolderBuildStreams[folderName]);
+ }
+ }
+}
+
+bool cmGlobalGhsMultiGenerator::IsTgtForBuild(const cmGeneratorTarget* tgt)
+{
+ const std::string config =
+ tgt->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ std::vector<cmSourceFile*> tgtSources;
+ tgt->GetSourceFiles(tgtSources, config);
+ bool tgtInBuild = true;
+ char const* excludeFromAll = tgt->GetProperty("EXCLUDE_FROM_ALL");
+ if (NULL != excludeFromAll && '1' == excludeFromAll[0] &&
+ '\0' == excludeFromAll[1]) {
+ tgtInBuild = false;
+ }
+ return !tgtSources.empty() && tgtInBuild;
+}
+
+std::string cmGlobalGhsMultiGenerator::trimQuotes(std::string const& str)
+{
+ std::string result;
+ result.reserve(str.size());
+ for (const char* ch = str.c_str(); *ch != '\0'; ++ch) {
+ if (*ch != '"') {
+ result += *ch;
+ }
+ }
+ return result;
+}
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
new file mode 100644
index 0000000..473d153
--- /dev/null
+++ b/Source/cmGlobalGhsMultiGenerator.h
@@ -0,0 +1,136 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Geoffrey Viola <geoffrey.viola@asirobots.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGhsMultiGenerator_h
+#define cmGhsMultiGenerator_h
+
+#include "cmGlobalGenerator.h"
+
+#include "cmGhsMultiGpj.h"
+#include "cmGlobalGeneratorFactory.h"
+
+class cmGeneratedFileStream;
+
+class cmGlobalGhsMultiGenerator : public cmGlobalGenerator
+{
+public:
+ /// The default name of GHS MULTI's build file. Typically: monolith.gpj.
+ static const char* FILE_EXTENSION;
+
+ cmGlobalGhsMultiGenerator(cmake* cm);
+ ~cmGlobalGhsMultiGenerator();
+
+ static cmGlobalGeneratorFactory* NewFactory()
+ {
+ return new cmGlobalGeneratorSimpleFactory<cmGlobalGhsMultiGenerator>();
+ }
+
+ ///! create the correct local generator
+ virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf);
+
+ /// @return the name of this generator.
+ static std::string GetActualName() { return "Green Hills MULTI"; }
+
+ ///! Get the name for this generator
+ virtual std::string GetName() const { return this->GetActualName(); }
+
+ /// Overloaded methods. @see cmGlobalGenerator::GetDocumentation()
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ /**
+ * Utilized by the generator factory to determine if this generator
+ * supports toolsets.
+ */
+ static bool SupportsToolset() { return false; }
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+ /*
+ * Determine what program to use for building the project.
+ */
+ virtual void FindMakeProgram(cmMakefile*);
+
+ cmGeneratedFileStream* GetBuildFileStream()
+ {
+ return this->TargetFolderBuildStreams[""];
+ }
+
+ static void OpenBuildFileStream(std::string const& filepath,
+ cmGeneratedFileStream** filestream);
+ static void OpenBuildFileStream(cmGeneratedFileStream* filestream);
+ static void CloseBuildFileStream(cmGeneratedFileStream** filestream);
+ /// Write the common disclaimer text at the top of each build file.
+ static void WriteDisclaimer(std::ostream* os);
+ std::vector<std::string> GetLibDirs() { return this->LibDirs; }
+
+ static void AddFilesUpToPath(
+ cmGeneratedFileStream* mainBuildFile,
+ std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams,
+ char const* homeOutputDirectory, std::string const& path,
+ GhsMultiGpj::Types projType, std::string const& relPath = "");
+ static void Open(std::string const& mapKeyName, std::string const& fileName,
+ std::map<std::string, cmGeneratedFileStream*>* fileMap);
+
+ static std::string trimQuotes(std::string const& str);
+ inline bool IsOSDirRelative() { return this->OSDirRelative; }
+
+protected:
+ virtual void Generate();
+ virtual void GenerateBuildCommand(
+ std::vector<std::string>& makeCommand, const std::string& makeProgram,
+ const std::string& projectName, const std::string& projectDir,
+ const std::string& targetName, const std::string& config, bool fast,
+ bool verbose,
+ std::vector<std::string> const& makeOptions = std::vector<std::string>());
+
+private:
+ std::string const& GetGhsBuildCommand();
+ std::string FindGhsBuildCommand();
+ std::string GetCompRoot();
+ std::vector<std::string> GetCompRootHardPaths();
+ std::vector<std::string> GetCompRootRegistry();
+ void OpenBuildFileStream();
+
+ void WriteMacros();
+ void WriteHighLevelDirectives();
+ void WriteCompilerOptions(std::string const& fOSDir);
+
+ static void AddFilesUpToPathNewBuildFile(
+ cmGeneratedFileStream* mainBuildFile,
+ std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams,
+ char const* homeOutputDirectory, std::string const& pathUpTo, bool isFirst,
+ std::string const& relPath, GhsMultiGpj::Types projType);
+ static void AddFilesUpToPathAppendNextFile(
+ std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams,
+ std::string const& pathUpTo,
+ std::vector<cmsys::String>::const_iterator splitPathI,
+ std::vector<cmsys::String>::const_iterator end,
+ GhsMultiGpj::Types projType);
+ static std::string GetFileNameFromPath(std::string const& path);
+ void UpdateBuildFiles(std::vector<cmGeneratorTarget*> tgts);
+ bool IsTgtForBuild(const cmGeneratorTarget* tgt);
+
+ std::vector<cmGeneratedFileStream*> TargetSubProjects;
+ std::map<std::string, cmGeneratedFileStream*> TargetFolderBuildStreams;
+
+ std::vector<std::string> LibDirs;
+
+ bool OSDirRelative;
+ bool GhsBuildCommandInitialized;
+ std::string GhsBuildCommand;
+ static const char* DEFAULT_MAKE_PROGRAM;
+};
+
+#endif
diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx
new file mode 100644
index 0000000..0bdd624
--- /dev/null
+++ b/Source/cmGlobalJOMMakefileGenerator.cxx
@@ -0,0 +1,61 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalJOMMakefileGenerator.h"
+
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+
+cmGlobalJOMMakefileGenerator::cmGlobalJOMMakefileGenerator(cmake* cm)
+ : cmGlobalUnixMakefileGenerator3(cm)
+{
+ this->FindMakeProgramFile = "CMakeJOMFindMake.cmake";
+ this->ForceUnixPaths = false;
+ this->ToolSupportsColor = true;
+ this->UseLinkScript = false;
+ cm->GetState()->SetWindowsShell(true);
+ cm->GetState()->SetNMake(true);
+ this->DefineWindowsNULL = true;
+ this->PassMakeflags = true;
+ this->UnixCD = false;
+ this->MakeSilentFlag = "/nologo";
+}
+
+void cmGlobalJOMMakefileGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ // pick a default
+ mf->AddDefinition("CMAKE_GENERATOR_CC", "cl");
+ mf->AddDefinition("CMAKE_GENERATOR_CXX", "cl");
+ this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
+}
+
+void cmGlobalJOMMakefileGenerator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalJOMMakefileGenerator::GetActualName();
+ entry.Brief = "Generates JOM makefiles.";
+}
+
+void cmGlobalJOMMakefileGenerator::PrintCompilerAdvice(
+ std::ostream& os, std::string const& lang, const char* envVar) const
+{
+ if (lang == "CXX" || lang == "C") {
+ /* clang-format off */
+ os <<
+ "To use the JOM generator with Visual C++, cmake must be run from a "
+ "shell that can use the compiler cl from the command line. This "
+ "environment is unable to invoke the cl compiler. To fix this problem, "
+ "run cmake from the Visual Studio Command Prompt (vcvarsall.bat).\n";
+ /* clang-format on */
+ }
+ this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
+}
diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h
new file mode 100644
index 0000000..bb2273a
--- /dev/null
+++ b/Source/cmGlobalJOMMakefileGenerator.h
@@ -0,0 +1,54 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalJOMMakefileGenerator_h
+#define cmGlobalJOMMakefileGenerator_h
+
+#include "cmGlobalUnixMakefileGenerator3.h"
+
+/** \class cmGlobalJOMMakefileGenerator
+ * \brief Write a JOM makefiles.
+ *
+ * cmGlobalJOMMakefileGenerator manages nmake build process for a tree
+ */
+class cmGlobalJOMMakefileGenerator : public cmGlobalUnixMakefileGenerator3
+{
+public:
+ cmGlobalJOMMakefileGenerator(cmake* cm);
+ static cmGlobalGeneratorFactory* NewFactory()
+ {
+ return new cmGlobalGeneratorSimpleFactory<cmGlobalJOMMakefileGenerator>();
+ }
+ ///! Get the name for the generator.
+ virtual std::string GetName() const
+ {
+ return cmGlobalJOMMakefileGenerator::GetActualName();
+ }
+ // use NMake Makefiles in the name so that scripts/tests that depend on the
+ // name NMake Makefiles will work
+ static std::string GetActualName() { return "NMake Makefiles JOM"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+
+private:
+ void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
+ const char* envVar) const;
+};
+
+#endif
diff --git a/Source/cmGlobalKdevelopGenerator.cxx b/Source/cmGlobalKdevelopGenerator.cxx
new file mode 100644
index 0000000..bbd6baa
--- /dev/null
+++ b/Source/cmGlobalKdevelopGenerator.cxx
@@ -0,0 +1,602 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2009 Kitware, Inc.
+ Copyright 2004 Alexander Neundorf (neundorf@kde.org)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalKdevelopGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/SystemTools.hxx>
+
+void cmGlobalKdevelopGenerator::GetDocumentation(cmDocumentationEntry& entry,
+ const std::string&) const
+{
+ entry.Name = this->GetName();
+ entry.Brief = "Generates KDevelop 3 project files.";
+}
+
+cmGlobalKdevelopGenerator::cmGlobalKdevelopGenerator()
+ : cmExternalMakefileProjectGenerator()
+{
+ this->SupportedGlobalGenerators.push_back("Unix Makefiles");
+#ifdef CMAKE_USE_NINJA
+ this->SupportedGlobalGenerators.push_back("Ninja");
+#endif
+}
+
+void cmGlobalKdevelopGenerator::Generate()
+{
+ // for each sub project in the project create
+ // a kdevelop project
+ for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
+ it = this->GlobalGenerator->GetProjectMap().begin();
+ it != this->GlobalGenerator->GetProjectMap().end(); ++it) {
+ std::string outputDir = it->second[0]->GetCurrentBinaryDirectory();
+ std::string projectDir = it->second[0]->GetSourceDirectory();
+ std::string projectName = it->second[0]->GetProjectName();
+ std::string cmakeFilePattern("CMakeLists.txt;*.cmake;");
+ std::string fileToOpen;
+ const std::vector<cmLocalGenerator*>& lgs = it->second;
+ // create the project.kdevelop.filelist file
+ if (!this->CreateFilelistFile(lgs, outputDir, projectDir, projectName,
+ cmakeFilePattern, fileToOpen)) {
+ cmSystemTools::Error("Can not create filelist file");
+ return;
+ }
+ // try to find the name of an executable so we have something to
+ // run from kdevelop for now just pick the first executable found
+ std::string executable;
+ for (std::vector<cmLocalGenerator*>::const_iterator lg = lgs.begin();
+ lg != lgs.end(); lg++) {
+ std::vector<cmGeneratorTarget*> const& targets =
+ (*lg)->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::const_iterator ti =
+ targets.begin();
+ ti != targets.end(); ti++) {
+ if ((*ti)->GetType() == cmState::EXECUTABLE) {
+ executable = (*ti)->GetLocation("");
+ break;
+ }
+ }
+ if (!executable.empty()) {
+ break;
+ }
+ }
+
+ // now create a project file
+ this->CreateProjectFile(outputDir, projectDir, projectName, executable,
+ cmakeFilePattern, fileToOpen);
+ }
+}
+
+bool cmGlobalKdevelopGenerator::CreateFilelistFile(
+ const std::vector<cmLocalGenerator*>& lgs, const std::string& outputDir,
+ const std::string& projectDirIn, const std::string& projectname,
+ std::string& cmakeFilePattern, std::string& fileToOpen)
+{
+ std::string projectDir = projectDirIn + "/";
+ std::string filename = outputDir + "/" + projectname + ".kdevelop.filelist";
+
+ std::set<std::string> files;
+ std::string tmp;
+
+ std::vector<std::string> hdrExts =
+ this->GlobalGenerator->GetCMakeInstance()->GetHeaderExtensions();
+
+ for (std::vector<cmLocalGenerator*>::const_iterator it = lgs.begin();
+ it != lgs.end(); it++) {
+ cmMakefile* makefile = (*it)->GetMakefile();
+ const std::vector<std::string>& listFiles = makefile->GetListFiles();
+ for (std::vector<std::string>::const_iterator lt = listFiles.begin();
+ lt != listFiles.end(); lt++) {
+ tmp = *lt;
+ cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
+ // make sure the file is part of this source tree
+ if ((tmp[0] != '/') &&
+ (strstr(tmp.c_str(), cmake::GetCMakeFilesDirectoryPostSlash()) ==
+ CM_NULLPTR)) {
+ files.insert(tmp);
+ tmp = cmSystemTools::GetFilenameName(tmp);
+ // add all files which dont match the default
+ // */CMakeLists.txt;*cmake; to the file pattern
+ if ((tmp != "CMakeLists.txt") &&
+ (strstr(tmp.c_str(), ".cmake") == CM_NULLPTR)) {
+ cmakeFilePattern += tmp + ";";
+ }
+ }
+ }
+
+ // get all sources
+ std::vector<cmGeneratorTarget*> targets = (*it)->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator ti = targets.begin();
+ ti != targets.end(); ti++) {
+ std::vector<cmSourceFile*> sources;
+ cmGeneratorTarget* gt = *ti;
+ gt->GetSourceFiles(sources, gt->Target->GetMakefile()->GetSafeDefinition(
+ "CMAKE_BUILD_TYPE"));
+ for (std::vector<cmSourceFile*>::const_iterator si = sources.begin();
+ si != sources.end(); si++) {
+ tmp = (*si)->GetFullPath();
+ std::string headerBasename = cmSystemTools::GetFilenamePath(tmp);
+ headerBasename += "/";
+ headerBasename += cmSystemTools::GetFilenameWithoutExtension(tmp);
+
+ cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
+
+ if ((tmp[0] != '/') &&
+ (strstr(tmp.c_str(), cmake::GetCMakeFilesDirectoryPostSlash()) ==
+ CM_NULLPTR) &&
+ (cmSystemTools::GetFilenameExtension(tmp) != ".moc")) {
+ files.insert(tmp);
+
+ // check if there's a matching header around
+ for (std::vector<std::string>::const_iterator ext = hdrExts.begin();
+ ext != hdrExts.end(); ++ext) {
+ std::string hname = headerBasename;
+ hname += ".";
+ hname += *ext;
+ if (cmSystemTools::FileExists(hname.c_str())) {
+ cmSystemTools::ReplaceString(hname, projectDir.c_str(), "");
+ files.insert(hname);
+ break;
+ }
+ }
+ }
+ }
+ for (std::vector<std::string>::const_iterator lt = listFiles.begin();
+ lt != listFiles.end(); lt++) {
+ tmp = *lt;
+ cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
+ if ((tmp[0] != '/') &&
+ (strstr(tmp.c_str(), cmake::GetCMakeFilesDirectoryPostSlash()) ==
+ CM_NULLPTR)) {
+ files.insert(tmp);
+ }
+ }
+ }
+ }
+
+ // check if the output file already exists and read it
+ // insert all files which exist into the set of files
+ cmsys::ifstream oldFilelist(filename.c_str());
+ if (oldFilelist) {
+ while (cmSystemTools::GetLineFromStream(oldFilelist, tmp)) {
+ if (tmp[0] == '/') {
+ continue;
+ }
+ std::string completePath = projectDir + tmp;
+ if (cmSystemTools::FileExists(completePath.c_str())) {
+ files.insert(tmp);
+ }
+ }
+ oldFilelist.close();
+ }
+
+ // now write the new filename
+ cmGeneratedFileStream fout(filename.c_str());
+ if (!fout) {
+ return false;
+ }
+
+ fileToOpen = "";
+ for (std::set<std::string>::const_iterator it = files.begin();
+ it != files.end(); it++) {
+ // get the full path to the file
+ tmp = cmSystemTools::CollapseFullPath(*it, projectDir.c_str());
+ // just select the first source file
+ if (fileToOpen.empty()) {
+ std::string ext = cmSystemTools::GetFilenameExtension(tmp);
+ if ((ext == ".c") || (ext == ".cc") || (ext == ".cpp") ||
+ (ext == ".cxx") || (ext == ".C") || (ext == ".h") ||
+ (ext == ".hpp")) {
+ fileToOpen = tmp;
+ }
+ }
+ // make it relative to the project dir
+ cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
+ // only put relative paths
+ if (!tmp.empty() && tmp[0] != '/') {
+ fout << tmp << "\n";
+ }
+ }
+ return true;
+}
+
+/* create the project file, if it already exists, merge it with the
+existing one, otherwise create a new one */
+void cmGlobalKdevelopGenerator::CreateProjectFile(
+ const std::string& outputDir, const std::string& projectDir,
+ const std::string& projectname, const std::string& executable,
+ const std::string& cmakeFilePattern, const std::string& fileToOpen)
+{
+ this->Blacklist.clear();
+
+ std::string filename = outputDir + "/";
+ filename += projectname + ".kdevelop";
+ std::string sessionFilename = outputDir + "/";
+ sessionFilename += projectname + ".kdevses";
+
+ if (cmSystemTools::FileExists(filename.c_str())) {
+ this->MergeProjectFiles(outputDir, projectDir, filename, executable,
+ cmakeFilePattern, fileToOpen, sessionFilename);
+ } else {
+ // add all subdirectories which are cmake build directories to the
+ // kdevelop blacklist so they are not monitored for added or removed files
+ // since this is handled by adding files to the cmake files
+ cmsys::Directory d;
+ if (d.Load(projectDir)) {
+ size_t numf = d.GetNumberOfFiles();
+ for (unsigned int i = 0; i < numf; i++) {
+ std::string nextFile = d.GetFile(i);
+ if ((nextFile != ".") && (nextFile != "..")) {
+ std::string tmp = projectDir;
+ tmp += "/";
+ tmp += nextFile;
+ if (cmSystemTools::FileIsDirectory(tmp)) {
+ tmp += "/CMakeCache.txt";
+ if ((nextFile == "CMakeFiles") ||
+ (cmSystemTools::FileExists(tmp.c_str()))) {
+ this->Blacklist.push_back(nextFile);
+ }
+ }
+ }
+ }
+ }
+ this->CreateNewProjectFile(outputDir, projectDir, filename, executable,
+ cmakeFilePattern, fileToOpen, sessionFilename);
+ }
+}
+
+void cmGlobalKdevelopGenerator::MergeProjectFiles(
+ const std::string& outputDir, const std::string& projectDir,
+ const std::string& filename, const std::string& executable,
+ const std::string& cmakeFilePattern, const std::string& fileToOpen,
+ const std::string& sessionFilename)
+{
+ cmsys::ifstream oldProjectFile(filename.c_str());
+ if (!oldProjectFile) {
+ this->CreateNewProjectFile(outputDir, projectDir, filename, executable,
+ cmakeFilePattern, fileToOpen, sessionFilename);
+ return;
+ }
+
+ /* Read the existing project file (line by line), copy all lines
+ into the new project file, except the ones which can be reliably
+ set from contents of the CMakeLists.txt */
+ std::string tmp;
+ std::vector<std::string> lines;
+ while (cmSystemTools::GetLineFromStream(oldProjectFile, tmp)) {
+ lines.push_back(tmp);
+ }
+ oldProjectFile.close();
+
+ cmGeneratedFileStream fout(filename.c_str());
+ if (!fout) {
+ return;
+ }
+
+ for (std::vector<std::string>::const_iterator it = lines.begin();
+ it != lines.end(); it++) {
+ const char* line = (*it).c_str();
+ // skip these tags as they are always replaced
+ if ((strstr(line, "<projectdirectory>") != CM_NULLPTR) ||
+ (strstr(line, "<projectmanagement>") != CM_NULLPTR) ||
+ (strstr(line, "<absoluteprojectpath>") != CM_NULLPTR) ||
+ (strstr(line, "<filelistdirectory>") != CM_NULLPTR) ||
+ (strstr(line, "<buildtool>") != CM_NULLPTR) ||
+ (strstr(line, "<builddir>") != CM_NULLPTR)) {
+ continue;
+ }
+
+ // output the line from the file if it is not one of the above tags
+ fout << *it << "\n";
+ // if this is the <general> tag output the stuff that goes in the
+ // general tag
+ if (strstr(line, "<general>")) {
+ fout << " <projectmanagement>KDevCustomProject</projectmanagement>\n";
+ fout << " <projectdirectory>" << projectDir
+ << "</projectdirectory>\n"; // this one is important
+ fout << " <absoluteprojectpath>true</absoluteprojectpath>\n";
+ // and this one
+ }
+ // inside kdevcustomproject the <filelistdirectory> must be put
+ if (strstr(line, "<kdevcustomproject>")) {
+ fout << " <filelistdirectory>" << outputDir
+ << "</filelistdirectory>\n";
+ }
+ // buildtool and builddir go inside <build>
+ if (strstr(line, "<build>")) {
+ fout << " <buildtool>make</buildtool>\n";
+ fout << " <builddir>" << outputDir << "</builddir>\n";
+ }
+ }
+}
+
+void cmGlobalKdevelopGenerator::CreateNewProjectFile(
+ const std::string& outputDir, const std::string& projectDir,
+ const std::string& filename, const std::string& executable,
+ const std::string& cmakeFilePattern, const std::string& fileToOpen,
+ const std::string& sessionFilename)
+{
+ cmGeneratedFileStream fout(filename.c_str());
+ if (!fout) {
+ return;
+ }
+ cmXMLWriter xml(fout);
+
+ // check for a version control system
+ bool hasSvn = cmSystemTools::FileExists((projectDir + "/.svn").c_str());
+ bool hasCvs = cmSystemTools::FileExists((projectDir + "/CVS").c_str());
+
+ bool enableCxx = (this->GlobalGenerator->GetLanguageEnabled("C") ||
+ this->GlobalGenerator->GetLanguageEnabled("CXX"));
+ bool enableFortran = this->GlobalGenerator->GetLanguageEnabled("Fortran");
+ std::string primaryLanguage = "C++";
+ if (enableFortran && !enableCxx) {
+ primaryLanguage = "Fortran77";
+ }
+
+ xml.StartDocument();
+ xml.StartElement("kdevelop");
+ xml.StartElement("general");
+
+ xml.Element("author", "");
+ xml.Element("email", "");
+ xml.Element("version", "$VERSION$");
+ xml.Element("projectmanagement", "KDevCustomProject");
+ xml.Element("primarylanguage", primaryLanguage);
+ xml.Element("ignoreparts");
+ xml.Element("projectdirectory", projectDir); // this one is important
+ xml.Element("absoluteprojectpath", "true"); // and this one
+
+ // setup additional languages
+ xml.StartElement("secondaryLanguages");
+ if (enableFortran && enableCxx) {
+ xml.Element("language", "Fortran");
+ }
+ if (enableCxx) {
+ xml.Element("language", "C");
+ }
+ xml.EndElement();
+
+ if (hasSvn) {
+ xml.Element("versioncontrol", "kdevsubversion");
+ } else if (hasCvs) {
+ xml.Element("versioncontrol", "kdevcvsservice");
+ }
+
+ xml.EndElement(); // general
+ xml.StartElement("kdevcustomproject");
+
+ xml.Element("filelistdirectory", outputDir);
+
+ xml.StartElement("run");
+ xml.Element("mainprogram", executable);
+ xml.Element("directoryradio", "custom");
+ xml.Element("customdirectory", outputDir);
+ xml.Element("programargs", "");
+ xml.Element("terminal", "false");
+ xml.Element("autocompile", "true");
+ xml.Element("envvars");
+ xml.EndElement();
+
+ xml.StartElement("build");
+ xml.Element("buildtool", "make"); // this one is important
+ xml.Element("builddir", outputDir); // and this one
+ xml.EndElement();
+
+ xml.StartElement("make");
+ xml.Element("abortonerror", "false");
+ xml.Element("numberofjobs", 1);
+ xml.Element("dontact", "false");
+ xml.Element("makebin", this->GlobalGenerator->GetLocalGenerators()[0]
+ ->GetMakefile()
+ ->GetRequiredDefinition("CMAKE_MAKE_PROGRAM"));
+ xml.Element("selectedenvironment", "default");
+
+ xml.StartElement("environments");
+ xml.StartElement("default");
+
+ xml.StartElement("envvar");
+ xml.Attribute("value", 1);
+ xml.Attribute("name", "VERBOSE");
+ xml.EndElement();
+
+ xml.StartElement("envvar");
+ xml.Attribute("value", 1);
+ xml.Attribute("name", "CMAKE_NO_VERBOSE");
+ xml.EndElement();
+
+ xml.EndElement(); // default
+ xml.EndElement(); // environments
+ xml.EndElement(); // make
+
+ xml.StartElement("blacklist");
+ for (std::vector<std::string>::const_iterator dirIt =
+ this->Blacklist.begin();
+ dirIt != this->Blacklist.end(); ++dirIt) {
+ xml.Element("path", *dirIt);
+ }
+ xml.EndElement();
+
+ xml.EndElement(); // kdevcustomproject
+
+ xml.StartElement("kdevfilecreate");
+ xml.Element("filetypes");
+ xml.StartElement("useglobaltypes");
+
+ xml.StartElement("type");
+ xml.Attribute("ext", "ui");
+ xml.EndElement();
+
+ xml.StartElement("type");
+ xml.Attribute("ext", "cpp");
+ xml.EndElement();
+
+ xml.StartElement("type");
+ xml.Attribute("ext", "h");
+ xml.EndElement();
+
+ xml.EndElement(); // useglobaltypes
+ xml.EndElement(); // kdevfilecreate
+
+ xml.StartElement("kdevdoctreeview");
+ xml.StartElement("projectdoc");
+ xml.Element("userdocDir", "html/");
+ xml.Element("apidocDir", "html/");
+ xml.EndElement(); // projectdoc
+ xml.Element("ignoreqt_xml");
+ xml.Element("ignoredoxygen");
+ xml.Element("ignorekdocs");
+ xml.Element("ignoretocs");
+ xml.Element("ignoredevhelp");
+ xml.EndElement(); // kdevdoctreeview;
+
+ if (enableCxx) {
+ xml.StartElement("cppsupportpart");
+ xml.StartElement("filetemplates");
+ xml.Element("interfacesuffix", ".h");
+ xml.Element("implementationsuffix", ".cpp");
+ xml.EndElement(); // filetemplates
+ xml.EndElement(); // cppsupportpart
+
+ xml.StartElement("kdevcppsupport");
+ xml.StartElement("codecompletion");
+ xml.Element("includeGlobalFunctions", "true");
+ xml.Element("includeTypes", "true");
+ xml.Element("includeEnums", "true");
+ xml.Element("includeTypedefs", "false");
+ xml.Element("automaticCodeCompletion", "true");
+ xml.Element("automaticArgumentsHint", "true");
+ xml.Element("automaticHeaderCompletion", "true");
+ xml.Element("codeCompletionDelay", 250);
+ xml.Element("argumentsHintDelay", 400);
+ xml.Element("headerCompletionDelay", 250);
+ xml.EndElement(); // codecompletion
+ xml.Element("references");
+ xml.EndElement(); // kdevcppsupport;
+ }
+
+ if (enableFortran) {
+ xml.StartElement("kdevfortransupport");
+ xml.StartElement("ftnchek");
+ xml.Element("division", "false");
+ xml.Element("extern", "false");
+ xml.Element("declare", "false");
+ xml.Element("pure", "false");
+ xml.Element("argumentsall", "false");
+ xml.Element("commonall", "false");
+ xml.Element("truncationall", "false");
+ xml.Element("usageall", "false");
+ xml.Element("f77all", "false");
+ xml.Element("portabilityall", "false");
+ xml.Element("argumentsonly");
+ xml.Element("commononly");
+ xml.Element("truncationonly");
+ xml.Element("usageonly");
+ xml.Element("f77only");
+ xml.Element("portabilityonly");
+ xml.EndElement(); // ftnchek
+ xml.EndElement(); // kdevfortransupport;
+ }
+
+ // set up file groups. maybe this can be used with the CMake SOURCE_GROUP()
+ // command
+ xml.StartElement("kdevfileview");
+ xml.StartElement("groups");
+
+ xml.StartElement("group");
+ xml.Attribute("pattern", cmakeFilePattern);
+ xml.Attribute("name", "CMake");
+ xml.EndElement();
+
+ if (enableCxx) {
+ xml.StartElement("group");
+ xml.Attribute("pattern", "*.h;*.hxx;*.hpp");
+ xml.Attribute("name", "Header");
+ xml.EndElement();
+
+ xml.StartElement("group");
+ xml.Attribute("pattern", "*.c");
+ xml.Attribute("name", "C Sources");
+ xml.EndElement();
+
+ xml.StartElement("group");
+ xml.Attribute("pattern", "*.cpp;*.C;*.cxx;*.cc");
+ xml.Attribute("name", "C++ Sources");
+ xml.EndElement();
+ }
+
+ if (enableFortran) {
+ xml.StartElement("group");
+ xml.Attribute("pattern",
+ "*.f;*.F;*.f77;*.F77;*.f90;*.F90;*.for;*.f95;*.F95");
+ xml.Attribute("name", "Fortran Sources");
+ xml.EndElement();
+ }
+
+ xml.StartElement("group");
+ xml.Attribute("pattern", "*.ui");
+ xml.Attribute("name", "Qt Designer files");
+ xml.EndElement();
+
+ xml.Element("hidenonprojectfiles", "true");
+ xml.EndElement(); // groups
+
+ xml.StartElement("tree");
+ xml.Element("hidepatterns", "*.o,*.lo,CVS,*~,cmake*");
+ xml.Element("hidenonprojectfiles", "true");
+ xml.EndElement(); // tree
+
+ xml.EndElement(); // kdevfileview
+ xml.EndElement(); // kdevelop;
+ xml.EndDocument();
+
+ if (sessionFilename.empty()) {
+ return;
+ }
+
+ // and a session file, so that kdevelop opens a file if it opens the
+ // project the first time
+ cmGeneratedFileStream devses(sessionFilename.c_str());
+ if (!devses) {
+ return;
+ }
+ cmXMLWriter sesxml(devses);
+ sesxml.StartDocument("UTF-8");
+ sesxml.Doctype("KDevPrjSession");
+ sesxml.StartElement("KDevPrjSession");
+
+ sesxml.StartElement("DocsAndViews");
+ sesxml.Attribute("NumberOfDocuments", 1);
+
+ sesxml.StartElement("Doc0");
+ sesxml.Attribute("NumberOfViews", 1);
+ sesxml.Attribute("URL", "file://" + fileToOpen);
+
+ sesxml.StartElement("View0");
+ sesxml.Attribute("line", 0);
+ sesxml.Attribute("Type", "Source");
+ sesxml.EndElement(); // View0
+
+ sesxml.EndElement(); // Doc0
+ sesxml.EndElement(); // DocsAndViews
+ sesxml.EndElement(); // KDevPrjSession;
+}
diff --git a/Source/cmGlobalKdevelopGenerator.h b/Source/cmGlobalKdevelopGenerator.h
new file mode 100644
index 0000000..c61cafb
--- /dev/null
+++ b/Source/cmGlobalKdevelopGenerator.h
@@ -0,0 +1,97 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2009 Kitware, Inc.
+ Copyright 2004 Alexander Neundorf (neundorf@kde.org)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalKdevelopGenerator_h
+#define cmGlobalKdevelopGenerator_h
+
+#include "cmExternalMakefileProjectGenerator.h"
+
+class cmLocalGenerator;
+
+/** \class cmGlobalKdevelopGenerator
+ * \brief Write Unix Makefiles accompanied by KDevelop3 project files.
+ *
+ * cmGlobalKdevelopGenerator produces a project file for KDevelop 3 (KDevelop
+ * > 3.1.1). The project is based on the "Custom Makefile based C/C++"
+ * project of KDevelop. Such a project consists of Unix Makefiles in the
+ * build directory together with a \<your_project\>.kdevelop project file,
+ * which contains the project settings and a \<your_project\>.kdevelop.filelist
+ * file, which lists the source files relative to the kdevelop project
+ * directory. The kdevelop project directory is the base source directory.
+ */
+class cmGlobalKdevelopGenerator : public cmExternalMakefileProjectGenerator
+{
+public:
+ cmGlobalKdevelopGenerator();
+
+ std::string GetName() const CM_OVERRIDE
+ {
+ return cmGlobalKdevelopGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "KDevelop3"; }
+ static cmExternalMakefileProjectGenerator* New()
+ {
+ return new cmGlobalKdevelopGenerator;
+ }
+ /** Get the documentation entry for this generator. */
+ void GetDocumentation(cmDocumentationEntry& entry,
+ const std::string& fullName) const CM_OVERRIDE;
+
+ void Generate() CM_OVERRIDE;
+
+private:
+ /*** Create the foo.kdevelop.filelist file, return false if it doesn't
+ succeed. If the file already exists the contents will be merged.
+ */
+ bool CreateFilelistFile(const std::vector<cmLocalGenerator*>& lgs,
+ const std::string& outputDir,
+ const std::string& projectDirIn,
+ const std::string& projectname,
+ std::string& cmakeFilePattern,
+ std::string& fileToOpen);
+
+ /** Create the foo.kdevelop file. This one calls MergeProjectFiles()
+ if it already exists, otherwise createNewProjectFile() The project
+ files will be created in \a outputDir (in the build tree), the
+ kdevelop project dir will be set to \a projectDir (in the source
+ tree). \a cmakeFilePattern consists of a lists of all cmake
+ listfiles used by this CMakeLists.txt */
+ void CreateProjectFile(const std::string& outputDir,
+ const std::string& projectDir,
+ const std::string& projectname,
+ const std::string& executable,
+ const std::string& cmakeFilePattern,
+ const std::string& fileToOpen);
+
+ /*** Reads the old foo.kdevelop line by line and only replaces the
+ "important" lines
+ */
+ void MergeProjectFiles(const std::string& outputDir,
+ const std::string& projectDir,
+ const std::string& filename,
+ const std::string& executable,
+ const std::string& cmakeFilePattern,
+ const std::string& fileToOpen,
+ const std::string& sessionFilename);
+ ///! Creates a new foo.kdevelop and a new foo.kdevses file
+ void CreateNewProjectFile(const std::string& outputDir,
+ const std::string& projectDir,
+ const std::string& filename,
+ const std::string& executable,
+ const std::string& cmakeFilePattern,
+ const std::string& fileToOpen,
+ const std::string& sessionFilename);
+
+ std::vector<std::string> Blacklist;
+};
+
+#endif
diff --git a/Source/cmGlobalMSYSMakefileGenerator.cxx b/Source/cmGlobalMSYSMakefileGenerator.cxx
new file mode 100644
index 0000000..6bf178a
--- /dev/null
+++ b/Source/cmGlobalMSYSMakefileGenerator.cxx
@@ -0,0 +1,94 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalMSYSMakefileGenerator.h"
+
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmake.h"
+#include <cmsys/FStream.hxx>
+
+cmGlobalMSYSMakefileGenerator::cmGlobalMSYSMakefileGenerator(cmake* cm)
+ : cmGlobalUnixMakefileGenerator3(cm)
+{
+ this->FindMakeProgramFile = "CMakeMSYSFindMake.cmake";
+ this->ForceUnixPaths = true;
+ this->ToolSupportsColor = true;
+ this->UseLinkScript = false;
+ cm->GetState()->SetMSYSShell(true);
+}
+
+std::string cmGlobalMSYSMakefileGenerator::FindMinGW(
+ std::string const& makeloc)
+{
+ std::string fstab = makeloc;
+ fstab += "/../etc/fstab";
+ cmsys::ifstream fin(fstab.c_str());
+ std::string path;
+ std::string mount;
+ std::string mingwBin;
+ while (fin) {
+ fin >> path;
+ fin >> mount;
+ if (mount == "/mingw") {
+ mingwBin = path;
+ mingwBin += "/bin";
+ }
+ }
+ return mingwBin;
+}
+
+void cmGlobalMSYSMakefileGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ this->FindMakeProgram(mf);
+ std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ std::vector<std::string> locations;
+ std::string makeloc = cmSystemTools::GetProgramPath(makeProgram.c_str());
+ locations.push_back(this->FindMinGW(makeloc));
+ locations.push_back(makeloc);
+ locations.push_back("/mingw/bin");
+ locations.push_back("c:/mingw/bin");
+ std::string tgcc = cmSystemTools::FindProgram("gcc", locations);
+ std::string gcc = "gcc.exe";
+ if (!tgcc.empty()) {
+ gcc = tgcc;
+ }
+ std::string tgxx = cmSystemTools::FindProgram("g++", locations);
+ std::string gxx = "g++.exe";
+ if (!tgxx.empty()) {
+ gxx = tgxx;
+ }
+ std::string trc = cmSystemTools::FindProgram("windres", locations);
+ std::string rc = "windres.exe";
+ if (!trc.empty()) {
+ rc = trc;
+ }
+ mf->AddDefinition("MSYS", "1");
+ mf->AddDefinition("CMAKE_GENERATOR_CC", gcc.c_str());
+ mf->AddDefinition("CMAKE_GENERATOR_CXX", gxx.c_str());
+ mf->AddDefinition("CMAKE_GENERATOR_RC", rc.c_str());
+ this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
+
+ 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"));
+ }
+}
+
+void cmGlobalMSYSMakefileGenerator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalMSYSMakefileGenerator::GetActualName();
+ entry.Brief = "Generates MSYS makefiles.";
+}
diff --git a/Source/cmGlobalMSYSMakefileGenerator.h b/Source/cmGlobalMSYSMakefileGenerator.h
new file mode 100644
index 0000000..d687d19
--- /dev/null
+++ b/Source/cmGlobalMSYSMakefileGenerator.h
@@ -0,0 +1,52 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalMSYSMakefileGenerator_h
+#define cmGlobalMSYSMakefileGenerator_h
+
+#include "cmGlobalUnixMakefileGenerator3.h"
+
+/** \class cmGlobalMSYSMakefileGenerator
+ * \brief Write a NMake makefiles.
+ *
+ * cmGlobalMSYSMakefileGenerator manages nmake build process for a tree
+ */
+class cmGlobalMSYSMakefileGenerator : public cmGlobalUnixMakefileGenerator3
+{
+public:
+ cmGlobalMSYSMakefileGenerator(cmake* cm);
+ static cmGlobalGeneratorFactory* NewFactory()
+ {
+ return new cmGlobalGeneratorSimpleFactory<cmGlobalMSYSMakefileGenerator>();
+ }
+
+ ///! Get the name for the generator.
+ virtual std::string GetName() const
+ {
+ return cmGlobalMSYSMakefileGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "MSYS Makefiles"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+
+private:
+ std::string FindMinGW(std::string const& makeloc);
+};
+
+#endif
diff --git a/Source/cmGlobalMinGWMakefileGenerator.cxx b/Source/cmGlobalMinGWMakefileGenerator.cxx
new file mode 100644
index 0000000..05f1b36
--- /dev/null
+++ b/Source/cmGlobalMinGWMakefileGenerator.cxx
@@ -0,0 +1,63 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalMinGWMakefileGenerator.h"
+
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+
+cmGlobalMinGWMakefileGenerator::cmGlobalMinGWMakefileGenerator(cmake* cm)
+ : cmGlobalUnixMakefileGenerator3(cm)
+{
+ this->FindMakeProgramFile = "CMakeMinGWFindMake.cmake";
+ this->ForceUnixPaths = true;
+ this->ToolSupportsColor = true;
+ this->UseLinkScript = true;
+ cm->GetState()->SetWindowsShell(true);
+ cm->GetState()->SetMinGWMake(true);
+}
+
+void cmGlobalMinGWMakefileGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ this->FindMakeProgram(mf);
+ std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ std::vector<std::string> locations;
+ locations.push_back(cmSystemTools::GetProgramPath(makeProgram));
+ locations.push_back("/mingw/bin");
+ locations.push_back("c:/mingw/bin");
+ std::string tgcc = cmSystemTools::FindProgram("gcc", locations);
+ std::string gcc = "gcc.exe";
+ if (!tgcc.empty()) {
+ gcc = tgcc;
+ }
+ std::string tgxx = cmSystemTools::FindProgram("g++", locations);
+ std::string gxx = "g++.exe";
+ if (!tgxx.empty()) {
+ gxx = tgxx;
+ }
+ std::string trc = cmSystemTools::FindProgram("windres", locations);
+ std::string rc = "windres.exe";
+ if (!trc.empty()) {
+ rc = trc;
+ }
+ mf->AddDefinition("CMAKE_GENERATOR_CC", gcc.c_str());
+ mf->AddDefinition("CMAKE_GENERATOR_CXX", gxx.c_str());
+ mf->AddDefinition("CMAKE_GENERATOR_RC", rc.c_str());
+ this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
+}
+
+void cmGlobalMinGWMakefileGenerator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalMinGWMakefileGenerator::GetActualName();
+ entry.Brief = "Generates a make file for use with mingw32-make.";
+}
diff --git a/Source/cmGlobalMinGWMakefileGenerator.h b/Source/cmGlobalMinGWMakefileGenerator.h
new file mode 100644
index 0000000..90cfde7
--- /dev/null
+++ b/Source/cmGlobalMinGWMakefileGenerator.h
@@ -0,0 +1,49 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalMinGWMakefileGenerator_h
+#define cmGlobalMinGWMakefileGenerator_h
+
+#include "cmGlobalUnixMakefileGenerator3.h"
+
+/** \class cmGlobalMinGWMakefileGenerator
+ * \brief Write a NMake makefiles.
+ *
+ * cmGlobalMinGWMakefileGenerator manages nmake build process for a tree
+ */
+class cmGlobalMinGWMakefileGenerator : public cmGlobalUnixMakefileGenerator3
+{
+public:
+ cmGlobalMinGWMakefileGenerator(cmake* cm);
+ static cmGlobalGeneratorFactory* NewFactory()
+ {
+ return new cmGlobalGeneratorSimpleFactory<
+ cmGlobalMinGWMakefileGenerator>();
+ }
+ ///! Get the name for the generator.
+ virtual std::string GetName() const
+ {
+ return cmGlobalMinGWMakefileGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "MinGW Makefiles"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+};
+
+#endif
diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx
new file mode 100644
index 0000000..605a773
--- /dev/null
+++ b/Source/cmGlobalNMakeMakefileGenerator.cxx
@@ -0,0 +1,61 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalNMakeMakefileGenerator.h"
+
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+
+cmGlobalNMakeMakefileGenerator::cmGlobalNMakeMakefileGenerator(cmake* cm)
+ : cmGlobalUnixMakefileGenerator3(cm)
+{
+ this->FindMakeProgramFile = "CMakeNMakeFindMake.cmake";
+ this->ForceUnixPaths = false;
+ this->ToolSupportsColor = true;
+ this->UseLinkScript = false;
+ cm->GetState()->SetWindowsShell(true);
+ cm->GetState()->SetNMake(true);
+ this->DefineWindowsNULL = true;
+ this->PassMakeflags = true;
+ this->UnixCD = false;
+ this->MakeSilentFlag = "/nologo";
+}
+
+void cmGlobalNMakeMakefileGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ // pick a default
+ mf->AddDefinition("CMAKE_GENERATOR_CC", "cl");
+ mf->AddDefinition("CMAKE_GENERATOR_CXX", "cl");
+ this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
+}
+
+void cmGlobalNMakeMakefileGenerator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalNMakeMakefileGenerator::GetActualName();
+ entry.Brief = "Generates NMake makefiles.";
+}
+
+void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice(
+ std::ostream& os, std::string const& lang, const char* envVar) const
+{
+ if (lang == "CXX" || lang == "C") {
+ /* clang-format off */
+ os <<
+ "To use the NMake generator with Visual C++, cmake must be run from a "
+ "shell that can use the compiler cl from the command line. This "
+ "environment is unable to invoke the cl compiler. To fix this problem, "
+ "run cmake from the Visual Studio Command Prompt (vcvarsall.bat).\n";
+ /* clang-format on */
+ }
+ this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
+}
diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h
new file mode 100644
index 0000000..3ab684e
--- /dev/null
+++ b/Source/cmGlobalNMakeMakefileGenerator.h
@@ -0,0 +1,53 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalNMakeMakefileGenerator_h
+#define cmGlobalNMakeMakefileGenerator_h
+
+#include "cmGlobalUnixMakefileGenerator3.h"
+
+/** \class cmGlobalNMakeMakefileGenerator
+ * \brief Write a NMake makefiles.
+ *
+ * cmGlobalNMakeMakefileGenerator manages nmake build process for a tree
+ */
+class cmGlobalNMakeMakefileGenerator : public cmGlobalUnixMakefileGenerator3
+{
+public:
+ cmGlobalNMakeMakefileGenerator(cmake* cm);
+ static cmGlobalGeneratorFactory* NewFactory()
+ {
+ return new cmGlobalGeneratorSimpleFactory<
+ cmGlobalNMakeMakefileGenerator>();
+ }
+ ///! Get the name for the generator.
+ virtual std::string GetName() const
+ {
+ return cmGlobalNMakeMakefileGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "NMake Makefiles"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+
+private:
+ void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
+ const char* envVar) const;
+};
+
+#endif
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
new file mode 100644
index 0000000..91f08e6
--- /dev/null
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -0,0 +1,1306 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
+ Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalNinjaGenerator.h"
+
+#include "cmAlgorithms.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpressionEvaluationFile.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalNinjaGenerator.h"
+#include "cmMakefile.h"
+#include "cmVersion.h"
+
+#include <algorithm>
+#include <assert.h>
+#include <ctype.h>
+
+const char* cmGlobalNinjaGenerator::NINJA_BUILD_FILE = "build.ninja";
+const char* cmGlobalNinjaGenerator::NINJA_RULES_FILE = "rules.ninja";
+const char* cmGlobalNinjaGenerator::INDENT = " ";
+
+void cmGlobalNinjaGenerator::Indent(std::ostream& os, int count)
+{
+ for (int i = 0; i < count; ++i) {
+ os << cmGlobalNinjaGenerator::INDENT;
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteDivider(std::ostream& os)
+{
+ os << "# ======================================"
+ << "=======================================\n";
+}
+
+void cmGlobalNinjaGenerator::WriteComment(std::ostream& os,
+ const std::string& comment)
+{
+ if (comment.empty()) {
+ return;
+ }
+
+ std::string::size_type lpos = 0;
+ std::string::size_type rpos;
+ os << "\n#############################################\n";
+ while ((rpos = comment.find('\n', lpos)) != std::string::npos) {
+ os << "# " << comment.substr(lpos, rpos - lpos) << "\n";
+ lpos = rpos + 1;
+ }
+ os << "# " << comment.substr(lpos) << "\n\n";
+}
+
+std::string cmGlobalNinjaGenerator::EncodeRuleName(std::string const& name)
+{
+ // Ninja rule names must match "[a-zA-Z0-9_.-]+". Use ".xx" to encode
+ // "." and all invalid characters as hexadecimal.
+ std::string encoded;
+ for (std::string::const_iterator i = name.begin(); i != name.end(); ++i) {
+ if (isalnum(*i) || *i == '_' || *i == '-') {
+ encoded += *i;
+ } else {
+ char buf[16];
+ sprintf(buf, ".%02x", static_cast<unsigned int>(*i));
+ encoded += buf;
+ }
+ }
+ return encoded;
+}
+
+static bool IsIdentChar(char c)
+{
+ return ('a' <= c && c <= 'z') ||
+ ('+' <= c && c <= '9') || // +,-./ and numbers
+ ('A' <= c && c <= 'Z') || (c == '_') || (c == '$') || (c == '\\') ||
+ (c == ' ') || (c == ':');
+}
+
+std::string cmGlobalNinjaGenerator::EncodeIdent(const std::string& ident,
+ std::ostream& vars)
+{
+ if (std::find_if(ident.begin(), ident.end(),
+ std::not1(std::ptr_fun(IsIdentChar))) != ident.end()) {
+ static unsigned VarNum = 0;
+ std::ostringstream names;
+ names << "ident" << VarNum++;
+ vars << names.str() << " = " << ident << "\n";
+ return "$" + names.str();
+ } else {
+ std::string result = ident;
+ cmSystemTools::ReplaceString(result, " ", "$ ");
+ cmSystemTools::ReplaceString(result, ":", "$:");
+ return result;
+ }
+}
+
+std::string cmGlobalNinjaGenerator::EncodeLiteral(const std::string& lit)
+{
+ std::string result = lit;
+ cmSystemTools::ReplaceString(result, "$", "$$");
+ cmSystemTools::ReplaceString(result, "\n", "$\n");
+ return result;
+}
+
+std::string cmGlobalNinjaGenerator::EncodePath(const std::string& path)
+{
+ std::string result = path;
+#ifdef _WIN32
+ if (this->IsGCCOnWindows())
+ std::replace(result.begin(), result.end(), '\\', '/');
+ else
+ std::replace(result.begin(), result.end(), '/', '\\');
+#endif
+ return EncodeLiteral(result);
+}
+
+std::string cmGlobalNinjaGenerator::EncodeDepfileSpace(const std::string& path)
+{
+ std::string result = path;
+ cmSystemTools::ReplaceString(result, " ", "\\ ");
+ return result;
+}
+
+void cmGlobalNinjaGenerator::WriteBuild(
+ std::ostream& os, const std::string& comment, const std::string& rule,
+ const cmNinjaDeps& outputs, const cmNinjaDeps& explicitDeps,
+ const cmNinjaDeps& implicitDeps, const cmNinjaDeps& orderOnlyDeps,
+ const cmNinjaVars& variables, const std::string& rspfile, 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());
+ 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());
+ return;
+ }
+
+ cmGlobalNinjaGenerator::WriteComment(os, comment);
+
+ std::string arguments;
+
+ // TODO: Better formatting for when there are multiple input/output files.
+
+ // Write explicit dependencies.
+ for (cmNinjaDeps::const_iterator i = explicitDeps.begin();
+ i != explicitDeps.end(); ++i) {
+ arguments += " " + EncodeIdent(EncodePath(*i), os);
+ }
+
+ // Write implicit dependencies.
+ if (!implicitDeps.empty()) {
+ arguments += " |";
+ for (cmNinjaDeps::const_iterator i = implicitDeps.begin();
+ i != implicitDeps.end(); ++i) {
+ arguments += " " + EncodeIdent(EncodePath(*i), os);
+ }
+ }
+
+ // Write order-only dependencies.
+ if (!orderOnlyDeps.empty()) {
+ arguments += " ||";
+ for (cmNinjaDeps::const_iterator i = orderOnlyDeps.begin();
+ i != orderOnlyDeps.end(); ++i) {
+ arguments += " " + EncodeIdent(EncodePath(*i), os);
+ }
+ }
+
+ arguments += "\n";
+
+ std::string build;
+
+ // Write outputs files.
+ build += "build";
+ for (cmNinjaDeps::const_iterator i = outputs.begin(); i != outputs.end();
+ ++i) {
+ build += " " + EncodeIdent(EncodePath(*i), os);
+ if (this->ComputingUnknownDependencies) {
+ this->CombinedBuildOutputs.insert(EncodePath(*i));
+ }
+ }
+ build += ":";
+
+ // Write the rule.
+ build += " " + rule;
+
+ // Write the variables bound to this build statement.
+ std::ostringstream variable_assignments;
+ for (cmNinjaVars::const_iterator i = variables.begin(); i != variables.end();
+ ++i) {
+ cmGlobalNinjaGenerator::WriteVariable(variable_assignments, i->first,
+ i->second, "", 1);
+ }
+
+ // check if a response file rule should be used
+ std::string buildstr = build;
+ std::string assignments = variable_assignments.str();
+ const std::string& args = arguments;
+ bool useResponseFile = false;
+ if (cmdLineLimit < 0 ||
+ (cmdLineLimit > 0 &&
+ (args.size() + buildstr.size() + assignments.size()) >
+ 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;
+ }
+
+ os << buildstr << args << 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, explicitDeps, implicitDeps,
+ orderOnlyDeps, variables);
+}
+
+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);
+}
+
+void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
+ const std::string& command, const std::string& description,
+ const std::string& comment, bool uses_terminal, bool restat,
+ const cmNinjaDeps& outputs, const cmNinjaDeps& deps,
+ const cmNinjaDeps& orderOnly)
+{
+ std::string cmd = command;
+#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";
+ }
+
+ this->WriteBuild(*this->BuildFileStream, comment, "CUSTOM_COMMAND", outputs,
+ 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 (cmNinjaDeps::const_iterator i = deps.begin(); i != deps.end(); ++i) {
+ this->CombinedCustomCommandExplicitDependencies.insert(EncodePath(*i));
+ }
+ }
+}
+
+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);
+}
+
+void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(const std::string& input,
+ const 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,
+ deps, cmNinjaDeps(), cmNinjaDeps(), cmNinjaVars());
+}
+
+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)
+{
+ // Make sure the rule has a name.
+ if (name.empty()) {
+ cmSystemTools::Error("No name given for WriteRuleStatement! called "
+ "with comment: ",
+ comment.c_str());
+ return;
+ }
+
+ // Make sure a command is given.
+ if (command.empty()) {
+ cmSystemTools::Error("No command given for WriteRuleStatement! called "
+ "with comment: ",
+ comment.c_str());
+ 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";
+ }
+
+ // Write the command.
+ cmGlobalNinjaGenerator::Indent(os, 1);
+ os << "command = " << command << "\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;
+ }
+ 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";
+ }
+
+ if (generator) {
+ cmGlobalNinjaGenerator::Indent(os, 1);
+ os << "generator = 1\n";
+ }
+
+ os << "\n";
+}
+
+void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os,
+ const std::string& name,
+ const std::string& value,
+ const std::string& comment,
+ int indent)
+{
+ // Make sure we have a name.
+ if (name.empty()) {
+ cmSystemTools::Error("No name given for WriteVariable! called "
+ "with comment: ",
+ comment.c_str());
+ return;
+ }
+
+ // Do not add a variable if the value is empty.
+ std::string val = cmSystemTools::TrimWhitespace(value);
+ if (val.empty()) {
+ return;
+ }
+
+ cmGlobalNinjaGenerator::WriteComment(os, comment);
+ cmGlobalNinjaGenerator::Indent(os, indent);
+ os << name << " = " << val << "\n";
+}
+
+void cmGlobalNinjaGenerator::WriteInclude(std::ostream& os,
+ const std::string& filename,
+ const std::string& comment)
+{
+ cmGlobalNinjaGenerator::WriteComment(os, comment);
+ os << "include " << filename << "\n";
+}
+
+void cmGlobalNinjaGenerator::WriteDefault(std::ostream& os,
+ const cmNinjaDeps& targets,
+ const std::string& comment)
+{
+ cmGlobalNinjaGenerator::WriteComment(os, comment);
+ os << "default";
+ for (cmNinjaDeps::const_iterator i = targets.begin(); i != targets.end();
+ ++i) {
+ os << " " << *i;
+ }
+ os << "\n";
+}
+
+cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm)
+ : cmGlobalCommonGenerator(cm)
+ , BuildFileStream(CM_NULLPTR)
+ , RulesFileStream(CM_NULLPTR)
+ , CompileCommandsStream(CM_NULLPTR)
+ , Rules()
+ , AllDependencies()
+ , UsingGCCOnWindows(false)
+ , ComputingUnknownDependencies(false)
+ , PolicyCMP0058(cmPolicies::WARN)
+{
+#ifdef _WIN32
+ cm->GetState()->SetWindowsShell(true);
+#endif
+ // // Ninja is not ported to non-Unix OS yet.
+ // this->ForceUnixPaths = true;
+ this->FindMakeProgramFile = "CMakeNinjaFindMake.cmake";
+}
+
+// Virtual public methods.
+
+cmLocalGenerator* cmGlobalNinjaGenerator::CreateLocalGenerator(cmMakefile* mf)
+{
+ return new cmLocalNinjaGenerator(this, mf);
+}
+
+void cmGlobalNinjaGenerator::GetDocumentation(cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalNinjaGenerator::GetActualName();
+ entry.Brief = "Generates build.ninja files.";
+}
+
+// Implemented in all cmGlobaleGenerator sub-classes.
+// Used in:
+// Source/cmLocalGenerator.cxx
+// Source/cmake.cxx
+void cmGlobalNinjaGenerator::Generate()
+{
+ // Check minimum Ninja version.
+ if (cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
+ this->NinjaVersion.c_str(),
+ RequiredNinjaVersion().c_str())) {
+ std::ostringstream msg;
+ msg << "The detected version of Ninja (" << this->NinjaVersion;
+ msg << ") is less than the version of Ninja required by CMake (";
+ msg << this->RequiredNinjaVersion() << ").";
+ this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, msg.str());
+ return;
+ }
+ this->OpenBuildFileStream();
+ this->OpenRulesFileStream();
+
+ this->InitOutputPathPrefix();
+ this->TargetAll = this->NinjaOutputPath("all");
+ this->CMakeCacheFile = this->NinjaOutputPath("CMakeCache.txt");
+
+ this->PolicyCMP0058 =
+ this->LocalGenerators[0]->GetMakefile()->GetPolicyStatus(
+ cmPolicies::CMP0058);
+ this->ComputingUnknownDependencies =
+ (this->PolicyCMP0058 == cmPolicies::OLD ||
+ this->PolicyCMP0058 == cmPolicies::WARN);
+
+ this->cmGlobalGenerator::Generate();
+
+ this->WriteAssumedSourceDependencies();
+ this->WriteTargetAliases(*this->BuildFileStream);
+ this->WriteFolderTargets(*this->BuildFileStream);
+ this->WriteUnknownExplicitDependencies(*this->BuildFileStream);
+ this->WriteBuiltinTargets(*this->BuildFileStream);
+
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ this->RulesFileStream->setstate(std::ios::failbit);
+ this->BuildFileStream->setstate(std::ios::failbit);
+ }
+
+ this->CloseCompileCommandsStream();
+ this->CloseRulesFileStream();
+ this->CloseBuildFileStream();
+}
+
+void cmGlobalNinjaGenerator::FindMakeProgram(cmMakefile* mf)
+{
+ this->cmGlobalGenerator::FindMakeProgram(mf);
+ if (const char* ninjaCommand = mf->GetDefinition("CMAKE_MAKE_PROGRAM")) {
+ this->NinjaCommand = ninjaCommand;
+ std::vector<std::string> command;
+ command.push_back(this->NinjaCommand);
+ command.push_back("--version");
+ std::string version;
+ cmSystemTools::RunSingleCommand(command, &version, CM_NULLPTR, CM_NULLPTR,
+ CM_NULLPTR, cmSystemTools::OUTPUT_NONE);
+ this->NinjaVersion = cmSystemTools::TrimWhitespace(version);
+ }
+}
+
+void cmGlobalNinjaGenerator::EnableLanguage(
+ std::vector<std::string> const& langs, cmMakefile* mf, bool optional)
+{
+ if (std::find(langs.begin(), langs.end(), "Fortran") != langs.end()) {
+ cmSystemTools::Error("The Ninja generator does not support Fortran yet.");
+ }
+ this->cmGlobalGenerator::EnableLanguage(langs, mf, optional);
+ for (std::vector<std::string>::const_iterator l = langs.begin();
+ l != langs.end(); ++l) {
+ if (*l == "NONE") {
+ continue;
+ }
+ this->ResolveLanguageCompiler(*l, mf, optional);
+ }
+#ifdef _WIN32
+ if (mf->IsOn("CMAKE_COMPILER_IS_MINGW") ||
+ strcmp(mf->GetSafeDefinition("CMAKE_C_COMPILER_ID"), "GNU") == 0 ||
+ strcmp(mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID"), "GNU") == 0 ||
+ strcmp(mf->GetSafeDefinition("CMAKE_C_SIMULATE_ID"), "GNU") == 0 ||
+ strcmp(mf->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID"), "GNU") == 0) {
+ this->UsingGCCOnWindows = true;
+ }
+#endif
+}
+
+// Implemented by:
+// cmGlobalUnixMakefileGenerator3
+// cmGlobalGhsMultiGenerator
+// cmGlobalVisualStudio10Generator
+// cmGlobalVisualStudio7Generator
+// cmGlobalXCodeGenerator
+// Called by:
+// cmGlobalGenerator::Build()
+void cmGlobalNinjaGenerator::GenerateBuildCommand(
+ std::vector<std::string>& makeCommand, const std::string& makeProgram,
+ const std::string& /*projectName*/, const std::string& /*projectDir*/,
+ const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
+ bool verbose, std::vector<std::string> const& makeOptions)
+{
+ makeCommand.push_back(this->SelectMakeProgram(makeProgram));
+
+ if (verbose) {
+ makeCommand.push_back("-v");
+ }
+
+ makeCommand.insert(makeCommand.end(), makeOptions.begin(),
+ makeOptions.end());
+ if (!targetName.empty()) {
+ if (targetName == "clean") {
+ makeCommand.push_back("-t");
+ makeCommand.push_back("clean");
+ } else {
+ makeCommand.push_back(targetName);
+ }
+ }
+}
+
+// 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)
+{
+ // Do not add the same rule twice.
+ if (this->HasRule(name)) {
+ return;
+ }
+
+ this->Rules.insert(name);
+ cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream, name, command,
+ description, comment, depfile, deptype,
+ rspfile, rspcontent, restat, generator);
+
+ this->RuleCmdLength[name] = (int)command.size();
+}
+
+bool cmGlobalNinjaGenerator::HasRule(const std::string& name)
+{
+ RulesSetType::const_iterator rule = this->Rules.find(name);
+ return (rule != this->Rules.end());
+}
+
+// Private virtual overrides
+
+std::string cmGlobalNinjaGenerator::GetEditCacheCommand() const
+{
+ // Ninja by design does not run interactive tools in the terminal,
+ // so our only choice is cmake-gui.
+ return cmSystemTools::GetCMakeGUICommand();
+}
+
+void cmGlobalNinjaGenerator::ComputeTargetObjectDirectory(
+ cmGeneratorTarget* gt) const
+{
+ // Compute full path to object file directory for this target.
+ std::string dir;
+ dir += gt->LocalGenerator->GetCurrentBinaryDirectory();
+ dir += "/";
+ dir += gt->LocalGenerator->GetTargetDirectory(gt);
+ dir += "/";
+ gt->ObjectDirectory = dir;
+}
+
+// Private methods
+
+void cmGlobalNinjaGenerator::OpenBuildFileStream()
+{
+ // Compute Ninja's build file path.
+ std::string buildFilePath =
+ this->GetCMakeInstance()->GetHomeOutputDirectory();
+ buildFilePath += "/";
+ buildFilePath += cmGlobalNinjaGenerator::NINJA_BUILD_FILE;
+
+ // Get a stream where to generate things.
+ if (!this->BuildFileStream) {
+ this->BuildFileStream = new cmGeneratedFileStream(buildFilePath.c_str());
+ if (!this->BuildFileStream) {
+ // An error message is generated by the constructor if it cannot
+ // open the file.
+ return;
+ }
+ }
+
+ // Write the do not edit header.
+ this->WriteDisclaimer(*this->BuildFileStream);
+
+ // Write a comment about this file.
+ *this->BuildFileStream
+ << "# This file contains all the build statements describing the\n"
+ << "# compilation DAG.\n\n";
+}
+
+void cmGlobalNinjaGenerator::CloseBuildFileStream()
+{
+ if (this->BuildFileStream) {
+ delete this->BuildFileStream;
+ this->BuildFileStream = CM_NULLPTR;
+ } else {
+ cmSystemTools::Error("Build file stream was not open.");
+ }
+}
+
+void cmGlobalNinjaGenerator::OpenRulesFileStream()
+{
+ // Compute Ninja's build file path.
+ std::string rulesFilePath =
+ this->GetCMakeInstance()->GetHomeOutputDirectory();
+ rulesFilePath += "/";
+ rulesFilePath += cmGlobalNinjaGenerator::NINJA_RULES_FILE;
+
+ // Get a stream where to generate things.
+ if (!this->RulesFileStream) {
+ this->RulesFileStream = new cmGeneratedFileStream(rulesFilePath.c_str());
+ if (!this->RulesFileStream) {
+ // An error message is generated by the constructor if it cannot
+ // open the file.
+ return;
+ }
+ }
+
+ // Write the do not edit header.
+ this->WriteDisclaimer(*this->RulesFileStream);
+
+ // Write comment about this file.
+ /* clang-format off */
+ *this->RulesFileStream
+ << "# This file contains all the rules used to get the outputs files\n"
+ << "# built from the input files.\n"
+ << "# It is included in the main '" << NINJA_BUILD_FILE << "'.\n\n"
+ ;
+ /* clang-format on */
+}
+
+void cmGlobalNinjaGenerator::CloseRulesFileStream()
+{
+ if (this->RulesFileStream) {
+ delete this->RulesFileStream;
+ this->RulesFileStream = CM_NULLPTR;
+ } else {
+ cmSystemTools::Error("Rules file stream was not open.");
+ }
+}
+
+static void EnsureTrailingSlash(std::string& path)
+{
+ if (path.empty()) {
+ return;
+ }
+ std::string::value_type last = path[path.size() - 1];
+#ifdef _WIN32
+ if (last != '\\') {
+ path += '\\';
+ }
+#else
+ if (last != '/') {
+ path += '/';
+ }
+#endif
+}
+
+std::string cmGlobalNinjaGenerator::ConvertToNinjaPath(const std::string& path)
+{
+ cmLocalNinjaGenerator* ng =
+ static_cast<cmLocalNinjaGenerator*>(this->LocalGenerators[0]);
+ std::string convPath = ng->Convert(path, cmOutputConverter::HOME_OUTPUT);
+ convPath = this->NinjaOutputPath(convPath);
+#ifdef _WIN32
+ std::replace(convPath.begin(), convPath.end(), '/', '\\');
+#endif
+ return convPath;
+}
+
+std::string cmGlobalNinjaGenerator::ConvertToNinjaFolderRule(
+ const std::string& path)
+{
+ cmLocalNinjaGenerator* ng =
+ static_cast<cmLocalNinjaGenerator*>(this->LocalGenerators[0]);
+ std::string convPath = ng->Convert(path + "/all", cmOutputConverter::HOME);
+ convPath = this->NinjaOutputPath(convPath);
+#ifdef _WIN32
+ std::replace(convPath.begin(), convPath.end(), '/', '\\');
+#endif
+ return convPath;
+}
+
+void cmGlobalNinjaGenerator::AddCXXCompileCommand(
+ const std::string& commandLine, const std::string& sourceFile)
+{
+ // Compute Ninja's build file path.
+ std::string buildFileDir =
+ this->GetCMakeInstance()->GetHomeOutputDirectory();
+ if (!this->CompileCommandsStream) {
+ std::string buildFilePath = buildFileDir + "/compile_commands.json";
+
+ // Get a stream where to generate things.
+ this->CompileCommandsStream =
+ new cmGeneratedFileStream(buildFilePath.c_str());
+ *this->CompileCommandsStream << "[";
+ } else {
+ *this->CompileCommandsStream << "," << std::endl;
+ }
+
+ std::string sourceFileName = sourceFile;
+ if (!cmSystemTools::FileIsFullPath(sourceFileName.c_str())) {
+ sourceFileName = cmSystemTools::CollapseFullPath(
+ sourceFileName, this->GetCMakeInstance()->GetHomeOutputDirectory());
+ }
+
+ /* clang-format off */
+ *this->CompileCommandsStream << "\n{\n"
+ << " \"directory\": \""
+ << cmGlobalGenerator::EscapeJSON(buildFileDir) << "\",\n"
+ << " \"command\": \""
+ << cmGlobalGenerator::EscapeJSON(commandLine) << "\",\n"
+ << " \"file\": \""
+ << cmGlobalGenerator::EscapeJSON(sourceFileName) << "\"\n"
+ << "}";
+ /* clang-format on */
+}
+
+void cmGlobalNinjaGenerator::CloseCompileCommandsStream()
+{
+ if (this->CompileCommandsStream) {
+ *this->CompileCommandsStream << "\n]";
+ delete this->CompileCommandsStream;
+ this->CompileCommandsStream = CM_NULLPTR;
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os)
+{
+ os << "# CMAKE generated file: DO NOT EDIT!\n"
+ << "# Generated by \"" << this->GetName() << "\""
+ << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
+ << cmVersion::GetMinorVersion() << "\n\n";
+}
+
+void cmGlobalNinjaGenerator::AddDependencyToAll(cmGeneratorTarget* target)
+{
+ this->AppendTargetOutputs(target, this->AllDependencies);
+}
+
+void cmGlobalNinjaGenerator::AddDependencyToAll(const std::string& input)
+{
+ this->AllDependencies.push_back(input);
+}
+
+void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies()
+{
+ for (std::map<std::string, std::set<std::string> >::iterator i =
+ this->AssumedSourceDependencies.begin();
+ i != this->AssumedSourceDependencies.end(); ++i) {
+ cmNinjaDeps deps;
+ std::copy(i->second.begin(), i->second.end(), std::back_inserter(deps));
+ WriteCustomCommandBuild(/*command=*/"", /*description=*/"",
+ "Assume dependencies for generated source file.",
+ /*uses_terminal*/ false,
+ /*restat*/ true, cmNinjaDeps(1, i->first), deps);
+ }
+}
+
+void cmGlobalNinjaGenerator::AppendTargetOutputs(
+ cmGeneratorTarget const* target, cmNinjaDeps& outputs)
+{
+ std::string configName =
+ target->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
+
+ // for frameworks, we want the real name, not smple name
+ // frameworks always appear versioned, and the build.ninja
+ // will always attempt to manage symbolic links instead
+ // of letting cmOSXBundleGenerator do it.
+ bool realname = target->IsFrameworkOnApple();
+
+ switch (target->GetType()) {
+ case cmState::EXECUTABLE:
+ case cmState::SHARED_LIBRARY:
+ case cmState::STATIC_LIBRARY:
+ case cmState::MODULE_LIBRARY: {
+ outputs.push_back(this->ConvertToNinjaPath(
+ target->GetFullPath(configName, false, realname)));
+ break;
+ }
+ case cmState::OBJECT_LIBRARY:
+ case cmState::UTILITY: {
+ std::string path =
+ target->GetLocalGenerator()->GetCurrentBinaryDirectory() +
+ std::string("/") + target->GetName();
+ outputs.push_back(this->ConvertToNinjaPath(path));
+ break;
+ }
+
+ case cmState::GLOBAL_TARGET:
+ // Always use the target in HOME instead of an unused duplicate in a
+ // subdirectory.
+ outputs.push_back(this->NinjaOutputPath(target->GetName()));
+ break;
+
+ default:
+ return;
+ }
+}
+
+void cmGlobalNinjaGenerator::AppendTargetDepends(
+ cmGeneratorTarget const* target, cmNinjaDeps& outputs)
+{
+ if (target->GetType() == cmState::GLOBAL_TARGET) {
+ // Global targets only depend on other utilities, which may not appear in
+ // the TargetDepends set (e.g. "all").
+ std::set<std::string> const& utils = target->GetUtilities();
+ std::copy(utils.begin(), utils.end(), std::back_inserter(outputs));
+ } else {
+ cmNinjaDeps outs;
+ cmTargetDependSet const& targetDeps = this->GetTargetDirectDepends(target);
+ for (cmTargetDependSet::const_iterator i = targetDeps.begin();
+ i != targetDeps.end(); ++i) {
+ if ((*i)->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ this->AppendTargetOutputs(*i, outs);
+ }
+ std::sort(outs.begin(), outs.end());
+ outputs.insert(outputs.end(), outs.begin(), outs.end());
+ }
+}
+
+void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias,
+ cmGeneratorTarget* target)
+{
+ std::string buildAlias = this->NinjaOutputPath(alias);
+ cmNinjaDeps outputs;
+ this->AppendTargetOutputs(target, outputs);
+ // Mark the target's outputs as ambiguous to ensure that no other target uses
+ // the output as an alias.
+ for (cmNinjaDeps::iterator i = outputs.begin(); i != outputs.end(); ++i) {
+ TargetAliases[*i] = CM_NULLPTR;
+ }
+
+ // Insert the alias into the map. If the alias was already present in the
+ // map and referred to another target, mark it as ambiguous.
+ std::pair<TargetAliasMap::iterator, bool> newAlias =
+ TargetAliases.insert(std::make_pair(buildAlias, target));
+ if (newAlias.second && newAlias.first->second != target) {
+ newAlias.first->second = CM_NULLPTR;
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os)
+{
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << "# Target aliases.\n\n";
+
+ for (TargetAliasMap::const_iterator i = TargetAliases.begin();
+ i != TargetAliases.end(); ++i) {
+ // Don't write ambiguous aliases.
+ if (!i->second) {
+ continue;
+ }
+
+ cmNinjaDeps deps;
+ this->AppendTargetOutputs(i->second, deps);
+
+ this->WritePhonyBuild(os, "", cmNinjaDeps(1, i->first), deps);
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
+{
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << "# Folder targets.\n\n";
+
+ std::map<std::string, cmNinjaDeps> targetsPerFolder;
+ for (std::vector<cmLocalGenerator*>::const_iterator lgi =
+ this->LocalGenerators.begin();
+ lgi != this->LocalGenerators.end(); ++lgi) {
+ cmLocalGenerator const* lg = *lgi;
+ const std::string currentSourceFolder(
+ lg->GetStateSnapshot().GetDirectory().GetCurrentSource());
+ // The directory-level rule should depend on the target-level rules
+ // for all targets in the directory.
+ targetsPerFolder[currentSourceFolder] = cmNinjaDeps();
+ for (std::vector<cmGeneratorTarget*>::const_iterator ti =
+ lg->GetGeneratorTargets().begin();
+ ti != lg->GetGeneratorTargets().end(); ++ti) {
+ cmGeneratorTarget const* gt = *ti;
+ cmState::TargetType const type = gt->GetType();
+ if ((type == cmState::EXECUTABLE || type == cmState::STATIC_LIBRARY ||
+ type == cmState::SHARED_LIBRARY ||
+ type == cmState::MODULE_LIBRARY ||
+ type == cmState::OBJECT_LIBRARY || type == cmState::UTILITY) &&
+ !gt->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+ targetsPerFolder[currentSourceFolder].push_back(gt->GetName());
+ }
+ }
+
+ // The directory-level rule should depend on the directory-level
+ // rules of the subdirectories.
+ std::vector<cmState::Snapshot> const& children =
+ lg->GetStateSnapshot().GetChildren();
+ for (std::vector<cmState::Snapshot>::const_iterator stateIt =
+ children.begin();
+ stateIt != children.end(); ++stateIt) {
+ targetsPerFolder[currentSourceFolder].push_back(
+ this->ConvertToNinjaFolderRule(
+ stateIt->GetDirectory().GetCurrentSource()));
+ }
+ }
+
+ std::string const rootSourceDir =
+ this->LocalGenerators[0]->GetSourceDirectory();
+ for (std::map<std::string, cmNinjaDeps>::const_iterator it =
+ targetsPerFolder.begin();
+ it != targetsPerFolder.end(); ++it) {
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ std::string const& currentSourceDir = it->first;
+
+ // Do not generate a rule for the root source dir.
+ if (rootSourceDir.length() >= currentSourceDir.length()) {
+ continue;
+ }
+
+ std::string const comment = "Folder: " + currentSourceDir;
+ cmNinjaDeps output(1);
+ output.push_back(this->ConvertToNinjaFolderRule(currentSourceDir));
+
+ this->WritePhonyBuild(os, comment, output, it->second);
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os)
+{
+ if (!this->ComputingUnknownDependencies) {
+ return;
+ }
+
+ // We need to collect the set of known build outputs.
+ // Start with those generated by WriteBuild calls.
+ // No other method needs this so we can take ownership
+ // of the set locally and throw it out when we are done.
+ std::set<std::string> knownDependencies;
+ knownDependencies.swap(this->CombinedBuildOutputs);
+
+ // now write out the unknown explicit dependencies.
+
+ // union the configured files, evaluations files and the
+ // CombinedBuildOutputs,
+ // and then difference with CombinedExplicitDependencies to find the explicit
+ // dependencies that we have no rule for
+
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ /* clang-format off */
+ os << "# Unknown Build Time Dependencies.\n"
+ << "# Tell Ninja that they may appear as side effects of build rules\n"
+ << "# otherwise ordered by order-only dependencies.\n\n";
+ /* clang-format on */
+
+ // get the list of files that cmake itself has generated as a
+ // product of configuration.
+
+ for (std::vector<cmLocalGenerator*>::const_iterator i =
+ this->LocalGenerators.begin();
+ i != this->LocalGenerators.end(); ++i) {
+ // 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 =
+ (*i)->GetMakefile()->GetOutputFiles();
+ typedef std::vector<std::string>::const_iterator vect_it;
+ for (vect_it j = files.begin(); j != files.end(); ++j) {
+ knownDependencies.insert(this->ConvertToNinjaPath(*j));
+ }
+ // get list files which are implicit dependencies as well and will be phony
+ // for rebuild manifest
+ std::vector<std::string> const& lf = (*i)->GetMakefile()->GetListFiles();
+ typedef std::vector<std::string>::const_iterator vect_it;
+ for (vect_it j = lf.begin(); j != lf.end(); ++j) {
+ knownDependencies.insert(this->ConvertToNinjaPath(*j));
+ }
+ std::vector<cmGeneratorExpressionEvaluationFile*> const& ef =
+ (*i)->GetMakefile()->GetEvaluationFiles();
+ for (std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator li =
+ ef.begin();
+ li != ef.end(); ++li) {
+ // get all the files created by generator expressions and convert them
+ // to ninja paths
+ std::vector<std::string> evaluationFiles = (*li)->GetFiles();
+ for (vect_it j = evaluationFiles.begin(); j != evaluationFiles.end();
+ ++j) {
+ knownDependencies.insert(this->ConvertToNinjaPath(*j));
+ }
+ }
+ }
+ knownDependencies.insert(this->CMakeCacheFile);
+
+ for (TargetAliasMap::const_iterator i = this->TargetAliases.begin();
+ i != this->TargetAliases.end(); ++i) {
+ knownDependencies.insert(this->ConvertToNinjaPath(i->first));
+ }
+
+ // remove all source files we know will exist.
+ typedef std::map<std::string, std::set<std::string> >::const_iterator map_it;
+ for (map_it i = this->AssumedSourceDependencies.begin();
+ i != this->AssumedSourceDependencies.end(); ++i) {
+ knownDependencies.insert(this->ConvertToNinjaPath(i->first));
+ }
+
+ // now we difference with CombinedCustomCommandExplicitDependencies to find
+ // the list of items we know nothing about.
+ // We have encoded all the paths in CombinedCustomCommandExplicitDependencies
+ // and knownDependencies so no matter if unix or windows paths they
+ // should all match now.
+
+ std::vector<std::string> unknownExplicitDepends;
+ this->CombinedCustomCommandExplicitDependencies.erase(this->TargetAll);
+
+ std::set_difference(this->CombinedCustomCommandExplicitDependencies.begin(),
+ this->CombinedCustomCommandExplicitDependencies.end(),
+ 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::vector<std::string>::const_iterator i =
+ unknownExplicitDepends.begin();
+ i != unknownExplicitDepends.end(); ++i) {
+ // 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 (!warnExplicitDepends.empty()) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0058) << "\n"
+ "This project specifies custom command DEPENDS on files "
+ "in the build tree that are not specified as the OUTPUT or "
+ "BYPRODUCTS of any add_custom_command or add_custom_target:\n"
+ " " << cmJoin(warnExplicitDepends, "\n ") <<
+ "\n"
+ "For compatibility with versions of CMake that did not have "
+ "the BYPRODUCTS option, CMake is generating phony rules for "
+ "such files to convince 'ninja' to build."
+ "\n"
+ "Project authors should add the missing BYPRODUCTS or OUTPUT "
+ "options to the custom commands that produce these files."
+ ;
+ /* clang-format on */
+ this->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os)
+{
+ // Write headers.
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << "# Built-in targets\n\n";
+
+ this->WriteTargetAll(os);
+ this->WriteTargetRebuildManifest(os);
+ this->WriteTargetClean(os);
+ this->WriteTargetHelp(os);
+}
+
+void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os)
+{
+ cmNinjaDeps outputs;
+ outputs.push_back(this->TargetAll);
+
+ this->WritePhonyBuild(os, "The main all target.", outputs,
+ this->AllDependencies);
+
+ if (!this->HasOutputPathPrefix()) {
+ cmGlobalNinjaGenerator::WriteDefault(os, outputs,
+ "Make the all target the default.");
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
+{
+ cmLocalGenerator* lg = this->LocalGenerators[0];
+
+ std::ostringstream cmd;
+ cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
+ cmOutputConverter::SHELL)
+ << " -H"
+ << 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;
+ for (std::vector<cmLocalGenerator*>::const_iterator i =
+ this->LocalGenerators.begin();
+ i != this->LocalGenerators.end(); ++i) {
+ std::vector<std::string> const& lf = (*i)->GetMakefile()->GetListFiles();
+ for (std::vector<std::string>::const_iterator fi = lf.begin();
+ fi != lf.end(); ++fi) {
+ implicitDeps.push_back(this->ConvertToNinjaPath(*fi));
+ }
+ }
+ implicitDeps.push_back(this->CMakeCacheFile);
+
+ std::sort(implicitDeps.begin(), implicitDeps.end());
+ implicitDeps.erase(std::unique(implicitDeps.begin(), implicitDeps.end()),
+ implicitDeps.end());
+
+ 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";
+ }
+
+ 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),
+ /*explicitDeps=*/cmNinjaDeps(), implicitDeps,
+ /*orderOnlyDeps=*/cmNinjaDeps(), variables);
+
+ this->WritePhonyBuild(os, "A missing CMake input file is not an error.",
+ implicitDeps, cmNinjaDeps());
+}
+
+std::string cmGlobalNinjaGenerator::ninjaCmd() const
+{
+ cmLocalGenerator* lgen = this->LocalGenerators[0];
+ if (lgen) {
+ return lgen->ConvertToOutputFormat(this->NinjaCommand,
+ cmOutputConverter::SHELL);
+ }
+ return "ninja";
+}
+
+bool cmGlobalNinjaGenerator::SupportsConsolePool() const
+{
+ return !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ RequiredNinjaVersionForConsolePool().c_str());
+}
+
+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")),
+ /*explicitDeps=*/cmNinjaDeps(),
+ /*implicitDeps=*/cmNinjaDeps(),
+ /*orderOnlyDeps=*/cmNinjaDeps(),
+ /*variables=*/cmNinjaVars());
+}
+
+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")),
+ /*explicitDeps=*/cmNinjaDeps(),
+ /*implicitDeps=*/cmNinjaDeps(),
+ /*orderOnlyDeps=*/cmNinjaDeps(),
+ /*variables=*/cmNinjaVars());
+}
+
+void cmGlobalNinjaGenerator::InitOutputPathPrefix()
+{
+ this->OutputPathPrefix =
+ this->LocalGenerators[0]->GetMakefile()->GetSafeDefinition(
+ "CMAKE_NINJA_OUTPUT_PATH_PREFIX");
+ EnsureTrailingSlash(this->OutputPathPrefix);
+}
+
+std::string cmGlobalNinjaGenerator::NinjaOutputPath(std::string const& path)
+{
+ if (!this->HasOutputPathPrefix() || cmSystemTools::FileIsFullPath(path)) {
+ return path;
+ }
+ return this->OutputPathPrefix + path;
+}
+
+void cmGlobalNinjaGenerator::StripNinjaOutputPathPrefixAsSuffix(
+ std::string& path)
+{
+ if (path.empty()) {
+ return;
+ }
+ EnsureTrailingSlash(path);
+ cmStripSuffixIfExists(path, this->OutputPathPrefix);
+}
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
new file mode 100644
index 0000000..69ec6ca
--- /dev/null
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -0,0 +1,418 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
+ Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalNinjaGenerator_h
+#define cmGlobalNinjaGenerator_h
+
+#include "cmGlobalCommonGenerator.h"
+
+#include "cmGlobalGeneratorFactory.h"
+#include "cmNinjaTypes.h"
+
+//#define NINJA_GEN_VERBOSE_FILES
+
+class cmLocalGenerator;
+class cmGeneratedFileStream;
+class cmGeneratorTarget;
+
+/**
+ * \class cmGlobalNinjaGenerator
+ * \brief Write a build.ninja file.
+ *
+ * The main differences between this generator and the UnixMakefile
+ * generator family are:
+ * - We don't care about VERBOSE variable or RULE_MESSAGES property since
+ * 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.
+ * - We use Ninja special variable $in and $out to produce nice output.
+ * - We extensively use Ninja variable overloading system to minimize the
+ * number of generated rules.
+ */
+class cmGlobalNinjaGenerator : public cmGlobalCommonGenerator
+{
+public:
+ /// The default name of Ninja's build file. Typically: build.ninja.
+ static const char* NINJA_BUILD_FILE;
+
+ /// The default name of Ninja's rules file. Typically: rules.ninja.
+ /// It is included in the main build.ninja file.
+ static const char* NINJA_RULES_FILE;
+
+ /// The indentation string used when generating Ninja's build file.
+ static const char* INDENT;
+
+ /// Write @a count times INDENT level to output stream @a os.
+ static void Indent(std::ostream& os, int count);
+
+ /// Write a divider in the given output stream @a os.
+ static void WriteDivider(std::ostream& os);
+
+ static std::string EncodeRuleName(std::string const& name);
+ static std::string EncodeIdent(const std::string& ident, std::ostream& vars);
+ static std::string EncodeLiteral(const std::string& lit);
+ std::string EncodePath(const std::string& path);
+ static std::string EncodeDepfileSpace(const std::string& path);
+
+ /**
+ * Write the given @a comment to the output stream @a os. It
+ * handles new line character properly.
+ */
+ static void WriteComment(std::ostream& os, const std::string& comment);
+
+ /**
+ * Utilized by the generator factory to determine if this generator
+ * supports toolsets.
+ */
+ static bool SupportsToolset() { return false; }
+
+ /**
+ * 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.
+ * @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& explicitDeps,
+ const cmNinjaDeps& implicitDeps,
+ const cmNinjaDeps& orderOnlyDeps,
+ const cmNinjaVars& variables,
+ const std::string& rspfile = std::string(),
+ int cmdLineLimit = 0, bool* usedResponseFile = CM_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, 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);
+
+ /**
+ * 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.
+ * @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);
+
+ /**
+ * Write a variable named @a name to @a os with value @a value and an
+ * optional @a comment. An @a indent level can be specified.
+ * @warning no escaping of any kind is done here.
+ */
+ static void WriteVariable(std::ostream& os, const std::string& name,
+ const std::string& value,
+ const std::string& comment = "", int indent = 0);
+
+ /**
+ * Write an include statement including @a filename with an optional
+ * @a comment to the @a os stream.
+ */
+ static void WriteInclude(std::ostream& os, const std::string& filename,
+ const std::string& comment = "");
+
+ /**
+ * Write a default target statement specifying @a targets as
+ * the default targets.
+ */
+ static void WriteDefault(std::ostream& os, const cmNinjaDeps& targets,
+ const std::string& comment = "");
+
+ bool IsGCCOnWindows() const { return UsingGCCOnWindows; }
+
+public:
+ cmGlobalNinjaGenerator(cmake* cm);
+
+ static cmGlobalGeneratorFactory* NewFactory()
+ {
+ return new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaGenerator>();
+ }
+
+ ~cmGlobalNinjaGenerator() CM_OVERRIDE {}
+
+ cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) CM_OVERRIDE;
+
+ std::string GetName() const CM_OVERRIDE
+ {
+ return cmGlobalNinjaGenerator::GetActualName();
+ }
+
+ static std::string GetActualName() { return "Ninja"; }
+
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile* mf, bool optional) CM_OVERRIDE;
+
+ void GenerateBuildCommand(std::vector<std::string>& makeCommand,
+ const std::string& makeProgram,
+ const std::string& projectName,
+ const std::string& projectDir,
+ const std::string& targetName,
+ const std::string& config, bool fast, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) CM_OVERRIDE;
+
+ // Setup target names
+ const char* GetAllTargetName() const CM_OVERRIDE { return "all"; }
+ const char* GetInstallTargetName() const CM_OVERRIDE { return "install"; }
+ const char* GetInstallLocalTargetName() const CM_OVERRIDE
+ {
+ return "install/local";
+ }
+ const char* GetInstallStripTargetName() const CM_OVERRIDE
+ {
+ return "install/strip";
+ }
+ const char* GetTestTargetName() const CM_OVERRIDE { return "test"; }
+ const char* GetPackageTargetName() const CM_OVERRIDE { return "package"; }
+ const char* GetPackageSourceTargetName() const CM_OVERRIDE
+ {
+ return "package_source";
+ }
+ const char* GetEditCacheTargetName() const CM_OVERRIDE
+ {
+ return "edit_cache";
+ }
+ const char* GetRebuildCacheTargetName() const CM_OVERRIDE
+ {
+ return "rebuild_cache";
+ }
+ const char* GetCleanTargetName() const CM_OVERRIDE { return "clean"; }
+
+ cmGeneratedFileStream* GetBuildFileStream() const
+ {
+ return this->BuildFileStream;
+ }
+
+ cmGeneratedFileStream* GetRulesFileStream() const
+ {
+ return this->RulesFileStream;
+ }
+
+ std::string ConvertToNinjaPath(const std::string& path);
+ std::string ConvertToNinjaFolderRule(const std::string& path);
+
+ struct MapToNinjaPathImpl
+ {
+ cmGlobalNinjaGenerator* GG;
+ MapToNinjaPathImpl(cmGlobalNinjaGenerator* gg)
+ : GG(gg)
+ {
+ }
+ std::string operator()(std::string const& path)
+ {
+ return this->GG->ConvertToNinjaPath(path);
+ }
+ };
+ MapToNinjaPathImpl MapToNinjaPath() { return MapToNinjaPathImpl(this); }
+
+ void AddCXXCompileCommand(const std::string& commandLine,
+ const std::string& sourceFile);
+
+ /**
+ * Add a rule to the generated build system.
+ * 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);
+
+ bool HasRule(const std::string& name);
+
+ void AddCustomCommandRule();
+ void AddMacOSXContentRule();
+
+ bool HasCustomCommandOutput(const std::string& output)
+ {
+ return this->CustomCommandOutputs.find(output) !=
+ this->CustomCommandOutputs.end();
+ }
+
+ /// Called when we have seen the given custom command. Returns true
+ /// if we has seen it before.
+ bool SeenCustomCommand(cmCustomCommand const* cc)
+ {
+ return !this->CustomCommands.insert(cc).second;
+ }
+
+ /// Called when we have seen the given custom command output.
+ void SeenCustomCommandOutput(const std::string& output)
+ {
+ this->CustomCommandOutputs.insert(output);
+ // We don't need the assumed dependencies anymore, because we have
+ // an output.
+ this->AssumedSourceDependencies.erase(output);
+ }
+
+ void AddAssumedSourceDependencies(const std::string& source,
+ const cmNinjaDeps& deps)
+ {
+ std::set<std::string>& ASD = this->AssumedSourceDependencies[source];
+ // Because we may see the same source file multiple times (same source
+ // specified in multiple targets), compute the union of any assumed
+ // dependencies.
+ ASD.insert(deps.begin(), deps.end());
+ }
+
+ void AppendTargetOutputs(cmGeneratorTarget const* target,
+ cmNinjaDeps& outputs);
+ void AppendTargetDepends(cmGeneratorTarget const* target,
+ cmNinjaDeps& outputs);
+ void AddDependencyToAll(cmGeneratorTarget* target);
+ void AddDependencyToAll(const std::string& input);
+
+ const std::vector<cmLocalGenerator*>& GetLocalGenerators() const
+ {
+ return LocalGenerators;
+ }
+
+ bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target)
+ {
+ return cmGlobalGenerator::IsExcluded(root, target);
+ }
+
+ int GetRuleCmdLength(const std::string& name) { return RuleCmdLength[name]; }
+
+ void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target);
+
+ void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const CM_OVERRIDE;
+
+ // Ninja generator uses 'deps' and 'msvc_deps_prefix' introduced in 1.3
+ static std::string RequiredNinjaVersion() { return "1.3"; }
+ static std::string RequiredNinjaVersionForConsolePool() { return "1.5"; }
+ bool SupportsConsolePool() const;
+
+ std::string NinjaOutputPath(std::string const& path);
+ bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
+ void StripNinjaOutputPathPrefixAsSuffix(std::string& path);
+
+protected:
+ void Generate() CM_OVERRIDE;
+
+ bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const CM_OVERRIDE { return true; }
+
+private:
+ std::string GetEditCacheCommand() const CM_OVERRIDE;
+ void FindMakeProgram(cmMakefile* mf) CM_OVERRIDE;
+
+ void OpenBuildFileStream();
+ void CloseBuildFileStream();
+
+ void CloseCompileCommandsStream();
+
+ void OpenRulesFileStream();
+ void CloseRulesFileStream();
+
+ /// Write the common disclaimer text at the top of each build file.
+ void WriteDisclaimer(std::ostream& os);
+
+ void WriteAssumedSourceDependencies();
+
+ void WriteTargetAliases(std::ostream& os);
+ void WriteFolderTargets(std::ostream& os);
+ void WriteUnknownExplicitDependencies(std::ostream& os);
+
+ void WriteBuiltinTargets(std::ostream& os);
+ void WriteTargetAll(std::ostream& os);
+ void WriteTargetRebuildManifest(std::ostream& os);
+ void WriteTargetClean(std::ostream& os);
+ void WriteTargetHelp(std::ostream& os);
+
+ std::string ninjaCmd() const;
+
+ /// The file containing the build statement. (the relationship of the
+ /// compilation DAG).
+ 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;
+
+ /// The set of rules added to the generated build system.
+ RulesSetType Rules;
+
+ /// Length of rule command, used by rsp file evaluation
+ std::map<std::string, int> RuleCmdLength;
+
+ /// The set of dependencies to add to the "all" target.
+ cmNinjaDeps AllDependencies;
+
+ bool UsingGCCOnWindows;
+
+ /// The set of custom commands we have seen.
+ std::set<cmCustomCommand const*> CustomCommands;
+
+ /// The set of custom command outputs we have seen.
+ std::set<std::string> CustomCommandOutputs;
+
+ /// Whether we are collecting known build outputs and needed
+ /// dependencies to determine unknown dependencies.
+ bool ComputingUnknownDependencies;
+ cmPolicies::PolicyStatus PolicyCMP0058;
+
+ /// The combined explicit dependencies of custom build commands
+ std::set<std::string> CombinedCustomCommandExplicitDependencies;
+
+ /// When combined with CombinedCustomCommandExplicitDependencies it allows
+ /// us to detect the set of explicit dependencies that have
+ std::set<std::string> CombinedBuildOutputs;
+
+ /// The mapping from source file to assumed dependencies.
+ std::map<std::string, std::set<std::string> > AssumedSourceDependencies;
+
+ typedef std::map<std::string, cmGeneratorTarget*> TargetAliasMap;
+ TargetAliasMap TargetAliases;
+
+ std::string NinjaCommand;
+ std::string NinjaVersion;
+
+private:
+ void InitOutputPathPrefix();
+
+ std::string OutputPathPrefix;
+ std::string TargetAll;
+ std::string CMakeCacheFile;
+};
+
+#endif // ! cmGlobalNinjaGenerator_h
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
new file mode 100644
index 0000000..f115ecb
--- /dev/null
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -0,0 +1,996 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalUnixMakefileGenerator3.h"
+
+#include "cmAlgorithms.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmMakefileTargetGenerator.h"
+#include "cmake.h"
+
+cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3(cmake* cm)
+ : cmGlobalCommonGenerator(cm)
+{
+ // This type of makefile always requires unix style paths
+ this->ForceUnixPaths = true;
+ this->FindMakeProgramFile = "CMakeUnixFindMake.cmake";
+ this->ToolSupportsColor = true;
+
+#if defined(_WIN32) || defined(__VMS)
+ this->UseLinkScript = false;
+#else
+ this->UseLinkScript = true;
+#endif
+ this->CommandDatabase = CM_NULLPTR;
+
+ this->IncludeDirective = "include";
+ this->DefineWindowsNULL = false;
+ this->PassMakeflags = false;
+ this->UnixCD = true;
+}
+
+void cmGlobalUnixMakefileGenerator3::EnableLanguage(
+ std::vector<std::string> const& languages, cmMakefile* mf, bool optional)
+{
+ this->cmGlobalGenerator::EnableLanguage(languages, mf, optional);
+ for (std::vector<std::string>::const_iterator l = languages.begin();
+ l != languages.end(); ++l) {
+ if (*l == "NONE") {
+ continue;
+ }
+ this->ResolveLanguageCompiler(*l, mf, optional);
+ }
+}
+
+///! Create a local generator appropriate to this Global Generator
+cmLocalGenerator* cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(
+ cmMakefile* mf)
+{
+ return new cmLocalUnixMakefileGenerator3(this, mf);
+}
+
+void cmGlobalUnixMakefileGenerator3::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalUnixMakefileGenerator3::GetActualName();
+ entry.Brief = "Generates standard UNIX makefiles.";
+}
+
+std::string cmGlobalUnixMakefileGenerator3::GetEditCacheCommand() const
+{
+ // If generating for an extra IDE, the edit_cache target cannot
+ // launch a terminal-interactive tool, so always use cmake-gui.
+ if (!this->GetExtraGeneratorName().empty()) {
+ return cmSystemTools::GetCMakeGUICommand();
+ }
+
+ // Use an internal cache entry to track the latest dialog used
+ // to edit the cache, and use that for the edit_cache target.
+ cmake* cm = this->GetCMakeInstance();
+ std::string editCacheCommand = cm->GetCMakeEditCommand();
+ if (!cm->GetCacheDefinition("CMAKE_EDIT_COMMAND") ||
+ !editCacheCommand.empty()) {
+ if (editCacheCommand.empty()) {
+ editCacheCommand = cmSystemTools::GetCMakeCursesCommand();
+ }
+ if (editCacheCommand.empty()) {
+ editCacheCommand = cmSystemTools::GetCMakeGUICommand();
+ }
+ if (!editCacheCommand.empty()) {
+ cm->AddCacheEntry("CMAKE_EDIT_COMMAND", editCacheCommand.c_str(),
+ "Path to cache edit program executable.",
+ cmState::INTERNAL);
+ }
+ }
+ const char* edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND");
+ return edit_cmd ? edit_cmd : "";
+}
+
+void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory(
+ cmGeneratorTarget* gt) const
+{
+ // Compute full path to object file directory for this target.
+ std::string dir;
+ dir += gt->LocalGenerator->GetCurrentBinaryDirectory();
+ dir += "/";
+ dir += gt->LocalGenerator->GetTargetDirectory(gt);
+ dir += "/";
+ gt->ObjectDirectory = dir;
+}
+
+void cmGlobalUnixMakefileGenerator3::Configure()
+{
+ // Initialize CMAKE_EDIT_COMMAND cache entry.
+ this->GetEditCacheCommand();
+
+ this->cmGlobalGenerator::Configure();
+}
+
+void cmGlobalUnixMakefileGenerator3::Generate()
+{
+ // first do superclass method
+ this->cmGlobalGenerator::Generate();
+
+ // initialize progress
+ unsigned long total = 0;
+ for (ProgressMapType::const_iterator pmi = this->ProgressMap.begin();
+ pmi != this->ProgressMap.end(); ++pmi) {
+ total += pmi->second.NumberOfActions;
+ }
+
+ // write each target's progress.make this loop is done twice. Bascially the
+ // Generate pass counts all the actions, the first loop below determines
+ // how many actions have progress updates for each target and writes to
+ // corrrect variable values for everything except the all targets. The
+ // second loop actually writes out correct values for the all targets as
+ // well. This is because the all targets require more information that is
+ // computed in the first loop.
+ unsigned long current = 0;
+ for (ProgressMapType::iterator pmi = this->ProgressMap.begin();
+ pmi != this->ProgressMap.end(); ++pmi) {
+ pmi->second.WriteProgressVariables(total, current);
+ }
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ cmLocalGenerator* lg = this->LocalGenerators[i];
+ std::string markFileName = lg->GetCurrentBinaryDirectory();
+ markFileName += "/";
+ markFileName += cmake::GetCMakeFilesDirectory();
+ markFileName += "/progress.marks";
+ cmGeneratedFileStream markFile(markFileName.c_str());
+ markFile << this->CountProgressMarksInAll(lg) << "\n";
+ }
+
+ // write the main makefile
+ this->WriteMainMakefile2();
+ this->WriteMainCMakefile();
+
+ if (this->CommandDatabase != CM_NULLPTR) {
+ *this->CommandDatabase << std::endl << "]";
+ delete this->CommandDatabase;
+ this->CommandDatabase = CM_NULLPTR;
+ }
+}
+
+void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
+ const std::string& sourceFile, const std::string& workingDirectory,
+ const std::string& compileCommand)
+{
+ if (this->CommandDatabase == CM_NULLPTR) {
+ std::string commandDatabaseName =
+ std::string(this->GetCMakeInstance()->GetHomeOutputDirectory()) +
+ "/compile_commands.json";
+ this->CommandDatabase =
+ new cmGeneratedFileStream(commandDatabaseName.c_str());
+ *this->CommandDatabase << "[" << std::endl;
+ } else {
+ *this->CommandDatabase << "," << std::endl;
+ }
+ *this->CommandDatabase << "{" << std::endl
+ << " \"directory\": \""
+ << cmGlobalGenerator::EscapeJSON(workingDirectory)
+ << "\"," << std::endl
+ << " \"command\": \""
+ << cmGlobalGenerator::EscapeJSON(compileCommand)
+ << "\"," << std::endl
+ << " \"file\": \""
+ << cmGlobalGenerator::EscapeJSON(sourceFile) << "\""
+ << std::endl
+ << "}";
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
+{
+ // Open the output file. This should not be copy-if-different
+ // because the check-build-system step compares the makefile time to
+ // see if the build system must be regenerated.
+ std::string makefileName =
+ this->GetCMakeInstance()->GetHomeOutputDirectory();
+ makefileName += cmake::GetCMakeFilesDirectory();
+ makefileName += "/Makefile2";
+ cmGeneratedFileStream makefileStream(makefileName.c_str());
+ if (!makefileStream) {
+ return;
+ }
+
+ // get a local generator for some useful methods
+ cmLocalUnixMakefileGenerator3* lg =
+ static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]);
+
+ // Write the do not edit header.
+ lg->WriteDisclaimer(makefileStream);
+
+ // Write the main entry point target. This must be the VERY first
+ // target so that make with no arguments will run it.
+ // Just depend on the all target to drive the build.
+ std::vector<std::string> depends;
+ std::vector<std::string> no_commands;
+ depends.push_back("all");
+
+ // Write the rule.
+ lg->WriteMakeRule(makefileStream,
+ "Default target executed when no arguments are "
+ "given to make.",
+ "default_target", depends, no_commands, true);
+
+ depends.clear();
+
+ // The all and preinstall rules might never have any dependencies
+ // added to them.
+ if (this->EmptyRuleHackDepends != "") {
+ 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 out the "special" stuff
+ lg->WriteSpecialTargetsTop(makefileStream);
+
+ // write the target convenience rules
+ unsigned int i;
+ for (i = 0; i < this->LocalGenerators.size(); ++i) {
+ lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[i]);
+ this->WriteConvenienceRules2(makefileStream, lg);
+ }
+
+ lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]);
+ lg->WriteSpecialTargetsBottom(makefileStream);
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
+{
+ // Open the output file. This should not be copy-if-different
+ // because the check-build-system step compares the makefile time to
+ // see if the build system must be regenerated.
+ std::string cmakefileName =
+ this->GetCMakeInstance()->GetHomeOutputDirectory();
+ cmakefileName += cmake::GetCMakeFilesDirectory();
+ cmakefileName += "/Makefile.cmake";
+ cmGeneratedFileStream cmakefileStream(cmakefileName.c_str());
+ if (!cmakefileStream) {
+ return;
+ }
+
+ std::string makefileName =
+ this->GetCMakeInstance()->GetHomeOutputDirectory();
+ makefileName += "/Makefile";
+
+ // get a local generator for some useful methods
+ cmLocalUnixMakefileGenerator3* lg =
+ static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]);
+
+ // Write the do not edit header.
+ lg->WriteDisclaimer(cmakefileStream);
+
+ // Save the generator name
+ cmakefileStream << "# The generator used is:\n"
+ << "set(CMAKE_DEPENDS_GENERATOR \"" << this->GetName()
+ << "\")\n\n";
+
+ // for each cmMakefile get its list of dependencies
+ std::vector<std::string> lfiles;
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[i]);
+
+ // Get the list of files contributing to this generation step.
+ lfiles.insert(lfiles.end(), lg->GetMakefile()->GetListFiles().begin(),
+ lg->GetMakefile()->GetListFiles().end());
+ }
+ // Sort the list and remove duplicates.
+ std::sort(lfiles.begin(), lfiles.end(), std::less<std::string>());
+#if !defined(__VMS) // The Compaq STL on VMS crashes, so accept duplicates.
+ std::vector<std::string>::iterator new_end =
+ std::unique(lfiles.begin(), lfiles.end());
+ lfiles.erase(new_end, lfiles.end());
+#endif
+
+ // reset lg to the first makefile
+ lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]);
+
+ // Build the path to the cache file.
+ std::string cache = this->GetCMakeInstance()->GetHomeOutputDirectory();
+ cache += "/CMakeCache.txt";
+
+ // Save the list to the cmake file.
+ cmakefileStream
+ << "# The top level Makefile was generated from the following files:\n"
+ << "set(CMAKE_MAKEFILE_DEPENDS\n"
+ << " \"" << lg->Convert(cache, cmOutputConverter::START_OUTPUT) << "\"\n";
+ for (std::vector<std::string>::const_iterator i = lfiles.begin();
+ i != lfiles.end(); ++i) {
+ cmakefileStream << " \""
+ << lg->Convert(*i, cmOutputConverter::START_OUTPUT)
+ << "\"\n";
+ }
+ cmakefileStream << " )\n\n";
+
+ // Build the path to the cache check file.
+ std::string check = this->GetCMakeInstance()->GetHomeOutputDirectory();
+ check += cmake::GetCMakeFilesDirectory();
+ check += "/cmake.check_cache";
+
+ // Set the corresponding makefile in the cmake file.
+ cmakefileStream << "# The corresponding makefile is:\n"
+ << "set(CMAKE_MAKEFILE_OUTPUTS\n"
+ << " \""
+ << lg->Convert(makefileName, cmOutputConverter::START_OUTPUT)
+ << "\"\n"
+ << " \""
+ << lg->Convert(check, cmOutputConverter::START_OUTPUT)
+ << "\"\n";
+ cmakefileStream << " )\n\n";
+
+ // CMake must rerun if a byproduct is missing.
+ {
+ cmakefileStream << "# Byproducts of CMake generate step:\n"
+ << "set(CMAKE_MAKEFILE_PRODUCTS\n";
+ const std::vector<std::string>& outfiles =
+ lg->GetMakefile()->GetOutputFiles();
+ for (std::vector<std::string>::const_iterator k = outfiles.begin();
+ k != outfiles.end(); ++k) {
+ cmakefileStream << " \""
+ << lg->Convert(*k, cmOutputConverter::HOME_OUTPUT)
+ << "\"\n";
+ }
+
+ // add in all the directory information files
+ std::string tmpStr;
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ lg =
+ static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[i]);
+ tmpStr = lg->GetCurrentBinaryDirectory();
+ tmpStr += cmake::GetCMakeFilesDirectory();
+ tmpStr += "/CMakeDirectoryInformation.cmake";
+ cmakefileStream << " \""
+ << lg->Convert(tmpStr, cmOutputConverter::HOME_OUTPUT)
+ << "\"\n";
+ }
+ cmakefileStream << " )\n\n";
+ }
+
+ this->WriteMainCMakefileLanguageRules(cmakefileStream,
+ this->LocalGenerators);
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules(
+ cmGeneratedFileStream& cmakefileStream,
+ std::vector<cmLocalGenerator*>& lGenerators)
+{
+ cmLocalUnixMakefileGenerator3* lg;
+
+ // now list all the target info files
+ cmakefileStream << "# Dependency information for all targets:\n";
+ cmakefileStream << "set(CMAKE_DEPEND_INFO_FILES\n";
+ for (unsigned int i = 0; i < lGenerators.size(); ++i) {
+ lg = static_cast<cmLocalUnixMakefileGenerator3*>(lGenerators[i]);
+ // for all of out targets
+ std::vector<cmGeneratorTarget*> tgts = lg->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator l = tgts.begin();
+ l != tgts.end(); l++) {
+ if (((*l)->GetType() == cmState::EXECUTABLE) ||
+ ((*l)->GetType() == cmState::STATIC_LIBRARY) ||
+ ((*l)->GetType() == cmState::SHARED_LIBRARY) ||
+ ((*l)->GetType() == cmState::MODULE_LIBRARY) ||
+ ((*l)->GetType() == cmState::OBJECT_LIBRARY) ||
+ ((*l)->GetType() == cmState::UTILITY)) {
+ cmGeneratorTarget* gt = *l;
+ std::string tname = lg->GetRelativeTargetDirectory(gt);
+ tname += "/DependInfo.cmake";
+ cmSystemTools::ConvertToUnixSlashes(tname);
+ cmakefileStream << " \"" << tname << "\"\n";
+ }
+ }
+ }
+ cmakefileStream << " )\n";
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
+ std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg,
+ const char* pass, bool check_all, bool check_relink)
+{
+ // Get the relative path to the subdirectory from the top.
+ std::string makeTarget = lg->GetCurrentBinaryDirectory();
+ 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;
+ std::vector<cmGeneratorTarget*> targets = lg->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator l = targets.begin();
+ l != targets.end(); ++l) {
+ cmGeneratorTarget* gtarget = *l;
+ int type = gtarget->GetType();
+ if ((type == cmState::EXECUTABLE) || (type == cmState::STATIC_LIBRARY) ||
+ (type == cmState::SHARED_LIBRARY) ||
+ (type == cmState::MODULE_LIBRARY) ||
+ (type == cmState::OBJECT_LIBRARY) || (type == cmState::UTILITY)) {
+ // Add this to the list of depends rules in this directory.
+ if ((!check_all || !gtarget->GetPropertyAsBool("EXCLUDE_FROM_ALL")) &&
+ (!check_relink ||
+ gtarget->NeedRelinkBeforeInstall(lg->GetConfigName()))) {
+ std::string tname = lg->GetRelativeTargetDirectory(gtarget);
+ tname += "/";
+ tname += pass;
+ depends.push_back(tname);
+ }
+ }
+ }
+
+ // The directory-level rule should depend on the directory-level
+ // rules of the subdirectories.
+ std::vector<cmState::Snapshot> children =
+ lg->GetStateSnapshot().GetChildren();
+ for (std::vector<cmState::Snapshot>::const_iterator ci = children.begin();
+ ci != children.end(); ++ci) {
+ std::string subdir = ci->GetDirectory().GetCurrentBinary();
+ subdir += "/";
+ subdir += pass;
+ depends.push_back(subdir);
+ }
+
+ // Work-around for makes that drop rules that have no dependencies
+ // or commands.
+ if (depends.empty() && this->EmptyRuleHackDepends != "") {
+ depends.push_back(this->EmptyRuleHackDepends);
+ }
+
+ // 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);
+}
+
+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 = lg->GetCurrentBinaryDirectory();
+ dir = lg->Convert(dir, cmOutputConverter::HOME_OUTPUT,
+ cmOutputConverter::MAKERULE);
+ lg->WriteDivider(ruleFileStream);
+ ruleFileStream << "# Directory level rules for directory " << dir << "\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);
+
+ // Write directory-level rules for "preinstall".
+ this->WriteDirectoryRule2(ruleFileStream, lg, "preinstall", true, true);
+}
+
+void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ std::vector<std::string>& makeCommand, const std::string& makeProgram,
+ const std::string& /*projectName*/, const std::string& /*projectDir*/,
+ const std::string& targetName, const std::string& /*config*/, bool fast,
+ bool /*verbose*/, std::vector<std::string> const& makeOptions)
+{
+ makeCommand.push_back(this->SelectMakeProgram(makeProgram));
+
+ // Since we have full control over the invocation of nmake, let us
+ // make it quiet.
+ if (cmHasLiteralPrefix(this->GetName(), "NMake Makefiles")) {
+ makeCommand.push_back("/NOLOGO");
+ }
+ makeCommand.insert(makeCommand.end(), makeOptions.begin(),
+ makeOptions.end());
+ if (!targetName.empty()) {
+ cmMakefile* mf;
+ if (!this->Makefiles.empty()) {
+ mf = this->Makefiles[0];
+ } else {
+ cmState::Snapshot snapshot = this->CMakeInstance->GetCurrentSnapshot();
+ snapshot.GetDirectory().SetCurrentSource(
+ this->CMakeInstance->GetHomeDirectory());
+ snapshot.GetDirectory().SetCurrentBinary(
+ this->CMakeInstance->GetHomeOutputDirectory());
+ snapshot.SetDefaultDefinitions();
+ mf = new cmMakefile(this, snapshot);
+ }
+
+ std::string tname = targetName;
+ if (fast) {
+ tname += "/fast";
+ }
+ cmOutputConverter conv(mf->GetStateSnapshot());
+ tname = conv.Convert(tname, cmOutputConverter::HOME_OUTPUT);
+ cmSystemTools::ConvertToOutputSlashes(tname);
+ makeCommand.push_back(tname);
+ if (this->Makefiles.empty()) {
+ delete mf;
+ }
+ }
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules(
+ std::ostream& ruleFileStream, std::set<std::string>& emitted)
+{
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+
+ depends.push_back("cmake_check_build_system");
+
+ // write the target convenience rules
+ unsigned int i;
+ cmLocalUnixMakefileGenerator3* lg;
+ for (i = 0; i < this->LocalGenerators.size(); ++i) {
+ lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[i]);
+ // for each target Generate the rule files for each target.
+ std::vector<cmGeneratorTarget*> targets = lg->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
+ t != targets.end(); ++t) {
+ cmGeneratorTarget* gtarget = *t;
+ // Don't emit the same rule twice (e.g. two targets with the same
+ // simple name)
+ int type = gtarget->GetType();
+ std::string name = gtarget->GetName();
+ if (!name.empty() && emitted.insert(name).second &&
+ // Handle user targets here. Global targets are handled in
+ // the local generator on a per-directory basis.
+ ((type == cmState::EXECUTABLE) ||
+ (type == cmState::STATIC_LIBRARY) ||
+ (type == cmState::SHARED_LIBRARY) ||
+ (type == cmState::MODULE_LIBRARY) ||
+ (type == cmState::OBJECT_LIBRARY) || (type == cmState::UTILITY))) {
+ // Add a rule to build the target by name.
+ lg->WriteDivider(ruleFileStream);
+ ruleFileStream << "# Target rules for targets named " << name
+ << "\n\n";
+
+ // Write the rule.
+ commands.clear();
+ std::string tmp = cmake::GetCMakeFilesDirectoryPostSlash();
+ tmp += "Makefile2";
+ commands.push_back(lg->GetRecursiveMakeCall(tmp.c_str(), name));
+ depends.clear();
+ depends.push_back("cmake_check_build_system");
+ lg->WriteMakeRule(ruleFileStream, "Build rule for target.", name,
+ depends, commands, true);
+
+ // Add a fast rule to build the target
+ std::string localName = lg->GetRelativeTargetDirectory(gtarget);
+ std::string makefileName;
+ makefileName = localName;
+ makefileName += "/build.make";
+ depends.clear();
+ commands.clear();
+ std::string makeTargetName = localName;
+ makeTargetName += "/build";
+ localName = name;
+ localName += "/fast";
+ commands.push_back(
+ lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
+ lg->WriteMakeRule(ruleFileStream, "fast build rule for target.",
+ localName, depends, commands, true);
+
+ // Add a local name for the rule to relink the target before
+ // installation.
+ if (gtarget->NeedRelinkBeforeInstall(lg->GetConfigName())) {
+ makeTargetName = lg->GetRelativeTargetDirectory(gtarget);
+ makeTargetName += "/preinstall";
+ localName = name;
+ localName += "/preinstall";
+ depends.clear();
+ commands.clear();
+ commands.push_back(
+ lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
+ lg->WriteMakeRule(ruleFileStream,
+ "Manual pre-install relink rule for target.",
+ localName, depends, commands, true);
+ }
+ }
+ }
+ }
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
+ std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg)
+{
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+ std::string localName;
+ std::string makeTargetName;
+
+ // write the directory level rules for this local gen
+ this->WriteDirectoryRules2(ruleFileStream, lg);
+
+ depends.push_back("cmake_check_build_system");
+
+ // for each target Generate the rule files for each target.
+ std::vector<cmGeneratorTarget*> targets = lg->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
+ t != targets.end(); ++t) {
+ cmGeneratorTarget* gtarget = *t;
+ int type = gtarget->GetType();
+ std::string name = gtarget->GetName();
+ if (!name.empty() &&
+ ((type == cmState::EXECUTABLE) || (type == cmState::STATIC_LIBRARY) ||
+ (type == cmState::SHARED_LIBRARY) ||
+ (type == cmState::MODULE_LIBRARY) ||
+ (type == cmState::OBJECT_LIBRARY) || (type == cmState::UTILITY))) {
+ std::string makefileName;
+ // Add a rule to build the target by name.
+ localName = lg->GetRelativeTargetDirectory(gtarget);
+ makefileName = localName;
+ makefileName += "/build.make";
+
+ bool needRequiresStep = this->NeedRequiresStep(gtarget);
+
+ lg->WriteDivider(ruleFileStream);
+ ruleFileStream << "# Target rules for target " << localName << "\n\n";
+
+ commands.clear();
+ makeTargetName = localName;
+ makeTargetName += "/depend";
+ commands.push_back(
+ lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
+
+ // add requires if we need it for this generator
+ if (needRequiresStep) {
+ makeTargetName = localName;
+ makeTargetName += "/requires";
+ commands.push_back(
+ lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
+ }
+ makeTargetName = localName;
+ makeTargetName += "/build";
+ commands.push_back(
+ lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
+
+ // Write the rule.
+ localName += "/all";
+ depends.clear();
+
+ cmLocalUnixMakefileGenerator3::EchoProgress progress;
+ progress.Dir = lg->GetBinaryDirectory();
+ progress.Dir += cmake::GetCMakeFilesDirectory();
+ {
+ std::ostringstream progressArg;
+ const char* sep = "";
+ std::vector<unsigned long>& progFiles =
+ this->ProgressMap[gtarget].Marks;
+ for (std::vector<unsigned long>::iterator i = progFiles.begin();
+ i != progFiles.end(); ++i) {
+ progressArg << sep << *i;
+ sep = ",";
+ }
+ progress.Arg = progressArg.str();
+ }
+
+ bool targetMessages = true;
+ if (const char* tgtMsg =
+ this->GetCMakeInstance()->GetState()->GetGlobalProperty(
+ "TARGET_MESSAGES")) {
+ targetMessages = cmSystemTools::IsOn(tgtMsg);
+ }
+
+ if (targetMessages) {
+ lg->AppendEcho(commands, "Built target " + name,
+ cmLocalUnixMakefileGenerator3::EchoNormal, &progress);
+ }
+
+ this->AppendGlobalTargetDepends(depends, gtarget);
+ 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();
+
+ {
+ // TODO: Convert the total progress count to a make variable.
+ std::ostringstream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
+ // # in target
+ progCmd << lg->Convert(progress.Dir, cmOutputConverter::FULL,
+ cmOutputConverter::SHELL);
+ //
+ std::set<cmGeneratorTarget const*> emitted;
+ progCmd << " " << this->CountProgressMarksInTarget(gtarget, emitted);
+ commands.push_back(progCmd.str());
+ }
+ std::string tmp = cmake::GetCMakeFilesDirectoryPostSlash();
+ tmp += "Makefile2";
+ commands.push_back(lg->GetRecursiveMakeCall(tmp.c_str(), localName));
+ {
+ std::ostringstream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
+ progCmd << lg->Convert(progress.Dir, cmOutputConverter::FULL,
+ cmOutputConverter::SHELL);
+ progCmd << " 0";
+ commands.push_back(progCmd.str());
+ }
+ depends.clear();
+ depends.push_back("cmake_check_build_system");
+ localName = lg->GetRelativeTargetDirectory(gtarget);
+ localName += "/rule";
+ lg->WriteMakeRule(ruleFileStream,
+ "Build rule for subdir invocation for target.",
+ localName, depends, commands, true);
+
+ // Add a target with the canonical name (no prefix, suffix or path).
+ commands.clear();
+ depends.clear();
+ depends.push_back(localName);
+ lg->WriteMakeRule(ruleFileStream, "Convenience name for target.", name,
+ depends, commands, true);
+
+ // Add rules to prepare the target for installation.
+ if (gtarget->NeedRelinkBeforeInstall(lg->GetConfigName())) {
+ localName = lg->GetRelativeTargetDirectory(gtarget);
+ localName += "/preinstall";
+ depends.clear();
+ commands.clear();
+ commands.push_back(
+ lg->GetRecursiveMakeCall(makefileName.c_str(), localName));
+ lg->WriteMakeRule(ruleFileStream,
+ "Pre-install relink rule for target.", localName,
+ depends, commands, true);
+
+ if (!this->IsExcluded(this->LocalGenerators[0], gtarget)) {
+ depends.clear();
+ depends.push_back(localName);
+ commands.clear();
+ lg->WriteMakeRule(ruleFileStream, "Prepare target for install.",
+ "preinstall", depends, commands, true);
+ }
+ }
+
+ // add the clean rule
+ localName = lg->GetRelativeTargetDirectory(gtarget);
+ makeTargetName = localName;
+ makeTargetName += "/clean";
+ depends.clear();
+ commands.clear();
+ commands.push_back(
+ lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
+ 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);
+ }
+ }
+}
+
+// Build a map that contains a the set of targets used by each local
+// generator directory level.
+void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks()
+{
+ this->DirectoryTargetsMap.clear();
+ // Loop over all targets in all local generators.
+ for (std::vector<cmLocalGenerator*>::const_iterator lgi =
+ this->LocalGenerators.begin();
+ lgi != this->LocalGenerators.end(); ++lgi) {
+ cmLocalGenerator* lg = *lgi;
+ std::vector<cmGeneratorTarget*> targets = lg->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::const_iterator t = targets.begin();
+ t != targets.end(); ++t) {
+ cmGeneratorTarget* gt = *t;
+
+ cmLocalGenerator* tlg = gt->GetLocalGenerator();
+
+ if (gt->GetType() == cmState::INTERFACE_LIBRARY ||
+ gt->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+ continue;
+ }
+
+ cmState::Snapshot csnp = lg->GetStateSnapshot();
+ cmState::Snapshot tsnp = tlg->GetStateSnapshot();
+
+ // Consider the directory containing the target and all its
+ // parents until something excludes the target.
+ for (; csnp.IsValid() && !this->IsExcluded(csnp, tsnp);
+ csnp = csnp.GetBuildsystemDirectoryParent()) {
+ // This local generator includes the target.
+ std::set<cmGeneratorTarget const*>& targetSet =
+ this->DirectoryTargetsMap[csnp];
+ targetSet.insert(gt);
+
+ // 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 (TargetDependSet::const_iterator ti = tgtdeps.begin();
+ ti != tgtdeps.end(); ++ti) {
+ targetSet.insert(*ti);
+ }
+ }
+ }
+ }
+}
+
+size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInTarget(
+ cmGeneratorTarget const* target, std::set<cmGeneratorTarget const*>& emitted)
+{
+ size_t count = 0;
+ if (emitted.insert(target).second) {
+ count = this->ProgressMap[target].Marks.size();
+ TargetDependSet const& depends = this->GetTargetDirectDepends(target);
+ for (TargetDependSet::const_iterator di = depends.begin();
+ di != depends.end(); ++di) {
+ if ((*di)->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ count += this->CountProgressMarksInTarget(*di, emitted);
+ }
+ }
+ return count;
+}
+
+size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInAll(
+ cmLocalGenerator* lg)
+{
+ size_t count = 0;
+ std::set<cmGeneratorTarget const*> emitted;
+ std::set<cmGeneratorTarget const*> const& targets =
+ this->DirectoryTargetsMap[lg->GetStateSnapshot()];
+ for (std::set<cmGeneratorTarget const*>::const_iterator t = targets.begin();
+ t != targets.end(); ++t) {
+ count += this->CountProgressMarksInTarget(*t, emitted);
+ }
+ return count;
+}
+
+void cmGlobalUnixMakefileGenerator3::RecordTargetProgress(
+ cmMakefileTargetGenerator* tg)
+{
+ TargetProgress& tp = this->ProgressMap[tg->GetGeneratorTarget()];
+ tp.NumberOfActions = tg->GetNumberOfProgressActions();
+ tp.VariableFile = tg->GetProgressFileNameFull();
+}
+
+void cmGlobalUnixMakefileGenerator3::TargetProgress::WriteProgressVariables(
+ unsigned long total, unsigned long& current)
+{
+ cmGeneratedFileStream fout(this->VariableFile.c_str());
+ for (unsigned long i = 1; i <= this->NumberOfActions; ++i) {
+ fout << "CMAKE_PROGRESS_" << i << " = ";
+ if (total <= 100) {
+ unsigned long num = i + current;
+ fout << num;
+ this->Marks.push_back(num);
+ } else if (((i + current) * 100) / total >
+ ((i - 1 + current) * 100) / total) {
+ unsigned long num = ((i + current) * 100) / total;
+ fout << num;
+ this->Marks.push_back(num);
+ }
+ fout << "\n";
+ }
+ fout << "\n";
+ current += this->NumberOfActions;
+}
+
+void cmGlobalUnixMakefileGenerator3::AppendGlobalTargetDepends(
+ std::vector<std::string>& depends, cmGeneratorTarget* target)
+{
+ TargetDependSet const& depends_set = this->GetTargetDirectDepends(target);
+ for (TargetDependSet::const_iterator i = depends_set.begin();
+ i != depends_set.end(); ++i) {
+ // Create the target-level dependency.
+ cmGeneratorTarget const* dep = *i;
+ if (dep->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ cmLocalUnixMakefileGenerator3* lg3 =
+ static_cast<cmLocalUnixMakefileGenerator3*>(dep->GetLocalGenerator());
+ std::string tgtName =
+ lg3->GetRelativeTargetDirectory(const_cast<cmGeneratorTarget*>(dep));
+ tgtName += "/all";
+ depends.push_back(tgtName);
+ }
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteHelpRule(
+ std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg)
+{
+ // add the help target
+ std::string path;
+ std::vector<std::string> no_depends;
+ std::vector<std::string> commands;
+ lg->AppendEcho(commands, "The following are some of the valid targets "
+ "for this Makefile:");
+ lg->AppendEcho(commands, "... all (the default if no target is provided)");
+ lg->AppendEcho(commands, "... clean");
+ lg->AppendEcho(commands, "... depend");
+
+ // Keep track of targets already listed.
+ std::set<std::string> emittedTargets;
+
+ // for each local generator
+ unsigned int i;
+ cmLocalUnixMakefileGenerator3* lg2;
+ for (i = 0; i < this->LocalGenerators.size(); ++i) {
+ lg2 =
+ static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[i]);
+ // for the passed in makefile or if this is the top Makefile wripte out
+ // the targets
+ if (lg2 == lg || lg->IsRootMakefile()) {
+ // for each target Generate the rule files for each target.
+ std::vector<cmGeneratorTarget*> targets = lg2->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
+ t != targets.end(); ++t) {
+ cmGeneratorTarget* target = *t;
+ cmState::TargetType type = target->GetType();
+ if ((type == cmState::EXECUTABLE) ||
+ (type == cmState::STATIC_LIBRARY) ||
+ (type == cmState::SHARED_LIBRARY) ||
+ (type == cmState::MODULE_LIBRARY) ||
+ (type == cmState::OBJECT_LIBRARY) ||
+ (type == cmState::GLOBAL_TARGET) || (type == cmState::UTILITY)) {
+ std::string name = target->GetName();
+ if (emittedTargets.insert(name).second) {
+ path = "... ";
+ path += name;
+ lg->AppendEcho(commands, path);
+ }
+ }
+ }
+ }
+ }
+ std::vector<std::string> const& localHelp = lg->GetLocalHelp();
+ for (std::vector<std::string>::const_iterator o = localHelp.begin();
+ o != localHelp.end(); ++o) {
+ path = "... ";
+ path += *o;
+ lg->AppendEcho(commands, path);
+ }
+ lg->WriteMakeRule(ruleFileStream, "Help Target", "help", no_depends,
+ commands, true);
+ ruleFileStream << "\n\n";
+}
+
+bool cmGlobalUnixMakefileGenerator3::NeedRequiresStep(
+ const cmGeneratorTarget* target)
+{
+ std::set<std::string> languages;
+ target->GetLanguages(
+ languages,
+ target->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ for (std::set<std::string>::const_iterator l = languages.begin();
+ l != languages.end(); ++l) {
+ std::string var = "CMAKE_NEEDS_REQUIRES_STEP_";
+ var += *l;
+ var += "_FLAG";
+ if (target->Target->GetMakefile()->GetDefinition(var)) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
new file mode 100644
index 0000000..98969ff
--- /dev/null
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -0,0 +1,246 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalUnixMakefileGenerator3_h
+#define cmGlobalUnixMakefileGenerator3_h
+
+#include "cmGlobalCommonGenerator.h"
+
+#include "cmGlobalGeneratorFactory.h"
+
+class cmGeneratedFileStream;
+class cmMakefileTargetGenerator;
+class cmLocalUnixMakefileGenerator3;
+
+/** \class cmGlobalUnixMakefileGenerator3
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalUnixMakefileGenerator3 manages UNIX build process for a tree
+
+
+ The basic approach of this generator is to produce Makefiles that will all
+ be run with the current working directory set to the Home Output
+ directory. The one exception to this is the subdirectory Makefiles which are
+ created as a convenience and just cd up to the Home Output directory and
+ invoke the main Makefiles.
+
+ The make process starts with Makefile. Makefile should only contain the
+ targets the user is likely to invoke directly from a make command line. No
+ internal targets should be in this file. Makefile2 contains the internal
+ targets that are required to make the process work.
+
+ Makefile2 in turn will recursively make targets in the correct order. Each
+ target has its own directory \<target\>.dir and its own makefile build.make in
+ that directory. Also in that directory is a couple makefiles per source file
+ used by the target. Typically these are named source.obj.build.make and
+ source.obj.build.depend.make. The source.obj.build.make contains the rules
+ for building, cleaning, and computing dependencies for the given source
+ file. The build.depend.make contains additional dependencies that were
+ computed during dependency scanning. An additional file called
+ source.obj.depend is used as a marker to indicate when dependencies must be
+ rescanned.
+
+ Rules for custom commands follow the same model as rules for source files.
+
+ */
+
+class cmGlobalUnixMakefileGenerator3 : public cmGlobalCommonGenerator
+{
+public:
+ cmGlobalUnixMakefileGenerator3(cmake* cm);
+ static cmGlobalGeneratorFactory* NewFactory()
+ {
+ return new cmGlobalGeneratorSimpleFactory<
+ cmGlobalUnixMakefileGenerator3>();
+ }
+
+ ///! Get the name for the generator.
+ std::string GetName() const CM_OVERRIDE
+ {
+ return cmGlobalUnixMakefileGenerator3::GetActualName();
+ }
+ static std::string GetActualName() { return "Unix Makefiles"; }
+
+ /**
+ * Utilized by the generator factory to determine if this generator
+ * supports toolsets.
+ */
+ static bool SupportsToolset() { return false; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) CM_OVERRIDE;
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) CM_OVERRIDE;
+
+ void Configure() CM_OVERRIDE;
+
+ /**
+ * Generate the all required files for building this project/tree. This
+ * basically creates a series of LocalGenerators for each directory and
+ * requests that they Generate.
+ */
+ void Generate() CM_OVERRIDE;
+
+ void WriteMainCMakefileLanguageRules(cmGeneratedFileStream& cmakefileStream,
+ std::vector<cmLocalGenerator*>&);
+
+ // write out the help rule listing the valid targets
+ void WriteHelpRule(std::ostream& ruleFileStream,
+ cmLocalUnixMakefileGenerator3*);
+
+ // write the top level target rules
+ void WriteConvenienceRules(std::ostream& ruleFileStream,
+ std::set<std::string>& emitted);
+
+ /** Get the command to use for a target that has no rule. This is
+ used for multiple output dependencies and for cmake_force. */
+ std::string GetEmptyRuleHackCommand() { return this->EmptyRuleHackCommand; }
+
+ /** Get the fake dependency to use when a rule has no real commands
+ or dependencies. */
+ std::string GetEmptyRuleHackDepends() { return this->EmptyRuleHackDepends; }
+
+ // change the build command for speed
+ void GenerateBuildCommand(std::vector<std::string>& makeCommand,
+ const std::string& makeProgram,
+ const std::string& projectName,
+ const std::string& projectDir,
+ const std::string& targetName,
+ const std::string& config, bool fast, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) CM_OVERRIDE;
+
+ /** Record per-target progress information. */
+ void RecordTargetProgress(cmMakefileTargetGenerator* tg);
+
+ void AddCXXCompileCommand(const std::string& sourceFile,
+ const std::string& workingDirectory,
+ const std::string& compileCommand);
+
+ /** Does the make tool tolerate .NOTPARALLEL? */
+ virtual bool AllowNotParallel() const { return true; }
+
+ /** Does the make tool tolerate .DELETE_ON_ERROR? */
+ virtual bool AllowDeleteOnError() const { return true; }
+
+ void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const CM_OVERRIDE;
+
+ std::string IncludeDirective;
+ bool DefineWindowsNULL;
+ bool PassMakeflags;
+ bool UnixCD;
+
+protected:
+ void WriteMainMakefile2();
+ void WriteMainCMakefile();
+
+ void WriteConvenienceRules2(std::ostream& ruleFileStream,
+ cmLocalUnixMakefileGenerator3*);
+
+ void WriteDirectoryRule2(std::ostream& ruleFileStream,
+ cmLocalUnixMakefileGenerator3* lg, const char* pass,
+ bool check_all, bool check_relink);
+ void WriteDirectoryRules2(std::ostream& ruleFileStream,
+ cmLocalUnixMakefileGenerator3* lg);
+
+ void AppendGlobalTargetDepends(std::vector<std::string>& depends,
+ cmGeneratorTarget* target);
+
+ // does this generator need a requires step for any of its targets
+ bool NeedRequiresStep(cmGeneratorTarget const*);
+
+ // Target name hooks for superclass.
+ const char* GetAllTargetName() const CM_OVERRIDE { return "all"; }
+ const char* GetInstallTargetName() const CM_OVERRIDE { return "install"; }
+ const char* GetInstallLocalTargetName() const CM_OVERRIDE
+ {
+ return "install/local";
+ }
+ const char* GetInstallStripTargetName() const CM_OVERRIDE
+ {
+ return "install/strip";
+ }
+ const char* GetPreinstallTargetName() const CM_OVERRIDE
+ {
+ return "preinstall";
+ }
+ const char* GetTestTargetName() const CM_OVERRIDE { return "test"; }
+ const char* GetPackageTargetName() const CM_OVERRIDE { return "package"; }
+ const char* GetPackageSourceTargetName() const CM_OVERRIDE
+ {
+ return "package_source";
+ }
+ const char* GetEditCacheTargetName() const CM_OVERRIDE
+ {
+ return "edit_cache";
+ }
+ const char* GetRebuildCacheTargetName() const CM_OVERRIDE
+ {
+ return "rebuild_cache";
+ }
+ const char* GetCleanTargetName() const CM_OVERRIDE { return "clean"; }
+
+ bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const CM_OVERRIDE { return true; }
+
+ // Some make programs (Borland) do not keep a rule if there are no
+ // dependencies or commands. This is a problem for creating rules
+ // that might not do anything but might have other dependencies
+ // added later. If non-empty this variable holds a fake dependency
+ // that can be added.
+ std::string EmptyRuleHackDepends;
+
+ // Some make programs (Watcom) do not like rules with no commands.
+ // If non-empty this variable holds a bogus command that may be put
+ // in the rule to satisfy the make program.
+ std::string EmptyRuleHackCommand;
+
+ // Store per-target progress counters.
+ struct TargetProgress
+ {
+ TargetProgress()
+ : NumberOfActions(0)
+ {
+ }
+ unsigned long NumberOfActions;
+ std::string VariableFile;
+ std::vector<unsigned long> Marks;
+ void WriteProgressVariables(unsigned long total, unsigned long& current);
+ };
+ typedef std::map<cmGeneratorTarget const*, TargetProgress,
+ cmGeneratorTarget::StrictTargetComparison>
+ ProgressMapType;
+ ProgressMapType ProgressMap;
+
+ size_t CountProgressMarksInTarget(
+ cmGeneratorTarget const* target,
+ std::set<cmGeneratorTarget const*>& emitted);
+ size_t CountProgressMarksInAll(cmLocalGenerator* lg);
+
+ cmGeneratedFileStream* CommandDatabase;
+
+private:
+ const char* GetBuildIgnoreErrorsFlag() const CM_OVERRIDE { return "-i"; }
+ std::string GetEditCacheCommand() const CM_OVERRIDE;
+
+ std::map<cmState::Snapshot, std::set<cmGeneratorTarget const*>,
+ cmState::Snapshot::StrictWeakOrder>
+ DirectoryTargetsMap;
+ void InitializeProgressMarks() CM_OVERRIDE;
+};
+
+#endif
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
new file mode 100644
index 0000000..90ff98b
--- /dev/null
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -0,0 +1,543 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "windows.h" // this must be first to define GetCurrentDirectory
+
+#include "cmGlobalVisualStudio10Generator.h"
+
+#include "cmAlgorithms.h"
+#include "cmLocalVisualStudio10Generator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmVisualStudioSlnData.h"
+#include "cmVisualStudioSlnParser.h"
+#include "cmake.h"
+
+static const char vs10generatorName[] = "Visual Studio 10 2010";
+
+// Map generator name without year to name with year.
+static const char* cmVS10GenName(const std::string& name, std::string& genName)
+{
+ if (strncmp(name.c_str(), vs10generatorName,
+ sizeof(vs10generatorName) - 6) != 0) {
+ return 0;
+ }
+ const char* p = name.c_str() + sizeof(vs10generatorName) - 6;
+ if (cmHasLiteralPrefix(p, " 2010")) {
+ p += 5;
+ }
+ genName = std::string(vs10generatorName) + p;
+ return p;
+}
+
+class cmGlobalVisualStudio10Generator::Factory
+ : public cmGlobalGeneratorFactory
+{
+public:
+ virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
+ cmake* cm) const
+ {
+ std::string genName;
+ const char* p = cmVS10GenName(name, genName);
+ if (!p) {
+ return 0;
+ }
+ if (!*p) {
+ return new cmGlobalVisualStudio10Generator(cm, genName, "");
+ }
+ if (*p++ != ' ') {
+ return 0;
+ }
+ if (strcmp(p, "Win64") == 0) {
+ return new cmGlobalVisualStudio10Generator(cm, genName, "x64");
+ }
+ if (strcmp(p, "IA64") == 0) {
+ return new cmGlobalVisualStudio10Generator(cm, genName, "Itanium");
+ }
+ return 0;
+ }
+
+ virtual void GetDocumentation(cmDocumentationEntry& entry) const
+ {
+ entry.Name = std::string(vs10generatorName) + " [arch]";
+ entry.Brief = "Generates Visual Studio 2010 project files. "
+ "Optional [arch] can be \"Win64\" or \"IA64\".";
+ }
+
+ virtual void GetGenerators(std::vector<std::string>& names) const
+ {
+ names.push_back(vs10generatorName);
+ names.push_back(vs10generatorName + std::string(" IA64"));
+ names.push_back(vs10generatorName + std::string(" Win64"));
+ }
+
+ virtual bool SupportsToolset() const { return true; }
+};
+
+cmGlobalGeneratorFactory* cmGlobalVisualStudio10Generator::NewFactory()
+{
+ return new Factory;
+}
+
+cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator(
+ cmake* cm, const std::string& name, const std::string& platformName)
+ : cmGlobalVisualStudio8Generator(cm, name, platformName)
+{
+ std::string vc10Express;
+ this->ExpressEdition = cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\10.0\\Setup\\VC;"
+ "ProductDir",
+ vc10Express, cmSystemTools::KeyWOW64_32);
+ this->SystemIsWindowsCE = false;
+ this->SystemIsWindowsPhone = false;
+ this->SystemIsWindowsStore = false;
+ this->MSBuildCommandInitialized = false;
+ this->Version = VS10;
+}
+
+bool cmGlobalVisualStudio10Generator::MatchesGeneratorName(
+ const std::string& name) const
+{
+ std::string genName;
+ if (cmVS10GenName(name, genName)) {
+ return genName == this->GetName();
+ }
+ return false;
+}
+
+bool cmGlobalVisualStudio10Generator::SetSystemName(std::string const& s,
+ cmMakefile* mf)
+{
+ this->SystemName = s;
+ this->SystemVersion = mf->GetSafeDefinition("CMAKE_SYSTEM_VERSION");
+ if (!this->InitializeSystem(mf)) {
+ return false;
+ }
+ return this->cmGlobalVisualStudio8Generator::SetSystemName(s, mf);
+}
+
+bool cmGlobalVisualStudio10Generator::SetGeneratorPlatform(
+ std::string const& p, cmMakefile* mf)
+{
+ if (!this->cmGlobalVisualStudio8Generator::SetGeneratorPlatform(p, mf)) {
+ return false;
+ }
+ if (this->GetPlatformName() == "Itanium" ||
+ this->GetPlatformName() == "x64") {
+ if (this->IsExpressEdition() && !this->Find64BitTools(mf)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
+ std::string const& ts, cmMakefile* mf)
+{
+ if (this->SystemIsWindowsCE && ts.empty() &&
+ this->DefaultPlatformToolset.empty()) {
+ std::ostringstream e;
+ e << this->GetName() << " Windows CE version '" << this->SystemVersion
+ << "' requires CMAKE_GENERATOR_TOOLSET to be set.";
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ this->GeneratorToolset = ts;
+ if (const char* toolset = this->GetPlatformToolset()) {
+ mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET", toolset);
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio10Generator::InitializeSystem(cmMakefile* mf)
+{
+ if (this->SystemName == "Windows") {
+ if (!this->InitializeWindows(mf)) {
+ return false;
+ }
+ } else if (this->SystemName == "WindowsCE") {
+ this->SystemIsWindowsCE = true;
+ if (!this->InitializeWindowsCE(mf)) {
+ return false;
+ }
+ } else if (this->SystemName == "WindowsPhone") {
+ this->SystemIsWindowsPhone = true;
+ if (!this->InitializeWindowsPhone(mf)) {
+ return false;
+ }
+ } else if (this->SystemName == "WindowsStore") {
+ this->SystemIsWindowsStore = true;
+ if (!this->InitializeWindowsStore(mf)) {
+ return false;
+ }
+ } else if (this->SystemName == "Android") {
+ if (this->DefaultPlatformName != "Win32") {
+ std::ostringstream e;
+ e << "CMAKE_SYSTEM_NAME is 'Android' but CMAKE_GENERATOR "
+ << "specifies a platform too: '" << this->GetName() << "'";
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ std::string v = this->GetInstalledNsightTegraVersion();
+ if (v.empty()) {
+ mf->IssueMessage(cmake::FATAL_ERROR,
+ "CMAKE_SYSTEM_NAME is 'Android' but "
+ "'NVIDIA Nsight Tegra Visual Studio Edition' "
+ "is not installed.");
+ return false;
+ }
+ this->DefaultPlatformName = "Tegra-Android";
+ this->DefaultPlatformToolset = "Default";
+ this->NsightTegraVersion = v;
+ mf->AddDefinition("CMAKE_VS_NsightTegra_VERSION", v.c_str());
+ }
+
+ return true;
+}
+
+bool cmGlobalVisualStudio10Generator::InitializeWindows(cmMakefile*)
+{
+ return true;
+}
+
+bool cmGlobalVisualStudio10Generator::InitializeWindowsCE(cmMakefile* mf)
+{
+ if (this->DefaultPlatformName != "Win32") {
+ std::ostringstream e;
+ e << "CMAKE_SYSTEM_NAME is 'WindowsCE' but CMAKE_GENERATOR "
+ << "specifies a platform too: '" << this->GetName() << "'";
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ this->DefaultPlatformToolset = this->SelectWindowsCEToolset();
+
+ return true;
+}
+
+bool cmGlobalVisualStudio10Generator::InitializeWindowsPhone(cmMakefile* mf)
+{
+ std::ostringstream e;
+ e << this->GetName() << " does not support Windows Phone.";
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+}
+
+bool cmGlobalVisualStudio10Generator::InitializeWindowsStore(cmMakefile* mf)
+{
+ std::ostringstream e;
+ e << this->GetName() << " does not support Windows Store.";
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+}
+
+bool cmGlobalVisualStudio10Generator::SelectWindowsPhoneToolset(
+ std::string& toolset) const
+{
+ toolset = "";
+ return false;
+}
+
+bool cmGlobalVisualStudio10Generator::SelectWindowsStoreToolset(
+ std::string& toolset) const
+{
+ toolset = "";
+ return false;
+}
+
+std::string cmGlobalVisualStudio10Generator::SelectWindowsCEToolset() const
+{
+ if (this->SystemVersion == "8.0") {
+ return "CE800";
+ }
+ return "";
+}
+
+void cmGlobalVisualStudio10Generator::WriteSLNHeader(std::ostream& fout)
+{
+ fout << "Microsoft Visual Studio Solution File, Format Version 11.00\n";
+ if (this->ExpressEdition) {
+ fout << "# Visual C++ Express 2010\n";
+ } else {
+ fout << "# Visual Studio 2010\n";
+ }
+}
+
+///! Create a local generator appropriate to this Global Generator
+cmLocalGenerator* cmGlobalVisualStudio10Generator::CreateLocalGenerator(
+ cmMakefile* mf)
+{
+ return new cmLocalVisualStudio10Generator(this, mf);
+}
+
+void cmGlobalVisualStudio10Generator::Generate()
+{
+ this->LongestSource = LongestSourcePath();
+ this->cmGlobalVisualStudio8Generator::Generate();
+ if (this->LongestSource.Length > 0) {
+ cmLocalGenerator* lg = this->LongestSource.Target->GetLocalGenerator();
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "The binary and/or source directory paths may be too long to generate "
+ "Visual Studio 10 files for this project. "
+ "Consider choosing shorter directory names to build this project with "
+ "Visual Studio 10. "
+ "A more detailed explanation follows."
+ "\n"
+ "There is a bug in the VS 10 IDE that renders property dialog fields "
+ "blank for files referenced by full path in the project file. "
+ "However, CMake must reference at least one file by full path:\n"
+ " " << this->LongestSource.SourceFile->GetFullPath() << "\n"
+ "This is because some Visual Studio tools would append the relative "
+ "path to the end of the referencing directory path, as in:\n"
+ " " << lg->GetCurrentBinaryDirectory() << "/"
+ << this->LongestSource.SourceRel << "\n"
+ "and then incorrectly complain that the file does not exist because "
+ "the path length is too long for some internal buffer or API. "
+ "To avoid this problem CMake must use a full path for this file "
+ "which then triggers the VS 10 property dialog bug.";
+ /* clang-format on */
+ lg->IssueMessage(cmake::WARNING, e.str().c_str());
+ }
+}
+
+void cmGlobalVisualStudio10Generator::EnableLanguage(
+ std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
+{
+ cmGlobalVisualStudio8Generator::EnableLanguage(lang, mf, optional);
+}
+
+const char* cmGlobalVisualStudio10Generator::GetPlatformToolset() const
+{
+ if (!this->GeneratorToolset.empty()) {
+ return this->GeneratorToolset.c_str();
+ }
+ if (!this->DefaultPlatformToolset.empty()) {
+ return this->DefaultPlatformToolset.c_str();
+ }
+ return 0;
+}
+
+void cmGlobalVisualStudio10Generator::FindMakeProgram(cmMakefile* mf)
+{
+ this->cmGlobalVisualStudio8Generator::FindMakeProgram(mf);
+ mf->AddDefinition("CMAKE_VS_MSBUILD_COMMAND",
+ this->GetMSBuildCommand().c_str());
+}
+
+std::string const& cmGlobalVisualStudio10Generator::GetMSBuildCommand()
+{
+ if (!this->MSBuildCommandInitialized) {
+ this->MSBuildCommandInitialized = true;
+ this->MSBuildCommand = this->FindMSBuildCommand();
+ }
+ return this->MSBuildCommand;
+}
+
+std::string cmGlobalVisualStudio10Generator::FindMSBuildCommand()
+{
+ std::string msbuild;
+ std::string mskey =
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\";
+ mskey += this->GetToolsVersion();
+ mskey += ";MSBuildToolsPath";
+ if (cmSystemTools::ReadRegistryValue(mskey.c_str(), msbuild,
+ cmSystemTools::KeyWOW64_32)) {
+ cmSystemTools::ConvertToUnixSlashes(msbuild);
+ msbuild += "/";
+ }
+ msbuild += "MSBuild.exe";
+ return msbuild;
+}
+
+std::string cmGlobalVisualStudio10Generator::FindDevEnvCommand()
+{
+ if (this->ExpressEdition) {
+ // Visual Studio Express >= 10 do not have "devenv.com" or
+ // "VCExpress.exe" that we can use to build reliably.
+ // Tell the caller it needs to use MSBuild instead.
+ return "";
+ }
+ // Skip over the cmGlobalVisualStudio8Generator implementation because
+ // we expect a real devenv and do not want to look for VCExpress.
+ return this->cmGlobalVisualStudio71Generator::FindDevEnvCommand();
+}
+
+void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
+ std::vector<std::string>& makeCommand, const std::string& makeProgram,
+ const std::string& projectName, const std::string& projectDir,
+ const std::string& targetName, const std::string& config, bool fast,
+ bool verbose, std::vector<std::string> const& makeOptions)
+{
+ // Select the caller- or user-preferred make program, else MSBuild.
+ std::string makeProgramSelected =
+ this->SelectMakeProgram(makeProgram, this->GetMSBuildCommand());
+
+ // Check if the caller explicitly requested a devenv tool.
+ std::string makeProgramLower = makeProgramSelected;
+ cmSystemTools::LowerCase(makeProgramLower);
+ bool useDevEnv = (makeProgramLower.find("devenv") != std::string::npos ||
+ makeProgramLower.find("vcexpress") != std::string::npos);
+
+ // MSBuild is preferred (and required for VS Express), but if the .sln has
+ // an Intel Fortran .vfproj then we have to use devenv. Parse it to find out.
+ cmSlnData slnData;
+ {
+ std::string slnFile;
+ if (!projectDir.empty()) {
+ slnFile = projectDir;
+ slnFile += "/";
+ }
+ slnFile += projectName;
+ slnFile += ".sln";
+ cmVisualStudioSlnParser parser;
+ if (parser.ParseFile(slnFile, slnData,
+ cmVisualStudioSlnParser::DataGroupProjects)) {
+ std::vector<cmSlnProjectEntry> slnProjects = slnData.GetProjects();
+ for (std::vector<cmSlnProjectEntry>::iterator i = slnProjects.begin();
+ !useDevEnv && i != slnProjects.end(); ++i) {
+ std::string proj = i->GetRelativePath();
+ if (proj.size() > 7 && proj.substr(proj.size() - 7) == ".vfproj") {
+ useDevEnv = true;
+ }
+ }
+ }
+ }
+ if (useDevEnv) {
+ // Use devenv to build solutions containing Intel Fortran projects.
+ cmGlobalVisualStudio7Generator::GenerateBuildCommand(
+ makeCommand, makeProgram, projectName, projectDir, targetName, config,
+ fast, verbose, makeOptions);
+ return;
+ }
+
+ makeCommand.push_back(makeProgramSelected);
+
+ std::string realTarget = targetName;
+ // msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug /target:ALL_BUILD
+ if (realTarget.empty()) {
+ realTarget = "ALL_BUILD";
+ }
+ if (realTarget == "clean") {
+ makeCommand.push_back(std::string(projectName) + ".sln");
+ makeCommand.push_back("/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);
+ }
+ }
+ makeCommand.push_back(targetProject);
+ }
+ std::string configArg = "/p:Configuration=";
+ if (!config.empty()) {
+ configArg += config;
+ } else {
+ configArg += "Debug";
+ }
+ makeCommand.push_back(configArg);
+ makeCommand.push_back(std::string("/p:VisualStudioVersion=") +
+ this->GetIDEVersion());
+ makeCommand.insert(makeCommand.end(), makeOptions.begin(),
+ makeOptions.end());
+}
+
+bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
+{
+ if (this->GetPlatformToolset()) {
+ return true;
+ }
+ // This edition does not come with 64-bit tools. Look for them.
+ //
+ // TODO: Detect available tools? x64\v100 exists but does not work?
+ // HKLM\\SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\4.0;VCTargetsPath
+ // c:/Program Files (x86)/MSBuild/Microsoft.Cpp/v4.0/Platforms/
+ // {Itanium,Win32,x64}/PlatformToolsets/{v100,v90,Windows7.1SDK}
+ std::string winSDK_7_1;
+ if (cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\"
+ "Windows\\v7.1;InstallationFolder",
+ winSDK_7_1)) {
+ std::ostringstream m;
+ m << "Found Windows SDK v7.1: " << winSDK_7_1;
+ mf->DisplayStatus(m.str().c_str(), -1);
+ this->DefaultPlatformToolset = "Windows7.1SDK";
+ return true;
+ } else {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "Cannot enable 64-bit tools with Visual Studio 2010 Express.\n"
+ << "Install the Microsoft Windows SDK v7.1 to get 64-bit tools:\n"
+ << " http://msdn.microsoft.com/en-us/windows/bb980924.aspx";
+ /* clang-format on */
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str().c_str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+}
+
+std::string cmGlobalVisualStudio10Generator::GenerateRuleFile(
+ std::string const& output) const
+{
+ // The VS 10 generator needs to create the .rule files on disk.
+ // Hide them away under the CMakeFiles directory.
+ std::string ruleDir = this->GetCMakeInstance()->GetHomeOutputDirectory();
+ ruleDir += cmake::GetCMakeFilesDirectory();
+ ruleDir += "/";
+ ruleDir += cmSystemTools::ComputeStringMD5(
+ cmSystemTools::GetFilenamePath(output).c_str());
+ std::string ruleFile = ruleDir + "/";
+ ruleFile += cmSystemTools::GetFilenameName(output);
+ ruleFile += ".rule";
+ return ruleFile;
+}
+
+void cmGlobalVisualStudio10Generator::PathTooLong(cmGeneratorTarget* target,
+ cmSourceFile const* sf,
+ std::string const& sfRel)
+{
+ size_t len =
+ (strlen(target->GetLocalGenerator()->GetCurrentBinaryDirectory()) + 1 +
+ sfRel.length());
+ if (len > this->LongestSource.Length) {
+ this->LongestSource.Length = len;
+ this->LongestSource.Target = target;
+ this->LongestSource.SourceFile = sf;
+ this->LongestSource.SourceRel = sfRel;
+ }
+}
+
+bool cmGlobalVisualStudio10Generator::IsNsightTegra() const
+{
+ return !this->NsightTegraVersion.empty();
+}
+
+std::string cmGlobalVisualStudio10Generator::GetNsightTegraVersion() const
+{
+ return this->NsightTegraVersion;
+}
+
+std::string cmGlobalVisualStudio10Generator::GetInstalledNsightTegraVersion()
+{
+ std::string version;
+ cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NVIDIA Corporation\\Nsight Tegra;"
+ "Version",
+ version, cmSystemTools::KeyWOW64_32);
+ return version;
+}
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
new file mode 100644
index 0000000..51fd5a5
--- /dev/null
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -0,0 +1,148 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalVisualStudio10Generator_h
+#define cmGlobalVisualStudio10Generator_h
+
+#include "cmGlobalVisualStudio8Generator.h"
+
+/** \class cmGlobalVisualStudio10Generator
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalVisualStudio10Generator manages UNIX build process for a tree
+ */
+class cmGlobalVisualStudio10Generator : public cmGlobalVisualStudio8Generator
+{
+public:
+ cmGlobalVisualStudio10Generator(cmake* cm, const std::string& name,
+ const std::string& platformName);
+ static cmGlobalGeneratorFactory* NewFactory();
+
+ virtual bool MatchesGeneratorName(const std::string& name) const;
+
+ virtual bool SetSystemName(std::string const& s, cmMakefile* mf);
+ virtual bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf);
+ virtual bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf);
+
+ virtual void GenerateBuildCommand(
+ std::vector<std::string>& makeCommand, const std::string& makeProgram,
+ const std::string& projectName, const std::string& projectDir,
+ const std::string& targetName, const std::string& config, bool fast,
+ bool verbose,
+ std::vector<std::string> const& makeOptions = std::vector<std::string>());
+
+ ///! create the correct local generator
+ virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf);
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+ virtual void WriteSLNHeader(std::ostream& fout);
+
+ /** Generating for Nsight Tegra VS plugin? */
+ bool IsNsightTegra() const;
+ std::string GetNsightTegraVersion() const;
+
+ /** The toolset name for the target platform. */
+ const char* GetPlatformToolset() const;
+
+ /** Return the CMAKE_SYSTEM_NAME. */
+ std::string const& GetSystemName() const { return this->SystemName; }
+
+ /** Return the CMAKE_SYSTEM_VERSION. */
+ std::string const& GetSystemVersion() const { return this->SystemVersion; }
+
+ /** Return the Windows version targeted on VS 2015 and above. */
+ std::string const& GetWindowsTargetPlatformVersion() const
+ {
+ return this->WindowsTargetPlatformVersion;
+ }
+
+ /** Return true if building for WindowsCE */
+ bool TargetsWindowsCE() const { return this->SystemIsWindowsCE; }
+
+ /** Return true if building for WindowsPhone */
+ bool TargetsWindowsPhone() const { return this->SystemIsWindowsPhone; }
+
+ /** Return true if building for WindowsStore */
+ bool TargetsWindowsStore() const { return this->SystemIsWindowsStore; }
+
+ virtual const char* GetCMakeCFGIntDir() const { return "$(Configuration)"; }
+ bool Find64BitTools(cmMakefile* mf);
+
+ /** Generate an <output>.rule file path for a given command output. */
+ virtual std::string GenerateRuleFile(std::string const& output) const;
+
+ void PathTooLong(cmGeneratorTarget* target, cmSourceFile const* sf,
+ std::string const& sfRel);
+
+ virtual const char* GetToolsVersion() { return "4.0"; }
+
+ virtual void FindMakeProgram(cmMakefile*);
+
+ static std::string GetInstalledNsightTegraVersion();
+
+protected:
+ virtual void Generate();
+ virtual bool InitializeSystem(cmMakefile* mf);
+ virtual bool InitializeWindows(cmMakefile* mf);
+ virtual bool InitializeWindowsCE(cmMakefile* mf);
+ virtual bool InitializeWindowsPhone(cmMakefile* mf);
+ virtual bool InitializeWindowsStore(cmMakefile* mf);
+
+ virtual std::string SelectWindowsCEToolset() const;
+ virtual bool SelectWindowsPhoneToolset(std::string& toolset) const;
+ virtual bool SelectWindowsStoreToolset(std::string& toolset) const;
+
+ virtual const char* GetIDEVersion() { return "10.0"; }
+
+ std::string const& GetMSBuildCommand();
+
+ std::string GeneratorToolset;
+ std::string DefaultPlatformToolset;
+ std::string WindowsTargetPlatformVersion;
+ std::string SystemName;
+ std::string SystemVersion;
+ std::string NsightTegraVersion;
+ bool SystemIsWindowsCE;
+ bool SystemIsWindowsPhone;
+ bool SystemIsWindowsStore;
+
+private:
+ class Factory;
+ struct LongestSourcePath
+ {
+ LongestSourcePath()
+ : Length(0)
+ , Target(0)
+ , SourceFile(0)
+ {
+ }
+ size_t Length;
+ cmGeneratorTarget* Target;
+ cmSourceFile const* SourceFile;
+ std::string SourceRel;
+ };
+ LongestSourcePath LongestSource;
+
+ std::string MSBuildCommand;
+ bool MSBuildCommandInitialized;
+ virtual std::string FindMSBuildCommand();
+ virtual std::string FindDevEnvCommand();
+ virtual std::string GetVSMakeProgram() { return this->GetMSBuildCommand(); }
+
+ // We do not use the reload macros for VS >= 10.
+ virtual std::string GetUserMacrosDirectory() { return ""; }
+};
+#endif
diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx
new file mode 100644
index 0000000..295b6eb
--- /dev/null
+++ b/Source/cmGlobalVisualStudio11Generator.cxx
@@ -0,0 +1,285 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2011 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalVisualStudio11Generator.h"
+
+#include "cmAlgorithms.h"
+#include "cmLocalVisualStudio10Generator.h"
+#include "cmMakefile.h"
+
+static const char vs11generatorName[] = "Visual Studio 11 2012";
+
+// Map generator name without year to name with year.
+static const char* cmVS11GenName(const std::string& name, std::string& genName)
+{
+ if (strncmp(name.c_str(), vs11generatorName,
+ sizeof(vs11generatorName) - 6) != 0) {
+ return 0;
+ }
+ const char* p = name.c_str() + sizeof(vs11generatorName) - 6;
+ if (cmHasLiteralPrefix(p, " 2012")) {
+ p += 5;
+ }
+ genName = std::string(vs11generatorName) + p;
+ return p;
+}
+
+class cmGlobalVisualStudio11Generator::Factory
+ : public cmGlobalGeneratorFactory
+{
+public:
+ virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
+ cmake* cm) const
+ {
+ std::string genName;
+ const char* p = cmVS11GenName(name, genName);
+ if (!p) {
+ return 0;
+ }
+ if (!*p) {
+ return new cmGlobalVisualStudio11Generator(cm, genName, "");
+ }
+ if (*p++ != ' ') {
+ return 0;
+ }
+ if (strcmp(p, "Win64") == 0) {
+ return new cmGlobalVisualStudio11Generator(cm, genName, "x64");
+ }
+ if (strcmp(p, "ARM") == 0) {
+ return new cmGlobalVisualStudio11Generator(cm, genName, "ARM");
+ }
+
+ std::set<std::string> installedSDKs =
+ cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs();
+
+ if (installedSDKs.find(p) == installedSDKs.end()) {
+ return 0;
+ }
+
+ cmGlobalVisualStudio11Generator* ret =
+ new cmGlobalVisualStudio11Generator(cm, name, p);
+ ret->WindowsCEVersion = "8.00";
+ return ret;
+ }
+
+ virtual void GetDocumentation(cmDocumentationEntry& entry) const
+ {
+ entry.Name = std::string(vs11generatorName) + " [arch]";
+ entry.Brief = "Generates Visual Studio 2012 project files. "
+ "Optional [arch] can be \"Win64\" or \"ARM\".";
+ }
+
+ virtual void GetGenerators(std::vector<std::string>& names) const
+ {
+ names.push_back(vs11generatorName);
+ names.push_back(vs11generatorName + std::string(" ARM"));
+ names.push_back(vs11generatorName + std::string(" Win64"));
+
+ std::set<std::string> installedSDKs =
+ cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs();
+ for (std::set<std::string>::const_iterator i = installedSDKs.begin();
+ i != installedSDKs.end(); ++i) {
+ names.push_back(std::string(vs11generatorName) + " " + *i);
+ }
+ }
+
+ virtual bool SupportsToolset() const { return true; }
+};
+
+cmGlobalGeneratorFactory* cmGlobalVisualStudio11Generator::NewFactory()
+{
+ return new Factory;
+}
+
+cmGlobalVisualStudio11Generator::cmGlobalVisualStudio11Generator(
+ cmake* cm, const std::string& name, const std::string& platformName)
+ : cmGlobalVisualStudio10Generator(cm, name, platformName)
+{
+ std::string vc11Express;
+ this->ExpressEdition = cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\11.0\\Setup\\VC;"
+ "ProductDir",
+ vc11Express, cmSystemTools::KeyWOW64_32);
+ this->DefaultPlatformToolset = "v110";
+ this->Version = VS11;
+}
+
+bool cmGlobalVisualStudio11Generator::MatchesGeneratorName(
+ const std::string& name) const
+{
+ std::string genName;
+ if (cmVS11GenName(name, genName)) {
+ return genName == this->GetName();
+ }
+ return false;
+}
+
+bool cmGlobalVisualStudio11Generator::InitializeWindowsPhone(cmMakefile* mf)
+{
+ if (!this->SelectWindowsPhoneToolset(this->DefaultPlatformToolset)) {
+ std::ostringstream e;
+ if (this->DefaultPlatformToolset.empty()) {
+ e << this->GetName() << " supports Windows Phone '8.0', but not '"
+ << this->SystemVersion << "'. Check CMAKE_SYSTEM_VERSION.";
+ } else {
+ e << "A Windows Phone component with CMake requires both the Windows "
+ << "Desktop SDK as well as the Windows Phone '" << this->SystemVersion
+ << "' SDK. Please make sure that you have both installed";
+ }
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio11Generator::InitializeWindowsStore(cmMakefile* mf)
+{
+ if (!this->SelectWindowsStoreToolset(this->DefaultPlatformToolset)) {
+ std::ostringstream e;
+ if (this->DefaultPlatformToolset.empty()) {
+ e << this->GetName() << " supports Windows Store '8.0', but not '"
+ << this->SystemVersion << "'. Check CMAKE_SYSTEM_VERSION.";
+ } else {
+ e << "A Windows Store component with CMake requires both the Windows "
+ << "Desktop SDK as well as the Windows Store '" << this->SystemVersion
+ << "' SDK. Please make sure that you have both installed";
+ }
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio11Generator::SelectWindowsPhoneToolset(
+ std::string& toolset) const
+{
+ if (this->SystemVersion == "8.0") {
+ if (this->IsWindowsPhoneToolsetInstalled() &&
+ this->IsWindowsDesktopToolsetInstalled()) {
+ toolset = "v110_wp80";
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return this->cmGlobalVisualStudio10Generator::SelectWindowsPhoneToolset(
+ toolset);
+}
+
+bool cmGlobalVisualStudio11Generator::SelectWindowsStoreToolset(
+ std::string& toolset) const
+{
+ if (this->SystemVersion == "8.0") {
+ if (this->IsWindowsStoreToolsetInstalled() &&
+ this->IsWindowsDesktopToolsetInstalled()) {
+ toolset = "v110";
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return this->cmGlobalVisualStudio10Generator::SelectWindowsStoreToolset(
+ toolset);
+}
+
+void cmGlobalVisualStudio11Generator::WriteSLNHeader(std::ostream& fout)
+{
+ fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
+ if (this->ExpressEdition) {
+ fout << "# Visual Studio Express 2012 for Windows Desktop\n";
+ } else {
+ fout << "# Visual Studio 2012\n";
+ }
+}
+
+bool cmGlobalVisualStudio11Generator::UseFolderProperty()
+{
+ // Intentionally skip up to the top-level class implementation.
+ // Folders are not supported by the Express editions in VS10 and earlier,
+ // but they are in VS11 Express and above.
+ return cmGlobalGenerator::UseFolderProperty();
+}
+
+std::set<std::string>
+cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs()
+{
+ const char sdksKey[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "Windows CE Tools\\SDKs";
+
+ std::vector<std::string> subkeys;
+ cmSystemTools::GetRegistrySubKeys(sdksKey, subkeys,
+ cmSystemTools::KeyWOW64_32);
+
+ std::set<std::string> ret;
+ for (std::vector<std::string>::const_iterator i = subkeys.begin();
+ i != subkeys.end(); ++i) {
+ std::string key = sdksKey;
+ key += '\\';
+ key += *i;
+ key += ';';
+
+ std::string path;
+ if (cmSystemTools::ReadRegistryValue(key.c_str(), path,
+ cmSystemTools::KeyWOW64_32) &&
+ !path.empty()) {
+ ret.insert(*i);
+ }
+ }
+
+ return ret;
+}
+
+bool cmGlobalVisualStudio11Generator::NeedsDeploy(
+ cmState::TargetType type) const
+{
+ if ((type == cmState::EXECUTABLE || type == cmState::SHARED_LIBRARY) &&
+ (this->SystemIsWindowsPhone || this->SystemIsWindowsStore)) {
+ return true;
+ }
+ return cmGlobalVisualStudio10Generator::NeedsDeploy(type);
+}
+
+bool cmGlobalVisualStudio11Generator::IsWindowsDesktopToolsetInstalled() const
+{
+ const char desktop80Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "VisualStudio\\11.0\\VC\\Libraries\\Extended";
+ const char VS2012DesktopExpressKey[] =
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "WDExpress\\11.0;InstallDir";
+
+ std::vector<std::string> subkeys;
+ std::string path;
+ return cmSystemTools::ReadRegistryValue(VS2012DesktopExpressKey, path,
+ cmSystemTools::KeyWOW64_32) ||
+ cmSystemTools::GetRegistrySubKeys(desktop80Key, subkeys,
+ cmSystemTools::KeyWOW64_32);
+}
+
+bool cmGlobalVisualStudio11Generator::IsWindowsPhoneToolsetInstalled() const
+{
+ const char wp80Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "Microsoft SDKs\\WindowsPhone\\v8.0\\"
+ "Install Path;Install Path";
+
+ std::string path;
+ cmSystemTools::ReadRegistryValue(wp80Key, path, cmSystemTools::KeyWOW64_32);
+ return !path.empty();
+}
+
+bool cmGlobalVisualStudio11Generator::IsWindowsStoreToolsetInstalled() const
+{
+ const char win80Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "VisualStudio\\11.0\\VC\\Libraries\\Core\\Arm";
+
+ std::vector<std::string> subkeys;
+ return cmSystemTools::GetRegistrySubKeys(win80Key, subkeys,
+ cmSystemTools::KeyWOW64_32);
+}
diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h
new file mode 100644
index 0000000..ef6d343
--- /dev/null
+++ b/Source/cmGlobalVisualStudio11Generator.h
@@ -0,0 +1,55 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2011 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalVisualStudio11Generator_h
+#define cmGlobalVisualStudio11Generator_h
+
+#include "cmGlobalVisualStudio10Generator.h"
+
+/** \class cmGlobalVisualStudio11Generator */
+class cmGlobalVisualStudio11Generator : public cmGlobalVisualStudio10Generator
+{
+public:
+ cmGlobalVisualStudio11Generator(cmake* cm, const std::string& name,
+ const std::string& platformName);
+ static cmGlobalGeneratorFactory* NewFactory();
+
+ virtual bool MatchesGeneratorName(const std::string& name) const;
+
+ virtual void WriteSLNHeader(std::ostream& fout);
+
+protected:
+ virtual bool InitializeWindowsPhone(cmMakefile* mf);
+ virtual bool InitializeWindowsStore(cmMakefile* mf);
+ virtual bool SelectWindowsPhoneToolset(std::string& toolset) const;
+ virtual bool SelectWindowsStoreToolset(std::string& toolset) const;
+
+ // Used to verify that the Desktop toolset for the current generator is
+ // installed on the machine.
+ virtual bool IsWindowsDesktopToolsetInstalled() const;
+
+ // These aren't virtual because we need to check if the selected version
+ // of the toolset is installed
+ bool IsWindowsPhoneToolsetInstalled() const;
+ bool IsWindowsStoreToolsetInstalled() const;
+
+ virtual const char* GetIDEVersion() { return "11.0"; }
+ bool UseFolderProperty();
+ static std::set<std::string> GetInstalledWindowsCESDKs();
+
+ /** Return true if the configuration needs to be deployed */
+ virtual bool NeedsDeploy(cmState::TargetType type) const;
+
+private:
+ class Factory;
+ friend class Factory;
+};
+#endif
diff --git a/Source/cmGlobalVisualStudio12Generator.cxx b/Source/cmGlobalVisualStudio12Generator.cxx
new file mode 100644
index 0000000..318cb39
--- /dev/null
+++ b/Source/cmGlobalVisualStudio12Generator.cxx
@@ -0,0 +1,216 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2011 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalVisualStudio12Generator.h"
+
+#include "cmAlgorithms.h"
+#include "cmLocalVisualStudio10Generator.h"
+#include "cmMakefile.h"
+
+static const char vs12generatorName[] = "Visual Studio 12 2013";
+
+// Map generator name without year to name with year.
+static const char* cmVS12GenName(const std::string& name, std::string& genName)
+{
+ if (strncmp(name.c_str(), vs12generatorName,
+ sizeof(vs12generatorName) - 6) != 0) {
+ return 0;
+ }
+ const char* p = name.c_str() + sizeof(vs12generatorName) - 6;
+ if (cmHasLiteralPrefix(p, " 2013")) {
+ p += 5;
+ }
+ genName = std::string(vs12generatorName) + p;
+ return p;
+}
+
+class cmGlobalVisualStudio12Generator::Factory
+ : public cmGlobalGeneratorFactory
+{
+public:
+ virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
+ cmake* cm) const
+ {
+ std::string genName;
+ const char* p = cmVS12GenName(name, genName);
+ if (!p) {
+ return 0;
+ }
+ if (!*p) {
+ return new cmGlobalVisualStudio12Generator(cm, genName, "");
+ }
+ if (*p++ != ' ') {
+ return 0;
+ }
+ if (strcmp(p, "Win64") == 0) {
+ return new cmGlobalVisualStudio12Generator(cm, genName, "x64");
+ }
+ if (strcmp(p, "ARM") == 0) {
+ return new cmGlobalVisualStudio12Generator(cm, genName, "ARM");
+ }
+ return 0;
+ }
+
+ virtual void GetDocumentation(cmDocumentationEntry& entry) const
+ {
+ entry.Name = std::string(vs12generatorName) + " [arch]";
+ entry.Brief = "Generates Visual Studio 2013 project files. "
+ "Optional [arch] can be \"Win64\" or \"ARM\".";
+ }
+
+ virtual void GetGenerators(std::vector<std::string>& names) const
+ {
+ names.push_back(vs12generatorName);
+ names.push_back(vs12generatorName + std::string(" ARM"));
+ names.push_back(vs12generatorName + std::string(" Win64"));
+ }
+
+ virtual bool SupportsToolset() const { return true; }
+};
+
+cmGlobalGeneratorFactory* cmGlobalVisualStudio12Generator::NewFactory()
+{
+ return new Factory;
+}
+
+cmGlobalVisualStudio12Generator::cmGlobalVisualStudio12Generator(
+ cmake* cm, const std::string& name, const std::string& platformName)
+ : cmGlobalVisualStudio11Generator(cm, name, platformName)
+{
+ std::string vc12Express;
+ this->ExpressEdition = cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\12.0\\Setup\\VC;"
+ "ProductDir",
+ vc12Express, cmSystemTools::KeyWOW64_32);
+ this->DefaultPlatformToolset = "v120";
+ this->Version = VS12;
+}
+
+bool cmGlobalVisualStudio12Generator::MatchesGeneratorName(
+ const std::string& name) const
+{
+ std::string genName;
+ if (cmVS12GenName(name, genName)) {
+ return genName == this->GetName();
+ }
+ return false;
+}
+
+bool cmGlobalVisualStudio12Generator::InitializeWindowsPhone(cmMakefile* mf)
+{
+ if (!this->SelectWindowsPhoneToolset(this->DefaultPlatformToolset)) {
+ std::ostringstream e;
+ if (this->DefaultPlatformToolset.empty()) {
+ e << this->GetName() << " supports Windows Phone '8.0' and '8.1', but "
+ "not '"
+ << this->SystemVersion << "'. Check CMAKE_SYSTEM_VERSION.";
+ } else {
+ e << "A Windows Phone component with CMake requires both the Windows "
+ << "Desktop SDK as well as the Windows Phone '" << this->SystemVersion
+ << "' SDK. Please make sure that you have both installed";
+ }
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio12Generator::InitializeWindowsStore(cmMakefile* mf)
+{
+ if (!this->SelectWindowsStoreToolset(this->DefaultPlatformToolset)) {
+ std::ostringstream e;
+ if (this->DefaultPlatformToolset.empty()) {
+ e << this->GetName() << " supports Windows Store '8.0' and '8.1', but "
+ "not '"
+ << this->SystemVersion << "'. Check CMAKE_SYSTEM_VERSION.";
+ } else {
+ e << "A Windows Store component with CMake requires both the Windows "
+ << "Desktop SDK as well as the Windows Store '" << this->SystemVersion
+ << "' SDK. Please make sure that you have both installed";
+ }
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio12Generator::SelectWindowsPhoneToolset(
+ std::string& toolset) const
+{
+ if (this->SystemVersion == "8.1") {
+ if (this->IsWindowsPhoneToolsetInstalled() &&
+ this->IsWindowsDesktopToolsetInstalled()) {
+ toolset = "v120_wp81";
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return this->cmGlobalVisualStudio11Generator::SelectWindowsPhoneToolset(
+ toolset);
+}
+
+bool cmGlobalVisualStudio12Generator::SelectWindowsStoreToolset(
+ std::string& toolset) const
+{
+ if (this->SystemVersion == "8.1") {
+ if (this->IsWindowsStoreToolsetInstalled() &&
+ this->IsWindowsDesktopToolsetInstalled()) {
+ toolset = "v120";
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return this->cmGlobalVisualStudio11Generator::SelectWindowsStoreToolset(
+ toolset);
+}
+
+void cmGlobalVisualStudio12Generator::WriteSLNHeader(std::ostream& fout)
+{
+ fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
+ if (this->ExpressEdition) {
+ fout << "# Visual Studio Express 2013 for Windows Desktop\n";
+ } else {
+ fout << "# Visual Studio 2013\n";
+ }
+}
+
+bool cmGlobalVisualStudio12Generator::IsWindowsDesktopToolsetInstalled() const
+{
+ const char desktop81Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "VisualStudio\\12.0\\VC\\LibraryDesktop";
+
+ std::vector<std::string> subkeys;
+ return cmSystemTools::GetRegistrySubKeys(desktop81Key, subkeys,
+ cmSystemTools::KeyWOW64_32);
+}
+
+bool cmGlobalVisualStudio12Generator::IsWindowsPhoneToolsetInstalled() const
+{
+ const char wp81Key[] =
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "Microsoft SDKs\\WindowsPhone\\v8.1\\Install Path;Install Path";
+
+ std::string path;
+ cmSystemTools::ReadRegistryValue(wp81Key, path, cmSystemTools::KeyWOW64_32);
+ return !path.empty();
+}
+
+bool cmGlobalVisualStudio12Generator::IsWindowsStoreToolsetInstalled() const
+{
+ const char win81Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "VisualStudio\\12.0\\VC\\Libraries\\Core\\Arm";
+
+ std::vector<std::string> subkeys;
+ return cmSystemTools::GetRegistrySubKeys(win81Key, subkeys,
+ cmSystemTools::KeyWOW64_32);
+}
diff --git a/Source/cmGlobalVisualStudio12Generator.h b/Source/cmGlobalVisualStudio12Generator.h
new file mode 100644
index 0000000..567e240
--- /dev/null
+++ b/Source/cmGlobalVisualStudio12Generator.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2011 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalVisualStudio12Generator_h
+#define cmGlobalVisualStudio12Generator_h
+
+#include "cmGlobalVisualStudio11Generator.h"
+
+/** \class cmGlobalVisualStudio12Generator */
+class cmGlobalVisualStudio12Generator : public cmGlobalVisualStudio11Generator
+{
+public:
+ cmGlobalVisualStudio12Generator(cmake* cm, const std::string& name,
+ const std::string& platformName);
+ static cmGlobalGeneratorFactory* NewFactory();
+
+ virtual bool MatchesGeneratorName(const std::string& name) const;
+
+ virtual void WriteSLNHeader(std::ostream& fout);
+
+ // in Visual Studio 2013 they detached the MSBuild tools version
+ // from the .Net Framework version and instead made it have it's own
+ // version number
+ virtual const char* GetToolsVersion() { return "12.0"; }
+protected:
+ virtual bool InitializeWindowsPhone(cmMakefile* mf);
+ virtual bool InitializeWindowsStore(cmMakefile* mf);
+ virtual bool SelectWindowsPhoneToolset(std::string& toolset) const;
+ virtual bool SelectWindowsStoreToolset(std::string& toolset) const;
+
+ // Used to verify that the Desktop toolset for the current generator is
+ // installed on the machine.
+ virtual bool IsWindowsDesktopToolsetInstalled() const;
+
+ // These aren't virtual because we need to check if the selected version
+ // of the toolset is installed
+ bool IsWindowsPhoneToolsetInstalled() const;
+ bool IsWindowsStoreToolsetInstalled() const;
+ virtual const char* GetIDEVersion() { return "12.0"; }
+private:
+ class Factory;
+};
+#endif
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
new file mode 100644
index 0000000..e190e84
--- /dev/null
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -0,0 +1,263 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalVisualStudio14Generator.h"
+
+#include "cmAlgorithms.h"
+#include "cmLocalVisualStudio10Generator.h"
+#include "cmMakefile.h"
+
+static const char vs14generatorName[] = "Visual Studio 14 2015";
+
+// Map generator name without year to name with year.
+static const char* cmVS14GenName(const std::string& name, std::string& genName)
+{
+ if (strncmp(name.c_str(), vs14generatorName,
+ sizeof(vs14generatorName) - 6) != 0) {
+ return 0;
+ }
+ const char* p = name.c_str() + sizeof(vs14generatorName) - 6;
+ if (cmHasLiteralPrefix(p, " 2015")) {
+ p += 5;
+ }
+ genName = std::string(vs14generatorName) + p;
+ return p;
+}
+
+class cmGlobalVisualStudio14Generator::Factory
+ : public cmGlobalGeneratorFactory
+{
+public:
+ virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
+ cmake* cm) const
+ {
+ std::string genName;
+ const char* p = cmVS14GenName(name, genName);
+ if (!p) {
+ return 0;
+ }
+ if (!*p) {
+ return new cmGlobalVisualStudio14Generator(cm, genName, "");
+ }
+ if (*p++ != ' ') {
+ return 0;
+ }
+ if (strcmp(p, "Win64") == 0) {
+ return new cmGlobalVisualStudio14Generator(cm, genName, "x64");
+ }
+ if (strcmp(p, "ARM") == 0) {
+ return new cmGlobalVisualStudio14Generator(cm, genName, "ARM");
+ }
+ return 0;
+ }
+
+ virtual void GetDocumentation(cmDocumentationEntry& entry) const
+ {
+ entry.Name = std::string(vs14generatorName) + " [arch]";
+ entry.Brief = "Generates Visual Studio 2015 project files. "
+ "Optional [arch] can be \"Win64\" or \"ARM\".";
+ }
+
+ virtual void GetGenerators(std::vector<std::string>& names) const
+ {
+ names.push_back(vs14generatorName);
+ names.push_back(vs14generatorName + std::string(" ARM"));
+ names.push_back(vs14generatorName + std::string(" Win64"));
+ }
+
+ virtual bool SupportsToolset() const { return true; }
+};
+
+cmGlobalGeneratorFactory* cmGlobalVisualStudio14Generator::NewFactory()
+{
+ return new Factory;
+}
+
+cmGlobalVisualStudio14Generator::cmGlobalVisualStudio14Generator(
+ cmake* cm, const std::string& name, const std::string& platformName)
+ : cmGlobalVisualStudio12Generator(cm, name, platformName)
+{
+ std::string vc14Express;
+ this->ExpressEdition = cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\14.0\\Setup\\VC;"
+ "ProductDir",
+ vc14Express, cmSystemTools::KeyWOW64_32);
+ this->DefaultPlatformToolset = "v140";
+ this->Version = VS14;
+}
+
+bool cmGlobalVisualStudio14Generator::MatchesGeneratorName(
+ const std::string& name) const
+{
+ std::string genName;
+ if (cmVS14GenName(name, genName)) {
+ return genName == this->GetName();
+ }
+ return false;
+}
+
+bool cmGlobalVisualStudio14Generator::InitializeWindows(cmMakefile* mf)
+{
+ if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) {
+ return this->SelectWindows10SDK(mf, false);
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio14Generator::InitializeWindowsStore(cmMakefile* mf)
+{
+ std::ostringstream e;
+ if (!this->SelectWindowsStoreToolset(this->DefaultPlatformToolset)) {
+ if (this->DefaultPlatformToolset.empty()) {
+ e << this->GetName() << " supports Windows Store '8.0', '8.1' and "
+ "'10.0', but not '"
+ << this->SystemVersion << "'. Check CMAKE_SYSTEM_VERSION.";
+ } else {
+ e << "A Windows Store component with CMake requires both the Windows "
+ << "Desktop SDK as well as the Windows Store '" << this->SystemVersion
+ << "' SDK. Please make sure that you have both installed";
+ }
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) {
+ return this->SelectWindows10SDK(mf, true);
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio14Generator::SelectWindows10SDK(cmMakefile* mf,
+ bool required)
+{
+ // Find the default version of the Windows 10 SDK.
+ this->WindowsTargetPlatformVersion = this->GetWindows10SDKVersion();
+ if (required && this->WindowsTargetPlatformVersion.empty()) {
+ std::ostringstream e;
+ e << "Could not find an appropriate version of the Windows 10 SDK"
+ << " installed on this machine";
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ mf->AddDefinition("CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION",
+ this->WindowsTargetPlatformVersion.c_str());
+ return true;
+}
+
+bool cmGlobalVisualStudio14Generator::SelectWindowsStoreToolset(
+ std::string& toolset) const
+{
+ if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) {
+ if (this->IsWindowsStoreToolsetInstalled() &&
+ this->IsWindowsDesktopToolsetInstalled()) {
+ toolset = "v140";
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return this->cmGlobalVisualStudio12Generator::SelectWindowsStoreToolset(
+ toolset);
+}
+
+void cmGlobalVisualStudio14Generator::WriteSLNHeader(std::ostream& fout)
+{
+ // Visual Studio 14 writes .sln format 12.00
+ fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
+ if (this->ExpressEdition) {
+ fout << "# Visual Studio Express 14 for Windows Desktop\n";
+ } else {
+ fout << "# Visual Studio 14\n";
+ }
+}
+
+bool cmGlobalVisualStudio14Generator::IsWindowsDesktopToolsetInstalled() const
+{
+ const char desktop10Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "VisualStudio\\14.0\\VC\\Runtimes";
+
+ std::vector<std::string> vc14;
+ return cmSystemTools::GetRegistrySubKeys(desktop10Key, vc14,
+ cmSystemTools::KeyWOW64_32);
+}
+
+bool cmGlobalVisualStudio14Generator::IsWindowsStoreToolsetInstalled() const
+{
+ const char universal10Key[] =
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "VisualStudio\\14.0\\Setup\\Build Tools for Windows 10;SrcPath";
+
+ std::string win10SDK;
+ return cmSystemTools::ReadRegistryValue(universal10Key, win10SDK,
+ cmSystemTools::KeyWOW64_32);
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+struct NoWindowsH
+{
+ bool operator()(std::string const& p)
+ {
+ return !cmSystemTools::FileExists(p + "/um/windows.h", true);
+ }
+};
+#endif
+
+std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion()
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // This logic is taken from the vcvarsqueryregistry.bat file from VS2015
+ // Try HKLM and then HKCU.
+ std::string win10Root;
+ if (!cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "Windows Kits\\Installed Roots;KitsRoot10",
+ win10Root, cmSystemTools::KeyWOW64_32) &&
+ !cmSystemTools::ReadRegistryValue(
+ "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\"
+ "Windows Kits\\Installed Roots;KitsRoot10",
+ win10Root, cmSystemTools::KeyWOW64_32)) {
+ return std::string();
+ }
+
+ std::vector<std::string> sdks;
+ std::string path = win10Root + "Include/*";
+ // Grab the paths of the different SDKs that are installed
+ cmSystemTools::GlobDirs(path, sdks);
+
+ // Skip SDKs that do not contain <um/windows.h> because that indicates that
+ // only the UCRT MSIs were installed for them.
+ sdks.erase(std::remove_if(sdks.begin(), sdks.end(), NoWindowsH()),
+ sdks.end());
+
+ if (!sdks.empty()) {
+ // Only use the filename, which will be the SDK version.
+ for (std::vector<std::string>::iterator i = sdks.begin(); i != sdks.end();
+ ++i) {
+ *i = cmSystemTools::GetFilenameName(*i);
+ }
+
+ // Sort the results to make sure we select the most recent one.
+ std::sort(sdks.begin(), sdks.end(), cmSystemTools::VersionCompareGreater);
+
+ // Look for a SDK exactly matching the requested target version.
+ for (std::vector<std::string>::iterator i = sdks.begin(); i != sdks.end();
+ ++i) {
+ if (cmSystemTools::VersionCompareEqual(*i, this->SystemVersion)) {
+ return *i;
+ }
+ }
+
+ // Use the latest Windows 10 SDK since the exact version is not available.
+ return sdks.at(0);
+ }
+#endif
+ // Return an empty string
+ return std::string();
+}
diff --git a/Source/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h
new file mode 100644
index 0000000..a00f6c7
--- /dev/null
+++ b/Source/cmGlobalVisualStudio14Generator.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalVisualStudio14Generator_h
+#define cmGlobalVisualStudio14Generator_h
+
+#include "cmGlobalVisualStudio12Generator.h"
+
+/** \class cmGlobalVisualStudio14Generator */
+class cmGlobalVisualStudio14Generator : public cmGlobalVisualStudio12Generator
+{
+public:
+ cmGlobalVisualStudio14Generator(cmake* cm, const std::string& name,
+ const std::string& platformName);
+ static cmGlobalGeneratorFactory* NewFactory();
+
+ virtual bool MatchesGeneratorName(const std::string& name) const;
+
+ virtual void WriteSLNHeader(std::ostream& fout);
+
+ virtual const char* GetToolsVersion() { return "14.0"; }
+protected:
+ virtual bool InitializeWindows(cmMakefile* mf);
+ virtual bool InitializeWindowsStore(cmMakefile* mf);
+ virtual bool SelectWindowsStoreToolset(std::string& toolset) const;
+
+ // These aren't virtual because we need to check if the selected version
+ // of the toolset is installed
+ bool IsWindowsStoreToolsetInstalled() const;
+
+ virtual const char* GetIDEVersion() { return "14.0"; }
+ virtual bool SelectWindows10SDK(cmMakefile* mf, bool required);
+
+ // Used to verify that the Desktop toolset for the current generator is
+ // installed on the machine.
+ virtual bool IsWindowsDesktopToolsetInstalled() const;
+
+ std::string GetWindows10SDKVersion();
+
+private:
+ class Factory;
+};
+#endif
diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx
new file mode 100644
index 0000000..45d9522
--- /dev/null
+++ b/Source/cmGlobalVisualStudio71Generator.cxx
@@ -0,0 +1,289 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "windows.h" // this must be first to define GetCurrentDirectory
+
+#include "cmGlobalVisualStudio71Generator.h"
+
+#include "cmLocalVisualStudio7Generator.h"
+#include "cmMakefile.h"
+#include "cmake.h"
+
+cmGlobalVisualStudio71Generator::cmGlobalVisualStudio71Generator(
+ cmake* cm, const std::string& platformName)
+ : cmGlobalVisualStudio7Generator(cm, platformName)
+{
+ this->ProjectConfigurationSectionName = "ProjectConfiguration";
+ this->Version = VS71;
+}
+
+std::string cmGlobalVisualStudio71Generator::GetUserMacrosDirectory()
+{
+ // Macros not supported on Visual Studio 7.1 and earlier because
+ // they do not appear to work *during* a build when called by an
+ // outside agent...
+ //
+ return "";
+
+#if 0
+ //
+ // The COM result from calling a Visual Studio macro with 7.1 indicates
+ // that the call succeeds, but the macro does not appear to execute...
+ //
+ // So, I am leaving this code here to show how to do it, but have not
+ // yet figured out what the issue is in terms of why the macro does not
+ // appear to execute...
+ //
+ std::string base;
+ std::string path;
+
+ // base begins with the VisualStudioProjectsLocation reg value...
+ if (cmSystemTools::ReadRegistryValue(
+ "HKEY_CURRENT_USER\\Software\\Microsoft\\VisualStudio\\7.1;"
+ "VisualStudioProjectsLocation",
+ base))
+ {
+ cmSystemTools::ConvertToUnixSlashes(base);
+
+ // 7.1 macros folder:
+ path = base + "/VSMacros71";
+ }
+
+ // path is (correctly) still empty if we did not read the base value from
+ // the Registry value
+ return path;
+#endif
+}
+
+std::string cmGlobalVisualStudio71Generator::GetUserMacrosRegKeyBase()
+{
+ // Macros not supported on Visual Studio 7.1 and earlier because
+ // they do not appear to work *during* a build when called by an
+ // outside agent...
+ //
+ return "";
+
+#if 0
+ return "Software\\Microsoft\\VisualStudio\\7.1\\vsmacros";
+#endif
+}
+
+void cmGlobalVisualStudio71Generator::WriteSLNFile(
+ std::ostream& fout, cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators)
+{
+ std::vector<std::string> configs;
+ root->GetMakefile()->GetConfigurations(configs);
+
+ // Write out the header for a SLN file
+ this->WriteSLNHeader(fout);
+
+ // 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, this->GetStartupProjectName(root));
+
+ // Generate the targets specification to a string. We will put this in
+ // the actual .sln file later. As a side effect, this method also
+ // populates the set of folders.
+ std::ostringstream targetsSlnString;
+ this->WriteTargetsToSolution(targetsSlnString, root, orderedProjectTargets);
+
+ // VS 7 does not support folders specified first.
+ if (this->GetVersion() <= VS71) {
+ fout << targetsSlnString.str();
+ }
+
+ // Generate folder specification.
+ bool useFolderProperty = this->UseFolderProperty();
+ if (useFolderProperty) {
+ this->WriteFolders(fout);
+ }
+
+ // Now write the actual target specification content.
+ if (this->GetVersion() > VS71) {
+ fout << targetsSlnString.str();
+ }
+
+ // Write out the configurations information for the solution
+ fout << "Global\n";
+ // Write out the configurations for the solution
+ this->WriteSolutionConfigurations(fout, configs);
+ fout << "\tGlobalSection(" << this->ProjectConfigurationSectionName
+ << ") = postSolution\n";
+ // Write out the configurations for all the targets in the project
+ this->WriteTargetConfigurations(fout, configs, orderedProjectTargets);
+ fout << "\tEndGlobalSection\n";
+
+ if (useFolderProperty) {
+ // Write out project folders
+ fout << "\tGlobalSection(NestedProjects) = preSolution\n";
+ this->WriteFoldersContent(fout);
+ fout << "\tEndGlobalSection\n";
+ }
+
+ // Write out global sections
+ this->WriteSLNGlobalSections(fout, root);
+
+ // Write the footer for the SLN file
+ this->WriteSLNFooter(fout);
+}
+
+void cmGlobalVisualStudio71Generator::WriteSolutionConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs)
+{
+ fout << "\tGlobalSection(SolutionConfiguration) = preSolution\n";
+ for (std::vector<std::string>::const_iterator i = configs.begin();
+ i != configs.end(); ++i) {
+ fout << "\t\t" << *i << " = " << *i << "\n";
+ }
+ fout << "\tEndGlobalSection\n";
+}
+
+// Write a dsp file into the SLN file,
+// Note, that dependencies from executables to
+// the libraries it uses are also done here
+void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout,
+ const std::string& dspname,
+ const char* dir,
+ cmGeneratorTarget const* t)
+{
+ // check to see if this is a fortran build
+ const char* ext = ".vcproj";
+ const char* project =
+ "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"";
+ if (this->TargetIsFortranOnly(t)) {
+ ext = ".vfproj";
+ project = "Project(\"{6989167D-11E4-40FE-8C1A-2192A86A7E90}\") = \"";
+ }
+ const char* targetExt = t->GetProperty("GENERATOR_FILE_NAME_EXT");
+ if (targetExt) {
+ ext = targetExt;
+ }
+
+ std::string guid = this->GetGUID(dspname);
+ fout << project << dspname << "\", \"" << this->ConvertToSolutionPath(dir)
+ << (dir[0] ? "\\" : "") << dspname << ext << "\", \"{" << guid
+ << "}\"\n";
+ fout << "\tProjectSection(ProjectDependencies) = postProject\n";
+ this->WriteProjectDepends(fout, dspname, dir, t);
+ fout << "\tEndProjectSection\n";
+
+ fout << "EndProject\n";
+
+ UtilityDependsMap::iterator ui = this->UtilityDepends.find(t);
+ if (ui != this->UtilityDepends.end()) {
+ const char* uname = ui->second.c_str();
+ /* clang-format off */
+ fout << "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \""
+ << uname << "\", \""
+ << this->ConvertToSolutionPath(dir) << (dir[0]? "\\":"")
+ << uname << ".vcproj" << "\", \"{"
+ << this->GetGUID(uname) << "}\"\n"
+ << "\tProjectSection(ProjectDependencies) = postProject\n"
+ << "\t\t{" << guid << "} = {" << guid << "}\n"
+ << "\tEndProjectSection\n"
+ << "EndProject\n";
+ /* clang-format on */
+ }
+}
+
+// Write a dsp file into the SLN file,
+// Note, that dependencies from executables to
+// the libraries it uses are also done here
+void cmGlobalVisualStudio71Generator::WriteProjectDepends(
+ std::ostream& fout, const std::string&, const char*,
+ cmGeneratorTarget const* target)
+{
+ VSDependSet const& depends = this->VSTargetDepends[target];
+ for (VSDependSet::const_iterator di = depends.begin(); di != depends.end();
+ ++di) {
+ const char* name = di->c_str();
+ std::string guid = this->GetGUID(name);
+ if (guid.empty()) {
+ std::string m = "Target: ";
+ m += target->GetName();
+ m += " depends on unknown target: ";
+ m += name;
+ cmSystemTools::Error(m.c_str());
+ }
+ fout << "\t\t{" << guid << "} = {" << guid << "}\n";
+ }
+}
+
+// Write a dsp file into the SLN file, Note, that dependencies from
+// executables to the libraries it uses are also done here
+void cmGlobalVisualStudio71Generator::WriteExternalProject(
+ std::ostream& fout, const std::string& name, const char* location,
+ const char* typeGuid, const std::set<std::string>& depends)
+{
+ fout << "Project(\"{"
+ << (typeGuid ? typeGuid : this->ExternalProjectType(location))
+ << "}\") = \"" << name << "\", \""
+ << this->ConvertToSolutionPath(location) << "\", \"{"
+ << this->GetGUID(name) << "}\"\n";
+
+ // write out the dependencies here VS 7.1 includes dependencies with the
+ // project instead of in the global section
+ if (!depends.empty()) {
+ fout << "\tProjectSection(ProjectDependencies) = postProject\n";
+ std::set<std::string>::const_iterator it;
+ for (it = depends.begin(); it != depends.end(); ++it) {
+ if (!it->empty()) {
+ fout << "\t\t{" << this->GetGUID(it->c_str()) << "} = {"
+ << this->GetGUID(it->c_str()) << "}\n";
+ }
+ }
+ fout << "\tEndProjectSection\n";
+ }
+
+ fout << "EndProject\n";
+}
+
+// Write a dsp file into the SLN file, Note, that dependencies from
+// executables to the libraries it uses are also done here
+void cmGlobalVisualStudio71Generator::WriteProjectConfigurations(
+ std::ostream& fout, const std::string& name, cmState::TargetType,
+ std::vector<std::string> const& configs,
+ const std::set<std::string>& configsPartOfDefaultBuild,
+ std::string const& platformMapping)
+{
+ const std::string& platformName =
+ !platformMapping.empty() ? platformMapping : this->GetPlatformName();
+ std::string guid = this->GetGUID(name);
+ for (std::vector<std::string>::const_iterator i = configs.begin();
+ i != configs.end(); ++i) {
+ fout << "\t\t{" << guid << "}." << *i << ".ActiveCfg = " << *i << "|"
+ << platformName << std::endl;
+ std::set<std::string>::const_iterator ci =
+ configsPartOfDefaultBuild.find(*i);
+ if (!(ci == configsPartOfDefaultBuild.end())) {
+ fout << "\t\t{" << guid << "}." << *i << ".Build.0 = " << *i << "|"
+ << platformName << std::endl;
+ }
+ }
+}
+
+// ouput standard header for dsw file
+void cmGlobalVisualStudio71Generator::WriteSLNHeader(std::ostream& fout)
+{
+ fout << "Microsoft Visual Studio Solution File, Format Version 8.00\n";
+}
+
+void cmGlobalVisualStudio71Generator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalVisualStudio71Generator::GetActualName();
+ entry.Brief = "Deprecated. Generates Visual Studio .NET 2003 project files.";
+}
diff --git a/Source/cmGlobalVisualStudio71Generator.h b/Source/cmGlobalVisualStudio71Generator.h
new file mode 100644
index 0000000..9ad1fad
--- /dev/null
+++ b/Source/cmGlobalVisualStudio71Generator.h
@@ -0,0 +1,83 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalVisualStudio71Generator_h
+#define cmGlobalVisualStudio71Generator_h
+
+#include "cmGlobalVisualStudio7Generator.h"
+
+/** \class cmGlobalVisualStudio71Generator
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalVisualStudio71Generator manages UNIX build process for a tree
+ */
+class cmGlobalVisualStudio71Generator : public cmGlobalVisualStudio7Generator
+{
+public:
+ cmGlobalVisualStudio71Generator(cmake* cm,
+ const std::string& platformName = "");
+ static cmGlobalGeneratorFactory* NewFactory()
+ {
+ return new cmGlobalGeneratorSimpleFactory<
+ cmGlobalVisualStudio71Generator>();
+ }
+
+ ///! Get the name for the generator.
+ virtual std::string GetName() const
+ {
+ return cmGlobalVisualStudio71Generator::GetActualName();
+ }
+ static std::string GetActualName() { return "Visual Studio 7 .NET 2003"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ /**
+ * Where does this version of Visual Studio look for macros for the
+ * current user? Returns the empty string if this version of Visual
+ * Studio does not implement support for VB macros.
+ */
+ virtual std::string GetUserMacrosDirectory();
+
+ /**
+ * What is the reg key path to "vsmacros" for this version of Visual
+ * Studio?
+ */
+ virtual std::string GetUserMacrosRegKeyBase();
+
+protected:
+ virtual const char* GetIDEVersion() { return "7.1"; }
+ virtual void WriteSLNFile(std::ostream& fout, cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators);
+ virtual void WriteSolutionConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs);
+ virtual void WriteProject(std::ostream& fout, const std::string& name,
+ const char* path, const cmGeneratorTarget* t);
+ virtual void WriteProjectDepends(std::ostream& fout, const std::string& name,
+ const char* path,
+ cmGeneratorTarget const* t);
+ virtual void WriteProjectConfigurations(
+ std::ostream& fout, const std::string& name, cmState::TargetType type,
+ std::vector<std::string> const& configs,
+ const std::set<std::string>& configsPartOfDefaultBuild,
+ const std::string& platformMapping = "");
+ virtual void WriteExternalProject(std::ostream& fout,
+ const std::string& name, const char* path,
+ const char* typeGuid,
+ const std::set<std::string>& depends);
+ virtual void WriteSLNHeader(std::ostream& fout);
+
+ // Folders are not supported by VS 7.1.
+ virtual bool UseFolderProperty() { return false; }
+
+ std::string ProjectConfigurationSectionName;
+};
+#endif
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
new file mode 100644
index 0000000..262909f
--- /dev/null
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -0,0 +1,725 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "windows.h" // this must be first to define GetCurrentDirectory
+
+#include "cmGlobalVisualStudio7Generator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmLocalVisualStudio7Generator.h"
+#include "cmMakefile.h"
+#include "cmUuid.h"
+#include "cmake.h"
+#include <cmsys/Encoding.hxx>
+
+#include <assert.h>
+
+static cmVS7FlagTable cmVS7ExtraFlagTable[] = {
+ // Precompiled header and related options. Note that the
+ // UsePrecompiledHeader entries are marked as "Continue" so that the
+ // corresponding PrecompiledHeaderThrough entry can be found.
+ { "UsePrecompiledHeader", "YX", "Automatically Generate", "2",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeaderThrough", "YX", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "UsePrecompiledHeader", "Yu", "Use Precompiled Header", "3",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeaderThrough", "Yu", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "WholeProgramOptimization", "LTCG", "WholeProgramOptimization", "true",
+ 0 },
+
+ // Exception handling mode. If no entries match, it will be FALSE.
+ { "ExceptionHandling", "GX", "enable c++ exceptions", "true", 0 },
+ { "ExceptionHandling", "EHsc", "enable c++ exceptions", "true", 0 },
+ // The EHa option does not have an IDE setting. Let it go to false,
+ // and have EHa passed on the command line by leaving out the table
+ // entry.
+
+ { 0, 0, 0, 0, 0 }
+};
+
+cmGlobalVisualStudio7Generator::cmGlobalVisualStudio7Generator(
+ cmake* cm, const std::string& platformName)
+ : cmGlobalVisualStudioGenerator(cm)
+{
+ this->IntelProjectVersion = 0;
+ this->DevEnvCommandInitialized = false;
+ this->MasmEnabled = false;
+
+ if (platformName.empty()) {
+ this->DefaultPlatformName = "Win32";
+ } else {
+ this->DefaultPlatformName = platformName;
+ }
+ this->ExtraFlagTable = cmVS7ExtraFlagTable;
+ this->Version = VS7;
+}
+
+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()
+{
+ if (!this->IntelProjectVersion) {
+ // 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::KeyWOW64_32);
+ unsigned int intelVersionNumber = ~0u;
+ sscanf(intelVersion.c_str(), "%u", &intelVersionNumber);
+ if (intelVersionNumber >= 11) {
+ // Default to latest known project file version.
+ intelVersion = "11.0";
+ } else if (intelVersionNumber == 10) {
+ // Version 10.x actually uses 9.10 in project files!
+ intelVersion = "9.10";
+ } else {
+ // Version <= 9: use ProductVersion from registry.
+ }
+ this->IntelProjectVersion = strdup(intelVersion.c_str());
+ }
+ return this->IntelProjectVersion;
+}
+
+void cmGlobalVisualStudio7Generator::EnableLanguage(
+ std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
+{
+ mf->AddDefinition("CMAKE_GENERATOR_RC", "rc");
+ mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
+ if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
+ mf->AddCacheDefinition(
+ "CMAKE_CONFIGURATION_TYPES", "Debug;Release;MinSizeRel;RelWithDebInfo",
+ "Semicolon separated list of supported configuration types, "
+ "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
+ "anything else will be ignored.",
+ cmState::STRING);
+ }
+
+ // Create list of configurations requested by user's cache, if any.
+ this->cmGlobalGenerator::EnableLanguage(lang, mf, optional);
+
+ // if this environment variable is set, then copy it to
+ // a static cache entry. It will be used by
+ // cmLocalGenerator::ConstructScript, to add an extra PATH
+ // to all custom commands. This is because the VS IDE
+ // does not use the environment it is run in, and this allows
+ // for running commands and using dll's that the IDE environment
+ // does not know about.
+ const char* extraPath = cmSystemTools::GetEnv("CMAKE_MSVCIDE_RUN_PATH");
+ if (extraPath) {
+ mf->AddCacheDefinition("CMAKE_MSVCIDE_RUN_PATH", extraPath,
+ "Saved environment variable CMAKE_MSVCIDE_RUN_PATH",
+ cmState::STATIC);
+ }
+}
+
+void cmGlobalVisualStudio7Generator::FindMakeProgram(cmMakefile* mf)
+{
+ this->cmGlobalVisualStudioGenerator::FindMakeProgram(mf);
+ mf->AddDefinition("CMAKE_VS_DEVENV_COMMAND",
+ this->GetDevEnvCommand().c_str());
+}
+
+std::string const& cmGlobalVisualStudio7Generator::GetDevEnvCommand()
+{
+ if (!this->DevEnvCommandInitialized) {
+ this->DevEnvCommandInitialized = true;
+ this->DevEnvCommand = this->FindDevEnvCommand();
+ }
+ return this->DevEnvCommand;
+}
+
+std::string cmGlobalVisualStudio7Generator::FindDevEnvCommand()
+{
+ std::string vscmd;
+ std::string vskey = this->GetRegistryBase() + ";InstallDir";
+ if (cmSystemTools::ReadRegistryValue(vskey.c_str(), vscmd,
+ cmSystemTools::KeyWOW64_32)) {
+ cmSystemTools::ConvertToUnixSlashes(vscmd);
+ vscmd += "/";
+ }
+ vscmd += "devenv.com";
+ return vscmd;
+}
+
+const char* cmGlobalVisualStudio7Generator::ExternalProjectType(
+ const char* location)
+{
+ std::string extension = cmSystemTools::GetFilenameLastExtension(location);
+ if (extension == ".vbproj") {
+ return "F184B08F-C81C-45F6-A57F-5ABD9991F28F";
+ } else if (extension == ".csproj") {
+ return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC";
+ } else if (extension == ".fsproj") {
+ return "F2A71F9B-5D33-465A-A702-920D77279786";
+ } else if (extension == ".vdproj") {
+ return "54435603-DBB4-11D2-8724-00A0C9A8B90C";
+ } else if (extension == ".dbproj") {
+ return "C8D11400-126E-41CD-887F-60BD40844F9E";
+ } else if (extension == ".wixproj") {
+ return "930C7802-8A8C-48F9-8165-68863BCCD9DD";
+ } else if (extension == ".pyproj") {
+ return "888888A0-9F3D-457C-B088-3A5042F75D52";
+ }
+ return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942";
+}
+void cmGlobalVisualStudio7Generator::GenerateBuildCommand(
+ std::vector<std::string>& makeCommand, const std::string& makeProgram,
+ const std::string& projectName, const std::string& /*projectDir*/,
+ const std::string& targetName, const std::string& config, bool /*fast*/,
+ bool /*verbose*/, std::vector<std::string> const& makeOptions)
+{
+ // Select the caller- or user-preferred make program, else devenv.
+ std::string makeProgramSelected =
+ this->SelectMakeProgram(makeProgram, this->GetDevEnvCommand());
+
+ // Ignore the above preference if it is msbuild.
+ // Assume any other value is either a devenv or
+ // command-line compatible with devenv.
+ std::string makeProgramLower = makeProgramSelected;
+ cmSystemTools::LowerCase(makeProgramLower);
+ if (makeProgramLower.find("msbuild") != std::string::npos) {
+ makeProgramSelected = this->GetDevEnvCommand();
+ }
+
+ makeCommand.push_back(makeProgramSelected);
+
+ makeCommand.push_back(std::string(projectName) + ".sln");
+ std::string realTarget = targetName;
+ bool clean = false;
+ if (realTarget == "clean") {
+ clean = true;
+ realTarget = "ALL_BUILD";
+ }
+ if (clean) {
+ makeCommand.push_back("/clean");
+ } else {
+ makeCommand.push_back("/build");
+ }
+
+ if (!config.empty()) {
+ makeCommand.push_back(config);
+ } else {
+ makeCommand.push_back("Debug");
+ }
+ makeCommand.push_back("/project");
+
+ if (!realTarget.empty()) {
+ makeCommand.push_back(realTarget);
+ } else {
+ makeCommand.push_back("ALL_BUILD");
+ }
+ makeCommand.insert(makeCommand.end(), makeOptions.begin(),
+ makeOptions.end());
+}
+
+///! Create a local generator appropriate to this Global Generator
+cmLocalGenerator* cmGlobalVisualStudio7Generator::CreateLocalGenerator(
+ cmMakefile* mf)
+{
+ cmLocalVisualStudio7Generator* lg =
+ new cmLocalVisualStudio7Generator(this, mf);
+ return lg;
+}
+
+std::string const& cmGlobalVisualStudio7Generator::GetPlatformName() const
+{
+ if (!this->GeneratorPlatform.empty()) {
+ return this->GeneratorPlatform;
+ }
+ return this->DefaultPlatformName;
+}
+
+bool cmGlobalVisualStudio7Generator::SetSystemName(std::string const& s,
+ cmMakefile* mf)
+{
+ mf->AddDefinition("CMAKE_VS_INTEL_Fortran_PROJECT_VERSION",
+ this->GetIntelProjectVersion());
+ return this->cmGlobalVisualStudioGenerator::SetSystemName(s, mf);
+}
+
+bool cmGlobalVisualStudio7Generator::SetGeneratorPlatform(std::string const& p,
+ cmMakefile* mf)
+{
+ if (this->GetPlatformName() == "x64") {
+ mf->AddDefinition("CMAKE_FORCE_WIN64", "TRUE");
+ } else if (this->GetPlatformName() == "Itanium") {
+ mf->AddDefinition("CMAKE_FORCE_IA64", "TRUE");
+ }
+ mf->AddDefinition("CMAKE_VS_PLATFORM_NAME", this->GetPlatformName().c_str());
+ return this->cmGlobalVisualStudioGenerator::SetGeneratorPlatform(p, mf);
+}
+
+void cmGlobalVisualStudio7Generator::Generate()
+{
+ // first do the superclass method
+ this->cmGlobalVisualStudioGenerator::Generate();
+
+ // Now write out the DSW
+ this->OutputSLNFile();
+ // If any solution or project files changed during the generation,
+ // tell Visual Studio to reload them...
+ if (!cmSystemTools::GetErrorOccuredFlag()) {
+ this->CallVisualStudioMacro(MacroReload);
+ }
+
+ if (this->Version == VS71 && !this->CMakeInstance->GetIsInTryCompile()) {
+ const char* cmakeWarnVS71 =
+ this->CMakeInstance->GetState()->GetCacheEntryValue("CMAKE_WARN_VS71");
+ if (!cmakeWarnVS71 || !cmSystemTools::IsOff(cmakeWarnVS71)) {
+ this->CMakeInstance->IssueMessage(
+ cmake::WARNING,
+ "The \"Visual Studio 7 .NET 2003\" generator is deprecated "
+ "and will be removed in a future version of CMake."
+ "\n"
+ "Add CMAKE_WARN_VS71=OFF to the cache to disable this warning.");
+ }
+ }
+}
+
+void cmGlobalVisualStudio7Generator::OutputSLNFile(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
+{
+ if (generators.empty()) {
+ return;
+ }
+ this->CurrentProject = root->GetProjectName();
+ std::string fname = root->GetCurrentBinaryDirectory();
+ fname += "/";
+ fname += root->GetProjectName();
+ fname += ".sln";
+ cmGeneratedFileStream fout(fname.c_str());
+ fout.SetCopyIfDifferent(true);
+ if (!fout) {
+ return;
+ }
+ this->WriteSLNFile(fout, root, generators);
+ if (fout.Close()) {
+ this->FileReplacedDuringGenerate(fname);
+ }
+}
+
+// output the SLN file
+void cmGlobalVisualStudio7Generator::OutputSLNFile()
+{
+ std::map<std::string, std::vector<cmLocalGenerator*> >::iterator it;
+ for (it = this->ProjectMap.begin(); it != this->ProjectMap.end(); ++it) {
+ this->OutputSLNFile(it->second[0], it->second);
+ }
+}
+
+void cmGlobalVisualStudio7Generator::WriteTargetConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs,
+ OrderedTargetDependSet const& projectTargets)
+{
+ // loop over again and write out configurations for each target
+ // in the solution
+ for (OrderedTargetDependSet::const_iterator tt = projectTargets.begin();
+ tt != projectTargets.end(); ++tt) {
+ cmGeneratorTarget const* target = *tt;
+ if (target->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ const char* expath = target->GetProperty("EXTERNAL_MSPROJECT");
+ if (expath) {
+ std::set<std::string> allConfigurations(configs.begin(), configs.end());
+ const char* mapping = target->GetProperty("VS_PLATFORM_MAPPING");
+ this->WriteProjectConfigurations(
+ fout, target->GetName().c_str(), target->GetType(), configs,
+ allConfigurations, mapping ? mapping : "");
+ } else {
+ const std::set<std::string>& configsPartOfDefaultBuild =
+ this->IsPartOfDefaultBuild(configs, projectTargets, target);
+ const char* vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
+ if (vcprojName) {
+ this->WriteProjectConfigurations(fout, vcprojName, target->GetType(),
+ configs, configsPartOfDefaultBuild);
+ }
+ }
+ }
+}
+
+void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
+ std::ostream& fout, cmLocalGenerator* root,
+ OrderedTargetDependSet const& projectTargets)
+{
+ VisualStudioFolders.clear();
+
+ for (OrderedTargetDependSet::const_iterator tt = projectTargets.begin();
+ tt != projectTargets.end(); ++tt) {
+ cmGeneratorTarget const* target = *tt;
+ if (target->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ bool written = false;
+
+ // handle external vc project files
+ const char* expath = target->GetProperty("EXTERNAL_MSPROJECT");
+ if (expath) {
+ std::string project = target->GetName();
+ std::string location = expath;
+
+ this->WriteExternalProject(fout, project.c_str(), location.c_str(),
+ target->GetProperty("VS_PROJECT_TYPE"),
+ target->GetUtilities());
+ written = true;
+ } else {
+ const char* vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
+ if (vcprojName) {
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ std::string dir = lg->GetCurrentBinaryDirectory();
+ dir = root->Convert(dir.c_str(), cmOutputConverter::START_OUTPUT);
+ if (dir == ".") {
+ dir = ""; // msbuild cannot handle ".\" prefix
+ }
+ this->WriteProject(fout, vcprojName, dir.c_str(), target);
+ written = true;
+ }
+ }
+
+ // Create "solution folder" information from FOLDER target property
+ //
+ if (written && this->UseFolderProperty()) {
+ const char* targetFolder = target->GetProperty("FOLDER");
+ if (targetFolder) {
+ std::vector<cmsys::String> tokens =
+ cmSystemTools::SplitString(targetFolder, '/', false);
+
+ std::string cumulativePath = "";
+
+ for (std::vector<cmsys::String>::iterator iter = tokens.begin();
+ iter != tokens.end(); ++iter) {
+ if (!iter->size()) {
+ continue;
+ }
+
+ if (cumulativePath.empty()) {
+ cumulativePath = "CMAKE_FOLDER_GUID_" + *iter;
+ } else {
+ VisualStudioFolders[cumulativePath].insert(cumulativePath + "/" +
+ *iter);
+
+ cumulativePath = cumulativePath + "/" + *iter;
+ }
+ }
+
+ if (!cumulativePath.empty()) {
+ VisualStudioFolders[cumulativePath].insert(target->GetName());
+ }
+ }
+ }
+ }
+}
+
+void cmGlobalVisualStudio7Generator::WriteTargetDepends(
+ std::ostream& fout, OrderedTargetDependSet const& projectTargets)
+{
+ for (OrderedTargetDependSet::const_iterator tt = projectTargets.begin();
+ tt != projectTargets.end(); ++tt) {
+ cmGeneratorTarget const* target = *tt;
+ if (target->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ const char* vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
+ if (vcprojName) {
+ std::string dir =
+ target->GetLocalGenerator()->GetCurrentSourceDirectory();
+ this->WriteProjectDepends(fout, vcprojName, dir.c_str(), target);
+ }
+ }
+}
+
+void cmGlobalVisualStudio7Generator::WriteFolders(std::ostream& fout)
+{
+ const char* prefix = "CMAKE_FOLDER_GUID_";
+ const std::string::size_type skip_prefix = strlen(prefix);
+ std::string guidProjectTypeFolder = "2150E333-8FDC-42A3-9474-1A3956D46DE8";
+ for (std::map<std::string, std::set<std::string> >::iterator iter =
+ VisualStudioFolders.begin();
+ iter != VisualStudioFolders.end(); ++iter) {
+ std::string fullName = iter->first;
+ std::string guid = this->GetGUID(fullName.c_str());
+
+ std::replace(fullName.begin(), fullName.end(), '/', '\\');
+ if (cmSystemTools::StringStartsWith(fullName.c_str(), prefix)) {
+ fullName = fullName.substr(skip_prefix);
+ }
+
+ std::string nameOnly = cmSystemTools::GetFilenameName(fullName);
+
+ fout << "Project(\"{" << guidProjectTypeFolder << "}\") = \"" << nameOnly
+ << "\", \"" << fullName << "\", \"{" << guid << "}\"\nEndProject\n";
+ }
+}
+
+void cmGlobalVisualStudio7Generator::WriteFoldersContent(std::ostream& fout)
+{
+ for (std::map<std::string, std::set<std::string> >::iterator iter =
+ VisualStudioFolders.begin();
+ iter != VisualStudioFolders.end(); ++iter) {
+ std::string key(iter->first);
+ std::string guidParent(this->GetGUID(key.c_str()));
+
+ for (std::set<std::string>::iterator it = iter->second.begin();
+ it != iter->second.end(); ++it) {
+ std::string value(*it);
+ std::string guid(this->GetGUID(value.c_str()));
+
+ fout << "\t\t{" << guid << "} = {" << guidParent << "}\n";
+ }
+ }
+}
+
+std::string cmGlobalVisualStudio7Generator::ConvertToSolutionPath(
+ const char* path)
+{
+ // Convert to backslashes. Do not use ConvertToOutputPath because
+ // we will add quoting ourselves, and we know these projects always
+ // use windows slashes.
+ std::string d = path;
+ std::string::size_type pos = 0;
+ while ((pos = d.find('/', pos)) != d.npos) {
+ d[pos++] = '\\';
+ }
+ return d;
+}
+
+void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections(
+ std::ostream& fout, cmLocalGenerator* root)
+{
+ bool extensibilityGlobalsOverridden = false;
+ bool extensibilityAddInsOverridden = false;
+ const std::vector<std::string> propKeys =
+ root->GetMakefile()->GetPropertyKeys();
+ for (std::vector<std::string>::const_iterator it = propKeys.begin();
+ it != propKeys.end(); ++it) {
+ if (it->find("VS_GLOBAL_SECTION_") == 0) {
+ std::string sectionType;
+ std::string name = it->substr(18);
+ if (name.find("PRE_") == 0) {
+ name = name.substr(4);
+ sectionType = "preSolution";
+ } else if (name.find("POST_") == 0) {
+ name = name.substr(5);
+ sectionType = "postSolution";
+ } else
+ continue;
+ if (!name.empty()) {
+ if (name == "ExtensibilityGlobals" && sectionType == "postSolution")
+ extensibilityGlobalsOverridden = true;
+ else if (name == "ExtensibilityAddIns" &&
+ sectionType == "postSolution")
+ extensibilityAddInsOverridden = true;
+ fout << "\tGlobalSection(" << name << ") = " << sectionType << "\n";
+ std::vector<std::string> keyValuePairs;
+ cmSystemTools::ExpandListArgument(
+ root->GetMakefile()->GetProperty(it->c_str()), keyValuePairs);
+ for (std::vector<std::string>::const_iterator itPair =
+ keyValuePairs.begin();
+ itPair != keyValuePairs.end(); ++itPair) {
+ const std::string::size_type posEqual = itPair->find('=');
+ if (posEqual != std::string::npos) {
+ const std::string key =
+ cmSystemTools::TrimWhitespace(itPair->substr(0, posEqual));
+ const std::string value =
+ cmSystemTools::TrimWhitespace(itPair->substr(posEqual + 1));
+ fout << "\t\t" << key << " = " << value << "\n";
+ }
+ }
+ fout << "\tEndGlobalSection\n";
+ }
+ }
+ }
+ if (!extensibilityGlobalsOverridden)
+ fout << "\tGlobalSection(ExtensibilityGlobals) = postSolution\n"
+ << "\tEndGlobalSection\n";
+ if (!extensibilityAddInsOverridden)
+ fout << "\tGlobalSection(ExtensibilityAddIns) = postSolution\n"
+ << "\tEndGlobalSection\n";
+}
+
+// Standard end of dsw file
+void cmGlobalVisualStudio7Generator::WriteSLNFooter(std::ostream& fout)
+{
+ fout << "EndGlobal\n";
+}
+
+std::string cmGlobalVisualStudio7Generator::WriteUtilityDepend(
+ cmGeneratorTarget const* target)
+{
+ std::vector<std::string> configs;
+ target->Target->GetMakefile()->GetConfigurations(configs);
+ std::string pname = target->GetName();
+ pname += "_UTILITY";
+ std::string fname = target->GetLocalGenerator()->GetCurrentBinaryDirectory();
+ fname += "/";
+ fname += pname;
+ fname += ".vcproj";
+ cmGeneratedFileStream fout(fname.c_str());
+ fout.SetCopyIfDifferent(true);
+ std::string guid = this->GetGUID(pname.c_str());
+
+ /* clang-format off */
+ fout <<
+ "<?xml version=\"1.0\" encoding = \""
+ << this->Encoding() << "\"?>\n"
+ "<VisualStudioProject\n"
+ "\tProjectType=\"Visual C++\"\n"
+ "\tVersion=\"" << this->GetIDEVersion() << "0\"\n"
+ "\tName=\"" << pname << "\"\n"
+ "\tProjectGUID=\"{" << guid << "}\"\n"
+ "\tKeyword=\"Win32Proj\">\n"
+ "\t<Platforms><Platform Name=\"Win32\"/></Platforms>\n"
+ "\t<Configurations>\n"
+ ;
+ /* clang-format on */
+ for (std::vector<std::string>::iterator i = configs.begin();
+ i != configs.end(); ++i) {
+ /* clang-format off */
+ fout <<
+ "\t\t<Configuration\n"
+ "\t\t\tName=\"" << *i << "|Win32\"\n"
+ "\t\t\tOutputDirectory=\"" << *i << "\"\n"
+ "\t\t\tIntermediateDirectory=\"" << pname << ".dir\\" << *i << "\"\n"
+ "\t\t\tConfigurationType=\"10\"\n"
+ "\t\t\tUseOfMFC=\"0\"\n"
+ "\t\t\tATLMinimizesCRunTimeLibraryUsage=\"FALSE\"\n"
+ "\t\t\tCharacterSet=\"2\">\n"
+ "\t\t</Configuration>\n"
+ ;
+ /* clang-format on */
+ }
+ /* clang-format off */
+ fout <<
+ "\t</Configurations>\n"
+ "\t<Files></Files>\n"
+ "\t<Globals></Globals>\n"
+ "</VisualStudioProject>\n"
+ ;
+ /* clang-format on */
+
+ if (fout.Close()) {
+ this->FileReplacedDuringGenerate(fname);
+ }
+ return pname;
+}
+
+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())) {
+ return std::string(storedGUID);
+ }
+ // Compute a GUID that is deterministic but unique to the build tree.
+ std::string input = this->CMakeInstance->GetState()->GetBinaryDirectory();
+ input += "|";
+ input += name;
+
+ cmUuid uuidGenerator;
+
+ std::vector<unsigned char> uuidNamespace;
+ uuidGenerator.StringToBinary("ee30c4be-5192-4fb0-b335-722a2dffe760",
+ uuidNamespace);
+
+ std::string guid = uuidGenerator.FromMd5(uuidNamespace, input);
+
+ return cmSystemTools::UpperCase(guid);
+}
+
+void cmGlobalVisualStudio7Generator::AppendDirectoryForConfig(
+ const std::string& prefix, const std::string& config,
+ const std::string& suffix, std::string& dir)
+{
+ if (!config.empty()) {
+ dir += prefix;
+ dir += config;
+ dir += suffix;
+ }
+}
+
+std::set<std::string> cmGlobalVisualStudio7Generator::IsPartOfDefaultBuild(
+ std::vector<std::string> const& configs,
+ OrderedTargetDependSet const& projectTargets,
+ cmGeneratorTarget const* target)
+{
+ std::set<std::string> activeConfigs;
+ // if it is a utilitiy target then only make it part of the
+ // default build if another target depends on it
+ int type = target->GetType();
+ if (type == cmState::GLOBAL_TARGET) {
+ // check if INSTALL target is part of default build
+ if (target->GetName() == "INSTALL") {
+ // inspect CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD properties
+ for (std::vector<std::string>::const_iterator i = configs.begin();
+ i != configs.end(); ++i) {
+ const char* propertyValue =
+ target->Target->GetMakefile()->GetDefinition(
+ "CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD");
+ cmGeneratorExpression ge;
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge =
+ ge.Parse(propertyValue);
+ if (cmSystemTools::IsOn(
+ cge->Evaluate(target->GetLocalGenerator(), *i))) {
+ activeConfigs.insert(*i);
+ }
+ }
+ }
+ return activeConfigs;
+ }
+ if (type == cmState::UTILITY &&
+ !this->IsDependedOn(projectTargets, target)) {
+ return activeConfigs;
+ }
+ // inspect EXCLUDE_FROM_DEFAULT_BUILD[_<CONFIG>] properties
+ for (std::vector<std::string>::const_iterator i = configs.begin();
+ i != configs.end(); ++i) {
+ const char* propertyValue =
+ target->GetFeature("EXCLUDE_FROM_DEFAULT_BUILD", i->c_str());
+ if (cmSystemTools::IsOff(propertyValue)) {
+ activeConfigs.insert(*i);
+ }
+ }
+ return activeConfigs;
+}
+
+bool cmGlobalVisualStudio7Generator::IsDependedOn(
+ OrderedTargetDependSet const& projectTargets, cmGeneratorTarget const* gtIn)
+{
+ for (OrderedTargetDependSet::const_iterator l = projectTargets.begin();
+ l != projectTargets.end(); ++l) {
+ TargetDependSet const& tgtdeps = this->GetTargetDirectDepends(*l);
+ if (tgtdeps.count(gtIn)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::string cmGlobalVisualStudio7Generator::Encoding()
+{
+ std::ostringstream encoding;
+#ifdef CMAKE_ENCODING_UTF8
+ encoding << "UTF-8";
+#else
+ encoding << "Windows-1252";
+#endif
+ return encoding.str();
+}
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
new file mode 100644
index 0000000..2092343
--- /dev/null
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -0,0 +1,179 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalVisualStudio7Generator_h
+#define cmGlobalVisualStudio7Generator_h
+
+#include "cmGlobalVisualStudioGenerator.h"
+
+#include "cmGlobalGeneratorFactory.h"
+
+class cmTarget;
+struct cmIDEFlagTable;
+
+/** \class cmGlobalVisualStudio7Generator
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalVisualStudio7Generator manages UNIX build process for a tree
+ */
+class cmGlobalVisualStudio7Generator : public cmGlobalVisualStudioGenerator
+{
+public:
+ cmGlobalVisualStudio7Generator(cmake* cm,
+ const std::string& platformName = "");
+ ~cmGlobalVisualStudio7Generator();
+
+ ///! Get the name for the platform.
+ std::string const& GetPlatformName() const;
+
+ ///! Create a local generator appropriate to this Global Generator
+ virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf);
+
+ virtual bool SetSystemName(std::string const& s, cmMakefile* mf);
+
+ virtual bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf);
+
+ /**
+ * Utilized by the generator factory to determine if this generator
+ * supports toolsets.
+ */
+ static bool SupportsToolset() { return false; }
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+
+ /**
+ * Try running cmake and building a file. This is used for dynamically
+ * loaded commands, not as part of the usual build process.
+ */
+ virtual void GenerateBuildCommand(
+ std::vector<std::string>& makeCommand, const std::string& makeProgram,
+ const std::string& projectName, const std::string& projectDir,
+ const std::string& targetName, const std::string& config, bool fast,
+ bool verbose,
+ std::vector<std::string> const& makeOptions = std::vector<std::string>());
+
+ /**
+ * Generate the DSW workspace file.
+ */
+ virtual void OutputSLNFile();
+
+ ///! Lookup a stored GUID or compute one deterministically.
+ std::string GetGUID(std::string const& name);
+
+ /** Append the subdirectory for the given configuration. */
+ virtual void AppendDirectoryForConfig(const std::string& prefix,
+ const std::string& config,
+ const std::string& suffix,
+ std::string& dir);
+
+ ///! What is the configurations directory variable called?
+ virtual const char* GetCMakeCFGIntDir() const
+ {
+ return "$(ConfigurationName)";
+ }
+
+ /** Return true if the target project file should have the option
+ LinkLibraryDependencies and link to .sln dependencies. */
+ virtual bool NeedLinkLibraryDependencies(cmGeneratorTarget*)
+ {
+ return false;
+ }
+
+ const char* GetIntelProjectVersion();
+
+ virtual void FindMakeProgram(cmMakefile*);
+
+ /** Is the Microsoft Assembler enabled? */
+ bool IsMasmEnabled() const { return this->MasmEnabled; }
+
+ // Encoding for Visual Studio files
+ virtual std::string Encoding();
+
+ cmIDEFlagTable const* ExtraFlagTable;
+
+protected:
+ virtual void Generate();
+ virtual const char* GetIDEVersion() = 0;
+
+ std::string const& GetDevEnvCommand();
+ virtual std::string FindDevEnvCommand();
+
+ static const char* ExternalProjectType(const char* location);
+
+ virtual void OutputSLNFile(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators);
+ virtual void WriteSLNFile(std::ostream& fout, cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators) = 0;
+ virtual void WriteProject(std::ostream& fout, const std::string& name,
+ const char* path, const cmGeneratorTarget* t) = 0;
+ virtual void WriteProjectDepends(std::ostream& fout, const std::string& name,
+ const char* path,
+ cmGeneratorTarget const* t) = 0;
+ virtual void WriteProjectConfigurations(
+ std::ostream& fout, const std::string& name, cmState::TargetType type,
+ std::vector<std::string> const& configs,
+ const std::set<std::string>& configsPartOfDefaultBuild,
+ const std::string& platformMapping = "") = 0;
+ virtual void WriteSLNGlobalSections(std::ostream& fout,
+ cmLocalGenerator* root);
+ virtual void WriteSLNFooter(std::ostream& fout);
+ virtual void WriteSLNHeader(std::ostream& fout) = 0;
+ virtual std::string WriteUtilityDepend(const cmGeneratorTarget* target);
+
+ virtual void WriteTargetsToSolution(
+ std::ostream& fout, cmLocalGenerator* root,
+ OrderedTargetDependSet const& projectTargets);
+ virtual void WriteTargetDepends(
+ std::ostream& fout, OrderedTargetDependSet const& projectTargets);
+ virtual void WriteTargetConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs,
+ OrderedTargetDependSet const& projectTargets);
+
+ virtual void WriteExternalProject(
+ std::ostream& fout, const std::string& name, const char* path,
+ const char* typeGuid, const std::set<std::string>& dependencies) = 0;
+
+ std::string ConvertToSolutionPath(const char* path);
+
+ std::set<std::string> IsPartOfDefaultBuild(
+ std::vector<std::string> const& configs,
+ OrderedTargetDependSet const& projectTargets,
+ cmGeneratorTarget const* target);
+ bool IsDependedOn(OrderedTargetDependSet const& projectTargets,
+ cmGeneratorTarget const* target);
+ std::map<std::string, std::string> GUIDMap;
+
+ virtual void WriteFolders(std::ostream& fout);
+ virtual void WriteFoldersContent(std::ostream& fout);
+ std::map<std::string, std::set<std::string> > VisualStudioFolders;
+
+ // Set during OutputSLNFile with the name of the current project.
+ // There is one SLN file per project.
+ std::string CurrentProject;
+ std::string GeneratorPlatform;
+ std::string DefaultPlatformName;
+ bool MasmEnabled;
+
+private:
+ char* IntelProjectVersion;
+ std::string DevEnvCommand;
+ bool DevEnvCommandInitialized;
+ virtual std::string GetVSMakeProgram() { return this->GetDevEnvCommand(); }
+};
+
+#define CMAKE_CHECK_BUILD_SYSTEM_TARGET "ZERO_CHECK"
+
+#endif
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
new file mode 100644
index 0000000..dfe196a
--- /dev/null
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -0,0 +1,478 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "windows.h" // this must be first to define GetCurrentDirectory
+
+#include "cmGlobalVisualStudio8Generator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmLocalVisualStudio7Generator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmVisualStudioWCEPlatformParser.h"
+#include "cmake.h"
+
+static const char vs8generatorName[] = "Visual Studio 8 2005";
+
+class cmGlobalVisualStudio8Generator::Factory : public cmGlobalGeneratorFactory
+{
+public:
+ virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
+ cmake* cm) const
+ {
+ if (strncmp(name.c_str(), vs8generatorName,
+ sizeof(vs8generatorName) - 1) != 0) {
+ return 0;
+ }
+
+ const char* p = name.c_str() + sizeof(vs8generatorName) - 1;
+ if (p[0] == '\0') {
+ return new cmGlobalVisualStudio8Generator(cm, name, "");
+ }
+
+ if (p[0] != ' ') {
+ return 0;
+ }
+
+ ++p;
+
+ if (!strcmp(p, "Win64")) {
+ return new cmGlobalVisualStudio8Generator(cm, name, "x64");
+ }
+
+ cmVisualStudioWCEPlatformParser parser(p);
+ parser.ParseVersion("8.0");
+ if (!parser.Found()) {
+ return 0;
+ }
+
+ cmGlobalVisualStudio8Generator* ret =
+ new cmGlobalVisualStudio8Generator(cm, name, p);
+ ret->WindowsCEVersion = parser.GetOSVersion();
+ return ret;
+ }
+
+ virtual void GetDocumentation(cmDocumentationEntry& entry) const
+ {
+ entry.Name = std::string(vs8generatorName) + " [arch]";
+ entry.Brief = "Generates Visual Studio 2005 project files. "
+ "Optional [arch] can be \"Win64\".";
+ }
+
+ virtual void GetGenerators(std::vector<std::string>& names) const
+ {
+ names.push_back(vs8generatorName);
+ names.push_back(vs8generatorName + std::string(" Win64"));
+ cmVisualStudioWCEPlatformParser parser;
+ parser.ParseVersion("8.0");
+ const std::vector<std::string>& availablePlatforms =
+ parser.GetAvailablePlatforms();
+ for (std::vector<std::string>::const_iterator i =
+ availablePlatforms.begin();
+ i != availablePlatforms.end(); ++i) {
+ names.push_back("Visual Studio 8 2005 " + *i);
+ }
+ }
+
+ virtual bool SupportsToolset() const { return false; }
+};
+
+cmGlobalGeneratorFactory* cmGlobalVisualStudio8Generator::NewFactory()
+{
+ return new Factory;
+}
+
+cmGlobalVisualStudio8Generator::cmGlobalVisualStudio8Generator(
+ cmake* cm, const std::string& name, const std::string& platformName)
+ : cmGlobalVisualStudio71Generator(cm, platformName)
+{
+ this->ProjectConfigurationSectionName = "ProjectConfigurationPlatforms";
+ this->Name = name;
+ this->ExtraFlagTable = this->GetExtraFlagTableVS8();
+ this->Version = VS8;
+ std::string vc8Express;
+ this->ExpressEdition = cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\8.0\\Setup\\VC;"
+ "ProductDir",
+ vc8Express, cmSystemTools::KeyWOW64_32);
+}
+
+std::string cmGlobalVisualStudio8Generator::FindDevEnvCommand()
+{
+ // First look for VCExpress.
+ std::string vsxcmd;
+ std::string vsxkey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\";
+ vsxkey += this->GetIDEVersion();
+ vsxkey += ";InstallDir";
+ if (cmSystemTools::ReadRegistryValue(vsxkey.c_str(), vsxcmd,
+ cmSystemTools::KeyWOW64_32)) {
+ cmSystemTools::ConvertToUnixSlashes(vsxcmd);
+ vsxcmd += "/VCExpress.exe";
+ return vsxcmd;
+ }
+ // Now look for devenv.
+ return this->cmGlobalVisualStudio71Generator::FindDevEnvCommand();
+}
+
+void cmGlobalVisualStudio8Generator::EnableLanguage(
+ std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
+{
+ for (std::vector<std::string>::const_iterator it = lang.begin();
+ it != lang.end(); ++it) {
+ if (*it == "ASM_MASM") {
+ this->MasmEnabled = true;
+ }
+ }
+ this->AddPlatformDefinitions(mf);
+ cmGlobalVisualStudio7Generator::EnableLanguage(lang, mf, optional);
+}
+
+void cmGlobalVisualStudio8Generator::AddPlatformDefinitions(cmMakefile* mf)
+{
+ if (this->TargetsWindowsCE()) {
+ mf->AddDefinition("CMAKE_VS_WINCE_VERSION",
+ this->WindowsCEVersion.c_str());
+ }
+}
+
+bool cmGlobalVisualStudio8Generator::SetGeneratorPlatform(std::string const& p,
+ cmMakefile* mf)
+{
+ if (this->DefaultPlatformName == "Win32") {
+ this->GeneratorPlatform = p;
+ return this->cmGlobalVisualStudio7Generator::SetGeneratorPlatform("", mf);
+ } else {
+ return this->cmGlobalVisualStudio7Generator::SetGeneratorPlatform(p, mf);
+ }
+}
+
+// ouput standard header for dsw file
+void cmGlobalVisualStudio8Generator::WriteSLNHeader(std::ostream& fout)
+{
+ fout << "Microsoft Visual Studio Solution File, Format Version 9.00\n";
+ fout << "# Visual Studio 2005\n";
+}
+
+void cmGlobalVisualStudio8Generator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalVisualStudio8Generator::GetActualName();
+ entry.Brief = "Generates Visual Studio 8 2005 project files.";
+}
+
+void cmGlobalVisualStudio8Generator::Configure()
+{
+ this->cmGlobalVisualStudio7Generator::Configure();
+}
+
+bool cmGlobalVisualStudio8Generator::UseFolderProperty()
+{
+ return IsExpressEdition() ? false : cmGlobalGenerator::UseFolderProperty();
+}
+
+std::string cmGlobalVisualStudio8Generator::GetUserMacrosDirectory()
+{
+ // Some VS8 sp0 versions cannot run macros.
+ // See http://support.microsoft.com/kb/928209
+ const char* vc8sp1Registry =
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\"
+ "InstalledProducts\\KB926601;";
+ const char* vc8exSP1Registry =
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\"
+ "InstalledProducts\\KB926748;";
+ std::string vc8sp1;
+ if (!cmSystemTools::ReadRegistryValue(vc8sp1Registry, vc8sp1) &&
+ !cmSystemTools::ReadRegistryValue(vc8exSP1Registry, vc8sp1)) {
+ return "";
+ }
+
+ std::string base;
+ std::string path;
+
+ // base begins with the VisualStudioProjectsLocation reg value...
+ if (cmSystemTools::ReadRegistryValue(
+ "HKEY_CURRENT_USER\\Software\\Microsoft\\VisualStudio\\8.0;"
+ "VisualStudioProjectsLocation",
+ base)) {
+ cmSystemTools::ConvertToUnixSlashes(base);
+
+ // 8.0 macros folder:
+ path = base + "/VSMacros80";
+ }
+
+ // path is (correctly) still empty if we did not read the base value from
+ // the Registry value
+ return path;
+}
+
+std::string cmGlobalVisualStudio8Generator::GetUserMacrosRegKeyBase()
+{
+ return "Software\\Microsoft\\VisualStudio\\8.0\\vsmacros";
+}
+
+bool cmGlobalVisualStudio8Generator::AddCheckTarget()
+{
+ // Add a special target on which all other targets depend that
+ // checks the build system and optionally re-runs CMake.
+ const char* no_working_directory = 0;
+ std::vector<std::string> no_depends;
+ std::vector<cmLocalGenerator*> const& generators = this->LocalGenerators;
+ cmLocalVisualStudio7Generator* lg =
+ static_cast<cmLocalVisualStudio7Generator*>(generators[0]);
+ cmMakefile* mf = lg->GetMakefile();
+
+ // Skip the target if no regeneration is to be done.
+ if (mf->IsOn("CMAKE_SUPPRESS_REGENERATION")) {
+ return false;
+ }
+
+ cmCustomCommandLines noCommandLines;
+ cmTarget* tgt =
+ mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false,
+ no_working_directory, no_depends, noCommandLines);
+
+ cmGeneratorTarget* gt = new cmGeneratorTarget(tgt, lg);
+ lg->AddGeneratorTarget(gt);
+
+ // Organize in the "predefined targets" folder:
+ //
+ if (this->UseFolderProperty()) {
+ tgt->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
+ }
+
+ // Create a list of all stamp files for this project.
+ std::vector<std::string> stamps;
+ std::string stampList = cmake::GetCMakeFilesDirectoryPostSlash();
+ stampList += "generate.stamp.list";
+ {
+ std::string stampListFile =
+ generators[0]->GetMakefile()->GetCurrentBinaryDirectory();
+ stampListFile += "/";
+ stampListFile += stampList;
+ std::string stampFile;
+ cmGeneratedFileStream fout(stampListFile.c_str());
+ for (std::vector<cmLocalGenerator*>::const_iterator gi =
+ generators.begin();
+ gi != generators.end(); ++gi) {
+ stampFile = (*gi)->GetMakefile()->GetCurrentBinaryDirectory();
+ stampFile += "/";
+ stampFile += cmake::GetCMakeFilesDirectoryPostSlash();
+ stampFile += "generate.stamp";
+ fout << stampFile << "\n";
+ stamps.push_back(stampFile);
+ }
+ }
+
+ // Add a custom rule to re-run CMake if any input files changed.
+ {
+ // 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());
+ }
+ // Sort the list of input files and remove duplicates.
+ std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>());
+ std::vector<std::string>::iterator new_end =
+ std::unique(listFiles.begin(), listFiles.end());
+ listFiles.erase(new_end, listFiles.end());
+
+ // Create a rule to re-run CMake.
+ std::string stampName = cmake::GetCMakeFilesDirectoryPostSlash();
+ stampName += "generate.stamp";
+ cmCustomCommandLine commandLine;
+ commandLine.push_back(cmSystemTools::GetCMakeCommand());
+ std::string argH = "-H";
+ argH += lg->GetSourceDirectory();
+ commandLine.push_back(argH);
+ std::string argB = "-B";
+ argB += lg->GetBinaryDirectory();
+ commandLine.push_back(argB);
+ commandLine.push_back("--check-stamp-list");
+ commandLine.push_back(stampList.c_str());
+ commandLine.push_back("--vs-solution-file");
+ commandLine.push_back("\"$(SolutionPath)\"");
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(commandLine);
+
+ // Add the rule. Note that we cannot use the CMakeLists.txt
+ // file as the main dependency because it would get
+ // overwritten by the CreateVCProjBuildRule.
+ // (this could be avoided with per-target source files)
+ std::string no_main_dependency = "";
+ std::vector<std::string> no_byproducts;
+ if (cmSourceFile* file = mf->AddCustomCommandToOutput(
+ stamps, no_byproducts, listFiles, no_main_dependency, commandLines,
+ "Checking Build System", no_working_directory, true)) {
+ gt->AddSource(file->GetFullPath());
+ } else {
+ cmSystemTools::Error("Error adding rule for ", stamps[0].c_str());
+ }
+ }
+
+ return true;
+}
+
+void cmGlobalVisualStudio8Generator::AddExtraIDETargets()
+{
+ cmGlobalVisualStudio7Generator::AddExtraIDETargets();
+ if (this->AddCheckTarget()) {
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ std::vector<cmGeneratorTarget*> tgts =
+ this->LocalGenerators[i]->GetGeneratorTargets();
+ // All targets depend on the build-system check target.
+ for (std::vector<cmGeneratorTarget*>::iterator ti = tgts.begin();
+ ti != tgts.end(); ++ti) {
+ if ((*ti)->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
+ (*ti)->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET);
+ }
+ }
+ }
+ }
+}
+
+void cmGlobalVisualStudio8Generator::WriteSolutionConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs)
+{
+ fout << "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n";
+ for (std::vector<std::string>::const_iterator i = configs.begin();
+ i != configs.end(); ++i) {
+ fout << "\t\t" << *i << "|" << this->GetPlatformName() << " = " << *i
+ << "|" << this->GetPlatformName() << "\n";
+ }
+ fout << "\tEndGlobalSection\n";
+}
+
+void cmGlobalVisualStudio8Generator::WriteProjectConfigurations(
+ std::ostream& fout, const std::string& name, cmState::TargetType type,
+ std::vector<std::string> const& configs,
+ const std::set<std::string>& configsPartOfDefaultBuild,
+ std::string const& platformMapping)
+{
+ std::string guid = this->GetGUID(name);
+ for (std::vector<std::string>::const_iterator i = configs.begin();
+ i != configs.end(); ++i) {
+ fout << "\t\t{" << guid << "}." << *i << "|" << this->GetPlatformName()
+ << ".ActiveCfg = " << *i << "|"
+ << (!platformMapping.empty() ? platformMapping
+ : this->GetPlatformName())
+ << "\n";
+ std::set<std::string>::const_iterator ci =
+ configsPartOfDefaultBuild.find(*i);
+ if (!(ci == configsPartOfDefaultBuild.end())) {
+ fout << "\t\t{" << guid << "}." << *i << "|" << this->GetPlatformName()
+ << ".Build.0 = " << *i << "|"
+ << (!platformMapping.empty() ? platformMapping
+ : this->GetPlatformName())
+ << "\n";
+ }
+ if (this->NeedsDeploy(type)) {
+ fout << "\t\t{" << guid << "}." << *i << "|" << this->GetPlatformName()
+ << ".Deploy.0 = " << *i << "|"
+ << (!platformMapping.empty() ? platformMapping
+ : this->GetPlatformName())
+ << "\n";
+ }
+ }
+}
+
+bool cmGlobalVisualStudio8Generator::NeedsDeploy(
+ cmState::TargetType type) const
+{
+ bool needsDeploy =
+ (type == cmState::EXECUTABLE || type == cmState::SHARED_LIBRARY);
+ return this->TargetsWindowsCE() && needsDeploy;
+}
+
+bool cmGlobalVisualStudio8Generator::ComputeTargetDepends()
+{
+ // Skip over the cmGlobalVisualStudioGenerator implementation!
+ // We do not need the support that VS <= 7.1 needs.
+ return this->cmGlobalGenerator::ComputeTargetDepends();
+}
+
+void cmGlobalVisualStudio8Generator::WriteProjectDepends(
+ std::ostream& fout, const std::string&, const char*,
+ cmGeneratorTarget const* gt)
+{
+ TargetDependSet const& unordered = this->GetTargetDirectDepends(gt);
+ OrderedTargetDependSet depends(unordered, std::string());
+ for (OrderedTargetDependSet::const_iterator i = depends.begin();
+ i != depends.end(); ++i) {
+ if ((*i)->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ std::string guid = this->GetGUID((*i)->GetName().c_str());
+ fout << "\t\t{" << guid << "} = {" << guid << "}\n";
+ }
+}
+
+bool cmGlobalVisualStudio8Generator::NeedLinkLibraryDependencies(
+ cmGeneratorTarget* target)
+{
+ // Look for utility dependencies that magically link.
+ for (std::set<std::string>::const_iterator ui =
+ target->GetUtilities().begin();
+ ui != target->GetUtilities().end(); ++ui) {
+ if (cmGeneratorTarget* depTarget =
+ target->GetLocalGenerator()->FindGeneratorTargetToUse(ui->c_str())) {
+ if (depTarget->GetType() != cmState::INTERFACE_LIBRARY &&
+ depTarget->GetProperty("EXTERNAL_MSPROJECT")) {
+ // This utility dependency names an external .vcproj target.
+ // We use LinkLibraryDependencies="true" to link to it without
+ // predicting the .lib file location or name.
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static cmVS7FlagTable cmVS8ExtraFlagTable[] = {
+ { "CallingConvention", "Gd", "cdecl", "0", 0 },
+ { "CallingConvention", "Gr", "fastcall", "1", 0 },
+ { "CallingConvention", "Gz", "stdcall", "2", 0 },
+
+ { "Detect64BitPortabilityProblems", "Wp64",
+ "Detect 64Bit Portability Problems", "true", 0 },
+ { "ErrorReporting", "errorReport:prompt", "Report immediately", "1", 0 },
+ { "ErrorReporting", "errorReport:queue", "Queue for next login", "2", 0 },
+ // Precompiled header and related options. Note that the
+ // UsePrecompiledHeader entries are marked as "Continue" so that the
+ // corresponding PrecompiledHeaderThrough entry can be found.
+ { "UsePrecompiledHeader", "Yu", "Use Precompiled Header", "2",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeaderThrough", "Yu", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ // There is no YX option in the VS8 IDE.
+
+ // Exception handling mode. If no entries match, it will be FALSE.
+ { "ExceptionHandling", "GX", "enable c++ exceptions", "1", 0 },
+ { "ExceptionHandling", "EHsc", "enable c++ exceptions", "1", 0 },
+ { "ExceptionHandling", "EHa", "enable SEH exceptions", "2", 0 },
+
+ { "EnablePREfast", "analyze", "", "true", 0 },
+ { "EnablePREfast", "analyze-", "", "false", 0 },
+
+ // Language options
+ { "TreatWChar_tAsBuiltInType", "Zc:wchar_t", "wchar_t is a built-in type",
+ "true", 0 },
+ { "TreatWChar_tAsBuiltInType", "Zc:wchar_t-",
+ "wchar_t is not a built-in type", "false", 0 },
+
+ { 0, 0, 0, 0, 0 }
+};
+cmIDEFlagTable const* cmGlobalVisualStudio8Generator::GetExtraFlagTableVS8()
+{
+ return cmVS8ExtraFlagTable;
+}
diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h
new file mode 100644
index 0000000..b29106f
--- /dev/null
+++ b/Source/cmGlobalVisualStudio8Generator.h
@@ -0,0 +1,110 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalVisualStudio8Generator_h
+#define cmGlobalVisualStudio8Generator_h
+
+#include "cmGlobalVisualStudio71Generator.h"
+
+/** \class cmGlobalVisualStudio8Generator
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalVisualStudio8Generator manages UNIX build process for a tree
+ */
+class cmGlobalVisualStudio8Generator : public cmGlobalVisualStudio71Generator
+{
+public:
+ cmGlobalVisualStudio8Generator(cmake* cm, const std::string& name,
+ const std::string& platformName);
+ static cmGlobalGeneratorFactory* NewFactory();
+
+ ///! Get the name for the generator.
+ virtual std::string GetName() const { return this->Name; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+ virtual void AddPlatformDefinitions(cmMakefile* mf);
+
+ virtual bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf);
+
+ /**
+ * Override Configure and Generate to add the build-system check
+ * target.
+ */
+ virtual void Configure();
+
+ /**
+ * Where does this version of Visual Studio look for macros for the
+ * current user? Returns the empty string if this version of Visual
+ * Studio does not implement support for VB macros.
+ */
+ virtual std::string GetUserMacrosDirectory();
+
+ /**
+ * What is the reg key path to "vsmacros" for this version of Visual
+ * Studio?
+ */
+ virtual std::string GetUserMacrosRegKeyBase();
+
+ /** Return true if the target project file should have the option
+ LinkLibraryDependencies and link to .sln dependencies. */
+ virtual bool NeedLinkLibraryDependencies(cmGeneratorTarget* target);
+
+ /** Return true if building for Windows CE */
+ virtual bool TargetsWindowsCE() const
+ {
+ return !this->WindowsCEVersion.empty();
+ }
+
+ /** Is the installed VS an Express edition? */
+ bool IsExpressEdition() const { return this->ExpressEdition; }
+
+protected:
+ virtual void AddExtraIDETargets();
+ virtual const char* GetIDEVersion() { return "8.0"; }
+
+ virtual std::string FindDevEnvCommand();
+
+ virtual bool VSLinksDependencies() const { return false; }
+
+ bool AddCheckTarget();
+
+ /** Return true if the configuration needs to be deployed */
+ virtual bool NeedsDeploy(cmState::TargetType type) const;
+
+ static cmIDEFlagTable const* GetExtraFlagTableVS8();
+ virtual void WriteSLNHeader(std::ostream& fout);
+ virtual void WriteSolutionConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs);
+ virtual void WriteProjectConfigurations(
+ std::ostream& fout, const std::string& name, cmState::TargetType type,
+ std::vector<std::string> const& configs,
+ const std::set<std::string>& configsPartOfDefaultBuild,
+ const std::string& platformMapping = "");
+ virtual bool ComputeTargetDepends();
+ virtual void WriteProjectDepends(std::ostream& fout, const std::string& name,
+ const char* path,
+ const cmGeneratorTarget* t);
+
+ bool UseFolderProperty();
+
+ std::string Name;
+ std::string WindowsCEVersion;
+ bool ExpressEdition;
+
+private:
+ class Factory;
+ friend class Factory;
+};
+#endif
diff --git a/Source/cmGlobalVisualStudio9Generator.cxx b/Source/cmGlobalVisualStudio9Generator.cxx
new file mode 100644
index 0000000..a47f4fc
--- /dev/null
+++ b/Source/cmGlobalVisualStudio9Generator.cxx
@@ -0,0 +1,142 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "windows.h" // this must be first to define GetCurrentDirectory
+
+#include "cmGlobalVisualStudio9Generator.h"
+
+#include "cmLocalVisualStudio7Generator.h"
+#include "cmMakefile.h"
+#include "cmVisualStudioWCEPlatformParser.h"
+#include "cmake.h"
+
+static const char vs9generatorName[] = "Visual Studio 9 2008";
+
+class cmGlobalVisualStudio9Generator::Factory : public cmGlobalGeneratorFactory
+{
+public:
+ virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
+ cmake* cm) const
+ {
+ if (strncmp(name.c_str(), vs9generatorName,
+ sizeof(vs9generatorName) - 1) != 0) {
+ return 0;
+ }
+
+ const char* p = name.c_str() + sizeof(vs9generatorName) - 1;
+ if (p[0] == '\0') {
+ return new cmGlobalVisualStudio9Generator(cm, name, "");
+ }
+
+ if (p[0] != ' ') {
+ return 0;
+ }
+
+ ++p;
+
+ if (!strcmp(p, "IA64")) {
+ return new cmGlobalVisualStudio9Generator(cm, name, "Itanium");
+ }
+
+ if (!strcmp(p, "Win64")) {
+ return new cmGlobalVisualStudio9Generator(cm, name, "x64");
+ }
+
+ cmVisualStudioWCEPlatformParser parser(p);
+ parser.ParseVersion("9.0");
+ if (!parser.Found()) {
+ return 0;
+ }
+
+ cmGlobalVisualStudio9Generator* ret =
+ new cmGlobalVisualStudio9Generator(cm, name, p);
+ ret->WindowsCEVersion = parser.GetOSVersion();
+ return ret;
+ }
+
+ virtual void GetDocumentation(cmDocumentationEntry& entry) const
+ {
+ entry.Name = std::string(vs9generatorName) + " [arch]";
+ entry.Brief = "Generates Visual Studio 2008 project files. "
+ "Optional [arch] can be \"Win64\" or \"IA64\".";
+ }
+
+ virtual void GetGenerators(std::vector<std::string>& names) const
+ {
+ names.push_back(vs9generatorName);
+ names.push_back(vs9generatorName + std::string(" Win64"));
+ names.push_back(vs9generatorName + std::string(" IA64"));
+ cmVisualStudioWCEPlatformParser parser;
+ parser.ParseVersion("9.0");
+ const std::vector<std::string>& availablePlatforms =
+ parser.GetAvailablePlatforms();
+ for (std::vector<std::string>::const_iterator i =
+ availablePlatforms.begin();
+ i != availablePlatforms.end(); ++i) {
+ names.push_back("Visual Studio 9 2008 " + *i);
+ }
+ }
+
+ virtual bool SupportsToolset() const { return false; }
+};
+
+cmGlobalGeneratorFactory* cmGlobalVisualStudio9Generator::NewFactory()
+{
+ return new Factory;
+}
+
+cmGlobalVisualStudio9Generator::cmGlobalVisualStudio9Generator(
+ cmake* cm, const std::string& name, const std::string& platformName)
+ : cmGlobalVisualStudio8Generator(cm, name, platformName)
+{
+ this->Version = VS9;
+ std::string vc9Express;
+ this->ExpressEdition = cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\9.0\\Setup\\VC;"
+ "ProductDir",
+ vc9Express, cmSystemTools::KeyWOW64_32);
+}
+
+void cmGlobalVisualStudio9Generator::WriteSLNHeader(std::ostream& fout)
+{
+ fout << "Microsoft Visual Studio Solution File, Format Version 10.00\n";
+ fout << "# Visual Studio 2008\n";
+}
+
+std::string cmGlobalVisualStudio9Generator::GetUserMacrosDirectory()
+{
+ std::string base;
+ std::string path;
+
+ // base begins with the VisualStudioProjectsLocation reg value...
+ if (cmSystemTools::ReadRegistryValue(
+ "HKEY_CURRENT_USER\\Software\\Microsoft\\VisualStudio\\9.0;"
+ "VisualStudioProjectsLocation",
+ base)) {
+ cmSystemTools::ConvertToUnixSlashes(base);
+
+ // 9.0 macros folder:
+ path = base + "/VSMacros80";
+ // *NOT* a typo; right now in Visual Studio 2008 beta the macros
+ // folder is VSMacros80... They may change it to 90 before final
+ // release of 2008 or they may not... we'll have to keep our eyes
+ // on it
+ }
+
+ // path is (correctly) still empty if we did not read the base value from
+ // the Registry value
+ return path;
+}
+
+std::string cmGlobalVisualStudio9Generator::GetUserMacrosRegKeyBase()
+{
+ return "Software\\Microsoft\\VisualStudio\\9.0\\vsmacros";
+}
diff --git a/Source/cmGlobalVisualStudio9Generator.h b/Source/cmGlobalVisualStudio9Generator.h
new file mode 100644
index 0000000..2c82c3a
--- /dev/null
+++ b/Source/cmGlobalVisualStudio9Generator.h
@@ -0,0 +1,54 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalVisualStudio9Generator_h
+#define cmGlobalVisualStudio9Generator_h
+
+#include "cmGlobalVisualStudio8Generator.h"
+
+/** \class cmGlobalVisualStudio9Generator
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalVisualStudio9Generator manages UNIX build process for a tree
+ */
+class cmGlobalVisualStudio9Generator : public cmGlobalVisualStudio8Generator
+{
+public:
+ cmGlobalVisualStudio9Generator(cmake* cm, const std::string& name,
+ const std::string& platformName);
+ static cmGlobalGeneratorFactory* NewFactory();
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void WriteSLNHeader(std::ostream& fout);
+
+ /**
+ * Where does this version of Visual Studio look for macros for the
+ * current user? Returns the empty string if this version of Visual
+ * Studio does not implement support for VB macros.
+ */
+ virtual std::string GetUserMacrosDirectory();
+
+ /**
+ * What is the reg key path to "vsmacros" for this version of Visual
+ * Studio?
+ */
+ virtual std::string GetUserMacrosRegKeyBase();
+
+protected:
+ virtual const char* GetIDEVersion() { return "9.0"; }
+private:
+ class Factory;
+ friend class Factory;
+};
+#endif
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
new file mode 100644
index 0000000..1bec581
--- /dev/null
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -0,0 +1,851 @@
+
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalVisualStudioGenerator.h"
+
+#include "cmAlgorithms.h"
+#include "cmCallVisualStudioMacro.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalVisualStudioGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmTarget.h"
+#include <cmsys/Encoding.hxx>
+
+cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator(cmake* cm)
+ : cmGlobalGenerator(cm)
+{
+ cm->GetState()->SetWindowsShell(true);
+ cm->GetState()->SetWindowsVSIDE(true);
+}
+
+cmGlobalVisualStudioGenerator::~cmGlobalVisualStudioGenerator()
+{
+}
+
+cmGlobalVisualStudioGenerator::VSVersion
+cmGlobalVisualStudioGenerator::GetVersion() const
+{
+ return this->Version;
+}
+
+void cmGlobalVisualStudioGenerator::SetVersion(VSVersion v)
+{
+ this->Version = v;
+}
+
+std::string cmGlobalVisualStudioGenerator::GetRegistryBase()
+{
+ return cmGlobalVisualStudioGenerator::GetRegistryBase(this->GetIDEVersion());
+}
+
+std::string cmGlobalVisualStudioGenerator::GetRegistryBase(const char* version)
+{
+ std::string key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\";
+ return key + version;
+}
+
+void cmGlobalVisualStudioGenerator::AddExtraIDETargets()
+{
+ // Add a special target that depends on ALL projects for easy build
+ // of one configuration only.
+ const char* no_working_dir = 0;
+ std::vector<std::string> no_depends;
+ cmCustomCommandLines no_commands;
+ std::map<std::string, std::vector<cmLocalGenerator*> >::iterator it;
+ for (it = this->ProjectMap.begin(); it != this->ProjectMap.end(); ++it) {
+ std::vector<cmLocalGenerator*>& gen = it->second;
+ // add the ALL_BUILD to the first local generator of each project
+ if (!gen.empty()) {
+ // Use no actual command lines so that the target itself is not
+ // considered always out of date.
+ cmTarget* allBuild = gen[0]->GetMakefile()->AddUtilityCommand(
+ "ALL_BUILD", true, no_working_dir, no_depends, no_commands, false,
+ "Build all projects");
+
+ cmGeneratorTarget* gt = new cmGeneratorTarget(allBuild, gen[0]);
+ gen[0]->AddGeneratorTarget(gt);
+
+ //
+ // Organize in the "predefined targets" folder:
+ //
+ if (this->UseFolderProperty()) {
+ allBuild->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
+ }
+
+ // Now make all targets depend on the ALL_BUILD target
+ for (std::vector<cmLocalGenerator*>::iterator i = gen.begin();
+ i != gen.end(); ++i) {
+ std::vector<cmGeneratorTarget*> targets = (*i)->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
+ t != targets.end(); ++t) {
+ cmGeneratorTarget* tgt = *t;
+ if (tgt->GetType() == cmState::GLOBAL_TARGET || tgt->IsImported()) {
+ continue;
+ }
+ if (!this->IsExcluded(gen[0], tgt)) {
+ allBuild->AddUtility(tgt->GetName());
+ }
+ }
+ }
+ }
+ }
+
+ // Configure CMake Visual Studio macros, for this user on this version
+ // of Visual Studio.
+ this->ConfigureCMakeVisualStudioMacros();
+
+ // Add CMakeLists.txt with custom command to rerun CMake.
+ for (std::vector<cmLocalGenerator*>::const_iterator lgi =
+ this->LocalGenerators.begin();
+ lgi != this->LocalGenerators.end(); ++lgi) {
+ cmLocalVisualStudioGenerator* lg =
+ static_cast<cmLocalVisualStudioGenerator*>(*lgi);
+ lg->AddCMakeListsRules();
+ }
+}
+
+void cmGlobalVisualStudioGenerator::ComputeTargetObjectDirectory(
+ cmGeneratorTarget* gt) const
+{
+ std::string dir = gt->LocalGenerator->GetCurrentBinaryDirectory();
+ dir += "/";
+ std::string tgtDir = gt->LocalGenerator->GetTargetDirectory(gt);
+ if (!tgtDir.empty()) {
+ dir += tgtDir;
+ dir += "/";
+ }
+ const char* cd = this->GetCMakeCFGIntDir();
+ if (cd && *cd) {
+ dir += cd;
+ dir += "/";
+ }
+ gt->ObjectDirectory = dir;
+}
+
+bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
+ const std::string& regKeyBase,
+ std::string& nextAvailableSubKeyName);
+
+void RegisterVisualStudioMacros(const std::string& macrosFile,
+ const std::string& regKeyBase);
+
+#define CMAKE_VSMACROS_FILENAME "CMakeVSMacros2.vsmacros"
+
+#define CMAKE_VSMACROS_RELOAD_MACRONAME \
+ "Macros.CMakeVSMacros2.Macros.ReloadProjects"
+
+#define CMAKE_VSMACROS_STOP_MACRONAME "Macros.CMakeVSMacros2.Macros.StopBuild"
+
+void cmGlobalVisualStudioGenerator::ConfigureCMakeVisualStudioMacros()
+{
+ std::string dir = this->GetUserMacrosDirectory();
+
+ if (dir != "") {
+ std::string src = cmSystemTools::GetCMakeRoot();
+ src += "/Templates/" CMAKE_VSMACROS_FILENAME;
+
+ std::string dst = dir + "/CMakeMacros/" CMAKE_VSMACROS_FILENAME;
+
+ // Copy the macros file to the user directory only if the
+ // destination does not exist or the source location is newer.
+ // This will allow the user to edit the macros for development
+ // purposes but newer versions distributed with CMake will replace
+ // older versions in user directories.
+ int res;
+ if (!cmSystemTools::FileTimeCompare(src.c_str(), dst.c_str(), &res) ||
+ res > 0) {
+ if (!cmSystemTools::CopyFileAlways(src.c_str(), dst.c_str())) {
+ std::ostringstream oss;
+ oss << "Could not copy from: " << src << std::endl;
+ oss << " to: " << dst << std::endl;
+ cmSystemTools::Message(oss.str().c_str(), "Warning");
+ }
+ }
+
+ RegisterVisualStudioMacros(dst, this->GetUserMacrosRegKeyBase());
+ }
+}
+
+void cmGlobalVisualStudioGenerator::CallVisualStudioMacro(
+ MacroName m, const char* vsSolutionFile)
+{
+ // If any solution or project files changed during the generation,
+ // tell Visual Studio to reload them...
+ cmMakefile* mf = this->LocalGenerators[0]->GetMakefile();
+ std::string dir = this->GetUserMacrosDirectory();
+
+ // Only really try to call the macro if:
+ // - there is a UserMacrosDirectory
+ // - the CMake vsmacros file exists
+ // - the CMake vsmacros file is registered
+ // - there were .sln/.vcproj files changed during generation
+ //
+ if (dir != "") {
+ std::string macrosFile = dir + "/CMakeMacros/" CMAKE_VSMACROS_FILENAME;
+ std::string nextSubkeyName;
+ if (cmSystemTools::FileExists(macrosFile.c_str()) &&
+ IsVisualStudioMacrosFileRegistered(
+ macrosFile, this->GetUserMacrosRegKeyBase(), nextSubkeyName)) {
+ std::string topLevelSlnName;
+ if (vsSolutionFile) {
+ topLevelSlnName = vsSolutionFile;
+ } else {
+ topLevelSlnName = mf->GetCurrentBinaryDirectory();
+ topLevelSlnName += "/";
+ topLevelSlnName += this->LocalGenerators[0]->GetProjectName();
+ topLevelSlnName += ".sln";
+ }
+
+ if (m == MacroReload) {
+ 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;
+ }
+ cmCallVisualStudioMacro::CallMacro(
+ topLevelSlnName, CMAKE_VSMACROS_RELOAD_MACRONAME, projects,
+ this->GetCMakeInstance()->GetDebugOutput());
+ }
+ } else if (m == MacroStop) {
+ cmCallVisualStudioMacro::CallMacro(
+ topLevelSlnName, CMAKE_VSMACROS_STOP_MACRONAME, "",
+ this->GetCMakeInstance()->GetDebugOutput());
+ }
+ }
+ }
+}
+
+std::string cmGlobalVisualStudioGenerator::GetUserMacrosDirectory()
+{
+ return "";
+}
+
+std::string cmGlobalVisualStudioGenerator::GetUserMacrosRegKeyBase()
+{
+ return "";
+}
+
+void cmGlobalVisualStudioGenerator::FillLinkClosure(
+ const cmGeneratorTarget* target, TargetSet& linked)
+{
+ if (linked.insert(target).second) {
+ TargetDependSet const& depends = this->GetTargetDirectDepends(target);
+ for (TargetDependSet::const_iterator di = depends.begin();
+ di != depends.end(); ++di) {
+ if (di->IsLink()) {
+ this->FillLinkClosure(*di, linked);
+ }
+ }
+ }
+}
+
+cmGlobalVisualStudioGenerator::TargetSet const&
+cmGlobalVisualStudioGenerator::GetTargetLinkClosure(cmGeneratorTarget* target)
+{
+ TargetSetMap::iterator i = this->TargetLinkClosure.find(target);
+ if (i == this->TargetLinkClosure.end()) {
+ TargetSetMap::value_type entry(target, TargetSet());
+ i = this->TargetLinkClosure.insert(entry).first;
+ this->FillLinkClosure(target, i->second);
+ }
+ return i->second;
+}
+
+void cmGlobalVisualStudioGenerator::FollowLinkDepends(
+ const cmGeneratorTarget* target, std::set<const cmGeneratorTarget*>& linked)
+{
+ if (target->GetType() == cmState::INTERFACE_LIBRARY) {
+ return;
+ }
+ if (linked.insert(target).second &&
+ target->GetType() == cmState::STATIC_LIBRARY) {
+ // Static library targets do not list their link dependencies so
+ // we must follow them transitively now.
+ TargetDependSet const& depends = this->GetTargetDirectDepends(target);
+ for (TargetDependSet::const_iterator di = depends.begin();
+ di != depends.end(); ++di) {
+ if (di->IsLink()) {
+ this->FollowLinkDepends(*di, linked);
+ }
+ }
+ }
+}
+
+bool cmGlobalVisualStudioGenerator::ComputeTargetDepends()
+{
+ if (!this->cmGlobalGenerator::ComputeTargetDepends()) {
+ return false;
+ }
+ std::map<std::string, std::vector<cmLocalGenerator*> >::iterator it;
+ for (it = this->ProjectMap.begin(); it != this->ProjectMap.end(); ++it) {
+ std::vector<cmLocalGenerator*>& gen = it->second;
+ for (std::vector<cmLocalGenerator*>::iterator i = gen.begin();
+ i != gen.end(); ++i) {
+ std::vector<cmGeneratorTarget*> targets = (*i)->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator ti = targets.begin();
+ ti != targets.end(); ++ti) {
+ this->ComputeVSTargetDepends(*ti);
+ }
+ }
+ }
+ return true;
+}
+
+static bool VSLinkable(cmGeneratorTarget const* t)
+{
+ return t->IsLinkable() || t->GetType() == cmState::OBJECT_LIBRARY;
+}
+
+void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(
+ cmGeneratorTarget* target)
+{
+ if (this->VSTargetDepends.find(target) != this->VSTargetDepends.end()) {
+ return;
+ }
+ VSDependSet& vsTargetDepend = this->VSTargetDepends[target];
+ // VS <= 7.1 has two behaviors that affect solution dependencies.
+ //
+ // (1) Solution-level dependencies between a linkable target and a
+ // library cause that library to be linked. We use an intermedite
+ // empty utility target to express the dependency. (VS 8 and above
+ // provide a project file "LinkLibraryDependencies" setting to
+ // choose whether to activate this behavior. We disable it except
+ // when linking external project files.)
+ //
+ // (2) We cannot let static libraries depend directly on targets to
+ // which they "link" because the librarian tool will copy the
+ // targets into the static library. While the work-around for
+ // behavior (1) would also avoid this, it would create a large
+ // number of extra utility targets for little gain. Instead, use
+ // the above work-around only for dependencies explicitly added by
+ // the add_dependencies() command. Approximate link dependencies by
+ // leaving them out for the static library itself but following them
+ // transitively for other targets.
+
+ bool allowLinkable = (target->GetType() != cmState::STATIC_LIBRARY &&
+ target->GetType() != cmState::SHARED_LIBRARY &&
+ target->GetType() != cmState::MODULE_LIBRARY &&
+ target->GetType() != cmState::EXECUTABLE);
+
+ TargetDependSet const& depends = this->GetTargetDirectDepends(target);
+
+ // Collect implicit link dependencies (target_link_libraries).
+ // Static libraries cannot depend on their link implementation
+ // due to behavior (2), but they do not really need to.
+ std::set<cmGeneratorTarget const*> linkDepends;
+ if (target->GetType() != cmState::STATIC_LIBRARY) {
+ for (TargetDependSet::const_iterator di = depends.begin();
+ di != depends.end(); ++di) {
+ cmTargetDepend dep = *di;
+ if (dep.IsLink()) {
+ this->FollowLinkDepends(*di, linkDepends);
+ }
+ }
+ }
+
+ // Collect explicit util dependencies (add_dependencies).
+ std::set<cmGeneratorTarget const*> utilDepends;
+ for (TargetDependSet::const_iterator di = depends.begin();
+ di != depends.end(); ++di) {
+ cmTargetDepend dep = *di;
+ if (dep.IsUtil()) {
+ this->FollowLinkDepends(*di, utilDepends);
+ }
+ }
+
+ // Collect all targets linked by this target so we can avoid
+ // intermediate targets below.
+ TargetSet linked;
+ if (target->GetType() != cmState::STATIC_LIBRARY) {
+ linked = this->GetTargetLinkClosure(target);
+ }
+
+ // Emit link dependencies.
+ for (std::set<cmGeneratorTarget const*>::iterator di = linkDepends.begin();
+ di != linkDepends.end(); ++di) {
+ cmGeneratorTarget const* dep = *di;
+ vsTargetDepend.insert(dep->GetName());
+ }
+
+ // Emit util dependencies. Possibly use intermediate targets.
+ for (std::set<cmGeneratorTarget const*>::iterator di = utilDepends.begin();
+ di != utilDepends.end(); ++di) {
+ cmGeneratorTarget const* dgt = *di;
+ if (allowLinkable || !VSLinkable(dgt) || linked.count(dgt)) {
+ // Direct dependency allowed.
+ vsTargetDepend.insert(dgt->GetName());
+ } else {
+ // Direct dependency on linkable target not allowed.
+ // Use an intermediate utility target.
+ vsTargetDepend.insert(this->GetUtilityDepend(dgt));
+ }
+ }
+}
+
+void cmGlobalVisualStudioGenerator::FindMakeProgram(cmMakefile* mf)
+{
+ // Visual Studio generators know how to lookup their build tool
+ // directly instead of needing a helper module to do it, so we
+ // do not actually need to put CMAKE_MAKE_PROGRAM into the cache.
+ if (cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
+ mf->AddDefinition("CMAKE_MAKE_PROGRAM", this->GetVSMakeProgram().c_str());
+ }
+}
+
+std::string cmGlobalVisualStudioGenerator::GetUtilityDepend(
+ cmGeneratorTarget const* target)
+{
+ UtilityDependsMap::iterator i = this->UtilityDepends.find(target);
+ if (i == this->UtilityDepends.end()) {
+ std::string name = this->WriteUtilityDepend(target);
+ UtilityDependsMap::value_type entry(target, name);
+ i = this->UtilityDepends.insert(entry).first;
+ }
+ return i->second;
+}
+
+std::string cmGlobalVisualStudioGenerator::GetStartupProjectName(
+ cmLocalGenerator const* root) const
+{
+ const char* n = root->GetMakefile()->GetProperty("VS_STARTUP_PROJECT");
+ if (n && *n) {
+ std::string startup = n;
+ if (this->FindTarget(startup)) {
+ return startup;
+ } else {
+ root->GetMakefile()->IssueMessage(
+ cmake::AUTHOR_WARNING,
+ "Directory property VS_STARTUP_PROJECT specifies target "
+ "'" +
+ startup + "' that does not exist. Ignoring.");
+ }
+ }
+
+ // default, if not specified
+ return this->GetAllTargetName();
+}
+
+#include <windows.h>
+
+bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
+ const std::string& regKeyBase,
+ std::string& nextAvailableSubKeyName)
+{
+ bool macrosRegistered = false;
+
+ std::string s1;
+ std::string s2;
+
+ // Make lowercase local copies, convert to Unix slashes, and
+ // see if the resulting strings are the same:
+ s1 = cmSystemTools::LowerCase(macrosFile);
+ cmSystemTools::ConvertToUnixSlashes(s1);
+
+ std::string keyname;
+ HKEY hkey = NULL;
+ LONG result = ERROR_SUCCESS;
+ DWORD index = 0;
+
+ keyname = regKeyBase + "\\OtherProjects7";
+ hkey = NULL;
+ result =
+ RegOpenKeyExW(HKEY_CURRENT_USER, cmsys::Encoding::ToWide(keyname).c_str(),
+ 0, KEY_READ, &hkey);
+ if (ERROR_SUCCESS == result) {
+ // Iterate the subkeys and look for the values of interest in each subkey:
+ wchar_t subkeyname[256];
+ DWORD cch_subkeyname = sizeof(subkeyname) * sizeof(subkeyname[0]);
+ wchar_t keyclass[256];
+ DWORD cch_keyclass = sizeof(keyclass) * sizeof(keyclass[0]);
+ FILETIME lastWriteTime;
+ lastWriteTime.dwHighDateTime = 0;
+ lastWriteTime.dwLowDateTime = 0;
+
+ while (ERROR_SUCCESS == RegEnumKeyExW(hkey, index, subkeyname,
+ &cch_subkeyname, 0, keyclass,
+ &cch_keyclass, &lastWriteTime)) {
+ // Open the subkey and query the values of interest:
+ HKEY hsubkey = NULL;
+ result = RegOpenKeyExW(hkey, subkeyname, 0, KEY_READ, &hsubkey);
+ if (ERROR_SUCCESS == result) {
+ DWORD valueType = REG_SZ;
+ wchar_t data1[256];
+ DWORD cch_data1 = sizeof(data1) * sizeof(data1[0]);
+ RegQueryValueExW(hsubkey, L"Path", 0, &valueType, (LPBYTE)&data1[0],
+ &cch_data1);
+
+ DWORD data2 = 0;
+ DWORD cch_data2 = sizeof(data2);
+ RegQueryValueExW(hsubkey, L"Security", 0, &valueType, (LPBYTE)&data2,
+ &cch_data2);
+
+ DWORD data3 = 0;
+ DWORD cch_data3 = sizeof(data3);
+ RegQueryValueExW(hsubkey, L"StorageFormat", 0, &valueType,
+ (LPBYTE)&data3, &cch_data3);
+
+ s2 = cmSystemTools::LowerCase(cmsys::Encoding::ToNarrow(data1));
+ cmSystemTools::ConvertToUnixSlashes(s2);
+ if (s2 == s1) {
+ macrosRegistered = true;
+ }
+
+ std::string fullname = cmsys::Encoding::ToNarrow(data1);
+ std::string filename;
+ std::string filepath;
+ std::string filepathname;
+ std::string filepathpath;
+ if (cmSystemTools::FileExists(fullname.c_str())) {
+ filename = cmSystemTools::GetFilenameName(fullname);
+ filepath = cmSystemTools::GetFilenamePath(fullname);
+ filepathname = cmSystemTools::GetFilenameName(filepath);
+ filepathpath = cmSystemTools::GetFilenamePath(filepath);
+ }
+
+ // std::cout << keyname << "\\" << subkeyname << ":" << std::endl;
+ // std::cout << " Path: " << data1 << std::endl;
+ // std::cout << " Security: " << data2 << std::endl;
+ // std::cout << " StorageFormat: " << data3 << std::endl;
+ // std::cout << " filename: " << filename << std::endl;
+ // std::cout << " filepath: " << filepath << std::endl;
+ // std::cout << " filepathname: " << filepathname << std::endl;
+ // std::cout << " filepathpath: " << filepathpath << std::endl;
+ // std::cout << std::endl;
+
+ RegCloseKey(hsubkey);
+ } else {
+ std::cout << "error opening subkey: " << subkeyname << std::endl;
+ std::cout << std::endl;
+ }
+
+ ++index;
+ cch_subkeyname = sizeof(subkeyname) * sizeof(subkeyname[0]);
+ cch_keyclass = sizeof(keyclass) * sizeof(keyclass[0]);
+ lastWriteTime.dwHighDateTime = 0;
+ lastWriteTime.dwLowDateTime = 0;
+ }
+
+ RegCloseKey(hkey);
+ } else {
+ std::cout << "error opening key: " << keyname << std::endl;
+ std::cout << std::endl;
+ }
+
+ // Pass back next available sub key name, assuming sub keys always
+ // follow the expected naming scheme. Expected naming scheme is that
+ // the subkeys of OtherProjects7 is 0 to n-1, so it's ok to use "n"
+ // as the name of the next subkey.
+ std::ostringstream ossNext;
+ ossNext << index;
+ nextAvailableSubKeyName = ossNext.str();
+
+ keyname = regKeyBase + "\\RecordingProject7";
+ hkey = NULL;
+ result =
+ RegOpenKeyExW(HKEY_CURRENT_USER, cmsys::Encoding::ToWide(keyname).c_str(),
+ 0, KEY_READ, &hkey);
+ if (ERROR_SUCCESS == result) {
+ DWORD valueType = REG_SZ;
+ wchar_t data1[256];
+ DWORD cch_data1 = sizeof(data1) * sizeof(data1[0]);
+ RegQueryValueExW(hkey, L"Path", 0, &valueType, (LPBYTE)&data1[0],
+ &cch_data1);
+
+ DWORD data2 = 0;
+ DWORD cch_data2 = sizeof(data2);
+ RegQueryValueExW(hkey, L"Security", 0, &valueType, (LPBYTE)&data2,
+ &cch_data2);
+
+ DWORD data3 = 0;
+ DWORD cch_data3 = sizeof(data3);
+ RegQueryValueExW(hkey, L"StorageFormat", 0, &valueType, (LPBYTE)&data3,
+ &cch_data3);
+
+ s2 = cmSystemTools::LowerCase(cmsys::Encoding::ToNarrow(data1));
+ cmSystemTools::ConvertToUnixSlashes(s2);
+ if (s2 == s1) {
+ macrosRegistered = true;
+ }
+
+ // std::cout << keyname << ":" << std::endl;
+ // std::cout << " Path: " << data1 << std::endl;
+ // std::cout << " Security: " << data2 << std::endl;
+ // std::cout << " StorageFormat: " << data3 << std::endl;
+ // std::cout << std::endl;
+
+ RegCloseKey(hkey);
+ } else {
+ std::cout << "error opening key: " << keyname << std::endl;
+ std::cout << std::endl;
+ }
+
+ return macrosRegistered;
+}
+
+void WriteVSMacrosFileRegistryEntry(const std::string& nextAvailableSubKeyName,
+ const std::string& macrosFile,
+ const std::string& regKeyBase)
+{
+ std::string keyname = regKeyBase + "\\OtherProjects7";
+ HKEY hkey = NULL;
+ LONG result =
+ RegOpenKeyExW(HKEY_CURRENT_USER, cmsys::Encoding::ToWide(keyname).c_str(),
+ 0, KEY_READ | KEY_WRITE, &hkey);
+ if (ERROR_SUCCESS == result) {
+ // Create the subkey and set the values of interest:
+ HKEY hsubkey = NULL;
+ wchar_t lpClass[] = L"";
+ result = RegCreateKeyExW(
+ hkey, cmsys::Encoding::ToWide(nextAvailableSubKeyName).c_str(), 0,
+ lpClass, 0, KEY_READ | KEY_WRITE, 0, &hsubkey, 0);
+ if (ERROR_SUCCESS == result) {
+ DWORD dw = 0;
+
+ std::string s(macrosFile);
+ std::replace(s.begin(), s.end(), '/', '\\');
+ std::wstring ws = cmsys::Encoding::ToWide(s);
+
+ result =
+ RegSetValueExW(hsubkey, L"Path", 0, REG_SZ, (LPBYTE)ws.c_str(),
+ static_cast<DWORD>(ws.size() + 1) * sizeof(wchar_t));
+ if (ERROR_SUCCESS != result) {
+ std::cout << "error result 1: " << result << std::endl;
+ std::cout << std::endl;
+ }
+
+ // Security value is always "1" for sample macros files (seems to be "2"
+ // if you put the file somewhere outside the standard VSMacros folder)
+ dw = 1;
+ result = RegSetValueExW(hsubkey, L"Security", 0, REG_DWORD, (LPBYTE)&dw,
+ sizeof(DWORD));
+ if (ERROR_SUCCESS != result) {
+ std::cout << "error result 2: " << result << std::endl;
+ std::cout << std::endl;
+ }
+
+ // StorageFormat value is always "0" for sample macros files
+ dw = 0;
+ result = RegSetValueExW(hsubkey, L"StorageFormat", 0, REG_DWORD,
+ (LPBYTE)&dw, sizeof(DWORD));
+ if (ERROR_SUCCESS != result) {
+ std::cout << "error result 3: " << result << std::endl;
+ std::cout << std::endl;
+ }
+
+ RegCloseKey(hsubkey);
+ } else {
+ std::cout << "error creating subkey: " << nextAvailableSubKeyName
+ << std::endl;
+ std::cout << std::endl;
+ }
+ RegCloseKey(hkey);
+ } else {
+ std::cout << "error opening key: " << keyname << std::endl;
+ std::cout << std::endl;
+ }
+}
+
+void RegisterVisualStudioMacros(const std::string& macrosFile,
+ const std::string& regKeyBase)
+{
+ bool macrosRegistered;
+ std::string nextAvailableSubKeyName;
+
+ macrosRegistered = IsVisualStudioMacrosFileRegistered(
+ macrosFile, regKeyBase, nextAvailableSubKeyName);
+
+ if (!macrosRegistered) {
+ int count =
+ cmCallVisualStudioMacro::GetNumberOfRunningVisualStudioInstances("ALL");
+
+ // Only register the macros file if there are *no* instances of Visual
+ // Studio running. If we register it while one is running, first, it has
+ // no effect on the running instance; second, and worse, Visual Studio
+ // removes our newly added registration entry when it quits. Instead,
+ // emit a warning asking the user to exit all running Visual Studio
+ // instances...
+ //
+ if (0 != count) {
+ std::ostringstream oss;
+ oss << "Could not register CMake's Visual Studio macros file '"
+ << CMAKE_VSMACROS_FILENAME "' while Visual Studio is running."
+ << " Please exit all running instances of Visual Studio before"
+ << " continuing." << std::endl
+ << std::endl
+ << "CMake needs to register Visual Studio macros when its macros"
+ << " file is updated or when it detects that its current macros file"
+ << " is no longer registered with Visual Studio." << std::endl;
+ cmSystemTools::Message(oss.str().c_str(), "Warning");
+
+ // Count them again now that the warning is over. In the case of a GUI
+ // warning, the user may have gone to close Visual Studio and then come
+ // back to the CMake GUI and clicked ok on the above warning. If so,
+ // then register the macros *now* if the count is *now* 0...
+ //
+ count = cmCallVisualStudioMacro::GetNumberOfRunningVisualStudioInstances(
+ "ALL");
+
+ // Also re-get the nextAvailableSubKeyName in case Visual Studio
+ // wrote out new registered macros information as it was exiting:
+ //
+ if (0 == count) {
+ IsVisualStudioMacrosFileRegistered(macrosFile, regKeyBase,
+ nextAvailableSubKeyName);
+ }
+ }
+
+ // Do another if check - 'count' may have changed inside the above if:
+ //
+ if (0 == count) {
+ WriteVSMacrosFileRegistryEntry(nextAvailableSubKeyName, macrosFile,
+ regKeyBase);
+ }
+ }
+}
+bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly(
+ cmGeneratorTarget const* gt)
+{
+ // check to see if this is a fortran build
+ std::set<std::string> languages;
+ {
+ // Issue diagnostic if the source files depend on the config.
+ std::vector<cmSourceFile*> sources;
+ if (!gt->GetConfigCommonSourceFiles(sources)) {
+ return false;
+ }
+ }
+ gt->GetLanguages(languages, "");
+ if (languages.size() == 1) {
+ if (*languages.begin() == "Fortran") {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmGlobalVisualStudioGenerator::TargetCompare::operator()(
+ cmGeneratorTarget const* l, cmGeneratorTarget const* r) const
+{
+ // Make sure a given named target is ordered first,
+ // e.g. to set ALL_BUILD as the default active project.
+ // When the empty string is named this is a no-op.
+ if (r->GetName() == this->First) {
+ return false;
+ }
+ if (l->GetName() == this->First) {
+ return true;
+ }
+ return l->GetName() < r->GetName();
+}
+
+cmGlobalVisualStudioGenerator::OrderedTargetDependSet::OrderedTargetDependSet(
+ TargetDependSet const& targets, std::string const& first)
+ : derived(TargetCompare(first))
+{
+ this->insert(targets.begin(), targets.end());
+}
+
+cmGlobalVisualStudioGenerator::OrderedTargetDependSet::OrderedTargetDependSet(
+ TargetSet const& targets, std::string const& first)
+ : derived(TargetCompare(first))
+{
+ for (TargetSet::const_iterator it = targets.begin(); it != targets.end();
+ ++it) {
+ this->insert(*it);
+ }
+}
+
+std::string cmGlobalVisualStudioGenerator::ExpandCFGIntDir(
+ const std::string& str, const std::string& config) const
+{
+ std::string replace = GetCMakeCFGIntDir();
+
+ std::string tmp = str;
+ for (std::string::size_type i = tmp.find(replace); i != std::string::npos;
+ i = tmp.find(replace, i)) {
+ tmp.replace(i, replace.size(), config);
+ i += config.size();
+ }
+ return tmp;
+}
+
+void cmGlobalVisualStudioGenerator::AddSymbolExportCommand(
+ cmGeneratorTarget* gt, std::vector<cmCustomCommand>& commands,
+ std::string const& configName)
+{
+ std::vector<std::string> outputs;
+ std::string deffile = gt->ObjectDirectory;
+ deffile += "/exportall.def";
+ outputs.push_back(deffile);
+ std::vector<std::string> empty;
+ std::vector<cmSourceFile const*> objectSources;
+ gt->GetObjectSources(objectSources, configName);
+ std::map<cmSourceFile const*, std::string> mapping;
+ for (std::vector<cmSourceFile const*>::const_iterator it =
+ objectSources.begin();
+ it != objectSources.end(); ++it) {
+ mapping[*it];
+ }
+ gt->LocalGenerator->ComputeObjectFilenames(mapping, gt);
+ std::string obj_dir = gt->ObjectDirectory;
+ std::string cmakeCommand = cmSystemTools::GetCMakeCommand();
+ cmSystemTools::ConvertToWindowsExtendedPath(cmakeCommand);
+ cmCustomCommandLine cmdl;
+ cmdl.push_back(cmakeCommand);
+ cmdl.push_back("-E");
+ cmdl.push_back("__create_def");
+ cmdl.push_back(deffile);
+ std::string obj_dir_expanded = obj_dir;
+ cmSystemTools::ReplaceString(obj_dir_expanded, this->GetCMakeCFGIntDir(),
+ configName.c_str());
+ std::string objs_file = obj_dir_expanded;
+ cmSystemTools::MakeDirectory(objs_file.c_str());
+ objs_file += "/objects.txt";
+ cmdl.push_back(objs_file);
+ cmGeneratedFileStream fout(objs_file.c_str());
+ if (!fout) {
+ cmSystemTools::Error("could not open ", objs_file.c_str());
+ return;
+ }
+ for (std::vector<cmSourceFile const*>::const_iterator it =
+ objectSources.begin();
+ it != objectSources.end(); ++it) {
+ // 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;
+ // replace $(ConfigurationName) in the object names
+ cmSystemTools::ReplaceString(objFile, this->GetCMakeCFGIntDir(),
+ configName.c_str());
+ if (cmHasLiteralSuffix(objFile, ".obj")) {
+ fout << objFile << "\n";
+ }
+ }
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(cmdl);
+ cmCustomCommand command(gt->Target->GetMakefile(), outputs, empty, empty,
+ commandLines, "Auto build dll exports", ".");
+ commands.push_back(command);
+}
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
new file mode 100644
index 0000000..1d456ff
--- /dev/null
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -0,0 +1,187 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalVisualStudioGenerator_h
+#define cmGlobalVisualStudioGenerator_h
+
+#include "cmGlobalGenerator.h"
+
+/** \class cmGlobalVisualStudioGenerator
+ * \brief Base class for global Visual Studio generators.
+ *
+ * cmGlobalVisualStudioGenerator provides functionality common to all
+ * global Visual Studio generators.
+ */
+class cmGlobalVisualStudioGenerator : public cmGlobalGenerator
+{
+public:
+ /** Known versions of Visual Studio. */
+ enum VSVersion
+ {
+ VS7 = 70,
+ VS71 = 71,
+ VS8 = 80,
+ VS9 = 90,
+ VS10 = 100,
+ VS11 = 110,
+ VS12 = 120,
+ /* VS13 = 130 was skipped */
+ VS14 = 140
+ };
+
+ cmGlobalVisualStudioGenerator(cmake* cm);
+ virtual ~cmGlobalVisualStudioGenerator();
+
+ VSVersion GetVersion() const;
+ void SetVersion(VSVersion v);
+
+ /**
+ * Configure CMake's Visual Studio macros file into the user's Visual
+ * Studio macros directory.
+ */
+ virtual void ConfigureCMakeVisualStudioMacros();
+
+ /**
+ * Where does this version of Visual Studio look for macros for the
+ * current user? Returns the empty string if this version of Visual
+ * Studio does not implement support for VB macros.
+ */
+ virtual std::string GetUserMacrosDirectory();
+
+ /**
+ * What is the reg key path to "vsmacros" for this version of Visual
+ * Studio?
+ */
+ virtual std::string GetUserMacrosRegKeyBase();
+
+ enum MacroName
+ {
+ MacroReload,
+ MacroStop
+ };
+
+ /**
+ * Call the ReloadProjects macro if necessary based on
+ * GetFilesReplacedDuringGenerate results.
+ */
+ void CallVisualStudioMacro(MacroName m, const char* vsSolutionFile = 0);
+
+ // return true if target is fortran only
+ bool TargetIsFortranOnly(const cmGeneratorTarget* gt);
+
+ /** Get the top-level registry key for this VS version. */
+ std::string GetRegistryBase();
+
+ /** Get the top-level registry key for the given VS version. */
+ static std::string GetRegistryBase(const char* version);
+
+ /** Return true if the generated build tree may contain multiple builds.
+ i.e. "Can I build Debug and Release in the same tree?" */
+ virtual bool IsMultiConfig() const { return true; }
+
+ /** Return true if building for Windows CE */
+ virtual bool TargetsWindowsCE() const { return false; }
+
+ class TargetSet : public std::set<cmGeneratorTarget const*>
+ {
+ };
+ class TargetCompare
+ {
+ std::string First;
+
+ public:
+ TargetCompare(std::string const& first)
+ : First(first)
+ {
+ }
+ bool operator()(cmGeneratorTarget const* l,
+ cmGeneratorTarget const* r) const;
+ };
+ class OrderedTargetDependSet;
+
+ virtual void FindMakeProgram(cmMakefile*);
+
+ virtual std::string ExpandCFGIntDir(const std::string& str,
+ const std::string& config) const;
+
+ void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const;
+
+ std::string GetStartupProjectName(cmLocalGenerator const* root) const;
+
+ void AddSymbolExportCommand(cmGeneratorTarget*,
+ std::vector<cmCustomCommand>& commands,
+ std::string const& configName);
+
+protected:
+ virtual void AddExtraIDETargets();
+
+ // Does this VS version link targets to each other if there are
+ // dependencies in the SLN file? This was done for VS versions
+ // below 8.
+ virtual bool VSLinksDependencies() const { return true; }
+
+ virtual const char* GetIDEVersion() = 0;
+
+ virtual bool ComputeTargetDepends();
+ class VSDependSet : public std::set<std::string>
+ {
+ };
+ class VSDependMap : public std::map<cmGeneratorTarget const*, VSDependSet>
+ {
+ };
+ VSDependMap VSTargetDepends;
+ void ComputeVSTargetDepends(cmGeneratorTarget*);
+
+ bool CheckTargetLinks(cmGeneratorTarget& target, const std::string& name);
+ std::string GetUtilityForTarget(cmGeneratorTarget& target,
+ const std::string&);
+ virtual std::string WriteUtilityDepend(cmGeneratorTarget const*) = 0;
+ std::string GetUtilityDepend(const cmGeneratorTarget* target);
+ typedef std::map<cmGeneratorTarget const*, std::string> UtilityDependsMap;
+ UtilityDependsMap UtilityDepends;
+
+protected:
+ VSVersion Version;
+
+private:
+ virtual std::string GetVSMakeProgram() = 0;
+ void PrintCompilerAdvice(std::ostream&, std::string const&,
+ const char*) const
+ {
+ }
+
+ void FollowLinkDepends(cmGeneratorTarget const* target,
+ std::set<cmGeneratorTarget const*>& linked);
+
+ class TargetSetMap : public std::map<cmGeneratorTarget*, TargetSet>
+ {
+ };
+ TargetSetMap TargetLinkClosure;
+ void FillLinkClosure(const cmGeneratorTarget* target, TargetSet& linked);
+ TargetSet const& GetTargetLinkClosure(cmGeneratorTarget* target);
+};
+
+class cmGlobalVisualStudioGenerator::OrderedTargetDependSet
+ : public std::multiset<cmTargetDepend,
+ cmGlobalVisualStudioGenerator::TargetCompare>
+{
+ typedef std::multiset<cmTargetDepend,
+ cmGlobalVisualStudioGenerator::TargetCompare>
+ derived;
+
+public:
+ typedef cmGlobalGenerator::TargetDependSet TargetDependSet;
+ typedef cmGlobalVisualStudioGenerator::TargetSet TargetSet;
+ OrderedTargetDependSet(TargetDependSet const&, std::string const& first);
+ OrderedTargetDependSet(TargetSet const&, std::string const& first);
+};
+
+#endif
diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx
new file mode 100644
index 0000000..86fe6f2
--- /dev/null
+++ b/Source/cmGlobalWatcomWMakeGenerator.cxx
@@ -0,0 +1,56 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalWatcomWMakeGenerator.h"
+
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+
+cmGlobalWatcomWMakeGenerator::cmGlobalWatcomWMakeGenerator(cmake* cm)
+ : cmGlobalUnixMakefileGenerator3(cm)
+{
+ this->FindMakeProgramFile = "CMakeFindWMake.cmake";
+#ifdef _WIN32
+ this->ForceUnixPaths = false;
+#endif
+ this->ToolSupportsColor = true;
+ this->NeedSymbolicMark = true;
+ this->EmptyRuleHackCommand = "@cd .";
+#ifdef _WIN32
+ cm->GetState()->SetWindowsShell(true);
+#endif
+ cm->GetState()->SetWatcomWMake(true);
+ this->IncludeDirective = "!include";
+ this->DefineWindowsNULL = true;
+ this->UnixCD = false;
+ this->MakeSilentFlag = "-h";
+}
+
+void cmGlobalWatcomWMakeGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ // pick a default
+ mf->AddDefinition("WATCOM", "1");
+ mf->AddDefinition("CMAKE_QUOTE_INCLUDE_PATHS", "1");
+ mf->AddDefinition("CMAKE_MANGLE_OBJECT_FILE_NAMES", "1");
+ mf->AddDefinition("CMAKE_MAKE_LINE_CONTINUE", "&");
+ mf->AddDefinition("CMAKE_MAKE_SYMBOLIC_RULE", ".SYMBOLIC");
+ mf->AddDefinition("CMAKE_GENERATOR_CC", "wcl386");
+ mf->AddDefinition("CMAKE_GENERATOR_CXX", "wcl386");
+ this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
+}
+
+void cmGlobalWatcomWMakeGenerator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalWatcomWMakeGenerator::GetActualName();
+ entry.Brief = "Generates Watcom WMake makefiles.";
+}
diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h
new file mode 100644
index 0000000..bc0d786
--- /dev/null
+++ b/Source/cmGlobalWatcomWMakeGenerator.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalWatcomWMakeGenerator_h
+#define cmGlobalWatcomWMakeGenerator_h
+
+#include "cmGlobalUnixMakefileGenerator3.h"
+
+/** \class cmGlobalWatcomWMakeGenerator
+ * \brief Write a NMake makefiles.
+ *
+ * cmGlobalWatcomWMakeGenerator manages nmake build process for a tree
+ */
+class cmGlobalWatcomWMakeGenerator : public cmGlobalUnixMakefileGenerator3
+{
+public:
+ cmGlobalWatcomWMakeGenerator(cmake* cm);
+ static cmGlobalGeneratorFactory* NewFactory()
+ {
+ return new cmGlobalGeneratorSimpleFactory<cmGlobalWatcomWMakeGenerator>();
+ }
+ ///! Get the name for the generator.
+ std::string GetName() const CM_OVERRIDE
+ {
+ return cmGlobalWatcomWMakeGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "Watcom WMake"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) CM_OVERRIDE;
+
+ bool AllowNotParallel() const CM_OVERRIDE { return false; }
+ bool AllowDeleteOnError() const CM_OVERRIDE { return false; }
+};
+
+#endif
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
new file mode 100644
index 0000000..e65ca09
--- /dev/null
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -0,0 +1,3490 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGlobalXCodeGenerator.h"
+
+#include "cmAlgorithms.h"
+#include "cmComputeLinkInformation.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGeneratorFactory.h"
+#include "cmLocalXCodeGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmXCode21Object.h"
+#include "cmXCodeObject.h"
+#include "cmake.h"
+
+#include <cm_auto_ptr.hxx>
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmXMLParser.h"
+
+// parse the xml file storing the installed version of Xcode on
+// the machine
+class cmXcodeVersionParser : public cmXMLParser
+{
+public:
+ cmXcodeVersionParser()
+ : Version("1.5")
+ {
+ }
+ void StartElement(const std::string&, const char**) { this->Data = ""; }
+ void EndElement(const std::string& name)
+ {
+ if (name == "key") {
+ this->Key = this->Data;
+ } else if (name == "string") {
+ if (this->Key == "CFBundleShortVersionString") {
+ this->Version = this->Data;
+ }
+ }
+ }
+ void CharacterDataHandler(const char* data, int length)
+ {
+ this->Data.append(data, length);
+ }
+ std::string Version;
+ std::string Key;
+ std::string Data;
+};
+#endif
+
+// Builds either an object list or a space-separated string from the
+// given inputs.
+class cmGlobalXCodeGenerator::BuildObjectListOrString
+{
+ cmGlobalXCodeGenerator* Generator;
+ cmXCodeObject* Group;
+ bool Empty;
+ std::string String;
+
+public:
+ BuildObjectListOrString(cmGlobalXCodeGenerator* gen, bool buildObjectList)
+ : Generator(gen)
+ , Group(0)
+ , Empty(true)
+ {
+ if (buildObjectList) {
+ this->Group = this->Generator->CreateObject(cmXCodeObject::OBJECT_LIST);
+ }
+ }
+
+ bool IsEmpty() const { return this->Empty; }
+
+ void Add(const std::string& newString)
+ {
+ this->Empty = false;
+
+ if (this->Group) {
+ this->Group->AddObject(this->Generator->CreateString(newString));
+ } else {
+ this->String += newString;
+ this->String += ' ';
+ }
+ }
+
+ const std::string& GetString() const { return this->String; }
+
+ cmXCodeObject* CreateList()
+ {
+ if (this->Group) {
+ return this->Group;
+ } else {
+ return this->Generator->CreateString(this->String);
+ }
+ }
+};
+
+class cmGlobalXCodeGenerator::Factory : public cmGlobalGeneratorFactory
+{
+public:
+ virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
+ cmake* cm) const;
+
+ virtual void GetDocumentation(cmDocumentationEntry& entry) const
+ {
+ cmGlobalXCodeGenerator::GetDocumentation(entry);
+ }
+
+ virtual void GetGenerators(std::vector<std::string>& names) const
+ {
+ names.push_back(cmGlobalXCodeGenerator::GetActualName());
+ }
+
+ virtual bool SupportsToolset() const { return true; }
+};
+
+cmGlobalXCodeGenerator::cmGlobalXCodeGenerator(cmake* cm,
+ std::string const& version)
+ : cmGlobalGenerator(cm)
+{
+ this->VersionString = version;
+
+ // Compute an integer form of the version number.
+ unsigned int v[2] = { 0, 0 };
+ sscanf(this->VersionString.c_str(), "%u.%u", &v[0], &v[1]);
+ this->XcodeVersion = 10 * v[0] + v[1];
+
+ this->RootObject = 0;
+ this->MainGroupChildren = 0;
+ this->SourcesGroupChildren = 0;
+ this->ResourcesGroupChildren = 0;
+ this->CurrentMakefile = 0;
+ this->CurrentLocalGenerator = 0;
+ this->XcodeBuildCommandInitialized = false;
+}
+
+cmGlobalGeneratorFactory* cmGlobalXCodeGenerator::NewFactory()
+{
+ return new Factory;
+}
+
+cmGlobalGenerator* cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator(
+ const std::string& name, cmake* cm) const
+{
+ if (name != GetActualName())
+ return 0;
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ cmXcodeVersionParser parser;
+ std::string versionFile;
+ {
+ std::string out;
+ std::string::size_type pos;
+ if (cmSystemTools::RunSingleCommand("xcode-select --print-path", &out, 0,
+ 0, 0, cmSystemTools::OUTPUT_NONE) &&
+ (pos = out.find(".app/"), pos != out.npos)) {
+ versionFile = out.substr(0, pos + 5) + "Contents/version.plist";
+ }
+ }
+ if (!versionFile.empty() && cmSystemTools::FileExists(versionFile.c_str())) {
+ parser.ParseFile(versionFile.c_str());
+ } else if (cmSystemTools::FileExists(
+ "/Applications/Xcode.app/Contents/version.plist")) {
+ parser.ParseFile("/Applications/Xcode.app/Contents/version.plist");
+ } else {
+ parser.ParseFile(
+ "/Developer/Applications/Xcode.app/Contents/version.plist");
+ }
+ CM_AUTO_PTR<cmGlobalXCodeGenerator> gg(
+ new cmGlobalXCodeGenerator(cm, parser.Version));
+ if (gg->XcodeVersion == 20) {
+ cmSystemTools::Message("Xcode 2.0 not really supported by cmake, "
+ "using Xcode 15 generator\n");
+ gg->XcodeVersion = 15;
+ }
+ return gg.release();
+#else
+ std::cerr << "CMake should be built with cmake to use Xcode, "
+ "default to Xcode 1.5\n";
+ return new cmGlobalXCodeGenerator(cm);
+#endif
+}
+
+void cmGlobalXCodeGenerator::FindMakeProgram(cmMakefile* mf)
+{
+ // The Xcode generator knows how to lookup its build tool
+ // directly instead of needing a helper module to do it, so we
+ // do not actually need to put CMAKE_MAKE_PROGRAM into the cache.
+ if (cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
+ mf->AddDefinition("CMAKE_MAKE_PROGRAM",
+ this->GetXcodeBuildCommand().c_str());
+ }
+}
+
+std::string const& cmGlobalXCodeGenerator::GetXcodeBuildCommand()
+{
+ if (!this->XcodeBuildCommandInitialized) {
+ this->XcodeBuildCommandInitialized = true;
+ this->XcodeBuildCommand = this->FindXcodeBuildCommand();
+ }
+ return this->XcodeBuildCommand;
+}
+
+std::string cmGlobalXCodeGenerator::FindXcodeBuildCommand()
+{
+ if (this->XcodeVersion >= 40) {
+ std::string makeProgram = cmSystemTools::FindProgram("xcodebuild");
+ if (makeProgram.empty()) {
+ makeProgram = "xcodebuild";
+ }
+ return makeProgram;
+ } else {
+ // Use cmakexbuild wrapper to suppress environment dump from output.
+ return cmSystemTools::GetCMakeCommand() + "xbuild";
+ }
+}
+
+bool cmGlobalXCodeGenerator::SetGeneratorToolset(std::string const& ts,
+ cmMakefile* mf)
+{
+ if (this->XcodeVersion >= 30) {
+ this->GeneratorToolset = ts;
+ if (!this->GeneratorToolset.empty()) {
+ mf->AddDefinition("CMAKE_XCODE_PLATFORM_TOOLSET",
+ this->GeneratorToolset.c_str());
+ }
+ return true;
+ } else {
+ return cmGlobalGenerator::SetGeneratorToolset(ts, mf);
+ }
+}
+
+void cmGlobalXCodeGenerator::EnableLanguage(
+ std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
+{
+ mf->AddDefinition("XCODE", "1");
+ mf->AddDefinition("XCODE_VERSION", this->VersionString.c_str());
+ if (this->XcodeVersion == 15) {
+ } else {
+ if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
+ mf->AddCacheDefinition(
+ "CMAKE_CONFIGURATION_TYPES", "Debug;Release;MinSizeRel;RelWithDebInfo",
+ "Semicolon separated list of supported configuration types, "
+ "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
+ "anything else will be ignored.",
+ cmState::STRING);
+ }
+ }
+ mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
+ this->cmGlobalGenerator::EnableLanguage(lang, mf, optional);
+ const char* osxArch = mf->GetDefinition("CMAKE_OSX_ARCHITECTURES");
+ const char* sysroot = mf->GetDefinition("CMAKE_OSX_SYSROOT");
+ if (osxArch && sysroot) {
+ this->Architectures.clear();
+ cmSystemTools::ExpandListArgument(std::string(osxArch),
+ this->Architectures);
+ }
+}
+
+void cmGlobalXCodeGenerator::GenerateBuildCommand(
+ std::vector<std::string>& makeCommand, const std::string& makeProgram,
+ const std::string& projectName, const std::string& /*projectDir*/,
+ const std::string& targetName, const std::string& config, bool /*fast*/,
+ bool /*verbose*/, std::vector<std::string> const& makeOptions)
+{
+ // now build the test
+ makeCommand.push_back(
+ this->SelectMakeProgram(makeProgram, this->GetXcodeBuildCommand()));
+
+ makeCommand.push_back("-project");
+ std::string projectArg = projectName;
+ projectArg += ".xcode";
+ if (this->XcodeVersion > 20) {
+ projectArg += "proj";
+ }
+ makeCommand.push_back(projectArg);
+
+ bool clean = false;
+ std::string realTarget = targetName;
+ if (realTarget == "clean") {
+ clean = true;
+ realTarget = "ALL_BUILD";
+ }
+ if (clean) {
+ makeCommand.push_back("clean");
+ } else {
+ makeCommand.push_back("build");
+ }
+ makeCommand.push_back("-target");
+ if (!realTarget.empty()) {
+ makeCommand.push_back(realTarget);
+ } else {
+ makeCommand.push_back("ALL_BUILD");
+ }
+ if (this->XcodeVersion == 15) {
+ makeCommand.push_back("-buildstyle");
+ makeCommand.push_back("Development");
+ } else {
+ makeCommand.push_back("-configuration");
+ makeCommand.push_back(!config.empty() ? config : "Debug");
+ }
+ makeCommand.insert(makeCommand.end(), makeOptions.begin(),
+ makeOptions.end());
+}
+
+///! Create a local generator appropriate to this Global Generator
+cmLocalGenerator* cmGlobalXCodeGenerator::CreateLocalGenerator(cmMakefile* mf)
+{
+ return new cmLocalXCodeGenerator(this, mf);
+}
+
+void cmGlobalXCodeGenerator::AddExtraIDETargets()
+{
+ std::map<std::string, std::vector<cmLocalGenerator*> >::iterator it;
+ // make sure extra targets are added before calling
+ // the parent generate which will call trace depends
+ for (it = this->ProjectMap.begin(); it != this->ProjectMap.end(); ++it) {
+ cmLocalGenerator* root = it->second[0];
+ this->SetGenerationRoot(root);
+ // add ALL_BUILD, INSTALL, etc
+ this->AddExtraTargets(root, it->second);
+ }
+}
+
+void cmGlobalXCodeGenerator::Generate()
+{
+ this->cmGlobalGenerator::Generate();
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+ std::map<std::string, std::vector<cmLocalGenerator*> >::iterator it;
+ for (it = this->ProjectMap.begin(); it != this->ProjectMap.end(); ++it) {
+ cmLocalGenerator* root = it->second[0];
+ this->SetGenerationRoot(root);
+ // now create the project
+ this->OutputXCodeProject(root, it->second);
+ }
+}
+
+void cmGlobalXCodeGenerator::SetGenerationRoot(cmLocalGenerator* root)
+{
+ this->CurrentProject = root->GetProjectName();
+ this->SetCurrentLocalGenerator(root);
+ cmSystemTools::SplitPath(
+ this->CurrentLocalGenerator->GetCurrentSourceDirectory(),
+ this->ProjectSourceDirectoryComponents);
+ cmSystemTools::SplitPath(
+ this->CurrentLocalGenerator->GetCurrentBinaryDirectory(),
+ this->ProjectOutputDirectoryComponents);
+
+ this->CurrentXCodeHackMakefile = root->GetCurrentBinaryDirectory();
+ this->CurrentXCodeHackMakefile += "/CMakeScripts";
+ cmSystemTools::MakeDirectory(this->CurrentXCodeHackMakefile.c_str());
+ this->CurrentXCodeHackMakefile += "/XCODE_DEPEND_HELPER.make";
+}
+
+std::string cmGlobalXCodeGenerator::PostBuildMakeTarget(
+ std::string const& tName, std::string const& configName)
+{
+ std::string target = tName;
+ std::replace(target.begin(), target.end(), ' ', '_');
+ std::string out = "PostBuild." + target;
+ if (this->XcodeVersion > 20) {
+ out += "." + configName;
+ }
+ return out;
+}
+
+#define CMAKE_CHECK_BUILD_SYSTEM_TARGET "ZERO_CHECK"
+
+void cmGlobalXCodeGenerator::AddExtraTargets(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& gens)
+{
+ cmMakefile* mf = root->GetMakefile();
+
+ // Add ALL_BUILD
+ const char* no_working_directory = 0;
+ std::vector<std::string> no_depends;
+ cmTarget* allbuild =
+ mf->AddUtilityCommand("ALL_BUILD", true, no_depends, no_working_directory,
+ "echo", "Build all projects");
+
+ cmGeneratorTarget* allBuildGt = new cmGeneratorTarget(allbuild, root);
+ root->AddGeneratorTarget(allBuildGt);
+
+ // Refer to the main build configuration file for easy editing.
+ std::string listfile = root->GetCurrentSourceDirectory();
+ listfile += "/";
+ listfile += "CMakeLists.txt";
+ allBuildGt->AddSource(listfile.c_str());
+
+ // Add XCODE depend helper
+ std::string dir = root->GetCurrentBinaryDirectory();
+ cmCustomCommandLine makeHelper;
+ if (this->XcodeVersion < 50) {
+ makeHelper.push_back("make");
+ makeHelper.push_back("-C");
+ makeHelper.push_back(dir.c_str());
+ makeHelper.push_back("-f");
+ makeHelper.push_back(this->CurrentXCodeHackMakefile.c_str());
+ makeHelper.push_back(""); // placeholder, see below
+ }
+
+ // Add ZERO_CHECK
+ bool regenerate = !mf->IsOn("CMAKE_SUPPRESS_REGENERATION");
+ if (regenerate) {
+ this->CreateReRunCMakeFile(root, gens);
+ std::string file =
+ this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile.c_str());
+ cmSystemTools::ReplaceString(file, "\\ ", " ");
+ cmTarget* check =
+ mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, true, no_depends,
+ no_working_directory, "make", "-f", file.c_str());
+
+ cmGeneratorTarget* checkGt = new cmGeneratorTarget(check, root);
+ root->AddGeneratorTarget(checkGt);
+ }
+
+ // now make the allbuild depend on all the non-utility targets
+ // in the project
+ for (std::vector<cmLocalGenerator*>::iterator i = gens.begin();
+ i != gens.end(); ++i) {
+ cmLocalGenerator* lg = *i;
+ if (this->IsExcluded(root, *i)) {
+ continue;
+ }
+
+ std::vector<cmGeneratorTarget*> tgts = lg->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator l = tgts.begin();
+ l != tgts.end(); l++) {
+ cmGeneratorTarget* target = *l;
+
+ if (target->GetType() == cmState::GLOBAL_TARGET) {
+ continue;
+ }
+
+ std::string targetName = target->GetName();
+
+ if (regenerate && (targetName != CMAKE_CHECK_BUILD_SYSTEM_TARGET)) {
+ target->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET);
+ }
+
+ // make all exe, shared libs and modules
+ // 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 (!makeHelper.empty() &&
+ (target->GetType() == cmState::EXECUTABLE ||
+ // Nope - no post-build for OBJECT_LIRBRARY
+ // target->GetType() == cmState::OBJECT_LIBRARY ||
+ target->GetType() == cmState::STATIC_LIBRARY ||
+ target->GetType() == cmState::SHARED_LIBRARY ||
+ target->GetType() == cmState::MODULE_LIBRARY)) {
+ makeHelper[makeHelper.size() - 1] = // fill placeholder
+ this->PostBuildMakeTarget(target->GetName(), "$(CONFIGURATION)");
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(makeHelper);
+ std::vector<std::string> no_byproducts;
+ lg->GetMakefile()->AddCustomCommandToTarget(
+ target->GetName(), no_byproducts, no_depends, commandLines,
+ cmTarget::POST_BUILD, "Depend check for xcode", dir.c_str());
+ }
+
+ if (target->GetType() != cmState::INTERFACE_LIBRARY &&
+ !target->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+ allbuild->AddUtility(target->GetName());
+ }
+
+ // Refer to the build configuration file for easy editing.
+ listfile = lg->GetCurrentSourceDirectory();
+ listfile += "/";
+ listfile += "CMakeLists.txt";
+ target->AddSource(listfile.c_str());
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::CreateReRunCMakeFile(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*> const& gens)
+{
+ std::vector<std::string> lfiles;
+ for (std::vector<cmLocalGenerator*>::const_iterator gi = gens.begin();
+ gi != gens.end(); ++gi) {
+ std::vector<std::string> const& lf = (*gi)->GetMakefile()->GetListFiles();
+ lfiles.insert(lfiles.end(), lf.begin(), lf.end());
+ }
+
+ // sort the array
+ std::sort(lfiles.begin(), lfiles.end(), std::less<std::string>());
+ std::vector<std::string>::iterator new_end =
+ std::unique(lfiles.begin(), lfiles.end());
+ lfiles.erase(new_end, lfiles.end());
+ this->CurrentReRunCMakeMakefile = root->GetCurrentBinaryDirectory();
+ this->CurrentReRunCMakeMakefile += "/CMakeScripts";
+ cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile.c_str());
+ this->CurrentReRunCMakeMakefile += "/ReRunCMake.make";
+ cmGeneratedFileStream makefileStream(
+ this->CurrentReRunCMakeMakefile.c_str());
+ makefileStream.SetCopyIfDifferent(true);
+ makefileStream << "# Generated by CMake, DO NOT EDIT\n\n";
+
+ makefileStream << "empty:= \n";
+ makefileStream << "space:= $(empty) $(empty)\n";
+ makefileStream << "spaceplus:= $(empty)\\ $(empty)\n\n";
+
+ for (std::vector<std::string>::const_iterator i = lfiles.begin();
+ i != lfiles.end(); ++i) {
+ makefileStream << "TARGETS += $(subst $(space),$(spaceplus),$(wildcard "
+ << this->ConvertToRelativeForMake(i->c_str()) << "))\n";
+ }
+
+ std::string checkCache = root->GetBinaryDirectory();
+ checkCache += "/";
+ checkCache += cmake::GetCMakeFilesDirectoryPostSlash();
+ checkCache += "cmake.check_cache";
+
+ makefileStream << "\n"
+ << this->ConvertToRelativeForMake(checkCache.c_str())
+ << ": $(TARGETS)\n";
+ makefileStream << "\t"
+ << this->ConvertToRelativeForMake(
+ cmSystemTools::GetCMakeCommand().c_str())
+ << " -H"
+ << this->ConvertToRelativeForMake(root->GetSourceDirectory())
+ << " -B"
+ << this->ConvertToRelativeForMake(root->GetBinaryDirectory())
+ << "\n";
+}
+
+static bool objectIdLessThan(cmXCodeObject* l, cmXCodeObject* r)
+{
+ return l->GetId() < r->GetId();
+}
+
+void cmGlobalXCodeGenerator::SortXCodeObjects()
+{
+ std::sort(this->XCodeObjects.begin(), this->XCodeObjects.end(),
+ objectIdLessThan);
+}
+
+void cmGlobalXCodeGenerator::ClearXCodeObjects()
+{
+ this->TargetDoneSet.clear();
+ for (unsigned int i = 0; i < this->XCodeObjects.size(); ++i) {
+ delete this->XCodeObjects[i];
+ }
+ this->XCodeObjects.clear();
+ this->XCodeObjectIDs.clear();
+ this->XCodeObjectMap.clear();
+ this->GroupMap.clear();
+ this->GroupNameMap.clear();
+ this->TargetGroup.clear();
+ this->FileRefs.clear();
+}
+
+void cmGlobalXCodeGenerator::addObject(cmXCodeObject* obj)
+{
+ if (obj->GetType() == cmXCodeObject::OBJECT) {
+ std::string id = obj->GetId();
+
+ // If this is a duplicate id, it's an error:
+ //
+ if (this->XCodeObjectIDs.count(id)) {
+ cmSystemTools::Error(
+ "Xcode generator: duplicate object ids not allowed");
+ }
+
+ this->XCodeObjectIDs.insert(id);
+ }
+
+ this->XCodeObjects.push_back(obj);
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateObject(
+ cmXCodeObject::PBXType ptype)
+{
+ cmXCodeObject* obj;
+ if (this->XcodeVersion == 15) {
+ obj = new cmXCodeObject(ptype, cmXCodeObject::OBJECT);
+ } else {
+ obj = new cmXCode21Object(ptype, cmXCodeObject::OBJECT);
+ }
+ this->addObject(obj);
+ return obj;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::Type type)
+{
+ cmXCodeObject* obj = new cmXCodeObject(cmXCodeObject::None, type);
+ this->addObject(obj);
+ return obj;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateString(const std::string& s)
+{
+ cmXCodeObject* obj = this->CreateObject(cmXCodeObject::STRING);
+ obj->SetString(s);
+ return obj;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateObjectReference(
+ cmXCodeObject* ref)
+{
+ cmXCodeObject* obj = this->CreateObject(cmXCodeObject::OBJECT_REF);
+ obj->SetObject(ref);
+ return obj;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateFlatClone(cmXCodeObject* orig)
+{
+ cmXCodeObject* obj = this->CreateObject(orig->GetType());
+ obj->CopyAttributes(orig);
+ return obj;
+}
+
+std::string GetGroupMapKeyFromPath(cmGeneratorTarget* target,
+ const std::string& fullpath)
+{
+ std::string key(target->GetName());
+ key += "-";
+ key += fullpath;
+ return key;
+}
+
+std::string GetGroupMapKey(cmGeneratorTarget* target, cmSourceFile* sf)
+{
+ return GetGroupMapKeyFromPath(target, sf->GetFullPath());
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath(
+ const std::string& fullpath, cmGeneratorTarget* target,
+ const std::string& lang, cmSourceFile* sf)
+{
+ // Using a map and the full path guarantees that we will always get the same
+ // fileRef object for any given full path.
+ //
+ cmXCodeObject* fileRef =
+ this->CreateXCodeFileReferenceFromPath(fullpath, target, lang, sf);
+
+ cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
+ buildFile->SetComment(fileRef->GetComment());
+ buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
+
+ return buildFile;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
+ cmLocalGenerator* lg, cmSourceFile* sf, cmGeneratorTarget* gtgt)
+{
+ // Add flags from target and source file properties.
+ std::string flags;
+ const char* srcfmt = sf->GetProperty("Fortran_FORMAT");
+ switch (cmOutputConverter::GetFortranFormat(srcfmt)) {
+ case cmOutputConverter::FortranFormatFixed:
+ flags = "-fixed " + flags;
+ break;
+ case cmOutputConverter::FortranFormatFree:
+ flags = "-free " + flags;
+ break;
+ default:
+ break;
+ }
+ lg->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS"));
+
+ // Add per-source definitions.
+ BuildObjectListOrString flagsBuild(this, false);
+ this->AppendDefines(flagsBuild, sf->GetProperty("COMPILE_DEFINITIONS"),
+ true);
+ if (!flagsBuild.IsEmpty()) {
+ if (!flags.empty()) {
+ flags += ' ';
+ }
+ flags += flagsBuild.GetString();
+ }
+
+ std::string lang = this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
+
+ cmXCodeObject* buildFile =
+ this->CreateXCodeSourceFileFromPath(sf->GetFullPath(), gtgt, lang, sf);
+ cmXCodeObject* fileRef = buildFile->GetObject("fileRef")->GetObject();
+
+ cmXCodeObject* settings = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ settings->AddAttributeIfNotEmpty("COMPILER_FLAGS",
+ this->CreateString(flags));
+
+ // Is this a resource file in this target? Add it to the resources group...
+ //
+
+ cmGeneratorTarget::SourceFileFlags tsFlags =
+ gtgt->GetTargetSourceFileFlags(sf);
+ bool isResource = tsFlags.Type == cmGeneratorTarget::SourceFileTypeResource;
+
+ cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+
+ // Is this a "private" or "public" framework header file?
+ // Set the ATTRIBUTES attribute appropriately...
+ //
+ if (gtgt->IsFrameworkOnApple()) {
+ if (tsFlags.Type == cmGeneratorTarget::SourceFileTypePrivateHeader) {
+ attrs->AddObject(this->CreateString("Private"));
+ isResource = true;
+ } else if (tsFlags.Type == cmGeneratorTarget::SourceFileTypePublicHeader) {
+ attrs->AddObject(this->CreateString("Public"));
+ isResource = true;
+ }
+ }
+
+ // Add user-specified file attributes.
+ const char* extraFileAttributes = sf->GetProperty("XCODE_FILE_ATTRIBUTES");
+ if (extraFileAttributes) {
+ // Expand the list of attributes.
+ std::vector<std::string> attributes;
+ cmSystemTools::ExpandListArgument(extraFileAttributes, attributes);
+
+ // Store the attributes.
+ for (std::vector<std::string>::const_iterator ai = attributes.begin();
+ ai != attributes.end(); ++ai) {
+ attrs->AddObject(this->CreateString(*ai));
+ }
+ }
+
+ settings->AddAttributeIfNotEmpty("ATTRIBUTES", attrs);
+
+ // Add the fileRef to the top level Resources group/folder if it is not
+ // already there.
+ //
+ if (isResource && this->ResourcesGroupChildren &&
+ !this->ResourcesGroupChildren->HasObject(fileRef)) {
+ this->ResourcesGroupChildren->AddObject(fileRef);
+ }
+
+ buildFile->AddAttributeIfNotEmpty("settings", settings);
+ return buildFile;
+}
+
+std::string GetSourcecodeValueFromFileExtension(const std::string& _ext,
+ const std::string& lang,
+ bool& keepLastKnownFileType)
+{
+ std::string ext = cmSystemTools::LowerCase(_ext);
+ std::string sourcecode = "sourcecode";
+
+ if (ext == "o") {
+ sourcecode = "compiled.mach-o.objfile";
+ } else if (ext == "xctest") {
+ sourcecode = "wrapper.cfbundle";
+ } else if (ext == "xib") {
+ keepLastKnownFileType = true;
+ sourcecode = "file.xib";
+ } else if (ext == "storyboard") {
+ keepLastKnownFileType = true;
+ sourcecode = "file.storyboard";
+ } else if (ext == "mm") {
+ sourcecode += ".cpp.objcpp";
+ } else if (ext == "m") {
+ sourcecode += ".c.objc";
+ } else if (ext == "swift") {
+ sourcecode += ".swift";
+ } else if (ext == "plist") {
+ sourcecode += ".text.plist";
+ } else if (ext == "h") {
+ sourcecode += ".c.h";
+ } else if (ext == "hxx" || ext == "hpp" || ext == "txx" || ext == "pch" ||
+ ext == "hh") {
+ sourcecode += ".cpp.h";
+ } else if (ext == "png" || ext == "gif" || ext == "jpg") {
+ keepLastKnownFileType = true;
+ sourcecode = "image";
+ } else if (ext == "txt") {
+ sourcecode += ".text";
+ } else if (lang == "CXX") {
+ sourcecode += ".cpp.cpp";
+ } else if (lang == "C") {
+ sourcecode += ".c.c";
+ } else if (lang == "Fortran") {
+ sourcecode += ".fortran.f90";
+ } else if (lang == "ASM") {
+ sourcecode += ".asm";
+ } else if (ext == "metal") {
+ sourcecode += ".metal";
+ } else if (ext == "mig") {
+ sourcecode += ".mig";
+ }
+ // else
+ // {
+ // // Already specialized above or we leave sourcecode == "sourcecode"
+ // // which is probably the most correct choice. Extensionless headers,
+ // // for example... Or file types unknown to Xcode that do not map to a
+ // // valid explicitFileType value.
+ // }
+
+ return sourcecode;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
+ const std::string& fullpath, cmGeneratorTarget* target,
+ const std::string& lang, cmSourceFile* sf)
+{
+ std::string key = GetGroupMapKeyFromPath(target, fullpath);
+ cmXCodeObject* fileRef = this->FileRefs[key];
+ if (!fileRef) {
+ fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
+ fileRef->SetComment(fullpath);
+ this->FileRefs[key] = fileRef;
+ }
+ cmXCodeObject* group = this->GroupMap[key];
+ cmXCodeObject* children = group->GetObject("children");
+ if (!children->HasObject(fileRef)) {
+ children->AddObject(fileRef);
+ }
+ fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
+
+ bool useLastKnownFileType = false;
+ std::string fileType;
+ if (sf) {
+ if (const char* e = sf->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) {
+ fileType = e;
+ } else if (const char* l = sf->GetProperty("XCODE_LAST_KNOWN_FILE_TYPE")) {
+ useLastKnownFileType = true;
+ fileType = l;
+ }
+ }
+ if (fileType.empty()) {
+ // Compute the extension without leading '.'.
+ std::string ext = cmSystemTools::GetFilenameLastExtension(fullpath);
+ if (!ext.empty()) {
+ ext = ext.substr(1);
+ }
+
+ // If fullpath references a directory, then we need to specify
+ // lastKnownFileType as folder in order for Xcode to be able to
+ // open the contents of the folder.
+ // (Xcode 4.6 does not like explicitFileType=folder).
+ if (cmSystemTools::FileIsDirectory(fullpath.c_str())) {
+ fileType = (ext == "xcassets" ? "folder.assetcatalog" : "folder");
+ useLastKnownFileType = true;
+ } else {
+ fileType =
+ GetSourcecodeValueFromFileExtension(ext, lang, useLastKnownFileType);
+ }
+ }
+
+ fileRef->AddAttribute(useLastKnownFileType ? "lastKnownFileType"
+ : "explicitFileType",
+ 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 name = cmSystemTools::GetFilenameName(path.c_str());
+ const char* sourceTree =
+ (cmSystemTools::FileIsFullPath(path.c_str()) ? "<absolute>"
+ : "SOURCE_ROOT");
+ fileRef->AddAttribute("name", this->CreateString(name));
+ fileRef->AddAttribute("path", this->CreateString(path));
+ fileRef->AddAttribute("sourceTree", this->CreateString(sourceTree));
+ if (this->XcodeVersion == 15) {
+ fileRef->AddAttribute("refType", this->CreateString("4"));
+ }
+ return fileRef;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReference(
+ cmSourceFile* sf, cmGeneratorTarget* target)
+{
+ std::string lang = this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
+
+ return this->CreateXCodeFileReferenceFromPath(sf->GetFullPath(), target,
+ lang, sf);
+}
+
+bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname)
+{
+ if (tname == "ALL_BUILD" || tname == "XCODE_DEPEND_HELPER" ||
+ tname == "install" || tname == "package" || tname == "RUN_TESTS" ||
+ tname == CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
+ if (this->TargetDoneSet.find(tname) != this->TargetDoneSet.end()) {
+ return true;
+ }
+ this->TargetDoneSet.insert(tname);
+ return false;
+ }
+ return false;
+}
+
+void cmGlobalXCodeGenerator::SetCurrentLocalGenerator(cmLocalGenerator* gen)
+{
+ this->CurrentLocalGenerator = gen;
+ this->CurrentMakefile = gen->GetMakefile();
+ std::string outdir = cmSystemTools::CollapseFullPath(
+ this->CurrentLocalGenerator->GetCurrentBinaryDirectory());
+ cmSystemTools::SplitPath(outdir.c_str(),
+ this->CurrentOutputDirectoryComponents);
+
+ // Select the current set of configuration types.
+ this->CurrentConfigurationTypes.clear();
+ this->CurrentMakefile->GetConfigurations(this->CurrentConfigurationTypes);
+ if (this->CurrentConfigurationTypes.empty()) {
+ this->CurrentConfigurationTypes.push_back("");
+ }
+}
+
+struct cmSourceFilePathCompare
+{
+ bool operator()(cmSourceFile* l, cmSourceFile* r)
+ {
+ return l->GetFullPath() < r->GetFullPath();
+ }
+};
+
+struct cmCompareTargets
+{
+ bool operator()(std::string const& a, std::string const& b) const
+ {
+ if (a == "ALL_BUILD") {
+ return true;
+ }
+ if (b == "ALL_BUILD") {
+ return false;
+ }
+ return strcmp(a.c_str(), b.c_str()) < 0;
+ }
+};
+
+bool cmGlobalXCodeGenerator::CreateXCodeTargets(
+ cmLocalGenerator* gen, std::vector<cmXCodeObject*>& targets)
+{
+ this->SetCurrentLocalGenerator(gen);
+ std::vector<cmGeneratorTarget*> tgts =
+ this->CurrentLocalGenerator->GetGeneratorTargets();
+ typedef std::map<std::string, cmGeneratorTarget*, cmCompareTargets>
+ cmSortedTargets;
+ cmSortedTargets sortedTargets;
+ for (std::vector<cmGeneratorTarget*>::iterator l = tgts.begin();
+ l != tgts.end(); l++) {
+ sortedTargets[(*l)->GetName()] = *l;
+ }
+ for (cmSortedTargets::iterator l = sortedTargets.begin();
+ l != sortedTargets.end(); l++) {
+ cmGeneratorTarget* gtgt = l->second;
+
+ std::string targetName = gtgt->GetName();
+
+ // make sure ALL_BUILD, INSTALL, etc are only done once
+ if (this->SpecialTargetEmitted(targetName.c_str())) {
+ continue;
+ }
+
+ if (gtgt->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+
+ if (gtgt->GetType() == cmState::UTILITY ||
+ gtgt->GetType() == cmState::GLOBAL_TARGET) {
+ cmXCodeObject* t = this->CreateUtilityTarget(gtgt);
+ if (!t) {
+ return false;
+ }
+ targets.push_back(t);
+ continue;
+ }
+
+ // organize the sources
+ std::vector<cmSourceFile*> classes;
+ if (!gtgt->GetConfigCommonSourceFiles(classes)) {
+ return false;
+ }
+ std::sort(classes.begin(), classes.end(), cmSourceFilePathCompare());
+
+ gtgt->ComputeObjectMapping();
+
+ std::vector<cmXCodeObject*> externalObjFiles;
+ std::vector<cmXCodeObject*> headerFiles;
+ std::vector<cmXCodeObject*> resourceFiles;
+ std::vector<cmXCodeObject*> sourceFiles;
+ for (std::vector<cmSourceFile*>::const_iterator i = classes.begin();
+ i != classes.end(); ++i) {
+ cmXCodeObject* xsf =
+ this->CreateXCodeSourceFile(this->CurrentLocalGenerator, *i, gtgt);
+ cmXCodeObject* fr = xsf->GetObject("fileRef");
+ cmXCodeObject* filetype = fr->GetObject()->GetObject("explicitFileType");
+
+ cmGeneratorTarget::SourceFileFlags tsFlags =
+ gtgt->GetTargetSourceFileFlags(*i);
+
+ if (filetype && filetype->GetString() == "compiled.mach-o.objfile") {
+ if ((*i)->GetObjectLibrary().empty()) {
+ externalObjFiles.push_back(xsf);
+ }
+ } else if (this->IsHeaderFile(*i) ||
+ (tsFlags.Type ==
+ cmGeneratorTarget::SourceFileTypePrivateHeader) ||
+ (tsFlags.Type ==
+ cmGeneratorTarget::SourceFileTypePublicHeader)) {
+ headerFiles.push_back(xsf);
+ } else if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeResource) {
+ resourceFiles.push_back(xsf);
+ } else if (!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY")) {
+ // Include this file in the build if it has a known language
+ // and has not been listed as an ignored extension for this
+ // generator.
+ if (!this->CurrentLocalGenerator->GetSourceFileLanguage(**i).empty() &&
+ !this->IgnoreFile((*i)->GetExtension().c_str())) {
+ sourceFiles.push_back(xsf);
+ }
+ }
+ }
+
+ 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<std::string> objs;
+ gtgt->UseObjectLibraries(objs, "");
+ for (std::vector<std::string>::const_iterator oi = objs.begin();
+ oi != objs.end(); ++oi) {
+ std::string obj = *oi;
+ cmXCodeObject* xsf =
+ this->CreateXCodeSourceFileFromPath(obj, gtgt, "", 0);
+ externalObjFiles.push_back(xsf);
+ }
+ }
+
+ // some build phases only apply to bundles and/or frameworks
+ bool isFrameworkTarget = gtgt->IsFrameworkOnApple();
+ bool isBundleTarget = gtgt->GetPropertyAsBool("MACOSX_BUNDLE");
+ bool isCFBundleTarget = gtgt->IsCFBundleOnApple();
+
+ cmXCodeObject* buildFiles = 0;
+
+ // create source build phase
+ cmXCodeObject* sourceBuildPhase = 0;
+ if (!sourceFiles.empty()) {
+ sourceBuildPhase =
+ this->CreateObject(cmXCodeObject::PBXSourcesBuildPhase);
+ sourceBuildPhase->SetComment("Sources");
+ sourceBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (std::vector<cmXCodeObject*>::iterator i = sourceFiles.begin();
+ i != sourceFiles.end(); ++i) {
+ buildFiles->AddObject(*i);
+ }
+ sourceBuildPhase->AddAttribute("files", buildFiles);
+ sourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ }
+
+ // create header build phase - only for framework targets
+ cmXCodeObject* headerBuildPhase = 0;
+ if (!headerFiles.empty() && isFrameworkTarget) {
+ headerBuildPhase =
+ this->CreateObject(cmXCodeObject::PBXHeadersBuildPhase);
+ headerBuildPhase->SetComment("Headers");
+ headerBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (std::vector<cmXCodeObject*>::iterator i = headerFiles.begin();
+ i != headerFiles.end(); ++i) {
+ buildFiles->AddObject(*i);
+ }
+ headerBuildPhase->AddAttribute("files", buildFiles);
+ headerBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ }
+
+ // create resource build phase - only for framework or bundle targets
+ cmXCodeObject* resourceBuildPhase = 0;
+ if (!resourceFiles.empty() &&
+ (isFrameworkTarget || isBundleTarget || isCFBundleTarget)) {
+ resourceBuildPhase =
+ this->CreateObject(cmXCodeObject::PBXResourcesBuildPhase);
+ resourceBuildPhase->SetComment("Resources");
+ resourceBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (std::vector<cmXCodeObject*>::iterator i = resourceFiles.begin();
+ i != resourceFiles.end(); ++i) {
+ buildFiles->AddObject(*i);
+ }
+ resourceBuildPhase->AddAttribute("files", buildFiles);
+ resourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ }
+
+ // create vector of "non-resource content file" build phases - only for
+ // framework or bundle targets
+ std::vector<cmXCodeObject*> contentBuildPhases;
+ if (isFrameworkTarget || isBundleTarget || isCFBundleTarget) {
+ typedef std::map<std::string, std::vector<cmSourceFile*> >
+ mapOfVectorOfSourceFiles;
+ mapOfVectorOfSourceFiles bundleFiles;
+ for (std::vector<cmSourceFile*>::const_iterator i = classes.begin();
+ i != classes.end(); ++i) {
+ cmGeneratorTarget::SourceFileFlags tsFlags =
+ gtgt->GetTargetSourceFileFlags(*i);
+ if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeMacContent) {
+ bundleFiles[tsFlags.MacFolder].push_back(*i);
+ }
+ }
+ mapOfVectorOfSourceFiles::iterator mit;
+ for (mit = bundleFiles.begin(); mit != bundleFiles.end(); ++mit) {
+ cmXCodeObject* copyFilesBuildPhase =
+ this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
+ copyFilesBuildPhase->SetComment("Copy files");
+ copyFilesBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ copyFilesBuildPhase->AddAttribute("dstSubfolderSpec",
+ this->CreateString("6"));
+ std::ostringstream ostr;
+ if (gtgt->IsFrameworkOnApple()) {
+ // dstPath in frameworks is relative to Versions/<version>
+ ostr << mit->first;
+ } else if (mit->first != "MacOS") {
+ // dstPath in bundles is relative to Contents/MacOS
+ ostr << "../" << mit->first.c_str();
+ }
+ copyFilesBuildPhase->AddAttribute("dstPath",
+ this->CreateString(ostr.str()));
+ copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ copyFilesBuildPhase->AddAttribute("files", buildFiles);
+ std::vector<cmSourceFile*>::iterator sfIt;
+ for (sfIt = mit->second.begin(); sfIt != mit->second.end(); ++sfIt) {
+ cmXCodeObject* xsf = this->CreateXCodeSourceFile(
+ this->CurrentLocalGenerator, *sfIt, gtgt);
+ buildFiles->AddObject(xsf);
+ }
+ contentBuildPhases.push_back(copyFilesBuildPhase);
+ }
+ }
+
+ // create framework build phase
+ cmXCodeObject* frameworkBuildPhase = 0;
+ if (!externalObjFiles.empty()) {
+ frameworkBuildPhase =
+ this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase);
+ frameworkBuildPhase->SetComment("Frameworks");
+ frameworkBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ frameworkBuildPhase->AddAttribute("files", buildFiles);
+ for (std::vector<cmXCodeObject*>::iterator i = externalObjFiles.begin();
+ i != externalObjFiles.end(); ++i) {
+ buildFiles->AddObject(*i);
+ }
+ frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ }
+
+ // create list of build phases and create the Xcode target
+ cmXCodeObject* buildPhases =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+
+ this->CreateCustomCommands(buildPhases, sourceBuildPhase, headerBuildPhase,
+ resourceBuildPhase, contentBuildPhases,
+ frameworkBuildPhase, gtgt);
+
+ targets.push_back(this->CreateXCodeTarget(gtgt, buildPhases));
+ }
+ return true;
+}
+
+void cmGlobalXCodeGenerator::ForceLinkerLanguages()
+{
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ std::vector<cmGeneratorTarget*> tgts =
+ this->LocalGenerators[i]->GetGeneratorTargets();
+ // All targets depend on the build-system check target.
+ for (std::vector<cmGeneratorTarget*>::const_iterator ti = tgts.begin();
+ ti != tgts.end(); ++ti) {
+ // This makes sure all targets link using the proper language.
+ this->ForceLinkerLanguage(*ti);
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmGeneratorTarget* gtgt)
+{
+ // This matters only for targets that link.
+ if (gtgt->GetType() != cmState::EXECUTABLE &&
+ gtgt->GetType() != cmState::SHARED_LIBRARY &&
+ gtgt->GetType() != cmState::MODULE_LIBRARY) {
+ return;
+ }
+
+ std::string llang = gtgt->GetLinkerLanguage("NOCONFIG");
+ if (llang.empty()) {
+ return;
+ }
+
+ // If the language is compiled as a source trust Xcode to link with it.
+ cmLinkImplementation const* impl = gtgt->GetLinkImplementation("NOCONFIG");
+ for (std::vector<std::string>::const_iterator li = impl->Languages.begin();
+ li != impl->Languages.end(); ++li) {
+ if (*li == llang) {
+ return;
+ }
+ }
+
+ // Add an empty source file to the target that compiles with the
+ // linker language. This should convince Xcode to choose the proper
+ // language.
+ cmMakefile* mf = gtgt->Target->GetMakefile();
+ std::string fname = gtgt->GetLocalGenerator()->GetCurrentBinaryDirectory();
+ fname += cmake::GetCMakeFilesDirectory();
+ fname += "/";
+ fname += gtgt->GetName();
+ fname += "-CMakeForceLinker";
+ fname += ".";
+ fname += cmSystemTools::LowerCase(llang);
+ {
+ cmGeneratedFileStream fout(fname.c_str());
+ fout << "\n";
+ }
+ if (cmSourceFile* sf = mf->GetOrCreateSource(fname.c_str())) {
+ sf->SetProperty("LANGUAGE", llang.c_str());
+ gtgt->AddSource(fname);
+ }
+}
+
+bool cmGlobalXCodeGenerator::IsHeaderFile(cmSourceFile* sf)
+{
+ const std::vector<std::string>& hdrExts =
+ this->CMakeInstance->GetHeaderExtensions();
+ return (std::find(hdrExts.begin(), hdrExts.end(), sf->GetExtension()) !=
+ hdrExts.end());
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateBuildPhase(
+ const char* name, const char* name2, cmGeneratorTarget* target,
+ const std::vector<cmCustomCommand>& commands)
+{
+ if (commands.size() == 0 && strcmp(name, "CMake ReRun") != 0) {
+ return 0;
+ }
+ cmXCodeObject* buildPhase =
+ this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
+ buildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ buildPhase->AddAttribute("files", buildFiles);
+ buildPhase->AddAttribute("name", this->CreateString(name));
+ buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ buildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
+ this->AddCommandsToBuildPhase(buildPhase, target, commands, name2);
+ return buildPhase;
+}
+
+void cmGlobalXCodeGenerator::CreateCustomCommands(
+ cmXCodeObject* buildPhases, cmXCodeObject* sourceBuildPhase,
+ cmXCodeObject* headerBuildPhase, cmXCodeObject* resourceBuildPhase,
+ std::vector<cmXCodeObject*> contentBuildPhases,
+ cmXCodeObject* frameworkBuildPhase, cmGeneratorTarget* gtgt)
+{
+ std::vector<cmCustomCommand> const& prebuild = gtgt->GetPreBuildCommands();
+ std::vector<cmCustomCommand> const& prelink = gtgt->GetPreLinkCommands();
+ std::vector<cmCustomCommand> postbuild = gtgt->GetPostBuildCommands();
+
+ if (gtgt->GetType() == cmState::SHARED_LIBRARY &&
+ !gtgt->IsFrameworkOnApple()) {
+ cmCustomCommandLines cmd;
+ cmd.resize(1);
+ cmd[0].push_back(cmSystemTools::GetCMakeCommand());
+ cmd[0].push_back("-E");
+ cmd[0].push_back("cmake_symlink_library");
+ std::string str_file = "$<TARGET_FILE:";
+ str_file += gtgt->GetName();
+ str_file += ">";
+ std::string str_so_file = "$<TARGET_SONAME_FILE:";
+ str_so_file += gtgt->GetName();
+ str_so_file += ">";
+ std::string str_link_file = "$<TARGET_LINKER_FILE:";
+ str_link_file += gtgt->GetName();
+ str_link_file += ">";
+ cmd[0].push_back(str_file);
+ cmd[0].push_back(str_so_file);
+ cmd[0].push_back(str_link_file);
+
+ cmCustomCommand command(this->CurrentMakefile, std::vector<std::string>(),
+ std::vector<std::string>(),
+ std::vector<std::string>(), cmd,
+ "Creating symlinks", "");
+
+ postbuild.push_back(command);
+ }
+
+ std::vector<cmSourceFile*> classes;
+ if (!gtgt->GetConfigCommonSourceFiles(classes)) {
+ return;
+ }
+ // add all the sources
+ std::vector<cmCustomCommand> commands;
+ for (std::vector<cmSourceFile*>::const_iterator i = classes.begin();
+ i != classes.end(); ++i) {
+ if ((*i)->GetCustomCommand()) {
+ commands.push_back(*(*i)->GetCustomCommand());
+ }
+ }
+ // create prebuild phase
+ cmXCodeObject* cmakeRulesBuildPhase = this->CreateBuildPhase(
+ "CMake Rules", "cmakeRulesBuildPhase", gtgt, commands);
+ // create prebuild phase
+ cmXCodeObject* preBuildPhase = this->CreateBuildPhase(
+ "CMake PreBuild Rules", "preBuildCommands", gtgt, prebuild);
+ // create prelink phase
+ cmXCodeObject* preLinkPhase = this->CreateBuildPhase(
+ "CMake PreLink Rules", "preLinkCommands", gtgt, prelink);
+ // create postbuild phase
+ cmXCodeObject* postBuildPhase = this->CreateBuildPhase(
+ "CMake PostBuild Rules", "postBuildPhase", gtgt, postbuild);
+
+ // The order here is the order they will be built in.
+ // The order "headers, resources, sources" mimics a native project generated
+ // from an xcode template...
+ //
+ if (preBuildPhase) {
+ buildPhases->AddObject(preBuildPhase);
+ }
+ if (cmakeRulesBuildPhase) {
+ buildPhases->AddObject(cmakeRulesBuildPhase);
+ }
+ if (headerBuildPhase) {
+ buildPhases->AddObject(headerBuildPhase);
+ }
+ if (resourceBuildPhase) {
+ buildPhases->AddObject(resourceBuildPhase);
+ }
+ std::vector<cmXCodeObject*>::iterator cit;
+ for (cit = contentBuildPhases.begin(); cit != contentBuildPhases.end();
+ ++cit) {
+ buildPhases->AddObject(*cit);
+ }
+ if (sourceBuildPhase) {
+ buildPhases->AddObject(sourceBuildPhase);
+ }
+ if (preLinkPhase) {
+ buildPhases->AddObject(preLinkPhase);
+ }
+ if (frameworkBuildPhase) {
+ buildPhases->AddObject(frameworkBuildPhase);
+ }
+ if (postBuildPhase) {
+ buildPhases->AddObject(postBuildPhase);
+ }
+}
+
+// This function removes each occurrence of the flag and returns the last one
+// (i.e., the dominant flag in GCC)
+std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag,
+ std::string& flags)
+{
+ std::string retFlag;
+ std::string::size_type lastOccurancePos = flags.rfind(flag);
+ bool saved = false;
+ while (lastOccurancePos != flags.npos) {
+ // increment pos, we use lastOccurancePos to reduce search space on next
+ // inc
+ std::string::size_type pos = lastOccurancePos;
+ if (pos == 0 || flags[pos - 1] == ' ') {
+ while (pos < flags.size() && flags[pos] != ' ') {
+ if (!saved) {
+ retFlag += flags[pos];
+ }
+ flags[pos] = ' ';
+ pos++;
+ }
+ saved = true;
+ }
+ // decrement lastOccurancePos while making sure we don't loop around
+ // and become a very large positive number since size_type is unsigned
+ lastOccurancePos = lastOccurancePos == 0 ? 0 : lastOccurancePos - 1;
+ lastOccurancePos = flags.rfind(flag, lastOccurancePos);
+ }
+ return retFlag;
+}
+
+// This function removes each matching occurrence of the expression and
+// returns the last one (i.e., the dominant flag in GCC)
+std::string cmGlobalXCodeGenerator::ExtractFlagRegex(const char* exp,
+ int matchIndex,
+ std::string& flags)
+{
+ std::string retFlag;
+
+ cmsys::RegularExpression regex(exp);
+ assert(regex.is_valid());
+ if (!regex.is_valid()) {
+ return retFlag;
+ }
+
+ std::string::size_type offset = 0;
+
+ while (regex.find(flags.c_str() + 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;
+
+ offset = startPos + 1;
+
+ retFlag.assign(flags, startPos, size);
+ flags.replace(startPos, size, size, ' ');
+ }
+
+ return retFlag;
+}
+
+//----------------------------------------------------------------------------
+// This function strips off Xcode attributes that do not target the current
+// configuration
+void cmGlobalXCodeGenerator::FilterConfigurationAttribute(
+ std::string const& configName, std::string& attribute)
+{
+ // Handle [variant=<config>] condition explicitly here.
+ std::string::size_type beginVariant = attribute.find("[variant=");
+ if (beginVariant == std::string::npos) {
+ // There is no variant in this attribute.
+ return;
+ }
+
+ std::string::size_type endVariant = attribute.find("]", beginVariant + 9);
+ if (endVariant == std::string::npos) {
+ // There is no terminating bracket.
+ return;
+ }
+
+ // Compare the variant to the configuration.
+ std::string variant =
+ attribute.substr(beginVariant + 9, endVariant - beginVariant - 9);
+ if (variant == configName) {
+ // The variant matches the configuration so use this
+ // attribute but drop the [variant=<config>] condition.
+ attribute.erase(beginVariant, endVariant - beginVariant + 1);
+ } else {
+ // The variant does not match the configuration so
+ // do not use this attribute.
+ attribute.clear();
+ }
+}
+
+void cmGlobalXCodeGenerator::AddCommandsToBuildPhase(
+ cmXCodeObject* buildphase, cmGeneratorTarget* target,
+ std::vector<cmCustomCommand> const& commands, const char* name)
+{
+ std::string dir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory();
+ dir += "/CMakeScripts";
+ cmSystemTools::MakeDirectory(dir.c_str());
+ std::string makefile = dir;
+ makefile += "/";
+ makefile += target->GetName();
+ makefile += "_";
+ makefile += name;
+ makefile += ".make";
+
+ for (std::vector<std::string>::const_iterator currentConfig =
+ this->CurrentConfigurationTypes.begin();
+ currentConfig != this->CurrentConfigurationTypes.end();
+ currentConfig++) {
+ this->CreateCustomRulesMakefile(makefile.c_str(), target, commands,
+ currentConfig->c_str());
+ }
+
+ std::string cdir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory();
+ cdir = this->ConvertToRelativeForMake(cdir.c_str());
+ std::string makecmd = "make -C ";
+ makecmd += cdir;
+ makecmd += " -f ";
+ makecmd +=
+ this->ConvertToRelativeForMake((makefile + "$CONFIGURATION").c_str());
+ makecmd += " all";
+ buildphase->AddAttribute("shellScript", this->CreateString(makecmd));
+ buildphase->AddAttribute("showEnvVarsInLog", this->CreateString("0"));
+}
+
+void cmGlobalXCodeGenerator::CreateCustomRulesMakefile(
+ const char* makefileBasename, cmGeneratorTarget* target,
+ std::vector<cmCustomCommand> const& commands, const std::string& configName)
+{
+ std::string makefileName = makefileBasename;
+ if (this->XcodeVersion > 20) {
+ makefileName += configName;
+ }
+ cmGeneratedFileStream makefileStream(makefileName.c_str());
+ if (!makefileStream) {
+ return;
+ }
+ makefileStream.SetCopyIfDifferent(true);
+ makefileStream << "# Generated by CMake, DO NOT EDIT\n";
+ makefileStream << "# Custom rules for " << target->GetName() << "\n";
+
+ // disable the implicit rules
+ makefileStream << ".SUFFIXES: "
+ << "\n";
+
+ // have all depend on all outputs
+ makefileStream << "all: ";
+ std::map<const cmCustomCommand*, std::string> tname;
+ int count = 0;
+ for (std::vector<cmCustomCommand>::const_iterator i = commands.begin();
+ i != commands.end(); ++i) {
+ cmCustomCommandGenerator ccg(*i, configName, this->CurrentLocalGenerator);
+ if (ccg.GetNumberOfCommands() > 0) {
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ if (!outputs.empty()) {
+ for (std::vector<std::string>::const_iterator o = outputs.begin();
+ o != outputs.end(); ++o) {
+ makefileStream << "\\\n\t"
+ << this->ConvertToRelativeForMake(o->c_str());
+ }
+ } else {
+ std::ostringstream str;
+ str << "_buildpart_" << count++;
+ tname[&ccg.GetCC()] = std::string(target->GetName()) + str.str();
+ makefileStream << "\\\n\t" << tname[&ccg.GetCC()];
+ }
+ }
+ }
+ makefileStream << "\n\n";
+ for (std::vector<cmCustomCommand>::const_iterator i = commands.begin();
+ i != commands.end(); ++i) {
+ cmCustomCommandGenerator ccg(*i, configName, this->CurrentLocalGenerator);
+ if (ccg.GetNumberOfCommands() > 0) {
+ makefileStream << "\n";
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ if (!outputs.empty()) {
+ // There is at least one output, start the rule for it
+ const char* sep = "";
+ for (std::vector<std::string>::const_iterator oi = outputs.begin();
+ oi != outputs.end(); ++oi) {
+ makefileStream << sep << this->ConvertToRelativeForMake(oi->c_str());
+ sep = " ";
+ }
+ makefileStream << ": ";
+ } else {
+ // There are no outputs. Use the generated force rule name.
+ makefileStream << tname[&ccg.GetCC()] << ": ";
+ }
+ for (std::vector<std::string>::const_iterator d =
+ ccg.GetDepends().begin();
+ d != ccg.GetDepends().end(); ++d) {
+ std::string dep;
+ if (this->CurrentLocalGenerator->GetRealDependency(d->c_str(),
+ configName, dep)) {
+ makefileStream << "\\\n"
+ << this->ConvertToRelativeForMake(dep.c_str());
+ }
+ }
+ makefileStream << "\n";
+
+ if (const char* comment = ccg.GetComment()) {
+ std::string echo_cmd = "echo ";
+ echo_cmd += (this->CurrentLocalGenerator->EscapeForShell(
+ comment, ccg.GetCC().GetEscapeAllowMakeVars()));
+ makefileStream << "\t" << echo_cmd << "\n";
+ }
+
+ // Add each command line to the set of commands.
+ for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
+ // Build the command line in a single string.
+ std::string cmd2 = ccg.GetCommand(c);
+ cmSystemTools::ReplaceString(cmd2, "/./", "/");
+ cmd2 = this->ConvertToRelativeForMake(cmd2.c_str());
+ std::string cmd;
+ std::string wd = ccg.GetWorkingDirectory();
+ if (!wd.empty()) {
+ cmd += "cd ";
+ cmd += this->ConvertToRelativeForMake(wd.c_str());
+ cmd += " && ";
+ }
+ cmd += cmd2;
+ ccg.AppendArguments(c, cmd);
+ makefileStream << "\t" << cmd << "\n";
+ }
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
+ cmXCodeObject* buildSettings,
+ const std::string& configName)
+{
+ if (gtgt->GetType() == cmState::INTERFACE_LIBRARY) {
+ return;
+ }
+
+ std::string defFlags;
+ bool shared = ((gtgt->GetType() == cmState::SHARED_LIBRARY) ||
+ (gtgt->GetType() == cmState::MODULE_LIBRARY));
+ bool binary = ((gtgt->GetType() == cmState::OBJECT_LIBRARY) ||
+ (gtgt->GetType() == cmState::STATIC_LIBRARY) ||
+ (gtgt->GetType() == cmState::EXECUTABLE) || shared);
+
+ // Compute the compilation flags for each language.
+ std::set<std::string> languages;
+ gtgt->GetLanguages(languages, configName);
+ std::map<std::string, std::string> cflags;
+ for (std::set<std::string>::iterator li = languages.begin();
+ li != languages.end(); ++li) {
+ std::string const& lang = *li;
+ std::string& flags = cflags[lang];
+
+ // Add language-specific flags.
+ this->CurrentLocalGenerator->AddLanguageFlags(flags, lang, configName);
+
+ // Add shared-library flags if needed.
+ this->CurrentLocalGenerator->AddCMP0018Flags(flags, gtgt, lang,
+ configName);
+
+ this->CurrentLocalGenerator->AddVisibilityPresetFlags(flags, gtgt, lang);
+
+ this->CurrentLocalGenerator->AddCompileOptions(flags, gtgt, lang,
+ configName);
+ }
+
+ std::string llang = gtgt->GetLinkerLanguage(configName);
+ if (binary && llang.empty()) {
+ cmSystemTools::Error(
+ "CMake can not determine linker language for target: ",
+ gtgt->GetName().c_str());
+ return;
+ }
+
+ // Add define flags
+ this->CurrentLocalGenerator->AppendFlags(
+ defFlags, this->CurrentMakefile->GetDefineFlags());
+
+ // Add preprocessor definitions for this target and configuration.
+ BuildObjectListOrString ppDefs(this, this->XcodeVersion >= 30);
+ if (this->XcodeVersion > 15) {
+ this->AppendDefines(
+ ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"");
+ }
+ if (const char* exportMacro = gtgt->GetExportMacro()) {
+ // Add the export symbol definition for shared library objects.
+ this->AppendDefines(ppDefs, exportMacro);
+ }
+ std::vector<std::string> targetDefines;
+ gtgt->GetCompileDefinitions(targetDefines, configName, "C");
+ this->AppendDefines(ppDefs, targetDefines);
+ buildSettings->AddAttribute("GCC_PREPROCESSOR_DEFINITIONS",
+ ppDefs.CreateList());
+
+ std::string extraLinkOptionsVar;
+ std::string extraLinkOptions;
+ if (gtgt->GetType() == cmState::EXECUTABLE) {
+ extraLinkOptionsVar = "CMAKE_EXE_LINKER_FLAGS";
+ } else if (gtgt->GetType() == cmState::SHARED_LIBRARY) {
+ extraLinkOptionsVar = "CMAKE_SHARED_LINKER_FLAGS";
+ } else if (gtgt->GetType() == cmState::MODULE_LIBRARY) {
+ extraLinkOptionsVar = "CMAKE_MODULE_LINKER_FLAGS";
+ }
+ if (!extraLinkOptionsVar.empty()) {
+ this->CurrentLocalGenerator->AddConfigVariableFlags(
+ extraLinkOptions, extraLinkOptionsVar.c_str(), configName);
+ }
+
+ if (gtgt->GetType() == cmState::OBJECT_LIBRARY ||
+ gtgt->GetType() == cmState::STATIC_LIBRARY) {
+ this->CurrentLocalGenerator->GetStaticLibraryFlags(
+ extraLinkOptions, cmSystemTools::UpperCase(configName), gtgt);
+ } else {
+ const char* targetLinkFlags = gtgt->GetProperty("LINK_FLAGS");
+ if (targetLinkFlags) {
+ this->CurrentLocalGenerator->AppendFlags(extraLinkOptions,
+ targetLinkFlags);
+ }
+ if (!configName.empty()) {
+ std::string linkFlagsVar = "LINK_FLAGS_";
+ linkFlagsVar += cmSystemTools::UpperCase(configName);
+ if (const char* linkFlags = gtgt->GetProperty(linkFlagsVar.c_str())) {
+ this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, linkFlags);
+ }
+ }
+ }
+
+ // Set target-specific architectures.
+ std::vector<std::string> archs;
+ gtgt->GetAppleArchs(configName, archs);
+
+ if (!archs.empty()) {
+ // Enable ARCHS attribute.
+ buildSettings->AddAttribute("ONLY_ACTIVE_ARCH", this->CreateString("NO"));
+
+ // Store ARCHS value.
+ if (archs.size() == 1) {
+ buildSettings->AddAttribute("ARCHS", this->CreateString(archs[0]));
+ } else {
+ cmXCodeObject* archObjects =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (std::vector<std::string>::iterator i = archs.begin();
+ i != archs.end(); i++) {
+ archObjects->AddObject(this->CreateString(*i));
+ }
+ buildSettings->AddAttribute("ARCHS", archObjects);
+ }
+ }
+
+ // Get the product name components.
+ std::string pnprefix;
+ std::string pnbase;
+ std::string pnsuffix;
+ gtgt->GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
+
+ const char* version = gtgt->GetProperty("VERSION");
+ const char* soversion = gtgt->GetProperty("SOVERSION");
+ if (!gtgt->HasSOName(configName) || gtgt->IsFrameworkOnApple()) {
+ version = 0;
+ soversion = 0;
+ }
+ if (version && !soversion) {
+ soversion = version;
+ }
+ if (!version && soversion) {
+ version = soversion;
+ }
+
+ std::string realName = pnbase;
+ std::string soName = pnbase;
+ if (version && soversion) {
+ realName += ".";
+ realName += version;
+ soName += ".";
+ soName += soversion;
+ }
+
+ // Set attributes to specify the proper name for the target.
+ std::string pndir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory();
+ if (gtgt->GetType() == cmState::STATIC_LIBRARY ||
+ gtgt->GetType() == cmState::SHARED_LIBRARY ||
+ gtgt->GetType() == cmState::MODULE_LIBRARY ||
+ gtgt->GetType() == cmState::EXECUTABLE) {
+ if (this->XcodeVersion >= 21) {
+ if (!gtgt->UsesDefaultOutputDir(configName, false)) {
+ std::string pncdir = gtgt->GetDirectory(configName);
+ buildSettings->AddAttribute("CONFIGURATION_BUILD_DIR",
+ this->CreateString(pncdir));
+ }
+ } else {
+ buildSettings->AddAttribute("OBJROOT", this->CreateString(pndir));
+ pndir = gtgt->GetDirectory(configName);
+ }
+
+ if (gtgt->IsFrameworkOnApple() || gtgt->IsCFBundleOnApple()) {
+ pnprefix = "";
+ }
+
+ buildSettings->AddAttribute("EXECUTABLE_PREFIX",
+ this->CreateString(pnprefix));
+ buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
+ this->CreateString(pnsuffix));
+ } else if (gtgt->GetType() == cmState::OBJECT_LIBRARY) {
+ pnprefix = "lib";
+ pnbase = gtgt->GetName();
+ pnsuffix = ".a";
+
+ if (this->XcodeVersion >= 21) {
+ std::string pncdir = this->GetObjectsNormalDirectory(
+ this->CurrentProject, configName, gtgt);
+ buildSettings->AddAttribute("CONFIGURATION_BUILD_DIR",
+ this->CreateString(pncdir));
+ } else {
+ buildSettings->AddAttribute("OBJROOT", this->CreateString(pndir));
+ pndir = this->GetObjectsNormalDirectory(this->CurrentProject, configName,
+ gtgt);
+ }
+ }
+
+ // Store the product name for all target types.
+ buildSettings->AddAttribute("PRODUCT_NAME", this->CreateString(realName));
+ buildSettings->AddAttribute("SYMROOT", this->CreateString(pndir));
+
+ // Handle settings for each target type.
+ switch (gtgt->GetType()) {
+ case cmState::OBJECT_LIBRARY:
+ case cmState::STATIC_LIBRARY: {
+ buildSettings->AddAttribute("LIBRARY_STYLE",
+ this->CreateString("STATIC"));
+ break;
+ }
+
+ case cmState::MODULE_LIBRARY: {
+ buildSettings->AddAttribute("LIBRARY_STYLE",
+ this->CreateString("BUNDLE"));
+ if (gtgt->IsCFBundleOnApple()) {
+ // It turns out that a BUNDLE is basically the same
+ // in many ways as an application bundle, as far as
+ // link flags go
+ std::string createFlags = this->LookupFlags(
+ "CMAKE_SHARED_MODULE_CREATE_", llang, "_FLAGS", "-bundle");
+ if (!createFlags.empty()) {
+ extraLinkOptions += " ";
+ extraLinkOptions += createFlags;
+ }
+ const char* ext = gtgt->GetProperty("BUNDLE_EXTENSION");
+ if (ext) {
+ buildSettings->AddAttribute("WRAPPER_EXTENSION",
+ this->CreateString(ext));
+ }
+ std::string plist = this->ComputeInfoPListLocation(gtgt);
+ // Xcode will create the final version of Info.plist at build time,
+ // so let it replace the cfbundle name. This avoids creating
+ // 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());
+ buildSettings->AddAttribute("INFOPLIST_FILE",
+ this->CreateString(plist));
+ } else if (this->XcodeVersion >= 22) {
+ buildSettings->AddAttribute("MACH_O_TYPE",
+ this->CreateString("mh_bundle"));
+ buildSettings->AddAttribute("GCC_DYNAMIC_NO_PIC",
+ this->CreateString("NO"));
+ // Add the flags to create an executable.
+ std::string createFlags =
+ this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", "");
+ if (!createFlags.empty()) {
+ extraLinkOptions += " ";
+ extraLinkOptions += createFlags;
+ }
+ } else {
+ // Add the flags to create a module.
+ std::string createFlags = this->LookupFlags(
+ "CMAKE_SHARED_MODULE_CREATE_", llang, "_FLAGS", "-bundle");
+ if (!createFlags.empty()) {
+ extraLinkOptions += " ";
+ extraLinkOptions += createFlags;
+ }
+ }
+ break;
+ }
+ case cmState::SHARED_LIBRARY: {
+ if (gtgt->GetPropertyAsBool("FRAMEWORK")) {
+ std::string fw_version = gtgt->GetFrameworkVersion();
+ buildSettings->AddAttribute("FRAMEWORK_VERSION",
+ this->CreateString(fw_version));
+
+ std::string plist = this->ComputeInfoPListLocation(gtgt);
+ // Xcode will create the final version of Info.plist at build time,
+ // 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());
+ buildSettings->AddAttribute("INFOPLIST_FILE",
+ this->CreateString(plist));
+ } else {
+ // Add the flags to create a shared library.
+ std::string createFlags = this->LookupFlags(
+ "CMAKE_SHARED_LIBRARY_CREATE_", llang, "_FLAGS", "-dynamiclib");
+ if (!createFlags.empty()) {
+ extraLinkOptions += " ";
+ extraLinkOptions += createFlags;
+ }
+ }
+
+ buildSettings->AddAttribute("LIBRARY_STYLE",
+ this->CreateString("DYNAMIC"));
+ break;
+ }
+ case cmState::EXECUTABLE: {
+ // Add the flags to create an executable.
+ std::string createFlags =
+ this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", "");
+ if (!createFlags.empty()) {
+ extraLinkOptions += " ";
+ extraLinkOptions += createFlags;
+ }
+
+ // Handle bundles and normal executables separately.
+ if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
+ std::string plist = this->ComputeInfoPListLocation(gtgt);
+ // Xcode will create the final version of Info.plist at build time,
+ // 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());
+ buildSettings->AddAttribute("INFOPLIST_FILE",
+ this->CreateString(plist));
+ }
+ } break;
+ default:
+ break;
+ }
+ if (this->XcodeVersion >= 22 && this->XcodeVersion < 40) {
+ buildSettings->AddAttribute("PREBINDING", this->CreateString("NO"));
+ }
+
+ BuildObjectListOrString dirs(this, this->XcodeVersion >= 30);
+ BuildObjectListOrString fdirs(this, this->XcodeVersion >= 30);
+ std::vector<std::string> includes;
+ this->CurrentLocalGenerator->GetIncludeDirectories(includes, gtgt, "C",
+ configName);
+ std::set<std::string> emitted;
+ emitted.insert("/System/Library/Frameworks");
+ for (std::vector<std::string>::iterator i = includes.begin();
+ i != includes.end(); ++i) {
+ if (this->NameResolvesToFramework(i->c_str())) {
+ std::string frameworkDir = *i;
+ frameworkDir += "/../";
+ frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
+ if (emitted.insert(frameworkDir).second) {
+ fdirs.Add(this->XCodeEscapePath(frameworkDir));
+ }
+ } else {
+ std::string incpath = this->XCodeEscapePath(*i);
+ dirs.Add(incpath);
+ }
+ }
+ // Add framework search paths needed for linking.
+ if (cmComputeLinkInformation* cli = gtgt->GetLinkInformation(configName)) {
+ std::vector<std::string> const& fwDirs = cli->GetFrameworkPaths();
+ for (std::vector<std::string>::const_iterator fdi = fwDirs.begin();
+ fdi != fwDirs.end(); ++fdi) {
+ if (emitted.insert(*fdi).second) {
+ fdirs.Add(this->XCodeEscapePath(*fdi));
+ }
+ }
+ }
+ if (!fdirs.IsEmpty()) {
+ buildSettings->AddAttribute("FRAMEWORK_SEARCH_PATHS", fdirs.CreateList());
+ }
+ if (!dirs.IsEmpty()) {
+ buildSettings->AddAttribute("HEADER_SEARCH_PATHS", dirs.CreateList());
+ }
+
+ bool same_gflags = true;
+ std::map<std::string, std::string> gflags;
+ std::string const* last_gflag = 0;
+ std::string optLevel = "0";
+
+ // Minimal map of flags to build settings.
+ for (std::set<std::string>::iterator li = languages.begin();
+ li != languages.end(); ++li) {
+ std::string& flags = cflags[*li];
+ std::string& gflag = gflags[*li];
+ std::string oflag =
+ this->ExtractFlagRegex("(^| )(-Ofast|-Os|-O[0-9]*)( |$)", 2, flags);
+ if (oflag.size() == 2) {
+ optLevel = "1";
+ } else if (oflag.size() > 2) {
+ optLevel = oflag.substr(2);
+ }
+ gflag = this->ExtractFlag("-g", flags);
+ // put back gdwarf-2 if used since there is no way
+ // to represent it in the gui, but we still want debug yes
+ if (gflag == "-gdwarf-2") {
+ flags += " ";
+ flags += gflag;
+ }
+ if (last_gflag && *last_gflag != gflag) {
+ same_gflags = false;
+ }
+ last_gflag = &gflag;
+ }
+
+ const char* debugStr = "YES";
+ if (!same_gflags) {
+ // We can't set the Xcode flag differently depending on the language,
+ // so put them back in this case.
+ for (std::set<std::string>::iterator li = languages.begin();
+ li != languages.end(); ++li) {
+ cflags[*li] += " ";
+ cflags[*li] += gflags[*li];
+ }
+ debugStr = "NO";
+ } else if (last_gflag && (last_gflag->empty() || *last_gflag == "-g0")) {
+ debugStr = "NO";
+ }
+
+ buildSettings->AddAttribute("COMBINE_HIDPI_IMAGES",
+ this->CreateString("YES"));
+ buildSettings->AddAttribute("GCC_GENERATE_DEBUGGING_SYMBOLS",
+ this->CreateString(debugStr));
+ buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL",
+ this->CreateString(optLevel));
+ buildSettings->AddAttribute("GCC_SYMBOLS_PRIVATE_EXTERN",
+ this->CreateString("NO"));
+ buildSettings->AddAttribute("GCC_INLINES_ARE_PRIVATE_EXTERN",
+ this->CreateString("NO"));
+ for (std::set<std::string>::iterator li = languages.begin();
+ li != languages.end(); ++li) {
+ std::string flags = cflags[*li] + " " + defFlags;
+ if (*li == "CXX") {
+ buildSettings->AddAttribute("OTHER_CPLUSPLUSFLAGS",
+ this->CreateString(flags));
+ } else if (*li == "Fortran") {
+ buildSettings->AddAttribute("IFORT_OTHER_FLAGS",
+ this->CreateString(flags));
+ } else if (*li == "C") {
+ buildSettings->AddAttribute("OTHER_CFLAGS", this->CreateString(flags));
+ }
+ }
+
+ // Add Fortran source format attribute if property is set.
+ const char* format = 0;
+ const char* tgtfmt = gtgt->GetProperty("Fortran_FORMAT");
+ switch (cmOutputConverter::GetFortranFormat(tgtfmt)) {
+ case cmOutputConverter::FortranFormatFixed:
+ format = "fixed";
+ break;
+ case cmOutputConverter::FortranFormatFree:
+ format = "free";
+ break;
+ default:
+ break;
+ }
+ if (format) {
+ buildSettings->AddAttribute("IFORT_LANG_SRCFMT",
+ this->CreateString(format));
+ }
+
+ // Create the INSTALL_PATH attribute.
+ std::string install_name_dir;
+ if (gtgt->GetType() == cmState::SHARED_LIBRARY) {
+ // Get the install_name directory for the build tree.
+ install_name_dir = gtgt->GetInstallNameDirForBuildTree(configName);
+ // Xcode doesn't create the correct install_name in some cases.
+ // That is, if the INSTALL_PATH is empty, or if we have versioning
+ // of dylib libraries, we want to specify the install_name.
+ // This is done by adding a link flag to create an install_name
+ // with just the library soname.
+ std::string install_name;
+ if (!install_name_dir.empty()) {
+ // Convert to a path for the native build tool.
+ cmSystemTools::ConvertToUnixSlashes(install_name_dir);
+ install_name += install_name_dir;
+ install_name += "/";
+ }
+ install_name += gtgt->GetSOName(configName);
+
+ if ((realName != soName) || install_name_dir.empty()) {
+ install_name_dir = "";
+ extraLinkOptions += " -install_name ";
+ extraLinkOptions += XCodeEscapePath(install_name);
+ }
+ }
+ buildSettings->AddAttribute("INSTALL_PATH",
+ this->CreateString(install_name_dir));
+
+ // Create the LD_RUNPATH_SEARCH_PATHS
+ cmComputeLinkInformation* pcli = gtgt->GetLinkInformation(configName);
+ if (pcli) {
+ std::string search_paths;
+ std::vector<std::string> runtimeDirs;
+ pcli->GetRPath(runtimeDirs, false);
+ // runpath dirs needs to be unique to prevent corruption
+ std::set<std::string> unique_dirs;
+
+ for (std::vector<std::string>::const_iterator i = runtimeDirs.begin();
+ i != runtimeDirs.end(); ++i) {
+ std::string runpath = *i;
+ runpath = this->ExpandCFGIntDir(runpath, configName);
+
+ if (unique_dirs.find(runpath) == unique_dirs.end()) {
+ unique_dirs.insert(runpath);
+ if (!search_paths.empty()) {
+ search_paths += " ";
+ }
+ search_paths += this->XCodeEscapePath(runpath);
+ }
+ }
+ if (!search_paths.empty()) {
+ buildSettings->AddAttribute("LD_RUNPATH_SEARCH_PATHS",
+ this->CreateString(search_paths));
+ }
+ }
+
+ buildSettings->AddAttribute(this->GetTargetLinkFlagsVar(gtgt),
+ this->CreateString(extraLinkOptions));
+ buildSettings->AddAttribute("OTHER_REZFLAGS", this->CreateString(""));
+ buildSettings->AddAttribute("SECTORDER_FLAGS", this->CreateString(""));
+ buildSettings->AddAttribute("USE_HEADERMAP", this->CreateString("NO"));
+ if (this->XcodeVersion >= 30) {
+ cmXCodeObject* group = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ group->AddObject(this->CreateString("-Wmost"));
+ group->AddObject(this->CreateString("-Wno-four-char-constants"));
+ group->AddObject(this->CreateString("-Wno-unknown-pragmas"));
+ group->AddObject(this->CreateString("$(inherited)"));
+ buildSettings->AddAttribute("WARNING_CFLAGS", group);
+ } else {
+ buildSettings->AddAttribute(
+ "WARNING_CFLAGS", this->CreateString("-Wmost -Wno-four-char-constants"
+ " -Wno-unknown-pragmas"));
+ }
+
+ // Runtime version information.
+ if (gtgt->GetType() == cmState::SHARED_LIBRARY) {
+ int major;
+ int minor;
+ int patch;
+
+ // VERSION -> current_version
+ gtgt->GetTargetVersion(false, major, minor, patch);
+ std::ostringstream v;
+
+ // Xcode always wants at least 1.0.0 or nothing
+ if (!(major == 0 && minor == 0 && patch == 0)) {
+ v << major << "." << minor << "." << patch;
+ }
+ buildSettings->AddAttribute("DYLIB_CURRENT_VERSION",
+ this->CreateString(v.str()));
+
+ // SOVERSION -> compatibility_version
+ gtgt->GetTargetVersion(true, major, minor, patch);
+ std::ostringstream vso;
+
+ // Xcode always wants at least 1.0.0 or nothing
+ if (!(major == 0 && minor == 0 && patch == 0)) {
+ vso << major << "." << minor << "." << patch;
+ }
+ buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION",
+ this->CreateString(vso.str()));
+ }
+ // put this last so it can override existing settings
+ // Convert "XCODE_ATTRIBUTE_*" properties directly.
+ {
+ std::vector<std::string> const& props = gtgt->GetPropertyKeys();
+ for (std::vector<std::string>::const_iterator i = props.begin();
+ i != props.end(); ++i) {
+ if (i->find("XCODE_ATTRIBUTE_") == 0) {
+ std::string attribute = i->substr(16);
+ this->FilterConfigurationAttribute(configName, attribute);
+ if (!attribute.empty()) {
+ cmGeneratorExpression ge;
+ std::string processed =
+ ge.Parse(gtgt->GetProperty(*i))
+ ->Evaluate(this->CurrentLocalGenerator, configName);
+ buildSettings->AddAttribute(attribute.c_str(),
+ this->CreateString(processed));
+ }
+ }
+ }
+ }
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget(
+ cmGeneratorTarget* gtgt)
+{
+ cmXCodeObject* shellBuildPhase =
+ this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
+ shellBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ shellBuildPhase->AddAttribute("files", buildFiles);
+ cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ shellBuildPhase->AddAttribute("inputPaths", inputPaths);
+ cmXCodeObject* outputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ shellBuildPhase->AddAttribute("outputPaths", outputPaths);
+ shellBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ shellBuildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
+ shellBuildPhase->AddAttribute(
+ "shellScript", this->CreateString("# shell script goes here\nexit 0"));
+ shellBuildPhase->AddAttribute("showEnvVarsInLog", this->CreateString("0"));
+
+ cmXCodeObject* target =
+ this->CreateObject(cmXCodeObject::PBXAggregateTarget);
+ target->SetComment(gtgt->GetName().c_str());
+ cmXCodeObject* buildPhases = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ std::vector<cmXCodeObject*> emptyContentVector;
+ this->CreateCustomCommands(buildPhases, 0, 0, 0, emptyContentVector, 0,
+ gtgt);
+ target->AddAttribute("buildPhases", buildPhases);
+ if (this->XcodeVersion > 20) {
+ this->AddConfigurations(target, gtgt);
+ } else {
+ std::string theConfig =
+ this->CurrentMakefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ cmXCodeObject* buildSettings =
+ this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ this->CreateBuildSettings(gtgt, buildSettings, theConfig);
+ target->AddAttribute("buildSettings", buildSettings);
+ }
+ cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ target->AddAttribute("dependencies", dependencies);
+ target->AddAttribute("name", this->CreateString(gtgt->GetName()));
+ target->AddAttribute("productName", this->CreateString(gtgt->GetName()));
+ target->SetTarget(gtgt);
+ this->XCodeObjectMap[gtgt] = target;
+
+ // Add source files without build rules for editing convenience.
+ if (gtgt->GetType() == cmState::UTILITY) {
+ std::vector<cmSourceFile*> sources;
+ if (!gtgt->GetConfigCommonSourceFiles(sources)) {
+ return 0;
+ }
+
+ for (std::vector<cmSourceFile*>::const_iterator i = sources.begin();
+ i != sources.end(); ++i) {
+ if (!(*i)->GetPropertyAsBool("GENERATED")) {
+ this->CreateXCodeFileReference(*i, gtgt);
+ }
+ }
+ }
+
+ target->SetId(this->GetOrCreateId(gtgt->GetName(), target->GetId()).c_str());
+
+ return target;
+}
+
+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);
+ cmXCodeObject* configlist =
+ this->CreateObject(cmXCodeObject::XCConfigurationList);
+ cmXCodeObject* buildConfigurations =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ configlist->AddAttribute("buildConfigurations", buildConfigurations);
+ std::string comment = "Build configuration list for ";
+ comment += cmXCodeObject::PBXTypeNames[target->GetIsA()];
+ comment += " \"";
+ comment += gtgt->GetName();
+ comment += "\"";
+ configlist->SetComment(comment.c_str());
+ target->AddAttribute("buildConfigurationList",
+ this->CreateObjectReference(configlist));
+ for (unsigned int i = 0; i < configVector.size(); ++i) {
+ cmXCodeObject* config =
+ this->CreateObject(cmXCodeObject::XCBuildConfiguration);
+ buildConfigurations->AddObject(config);
+ cmXCodeObject* buildSettings =
+ this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ this->CreateBuildSettings(gtgt, buildSettings, configVector[i].c_str());
+ config->AddAttribute("name", this->CreateString(configVector[i]));
+ config->SetComment(configVector[i].c_str());
+ config->AddAttribute("buildSettings", buildSettings);
+ }
+ if (!configVector.empty()) {
+ configlist->AddAttribute("defaultConfigurationName",
+ this->CreateString(configVector[0]));
+ configlist->AddAttribute("defaultConfigurationIsVisible",
+ this->CreateString("0"));
+ return configVector[0];
+ }
+ return "";
+}
+
+const char* cmGlobalXCodeGenerator::GetTargetLinkFlagsVar(
+ cmGeneratorTarget const* target) const
+{
+ if (this->XcodeVersion >= 60 &&
+ (target->GetType() == cmState::STATIC_LIBRARY ||
+ target->GetType() == cmState::OBJECT_LIBRARY)) {
+ return "OTHER_LIBTOOLFLAGS";
+ } else {
+ return "OTHER_LDFLAGS";
+ }
+}
+
+const char* cmGlobalXCodeGenerator::GetTargetFileType(
+ cmGeneratorTarget* target)
+{
+ switch (target->GetType()) {
+ case cmState::OBJECT_LIBRARY:
+ case cmState::STATIC_LIBRARY:
+ return "archive.ar";
+ case cmState::MODULE_LIBRARY:
+ if (target->IsXCTestOnApple())
+ return "wrapper.cfbundle";
+ else if (target->IsCFBundleOnApple())
+ return "wrapper.plug-in";
+ else
+ return ((this->XcodeVersion >= 22) ? "compiled.mach-o.executable"
+ : "compiled.mach-o.dylib");
+ case cmState::SHARED_LIBRARY:
+ return (target->GetPropertyAsBool("FRAMEWORK")
+ ? "wrapper.framework"
+ : "compiled.mach-o.dylib");
+ case cmState::EXECUTABLE:
+ return "compiled.mach-o.executable";
+ default:
+ break;
+ }
+ return 0;
+}
+
+const char* cmGlobalXCodeGenerator::GetTargetProductType(
+ cmGeneratorTarget* target)
+{
+ switch (target->GetType()) {
+ case cmState::OBJECT_LIBRARY:
+ case cmState::STATIC_LIBRARY:
+ return "com.apple.product-type.library.static";
+ case cmState::MODULE_LIBRARY:
+ if (target->IsXCTestOnApple())
+ return "com.apple.product-type.bundle.unit-test";
+ else if (target->IsCFBundleOnApple())
+ return "com.apple.product-type.bundle";
+ else
+ return ((this->XcodeVersion >= 22)
+ ? "com.apple.product-type.tool"
+ : "com.apple.product-type.library.dynamic");
+ case cmState::SHARED_LIBRARY:
+ return (target->GetPropertyAsBool("FRAMEWORK")
+ ? "com.apple.product-type.framework"
+ : "com.apple.product-type.library.dynamic");
+ case cmState::EXECUTABLE:
+ return (target->GetPropertyAsBool("MACOSX_BUNDLE")
+ ? "com.apple.product-type.application"
+ : "com.apple.product-type.tool");
+ default:
+ break;
+ }
+ return 0;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeTarget(
+ cmGeneratorTarget* gtgt, cmXCodeObject* buildPhases)
+{
+ if (gtgt->GetType() == cmState::INTERFACE_LIBRARY) {
+ return 0;
+ }
+ cmXCodeObject* target = this->CreateObject(cmXCodeObject::PBXNativeTarget);
+ target->AddAttribute("buildPhases", buildPhases);
+ cmXCodeObject* buildRules = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ target->AddAttribute("buildRules", buildRules);
+ std::string defConfig;
+ if (this->XcodeVersion > 20) {
+ defConfig = this->AddConfigurations(target, gtgt);
+ } else {
+ cmXCodeObject* buildSettings =
+ this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ defConfig = this->CurrentMakefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ this->CreateBuildSettings(gtgt, buildSettings, defConfig.c_str());
+ target->AddAttribute("buildSettings", buildSettings);
+ }
+ cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ target->AddAttribute("dependencies", dependencies);
+ target->AddAttribute("name", this->CreateString(gtgt->GetName()));
+ target->AddAttribute("productName", this->CreateString(gtgt->GetName()));
+
+ cmXCodeObject* fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
+ if (const char* fileType = this->GetTargetFileType(gtgt)) {
+ fileRef->AddAttribute("explicitFileType", this->CreateString(fileType));
+ }
+ std::string fullName;
+ if (gtgt->GetType() == cmState::OBJECT_LIBRARY) {
+ fullName = "lib";
+ fullName += gtgt->GetName();
+ fullName += ".a";
+ } else {
+ fullName = gtgt->GetFullName(defConfig.c_str());
+ }
+ fileRef->AddAttribute("path", this->CreateString(fullName));
+ if (this->XcodeVersion == 15) {
+ fileRef->AddAttribute("refType", this->CreateString("0"));
+ }
+ fileRef->AddAttribute("sourceTree",
+ this->CreateString("BUILT_PRODUCTS_DIR"));
+ fileRef->SetComment(gtgt->GetName().c_str());
+ target->AddAttribute("productReference",
+ this->CreateObjectReference(fileRef));
+ if (const char* productType = this->GetTargetProductType(gtgt)) {
+ target->AddAttribute("productType", this->CreateString(productType));
+ }
+ target->SetTarget(gtgt);
+ this->XCodeObjectMap[gtgt] = target;
+ target->SetId(this->GetOrCreateId(gtgt->GetName(), target->GetId()).c_str());
+ return target;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::FindXCodeTarget(
+ cmGeneratorTarget const* t)
+{
+ if (!t) {
+ return 0;
+ }
+
+ std::map<cmGeneratorTarget const*, cmXCodeObject*>::const_iterator const i =
+ this->XCodeObjectMap.find(t);
+ if (i == this->XCodeObjectMap.end()) {
+ return 0;
+ }
+ return i->second;
+}
+
+std::string cmGlobalXCodeGenerator::GetOrCreateId(const std::string& name,
+ const std::string& id)
+{
+ std::string guidStoreName = name;
+ guidStoreName += "_GUID_CMAKE";
+ const char* storedGUID =
+ this->CMakeInstance->GetCacheDefinition(guidStoreName.c_str());
+
+ if (storedGUID) {
+ return storedGUID;
+ }
+
+ this->CMakeInstance->AddCacheEntry(guidStoreName.c_str(), id.c_str(),
+ "Stored Xcode object GUID",
+ cmState::INTERNAL);
+
+ return id;
+}
+
+void cmGlobalXCodeGenerator::AddDependTarget(cmXCodeObject* target,
+ cmXCodeObject* dependTarget)
+{
+ // This is called once for every edge in the target dependency graph.
+ cmXCodeObject* container =
+ this->CreateObject(cmXCodeObject::PBXContainerItemProxy);
+ container->SetComment("PBXContainerItemProxy");
+ container->AddAttribute("containerPortal",
+ this->CreateObjectReference(this->RootObject));
+ container->AddAttribute("proxyType", this->CreateString("1"));
+ container->AddAttribute("remoteGlobalIDString",
+ this->CreateObjectReference(dependTarget));
+ container->AddAttribute(
+ "remoteInfo", this->CreateString(dependTarget->GetTarget()->GetName()));
+ cmXCodeObject* targetdep =
+ this->CreateObject(cmXCodeObject::PBXTargetDependency);
+ targetdep->SetComment("PBXTargetDependency");
+ targetdep->AddAttribute("target", this->CreateObjectReference(dependTarget));
+ targetdep->AddAttribute("targetProxy",
+ this->CreateObjectReference(container));
+
+ cmXCodeObject* depends = target->GetObject("dependencies");
+ if (!depends) {
+ cmSystemTools::Error(
+ "target does not have dependencies attribute error..");
+
+ } else {
+ depends->AddUniqueObject(targetdep);
+ }
+}
+
+void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings,
+ const char* attribute,
+ const char* value)
+{
+ if (settings) {
+ cmXCodeObject* attr = settings->GetObject(attribute);
+ if (!attr) {
+ settings->AddAttribute(attribute, this->CreateString(value));
+ } else {
+ std::string oldValue = attr->GetString();
+ oldValue += " ";
+ oldValue += value;
+ attr->SetString(oldValue.c_str());
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::AppendBuildSettingAttribute(
+ cmXCodeObject* target, const char* attribute, const char* value,
+ const std::string& configName)
+{
+ if (this->XcodeVersion < 21) {
+ // There is only one configuration. Add the setting to the buildSettings
+ // of the target.
+ this->AppendOrAddBuildSetting(target->GetObject("buildSettings"),
+ attribute, value);
+ } else {
+ // There are multiple configurations. Add the setting to the
+ // buildSettings of the configuration name given.
+ cmXCodeObject* configurationList =
+ target->GetObject("buildConfigurationList")->GetObject();
+ cmXCodeObject* buildConfigs =
+ configurationList->GetObject("buildConfigurations");
+ std::vector<cmXCodeObject*> list = buildConfigs->GetObjectList();
+ // each configuration and the target itself has a buildSettings in it
+ // list.push_back(target);
+ for (std::vector<cmXCodeObject*>::iterator i = list.begin();
+ i != list.end(); ++i) {
+ if (!configName.empty()) {
+ if ((*i)->GetObject("name")->GetString() == configName) {
+ cmXCodeObject* settings = (*i)->GetObject("buildSettings");
+ this->AppendOrAddBuildSetting(settings, attribute, value);
+ }
+ } else {
+ cmXCodeObject* settings = (*i)->GetObject("buildSettings");
+ this->AppendOrAddBuildSetting(settings, attribute, value);
+ }
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
+{
+ cmGeneratorTarget* gt = target->GetTarget();
+ if (!gt) {
+ cmSystemTools::Error("Error no target on xobject\n");
+ return;
+ }
+ if (gt->GetType() == cmState::INTERFACE_LIBRARY) {
+ return;
+ }
+
+ // Add dependencies on other CMake targets.
+ TargetDependSet const& deps = this->GetTargetDirectDepends(gt);
+ for (TargetDependSet::const_iterator i = deps.begin(); i != deps.end();
+ ++i) {
+ if (cmXCodeObject* dptarget = this->FindXCodeTarget(*i)) {
+ this->AddDependTarget(target, dptarget);
+ }
+ }
+
+ // Loop over configuration types and set per-configuration info.
+ for (std::vector<std::string>::iterator i =
+ this->CurrentConfigurationTypes.begin();
+ i != this->CurrentConfigurationTypes.end(); ++i) {
+ // Get the current configuration name.
+ std::string configName = *i;
+
+ if (this->XcodeVersion >= 50) {
+ // Add object library contents as link flags.
+ std::string linkObjs;
+ const char* sep = "";
+ std::vector<std::string> objs;
+ gt->UseObjectLibraries(objs, "");
+ for (std::vector<std::string>::const_iterator oi = objs.begin();
+ oi != objs.end(); ++oi) {
+ linkObjs += sep;
+ sep = " ";
+ linkObjs += this->XCodeEscapePath(*oi);
+ }
+ this->AppendBuildSettingAttribute(
+ target, this->GetTargetLinkFlagsVar(gt), linkObjs.c_str(), configName);
+ }
+
+ // Skip link information for object libraries.
+ if (gt->GetType() == cmState::OBJECT_LIBRARY ||
+ gt->GetType() == cmState::STATIC_LIBRARY) {
+ continue;
+ }
+
+ // Compute the link library and directory information.
+ cmComputeLinkInformation* pcli = gt->GetLinkInformation(configName);
+ if (!pcli) {
+ continue;
+ }
+ cmComputeLinkInformation& cli = *pcli;
+
+ // Add dependencies directly on library files.
+ {
+ std::vector<std::string> const& libDeps = cli.GetDepends();
+ for (std::vector<std::string>::const_iterator j = libDeps.begin();
+ j != libDeps.end(); ++j) {
+ target->AddDependLibrary(configName, j->c_str());
+ }
+ }
+
+ // add the library search paths
+ {
+ std::vector<std::string> const& libDirs = cli.GetDirectories();
+ std::string linkDirs;
+ for (std::vector<std::string>::const_iterator libDir = libDirs.begin();
+ libDir != libDirs.end(); ++libDir) {
+ if (libDir->size() && *libDir != "/usr/lib") {
+ if (this->XcodeVersion > 15) {
+ // Now add the same one but append
+ // $(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) to it:
+ linkDirs += " ";
+ linkDirs += this->XCodeEscapePath(
+ *libDir + "/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)");
+ }
+ linkDirs += " ";
+ linkDirs += this->XCodeEscapePath(*libDir);
+ }
+ }
+ this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
+ linkDirs.c_str(), configName);
+ }
+
+ // now add the link libraries
+ {
+ std::string linkLibs;
+ const char* sep = "";
+ typedef cmComputeLinkInformation::ItemVector ItemVector;
+ ItemVector const& libNames = cli.GetItems();
+ for (ItemVector::const_iterator li = libNames.begin();
+ li != libNames.end(); ++li) {
+ linkLibs += sep;
+ sep = " ";
+ if (li->IsPath) {
+ linkLibs += this->XCodeEscapePath(li->Value);
+ } else if (!li->Target ||
+ li->Target->GetType() != cmState::INTERFACE_LIBRARY) {
+ linkLibs += li->Value;
+ }
+ if (li->Target && !li->Target->IsImported()) {
+ target->AddDependTarget(configName, li->Target->GetName());
+ }
+ }
+ this->AppendBuildSettingAttribute(
+ target, this->GetTargetLinkFlagsVar(gt), linkLibs.c_str(), configName);
+ }
+ }
+}
+
+bool cmGlobalXCodeGenerator::CreateGroups(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
+{
+ for (std::vector<cmLocalGenerator*>::iterator i = generators.begin();
+ i != generators.end(); ++i) {
+ if (this->IsExcluded(root, *i)) {
+ continue;
+ }
+ cmMakefile* mf = (*i)->GetMakefile();
+ std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups();
+ std::vector<cmGeneratorTarget*> tgts = (*i)->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator l = tgts.begin();
+ l != tgts.end(); l++) {
+ cmGeneratorTarget* gtgt = *l;
+
+ // Same skipping logic here as in CreateXCodeTargets so that we do not
+ // end up with (empty anyhow) ALL_BUILD and XCODE_DEPEND_HELPER source
+ // groups:
+ //
+ if (gtgt->GetType() == cmState::GLOBAL_TARGET) {
+ continue;
+ }
+ if (gtgt->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+
+ // add the soon to be generated Info.plist file as a source for a
+ // MACOSX_BUNDLE file
+ if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
+ std::string plist = this->ComputeInfoPListLocation(gtgt);
+ mf->GetOrCreateSource(plist, true);
+ gtgt->AddSource(plist);
+ }
+
+ std::vector<cmSourceFile*> classes;
+ if (!gtgt->GetConfigCommonSourceFiles(classes)) {
+ return false;
+ }
+ // Put cmSourceFile instances in proper groups:
+ for (std::vector<cmSourceFile*>::const_iterator s = classes.begin();
+ s != classes.end(); s++) {
+ cmSourceFile* sf = *s;
+ // Add the file to the list of sources.
+ std::string const& source = sf->GetFullPath();
+ cmSourceGroup* sourceGroup =
+ mf->FindSourceGroup(source.c_str(), sourceGroups);
+ cmXCodeObject* pbxgroup = this->CreateOrGetPBXGroup(gtgt, sourceGroup);
+ std::string key = GetGroupMapKey(gtgt, sf);
+ this->GroupMap[key] = pbxgroup;
+ }
+
+ // Put OBJECT_LIBRARY objects in proper groups:
+ std::vector<std::string> objs;
+ gtgt->UseObjectLibraries(objs, "");
+ for (std::vector<std::string>::const_iterator oi = objs.begin();
+ oi != objs.end(); ++oi) {
+ std::string const& source = *oi;
+ cmSourceGroup* sourceGroup =
+ mf->FindSourceGroup(source.c_str(), sourceGroups);
+ cmXCodeObject* pbxgroup = this->CreateOrGetPBXGroup(gtgt, sourceGroup);
+ std::string key = GetGroupMapKeyFromPath(gtgt, source);
+ this->GroupMap[key] = pbxgroup;
+ }
+ }
+ }
+ return true;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreatePBXGroup(cmXCodeObject* parent,
+ std::string name)
+{
+ cmXCodeObject* parentChildren = NULL;
+ if (parent)
+ parentChildren = parent->GetObject("children");
+ cmXCodeObject* group = this->CreateObject(cmXCodeObject::PBXGroup);
+ cmXCodeObject* groupChildren =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ group->AddAttribute("name", this->CreateString(name));
+ group->AddAttribute("children", groupChildren);
+ if (this->XcodeVersion == 15) {
+ group->AddAttribute("refType", this->CreateString("4"));
+ }
+ group->AddAttribute("sourceTree", this->CreateString("<group>"));
+ if (parentChildren)
+ parentChildren->AddObject(group);
+ return group;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateOrGetPBXGroup(
+ cmGeneratorTarget* gtgt, cmSourceGroup* sg)
+{
+ std::string s;
+ std::string target;
+ const char* targetFolder = gtgt->GetProperty("FOLDER");
+ if (targetFolder) {
+ target = targetFolder;
+ target += "/";
+ }
+ target += gtgt->GetName();
+ s = target + "/";
+ s += sg->GetFullName();
+ std::map<std::string, cmXCodeObject*>::iterator it =
+ this->GroupNameMap.find(s);
+ if (it != this->GroupNameMap.end()) {
+ return it->second;
+ }
+
+ it = this->TargetGroup.find(target);
+ cmXCodeObject* tgroup = 0;
+ if (it != this->TargetGroup.end()) {
+ tgroup = it->second;
+ } else {
+ std::vector<std::string> tgt_folders =
+ cmSystemTools::tokenize(target, "/");
+ std::string curr_tgt_folder;
+ for (std::vector<std::string>::size_type i = 0; i < tgt_folders.size();
+ i++) {
+ if (i != 0) {
+ curr_tgt_folder += "/";
+ }
+ curr_tgt_folder += tgt_folders[i];
+ it = this->TargetGroup.find(curr_tgt_folder);
+ if (it != this->TargetGroup.end()) {
+ tgroup = it->second;
+ continue;
+ }
+ tgroup = this->CreatePBXGroup(tgroup, tgt_folders[i]);
+ this->TargetGroup[curr_tgt_folder] = tgroup;
+ if (i == 0) {
+ this->SourcesGroupChildren->AddObject(tgroup);
+ }
+ }
+ }
+ this->TargetGroup[target] = tgroup;
+
+ // If it's the default source group (empty name) then put the source file
+ // directly in the tgroup...
+ //
+ if (std::string(sg->GetFullName()) == "") {
+ this->GroupNameMap[s] = tgroup;
+ return tgroup;
+ }
+
+ // It's a recursive folder structure, let's find the real parent group
+ if (std::string(sg->GetFullName()) != std::string(sg->GetName())) {
+ std::vector<std::string> folders =
+ cmSystemTools::tokenize(sg->GetFullName(), "\\");
+ std::string curr_folder = target;
+ curr_folder += "/";
+ for (std::vector<std::string>::size_type i = 0; i < folders.size(); i++) {
+ curr_folder += folders[i];
+ std::map<std::string, cmXCodeObject*>::iterator i_folder =
+ this->GroupNameMap.find(curr_folder);
+ // Create new folder
+ if (i_folder == this->GroupNameMap.end()) {
+ cmXCodeObject* group = this->CreatePBXGroup(tgroup, folders[i]);
+ this->GroupNameMap[curr_folder] = group;
+ tgroup = group;
+ } else {
+ tgroup = i_folder->second;
+ }
+ curr_folder = curr_folder + "\\";
+ }
+ return tgroup;
+ }
+ cmXCodeObject* group = this->CreatePBXGroup(tgroup, sg->GetName());
+ this->GroupNameMap[s] = group;
+ return group;
+}
+
+bool cmGlobalXCodeGenerator::CreateXCodeObjects(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
+{
+ this->ClearXCodeObjects();
+ this->RootObject = 0;
+ this->SourcesGroupChildren = 0;
+ this->ResourcesGroupChildren = 0;
+ this->MainGroupChildren = 0;
+ cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
+ cmXCodeObject* developBuildStyle =
+ this->CreateObject(cmXCodeObject::PBXBuildStyle);
+ cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ if (this->XcodeVersion == 15) {
+ developBuildStyle->AddAttribute("name", this->CreateString("Development"));
+ developBuildStyle->AddAttribute("buildSettings", group);
+ listObjs->AddObject(developBuildStyle);
+ group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("YES"));
+ cmXCodeObject* deployBuildStyle =
+ this->CreateObject(cmXCodeObject::PBXBuildStyle);
+ deployBuildStyle->AddAttribute("name", this->CreateString("Deployment"));
+ deployBuildStyle->AddAttribute("buildSettings", group);
+ listObjs->AddObject(deployBuildStyle);
+ } else {
+ for (unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i) {
+ cmXCodeObject* buildStyle =
+ this->CreateObject(cmXCodeObject::PBXBuildStyle);
+ const char* name = this->CurrentConfigurationTypes[i].c_str();
+ buildStyle->AddAttribute("name", this->CreateString(name));
+ buildStyle->SetComment(name);
+ cmXCodeObject* sgroup =
+ this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ sgroup->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
+ buildStyle->AddAttribute("buildSettings", sgroup);
+ listObjs->AddObject(buildStyle);
+ }
+ }
+
+ cmXCodeObject* mainGroup = this->CreateObject(cmXCodeObject::PBXGroup);
+ this->MainGroupChildren = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ mainGroup->AddAttribute("children", this->MainGroupChildren);
+ if (this->XcodeVersion == 15) {
+ mainGroup->AddAttribute("refType", this->CreateString("4"));
+ }
+ mainGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
+
+ cmXCodeObject* sourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
+ this->SourcesGroupChildren = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ sourcesGroup->AddAttribute("name", this->CreateString("Sources"));
+ sourcesGroup->AddAttribute("children", this->SourcesGroupChildren);
+ if (this->XcodeVersion == 15) {
+ sourcesGroup->AddAttribute("refType", this->CreateString("4"));
+ }
+ sourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
+ this->MainGroupChildren->AddObject(sourcesGroup);
+
+ cmXCodeObject* resourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
+ this->ResourcesGroupChildren =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ resourcesGroup->AddAttribute("name", this->CreateString("Resources"));
+ resourcesGroup->AddAttribute("children", this->ResourcesGroupChildren);
+ if (this->XcodeVersion == 15) {
+ resourcesGroup->AddAttribute("refType", this->CreateString("4"));
+ }
+ resourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
+ this->MainGroupChildren->AddObject(resourcesGroup);
+
+ // now create the cmake groups
+ if (!this->CreateGroups(root, generators)) {
+ return false;
+ }
+
+ cmXCodeObject* productGroup = this->CreateObject(cmXCodeObject::PBXGroup);
+ productGroup->AddAttribute("name", this->CreateString("Products"));
+ if (this->XcodeVersion == 15) {
+ productGroup->AddAttribute("refType", this->CreateString("4"));
+ }
+ productGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
+ cmXCodeObject* productGroupChildren =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ productGroup->AddAttribute("children", productGroupChildren);
+ this->MainGroupChildren->AddObject(productGroup);
+
+ this->RootObject = this->CreateObject(cmXCodeObject::PBXProject);
+ this->RootObject->SetComment("Project object");
+
+ std::string project_id = "PROJECT_";
+ project_id += root->GetProjectName();
+ this->RootObject->SetId(
+ this->GetOrCreateId(project_id.c_str(), this->RootObject->GetId())
+ .c_str());
+
+ group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ this->RootObject->AddAttribute("mainGroup",
+ this->CreateObjectReference(mainGroup));
+ this->RootObject->AddAttribute("buildSettings", group);
+ this->RootObject->AddAttribute("buildStyles", listObjs);
+ this->RootObject->AddAttribute("hasScannedForEncodings",
+ this->CreateString("0"));
+ if (this->XcodeVersion >= 30) {
+ group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ group->AddAttribute("BuildIndependentTargetsInParallel",
+ this->CreateString("YES"));
+ std::ostringstream v;
+ 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"));
+ }
+ // Point Xcode at the top of the source tree.
+ {
+ std::string pdir =
+ this->RelativeToBinary(root->GetCurrentSourceDirectory());
+ this->RootObject->AddAttribute("projectDirPath", this->CreateString(pdir));
+ this->RootObject->AddAttribute("projectRoot", this->CreateString(""));
+ }
+ cmXCodeObject* configlist =
+ this->CreateObject(cmXCodeObject::XCConfigurationList);
+ cmXCodeObject* buildConfigurations =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ typedef std::vector<std::pair<std::string, cmXCodeObject*> > Configs;
+ Configs configs;
+ const char* defaultConfigName = "Debug";
+ if (this->XcodeVersion == 15) {
+ cmXCodeObject* configDebug =
+ this->CreateObject(cmXCodeObject::XCBuildConfiguration);
+ configDebug->AddAttribute("name", this->CreateString("Debug"));
+ configs.push_back(std::make_pair("Debug", configDebug));
+ cmXCodeObject* configRelease =
+ this->CreateObject(cmXCodeObject::XCBuildConfiguration);
+ configRelease->AddAttribute("name", this->CreateString("Release"));
+ configs.push_back(std::make_pair("Release", configRelease));
+ } else {
+ for (unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i) {
+ const char* name = this->CurrentConfigurationTypes[i].c_str();
+ if (0 == i) {
+ defaultConfigName = name;
+ }
+ cmXCodeObject* config =
+ this->CreateObject(cmXCodeObject::XCBuildConfiguration);
+ config->AddAttribute("name", this->CreateString(name));
+ configs.push_back(std::make_pair(name, config));
+ }
+ }
+ for (Configs::iterator c = configs.begin(); c != configs.end(); ++c) {
+ buildConfigurations->AddObject(c->second);
+ }
+ configlist->AddAttribute("buildConfigurations", buildConfigurations);
+
+ std::string comment = "Build configuration list for PBXProject";
+ comment += " \"";
+ comment += this->CurrentProject;
+ comment += "\"";
+ configlist->SetComment(comment.c_str());
+ configlist->AddAttribute("defaultConfigurationIsVisible",
+ this->CreateString("0"));
+ configlist->AddAttribute("defaultConfigurationName",
+ this->CreateString(defaultConfigName));
+ cmXCodeObject* buildSettings =
+ this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ const char* osxArch =
+ this->CurrentMakefile->GetDefinition("CMAKE_OSX_ARCHITECTURES");
+ const char* sysroot =
+ this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT");
+ const char* deploymentTarget =
+ this->CurrentMakefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
+ std::string archs;
+ if (sysroot) {
+ if (osxArch) {
+ // recompute this as it may have been changed since enable language
+ this->Architectures.clear();
+ cmSystemTools::ExpandListArgument(std::string(osxArch),
+ this->Architectures);
+ archs = cmJoin(this->Architectures, " ");
+ }
+ buildSettings->AddAttribute("SDKROOT", this->CreateString(sysroot));
+ }
+ if (archs.empty()) {
+ // Tell Xcode to use NATIVE_ARCH instead of ARCHS.
+ buildSettings->AddAttribute("ONLY_ACTIVE_ARCH", this->CreateString("YES"));
+ } else {
+ // Tell Xcode to use ARCHS (ONLY_ACTIVE_ARCH defaults to NO).
+ buildSettings->AddAttribute("ARCHS", this->CreateString(archs));
+ }
+ if (deploymentTarget && *deploymentTarget) {
+ buildSettings->AddAttribute("MACOSX_DEPLOYMENT_TARGET",
+ this->CreateString(deploymentTarget));
+ }
+ if (!this->GeneratorToolset.empty()) {
+ buildSettings->AddAttribute("GCC_VERSION",
+ this->CreateString(this->GeneratorToolset));
+ }
+
+ std::string symroot = root->GetCurrentBinaryDirectory();
+ symroot += "/build";
+ buildSettings->AddAttribute("SYMROOT", this->CreateString(symroot));
+
+ for (Configs::iterator i = configs.begin(); i != configs.end(); ++i) {
+ cmXCodeObject* buildSettingsForCfg = this->CreateFlatClone(buildSettings);
+
+ // Put this last so it can override existing settings
+ // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly.
+ std::vector<std::string> vars = this->CurrentMakefile->GetDefinitions();
+ for (std::vector<std::string>::const_iterator d = vars.begin();
+ d != vars.end(); ++d) {
+ if (d->find("CMAKE_XCODE_ATTRIBUTE_") == 0) {
+ std::string attribute = d->substr(22);
+ this->FilterConfigurationAttribute(i->first, attribute);
+ if (!attribute.empty()) {
+ cmGeneratorExpression ge;
+ std::string processed =
+ ge.Parse(this->CurrentMakefile->GetDefinition(*d))
+ ->Evaluate(this->CurrentLocalGenerator, i->first);
+ buildSettingsForCfg->AddAttribute(attribute,
+ this->CreateString(processed));
+ }
+ }
+ }
+ // store per-config buildSettings into configuration object
+ i->second->AddAttribute("buildSettings", buildSettingsForCfg);
+ }
+
+ this->RootObject->AddAttribute("buildConfigurationList",
+ this->CreateObjectReference(configlist));
+
+ std::vector<cmXCodeObject*> targets;
+ for (std::vector<cmLocalGenerator*>::iterator i = generators.begin();
+ i != generators.end(); ++i) {
+ if (!this->IsExcluded(root, *i)) {
+ if (!this->CreateXCodeTargets(*i, targets)) {
+ return false;
+ }
+ }
+ }
+ // loop over all targets and add link and depend info
+ for (std::vector<cmXCodeObject*>::iterator i = targets.begin();
+ i != targets.end(); ++i) {
+ cmXCodeObject* t = *i;
+ this->AddDependAndLinkInformation(t);
+ }
+ if (this->XcodeVersion < 50) {
+ // now create xcode depend hack makefile
+ this->CreateXCodeDependHackTarget(targets);
+ }
+ // now add all targets to the root object
+ cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (std::vector<cmXCodeObject*>::iterator i = targets.begin();
+ i != targets.end(); ++i) {
+ cmXCodeObject* t = *i;
+ allTargets->AddObject(t);
+ cmXCodeObject* productRef = t->GetObject("productReference");
+ if (productRef) {
+ productGroupChildren->AddObject(productRef->GetObject());
+ }
+ }
+ this->RootObject->AddAttribute("targets", allTargets);
+ return true;
+}
+
+std::string cmGlobalXCodeGenerator::GetObjectsNormalDirectory(
+ const std::string& projName, const std::string& configName,
+ const cmGeneratorTarget* t) const
+{
+ std::string dir = t->GetLocalGenerator()->GetCurrentBinaryDirectory();
+ dir += "/";
+ dir += projName;
+ dir += ".build/";
+ dir += configName;
+ dir += "/";
+ dir += t->GetName();
+ dir += ".build/Objects-normal/";
+
+ return dir;
+}
+
+void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
+ std::vector<cmXCodeObject*>& targets)
+{
+ cmGeneratedFileStream makefileStream(this->CurrentXCodeHackMakefile.c_str());
+ if (!makefileStream) {
+ cmSystemTools::Error("Could not create",
+ this->CurrentXCodeHackMakefile.c_str());
+ return;
+ }
+ makefileStream.SetCopyIfDifferent(true);
+ // one more pass for external depend information not handled
+ // correctly by xcode
+ /* clang-format off */
+ makefileStream << "# DO NOT EDIT\n";
+ makefileStream << "# This makefile makes sure all linkable targets are\n";
+ makefileStream << "# up-to-date with anything they link to\n"
+ "default:\n"
+ "\techo \"Do not invoke directly\"\n"
+ "\n";
+ makefileStream
+ << "# For each target create a dummy rule "
+ "so the target does not have to exist\n";
+ /* clang-format on */
+ std::set<std::string> emitted;
+ for (std::vector<cmXCodeObject*>::iterator i = targets.begin();
+ i != targets.end(); ++i) {
+ cmXCodeObject* target = *i;
+ std::map<std::string, cmXCodeObject::StringVec> const& deplibs =
+ target->GetDependLibraries();
+ for (std::map<std::string, cmXCodeObject::StringVec>::const_iterator ci =
+ deplibs.begin();
+ ci != deplibs.end(); ++ci) {
+ for (cmXCodeObject::StringVec::const_iterator d = ci->second.begin();
+ d != ci->second.end(); ++d) {
+ if (emitted.insert(*d).second) {
+ makefileStream << this->ConvertToRelativeForMake(d->c_str())
+ << ":\n";
+ }
+ }
+ }
+ }
+ makefileStream << "\n\n";
+
+ // Write rules to help Xcode relink things at the right time.
+ /* clang-format off */
+ makefileStream <<
+ "# Rules to remove targets that are older than anything to which they\n"
+ "# link. This forces Xcode to relink the targets from scratch. It\n"
+ "# does not seem to check these dependencies itself.\n";
+ /* clang-format on */
+ for (std::vector<std::string>::const_iterator ct =
+ this->CurrentConfigurationTypes.begin();
+ ct != this->CurrentConfigurationTypes.end(); ++ct) {
+ std::string configName = *ct;
+ for (std::vector<cmXCodeObject*>::iterator i = targets.begin();
+ i != targets.end(); ++i) {
+ cmXCodeObject* target = *i;
+ cmGeneratorTarget* gt = target->GetTarget();
+
+ if (gt->GetType() == cmState::EXECUTABLE ||
+ // Nope - no post-build for OBJECT_LIRBRARY
+ // gt->GetType() == cmState::OBJECT_LIBRARY ||
+ gt->GetType() == cmState::STATIC_LIBRARY ||
+ gt->GetType() == cmState::SHARED_LIBRARY ||
+ gt->GetType() == cmState::MODULE_LIBRARY) {
+ // Declare an entry point for the target post-build phase.
+ makefileStream << this->PostBuildMakeTarget(gt->GetName(), *ct)
+ << ":\n";
+ }
+
+ if (gt->GetType() == cmState::EXECUTABLE ||
+ gt->GetType() == cmState::SHARED_LIBRARY ||
+ gt->GetType() == cmState::MODULE_LIBRARY) {
+ std::string tfull = gt->GetFullPath(configName);
+ std::string trel = this->ConvertToRelativeForMake(tfull.c_str());
+
+ // Add this target to the post-build phases of its dependencies.
+ std::map<std::string, cmXCodeObject::StringVec>::const_iterator y =
+ target->GetDependTargets().find(*ct);
+ if (y != target->GetDependTargets().end()) {
+ std::vector<std::string> const& deptgts = y->second;
+ for (std::vector<std::string>::const_iterator d = deptgts.begin();
+ d != deptgts.end(); ++d) {
+ makefileStream << this->PostBuildMakeTarget(*d, *ct) << ": "
+ << trel << "\n";
+ }
+ }
+
+ // Create a rule for this target.
+ makefileStream << trel << ":";
+
+ // List dependencies if any exist.
+ std::map<std::string, cmXCodeObject::StringVec>::const_iterator x =
+ target->GetDependLibraries().find(*ct);
+ if (x != target->GetDependLibraries().end()) {
+ std::vector<std::string> const& deplibs = x->second;
+ for (std::vector<std::string>::const_iterator d = deplibs.begin();
+ d != deplibs.end(); ++d) {
+ makefileStream << "\\\n\t"
+ << this->ConvertToRelativeForMake(d->c_str());
+ }
+ }
+ // Write the action to remove the target if it is out of date.
+ makefileStream << "\n";
+ makefileStream << "\t/bin/rm -f "
+ << this->ConvertToRelativeForMake(tfull.c_str())
+ << "\n";
+ // if building for more than one architecture
+ // then remove those exectuables as well
+ if (this->Architectures.size() > 1) {
+ std::string universal = this->GetObjectsNormalDirectory(
+ this->CurrentProject, configName, gt);
+ for (std::vector<std::string>::iterator arch =
+ this->Architectures.begin();
+ arch != this->Architectures.end(); ++arch) {
+ std::string universalFile = universal;
+ universalFile += *arch;
+ universalFile += "/";
+ universalFile += gt->GetFullName(configName);
+ makefileStream << "\t/bin/rm -f "
+ << this->ConvertToRelativeForMake(
+ universalFile.c_str())
+ << "\n";
+ }
+ }
+ makefileStream << "\n\n";
+ }
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::OutputXCodeProject(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
+{
+ if (generators.size() == 0) {
+ return;
+ }
+ // Skip local generators that are excluded from this project.
+ for (std::vector<cmLocalGenerator*>::iterator g = generators.begin();
+ g != generators.end(); ++g) {
+ if (this->IsExcluded(root, *g)) {
+ continue;
+ }
+ }
+
+ if (!this->CreateXCodeObjects(root, generators)) {
+ return;
+ }
+ std::string xcodeDir = root->GetCurrentBinaryDirectory();
+ xcodeDir += "/";
+ xcodeDir += root->GetProjectName();
+ xcodeDir += ".xcode";
+ if (this->XcodeVersion > 20) {
+ xcodeDir += "proj";
+ }
+ cmSystemTools::MakeDirectory(xcodeDir.c_str());
+ std::string xcodeProjFile = xcodeDir + "/project.pbxproj";
+ cmGeneratedFileStream fout(xcodeProjFile.c_str());
+ fout.SetCopyIfDifferent(true);
+ if (!fout) {
+ return;
+ }
+ this->WriteXCodePBXProj(fout, root, generators);
+ this->ClearXCodeObjects();
+
+ // Since this call may have created new cache entries, save the cache:
+ //
+ root->GetMakefile()->GetCMakeInstance()->SaveCache(
+ root->GetBinaryDirectory());
+}
+
+void cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
+ cmLocalGenerator*,
+ std::vector<cmLocalGenerator*>&)
+{
+ SortXCodeObjects();
+
+ fout << "// !$*UTF8*$!\n";
+ fout << "{\n";
+ cmXCodeObject::Indent(1, fout);
+ fout << "archiveVersion = 1;\n";
+ cmXCodeObject::Indent(1, fout);
+ fout << "classes = {\n";
+ cmXCodeObject::Indent(1, fout);
+ fout << "};\n";
+ cmXCodeObject::Indent(1, fout);
+ if (this->XcodeVersion >= 21) {
+ if (this->XcodeVersion >= 32)
+ fout << "objectVersion = 46;\n";
+ else if (this->XcodeVersion >= 31)
+ fout << "objectVersion = 45;\n";
+ else if (this->XcodeVersion >= 30)
+ fout << "objectVersion = 44;\n";
+ else
+ fout << "objectVersion = 42;\n";
+ cmXCode21Object::PrintList(this->XCodeObjects, fout);
+ } else {
+ fout << "objectVersion = 39;\n";
+ cmXCodeObject::PrintList(this->XCodeObjects, fout);
+ }
+ cmXCodeObject::Indent(1, fout);
+ fout << "rootObject = " << this->RootObject->GetId()
+ << " /* Project object */;\n";
+ fout << "}\n";
+}
+
+const char* cmGlobalXCodeGenerator::GetCMakeCFGIntDir() const
+{
+ return this->XcodeVersion >= 21
+ ? "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"
+ : ".";
+}
+
+std::string cmGlobalXCodeGenerator::ExpandCFGIntDir(
+ const std::string& str, const std::string& config) const
+{
+ std::string replace1 = "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)";
+ std::string replace2 = "$(CONFIGURATION)";
+
+ std::string tmp = str;
+ for (std::string::size_type i = tmp.find(replace1); i != std::string::npos;
+ i = tmp.find(replace1, i)) {
+ tmp.replace(i, replace1.size(), config);
+ i += config.size();
+ }
+ for (std::string::size_type i = tmp.find(replace2); i != std::string::npos;
+ i = tmp.find(replace2, i)) {
+ tmp.replace(i, replace2.size(), config);
+ i += config.size();
+ }
+ return tmp;
+}
+
+void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalXCodeGenerator::GetActualName();
+ entry.Brief = "Generate Xcode project files.";
+}
+
+std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(const char* p)
+{
+ return cmSystemTools::ConvertToOutputPath(p);
+}
+
+std::string cmGlobalXCodeGenerator::RelativeToSource(const char* p)
+{
+ // We force conversion because Xcode breakpoints do not work unless
+ // they are in a file named relative to the source tree.
+ return this->CurrentLocalGenerator->ConvertToRelativePath(
+ this->ProjectSourceDirectoryComponents, p, true);
+}
+
+std::string cmGlobalXCodeGenerator::RelativeToBinary(const char* p)
+{
+ return this->CurrentLocalGenerator->ConvertToRelativePath(
+ this->ProjectOutputDirectoryComponents, p);
+}
+
+std::string cmGlobalXCodeGenerator::XCodeEscapePath(const std::string& p)
+{
+ if (p.find(' ') != p.npos) {
+ std::string t = "\"";
+ t += p;
+ t += "\"";
+ return t;
+ }
+ return p;
+}
+
+void cmGlobalXCodeGenerator::AppendDirectoryForConfig(
+ const std::string& prefix, const std::string& config,
+ const std::string& suffix, std::string& dir)
+{
+ if (this->XcodeVersion > 20) {
+ if (!config.empty()) {
+ dir += prefix;
+ dir += config;
+ dir += suffix;
+ }
+ }
+}
+
+std::string cmGlobalXCodeGenerator::LookupFlags(
+ const std::string& varNamePrefix, const std::string& varNameLang,
+ const std::string& varNameSuffix, const std::string& default_flags)
+{
+ if (!varNameLang.empty()) {
+ std::string varName = varNamePrefix;
+ varName += varNameLang;
+ varName += varNameSuffix;
+ if (const char* varValue =
+ this->CurrentMakefile->GetDefinition(varName.c_str())) {
+ if (*varValue) {
+ return varValue;
+ }
+ }
+ }
+ return default_flags;
+}
+
+void cmGlobalXCodeGenerator::AppendDefines(BuildObjectListOrString& defs,
+ const char* defines_list,
+ bool dflag)
+{
+ // Skip this if there are no definitions.
+ if (!defines_list) {
+ return;
+ }
+
+ // Expand the list of definitions.
+ std::vector<std::string> defines;
+ cmSystemTools::ExpandListArgument(defines_list, defines);
+
+ // Store the definitions in the string.
+ this->AppendDefines(defs, defines, dflag);
+}
+
+void cmGlobalXCodeGenerator::AppendDefines(
+ BuildObjectListOrString& defs, std::vector<std::string> const& defines,
+ bool dflag)
+{
+ // GCC_PREPROCESSOR_DEFINITIONS is a space-separated list of definitions.
+ std::string def;
+ for (std::vector<std::string>::const_iterator di = defines.begin();
+ di != defines.end(); ++di) {
+ // Start with -D if requested.
+ def = dflag ? "-D" : "";
+ def += *di;
+
+ // Append the flag with needed escapes.
+ std::string tmp;
+ this->AppendFlag(tmp, def);
+ defs.Add(tmp);
+ }
+}
+
+void cmGlobalXCodeGenerator::AppendFlag(std::string& flags,
+ std::string const& flag)
+{
+ // Short-circuit for an empty flag.
+ if (flag.empty()) {
+ return;
+ }
+
+ // Separate from previous flags.
+ if (!flags.empty()) {
+ flags += " ";
+ }
+
+ // Check if the flag needs quoting.
+ bool quoteFlag =
+ flag.find_first_of("`~!@#$%^&*()+={}[]|:;\"'<>,.? ") != flag.npos;
+
+ // We escape a flag as follows:
+ // - Place each flag in single quotes ''
+ // - Escape a single quote as \'
+ // - Escape a backslash as \\ since it itself is an escape
+ // Note that in the code below we need one more level of escapes for
+ // C string syntax in this source file.
+ //
+ // The final level of escaping is done when the string is stored
+ // into the project file by cmXCodeObject::PrintString.
+
+ if (quoteFlag) {
+ // Open single quote.
+ flags += "'";
+ }
+
+ // Flag value with escaped quotes and backslashes.
+ for (const char* c = flag.c_str(); *c; ++c) {
+ if (*c == '\'') {
+ if (this->XcodeVersion >= 40) {
+ flags += "'\\''";
+ } else {
+ flags += "\\'";
+ }
+ } else if (*c == '\\') {
+ flags += "\\\\";
+ } else {
+ flags += *c;
+ }
+ }
+
+ if (quoteFlag) {
+ // Close single quote.
+ flags += "'";
+ }
+}
+
+std::string cmGlobalXCodeGenerator::ComputeInfoPListLocation(
+ cmGeneratorTarget* target)
+{
+ std::string plist = target->GetLocalGenerator()->GetCurrentBinaryDirectory();
+ plist += cmake::GetCMakeFilesDirectory();
+ plist += "/";
+ plist += target->GetName();
+ plist += ".dir/Info.plist";
+ return plist;
+}
+
+// Return true if the generated build tree may contain multiple builds.
+// i.e. "Can I build Debug and Release in the same tree?"
+bool cmGlobalXCodeGenerator::IsMultiConfig() const
+{
+ // Old Xcode 1.5 is single config:
+ if (this->XcodeVersion == 15) {
+ return false;
+ }
+
+ // Newer Xcode versions are multi config:
+ return true;
+}
+
+void cmGlobalXCodeGenerator::ComputeTargetObjectDirectory(
+ cmGeneratorTarget* gt) const
+{
+ std::string configName = this->GetCMakeCFGIntDir();
+ std::string dir =
+ this->GetObjectsNormalDirectory("$(PROJECT_NAME)", configName, gt);
+ if (this->XcodeVersion >= 21) {
+ dir += "$(CURRENT_ARCH)/";
+ } else {
+#ifdef __ppc__
+ dir += "ppc/";
+#endif
+#ifdef __i386
+ dir += "i386/";
+#endif
+ }
+ gt->ObjectDirectory = dir;
+}
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
new file mode 100644
index 0000000..0485d4f
--- /dev/null
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -0,0 +1,257 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGlobalXCodeGenerator_h
+#define cmGlobalXCodeGenerator_h
+
+#include "cmGlobalGenerator.h"
+
+#include "cmCustomCommand.h"
+#include "cmXCodeObject.h"
+class cmGlobalGeneratorFactory;
+class cmSourceFile;
+class cmSourceGroup;
+
+/** \class cmGlobalXCodeGenerator
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalXCodeGenerator manages UNIX build process for a tree
+ */
+class cmGlobalXCodeGenerator : public cmGlobalGenerator
+{
+public:
+ cmGlobalXCodeGenerator(cmake* cm, std::string const& version);
+ static cmGlobalGeneratorFactory* NewFactory();
+
+ ///! Get the name for the generator.
+ virtual std::string GetName() const
+ {
+ return cmGlobalXCodeGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "Xcode"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ ///! Create a local generator appropriate to this Global Generator
+ virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf);
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+ /**
+ * Try running cmake and building a file. This is used for dynalically
+ * loaded commands, not as part of the usual build process.
+ */
+ virtual void GenerateBuildCommand(
+ std::vector<std::string>& makeCommand, const std::string& makeProgram,
+ const std::string& projectName, const std::string& projectDir,
+ const std::string& targetName, const std::string& config, bool fast,
+ bool verbose,
+ std::vector<std::string> const& makeOptions = std::vector<std::string>());
+
+ /** Append the subdirectory for the given configuration. */
+ virtual void AppendDirectoryForConfig(const std::string& prefix,
+ const std::string& config,
+ const std::string& suffix,
+ std::string& dir);
+
+ virtual void FindMakeProgram(cmMakefile*);
+
+ ///! What is the configurations directory variable called?
+ virtual const char* GetCMakeCFGIntDir() const;
+ ///! expand CFGIntDir
+ virtual std::string ExpandCFGIntDir(const std::string& str,
+ const std::string& config) const;
+
+ void SetCurrentLocalGenerator(cmLocalGenerator*);
+
+ /** Return true if the generated build tree may contain multiple builds.
+ i.e. "Can I build Debug and Release in the same tree?" */
+ virtual bool IsMultiConfig() const;
+
+ virtual bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf);
+ void AppendFlag(std::string& flags, std::string const& flag);
+
+protected:
+ virtual void AddExtraIDETargets();
+ virtual void Generate();
+
+private:
+ cmXCodeObject* CreateOrGetPBXGroup(cmGeneratorTarget* gtgt,
+ cmSourceGroup* sg);
+ cmXCodeObject* CreatePBXGroup(cmXCodeObject* parent, std::string name);
+ bool CreateGroups(cmLocalGenerator* root,
+ 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 ConvertToRelativeForMake(const char* p);
+ void CreateCustomCommands(cmXCodeObject* buildPhases,
+ cmXCodeObject* sourceBuildPhase,
+ cmXCodeObject* headerBuildPhase,
+ cmXCodeObject* resourceBuildPhase,
+ std::vector<cmXCodeObject*> contentBuildPhases,
+ cmXCodeObject* frameworkBuildPhase,
+ cmGeneratorTarget* gtgt);
+
+ std::string ComputeInfoPListLocation(cmGeneratorTarget* target);
+
+ void AddCommandsToBuildPhase(cmXCodeObject* buildphase,
+ cmGeneratorTarget* target,
+ std::vector<cmCustomCommand> const& commands,
+ const char* commandFileName);
+
+ void CreateCustomRulesMakefile(const char* makefileBasename,
+ cmGeneratorTarget* target,
+ std::vector<cmCustomCommand> const& commands,
+ const std::string& configName);
+
+ cmXCodeObject* FindXCodeTarget(const cmGeneratorTarget*);
+ std::string GetOrCreateId(const std::string& name, const std::string& id);
+
+ // create cmXCodeObject from these functions so that memory can be managed
+ // correctly. All objects created are stored in this->XCodeObjects.
+ cmXCodeObject* CreateObject(cmXCodeObject::PBXType ptype);
+ cmXCodeObject* CreateObject(cmXCodeObject::Type type);
+ cmXCodeObject* CreateString(const std::string& s);
+ cmXCodeObject* CreateObjectReference(cmXCodeObject*);
+ cmXCodeObject* CreateFlatClone(cmXCodeObject*);
+ cmXCodeObject* CreateXCodeTarget(cmGeneratorTarget* gtgt,
+ cmXCodeObject* buildPhases);
+ void ForceLinkerLanguages();
+ void ForceLinkerLanguage(cmGeneratorTarget* gtgt);
+ const char* GetTargetLinkFlagsVar(const cmGeneratorTarget* target) const;
+ const char* GetTargetFileType(cmGeneratorTarget* target);
+ const char* GetTargetProductType(cmGeneratorTarget* target);
+ std::string AddConfigurations(cmXCodeObject* target,
+ cmGeneratorTarget* gtgt);
+ void AppendOrAddBuildSetting(cmXCodeObject* settings, const char* attr,
+ const char* value);
+ void AppendBuildSettingAttribute(cmXCodeObject* target, const char* attr,
+ const char* value,
+ const std::string& configName);
+ cmXCodeObject* CreateUtilityTarget(cmGeneratorTarget* gtgt);
+ void AddDependAndLinkInformation(cmXCodeObject* target);
+ void CreateBuildSettings(cmGeneratorTarget* gtgt,
+ cmXCodeObject* buildSettings,
+ const std::string& buildType);
+ std::string ExtractFlag(const char* flag, std::string& flags);
+ std::string ExtractFlagRegex(const char* exp, int matchIndex,
+ std::string& flags);
+ void FilterConfigurationAttribute(std::string const& configName,
+ std::string& attribute);
+ void SortXCodeObjects();
+ // delete all objects in the this->XCodeObjects vector.
+ void ClearXCodeObjects();
+ bool CreateXCodeObjects(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators);
+ void OutputXCodeProject(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators);
+ void WriteXCodePBXProj(std::ostream& fout, cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators);
+ cmXCodeObject* CreateXCodeFileReferenceFromPath(const std::string& fullpath,
+ cmGeneratorTarget* target,
+ const std::string& lang,
+ cmSourceFile* sf);
+ cmXCodeObject* CreateXCodeSourceFileFromPath(const std::string& fullpath,
+ cmGeneratorTarget* target,
+ const std::string& lang,
+ cmSourceFile* sf);
+ cmXCodeObject* CreateXCodeFileReference(cmSourceFile* sf,
+ cmGeneratorTarget* target);
+ cmXCodeObject* CreateXCodeSourceFile(cmLocalGenerator* gen, cmSourceFile* sf,
+ cmGeneratorTarget* gtgt);
+ bool CreateXCodeTargets(cmLocalGenerator* gen, std::vector<cmXCodeObject*>&);
+ bool IsHeaderFile(cmSourceFile*);
+ void AddDependTarget(cmXCodeObject* target, cmXCodeObject* dependTarget);
+ void CreateXCodeDependHackTarget(std::vector<cmXCodeObject*>& targets);
+ bool SpecialTargetEmitted(std::string const& tname);
+ void SetGenerationRoot(cmLocalGenerator* root);
+ void AddExtraTargets(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& gens);
+ cmXCodeObject* CreateBuildPhase(const char* name, const char* name2,
+ cmGeneratorTarget* target,
+ const std::vector<cmCustomCommand>&);
+ void CreateReRunCMakeFile(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*> const& gens);
+
+ std::string LookupFlags(const std::string& varNamePrefix,
+ const std::string& varNameLang,
+ const std::string& varNameSuffix,
+ const std::string& default_flags);
+
+ class Factory;
+ class BuildObjectListOrString;
+ friend class BuildObjectListOrString;
+
+ void AppendDefines(BuildObjectListOrString& defs, const char* defines_list,
+ bool dflag = false);
+ void AppendDefines(BuildObjectListOrString& defs,
+ std::vector<std::string> const& defines,
+ bool dflag = false);
+
+ void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const;
+
+protected:
+ virtual const char* GetInstallTargetName() const { return "install"; }
+ virtual const char* GetPackageTargetName() const { return "package"; }
+
+ unsigned int XcodeVersion;
+ std::string VersionString;
+ std::set<std::string> XCodeObjectIDs;
+ std::vector<cmXCodeObject*> XCodeObjects;
+ cmXCodeObject* RootObject;
+
+private:
+ std::string const& GetXcodeBuildCommand();
+ std::string FindXcodeBuildCommand();
+ std::string XcodeBuildCommand;
+ bool XcodeBuildCommandInitialized;
+
+ void PrintCompilerAdvice(std::ostream&, std::string const&,
+ const char*) const
+ {
+ }
+
+ std::string GetObjectsNormalDirectory(const std::string& projName,
+ const std::string& configName,
+ const cmGeneratorTarget* t) const;
+
+ void addObject(cmXCodeObject* obj);
+ std::string PostBuildMakeTarget(std::string const& tName,
+ std::string const& configName);
+ cmXCodeObject* MainGroupChildren;
+ cmXCodeObject* SourcesGroupChildren;
+ cmXCodeObject* ResourcesGroupChildren;
+ cmMakefile* CurrentMakefile;
+ cmLocalGenerator* CurrentLocalGenerator;
+ std::vector<std::string> CurrentConfigurationTypes;
+ std::string CurrentReRunCMakeMakefile;
+ std::string CurrentXCodeHackMakefile;
+ std::string CurrentProject;
+ std::set<std::string> TargetDoneSet;
+ std::vector<std::string> CurrentOutputDirectoryComponents;
+ std::vector<std::string> ProjectSourceDirectoryComponents;
+ std::vector<std::string> ProjectOutputDirectoryComponents;
+ std::map<std::string, cmXCodeObject*> GroupMap;
+ std::map<std::string, cmXCodeObject*> GroupNameMap;
+ std::map<std::string, cmXCodeObject*> TargetGroup;
+ std::map<std::string, cmXCodeObject*> FileRefs;
+ std::map<cmGeneratorTarget const*, cmXCodeObject*> XCodeObjectMap;
+ std::vector<std::string> Architectures;
+ std::string GeneratorToolset;
+};
+
+#endif
diff --git a/Source/cmGraphAdjacencyList.h b/Source/cmGraphAdjacencyList.h
new file mode 100644
index 0000000..5666d48
--- /dev/null
+++ b/Source/cmGraphAdjacencyList.h
@@ -0,0 +1,62 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGraphAdjacencyList_h
+#define cmGraphAdjacencyList_h
+
+#include "cmStandardIncludes.h"
+
+/**
+ * Graph edge representation. Most use cases just need the
+ * destination vertex, so we support conversion to/from an int. We
+ * also store boolean to indicate whether an edge is "strong".
+ */
+class cmGraphEdge
+{
+public:
+ cmGraphEdge()
+ : Dest(0)
+ , Strong(true)
+ {
+ }
+ cmGraphEdge(int n)
+ : Dest(n)
+ , Strong(true)
+ {
+ }
+ cmGraphEdge(int n, bool s)
+ : Dest(n)
+ , Strong(s)
+ {
+ }
+ cmGraphEdge(cmGraphEdge const& r)
+ : Dest(r.Dest)
+ , Strong(r.Strong)
+ {
+ }
+ operator int() const { return this->Dest; }
+
+ bool IsStrong() const { return this->Strong; }
+private:
+ int Dest;
+ bool Strong;
+};
+struct cmGraphEdgeList : public std::vector<cmGraphEdge>
+{
+};
+struct cmGraphNodeList : public std::vector<int>
+{
+};
+struct cmGraphAdjacencyList : public std::vector<cmGraphEdgeList>
+{
+};
+
+#endif
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
new file mode 100644
index 0000000..adb9936
--- /dev/null
+++ b/Source/cmGraphVizWriter.cxx
@@ -0,0 +1,512 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGraphVizWriter.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+
+static const char* getShapeForTarget(const cmGeneratorTarget* target)
+{
+ if (!target) {
+ return "ellipse";
+ }
+
+ switch (target->GetType()) {
+ case cmState::EXECUTABLE:
+ return "house";
+ case cmState::STATIC_LIBRARY:
+ return "diamond";
+ case cmState::SHARED_LIBRARY:
+ return "polygon";
+ case cmState::MODULE_LIBRARY:
+ return "octagon";
+ default:
+ break;
+ }
+
+ return "box";
+}
+
+cmGraphVizWriter::cmGraphVizWriter(
+ const std::vector<cmLocalGenerator*>& localGenerators)
+ : GraphType("digraph")
+ , GraphName("GG")
+ , GraphHeader("node [\n fontsize = \"12\"\n];")
+ , GraphNodePrefix("node")
+ , LocalGenerators(localGenerators)
+ , GenerateForExecutables(true)
+ , GenerateForStaticLibs(true)
+ , GenerateForSharedLibs(true)
+ , GenerateForModuleLibs(true)
+ , GenerateForExternals(true)
+ , GeneratePerTarget(true)
+ , GenerateDependers(true)
+ , HaveTargetsAndLibs(false)
+{
+}
+
+void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
+ const char* fallbackSettingsFileName)
+{
+ cmake cm;
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator ggi(&cm);
+ CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(&ggi, cm.GetCurrentSnapshot()));
+ CM_AUTO_PTR<cmLocalGenerator> lg(ggi.CreateLocalGenerator(mf.get()));
+
+ const char* inFileName = settingsFileName;
+
+ if (!cmSystemTools::FileExists(inFileName)) {
+ inFileName = fallbackSettingsFileName;
+ if (!cmSystemTools::FileExists(inFileName)) {
+ return;
+ }
+ }
+
+ if (!mf->ReadListFile(inFileName)) {
+ cmSystemTools::Error("Problem opening GraphViz options file: ",
+ inFileName);
+ return;
+ }
+
+ std::cout << "Reading GraphViz options file: " << inFileName << std::endl;
+
+#define __set_if_set(var, cmakeDefinition) \
+ { \
+ const char* value = mf->GetDefinition(cmakeDefinition); \
+ if (value) { \
+ var = value; \
+ } \
+ }
+
+ __set_if_set(this->GraphType, "GRAPHVIZ_GRAPH_TYPE");
+ __set_if_set(this->GraphName, "GRAPHVIZ_GRAPH_NAME");
+ __set_if_set(this->GraphHeader, "GRAPHVIZ_GRAPH_HEADER");
+ __set_if_set(this->GraphNodePrefix, "GRAPHVIZ_NODE_PREFIX");
+
+#define __set_bool_if_set(var, cmakeDefinition) \
+ { \
+ const char* value = mf->GetDefinition(cmakeDefinition); \
+ if (value) { \
+ var = mf->IsOn(cmakeDefinition); \
+ } \
+ }
+
+ __set_bool_if_set(this->GenerateForExecutables, "GRAPHVIZ_EXECUTABLES");
+ __set_bool_if_set(this->GenerateForStaticLibs, "GRAPHVIZ_STATIC_LIBS");
+ __set_bool_if_set(this->GenerateForSharedLibs, "GRAPHVIZ_SHARED_LIBS");
+ __set_bool_if_set(this->GenerateForModuleLibs, "GRAPHVIZ_MODULE_LIBS");
+ __set_bool_if_set(this->GenerateForExternals, "GRAPHVIZ_EXTERNAL_LIBS");
+ __set_bool_if_set(this->GeneratePerTarget, "GRAPHVIZ_GENERATE_PER_TARGET");
+ __set_bool_if_set(this->GenerateDependers, "GRAPHVIZ_GENERATE_DEPENDERS");
+
+ std::string ignoreTargetsRegexes;
+ __set_if_set(ignoreTargetsRegexes, "GRAPHVIZ_IGNORE_TARGETS");
+
+ this->TargetsToIgnoreRegex.clear();
+ if (!ignoreTargetsRegexes.empty()) {
+ std::vector<std::string> ignoreTargetsRegExVector;
+ cmSystemTools::ExpandListArgument(ignoreTargetsRegexes,
+ ignoreTargetsRegExVector);
+ for (std::vector<std::string>::const_iterator itvIt =
+ ignoreTargetsRegExVector.begin();
+ itvIt != ignoreTargetsRegExVector.end(); ++itvIt) {
+ std::string currentRegexString(*itvIt);
+ cmsys::RegularExpression currentRegex;
+ if (!currentRegex.compile(currentRegexString.c_str())) {
+ std::cerr << "Could not compile bad regex \"" << currentRegexString
+ << "\"" << std::endl;
+ }
+ this->TargetsToIgnoreRegex.push_back(currentRegex);
+ }
+ }
+}
+
+// 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)
+{
+ if (!this->GenerateDependers) {
+ return;
+ }
+
+ this->CollectTargetsAndLibs();
+
+ for (std::map<std::string, const cmGeneratorTarget*>::const_iterator ptrIt =
+ this->TargetPtrs.begin();
+ ptrIt != this->TargetPtrs.end(); ++ptrIt) {
+ if (ptrIt->second == CM_NULLPTR) {
+ continue;
+ }
+
+ if (!this->GenerateForTargetType(ptrIt->second->GetType())) {
+ continue;
+ }
+
+ std::string currentFilename = fileName;
+ currentFilename += ".";
+ currentFilename += ptrIt->first;
+ currentFilename += ".dependers";
+
+ cmGeneratedFileStream str(currentFilename.c_str());
+ if (!str) {
+ return;
+ }
+
+ std::set<std::string> insertedConnections;
+ std::set<std::string> insertedNodes;
+
+ std::cout << "Writing " << currentFilename << "..." << std::endl;
+ this->WriteHeader(str);
+
+ this->WriteDependerConnections(ptrIt->first, insertedNodes,
+ insertedConnections, str);
+
+ this->WriteFooter(str);
+ }
+}
+
+// Iterate over all targets and write for each one a graph which shows
+// on which targets it depends.
+void cmGraphVizWriter::WritePerTargetFiles(const char* fileName)
+{
+ if (!this->GeneratePerTarget) {
+ return;
+ }
+
+ this->CollectTargetsAndLibs();
+
+ for (std::map<std::string, const cmGeneratorTarget*>::const_iterator ptrIt =
+ this->TargetPtrs.begin();
+ ptrIt != this->TargetPtrs.end(); ++ptrIt) {
+ if (ptrIt->second == CM_NULLPTR) {
+ continue;
+ }
+
+ if (!this->GenerateForTargetType(ptrIt->second->GetType())) {
+ continue;
+ }
+
+ std::set<std::string> insertedConnections;
+ std::set<std::string> insertedNodes;
+
+ std::string currentFilename = fileName;
+ currentFilename += ".";
+ currentFilename += ptrIt->first;
+ cmGeneratedFileStream str(currentFilename.c_str());
+ if (!str) {
+ return;
+ }
+
+ std::cout << "Writing " << currentFilename << "..." << std::endl;
+ this->WriteHeader(str);
+
+ this->WriteConnections(ptrIt->first, insertedNodes, insertedConnections,
+ str);
+ this->WriteFooter(str);
+ }
+}
+
+void cmGraphVizWriter::WriteGlobalFile(const char* fileName)
+{
+ this->CollectTargetsAndLibs();
+
+ cmGeneratedFileStream str(fileName);
+ if (!str) {
+ return;
+ }
+ this->WriteHeader(str);
+
+ std::cout << "Writing " << fileName << "..." << std::endl;
+
+ std::set<std::string> insertedConnections;
+ std::set<std::string> insertedNodes;
+
+ for (std::map<std::string, const cmGeneratorTarget*>::const_iterator ptrIt =
+ this->TargetPtrs.begin();
+ ptrIt != this->TargetPtrs.end(); ++ptrIt) {
+ if (ptrIt->second == CM_NULLPTR) {
+ continue;
+ }
+
+ if (!this->GenerateForTargetType(ptrIt->second->GetType())) {
+ continue;
+ }
+
+ this->WriteConnections(ptrIt->first, insertedNodes, insertedConnections,
+ str);
+ }
+ this->WriteFooter(str);
+}
+
+void cmGraphVizWriter::WriteHeader(cmGeneratedFileStream& str) const
+{
+ str << this->GraphType << " \"" << this->GraphName << "\" {" << std::endl;
+ str << this->GraphHeader << std::endl;
+}
+
+void cmGraphVizWriter::WriteFooter(cmGeneratedFileStream& str) const
+{
+ str << "}" << std::endl;
+}
+
+void cmGraphVizWriter::WriteConnections(
+ const std::string& targetName, std::set<std::string>& insertedNodes,
+ std::set<std::string>& insertedConnections, cmGeneratedFileStream& str) const
+{
+ std::map<std::string, const cmGeneratorTarget*>::const_iterator targetPtrIt =
+ this->TargetPtrs.find(targetName);
+
+ if (targetPtrIt == this->TargetPtrs.end()) // not found at all
+ {
+ return;
+ }
+
+ this->WriteNode(targetName, targetPtrIt->second, insertedNodes, str);
+
+ if (targetPtrIt->second == CM_NULLPTR) // it's an external library
+ {
+ return;
+ }
+
+ std::string myNodeName = this->TargetNamesNodes.find(targetName)->second;
+
+ const cmTarget::LinkLibraryVectorType* ll =
+ &(targetPtrIt->second->Target->GetOriginalLinkLibraries());
+
+ for (cmTarget::LinkLibraryVectorType::const_iterator llit = ll->begin();
+ llit != ll->end(); ++llit) {
+ const char* libName = llit->first.c_str();
+ std::map<std::string, std::string>::const_iterator libNameIt =
+ this->TargetNamesNodes.find(libName);
+
+ // can happen e.g. if GRAPHVIZ_TARGET_IGNORE_REGEX is used
+ if (libNameIt == this->TargetNamesNodes.end()) {
+ continue;
+ }
+
+ std::string connectionName = myNodeName;
+ connectionName += "-";
+ connectionName += libNameIt->second;
+ if (insertedConnections.find(connectionName) ==
+ insertedConnections.end()) {
+ insertedConnections.insert(connectionName);
+ this->WriteNode(libName, this->TargetPtrs.find(libName)->second,
+ insertedNodes, str);
+
+ str << " \"" << myNodeName << "\" -> \"" << libNameIt->second << "\"";
+ str << " // " << targetName << " -> " << libName << std::endl;
+ this->WriteConnections(libName, insertedNodes, insertedConnections, str);
+ }
+ }
+}
+
+void cmGraphVizWriter::WriteDependerConnections(
+ const std::string& targetName, std::set<std::string>& insertedNodes,
+ std::set<std::string>& insertedConnections, cmGeneratedFileStream& str) const
+{
+ std::map<std::string, const cmGeneratorTarget*>::const_iterator targetPtrIt =
+ this->TargetPtrs.find(targetName);
+
+ if (targetPtrIt == this->TargetPtrs.end()) // not found at all
+ {
+ return;
+ }
+
+ this->WriteNode(targetName, targetPtrIt->second, insertedNodes, str);
+
+ if (targetPtrIt->second == CM_NULLPTR) // it's an external library
+ {
+ return;
+ }
+
+ std::string myNodeName = this->TargetNamesNodes.find(targetName)->second;
+
+ // now search who links against me
+ for (std::map<std::string, const cmGeneratorTarget*>::const_iterator
+ dependerIt = this->TargetPtrs.begin();
+ dependerIt != this->TargetPtrs.end(); ++dependerIt) {
+ if (dependerIt->second == CM_NULLPTR) {
+ continue;
+ }
+
+ if (!this->GenerateForTargetType(dependerIt->second->GetType())) {
+ continue;
+ }
+
+ // Now we have a target, check whether it links against targetName.
+ // If so, draw a connection, and then continue with dependers on that one.
+ const cmTarget::LinkLibraryVectorType* ll =
+ &(dependerIt->second->Target->GetOriginalLinkLibraries());
+
+ for (cmTarget::LinkLibraryVectorType::const_iterator llit = ll->begin();
+ llit != ll->end(); ++llit) {
+ std::string libName = llit->first;
+ if (libName == targetName) {
+ // So this target links against targetName.
+ std::map<std::string, std::string>::const_iterator dependerNodeNameIt =
+ this->TargetNamesNodes.find(dependerIt->first);
+
+ if (dependerNodeNameIt != this->TargetNamesNodes.end()) {
+ std::string connectionName = dependerNodeNameIt->second;
+ connectionName += "-";
+ connectionName += myNodeName;
+
+ if (insertedConnections.find(connectionName) ==
+ insertedConnections.end()) {
+ insertedConnections.insert(connectionName);
+ this->WriteNode(dependerIt->first, dependerIt->second,
+ insertedNodes, str);
+
+ str << " \"" << dependerNodeNameIt->second << "\" -> \""
+ << myNodeName << "\"";
+ str << " // " << targetName << " -> " << dependerIt->first
+ << std::endl;
+ this->WriteDependerConnections(dependerIt->first, insertedNodes,
+ insertedConnections, str);
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+void cmGraphVizWriter::WriteNode(const std::string& targetName,
+ const cmGeneratorTarget* target,
+ std::set<std::string>& insertedNodes,
+ cmGeneratedFileStream& str) const
+{
+ if (insertedNodes.find(targetName) == insertedNodes.end()) {
+ insertedNodes.insert(targetName);
+ std::map<std::string, std::string>::const_iterator nameIt =
+ this->TargetNamesNodes.find(targetName);
+
+ str << " \"" << nameIt->second << "\" [ label=\"" << targetName
+ << "\" shape=\"" << getShapeForTarget(target) << "\"];" << std::endl;
+ }
+}
+
+void cmGraphVizWriter::CollectTargetsAndLibs()
+{
+ if (!this->HaveTargetsAndLibs) {
+ this->HaveTargetsAndLibs = true;
+ int cnt = this->CollectAllTargets();
+ if (this->GenerateForExternals) {
+ this->CollectAllExternalLibs(cnt);
+ }
+ }
+}
+
+int cmGraphVizWriter::CollectAllTargets()
+{
+ int cnt = 0;
+ // First pass get the list of all cmake targets
+ for (std::vector<cmLocalGenerator*>::const_iterator lit =
+ this->LocalGenerators.begin();
+ lit != this->LocalGenerators.end(); ++lit) {
+ std::vector<cmGeneratorTarget*> targets = (*lit)->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::const_iterator it = targets.begin();
+ it != targets.end(); ++it) {
+ const char* realTargetName = (*it)->GetName().c_str();
+ if (this->IgnoreThisTarget(realTargetName)) {
+ // Skip ignored targets
+ continue;
+ }
+ // std::cout << "Found target: " << tit->first << std::endl;
+ std::ostringstream ostr;
+ ostr << this->GraphNodePrefix << cnt++;
+ this->TargetNamesNodes[realTargetName] = ostr.str();
+ this->TargetPtrs[realTargetName] = *it;
+ }
+ }
+
+ return cnt;
+}
+
+int cmGraphVizWriter::CollectAllExternalLibs(int cnt)
+{
+ // Ok, now find all the stuff we link to that is not in cmake
+ for (std::vector<cmLocalGenerator*>::const_iterator lit =
+ this->LocalGenerators.begin();
+ lit != this->LocalGenerators.end(); ++lit) {
+ std::vector<cmGeneratorTarget*> targets = (*lit)->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::const_iterator it = targets.begin();
+ it != targets.end(); ++it) {
+ const char* realTargetName = (*it)->GetName().c_str();
+ if (this->IgnoreThisTarget(realTargetName)) {
+ // Skip ignored targets
+ continue;
+ }
+ const cmTarget::LinkLibraryVectorType* ll =
+ &((*it)->Target->GetOriginalLinkLibraries());
+ for (cmTarget::LinkLibraryVectorType::const_iterator llit = ll->begin();
+ llit != ll->end(); ++llit) {
+ const char* libName = llit->first.c_str();
+ if (this->IgnoreThisTarget(libName)) {
+ // Skip ignored targets
+ continue;
+ }
+
+ std::map<std::string, const cmGeneratorTarget*>::const_iterator tarIt =
+ this->TargetPtrs.find(libName);
+ if (tarIt == this->TargetPtrs.end()) {
+ std::ostringstream ostr;
+ ostr << this->GraphNodePrefix << cnt++;
+ this->TargetNamesNodes[libName] = ostr.str();
+ this->TargetPtrs[libName] = CM_NULLPTR;
+ // str << " \"" << ostr << "\" [ label=\"" << libName
+ // << "\" shape=\"ellipse\"];" << std::endl;
+ }
+ }
+ }
+ }
+ return cnt;
+}
+
+bool cmGraphVizWriter::IgnoreThisTarget(const std::string& name)
+{
+ for (std::vector<cmsys::RegularExpression>::iterator itvIt =
+ this->TargetsToIgnoreRegex.begin();
+ itvIt != this->TargetsToIgnoreRegex.end(); ++itvIt) {
+ cmsys::RegularExpression& regEx = *itvIt;
+ if (regEx.is_valid()) {
+ if (regEx.find(name)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool cmGraphVizWriter::GenerateForTargetType(
+ cmState::TargetType targetType) const
+{
+ switch (targetType) {
+ case cmState::EXECUTABLE:
+ return this->GenerateForExecutables;
+ case cmState::STATIC_LIBRARY:
+ return this->GenerateForStaticLibs;
+ case cmState::SHARED_LIBRARY:
+ return this->GenerateForSharedLibs;
+ case cmState::MODULE_LIBRARY:
+ return this->GenerateForModuleLibs;
+ default:
+ break;
+ }
+ return false;
+}
diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h
new file mode 100644
index 0000000..c73d82d
--- /dev/null
+++ b/Source/cmGraphVizWriter.h
@@ -0,0 +1,91 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef CMGRAPHVIZWRITER_H
+#define CMGRAPHVIZWRITER_H
+
+#include "cmStandardIncludes.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmLocalGenerator.h"
+#include <cmsys/RegularExpression.hxx>
+
+class cmGeneratorTarget;
+
+/** This class implements writing files for graphviz (dot) for graphs
+ * representing the dependencies between the targets in the project. */
+class cmGraphVizWriter
+{
+public:
+ cmGraphVizWriter(const std::vector<cmLocalGenerator*>& localGenerators);
+
+ void ReadSettings(const char* settingsFileName,
+ const char* fallbackSettingsFileName);
+
+ void WritePerTargetFiles(const char* fileName);
+ void WriteTargetDependersFiles(const char* fileName);
+
+ void WriteGlobalFile(const char* fileName);
+
+protected:
+ void CollectTargetsAndLibs();
+
+ int CollectAllTargets();
+
+ int CollectAllExternalLibs(int cnt);
+
+ void WriteHeader(cmGeneratedFileStream& str) const;
+
+ void WriteConnections(const std::string& targetName,
+ std::set<std::string>& insertedNodes,
+ std::set<std::string>& insertedConnections,
+ cmGeneratedFileStream& str) const;
+
+ void WriteDependerConnections(const std::string& targetName,
+ std::set<std::string>& insertedNodes,
+ std::set<std::string>& insertedConnections,
+ cmGeneratedFileStream& str) const;
+
+ void WriteNode(const std::string& targetName,
+ const cmGeneratorTarget* target,
+ std::set<std::string>& insertedNodes,
+ cmGeneratedFileStream& str) const;
+
+ void WriteFooter(cmGeneratedFileStream& str) const;
+
+ bool IgnoreThisTarget(const std::string& name);
+
+ bool GenerateForTargetType(cmState::TargetType targetType) const;
+
+ std::string GraphType;
+ std::string GraphName;
+ std::string GraphHeader;
+ std::string GraphNodePrefix;
+
+ std::vector<cmsys::RegularExpression> TargetsToIgnoreRegex;
+
+ const std::vector<cmLocalGenerator*>& LocalGenerators;
+
+ std::map<std::string, const cmGeneratorTarget*> TargetPtrs;
+ // maps from the actual target names to node names in dot:
+ std::map<std::string, std::string> TargetNamesNodes;
+
+ bool GenerateForExecutables;
+ bool GenerateForStaticLibs;
+ bool GenerateForSharedLibs;
+ bool GenerateForModuleLibs;
+ bool GenerateForExternals;
+ bool GeneratePerTarget;
+ bool GenerateDependers;
+ bool HaveTargetsAndLibs;
+};
+
+#endif
diff --git a/Source/cmHexFileConverter.cxx b/Source/cmHexFileConverter.cxx
new file mode 100644
index 0000000..34fd626
--- /dev/null
+++ b/Source/cmHexFileConverter.cxx
@@ -0,0 +1,224 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmHexFileConverter.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#define INTEL_HEX_MIN_LINE_LENGTH (1 + 8 + 2)
+#define INTEL_HEX_MAX_LINE_LENGTH (1 + 8 + (256 * 2) + 2)
+#define MOTOROLA_SREC_MIN_LINE_LENGTH (2 + 2 + 4 + 2)
+#define MOTOROLA_SREC_MAX_LINE_LENGTH (2 + 2 + 8 + (256 * 2) + 2)
+
+// might go to SystemTools ?
+static bool cm_IsHexChar(char c)
+{
+ return (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) ||
+ ((c >= 'A') && (c <= 'F')));
+}
+
+static unsigned int ChompStrlen(const char* line)
+{
+ if (line == CM_NULLPTR) {
+ return 0;
+ }
+ unsigned int length = static_cast<unsigned int>(strlen(line));
+ if ((line[length - 1] == '\n') || (line[length - 1] == '\r')) {
+ length--;
+ }
+ if ((line[length - 1] == '\n') || (line[length - 1] == '\r')) {
+ length--;
+ }
+ return length;
+}
+
+static bool OutputBin(FILE* file, const char* buf, unsigned int startIndex,
+ unsigned int stopIndex)
+{
+ bool success = true;
+ char hexNumber[3];
+ hexNumber[2] = '\0';
+ char outBuf[256];
+ unsigned int outBufCount = 0;
+ for (unsigned int i = startIndex; i < stopIndex; i += 2) {
+ hexNumber[0] = buf[i];
+ hexNumber[1] = buf[i + 1];
+ unsigned int convertedByte = 0;
+ if (sscanf(hexNumber, "%x", &convertedByte) != 1) {
+ success = false;
+ break;
+ }
+ outBuf[outBufCount] = static_cast<char>(convertedByte & 0xff);
+ outBufCount++;
+ }
+ if (success) {
+ success = (fwrite(outBuf, 1, outBufCount, file) == outBufCount);
+ }
+ return success;
+}
+
+// see http://www.die.net/doc/linux/man/man5/srec.5.html
+static bool ConvertMotorolaSrecLine(const char* buf, FILE* outFile)
+{
+ unsigned int slen = ChompStrlen(buf);
+ if ((slen < MOTOROLA_SREC_MIN_LINE_LENGTH) ||
+ (slen > MOTOROLA_SREC_MAX_LINE_LENGTH)) {
+ return false;
+ }
+
+ // line length must be even
+ if (slen % 2 == 1) {
+ return false;
+ }
+
+ if (buf[0] != 'S') {
+ return false;
+ }
+
+ unsigned int dataStart = 0;
+ // ignore extra address records
+ if ((buf[1] == '5') || (buf[1] == '7') || (buf[1] == '8') ||
+ (buf[1] == '9')) {
+ return true;
+ } else if (buf[1] == '1') {
+ dataStart = 8;
+ } else if (buf[1] == '2') {
+ dataStart = 10;
+ } else if (buf[1] == '3') {
+ dataStart = 12;
+ } else // unknown record type
+ {
+ return false;
+ }
+
+ // ignore the last two bytes (checksum)
+ return OutputBin(outFile, buf, dataStart, slen - 2);
+}
+
+// see http://en.wikipedia.org/wiki/Intel_hex
+static bool ConvertIntelHexLine(const char* buf, FILE* outFile)
+{
+ unsigned int slen = ChompStrlen(buf);
+ if ((slen < INTEL_HEX_MIN_LINE_LENGTH) ||
+ (slen > INTEL_HEX_MAX_LINE_LENGTH)) {
+ return false;
+ }
+
+ // line length must be odd
+ if (slen % 2 == 0) {
+ return false;
+ }
+
+ if ((buf[0] != ':') || (buf[7] != '0')) {
+ return false;
+ }
+
+ unsigned int dataStart = 0;
+ if ((buf[8] == '0') || (buf[8] == '1')) {
+ dataStart = 9;
+ }
+ // ignore extra address records
+ else if ((buf[8] == '2') || (buf[8] == '3') || (buf[8] == '4') ||
+ (buf[8] == '5')) {
+ return true;
+ } else // unknown record type
+ {
+ return false;
+ }
+
+ // ignore the last two bytes (checksum)
+ return OutputBin(outFile, buf, dataStart, slen - 2);
+}
+
+cmHexFileConverter::FileType cmHexFileConverter::DetermineFileType(
+ const char* inFileName)
+{
+ char buf[1024];
+ FILE* inFile = cmsys::SystemTools::Fopen(inFileName, "rb");
+ if (inFile == CM_NULLPTR) {
+ return Binary;
+ }
+
+ if (!fgets(buf, 1024, inFile)) {
+ buf[0] = 0;
+ }
+ fclose(inFile);
+ FileType type = Binary;
+ unsigned int minLineLength = 0;
+ unsigned int maxLineLength = 0;
+ if (buf[0] == ':') // might be an intel hex file
+ {
+ type = IntelHex;
+ minLineLength = INTEL_HEX_MIN_LINE_LENGTH;
+ maxLineLength = INTEL_HEX_MAX_LINE_LENGTH;
+ } else if (buf[0] == 'S') // might be a motorola srec file
+ {
+ type = MotorolaSrec;
+ minLineLength = MOTOROLA_SREC_MIN_LINE_LENGTH;
+ maxLineLength = MOTOROLA_SREC_MAX_LINE_LENGTH;
+ } else {
+ return Binary;
+ }
+
+ unsigned int slen = ChompStrlen(buf);
+ if ((slen < minLineLength) || (slen > maxLineLength)) {
+ return Binary;
+ }
+
+ for (unsigned int i = 1; i < slen; i++) {
+ if (!cm_IsHexChar(buf[i])) {
+ return Binary;
+ }
+ }
+ return type;
+}
+
+bool cmHexFileConverter::TryConvert(const char* inFileName,
+ const char* outFileName)
+{
+ FileType type = DetermineFileType(inFileName);
+ if (type == Binary) {
+ return false;
+ }
+
+ // try to open the file
+ FILE* inFile = cmsys::SystemTools::Fopen(inFileName, "rb");
+ FILE* outFile = cmsys::SystemTools::Fopen(outFileName, "wb");
+ if ((inFile == CM_NULLPTR) || (outFile == CM_NULLPTR)) {
+ if (inFile != CM_NULLPTR) {
+ fclose(inFile);
+ }
+ if (outFile != CM_NULLPTR) {
+ fclose(outFile);
+ }
+ return false;
+ }
+
+ // convert them line by line
+ bool success = false;
+ char buf[1024];
+ while (fgets(buf, 1024, inFile) != CM_NULLPTR) {
+ if (type == MotorolaSrec) {
+ success = ConvertMotorolaSrecLine(buf, outFile);
+ } else if (type == IntelHex) {
+ success = ConvertIntelHexLine(buf, outFile);
+ }
+ if (success == false) {
+ break;
+ }
+ }
+
+ // close them again
+ fclose(inFile);
+ fclose(outFile);
+ return success;
+}
diff --git a/Source/cmHexFileConverter.h b/Source/cmHexFileConverter.h
new file mode 100644
index 0000000..56fa9b1
--- /dev/null
+++ b/Source/cmHexFileConverter.h
@@ -0,0 +1,35 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmHexFileConverter_h
+#define cmHexFileConverter_h
+
+#include "cmStandardIncludes.h"
+
+/** \class cmHexFileConverter
+ * \brief Can detects Intel Hex and Motorola S-record files and convert them
+ * to binary files.
+ *
+ */
+class cmHexFileConverter
+{
+public:
+ enum FileType
+ {
+ Binary,
+ IntelHex,
+ MotorolaSrec
+ };
+ static FileType DetermineFileType(const char* inFileName);
+ static bool TryConvert(const char* inFileName, const char* outFileName);
+};
+
+#endif
diff --git a/Source/cmIDEFlagTable.h b/Source/cmIDEFlagTable.h
new file mode 100644
index 0000000..e8a6e38
--- /dev/null
+++ b/Source/cmIDEFlagTable.h
@@ -0,0 +1,42 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmIDEFlagTable_h
+#define cmIDEFlagTable_h
+
+// This is a table mapping XML tag IDE names to command line options
+struct cmIDEFlagTable
+{
+ const char* IDEName; // name used in the IDE xml file
+ const char* commandFlag; // command line flag
+ const char* comment; // comment
+ const char* value; // string value
+ unsigned int special; // flags for special handling requests
+ enum
+ {
+ UserValue = (1 << 0), // flag contains a user-specified value
+ UserIgnored = (1 << 1), // ignore any user value
+ UserRequired = (1 << 2), // match only when user value is non-empty
+ Continue = (1 << 3), // continue looking for matching entries
+ SemicolonAppendable = (1 << 4), // a flag that if specified multiple times
+ // should have its value appended to the
+ // old value with semicolons (e.g.
+ // /NODEFAULTLIB: =>
+ // IgnoreDefaultLibraryNames)
+ UserFollowing = (1 << 5), // expect value in following argument
+ CaseInsensitive = (1 << 6), // flag may be any case
+
+ UserValueIgnored = UserValue | UserIgnored,
+ UserValueRequired = UserValue | UserRequired
+ };
+};
+
+#endif
diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx
new file mode 100644
index 0000000..9f4b537
--- /dev/null
+++ b/Source/cmIDEOptions.cxx
@@ -0,0 +1,199 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmIDEOptions.h"
+
+#include "cmSystemTools.h"
+
+#include <cmsys/String.h>
+
+cmIDEOptions::cmIDEOptions()
+{
+ this->DoingDefine = false;
+ this->AllowDefine = true;
+ this->AllowSlash = false;
+ this->DoingFollowing = 0;
+ for (int i = 0; i < FlagTableCount; ++i) {
+ this->FlagTable[i] = 0;
+ }
+}
+
+cmIDEOptions::~cmIDEOptions()
+{
+}
+
+void cmIDEOptions::HandleFlag(const char* flag)
+{
+ // If the last option was -D then this option is the definition.
+ if (this->DoingDefine) {
+ this->DoingDefine = false;
+ this->Defines.push_back(flag);
+ return;
+ }
+
+ // If the last option expected a following value, this is it.
+ if (this->DoingFollowing) {
+ this->FlagMapUpdate(this->DoingFollowing, flag);
+ this->DoingFollowing = 0;
+ return;
+ }
+
+ // Look for known arguments.
+ if (flag[0] == '-' || (this->AllowSlash && flag[0] == '/')) {
+ // Look for preprocessor definitions.
+ if (this->AllowDefine && flag[1] == 'D') {
+ if (flag[2] == '\0') {
+ // The next argument will have the definition.
+ this->DoingDefine = true;
+ } else {
+ // Store this definition.
+ this->Defines.push_back(flag + 2);
+ }
+ return;
+ }
+
+ // Look through the available flag tables.
+ bool flag_handled = false;
+ for (int i = 0; i < FlagTableCount && this->FlagTable[i]; ++i) {
+ if (this->CheckFlagTable(this->FlagTable[i], flag, flag_handled)) {
+ return;
+ }
+ }
+
+ // If any map entry handled the flag we are done.
+ if (flag_handled) {
+ return;
+ }
+ }
+
+ // This option is not known. Store it in the output flags.
+ this->StoreUnknownFlag(flag);
+}
+
+bool cmIDEOptions::CheckFlagTable(cmIDEFlagTable const* table,
+ const char* flag, bool& flag_handled)
+{
+ // Look for an entry in the flag table matching this flag.
+ for (cmIDEFlagTable const* entry = table; entry->IDEName; ++entry) {
+ bool entry_found = false;
+ if (entry->special & cmIDEFlagTable::UserValue) {
+ // This flag table entry accepts a user-specified value. If
+ // the entry specifies UserRequired we must match only if a
+ // non-empty value is given.
+ int n = static_cast<int>(strlen(entry->commandFlag));
+ if ((strncmp(flag + 1, entry->commandFlag, n) == 0 ||
+ (entry->special & cmIDEFlagTable::CaseInsensitive &&
+ cmsysString_strncasecmp(flag + 1, entry->commandFlag, n))) &&
+ (!(entry->special & cmIDEFlagTable::UserRequired) ||
+ static_cast<int>(strlen(flag + 1)) > n)) {
+ this->FlagMapUpdate(entry, flag + n + 1);
+ entry_found = true;
+ }
+ } else if (strcmp(flag + 1, entry->commandFlag) == 0 ||
+ (entry->special & cmIDEFlagTable::CaseInsensitive &&
+ cmsysString_strcasecmp(flag + 1, entry->commandFlag) == 0)) {
+ if (entry->special & cmIDEFlagTable::UserFollowing) {
+ // This flag expects a value in the following argument.
+ this->DoingFollowing = entry;
+ } else {
+ // This flag table entry provides a fixed value.
+ this->FlagMap[entry->IDEName] = entry->value;
+ }
+ entry_found = true;
+ }
+
+ // If the flag has been handled by an entry not requesting a
+ // search continuation we are done.
+ if (entry_found && !(entry->special & cmIDEFlagTable::Continue)) {
+ return true;
+ }
+
+ // If the entry was found the flag has been handled.
+ flag_handled = flag_handled || entry_found;
+ }
+
+ return false;
+}
+
+void cmIDEOptions::FlagMapUpdate(cmIDEFlagTable const* entry,
+ const char* new_value)
+{
+ if (entry->special & cmIDEFlagTable::UserIgnored) {
+ // Ignore the user-specified value.
+ this->FlagMap[entry->IDEName] = entry->value;
+ } else if (entry->special & cmIDEFlagTable::SemicolonAppendable) {
+ this->FlagMap[entry->IDEName].push_back(new_value);
+ } else {
+ // Use the user-specified value.
+ this->FlagMap[entry->IDEName] = new_value;
+ }
+}
+
+void cmIDEOptions::AddDefine(const std::string& def)
+{
+ this->Defines.push_back(def);
+}
+
+void cmIDEOptions::AddDefines(const char* defines)
+{
+ if (defines) {
+ // Expand the list of definitions.
+ cmSystemTools::ExpandListArgument(defines, this->Defines);
+ }
+}
+void cmIDEOptions::AddDefines(const std::vector<std::string>& defines)
+{
+ this->Defines.insert(this->Defines.end(), defines.begin(), defines.end());
+}
+
+void cmIDEOptions::AddFlag(const char* flag, const char* value)
+{
+ this->FlagMap[flag] = value;
+}
+
+void cmIDEOptions::AddFlag(const char* flag,
+ std::vector<std::string> const& value)
+{
+ this->FlagMap[flag] = value;
+}
+
+void cmIDEOptions::AppendFlag(std::string const& flag,
+ std::string const& value)
+{
+ this->FlagMap[flag].push_back(value);
+}
+
+void cmIDEOptions::AppendFlag(std::string const& flag,
+ std::vector<std::string> const& value)
+{
+ FlagValue& fv = this->FlagMap[flag];
+ std::copy(value.begin(), value.end(), std::back_inserter(fv));
+}
+
+void cmIDEOptions::RemoveFlag(const char* flag)
+{
+ this->FlagMap.erase(flag);
+}
+
+bool cmIDEOptions::HasFlag(std::string const& flag) const
+{
+ return this->FlagMap.find(flag) != this->FlagMap.end();
+}
+
+const char* cmIDEOptions::GetFlag(const char* flag)
+{
+ // This method works only for single-valued flags!
+ std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(flag);
+ if (i != this->FlagMap.end() && i->second.size() == 1) {
+ return i->second[0].c_str();
+ }
+ return 0;
+}
diff --git a/Source/cmIDEOptions.h b/Source/cmIDEOptions.h
new file mode 100644
index 0000000..fac7d4e
--- /dev/null
+++ b/Source/cmIDEOptions.h
@@ -0,0 +1,90 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmIDEOptions_h
+#define cmIDEOptions_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmIDEFlagTable.h"
+
+/** \class cmIDEOptions
+ * \brief Superclass for IDE option processing
+ */
+class cmIDEOptions
+{
+public:
+ cmIDEOptions();
+ virtual ~cmIDEOptions();
+
+ // Store definitions and flags.
+ void AddDefine(const std::string& define);
+ void AddDefines(const char* defines);
+ void AddDefines(const std::vector<std::string>& defines);
+ void AddFlag(const char* flag, const char* value);
+ void AddFlag(const char* flag, std::vector<std::string> const& value);
+ void AppendFlag(std::string const& flag, std::string const& value);
+ void AppendFlag(std::string const& flag,
+ std::vector<std::string> const& value);
+ void RemoveFlag(const char* flag);
+ bool HasFlag(std::string const& flag) const;
+ const char* GetFlag(const char* flag);
+
+protected:
+ // create a map of xml tags to the values they should have in the output
+ // for example, "BufferSecurityCheck" = "TRUE"
+ // first fill this table with the values for the configuration
+ // Debug, Release, etc,
+ // Then parse the command line flags specified in CMAKE_CXX_FLAGS
+ // and CMAKE_C_FLAGS
+ // and overwrite or add new values to this map
+ class FlagValue : public std::vector<std::string>
+ {
+ typedef std::vector<std::string> derived;
+
+ public:
+ FlagValue& operator=(std::string const& r)
+ {
+ this->resize(1);
+ this->operator[](0) = r;
+ return *this;
+ }
+ FlagValue& operator=(std::vector<std::string> const& r)
+ {
+ this->derived::operator=(r);
+ return *this;
+ }
+ };
+ std::map<std::string, FlagValue> FlagMap;
+
+ // Preprocessor definitions.
+ std::vector<std::string> Defines;
+
+ // Unrecognized flags that get no special handling.
+ std::string FlagString;
+
+ bool DoingDefine;
+ bool AllowDefine;
+ bool AllowSlash;
+ cmIDEFlagTable const* DoingFollowing;
+ enum
+ {
+ FlagTableCount = 16
+ };
+ cmIDEFlagTable const* FlagTable[FlagTableCount];
+ void HandleFlag(const char* flag);
+ bool CheckFlagTable(cmIDEFlagTable const* table, const char* flag,
+ bool& flag_handled);
+ void FlagMapUpdate(cmIDEFlagTable const* entry, const char* new_value);
+ virtual void StoreUnknownFlag(const char* flag) = 0;
+};
+
+#endif
diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx
new file mode 100644
index 0000000..dd04136
--- /dev/null
+++ b/Source/cmIfCommand.cxx
@@ -0,0 +1,209 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmIfCommand.h"
+
+#include "cmOutputConverter.h"
+#include "cmStringCommand.h"
+
+#include "cmConditionEvaluator.h"
+
+#include <cmsys/RegularExpression.hxx>
+#include <list>
+#include <stdlib.h> // required for atof
+
+static std::string cmIfCommandError(
+ std::vector<cmExpandedCommandArgument> const& args)
+{
+ std::string err = "given arguments:\n ";
+ for (std::vector<cmExpandedCommandArgument>::const_iterator i = args.begin();
+ i != args.end(); ++i) {
+ err += " ";
+ err += cmOutputConverter::EscapeForCMake(i->GetValue());
+ }
+ err += "\n";
+ return err;
+}
+
+//=========================================================================
+bool cmIfFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
+ cmMakefile& mf,
+ cmExecutionStatus& inStatus)
+{
+ // we start by recording all the functions
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(), "if")) {
+ this->ScopeDepth++;
+ } else if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endif")) {
+ this->ScopeDepth--;
+ // if this is the endif for this if statement, then start executing
+ if (!this->ScopeDepth) {
+ // Remove the function blocker for this scope or bail.
+ CM_AUTO_PTR<cmFunctionBlocker> fb(mf.RemoveFunctionBlocker(this, lff));
+ if (!fb.get()) {
+ return false;
+ }
+
+ // execute the functions for the true parts of the if statement
+ cmExecutionStatus status;
+ int scopeDepth = 0;
+ for (unsigned int c = 0; c < this->Functions.size(); ++c) {
+ // keep track of scope depth
+ if (!cmSystemTools::Strucmp(this->Functions[c].Name.c_str(), "if")) {
+ scopeDepth++;
+ }
+ if (!cmSystemTools::Strucmp(this->Functions[c].Name.c_str(),
+ "endif")) {
+ scopeDepth--;
+ }
+ // watch for our state change
+ if (scopeDepth == 0 &&
+ !cmSystemTools::Strucmp(this->Functions[c].Name.c_str(), "else")) {
+ this->IsBlocking = this->HasRun;
+ this->HasRun = true;
+
+ // if trace is enabled, print a (trivially) evaluated "else"
+ // statement
+ if (!this->IsBlocking && mf.GetCMakeInstance()->GetTrace()) {
+ mf.PrintCommandTrace(this->Functions[c]);
+ }
+ } else if (scopeDepth == 0 &&
+ !cmSystemTools::Strucmp(this->Functions[c].Name.c_str(),
+ "elseif")) {
+ if (this->HasRun) {
+ this->IsBlocking = true;
+ } else {
+ // if trace is enabled, print the evaluated "elseif" statement
+ if (mf.GetCMakeInstance()->GetTrace()) {
+ mf.PrintCommandTrace(this->Functions[c]);
+ }
+
+ std::string errorString;
+
+ std::vector<cmExpandedCommandArgument> expandedArguments;
+ mf.ExpandArguments(this->Functions[c].Arguments,
+ expandedArguments);
+
+ cmake::MessageType messType;
+
+ cmListFileContext conditionContext =
+ cmListFileContext::FromCommandContext(
+ this->Functions[c], this->GetStartingContext().FilePath);
+
+ cmConditionEvaluator conditionEvaluator(
+ mf, conditionContext, mf.GetBacktrace(this->Functions[c]));
+
+ bool isTrue = conditionEvaluator.IsTrue(expandedArguments,
+ errorString, messType);
+
+ if (!errorString.empty()) {
+ std::string err = cmIfCommandError(expandedArguments);
+ err += errorString;
+ cmListFileBacktrace bt = mf.GetBacktrace(this->Functions[c]);
+ mf.GetCMakeInstance()->IssueMessage(messType, err, bt);
+ if (messType == cmake::FATAL_ERROR) {
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ }
+
+ if (isTrue) {
+ this->IsBlocking = false;
+ this->HasRun = true;
+ }
+ }
+ }
+
+ // should we execute?
+ else if (!this->IsBlocking) {
+ status.Clear();
+ mf.ExecuteCommand(this->Functions[c], status);
+ if (status.GetReturnInvoked()) {
+ inStatus.SetReturnInvoked(true);
+ return true;
+ }
+ if (status.GetBreakInvoked()) {
+ inStatus.SetBreakInvoked(true);
+ return true;
+ }
+ if (status.GetContinueInvoked()) {
+ inStatus.SetContinueInvoked(true);
+ return true;
+ }
+ }
+ }
+ return true;
+ }
+ }
+
+ // record the command
+ this->Functions.push_back(lff);
+
+ // always return true
+ return true;
+}
+
+//=========================================================================
+bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
+ cmMakefile&)
+{
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endif")) {
+ // if the endif has arguments, then make sure
+ // they match the arguments of the matching if
+ if (lff.Arguments.empty() || lff.Arguments == this->Args) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//=========================================================================
+bool cmIfCommand::InvokeInitialPass(
+ const std::vector<cmListFileArgument>& args, cmExecutionStatus&)
+{
+ std::string errorString;
+
+ std::vector<cmExpandedCommandArgument> expandedArguments;
+ this->Makefile->ExpandArguments(args, expandedArguments);
+
+ cmake::MessageType status;
+
+ cmConditionEvaluator conditionEvaluator(
+ *(this->Makefile), this->Makefile->GetExecutionContext(),
+ this->Makefile->GetBacktrace());
+
+ bool isTrue =
+ conditionEvaluator.IsTrue(expandedArguments, errorString, status);
+
+ if (!errorString.empty()) {
+ std::string err = "if " + cmIfCommandError(expandedArguments);
+ err += errorString;
+ if (status == cmake::FATAL_ERROR) {
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, err);
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ } else {
+ this->Makefile->IssueMessage(status, err);
+ }
+ }
+
+ cmIfFunctionBlocker* f = new cmIfFunctionBlocker();
+ // if is isn't true block the commands
+ f->ScopeDepth = 1;
+ f->IsBlocking = !isTrue;
+ if (isTrue) {
+ f->HasRun = true;
+ }
+ f->Args = args;
+ this->Makefile->AddFunctionBlocker(f);
+
+ return true;
+}
diff --git a/Source/cmIfCommand.h b/Source/cmIfCommand.h
new file mode 100644
index 0000000..f1f979d
--- /dev/null
+++ b/Source/cmIfCommand.h
@@ -0,0 +1,82 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmIfCommand_h
+#define cmIfCommand_h
+
+#include "cmCommand.h"
+
+#include "cmFunctionBlocker.h"
+
+class cmIfFunctionBlocker : public cmFunctionBlocker
+{
+public:
+ cmIfFunctionBlocker()
+ {
+ this->HasRun = false;
+ this->ScopeDepth = 0;
+ }
+ ~cmIfFunctionBlocker() CM_OVERRIDE {}
+ bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf,
+ cmExecutionStatus&) CM_OVERRIDE;
+ bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) CM_OVERRIDE;
+
+ std::vector<cmListFileArgument> Args;
+ std::vector<cmListFileFunction> Functions;
+ bool IsBlocking;
+ bool HasRun;
+ unsigned int ScopeDepth;
+};
+
+/// Starts an if block
+class cmIfCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmIfCommand; }
+
+ /**
+ * This overrides the default InvokeInitialPass implementation.
+ * It records the arguments before expansion.
+ */
+ bool InvokeInitialPass(const std::vector<cmListFileArgument>& args,
+ cmExecutionStatus&) CM_OVERRIDE;
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&) CM_OVERRIDE
+ {
+ return false;
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "if"; }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ // Filter the given variable definition based on policy CMP0054.
+ static const char* GetDefinitionIfUnquoted(
+ const cmMakefile* mf, cmExpandedCommandArgument const& argument);
+
+ cmTypeMacro(cmIfCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx
new file mode 100644
index 0000000..360ebeb
--- /dev/null
+++ b/Source/cmIncludeCommand.cxx
@@ -0,0 +1,138 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmIncludeCommand.h"
+
+// cmIncludeCommand
+bool cmIncludeCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1 || args.size() > 4) {
+ this->SetError("called with wrong number of arguments. "
+ "include() only takes one file.");
+ return false;
+ }
+ bool optional = false;
+ bool noPolicyScope = false;
+ std::string fname = args[0];
+ std::string resultVarName;
+
+ for (unsigned int i = 1; i < args.size(); i++) {
+ if (args[i] == "OPTIONAL") {
+ if (optional) {
+ this->SetError("called with invalid arguments: OPTIONAL used twice");
+ return false;
+ }
+ optional = true;
+ } else if (args[i] == "RESULT_VARIABLE") {
+ if (!resultVarName.empty()) {
+ this->SetError("called with invalid arguments: "
+ "only one result variable allowed");
+ return false;
+ }
+ if (++i < args.size()) {
+ resultVarName = args[i];
+ } else {
+ this->SetError("called with no value for RESULT_VARIABLE.");
+ return false;
+ }
+ } else if (args[i] == "NO_POLICY_SCOPE") {
+ noPolicyScope = true;
+ } else if (i > 1) // compat.: in previous cmake versions the second
+ // parameter was ignored if it wasn't "OPTIONAL"
+ {
+ std::string errorText = "called with invalid argument: ";
+ errorText += args[i];
+ this->SetError(errorText);
+ return false;
+ }
+ }
+
+ if (fname.empty()) {
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
+ "include() given empty file name (ignored).");
+ return true;
+ }
+
+ if (!cmSystemTools::FileIsFullPath(fname.c_str())) {
+ // Not a path. Maybe module.
+ std::string module = fname;
+ module += ".cmake";
+ std::string mfile = this->Makefile->GetModulesFile(module.c_str());
+ if (!mfile.empty()) {
+ fname = mfile.c_str();
+ }
+ }
+
+ std::string fname_abs = cmSystemTools::CollapseFullPath(
+ fname, this->Makefile->GetCurrentSourceDirectory());
+
+ cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ if (gg->IsExportedTargetsFile(fname_abs)) {
+ const char* modal = CM_NULLPTR;
+ std::ostringstream e;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0024)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0024) << "\n";
+ modal = "should";
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ modal = "may";
+ messageType = cmake::FATAL_ERROR;
+ }
+ if (modal) {
+ e << "The file\n " << fname_abs << "\nwas generated by the export() "
+ "command. It "
+ << modal
+ << " not be used as the argument to the "
+ "include() command. Use ALIAS targets instead to refer to targets "
+ "by alternative names.\n";
+ this->Makefile->IssueMessage(messageType, e.str());
+ if (messageType == cmake::FATAL_ERROR) {
+ return false;
+ }
+ }
+ gg->CreateGenerationObjects();
+ gg->GenerateImportFile(fname_abs);
+ }
+
+ std::string listFile = cmSystemTools::CollapseFullPath(
+ fname.c_str(), this->Makefile->GetCurrentSourceDirectory());
+ if (optional && !cmSystemTools::FileExists(listFile.c_str())) {
+ if (!resultVarName.empty()) {
+ this->Makefile->AddDefinition(resultVarName, "NOTFOUND");
+ }
+ return true;
+ }
+
+ bool readit =
+ this->Makefile->ReadDependentFile(listFile.c_str(), noPolicyScope);
+
+ // add the location of the included file if a result variable was given
+ if (!resultVarName.empty()) {
+ this->Makefile->AddDefinition(resultVarName,
+ readit ? fname_abs.c_str() : "NOTFOUND");
+ }
+
+ if (!optional && !readit && !cmSystemTools::GetFatalErrorOccured()) {
+ std::string m = "could not find load file:\n"
+ " ";
+ m += fname;
+ this->SetError(m);
+ return false;
+ }
+ return true;
+}
diff --git a/Source/cmIncludeCommand.h b/Source/cmIncludeCommand.h
new file mode 100644
index 0000000..365a830
--- /dev/null
+++ b/Source/cmIncludeCommand.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmIncludeCommand_h
+#define cmIncludeCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmIncludeCommand
+ * \brief cmIncludeCommand defines a list of distant
+ * files that can be "included" in the current list file.
+ * In almost every sense, this is identical to a C/C++
+ * #include command. Arguments are first expended as usual.
+ */
+class cmIncludeCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmIncludeCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "include"; }
+
+ cmTypeMacro(cmIncludeCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx
new file mode 100644
index 0000000..cafdba7
--- /dev/null
+++ b/Source/cmIncludeDirectoryCommand.cxx
@@ -0,0 +1,136 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmIncludeDirectoryCommand.h"
+
+// cmIncludeDirectoryCommand
+bool cmIncludeDirectoryCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ return true;
+ }
+
+ std::vector<std::string>::const_iterator i = args.begin();
+
+ bool before = this->Makefile->IsOn("CMAKE_INCLUDE_DIRECTORIES_BEFORE");
+ bool system = false;
+
+ if ((*i) == "BEFORE") {
+ before = true;
+ ++i;
+ } else if ((*i) == "AFTER") {
+ before = false;
+ ++i;
+ }
+
+ std::vector<std::string> beforeIncludes;
+ std::vector<std::string> afterIncludes;
+ std::set<std::string> systemIncludes;
+
+ for (; i != args.end(); ++i) {
+ if (*i == "SYSTEM") {
+ system = true;
+ continue;
+ }
+ if (i->empty()) {
+ this->SetError("given empty-string as include directory.");
+ return false;
+ }
+
+ std::vector<std::string> includes;
+
+ this->GetIncludes(*i, includes);
+
+ if (before) {
+ beforeIncludes.insert(beforeIncludes.end(), includes.begin(),
+ includes.end());
+ } else {
+ afterIncludes.insert(afterIncludes.end(), includes.begin(),
+ includes.end());
+ }
+ if (system) {
+ systemIncludes.insert(includes.begin(), includes.end());
+ }
+ }
+ std::reverse(beforeIncludes.begin(), beforeIncludes.end());
+
+ this->Makefile->AddIncludeDirectories(afterIncludes);
+ this->Makefile->AddIncludeDirectories(beforeIncludes, before);
+ this->Makefile->AddSystemIncludeDirectories(systemIncludes);
+
+ return true;
+}
+
+static bool StartsWithGeneratorExpression(const std::string& input)
+{
+ return input[0] == '$' && input[1] == '<';
+}
+
+// do a lot of cleanup on the arguments because this is one place where folks
+// sometimes take the output of a program and pass it directly into this
+// command not thinking that a single argument could be filled with spaces
+// and newlines etc liek below:
+//
+// " /foo/bar
+// /boo/hoo /dingle/berry "
+//
+// ideally that should be three separate arguments but when sucking the
+// output from a program and passing it into a command the cleanup doesn't
+// always happen
+//
+void cmIncludeDirectoryCommand::GetIncludes(const std::string& arg,
+ std::vector<std::string>& incs)
+{
+ // break apart any line feed arguments
+ std::string::size_type pos = 0;
+ std::string::size_type lastPos = 0;
+ while ((pos = arg.find('\n', lastPos)) != std::string::npos) {
+ if (pos) {
+ std::string inc = arg.substr(lastPos, pos);
+ this->NormalizeInclude(inc);
+ if (!inc.empty()) {
+ incs.push_back(inc);
+ }
+ }
+ lastPos = pos + 1;
+ }
+ std::string inc = arg.substr(lastPos);
+ this->NormalizeInclude(inc);
+ if (!inc.empty()) {
+ incs.push_back(inc);
+ }
+}
+
+void cmIncludeDirectoryCommand::NormalizeInclude(std::string& inc)
+{
+ std::string::size_type b = inc.find_first_not_of(" \r");
+ std::string::size_type e = inc.find_last_not_of(" \r");
+ if ((b != inc.npos) && (e != inc.npos)) {
+ inc.assign(inc, b, 1 + e - b); // copy the remaining substring
+ } else {
+ inc = "";
+ return;
+ }
+
+ if (!cmSystemTools::IsOff(inc.c_str())) {
+ cmSystemTools::ConvertToUnixSlashes(inc);
+
+ if (!cmSystemTools::FileIsFullPath(inc.c_str())) {
+ if (!StartsWithGeneratorExpression(inc)) {
+ std::string tmp = this->Makefile->GetCurrentSourceDirectory();
+ tmp += "/";
+ tmp += inc;
+ inc = tmp;
+ }
+ }
+ }
+}
diff --git a/Source/cmIncludeDirectoryCommand.h b/Source/cmIncludeDirectoryCommand.h
new file mode 100644
index 0000000..25be709
--- /dev/null
+++ b/Source/cmIncludeDirectoryCommand.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmIncludeDirectoryCommand_h
+#define cmIncludeDirectoryCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmIncludeDirectoryCommand
+ * \brief Add include directories to the build.
+ *
+ * cmIncludeDirectoryCommand is used to specify directory locations
+ * to search for included files.
+ */
+class cmIncludeDirectoryCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmIncludeDirectoryCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "include_directories"; }
+
+ cmTypeMacro(cmIncludeDirectoryCommand, cmCommand);
+
+protected:
+ // used internally
+ void GetIncludes(const std::string& arg, std::vector<std::string>& incs);
+ void NormalizeInclude(std::string& inc);
+};
+
+#endif
diff --git a/Source/cmIncludeExternalMSProjectCommand.cxx b/Source/cmIncludeExternalMSProjectCommand.cxx
new file mode 100644
index 0000000..9720d63
--- /dev/null
+++ b/Source/cmIncludeExternalMSProjectCommand.cxx
@@ -0,0 +1,101 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmIncludeExternalMSProjectCommand.h"
+
+// cmIncludeExternalMSProjectCommand
+bool cmIncludeExternalMSProjectCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("INCLUDE_EXTERNAL_MSPROJECT called with incorrect "
+ "number of arguments");
+ return false;
+ }
+// only compile this for win32 to avoid coverage errors
+#ifdef _WIN32
+ if (this->Makefile->GetDefinition("WIN32")) {
+ enum Doing
+ {
+ DoingNone,
+ DoingType,
+ DoingGuid,
+ DoingPlatform
+ };
+
+ Doing doing = DoingNone;
+
+ std::string customType;
+ std::string customGuid;
+ std::string platformMapping;
+
+ std::vector<std::string> depends;
+ for (unsigned int i = 2; i < args.size(); ++i) {
+ if (args[i] == "TYPE") {
+ doing = DoingType;
+ } else if (args[i] == "GUID") {
+ doing = DoingGuid;
+ } else if (args[i] == "PLATFORM") {
+ doing = DoingPlatform;
+ } else {
+ switch (doing) {
+ case DoingNone:
+ depends.push_back(args[i]);
+ break;
+ case DoingType:
+ customType = args[i];
+ break;
+ case DoingGuid:
+ customGuid = args[i];
+ break;
+ case DoingPlatform:
+ platformMapping = args[i];
+ break;
+ }
+ doing = DoingNone;
+ }
+ }
+
+ // Hack together a utility target storing enough information
+ // to reproduce the target inclusion.
+ std::string utility_name = args[0];
+
+ std::string path = args[1];
+ cmSystemTools::ConvertToUnixSlashes(path);
+
+ if (!customGuid.empty()) {
+ std::string guidVariable = utility_name + "_GUID_CMAKE";
+ this->Makefile->GetCMakeInstance()->AddCacheEntry(
+ guidVariable.c_str(), customGuid.c_str(), "Stored GUID",
+ cmState::INTERNAL);
+ }
+
+ // Create a target instance for this utility.
+ cmTarget* target =
+ this->Makefile->AddNewTarget(cmState::UTILITY, utility_name.c_str());
+
+ target->SetProperty("GENERATOR_FILE_NAME", utility_name.c_str());
+ target->SetProperty("EXTERNAL_MSPROJECT", path.c_str());
+ target->SetProperty("EXCLUDE_FROM_ALL", "FALSE");
+
+ if (!customType.empty())
+ target->SetProperty("VS_PROJECT_TYPE", customType.c_str());
+ if (!platformMapping.empty())
+ target->SetProperty("VS_PLATFORM_MAPPING", platformMapping.c_str());
+
+ for (std::vector<std::string>::const_iterator it = depends.begin();
+ it != depends.end(); ++it) {
+ target->AddUtility(it->c_str());
+ }
+ }
+#endif
+ return true;
+}
diff --git a/Source/cmIncludeExternalMSProjectCommand.h b/Source/cmIncludeExternalMSProjectCommand.h
new file mode 100644
index 0000000..8cda7b9
--- /dev/null
+++ b/Source/cmIncludeExternalMSProjectCommand.h
@@ -0,0 +1,53 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmIncludeExternalMSProjectCommand_h
+#define cmIncludeExternalMSProjectCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmIncludeExternalMSProjectCommand
+ * \brief Specify an external MS project file for inclusion in the workspace.
+ *
+ * cmIncludeExternalMSProjectCommand is used to specify an externally
+ * generated Microsoft project file for inclusion in the default workspace
+ * generated by CMake.
+ */
+class cmIncludeExternalMSProjectCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ return new cmIncludeExternalMSProjectCommand;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE
+ {
+ return "include_external_msproject";
+ }
+
+ cmTypeMacro(cmIncludeExternalMSProjectCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmIncludeRegularExpressionCommand.cxx b/Source/cmIncludeRegularExpressionCommand.cxx
new file mode 100644
index 0000000..2473dff
--- /dev/null
+++ b/Source/cmIncludeRegularExpressionCommand.cxx
@@ -0,0 +1,29 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmIncludeRegularExpressionCommand.h"
+
+// cmIncludeRegularExpressionCommand
+bool cmIncludeRegularExpressionCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if ((args.size() < 1) || (args.size() > 2)) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ this->Makefile->SetIncludeRegularExpression(args[0].c_str());
+
+ if (args.size() > 1) {
+ this->Makefile->SetComplainRegularExpression(args[1]);
+ }
+
+ return true;
+}
diff --git a/Source/cmIncludeRegularExpressionCommand.h b/Source/cmIncludeRegularExpressionCommand.h
new file mode 100644
index 0000000..52fdff0
--- /dev/null
+++ b/Source/cmIncludeRegularExpressionCommand.h
@@ -0,0 +1,52 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmIncludeRegularExpressionCommand_h
+#define cmIncludeRegularExpressionCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmIncludeRegularExpressionCommand
+ * \brief Set the regular expression for following #includes.
+ *
+ * cmIncludeRegularExpressionCommand is used to specify the regular expression
+ * that determines whether to follow a #include file in dependency checking.
+ */
+class cmIncludeRegularExpressionCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ return new cmIncludeRegularExpressionCommand;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE
+ {
+ return "include_regular_expression";
+ }
+
+ cmTypeMacro(cmIncludeRegularExpressionCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
new file mode 100644
index 0000000..86ab85a
--- /dev/null
+++ b/Source/cmInstallCommand.cxx
@@ -0,0 +1,1261 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmInstallCommand.h"
+
+#include "cmExportSet.h"
+#include "cmInstallCommandArguments.h"
+#include "cmInstallDirectoryGenerator.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallFilesGenerator.h"
+#include "cmInstallScriptGenerator.h"
+#include "cmInstallTargetGenerator.h"
+#include "cmTargetExport.h"
+
+#include <cmsys/Glob.hxx>
+
+static cmInstallTargetGenerator* CreateInstallTargetGenerator(
+ cmTarget& target, const cmInstallCommandArguments& args, bool impLib,
+ bool forceOpt = false)
+{
+ cmInstallGenerator::MessageLevel message =
+ cmInstallGenerator::SelectMessageLevel(target.GetMakefile());
+ target.SetHaveInstallRule(true);
+ return new cmInstallTargetGenerator(
+ target.GetName(), args.GetDestination().c_str(), impLib,
+ args.GetPermissions().c_str(), args.GetConfigurations(),
+ args.GetComponent().c_str(), message, args.GetExcludeFromAll(),
+ args.GetOptional() || forceOpt);
+}
+
+static cmInstallFilesGenerator* CreateInstallFilesGenerator(
+ cmMakefile* mf, const std::vector<std::string>& absFiles,
+ const cmInstallCommandArguments& args, bool programs)
+{
+ cmInstallGenerator::MessageLevel message =
+ cmInstallGenerator::SelectMessageLevel(mf);
+ return new cmInstallFilesGenerator(
+ absFiles, args.GetDestination().c_str(), programs,
+ args.GetPermissions().c_str(), args.GetConfigurations(),
+ args.GetComponent().c_str(), message, args.GetExcludeFromAll(),
+ args.GetRename().c_str(), args.GetOptional());
+}
+
+// cmInstallCommand
+bool cmInstallCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ // Allow calling with no arguments so that arguments may be built up
+ // using a variable that may be left empty.
+ if (args.empty()) {
+ return true;
+ }
+
+ // Enable the install target.
+ this->Makefile->GetGlobalGenerator()->EnableInstallTarget();
+
+ this->DefaultComponentName =
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME");
+ if (this->DefaultComponentName.empty()) {
+ this->DefaultComponentName = "Unspecified";
+ }
+
+ // Switch among the command modes.
+ if (args[0] == "SCRIPT") {
+ return this->HandleScriptMode(args);
+ } else if (args[0] == "CODE") {
+ return this->HandleScriptMode(args);
+ } else if (args[0] == "TARGETS") {
+ return this->HandleTargetsMode(args);
+ } else if (args[0] == "FILES") {
+ return this->HandleFilesMode(args);
+ } else if (args[0] == "PROGRAMS") {
+ return this->HandleFilesMode(args);
+ } else if (args[0] == "DIRECTORY") {
+ return this->HandleDirectoryMode(args);
+ } else if (args[0] == "EXPORT") {
+ return this->HandleExportMode(args);
+ }
+
+ // Unknown mode.
+ std::string e = "called with unknown mode ";
+ e += args[0];
+ this->SetError(e);
+ return false;
+}
+
+bool cmInstallCommand::HandleScriptMode(std::vector<std::string> const& args)
+{
+ std::string component = this->DefaultComponentName;
+ int componentCount = 0;
+ bool doing_script = false;
+ bool doing_code = false;
+ bool exclude_from_all = false;
+
+ // Scan the args once for COMPONENT. Only allow one.
+ //
+ for (size_t i = 0; i < args.size(); ++i) {
+ if (args[i] == "COMPONENT" && i + 1 < args.size()) {
+ ++componentCount;
+ ++i;
+ component = args[i];
+ }
+ if (args[i] == "EXCLUDE_FROM_ALL") {
+ exclude_from_all = true;
+ }
+ }
+
+ if (componentCount > 1) {
+ this->SetError("given more than one COMPONENT for the SCRIPT or CODE "
+ "signature of the INSTALL command. "
+ "Use multiple INSTALL commands with one COMPONENT each.");
+ return false;
+ }
+
+ // Scan the args again, this time adding install generators each time we
+ // encounter a SCRIPT or CODE arg:
+ //
+ for (size_t i = 0; i < args.size(); ++i) {
+ if (args[i] == "SCRIPT") {
+ doing_script = true;
+ doing_code = false;
+ } else if (args[i] == "CODE") {
+ doing_script = false;
+ doing_code = true;
+ } else if (args[i] == "COMPONENT") {
+ doing_script = false;
+ doing_code = false;
+ } else if (doing_script) {
+ doing_script = false;
+ std::string script = args[i];
+ if (!cmSystemTools::FileIsFullPath(script.c_str())) {
+ script = this->Makefile->GetCurrentSourceDirectory();
+ script += "/";
+ script += args[i];
+ }
+ if (cmSystemTools::FileIsDirectory(script)) {
+ this->SetError("given a directory as value of SCRIPT argument.");
+ return false;
+ }
+ this->Makefile->AddInstallGenerator(new cmInstallScriptGenerator(
+ script.c_str(), false, component.c_str(), exclude_from_all));
+ } else if (doing_code) {
+ doing_code = false;
+ std::string code = args[i];
+ this->Makefile->AddInstallGenerator(new cmInstallScriptGenerator(
+ code.c_str(), true, component.c_str(), exclude_from_all));
+ }
+ }
+
+ if (doing_script) {
+ this->SetError("given no value for SCRIPT argument.");
+ return false;
+ }
+ if (doing_code) {
+ this->SetError("given no value for CODE argument.");
+ return false;
+ }
+
+ // Tell the global generator about any installation component names
+ // specified.
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(component.c_str());
+
+ 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, CM_NULLPTR);
+ cmCAStringVector archiveArgVector(&argHelper, "ARCHIVE", &group);
+ cmCAStringVector libraryArgVector(&argHelper, "LIBRARY", &group);
+ cmCAStringVector runtimeArgVector(&argHelper, "RUNTIME", &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(CM_NULLPTR);
+ group.Follows(&genericArgVector);
+
+ argHelper.Parse(&args, CM_NULLPTR);
+
+ // 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> unknownArgs;
+ cmInstallCommandArguments genericArgs(this->DefaultComponentName);
+ cmCAStringVector targetList(&genericArgs.Parser, "TARGETS");
+ cmCAString exports(&genericArgs.Parser, "EXPORT",
+ &genericArgs.ArgumentGroup);
+ targetList.Follows(CM_NULLPTR);
+ genericArgs.ArgumentGroup.Follows(&targetList);
+ genericArgs.Parse(&genericArgVector.GetVector(), &unknownArgs);
+ bool success = genericArgs.Finalize();
+
+ cmInstallCommandArguments archiveArgs(this->DefaultComponentName);
+ cmInstallCommandArguments libraryArgs(this->DefaultComponentName);
+ cmInstallCommandArguments runtimeArgs(this->DefaultComponentName);
+ cmInstallCommandArguments frameworkArgs(this->DefaultComponentName);
+ cmInstallCommandArguments bundleArgs(this->DefaultComponentName);
+ cmInstallCommandArguments privateHeaderArgs(this->DefaultComponentName);
+ cmInstallCommandArguments publicHeaderArgs(this->DefaultComponentName);
+ cmInstallCommandArguments resourceArgs(this->DefaultComponentName);
+ cmInstallCommandIncludesArgument includesArgs;
+
+ // 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);
+ 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);
+
+ if (!unknownArgs.empty()) {
+ // Unknown argument.
+ std::ostringstream e;
+ e << "TARGETS given unknown argument \"" << unknownArgs[0] << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // apply generic args
+ archiveArgs.SetGenericArguments(&genericArgs);
+ libraryArgs.SetGenericArguments(&genericArgs);
+ runtimeArgs.SetGenericArguments(&genericArgs);
+ frameworkArgs.SetGenericArguments(&genericArgs);
+ bundleArgs.SetGenericArguments(&genericArgs);
+ privateHeaderArgs.SetGenericArguments(&genericArgs);
+ publicHeaderArgs.SetGenericArguments(&genericArgs);
+ resourceArgs.SetGenericArguments(&genericArgs);
+
+ success = success && archiveArgs.Finalize();
+ success = success && libraryArgs.Finalize();
+ success = success && runtimeArgs.Finalize();
+ success = success && frameworkArgs.Finalize();
+ success = success && bundleArgs.Finalize();
+ success = success && privateHeaderArgs.Finalize();
+ success = success && publicHeaderArgs.Finalize();
+ success = success && resourceArgs.Finalize();
+
+ if (!success) {
+ return false;
+ }
+
+ // Enforce argument rules too complex to specify for the
+ // general-purpose parser.
+ if (archiveArgs.GetNamelinkOnly() || runtimeArgs.GetNamelinkOnly() ||
+ frameworkArgs.GetNamelinkOnly() || bundleArgs.GetNamelinkOnly() ||
+ privateHeaderArgs.GetNamelinkOnly() ||
+ publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly()) {
+ this->SetError(
+ "TARGETS given NAMELINK_ONLY option not in LIBRARY group. "
+ "The NAMELINK_ONLY option may be specified only following LIBRARY.");
+ return false;
+ }
+ if (archiveArgs.GetNamelinkSkip() || runtimeArgs.GetNamelinkSkip() ||
+ frameworkArgs.GetNamelinkSkip() || bundleArgs.GetNamelinkSkip() ||
+ privateHeaderArgs.GetNamelinkSkip() ||
+ publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip()) {
+ this->SetError(
+ "TARGETS given NAMELINK_SKIP option not in LIBRARY group. "
+ "The NAMELINK_SKIP option may be specified only following LIBRARY.");
+ return false;
+ }
+ if (libraryArgs.GetNamelinkOnly() && libraryArgs.GetNamelinkSkip()) {
+ this->SetError("TARGETS given NAMELINK_ONLY and NAMELINK_SKIP. "
+ "At most one of these two options may be specified.");
+ return false;
+ }
+
+ // Select the mode for installing symlinks to versioned shared libraries.
+ cmInstallTargetGenerator::NamelinkModeType namelinkMode =
+ cmInstallTargetGenerator::NamelinkModeNone;
+ if (libraryArgs.GetNamelinkOnly()) {
+ namelinkMode = cmInstallTargetGenerator::NamelinkModeOnly;
+ } else if (libraryArgs.GetNamelinkSkip()) {
+ namelinkMode = cmInstallTargetGenerator::NamelinkModeSkip;
+ }
+
+ // Check if there is something to do.
+ if (targetList.GetVector().empty()) {
+ return true;
+ }
+
+ // Check whether this is a DLL platform.
+ bool dll_platform =
+ (this->Makefile->IsOn("WIN32") || this->Makefile->IsOn("CYGWIN") ||
+ this->Makefile->IsOn("MINGW"));
+
+ for (std::vector<std::string>::const_iterator targetIt =
+ targetList.GetVector().begin();
+ targetIt != targetList.GetVector().end(); ++targetIt) {
+
+ if (this->Makefile->IsAlias(*targetIt)) {
+ std::ostringstream e;
+ e << "TARGETS given target \"" << (*targetIt) << "\" which is an alias.";
+ this->SetError(e.str());
+ return false;
+ }
+ // Lookup this target in the current directory.
+ if (cmTarget* target =
+ this->Makefile->FindLocalNonAliasTarget(*targetIt)) {
+ // Found the target. Check its type.
+ if (target->GetType() != cmState::EXECUTABLE &&
+ target->GetType() != cmState::STATIC_LIBRARY &&
+ target->GetType() != cmState::SHARED_LIBRARY &&
+ target->GetType() != cmState::MODULE_LIBRARY &&
+ target->GetType() != cmState::OBJECT_LIBRARY &&
+ target->GetType() != cmState::INTERFACE_LIBRARY) {
+ std::ostringstream e;
+ e << "TARGETS given target \"" << (*targetIt)
+ << "\" which is not an executable, library, or module.";
+ this->SetError(e.str());
+ return false;
+ } else if (target->GetType() == cmState::OBJECT_LIBRARY) {
+ std::ostringstream e;
+ e << "TARGETS given OBJECT library \"" << (*targetIt)
+ << "\" which may not be installed.";
+ this->SetError(e.str());
+ return false;
+ }
+ // Store the target in the list to be installed.
+ targets.push_back(target);
+ } else {
+ // Did not find the target.
+ std::ostringstream e;
+ e << "TARGETS given target \"" << (*targetIt)
+ << "\" which does not exist in this directory.";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ // Keep track of whether we will be performing an installation of
+ // any files of the given type.
+ bool installsArchive = false;
+ bool installsLibrary = false;
+ bool installsRuntime = false;
+ bool installsFramework = false;
+ bool installsBundle = false;
+ bool installsPrivateHeader = false;
+ bool installsPublicHeader = false;
+ bool installsResource = false;
+
+ // Generate install script code to install the given targets.
+ for (std::vector<cmTarget*>::iterator ti = targets.begin();
+ ti != targets.end(); ++ti) {
+ // Handle each target type.
+ cmTarget& target = *(*ti);
+ cmInstallTargetGenerator* archiveGenerator = CM_NULLPTR;
+ cmInstallTargetGenerator* libraryGenerator = CM_NULLPTR;
+ cmInstallTargetGenerator* runtimeGenerator = CM_NULLPTR;
+ cmInstallTargetGenerator* frameworkGenerator = CM_NULLPTR;
+ cmInstallTargetGenerator* bundleGenerator = CM_NULLPTR;
+ cmInstallFilesGenerator* privateHeaderGenerator = CM_NULLPTR;
+ cmInstallFilesGenerator* publicHeaderGenerator = CM_NULLPTR;
+ cmInstallFilesGenerator* resourceGenerator = CM_NULLPTR;
+
+ // Track whether this is a namelink-only rule.
+ bool namelinkOnly = false;
+
+ switch (target.GetType()) {
+ case cmState::SHARED_LIBRARY: {
+ // Shared libraries are handled differently on DLL and non-DLL
+ // platforms. All windows platforms are DLL platforms including
+ // cygwin. Currently no other platform is a DLL platform.
+ if (dll_platform) {
+ // When in namelink only mode skip all libraries on Windows.
+ if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
+ continue;
+ }
+
+ // This is a DLL platform.
+ if (!archiveArgs.GetDestination().empty()) {
+ // The import library uses the ARCHIVE properties.
+ archiveGenerator =
+ CreateInstallTargetGenerator(target, archiveArgs, true);
+ }
+ if (!runtimeArgs.GetDestination().empty()) {
+ // The DLL uses the RUNTIME properties.
+ runtimeGenerator =
+ CreateInstallTargetGenerator(target, runtimeArgs, false);
+ }
+ if ((archiveGenerator == CM_NULLPTR) &&
+ (runtimeGenerator == CM_NULLPTR)) {
+ this->SetError("Library TARGETS given no DESTINATION!");
+ return false;
+ }
+ } else {
+ // This is a non-DLL platform.
+ // If it is marked with FRAMEWORK property use the FRAMEWORK set of
+ // INSTALL properties. Otherwise, use the LIBRARY properties.
+ if (target.IsFrameworkOnApple()) {
+ // When in namelink only mode skip frameworks.
+ if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
+ continue;
+ }
+
+ // Use the FRAMEWORK properties.
+ if (!frameworkArgs.GetDestination().empty()) {
+ frameworkGenerator =
+ CreateInstallTargetGenerator(target, frameworkArgs, false);
+ } else {
+ std::ostringstream e;
+ e << "TARGETS given no FRAMEWORK DESTINATION for shared library "
+ "FRAMEWORK target \""
+ << target.GetName() << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ } else {
+ // The shared library uses the LIBRARY properties.
+ if (!libraryArgs.GetDestination().empty()) {
+ libraryGenerator =
+ CreateInstallTargetGenerator(target, libraryArgs, false);
+ libraryGenerator->SetNamelinkMode(namelinkMode);
+ namelinkOnly =
+ (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
+ } else {
+ std::ostringstream e;
+ e << "TARGETS given no LIBRARY DESTINATION for shared library "
+ "target \""
+ << target.GetName() << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+ }
+ } break;
+ case cmState::STATIC_LIBRARY: {
+ // Static libraries use ARCHIVE properties.
+ if (!archiveArgs.GetDestination().empty()) {
+ archiveGenerator =
+ CreateInstallTargetGenerator(target, archiveArgs, false);
+ } else {
+ std::ostringstream e;
+ e << "TARGETS given no ARCHIVE DESTINATION for static library "
+ "target \""
+ << target.GetName() << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ } break;
+ case cmState::MODULE_LIBRARY: {
+ // Modules use LIBRARY properties.
+ if (!libraryArgs.GetDestination().empty()) {
+ libraryGenerator =
+ CreateInstallTargetGenerator(target, libraryArgs, false);
+ libraryGenerator->SetNamelinkMode(namelinkMode);
+ namelinkOnly =
+ (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
+ } else {
+ std::ostringstream e;
+ e << "TARGETS given no LIBRARY DESTINATION for module target \""
+ << target.GetName() << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ } break;
+ case cmState::EXECUTABLE: {
+ if (target.IsAppBundleOnApple()) {
+ // Application bundles use the BUNDLE properties.
+ if (!bundleArgs.GetDestination().empty()) {
+ bundleGenerator =
+ CreateInstallTargetGenerator(target, bundleArgs, false);
+ } else if (!runtimeArgs.GetDestination().empty()) {
+ bool failure = false;
+ if (this->CheckCMP0006(failure)) {
+ // For CMake 2.4 compatibility fallback to the RUNTIME
+ // properties.
+ bundleGenerator =
+ CreateInstallTargetGenerator(target, runtimeArgs, false);
+ } else if (failure) {
+ return false;
+ }
+ }
+ if (!bundleGenerator) {
+ std::ostringstream e;
+ e << "TARGETS given no BUNDLE DESTINATION for MACOSX_BUNDLE "
+ "executable target \""
+ << target.GetName() << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ } else {
+ // Executables use the RUNTIME properties.
+ if (!runtimeArgs.GetDestination().empty()) {
+ runtimeGenerator =
+ CreateInstallTargetGenerator(target, runtimeArgs, false);
+ } else {
+ std::ostringstream e;
+ e << "TARGETS given no RUNTIME DESTINATION for executable "
+ "target \""
+ << target.GetName() << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ // On DLL platforms an executable may also have an import
+ // library. Install it to the archive destination if it
+ // exists.
+ if (dll_platform && !archiveArgs.GetDestination().empty() &&
+ target.IsExecutableWithExports()) {
+ // The import library uses the ARCHIVE properties.
+ archiveGenerator =
+ CreateInstallTargetGenerator(target, archiveArgs, true, true);
+ }
+ } break;
+ case cmState::INTERFACE_LIBRARY:
+ // Nothing to do. An INTERFACE_LIBRARY can be installed, but the
+ // only effect of that is to make it exportable. It installs no
+ // other files itself.
+ break;
+ default:
+ // This should never happen due to the above type check.
+ // Ignore the case.
+ break;
+ }
+
+ // These well-known sets of files are installed *automatically* for
+ // FRAMEWORK SHARED library targets on the Mac as part of installing the
+ // FRAMEWORK. For other target types or on other platforms, they are not
+ // installed automatically and so we need to create install files
+ // generators for them.
+ bool createInstallGeneratorsForTargetFileSets = true;
+
+ if (target.IsFrameworkOnApple() ||
+ target.GetType() == cmState::INTERFACE_LIBRARY) {
+ createInstallGeneratorsForTargetFileSets = false;
+ }
+
+ if (createInstallGeneratorsForTargetFileSets && !namelinkOnly) {
+ const char* files = target.GetProperty("PRIVATE_HEADER");
+ if ((files) && (*files)) {
+ std::vector<std::string> relFiles;
+ cmSystemTools::ExpandListArgument(files, relFiles);
+ std::vector<std::string> absFiles;
+ if (!this->MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles)) {
+ return false;
+ }
+
+ // Create the files install generator.
+ if (!privateHeaderArgs.GetDestination().empty()) {
+ privateHeaderGenerator = CreateInstallFilesGenerator(
+ this->Makefile, absFiles, privateHeaderArgs, false);
+ } else {
+ std::ostringstream e;
+ e << "INSTALL TARGETS - target " << target.GetName() << " has "
+ << "PRIVATE_HEADER files but no PRIVATE_HEADER DESTINATION.";
+ cmSystemTools::Message(e.str().c_str(), "Warning");
+ }
+ }
+
+ files = target.GetProperty("PUBLIC_HEADER");
+ if ((files) && (*files)) {
+ std::vector<std::string> relFiles;
+ cmSystemTools::ExpandListArgument(files, relFiles);
+ std::vector<std::string> absFiles;
+ if (!this->MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles)) {
+ return false;
+ }
+
+ // Create the files install generator.
+ if (!publicHeaderArgs.GetDestination().empty()) {
+ publicHeaderGenerator = CreateInstallFilesGenerator(
+ this->Makefile, absFiles, publicHeaderArgs, false);
+ } else {
+ std::ostringstream e;
+ e << "INSTALL TARGETS - target " << target.GetName() << " has "
+ << "PUBLIC_HEADER files but no PUBLIC_HEADER DESTINATION.";
+ cmSystemTools::Message(e.str().c_str(), "Warning");
+ }
+ }
+
+ files = target.GetProperty("RESOURCE");
+ if ((files) && (*files)) {
+ std::vector<std::string> relFiles;
+ cmSystemTools::ExpandListArgument(files, relFiles);
+ std::vector<std::string> absFiles;
+ if (!this->MakeFilesFullPath("RESOURCE", relFiles, absFiles)) {
+ return false;
+ }
+
+ // Create the files install generator.
+ if (!resourceArgs.GetDestination().empty()) {
+ resourceGenerator = CreateInstallFilesGenerator(
+ this->Makefile, absFiles, resourceArgs, false);
+ } else {
+ std::ostringstream e;
+ e << "INSTALL TARGETS - target " << target.GetName() << " has "
+ << "RESOURCE files but no RESOURCE DESTINATION.";
+ cmSystemTools::Message(e.str().c_str(), "Warning");
+ }
+ }
+ }
+
+ // Keep track of whether we're installing anything in each category
+ installsArchive = installsArchive || archiveGenerator != CM_NULLPTR;
+ installsLibrary = installsLibrary || libraryGenerator != CM_NULLPTR;
+ installsRuntime = installsRuntime || runtimeGenerator != CM_NULLPTR;
+ installsFramework = installsFramework || frameworkGenerator != CM_NULLPTR;
+ installsBundle = installsBundle || bundleGenerator != CM_NULLPTR;
+ installsPrivateHeader =
+ installsPrivateHeader || privateHeaderGenerator != CM_NULLPTR;
+ installsPublicHeader =
+ installsPublicHeader || publicHeaderGenerator != CM_NULLPTR;
+ installsResource = installsResource || resourceGenerator;
+
+ this->Makefile->AddInstallGenerator(archiveGenerator);
+ this->Makefile->AddInstallGenerator(libraryGenerator);
+ this->Makefile->AddInstallGenerator(runtimeGenerator);
+ this->Makefile->AddInstallGenerator(frameworkGenerator);
+ this->Makefile->AddInstallGenerator(bundleGenerator);
+ this->Makefile->AddInstallGenerator(privateHeaderGenerator);
+ this->Makefile->AddInstallGenerator(publicHeaderGenerator);
+ this->Makefile->AddInstallGenerator(resourceGenerator);
+
+ // Add this install rule to an export if one was specified and
+ // this is not a namelink-only rule.
+ if (!exports.GetString().empty() && !namelinkOnly) {
+ cmTargetExport* te = new cmTargetExport;
+ te->TargetName = target.GetName();
+ te->ArchiveGenerator = archiveGenerator;
+ te->BundleGenerator = bundleGenerator;
+ te->FrameworkGenerator = frameworkGenerator;
+ te->HeaderGenerator = publicHeaderGenerator;
+ te->LibraryGenerator = libraryGenerator;
+ te->RuntimeGenerator = runtimeGenerator;
+ this->Makefile->GetGlobalGenerator()
+ ->GetExportSets()[exports.GetString()]
+ ->AddTargetExport(te);
+
+ te->InterfaceIncludeDirectories =
+ cmJoin(includesArgs.GetIncludeDirs(), ";");
+ }
+ }
+
+ // Tell the global generator about any installation component names
+ // specified
+ if (installsArchive) {
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(
+ archiveArgs.GetComponent().c_str());
+ }
+ if (installsLibrary) {
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(
+ libraryArgs.GetComponent().c_str());
+ }
+ if (installsRuntime) {
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(
+ runtimeArgs.GetComponent().c_str());
+ }
+ if (installsFramework) {
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(
+ frameworkArgs.GetComponent().c_str());
+ }
+ if (installsBundle) {
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(
+ bundleArgs.GetComponent().c_str());
+ }
+ if (installsPrivateHeader) {
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(
+ privateHeaderArgs.GetComponent().c_str());
+ }
+ if (installsPublicHeader) {
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(
+ publicHeaderArgs.GetComponent().c_str());
+ }
+ if (installsResource) {
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(
+ resourceArgs.GetComponent().c_str());
+ }
+
+ return true;
+}
+
+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(CM_NULLPTR);
+ ica.ArgumentGroup.Follows(&files);
+ std::vector<std::string> unknownArgs;
+ ica.Parse(&args, &unknownArgs);
+
+ if (!unknownArgs.empty()) {
+ // Unknown argument.
+ std::ostringstream e;
+ e << args[0] << " given unknown argument \"" << unknownArgs[0] << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+
+ const std::vector<std::string>& filesVector = files.GetVector();
+
+ // Check if there is something to do.
+ if (filesVector.empty()) {
+ return true;
+ }
+
+ if (!ica.GetRename().empty() && filesVector.size() > 1) {
+ // The rename option works only with one file.
+ std::ostringstream e;
+ e << args[0] << " given RENAME option with more than one file.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ std::vector<std::string> absFiles;
+ if (!this->MakeFilesFullPath(args[0].c_str(), filesVector, absFiles)) {
+ return false;
+ }
+
+ cmPolicies::PolicyStatus status =
+ this->Makefile->GetPolicyStatus(cmPolicies::CMP0062);
+
+ cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ for (std::vector<std::string>::const_iterator fileIt = filesVector.begin();
+ fileIt != filesVector.end(); ++fileIt) {
+ if (gg->IsExportedTargetsFile(*fileIt)) {
+ const char* modal = CM_NULLPTR;
+ std::ostringstream e;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+
+ switch (status) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0062) << "\n";
+ modal = "should";
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ modal = "may";
+ messageType = cmake::FATAL_ERROR;
+ }
+ if (modal) {
+ e << "The file\n " << *fileIt << "\nwas generated by the export() "
+ "command. It "
+ << modal << " not be installed with the "
+ "install() command. Use the install(EXPORT) mechanism "
+ "instead. See the cmake-packages(7) manual for more.\n";
+ this->Makefile->IssueMessage(messageType, e.str());
+ if (messageType == cmake::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+ }
+
+ if (!ica.Finalize()) {
+ return false;
+ }
+
+ if (ica.GetDestination().empty()) {
+ // A destination is required.
+ std::ostringstream e;
+ e << args[0] << " given no DESTINATION!";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Create the files install generator.
+ this->Makefile->AddInstallGenerator(
+ CreateInstallFilesGenerator(this->Makefile, absFiles, ica, programs));
+
+ // Tell the global generator about any installation component names
+ // specified.
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(
+ ica.GetComponent().c_str());
+
+ return true;
+}
+
+bool cmInstallCommand::HandleDirectoryMode(
+ std::vector<std::string> const& args)
+{
+ enum Doing
+ {
+ DoingNone,
+ DoingDirs,
+ DoingDestination,
+ DoingPattern,
+ DoingRegex,
+ DoingPermsFile,
+ DoingPermsDir,
+ DoingPermsMatch,
+ DoingConfigurations,
+ DoingComponent
+ };
+ Doing doing = DoingDirs;
+ bool in_match_mode = false;
+ bool optional = false;
+ bool exclude_from_all = false;
+ bool message_never = false;
+ std::vector<std::string> dirs;
+ const char* destination = CM_NULLPTR;
+ std::string permissions_file;
+ std::string permissions_dir;
+ std::vector<std::string> configurations;
+ std::string component = this->DefaultComponentName;
+ std::string literal_args;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "DESTINATION") {
+ if (in_match_mode) {
+ std::ostringstream e;
+ e << args[0] << " does not allow \"" << args[i]
+ << "\" after PATTERN or REGEX.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Switch to setting the destination property.
+ doing = DoingDestination;
+ } else if (args[i] == "OPTIONAL") {
+ if (in_match_mode) {
+ std::ostringstream e;
+ e << args[0] << " does not allow \"" << args[i]
+ << "\" after PATTERN or REGEX.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Mark the rule as optional.
+ optional = true;
+ doing = DoingNone;
+ } else if (args[i] == "MESSAGE_NEVER") {
+ if (in_match_mode) {
+ std::ostringstream e;
+ e << args[0] << " does not allow \"" << args[i]
+ << "\" after PATTERN or REGEX.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Mark the rule as quiet.
+ message_never = true;
+ doing = DoingNone;
+ } else if (args[i] == "PATTERN") {
+ // Switch to a new pattern match rule.
+ doing = DoingPattern;
+ in_match_mode = true;
+ } else if (args[i] == "REGEX") {
+ // Switch to a new regex match rule.
+ doing = DoingRegex;
+ in_match_mode = true;
+ } else if (args[i] == "EXCLUDE") {
+ // Add this property to the current match rule.
+ if (!in_match_mode || doing == DoingPattern || doing == DoingRegex) {
+ std::ostringstream e;
+ e << args[0] << " does not allow \"" << args[i]
+ << "\" before a PATTERN or REGEX is given.";
+ this->SetError(e.str());
+ return false;
+ }
+ literal_args += " EXCLUDE";
+ doing = DoingNone;
+ } else if (args[i] == "PERMISSIONS") {
+ if (!in_match_mode) {
+ std::ostringstream e;
+ e << args[0] << " does not allow \"" << args[i]
+ << "\" before a PATTERN or REGEX is given.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Switch to setting the current match permissions property.
+ literal_args += " PERMISSIONS";
+ doing = DoingPermsMatch;
+ } else if (args[i] == "FILE_PERMISSIONS") {
+ if (in_match_mode) {
+ std::ostringstream e;
+ e << args[0] << " does not allow \"" << args[i]
+ << "\" after PATTERN or REGEX.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Switch to setting the file permissions property.
+ doing = DoingPermsFile;
+ } else if (args[i] == "DIRECTORY_PERMISSIONS") {
+ if (in_match_mode) {
+ std::ostringstream e;
+ e << args[0] << " does not allow \"" << args[i]
+ << "\" after PATTERN or REGEX.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Switch to setting the directory permissions property.
+ doing = DoingPermsDir;
+ } else if (args[i] == "USE_SOURCE_PERMISSIONS") {
+ if (in_match_mode) {
+ std::ostringstream e;
+ e << args[0] << " does not allow \"" << args[i]
+ << "\" after PATTERN or REGEX.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Add this option literally.
+ literal_args += " USE_SOURCE_PERMISSIONS";
+ doing = DoingNone;
+ } else if (args[i] == "FILES_MATCHING") {
+ if (in_match_mode) {
+ std::ostringstream e;
+ e << args[0] << " does not allow \"" << args[i]
+ << "\" after PATTERN or REGEX.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Add this option literally.
+ literal_args += " FILES_MATCHING";
+ doing = DoingNone;
+ } else if (args[i] == "CONFIGURATIONS") {
+ if (in_match_mode) {
+ std::ostringstream e;
+ e << args[0] << " does not allow \"" << args[i]
+ << "\" after PATTERN or REGEX.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Switch to setting the configurations property.
+ doing = DoingConfigurations;
+ } else if (args[i] == "COMPONENT") {
+ if (in_match_mode) {
+ std::ostringstream e;
+ e << args[0] << " does not allow \"" << args[i]
+ << "\" after PATTERN or REGEX.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Switch to setting the component property.
+ doing = DoingComponent;
+ } else if (args[i] == "EXCLUDE_FROM_ALL") {
+ if (in_match_mode) {
+ std::ostringstream e;
+ e << args[0] << " does not allow \"" << args[i]
+ << "\" after PATTERN or REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+ exclude_from_all = true;
+ doing = DoingNone;
+ } else if (doing == DoingDirs) {
+ // Convert this directory to a full path.
+ std::string dir = args[i];
+ if (!cmSystemTools::FileIsFullPath(dir.c_str())) {
+ dir = this->Makefile->GetCurrentSourceDirectory();
+ dir += "/";
+ dir += args[i];
+ }
+
+ // Make sure the name is a directory.
+ if (cmSystemTools::FileExists(dir.c_str()) &&
+ !cmSystemTools::FileIsDirectory(dir)) {
+ std::ostringstream e;
+ e << args[0] << " given non-directory \"" << args[i]
+ << "\" to install.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Store the directory for installation.
+ dirs.push_back(dir);
+ } else if (doing == DoingConfigurations) {
+ configurations.push_back(args[i]);
+ } else if (doing == DoingDestination) {
+ destination = args[i].c_str();
+ doing = DoingNone;
+ } else if (doing == 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.
+ literal_args += " REGEX \"/";
+ std::string regex = cmsys::Glob::PatternToRegex(args[i], false);
+ cmSystemTools::ReplaceString(regex, "\\", "\\\\");
+ literal_args += regex;
+ literal_args += "$\"";
+ doing = DoingNone;
+ } else if (doing == DoingRegex) {
+ literal_args += " REGEX \"";
+// Match rules are case-insensitive on some platforms.
+#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
+ std::string regex = cmSystemTools::LowerCase(args[i]);
+#else
+ std::string regex = args[i];
+#endif
+ cmSystemTools::ReplaceString(regex, "\\", "\\\\");
+ literal_args += regex;
+ literal_args += "\"";
+ doing = DoingNone;
+ } else if (doing == DoingComponent) {
+ component = args[i];
+ doing = DoingNone;
+ } else if (doing == DoingPermsFile) {
+ // Check the requested permission.
+ if (!cmInstallCommandArguments::CheckPermissions(args[i],
+ permissions_file)) {
+ std::ostringstream e;
+ e << args[0] << " given invalid file permission \"" << args[i]
+ << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ } else if (doing == DoingPermsDir) {
+ // Check the requested permission.
+ if (!cmInstallCommandArguments::CheckPermissions(args[i],
+ permissions_dir)) {
+ std::ostringstream e;
+ e << args[0] << " given invalid directory permission \"" << args[i]
+ << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ } else if (doing == DoingPermsMatch) {
+ // Check the requested permission.
+ if (!cmInstallCommandArguments::CheckPermissions(args[i],
+ literal_args)) {
+ std::ostringstream e;
+ e << args[0] << " given invalid permission \"" << args[i] << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ } else {
+ // Unknown argument.
+ std::ostringstream e;
+ e << args[0] << " given unknown argument \"" << args[i] << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ // Support installing an empty directory.
+ if (dirs.empty() && destination) {
+ dirs.push_back("");
+ }
+
+ // Check if there is something to do.
+ if (dirs.empty()) {
+ return true;
+ }
+ if (!destination) {
+ // A destination is required.
+ std::ostringstream e;
+ e << args[0] << " given no DESTINATION!";
+ this->SetError(e.str());
+ return false;
+ }
+
+ cmInstallGenerator::MessageLevel message =
+ cmInstallGenerator::SelectMessageLevel(this->Makefile, message_never);
+
+ // Create the directory install generator.
+ this->Makefile->AddInstallGenerator(new cmInstallDirectoryGenerator(
+ dirs, destination, permissions_file.c_str(), permissions_dir.c_str(),
+ configurations, component.c_str(), message, exclude_from_all,
+ literal_args.c_str(), optional));
+
+ // Tell the global generator about any installation component names
+ // specified.
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(component.c_str());
+
+ return true;
+}
+
+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(CM_NULLPTR);
+
+ ica.ArgumentGroup.Follows(&exp);
+ std::vector<std::string> unknownArgs;
+ ica.Parse(&args, &unknownArgs);
+
+ if (!unknownArgs.empty()) {
+ // Unknown argument.
+ std::ostringstream e;
+ e << args[0] << " given unknown argument \"" << unknownArgs[0] << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+
+ if (!ica.Finalize()) {
+ return false;
+ }
+
+ // Make sure there is a destination.
+ if (ica.GetDestination().empty()) {
+ // A destination is required.
+ std::ostringstream e;
+ e << args[0] << " given no DESTINATION!";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Check the file name.
+ std::string fname = filename.GetString();
+ if (fname.find_first_of(":/\\") != fname.npos) {
+ std::ostringstream e;
+ e << args[0] << " given invalid export file name \"" << fname << "\". "
+ << "The FILE argument may not contain a path. "
+ << "Specify the path in the DESTINATION argument.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Check the file extension.
+ if (!fname.empty() &&
+ cmSystemTools::GetFilenameLastExtension(fname) != ".cmake") {
+ std::ostringstream e;
+ e << args[0] << " given invalid export file name \"" << fname << "\". "
+ << "The FILE argument must specify a name ending in \".cmake\".";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Construct the file name.
+ if (fname.empty()) {
+ fname = exp.GetString();
+ fname += ".cmake";
+
+ if (fname.find_first_of(":/\\") != fname.npos) {
+ std::ostringstream e;
+ e << args[0] << " given export name \"" << exp.GetString() << "\". "
+ << "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.";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ cmExportSet* exportSet =
+ this->Makefile->GetGlobalGenerator()->GetExportSets()[exp.GetString()];
+ if (exportOld.IsEnabled()) {
+ for (std::vector<cmTargetExport*>::const_iterator tei =
+ exportSet->GetTargetExports()->begin();
+ tei != exportSet->GetTargetExports()->end(); ++tei) {
+ cmTargetExport const* te = *tei;
+ cmTarget* tgt =
+ this->Makefile->GetGlobalGenerator()->FindTarget(te->TargetName);
+ const bool newCMP0022Behavior =
+ (tgt && tgt->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
+ tgt->GetPolicyStatusCMP0022() != cmPolicies::OLD);
+
+ if (!newCMP0022Behavior) {
+ std::ostringstream e;
+ e << "INSTALL(EXPORT) given keyword \""
+ << "EXPORT_LINK_INTERFACE_LIBRARIES"
+ << "\", but target \"" << te->TargetName
+ << "\" does not have policy CMP0022 set to NEW.";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+ }
+
+ cmInstallGenerator::MessageLevel message =
+ cmInstallGenerator::SelectMessageLevel(this->Makefile);
+
+ // Create the export install generator.
+ 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());
+ this->Makefile->AddInstallGenerator(exportGenerator);
+
+ return true;
+}
+
+bool cmInstallCommand::MakeFilesFullPath(
+ const char* modeName, const std::vector<std::string>& relFiles,
+ std::vector<std::string>& absFiles)
+{
+ for (std::vector<std::string>::const_iterator fileIt = relFiles.begin();
+ fileIt != relFiles.end(); ++fileIt) {
+ std::string file = (*fileIt);
+ std::string::size_type gpos = cmGeneratorExpression::Find(file);
+ if (gpos != 0 && !cmSystemTools::FileIsFullPath(file.c_str())) {
+ file = this->Makefile->GetCurrentSourceDirectory();
+ file += "/";
+ file += *fileIt;
+ }
+
+ // Make sure the file is not a directory.
+ if (gpos == file.npos && cmSystemTools::FileIsDirectory(file)) {
+ std::ostringstream e;
+ e << modeName << " given directory \"" << (*fileIt) << "\" to install.";
+ this->SetError(e.str());
+ return false;
+ }
+ // Store the file for installation.
+ absFiles.push_back(file);
+ }
+ return true;
+}
+
+bool cmInstallCommand::CheckCMP0006(bool& failure)
+{
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0006)) {
+ case cmPolicies::WARN: {
+ this->Makefile->IssueMessage(
+ cmake::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0006));
+ }
+ case cmPolicies::OLD:
+ // OLD behavior is to allow compatibility
+ return true;
+ case cmPolicies::NEW:
+ // NEW behavior is to disallow compatibility
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ failure = true;
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0006));
+ break;
+ }
+ return false;
+}
diff --git a/Source/cmInstallCommand.h b/Source/cmInstallCommand.h
new file mode 100644
index 0000000..3718ad5
--- /dev/null
+++ b/Source/cmInstallCommand.h
@@ -0,0 +1,59 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmInstallCommand_h
+#define cmInstallCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmInstallCommand
+ * \brief Specifies where to install some files
+ *
+ * cmInstallCommand is a general-purpose interface command for
+ * specifying install rules.
+ */
+class cmInstallCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmInstallCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "install"; }
+
+ cmTypeMacro(cmInstallCommand, cmCommand);
+
+private:
+ bool HandleScriptMode(std::vector<std::string> const& args);
+ bool HandleTargetsMode(std::vector<std::string> const& args);
+ bool HandleFilesMode(std::vector<std::string> const& args);
+ bool HandleDirectoryMode(std::vector<std::string> const& args);
+ bool HandleExportMode(std::vector<std::string> const& args);
+ bool MakeFilesFullPath(const char* modeName,
+ const std::vector<std::string>& relFiles,
+ std::vector<std::string>& absFiles);
+ bool CheckCMP0006(bool& failure);
+
+ std::string DefaultComponentName;
+};
+
+#endif
diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx
new file mode 100644
index 0000000..312c50e
--- /dev/null
+++ b/Source/cmInstallCommandArguments.cxx
@@ -0,0 +1,216 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmInstallCommandArguments.h"
+
+#include "cmSystemTools.h"
+
+// Table of valid permissions.
+const char* cmInstallCommandArguments::PermissionsTable[] = {
+ "OWNER_READ", "OWNER_WRITE", "OWNER_EXECUTE", "GROUP_READ",
+ "GROUP_WRITE", "GROUP_EXECUTE", "WORLD_READ", "WORLD_WRITE",
+ "WORLD_EXECUTE", "SETUID", "SETGID", CM_NULLPTR
+};
+
+const std::string cmInstallCommandArguments::EmptyString;
+
+cmInstallCommandArguments::cmInstallCommandArguments(
+ const std::string& defaultComponent)
+ : Parser()
+ , ArgumentGroup()
+ , Destination(&Parser, "DESTINATION", &ArgumentGroup)
+ , Component(&Parser, "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)
+ , GenericArguments(CM_NULLPTR)
+ , DefaultComponentName(defaultComponent)
+{
+}
+
+const std::string& cmInstallCommandArguments::GetDestination() const
+{
+ if (!this->DestinationString.empty()) {
+ return this->DestinationString;
+ }
+ if (this->GenericArguments != CM_NULLPTR) {
+ return this->GenericArguments->GetDestination();
+ }
+ return this->EmptyString;
+}
+
+const std::string& cmInstallCommandArguments::GetComponent() const
+{
+ if (!this->Component.GetString().empty()) {
+ return this->Component.GetString();
+ }
+ if (this->GenericArguments != CM_NULLPTR) {
+ return this->GenericArguments->GetComponent();
+ }
+ if (!this->DefaultComponentName.empty()) {
+ return this->DefaultComponentName;
+ }
+ static std::string unspecifiedComponent = "Unspecified";
+ return unspecifiedComponent;
+}
+
+const std::string& cmInstallCommandArguments::GetRename() const
+{
+ if (!this->Rename.GetString().empty()) {
+ return this->Rename.GetString();
+ }
+ if (this->GenericArguments != CM_NULLPTR) {
+ return this->GenericArguments->GetRename();
+ }
+ return this->EmptyString;
+}
+
+const std::string& cmInstallCommandArguments::GetPermissions() const
+{
+ if (!this->PermissionsString.empty()) {
+ return this->PermissionsString;
+ }
+ if (this->GenericArguments != CM_NULLPTR) {
+ return this->GenericArguments->GetPermissions();
+ }
+ return this->EmptyString;
+}
+
+bool cmInstallCommandArguments::GetOptional() const
+{
+ if (this->Optional.IsEnabled()) {
+ return true;
+ }
+ if (this->GenericArguments != CM_NULLPTR) {
+ return this->GenericArguments->GetOptional();
+ }
+ return false;
+}
+
+bool cmInstallCommandArguments::GetExcludeFromAll() const
+{
+ if (this->ExcludeFromAll.IsEnabled()) {
+ return true;
+ }
+ if (this->GenericArguments != CM_NULLPTR) {
+ return this->GenericArguments->GetExcludeFromAll();
+ }
+ return false;
+}
+
+bool cmInstallCommandArguments::GetNamelinkOnly() const
+{
+ if (this->NamelinkOnly.IsEnabled()) {
+ return true;
+ }
+ if (this->GenericArguments != CM_NULLPTR) {
+ return this->GenericArguments->GetNamelinkOnly();
+ }
+ return false;
+}
+
+bool cmInstallCommandArguments::GetNamelinkSkip() const
+{
+ if (this->NamelinkSkip.IsEnabled()) {
+ return true;
+ }
+ if (this->GenericArguments != CM_NULLPTR) {
+ return this->GenericArguments->GetNamelinkSkip();
+ }
+ return false;
+}
+
+const std::vector<std::string>& cmInstallCommandArguments::GetConfigurations()
+ const
+{
+ if (!this->Configurations.GetVector().empty()) {
+ return this->Configurations.GetVector();
+ }
+ if (this->GenericArguments != CM_NULLPTR) {
+ return this->GenericArguments->GetConfigurations();
+ }
+ return this->Configurations.GetVector();
+}
+
+bool cmInstallCommandArguments::Finalize()
+{
+ if (!this->CheckPermissions()) {
+ return false;
+ }
+ this->DestinationString = this->Destination.GetString();
+ 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 = "";
+ for (std::vector<std::string>::const_iterator permIt =
+ this->Permissions.GetVector().begin();
+ permIt != this->Permissions.GetVector().end(); ++permIt) {
+ if (!this->CheckPermissions(*permIt, this->PermissionsString)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmInstallCommandArguments::CheckPermissions(
+ const std::string& onePermission, std::string& permissions)
+{
+ // Check the permission against the table.
+ for (const char** valid = cmInstallCommandArguments::PermissionsTable;
+ *valid; ++valid) {
+ if (onePermission == *valid) {
+ // This is a valid permission.
+ permissions += " ";
+ permissions += onePermission;
+ return true;
+ }
+ }
+ // This is not a valid permission.
+ return false;
+}
+
+cmInstallCommandIncludesArgument::cmInstallCommandIncludesArgument()
+{
+}
+
+const std::vector<std::string>&
+cmInstallCommandIncludesArgument::GetIncludeDirs() const
+{
+ return this->IncludeDirs;
+}
+
+void cmInstallCommandIncludesArgument::Parse(
+ const std::vector<std::string>* args, std::vector<std::string>*)
+{
+ if (args->empty()) {
+ return;
+ }
+ std::vector<std::string>::const_iterator it = args->begin();
+ ++it;
+ for (; it != args->end(); ++it) {
+ std::string dir = *it;
+ cmSystemTools::ConvertToUnixSlashes(dir);
+ this->IncludeDirs.push_back(dir);
+ }
+}
diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h
new file mode 100644
index 0000000..6ccb3e8
--- /dev/null
+++ b/Source/cmInstallCommandArguments.h
@@ -0,0 +1,86 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmInstallCommandArguments_h
+#define cmInstallCommandArguments_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmCommandArgumentsHelper.h"
+
+class cmInstallCommandArguments
+{
+public:
+ cmInstallCommandArguments(const std::string& defaultComponent);
+ void SetGenericArguments(cmInstallCommandArguments* args)
+ {
+ this->GenericArguments = args;
+ }
+ void Parse(const std::vector<std::string>* args,
+ std::vector<std::string>* unconsumedArgs);
+
+ // Compute destination path.and check permissions
+ bool Finalize();
+
+ const std::string& GetDestination() const;
+ const std::string& GetComponent() const;
+ bool GetExcludeFromAll() const;
+ const std::string& GetRename() const;
+ const std::string& GetPermissions() const;
+ const std::vector<std::string>& GetConfigurations() const;
+ bool GetOptional() const;
+ bool GetNamelinkOnly() const;
+ bool GetNamelinkSkip() 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:
+ cmInstallCommandArguments(); // disabled
+ cmCAString Destination;
+ cmCAString Component;
+ cmCAEnabler ExcludeFromAll;
+ cmCAString Rename;
+ cmCAStringVector Permissions;
+ cmCAStringVector Configurations;
+ cmCAEnabler Optional;
+ cmCAEnabler NamelinkOnly;
+ cmCAEnabler NamelinkSkip;
+
+ std::string DestinationString;
+ std::string PermissionsString;
+
+ cmInstallCommandArguments* GenericArguments;
+ static const char* PermissionsTable[];
+ static const std::string EmptyString;
+ std::string DefaultComponentName;
+ bool CheckPermissions();
+};
+
+class cmInstallCommandIncludesArgument
+{
+public:
+ cmInstallCommandIncludesArgument();
+ void Parse(const std::vector<std::string>* args,
+ std::vector<std::string>* unconsumedArgs);
+
+ const std::vector<std::string>& GetIncludeDirs() const;
+
+private:
+ std::vector<std::string> IncludeDirs;
+};
+
+#endif
diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx
new file mode 100644
index 0000000..3928231
--- /dev/null
+++ b/Source/cmInstallDirectoryGenerator.cxx
@@ -0,0 +1,97 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmInstallDirectoryGenerator.h"
+
+#include "cmGeneratorExpression.h"
+#include "cmLocalGenerator.h"
+
+cmInstallDirectoryGenerator::cmInstallDirectoryGenerator(
+ std::vector<std::string> const& dirs, const char* dest,
+ const char* file_permissions, const char* dir_permissions,
+ std::vector<std::string> const& configurations, const char* component,
+ MessageLevel message, bool exclude_from_all, const char* literal_args,
+ bool optional)
+ : cmInstallGenerator(dest, configurations, component, message,
+ exclude_from_all)
+ , LocalGenerator(CM_NULLPTR)
+ , Directories(dirs)
+ , FilePermissions(file_permissions)
+ , DirPermissions(dir_permissions)
+ , LiteralArguments(literal_args)
+ , Optional(optional)
+{
+ // We need per-config actions if destination have generator expressions.
+ if (cmGeneratorExpression::Find(Destination) != std::string::npos) {
+ this->ActionsPerConfig = true;
+ }
+
+ // 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;
+ }
+ }
+}
+
+cmInstallDirectoryGenerator::~cmInstallDirectoryGenerator()
+{
+}
+
+void cmInstallDirectoryGenerator::Compute(cmLocalGenerator* lg)
+{
+ LocalGenerator = lg;
+}
+
+void cmInstallDirectoryGenerator::GenerateScriptActions(std::ostream& os,
+ Indent const& indent)
+{
+ if (this->ActionsPerConfig) {
+ this->cmInstallGenerator::GenerateScriptActions(os, indent);
+ } else {
+ this->AddDirectoryInstallRule(os, "", indent, this->Directories);
+ }
+}
+
+void cmInstallDirectoryGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent const& indent)
+{
+ std::vector<std::string> dirs;
+ cmGeneratorExpression ge;
+ for (std::vector<std::string>::const_iterator i = this->Directories.begin();
+ i != this->Directories.end(); ++i) {
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(*i);
+ cmSystemTools::ExpandListArgument(
+ cge->Evaluate(this->LocalGenerator, config), dirs);
+ }
+ this->AddDirectoryInstallRule(os, config, indent, dirs);
+}
+
+void cmInstallDirectoryGenerator::AddDirectoryInstallRule(
+ std::ostream& os, const std::string& config, Indent const& indent,
+ std::vector<std::string> const& dirs)
+{
+ // Write code to install the directories.
+ const char* no_rename = CM_NULLPTR;
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_DIRECTORY, dirs, this->Optional,
+ this->FilePermissions.c_str(),
+ this->DirPermissions.c_str(), no_rename,
+ this->LiteralArguments.c_str(), indent);
+}
+
+std::string cmInstallDirectoryGenerator::GetDestination(
+ std::string const& config) const
+{
+ cmGeneratorExpression ge;
+ return ge.Parse(this->Destination)->Evaluate(this->LocalGenerator, config);
+}
diff --git a/Source/cmInstallDirectoryGenerator.h b/Source/cmInstallDirectoryGenerator.h
new file mode 100644
index 0000000..93becf4
--- /dev/null
+++ b/Source/cmInstallDirectoryGenerator.h
@@ -0,0 +1,52 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmInstallDirectoryGenerator_h
+#define cmInstallDirectoryGenerator_h
+
+#include "cmInstallGenerator.h"
+
+/** \class cmInstallDirectoryGenerator
+ * \brief Generate directory installation rules.
+ */
+class cmInstallDirectoryGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallDirectoryGenerator(std::vector<std::string> const& dirs,
+ const char* dest, const char* file_permissions,
+ const char* dir_permissions,
+ std::vector<std::string> const& configurations,
+ const char* component, MessageLevel message,
+ bool exclude_from_all, const char* literal_args,
+ bool optional = false);
+ ~cmInstallDirectoryGenerator() CM_OVERRIDE;
+
+ void Compute(cmLocalGenerator* lg) CM_OVERRIDE;
+
+ std::string GetDestination(std::string const& config) const;
+
+protected:
+ void GenerateScriptActions(std::ostream& os,
+ Indent const& indent) CM_OVERRIDE;
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent const& indent) CM_OVERRIDE;
+ void AddDirectoryInstallRule(std::ostream& os, const std::string& config,
+ Indent const& indent,
+ std::vector<std::string> const& dirs);
+ cmLocalGenerator* LocalGenerator;
+ std::vector<std::string> Directories;
+ std::string FilePermissions;
+ std::string DirPermissions;
+ std::string LiteralArguments;
+ bool Optional;
+};
+
+#endif
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
new file mode 100644
index 0000000..6250012
--- /dev/null
+++ b/Source/cmInstallExportGenerator.cxx
@@ -0,0 +1,206 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmInstallExportGenerator.h"
+
+#include <stdio.h>
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallTargetGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmake.h"
+
+#include "cmInstallFilesGenerator.h"
+
+#include "cmExportInstallFileGenerator.h"
+#include "cmExportSet.h"
+
+cmInstallExportGenerator::cmInstallExportGenerator(
+ cmExportSet* exportSet, const char* destination,
+ const char* file_permissions, std::vector<std::string> const& configurations,
+ const char* component, MessageLevel message, bool exclude_from_all,
+ const char* filename, const char* name_space, bool exportOld)
+ : cmInstallGenerator(destination, configurations, component, message,
+ exclude_from_all)
+ , ExportSet(exportSet)
+ , FilePermissions(file_permissions)
+ , FileName(filename)
+ , Namespace(name_space)
+ , ExportOld(exportOld)
+ , LocalGenerator(CM_NULLPTR)
+{
+ this->EFGen = new cmExportInstallFileGenerator(this);
+ exportSet->AddInstallation(this);
+}
+
+cmInstallExportGenerator::~cmInstallExportGenerator()
+{
+ delete this->EFGen;
+}
+
+void cmInstallExportGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LocalGenerator = lg;
+ this->ExportSet->Compute(lg);
+}
+
+void cmInstallExportGenerator::ComputeTempDir()
+{
+ // Choose a temporary directory in which to generate the import
+ // files to be installed.
+ this->TempDir = this->LocalGenerator->GetCurrentBinaryDirectory();
+ this->TempDir += cmake::GetCMakeFilesDirectory();
+ this->TempDir += "/Export";
+ if (this->Destination.empty()) {
+ return;
+ } else {
+ this->TempDir += "/";
+ }
+
+ // Enforce a maximum length.
+ bool useMD5 = false;
+#if defined(_WIN32) || defined(__CYGWIN__)
+ std::string::size_type const max_total_len = 250;
+#else
+ std::string::size_type const max_total_len = 1000;
+#endif
+ if (this->TempDir.size() < max_total_len) {
+ // Keep the total path length below the limit.
+ std::string::size_type max_len = max_total_len - this->TempDir.size();
+ if (this->Destination.size() > max_len) {
+ useMD5 = true;
+ }
+ } else {
+ useMD5 = true;
+ }
+ if (useMD5) {
+ // Replace the destination path with a hash to keep it short.
+ this->TempDir += cmSystemTools::ComputeStringMD5(this->Destination);
+ } else {
+ std::string dest = this->Destination;
+ // Avoid unix full paths.
+ if (dest[0] == '/') {
+ dest[0] = '_';
+ }
+ // Avoid windows full paths by removing colons.
+ std::replace(dest.begin(), dest.end(), ':', '_');
+ // Avoid relative paths that go up the tree.
+ cmSystemTools::ReplaceString(dest, "../", "__/");
+ // Avoid spaces.
+ std::replace(dest.begin(), dest.end(), ' ', '_');
+ this->TempDir += dest;
+ }
+}
+
+void cmInstallExportGenerator::GenerateScript(std::ostream& os)
+{
+ // Skip empty sets.
+ if (ExportSet->GetTargetExports()->empty()) {
+ std::ostringstream e;
+ e << "INSTALL(EXPORT) given unknown export \"" << ExportSet->GetName()
+ << "\"";
+ cmSystemTools::Error(e.str().c_str());
+ return;
+ }
+
+ // Create the temporary directory in which to store the files.
+ this->ComputeTempDir();
+ cmSystemTools::MakeDirectory(this->TempDir.c_str());
+
+ // Construct a temporary location for the file.
+ this->MainImportFile = this->TempDir;
+ this->MainImportFile += "/";
+ this->MainImportFile += this->FileName;
+
+ // Generate the import file for this export set.
+ this->EFGen->SetExportFile(this->MainImportFile.c_str());
+ this->EFGen->SetNamespace(this->Namespace);
+ this->EFGen->SetExportOld(this->ExportOld);
+ if (this->ConfigurationTypes->empty()) {
+ if (!this->ConfigurationName.empty()) {
+ this->EFGen->AddConfiguration(this->ConfigurationName);
+ } else {
+ this->EFGen->AddConfiguration("");
+ }
+ } else {
+ for (std::vector<std::string>::const_iterator ci =
+ this->ConfigurationTypes->begin();
+ ci != this->ConfigurationTypes->end(); ++ci) {
+ this->EFGen->AddConfiguration(*ci);
+ }
+ }
+ this->EFGen->GenerateImportFile();
+
+ // Perform the main install script generation.
+ this->cmInstallGenerator::GenerateScript(os);
+}
+
+void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
+ Indent const& indent)
+{
+ // Create the main install rules first.
+ this->cmInstallGenerator::GenerateScriptConfigs(os, indent);
+
+ // 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);
+ os << indent << "if(" << config_test << ")\n";
+ this->AddInstallRule(os, this->Destination, cmInstallType_FILES, files,
+ false, this->FilePermissions.c_str(), CM_NULLPTR,
+ CM_NULLPTR, CM_NULLPTR, indent.Next());
+ os << indent << "endif()\n";
+ files.clear();
+ }
+}
+
+void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os,
+ Indent const& indent)
+{
+ // Remove old per-configuration export files if the main changes.
+ std::string installedDir = "$ENV{DESTDIR}";
+ installedDir += this->ConvertToAbsoluteDestination(this->Destination);
+ installedDir += "/";
+ std::string installedFile = installedDir;
+ installedFile += this->FileName;
+ os << indent << "if(EXISTS \"" << installedFile << "\")\n";
+ Indent indentN = indent.Next();
+ Indent indentNN = indentN.Next();
+ Indent indentNNN = indentNN.Next();
+ /* clang-format off */
+ os << indentN << "file(DIFFERENT EXPORT_FILE_CHANGED FILES\n"
+ << indentN << " \"" << installedFile << "\"\n"
+ << indentN << " \"" << this->MainImportFile << "\")\n";
+ os << indentN << "if(EXPORT_FILE_CHANGED)\n";
+ 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
+ << "\\\" will be replaced. Removing files [${OLD_CONFIG_FILES}].\")\n";
+ os << indentNNN << "file(REMOVE ${OLD_CONFIG_FILES})\n";
+ os << indentNN << "endif()\n";
+ os << indentN << "endif()\n";
+ os << indent << "endif()\n";
+ /* clang-format on */
+
+ // Install the main export file.
+ std::vector<std::string> files;
+ files.push_back(this->MainImportFile);
+ this->AddInstallRule(os, this->Destination, cmInstallType_FILES, files,
+ false, this->FilePermissions.c_str(), CM_NULLPTR,
+ CM_NULLPTR, CM_NULLPTR, indent);
+}
diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h
new file mode 100644
index 0000000..4435f53
--- /dev/null
+++ b/Source/cmInstallExportGenerator.h
@@ -0,0 +1,69 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmInstallExportGenerator_h
+#define cmInstallExportGenerator_h
+
+#include "cmInstallGenerator.h"
+
+class cmExportInstallFileGenerator;
+class cmInstallFilesGenerator;
+class cmInstallTargetGenerator;
+class cmExportSet;
+class cmMakefile;
+
+/** \class cmInstallExportGenerator
+ * \brief Generate rules for creating an export files.
+ */
+class cmInstallExportGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallExportGenerator(cmExportSet* exportSet, const char* dest,
+ const char* file_permissions,
+ const std::vector<std::string>& configurations,
+ const char* component, MessageLevel message,
+ bool exclude_from_all, const char* filename,
+ const char* name_space, bool exportOld);
+ ~cmInstallExportGenerator() CM_OVERRIDE;
+
+ cmExportSet* GetExportSet() { return this->ExportSet; }
+
+ void Compute(cmLocalGenerator* lg) CM_OVERRIDE;
+
+ cmLocalGenerator* GetLocalGenerator() const { return this->LocalGenerator; }
+
+ const std::string& GetNamespace() const { return this->Namespace; }
+
+ std::string const& GetDestination() const { return this->Destination; }
+
+protected:
+ void GenerateScript(std::ostream& os) CM_OVERRIDE;
+ void GenerateScriptConfigs(std::ostream& os,
+ Indent const& indent) CM_OVERRIDE;
+ void GenerateScriptActions(std::ostream& os,
+ Indent const& indent) CM_OVERRIDE;
+ void GenerateImportFile(cmExportSet const* exportSet);
+ void GenerateImportFile(const char* config, cmExportSet const* exportSet);
+ void ComputeTempDir();
+
+ cmExportSet* ExportSet;
+ std::string FilePermissions;
+ std::string FileName;
+ std::string Namespace;
+ bool ExportOld;
+ cmLocalGenerator* LocalGenerator;
+
+ std::string TempDir;
+ std::string MainImportFile;
+ cmExportInstallFileGenerator* EFGen;
+};
+
+#endif
diff --git a/Source/cmInstallFilesCommand.cxx b/Source/cmInstallFilesCommand.cxx
new file mode 100644
index 0000000..64efe61
--- /dev/null
+++ b/Source/cmInstallFilesCommand.cxx
@@ -0,0 +1,154 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmInstallFilesCommand.h"
+
+#include "cmInstallFilesGenerator.h"
+
+// cmExecutableCommand
+bool cmInstallFilesCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Enable the install target.
+ this->Makefile->GetGlobalGenerator()->EnableInstallTarget();
+
+ this->Destination = args[0];
+
+ 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) {
+ // Find the source location for each file listed.
+ std::string f = this->FindInstallSource(s->c_str());
+ this->Files.push_back(f);
+ }
+ this->CreateInstallGenerator();
+ } else {
+ this->IsFilesForm = false;
+ this->FinalArgs.insert(this->FinalArgs.end(), args.begin() + 1,
+ args.end());
+ }
+
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"));
+
+ return true;
+}
+
+void cmInstallFilesCommand::FinalPass()
+{
+ // No final pass for "FILES" form of arguments.
+ if (this->IsFilesForm) {
+ return;
+ }
+
+ std::string testf;
+ std::string ext = this->FinalArgs[0];
+
+ // two different options
+ if (this->FinalArgs.size() > 1) {
+ // now put the files into the list
+ std::vector<std::string>::iterator s = this->FinalArgs.begin();
+ ++s;
+ // for each argument, get the files
+ for (; s != this->FinalArgs.end(); ++s) {
+ // replace any variables
+ std::string temps = *s;
+ if (!cmSystemTools::GetFilenamePath(temps).empty()) {
+ testf = cmSystemTools::GetFilenamePath(temps) + "/" +
+ cmSystemTools::GetFilenameWithoutLastExtension(temps) + ext;
+ } else {
+ testf = cmSystemTools::GetFilenameWithoutLastExtension(temps) + ext;
+ }
+
+ // add to the result
+ this->Files.push_back(this->FindInstallSource(testf.c_str()));
+ }
+ } else // reg exp list
+ {
+ std::vector<std::string> files;
+ std::string regex = this->FinalArgs[0];
+ cmSystemTools::Glob(this->Makefile->GetCurrentSourceDirectory(), regex,
+ files);
+
+ std::vector<std::string>::iterator s = files.begin();
+ // for each argument, get the files
+ for (; s != files.end(); ++s) {
+ this->Files.push_back(this->FindInstallSource(s->c_str()));
+ }
+ }
+
+ this->CreateInstallGenerator();
+}
+
+void cmInstallFilesCommand::CreateInstallGenerator() const
+{
+ // Construct the destination. This command always installs under
+ // the prefix. We skip the leading slash given by the user.
+ std::string destination = this->Destination.substr(1);
+ cmSystemTools::ConvertToUnixSlashes(destination);
+ if (destination.empty()) {
+ destination = ".";
+ }
+
+ // Use a file install generator.
+ const char* no_permissions = "";
+ const char* no_rename = "";
+ bool no_exclude_from_all = false;
+ std::string no_component =
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME");
+ std::vector<std::string> no_configurations;
+ cmInstallGenerator::MessageLevel message =
+ cmInstallGenerator::SelectMessageLevel(this->Makefile);
+ this->Makefile->AddInstallGenerator(new cmInstallFilesGenerator(
+ this->Files, destination.c_str(), false, no_permissions, no_configurations,
+ no_component.c_str(), message, no_exclude_from_all, no_rename));
+}
+
+/**
+ * Find a file in the build or source tree for installation given a
+ * relative path from the CMakeLists.txt file. This will favor files
+ * present in the build tree. If a full path is given, it is just
+ * returned.
+ */
+std::string cmInstallFilesCommand::FindInstallSource(const char* name) const
+{
+ if (cmSystemTools::FileIsFullPath(name) ||
+ cmGeneratorExpression::Find(name) == 0) {
+ // This is a full path.
+ return name;
+ }
+
+ // This is a relative path.
+ std::string tb = this->Makefile->GetCurrentBinaryDirectory();
+ tb += "/";
+ tb += name;
+ std::string ts = this->Makefile->GetCurrentSourceDirectory();
+ ts += "/";
+ ts += name;
+
+ if (cmSystemTools::FileExists(tb.c_str())) {
+ // The file exists in the binary tree. Use it.
+ return tb;
+ } else if (cmSystemTools::FileExists(ts.c_str())) {
+ // The file exists in the source tree. Use it.
+ return ts;
+ } else {
+ // The file doesn't exist. Assume it will be present in the
+ // binary tree when the install occurs.
+ return tb;
+ }
+}
diff --git a/Source/cmInstallFilesCommand.h b/Source/cmInstallFilesCommand.h
new file mode 100644
index 0000000..cf2c9ff
--- /dev/null
+++ b/Source/cmInstallFilesCommand.h
@@ -0,0 +1,65 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmInstallFilesCommand_h
+#define cmInstallFilesCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmInstallFilesCommand
+ * \brief Specifies where to install some files
+ *
+ * cmInstallFilesCommand specifies the relative path where a list of
+ * files should be installed.
+ */
+class cmInstallFilesCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmInstallFilesCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "install_files"; }
+
+ /**
+ * This is called at the end after all the information
+ * specified by the command is accumulated. Most commands do
+ * not implement this method. At this point, reading and
+ * writing to the cache can be done.
+ */
+ void FinalPass() CM_OVERRIDE;
+ bool HasFinalPass() const CM_OVERRIDE { return !this->IsFilesForm; }
+
+ cmTypeMacro(cmInstallFilesCommand, cmCommand);
+
+protected:
+ void CreateInstallGenerator() const;
+ std::string FindInstallSource(const char* name) const;
+
+private:
+ std::vector<std::string> FinalArgs;
+ bool IsFilesForm;
+ std::string Destination;
+ std::vector<std::string> Files;
+};
+
+#endif
diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx
new file mode 100644
index 0000000..93a740c
--- /dev/null
+++ b/Source/cmInstallFilesGenerator.cxx
@@ -0,0 +1,98 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmInstallFilesGenerator.h"
+
+#include "cmGeneratorExpression.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+cmInstallFilesGenerator::cmInstallFilesGenerator(
+ std::vector<std::string> const& files, const char* dest, bool programs,
+ const char* file_permissions, std::vector<std::string> const& configurations,
+ const char* component, MessageLevel message, bool exclude_from_all,
+ const char* rename, bool optional)
+ : cmInstallGenerator(dest, configurations, component, message,
+ exclude_from_all)
+ , LocalGenerator(CM_NULLPTR)
+ , Files(files)
+ , FilePermissions(file_permissions)
+ , Rename(rename)
+ , Programs(programs)
+ , Optional(optional)
+{
+ // We need per-config actions if the destination has generator expressions.
+ if (cmGeneratorExpression::Find(Destination) != std::string::npos) {
+ 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;
+ }
+ }
+}
+
+cmInstallFilesGenerator::~cmInstallFilesGenerator()
+{
+}
+
+void cmInstallFilesGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LocalGenerator = lg;
+}
+
+std::string cmInstallFilesGenerator::GetDestination(
+ std::string const& config) const
+{
+ cmGeneratorExpression ge;
+ return ge.Parse(this->Destination)->Evaluate(this->LocalGenerator, config);
+}
+
+void cmInstallFilesGenerator::AddFilesInstallRule(
+ std::ostream& os, std::string const& config, Indent const& indent,
+ std::vector<std::string> const& files)
+{
+ // Write code to install the files.
+ const char* no_dir_permissions = CM_NULLPTR;
+ this->AddInstallRule(
+ os, this->GetDestination(config),
+ (this->Programs ? cmInstallType_PROGRAMS : cmInstallType_FILES), files,
+ this->Optional, this->FilePermissions.c_str(), no_dir_permissions,
+ this->Rename.c_str(), CM_NULLPTR, indent);
+}
+
+void cmInstallFilesGenerator::GenerateScriptActions(std::ostream& os,
+ Indent const& indent)
+{
+ if (this->ActionsPerConfig) {
+ this->cmInstallGenerator::GenerateScriptActions(os, indent);
+ } else {
+ this->AddFilesInstallRule(os, "", indent, this->Files);
+ }
+}
+
+void cmInstallFilesGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent const& indent)
+{
+ std::vector<std::string> files;
+ cmGeneratorExpression ge;
+ for (std::vector<std::string>::const_iterator i = this->Files.begin();
+ i != this->Files.end(); ++i) {
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(*i);
+ cmSystemTools::ExpandListArgument(
+ cge->Evaluate(this->LocalGenerator, config), files);
+ }
+ this->AddFilesInstallRule(os, config, indent, files);
+}
diff --git a/Source/cmInstallFilesGenerator.h b/Source/cmInstallFilesGenerator.h
new file mode 100644
index 0000000..5cb09f4
--- /dev/null
+++ b/Source/cmInstallFilesGenerator.h
@@ -0,0 +1,53 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmInstallFilesGenerator_h
+#define cmInstallFilesGenerator_h
+
+#include "cmInstallGenerator.h"
+
+/** \class cmInstallFilesGenerator
+ * \brief Generate file installation rules.
+ */
+class cmInstallFilesGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallFilesGenerator(std::vector<std::string> const& files,
+ const char* dest, bool programs,
+ const char* file_permissions,
+ std::vector<std::string> const& configurations,
+ const char* component, MessageLevel message,
+ bool exclude_from_all, const char* rename,
+ bool optional = false);
+ ~cmInstallFilesGenerator() CM_OVERRIDE;
+
+ void Compute(cmLocalGenerator* lg) CM_OVERRIDE;
+
+ std::string GetDestination(std::string const& config) const;
+
+protected:
+ void GenerateScriptActions(std::ostream& os,
+ Indent const& indent) CM_OVERRIDE;
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent const& indent) CM_OVERRIDE;
+ void AddFilesInstallRule(std::ostream& os, std::string const& config,
+ Indent const& indent,
+ std::vector<std::string> const& files);
+
+ cmLocalGenerator* LocalGenerator;
+ std::vector<std::string> Files;
+ std::string FilePermissions;
+ std::string Rename;
+ bool Programs;
+ bool Optional;
+};
+
+#endif
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
new file mode 100644
index 0000000..e3d5bad
--- /dev/null
+++ b/Source/cmInstallGenerator.cxx
@@ -0,0 +1,200 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmInstallGenerator.h"
+
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+cmInstallGenerator::cmInstallGenerator(
+ const char* destination, std::vector<std::string> const& configurations,
+ const char* component, MessageLevel message, bool exclude_from_all)
+ : cmScriptGenerator("CMAKE_INSTALL_CONFIG_NAME", configurations)
+ , Destination(destination ? destination : "")
+ , Component(component ? component : "")
+ , Message(message)
+ , ExcludeFromAll(exclude_from_all)
+{
+}
+
+cmInstallGenerator::~cmInstallGenerator()
+{
+}
+
+void cmInstallGenerator::AddInstallRule(
+ std::ostream& os, std::string const& dest, cmInstallType type,
+ std::vector<std::string> const& files, bool optional /* = false */,
+ const char* permissions_file /* = 0 */,
+ const char* permissions_dir /* = 0 */, const char* rename /* = 0 */,
+ const char* literal_args /* = 0 */, Indent const& indent)
+{
+ // Use the FILE command to install the file.
+ std::string stype;
+ switch (type) {
+ case cmInstallType_DIRECTORY:
+ stype = "DIRECTORY";
+ break;
+ case cmInstallType_PROGRAMS:
+ stype = "PROGRAM";
+ break;
+ case cmInstallType_EXECUTABLE:
+ stype = "EXECUTABLE";
+ break;
+ case cmInstallType_STATIC_LIBRARY:
+ stype = "STATIC_LIBRARY";
+ break;
+ case cmInstallType_SHARED_LIBRARY:
+ stype = "SHARED_LIBRARY";
+ break;
+ case cmInstallType_MODULE_LIBRARY:
+ stype = "MODULE";
+ break;
+ case cmInstallType_FILES:
+ stype = "FILE";
+ break;
+ }
+ os << indent;
+ if (cmSystemTools::FileIsFullPath(dest.c_str())) {
+ 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()) {
+ os << ";";
+ }
+ os << dest << "/";
+ if (rename && *rename) {
+ os << rename;
+ } else {
+ os << cmSystemTools::GetFilenameName(*fi);
+ }
+ }
+ os << "\")\n";
+ os << indent << "if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n";
+ os << indent << indent << "message(WARNING \"ABSOLUTE path INSTALL "
+ << "DESTINATION : ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n";
+ os << indent << "endif()\n";
+
+ os << indent << "if(CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n";
+ os << indent << indent << "message(FATAL_ERROR \"ABSOLUTE path INSTALL "
+ << "DESTINATION forbidden (by caller): "
+ << "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n";
+ os << indent << "endif()\n";
+ }
+ std::string absDest = this->ConvertToAbsoluteDestination(dest);
+ os << "file(INSTALL DESTINATION \"" << absDest << "\" TYPE " << stype;
+ if (optional) {
+ os << " OPTIONAL";
+ }
+ switch (this->Message) {
+ case MessageDefault:
+ break;
+ case MessageAlways:
+ os << " MESSAGE_ALWAYS";
+ break;
+ case MessageLazy:
+ os << " MESSAGE_LAZY";
+ break;
+ case MessageNever:
+ os << " MESSAGE_NEVER";
+ break;
+ }
+ if (permissions_file && *permissions_file) {
+ os << " PERMISSIONS" << permissions_file;
+ }
+ if (permissions_dir && *permissions_dir) {
+ os << " DIR_PERMISSIONS" << permissions_dir;
+ }
+ if (rename && *rename) {
+ os << " RENAME \"" << rename << "\"";
+ }
+ os << " FILES";
+ if (files.size() == 1) {
+ os << " \"" << files[0] << "\"";
+ } else {
+ for (std::vector<std::string>::const_iterator fi = files.begin();
+ fi != files.end(); ++fi) {
+ os << "\n" << indent << " \"" << *fi << "\"";
+ }
+ os << "\n" << indent << " ";
+ if (!(literal_args && *literal_args)) {
+ os << " ";
+ }
+ }
+ if (literal_args && *literal_args) {
+ os << literal_args;
+ }
+ os << ")\n";
+}
+
+std::string cmInstallGenerator::CreateComponentTest(const char* component,
+ bool exclude_from_all)
+{
+ std::string result = "\"${CMAKE_INSTALL_COMPONENT}\" STREQUAL \"";
+ result += component;
+ result += "\"";
+ if (!exclude_from_all) {
+ result += " OR NOT CMAKE_INSTALL_COMPONENT";
+ }
+ return result;
+}
+
+void cmInstallGenerator::GenerateScript(std::ostream& os)
+{
+ // Track indentation.
+ Indent indent;
+
+ // Begin this block of installation.
+ std::string component_test =
+ this->CreateComponentTest(this->Component.c_str(), this->ExcludeFromAll);
+ os << indent << "if(" << component_test << ")\n";
+
+ // Generate the script possibly with per-configuration code.
+ this->GenerateScriptConfigs(os, indent.Next());
+
+ // End this block of installation.
+ os << indent << "endif()\n\n";
+}
+
+bool cmInstallGenerator::InstallsForConfig(const std::string& config)
+{
+ return this->GeneratesForConfig(config);
+}
+
+std::string cmInstallGenerator::ConvertToAbsoluteDestination(
+ std::string const& dest) const
+{
+ std::string result;
+ if (!dest.empty() && !cmSystemTools::FileIsFullPath(dest.c_str())) {
+ result = "${CMAKE_INSTALL_PREFIX}/";
+ }
+ result += dest;
+ return result;
+}
+
+cmInstallGenerator::MessageLevel cmInstallGenerator::SelectMessageLevel(
+ cmMakefile* mf, bool never)
+{
+ if (never) {
+ return MessageNever;
+ }
+ std::string m = mf->GetSafeDefinition("CMAKE_INSTALL_MESSAGE");
+ if (m == "ALWAYS") {
+ return MessageAlways;
+ }
+ if (m == "LAZY") {
+ return MessageLazy;
+ }
+ if (m == "NEVER") {
+ return MessageNever;
+ }
+ return MessageDefault;
+}
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
new file mode 100644
index 0000000..ad9fc28
--- /dev/null
+++ b/Source/cmInstallGenerator.h
@@ -0,0 +1,74 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmInstallGenerator_h
+#define cmInstallGenerator_h
+
+#include "cmInstallType.h"
+#include "cmScriptGenerator.h"
+
+class cmLocalGenerator;
+class cmMakefile;
+
+/** \class cmInstallGenerator
+ * \brief Support class for generating install scripts.
+ *
+ */
+class cmInstallGenerator : public cmScriptGenerator
+{
+public:
+ enum MessageLevel
+ {
+ MessageDefault,
+ MessageAlways,
+ MessageLazy,
+ MessageNever
+ };
+
+ cmInstallGenerator(const char* destination,
+ std::vector<std::string> const& configurations,
+ const char* component, MessageLevel message,
+ bool exclude_from_all);
+ ~cmInstallGenerator() CM_OVERRIDE;
+
+ void AddInstallRule(
+ std::ostream& os, std::string const& dest, cmInstallType type,
+ std::vector<std::string> const& files, bool optional = false,
+ const char* permissions_file = CM_NULLPTR,
+ const char* permissions_dir = CM_NULLPTR, const char* rename = CM_NULLPTR,
+ const char* literal_args = CM_NULLPTR, Indent const& indent = Indent());
+
+ /** Get the install destination as it should appear in the
+ installation script. */
+ std::string ConvertToAbsoluteDestination(std::string const& dest) const;
+
+ /** Test if this generator installs something for a given configuration. */
+ bool InstallsForConfig(const std::string& config);
+
+ /** Select message level from CMAKE_INSTALL_MESSAGE or 'never'. */
+ static MessageLevel SelectMessageLevel(cmMakefile* mf, bool never = false);
+
+ virtual void Compute(cmLocalGenerator*) {}
+
+protected:
+ void GenerateScript(std::ostream& os) CM_OVERRIDE;
+
+ std::string CreateComponentTest(const char* component,
+ bool exclude_from_all);
+
+ // Information shared by most generator types.
+ std::string Destination;
+ std::string Component;
+ MessageLevel Message;
+ bool ExcludeFromAll;
+};
+
+#endif
diff --git a/Source/cmInstallProgramsCommand.cxx b/Source/cmInstallProgramsCommand.cxx
new file mode 100644
index 0000000..2e5fc1f
--- /dev/null
+++ b/Source/cmInstallProgramsCommand.cxx
@@ -0,0 +1,124 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmInstallProgramsCommand.h"
+
+#include "cmInstallFilesGenerator.h"
+// cmExecutableCommand
+bool cmInstallProgramsCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Enable the install target.
+ this->Makefile->GetGlobalGenerator()->EnableInstallTarget();
+
+ this->Destination = args[0];
+
+ this->FinalArgs.insert(this->FinalArgs.end(), args.begin() + 1, args.end());
+
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"));
+
+ return true;
+}
+
+void cmInstallProgramsCommand::FinalPass()
+{
+ bool files_mode = false;
+ if (!this->FinalArgs.empty() && this->FinalArgs[0] == "FILES") {
+ files_mode = true;
+ }
+
+ // two different options
+ if (this->FinalArgs.size() > 1 || files_mode) {
+ // for each argument, get the programs
+ std::vector<std::string>::iterator s = this->FinalArgs.begin();
+ if (files_mode) {
+ // Skip the FILES argument in files mode.
+ ++s;
+ }
+ for (; s != this->FinalArgs.end(); ++s) {
+ // add to the result
+ this->Files.push_back(this->FindInstallSource(s->c_str()));
+ }
+ } else // reg exp list
+ {
+ std::vector<std::string> programs;
+ cmSystemTools::Glob(this->Makefile->GetCurrentSourceDirectory(),
+ this->FinalArgs[0], programs);
+
+ std::vector<std::string>::iterator s = programs.begin();
+ // for each argument, get the programs
+ for (; s != programs.end(); ++s) {
+ this->Files.push_back(this->FindInstallSource(s->c_str()));
+ }
+ }
+
+ // Construct the destination. This command always installs under
+ // the prefix. We skip the leading slash given by the user.
+ std::string destination = this->Destination.substr(1);
+ cmSystemTools::ConvertToUnixSlashes(destination);
+ if (destination.empty()) {
+ destination = ".";
+ }
+
+ // Use a file install generator.
+ const char* no_permissions = "";
+ const char* no_rename = "";
+ bool no_exclude_from_all = false;
+ std::string no_component =
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME");
+ std::vector<std::string> no_configurations;
+ cmInstallGenerator::MessageLevel message =
+ cmInstallGenerator::SelectMessageLevel(this->Makefile);
+ this->Makefile->AddInstallGenerator(new cmInstallFilesGenerator(
+ this->Files, destination.c_str(), true, no_permissions, no_configurations,
+ no_component.c_str(), message, no_exclude_from_all, no_rename));
+}
+
+/**
+ * Find a file in the build or source tree for installation given a
+ * relative path from the CMakeLists.txt file. This will favor files
+ * present in the build tree. If a full path is given, it is just
+ * returned.
+ */
+std::string cmInstallProgramsCommand::FindInstallSource(const char* name) const
+{
+ if (cmSystemTools::FileIsFullPath(name) ||
+ cmGeneratorExpression::Find(name) == 0) {
+ // This is a full path.
+ return name;
+ }
+
+ // This is a relative path.
+ std::string tb = this->Makefile->GetCurrentBinaryDirectory();
+ tb += "/";
+ tb += name;
+ std::string ts = this->Makefile->GetCurrentSourceDirectory();
+ ts += "/";
+ ts += name;
+
+ if (cmSystemTools::FileExists(tb.c_str())) {
+ // The file exists in the binary tree. Use it.
+ return tb;
+ } else if (cmSystemTools::FileExists(ts.c_str())) {
+ // The file exists in the source tree. Use it.
+ return ts;
+ } else {
+ // The file doesn't exist. Assume it will be present in the
+ // binary tree when the install occurs.
+ return tb;
+ }
+}
diff --git a/Source/cmInstallProgramsCommand.h b/Source/cmInstallProgramsCommand.h
new file mode 100644
index 0000000..b56a9b1
--- /dev/null
+++ b/Source/cmInstallProgramsCommand.h
@@ -0,0 +1,64 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmInstallProgramsCommand_h
+#define cmInstallProgramsCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmInstallProgramsCommand
+ * \brief Specifies where to install some programs
+ *
+ * cmInstallProgramsCommand specifies the relative path where a list of
+ * programs should be installed.
+ */
+class cmInstallProgramsCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmInstallProgramsCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "install_programs"; }
+
+ /**
+ * This is called at the end after all the information
+ * specified by the command is accumulated. Most commands do
+ * not implement this method. At this point, reading and
+ * writing to the cache can be done.
+ */
+ void FinalPass() CM_OVERRIDE;
+
+ bool HasFinalPass() const CM_OVERRIDE { return true; }
+
+ cmTypeMacro(cmInstallProgramsCommand, cmCommand);
+
+protected:
+ std::string FindInstallSource(const char* name) const;
+
+private:
+ std::vector<std::string> FinalArgs;
+ std::string Destination;
+ std::vector<std::string> Files;
+};
+
+#endif
diff --git a/Source/cmInstallScriptGenerator.cxx b/Source/cmInstallScriptGenerator.cxx
new file mode 100644
index 0000000..76d6b71
--- /dev/null
+++ b/Source/cmInstallScriptGenerator.cxx
@@ -0,0 +1,43 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmInstallScriptGenerator.h"
+
+cmInstallScriptGenerator::cmInstallScriptGenerator(const char* script,
+ bool code,
+ const char* component,
+ bool exclude_from_all)
+ : cmInstallGenerator(CM_NULLPTR, std::vector<std::string>(), component,
+ MessageDefault, exclude_from_all)
+ , Script(script)
+ , Code(code)
+{
+}
+
+cmInstallScriptGenerator::~cmInstallScriptGenerator()
+{
+}
+
+void cmInstallScriptGenerator::GenerateScript(std::ostream& os)
+{
+ Indent indent;
+ std::string component_test =
+ this->CreateComponentTest(this->Component.c_str(), this->ExcludeFromAll);
+ os << indent << "if(" << component_test << ")\n";
+
+ if (this->Code) {
+ os << indent.Next() << this->Script << "\n";
+ } else {
+ os << indent.Next() << "include(\"" << this->Script << "\")\n";
+ }
+
+ os << indent << "endif()\n\n";
+}
diff --git a/Source/cmInstallScriptGenerator.h b/Source/cmInstallScriptGenerator.h
new file mode 100644
index 0000000..dc00359
--- /dev/null
+++ b/Source/cmInstallScriptGenerator.h
@@ -0,0 +1,33 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmInstallScriptGenerator_h
+#define cmInstallScriptGenerator_h
+
+#include "cmInstallGenerator.h"
+
+/** \class cmInstallScriptGenerator
+ * \brief Generate target installation rules.
+ */
+class cmInstallScriptGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallScriptGenerator(const char* script, bool code,
+ const char* component, bool exclude_from_all);
+ ~cmInstallScriptGenerator() CM_OVERRIDE;
+
+protected:
+ void GenerateScript(std::ostream& os) CM_OVERRIDE;
+ std::string Script;
+ bool Code;
+};
+
+#endif
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
new file mode 100644
index 0000000..448d278
--- /dev/null
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -0,0 +1,780 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmInstallTargetGenerator.h"
+
+#include "cmComputeLinkInformation.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmake.h"
+
+#include <assert.h>
+
+cmInstallTargetGenerator::cmInstallTargetGenerator(
+ const std::string& targetName, const char* dest, bool implib,
+ const char* file_permissions, std::vector<std::string> const& configurations,
+ const char* component, MessageLevel message, bool exclude_from_all,
+ bool optional)
+ : cmInstallGenerator(dest, configurations, component, message,
+ exclude_from_all)
+ , TargetName(targetName)
+ , Target(CM_NULLPTR)
+ , FilePermissions(file_permissions)
+ , ImportLibrary(implib)
+ , Optional(optional)
+{
+ this->ActionsPerConfig = true;
+ this->NamelinkMode = NamelinkModeNone;
+}
+
+cmInstallTargetGenerator::~cmInstallTargetGenerator()
+{
+}
+
+void cmInstallTargetGenerator::GenerateScript(std::ostream& os)
+{
+ // Warn if installing an exclude-from-all target.
+ if (this->Target->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+ std::ostringstream msg;
+ msg << "WARNING: Target \"" << this->Target->GetName()
+ << "\" has EXCLUDE_FROM_ALL set and will not be built by default "
+ << "but an install rule has been provided for it. CMake does "
+ << "not define behavior for this case.";
+ cmSystemTools::Message(msg.str().c_str(), "Warning");
+ }
+
+ // Perform the main install script generation.
+ this->cmInstallGenerator::GenerateScript(os);
+}
+
+void cmInstallTargetGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent const& indent)
+{
+ // Compute the build tree directory from which to copy the target.
+ std::string fromDirConfig;
+ if (this->Target->NeedRelinkBeforeInstall(config)) {
+ fromDirConfig =
+ this->Target->GetLocalGenerator()->GetCurrentBinaryDirectory();
+ fromDirConfig += cmake::GetCMakeFilesDirectory();
+ fromDirConfig += "/CMakeRelink.dir/";
+ } else {
+ fromDirConfig = this->Target->GetDirectory(config, this->ImportLibrary);
+ fromDirConfig += "/";
+ }
+ std::string toDir =
+ this->ConvertToAbsoluteDestination(this->GetDestination(config));
+ toDir += "/";
+
+ // Compute the list of files to install for this target.
+ std::vector<std::string> filesFrom;
+ std::vector<std::string> filesTo;
+ std::string literal_args;
+ cmState::TargetType targetType = this->Target->GetType();
+ cmInstallType type = cmInstallType();
+ switch (targetType) {
+ case cmState::EXECUTABLE:
+ type = cmInstallType_EXECUTABLE;
+ break;
+ case cmState::STATIC_LIBRARY:
+ type = cmInstallType_STATIC_LIBRARY;
+ break;
+ case cmState::SHARED_LIBRARY:
+ type = cmInstallType_SHARED_LIBRARY;
+ break;
+ case cmState::MODULE_LIBRARY:
+ type = cmInstallType_MODULE_LIBRARY;
+ break;
+ case cmState::INTERFACE_LIBRARY:
+ // Not reachable. We never create a cmInstallTargetGenerator for
+ // an INTERFACE_LIBRARY.
+ assert(0 && "INTERFACE_LIBRARY targets have no installable outputs.");
+ break;
+ case cmState::OBJECT_LIBRARY:
+ case cmState::UTILITY:
+ case cmState::GLOBAL_TARGET:
+ case cmState::UNKNOWN_LIBRARY:
+ this->Target->GetLocalGenerator()->IssueMessage(
+ cmake::INTERNAL_ERROR,
+ "cmInstallTargetGenerator created with non-installable target.");
+ return;
+ }
+ if (targetType == cmState::EXECUTABLE) {
+ // 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);
+ if (this->ImportLibrary) {
+ std::string from1 = fromDirConfig + targetNameImport;
+ std::string to1 = toDir + targetNameImport;
+ filesFrom.push_back(from1);
+ filesTo.push_back(to1);
+ std::string targetNameImportLib;
+ if (this->Target->GetImplibGNUtoMS(targetNameImport,
+ targetNameImportLib)) {
+ filesFrom.push_back(fromDirConfig + targetNameImportLib);
+ filesTo.push_back(toDir + targetNameImportLib);
+ }
+
+ // An import library looks like a static library.
+ type = cmInstallType_STATIC_LIBRARY;
+ } else {
+ std::string from1 = fromDirConfig + targetName;
+ std::string to1 = toDir + targetName;
+
+ // Handle OSX Bundles.
+ if (this->Target->IsAppBundleOnApple()) {
+ cmMakefile const* mf = this->Target->Target->GetMakefile();
+
+ // Install the whole app bundle directory.
+ type = cmInstallType_DIRECTORY;
+ literal_args += " USE_SOURCE_PERMISSIONS";
+ from1 += ".app";
+
+ // Tweaks apply to the binary inside the bundle.
+ to1 += ".app/";
+ if (!mf->PlatformIsAppleIos()) {
+ to1 += "Contents/MacOS/";
+ }
+ to1 += targetName;
+ } else {
+ // Tweaks apply to the real file, so list it first.
+ if (targetNameReal != targetName) {
+ std::string from2 = fromDirConfig + targetNameReal;
+ std::string to2 = toDir += targetNameReal;
+ filesFrom.push_back(from2);
+ filesTo.push_back(to2);
+ }
+ }
+
+ filesFrom.push_back(from1);
+ filesTo.push_back(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);
+ 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;
+ filesFrom.push_back(from1);
+ filesTo.push_back(to1);
+ std::string targetNameImportLib;
+ if (this->Target->GetImplibGNUtoMS(targetNameImport,
+ targetNameImportLib)) {
+ filesFrom.push_back(fromDirConfig + targetNameImportLib);
+ filesTo.push_back(toDir + targetNameImportLib);
+ }
+
+ // An import library looks like a static library.
+ type = cmInstallType_STATIC_LIBRARY;
+ } else if (this->Target->IsFrameworkOnApple()) {
+ // There is a bug in cmInstallCommand if this fails.
+ assert(this->NamelinkMode == NamelinkModeNone);
+
+ // Install the whole framework directory.
+ type = cmInstallType_DIRECTORY;
+ literal_args += " USE_SOURCE_PERMISSIONS";
+
+ std::string from1 = fromDirConfig + targetName;
+ from1 = cmSystemTools::GetFilenamePath(from1);
+
+ // Tweaks apply to the binary inside the bundle.
+ std::string to1 = toDir + targetNameReal;
+
+ filesFrom.push_back(from1);
+ filesTo.push_back(to1);
+ } else if (this->Target->IsCFBundleOnApple()) {
+ // Install the whole app bundle directory.
+ type = cmInstallType_DIRECTORY;
+ literal_args += " USE_SOURCE_PERMISSIONS";
+
+ std::string targetNameBase = targetName.substr(0, targetName.find('/'));
+
+ std::string from1 = fromDirConfig + targetNameBase;
+ std::string to1 = toDir + targetName;
+
+ filesFrom.push_back(from1);
+ filesTo.push_back(to1);
+ } else {
+ bool haveNamelink = false;
+
+ // Library link name.
+ std::string fromName = fromDirConfig + targetName;
+ std::string toName = toDir + targetName;
+
+ // Library interface name.
+ std::string fromSOName;
+ std::string toSOName;
+ if (targetNameSO != targetName) {
+ haveNamelink = true;
+ fromSOName = fromDirConfig + targetNameSO;
+ toSOName = toDir + targetNameSO;
+ }
+
+ // Library implementation name.
+ std::string fromRealName;
+ std::string toRealName;
+ if (targetNameReal != targetName && targetNameReal != targetNameSO) {
+ haveNamelink = true;
+ fromRealName = fromDirConfig + targetNameReal;
+ toRealName = toDir + targetNameReal;
+ }
+
+ // Add the names based on the current namelink mode.
+ if (haveNamelink) {
+ // With a namelink we need to check the mode.
+ if (this->NamelinkMode == NamelinkModeOnly) {
+ // Install the namelink only.
+ filesFrom.push_back(fromName);
+ filesTo.push_back(toName);
+ } else {
+ // Install the real file if it has its own name.
+ if (!fromRealName.empty()) {
+ filesFrom.push_back(fromRealName);
+ filesTo.push_back(toRealName);
+ }
+
+ // Install the soname link if it has its own name.
+ if (!fromSOName.empty()) {
+ filesFrom.push_back(fromSOName);
+ filesTo.push_back(toSOName);
+ }
+
+ // Install the namelink if it is not to be skipped.
+ if (this->NamelinkMode != NamelinkModeSkip) {
+ filesFrom.push_back(fromName);
+ filesTo.push_back(toName);
+ }
+ }
+ } else {
+ // Without a namelink there will be only one file. Install it
+ // if this is not a namelink-only rule.
+ if (this->NamelinkMode != NamelinkModeOnly) {
+ filesFrom.push_back(fromName);
+ filesTo.push_back(toName);
+ }
+ }
+ }
+ }
+
+ // If this fails the above code is buggy.
+ assert(filesFrom.size() == filesTo.size());
+
+ // Skip this rule if no files are to be installed for the target.
+ if (filesFrom.empty()) {
+ return;
+ }
+
+ // Add pre-installation tweaks.
+ this->AddTweak(os, indent, config, filesTo,
+ &cmInstallTargetGenerator::PreReplacementTweaks);
+
+ // Write code to install the target file.
+ const char* no_dir_permissions = CM_NULLPTR;
+ const char* no_rename = CM_NULLPTR;
+ bool optional = this->Optional || this->ImportLibrary;
+ this->AddInstallRule(os, this->GetDestination(config), type, filesFrom,
+ optional, this->FilePermissions.c_str(),
+ no_dir_permissions, no_rename, literal_args.c_str(),
+ indent);
+
+ // Add post-installation tweaks.
+ this->AddTweak(os, indent, config, filesTo,
+ &cmInstallTargetGenerator::PostReplacementTweaks);
+}
+
+std::string cmInstallTargetGenerator::GetDestination(
+ std::string const& config) const
+{
+ cmGeneratorExpression ge;
+ return ge.Parse(this->Destination)
+ ->Evaluate(this->Target->GetLocalGenerator(), config);
+}
+
+std::string cmInstallTargetGenerator::GetInstallFilename(
+ const std::string& config) const
+{
+ NameType nameType = this->ImportLibrary ? NameImplib : NameNormal;
+ return cmInstallTargetGenerator::GetInstallFilename(this->Target, config,
+ nameType);
+}
+
+std::string cmInstallTargetGenerator::GetInstallFilename(
+ cmGeneratorTarget const* target, const std::string& config,
+ NameType nameType)
+{
+ std::string fname;
+ // Compute the name of the library.
+ if (target->GetType() == cmState::EXECUTABLE) {
+ std::string targetName;
+ std::string targetNameReal;
+ std::string targetNameImport;
+ std::string targetNamePDB;
+ target->GetExecutableNames(targetName, targetNameReal, targetNameImport,
+ targetNamePDB, config);
+ if (nameType == NameImplib) {
+ // Use the import library name.
+ if (!target->GetImplibGNUtoMS(targetNameImport, fname,
+ "${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
+ fname = targetNameImport;
+ }
+ } else if (nameType == NameReal) {
+ // Use the canonical name.
+ fname = targetNameReal;
+ } else {
+ // Use the canonical name.
+ fname = targetName;
+ }
+ } else {
+ std::string targetName;
+ std::string targetNameSO;
+ std::string targetNameReal;
+ std::string targetNameImport;
+ std::string targetNamePDB;
+ target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
+ targetNameImport, targetNamePDB, config);
+ if (nameType == NameImplib) {
+ // Use the import library name.
+ if (!target->GetImplibGNUtoMS(targetNameImport, fname,
+ "${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
+ fname = targetNameImport;
+ }
+ } else if (nameType == NameSO) {
+ // Use the soname.
+ fname = targetNameSO;
+ } else if (nameType == NameReal) {
+ // Use the real name.
+ fname = targetNameReal;
+ } else {
+ // Use the canonical name.
+ fname = targetName;
+ }
+ }
+
+ return fname;
+}
+
+void cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->Target = lg->FindLocalNonAliasGeneratorTarget(this->TargetName);
+}
+
+void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent const& indent,
+ const std::string& config,
+ std::string const& file,
+ TweakMethod tweak)
+{
+ std::ostringstream tw;
+ (this->*tweak)(tw, indent.Next(), config, file);
+ std::string tws = tw.str();
+ if (!tws.empty()) {
+ os << indent << "if(EXISTS \"" << file << "\" AND\n"
+ << indent << " NOT IS_SYMLINK \"" << file << "\")\n";
+ os << tws;
+ os << indent << "endif()\n";
+ }
+}
+
+void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent const& indent,
+ const std::string& config,
+ std::vector<std::string> const& files,
+ TweakMethod tweak)
+{
+ if (files.size() == 1) {
+ // Tweak a single file.
+ this->AddTweak(os, indent, config, this->GetDestDirPath(files[0]), tweak);
+ } else {
+ // Generate a foreach loop to tweak multiple files.
+ std::ostringstream tw;
+ this->AddTweak(tw, indent.Next(), config, "${file}", tweak);
+ std::string tws = tw.str();
+ if (!tws.empty()) {
+ Indent indent2 = indent.Next().Next();
+ os << indent << "foreach(file\n";
+ for (std::vector<std::string>::const_iterator i = files.begin();
+ i != files.end(); ++i) {
+ os << indent2 << "\"" << this->GetDestDirPath(*i) << "\"\n";
+ }
+ os << indent2 << ")\n";
+ os << tws;
+ os << indent << "endforeach()\n";
+ }
+ }
+}
+
+std::string cmInstallTargetGenerator::GetDestDirPath(std::string const& file)
+{
+ // Construct the path of the file on disk after installation on
+ // which tweaks may be performed.
+ std::string toDestDirPath = "$ENV{DESTDIR}";
+ if (file[0] != '/' && file[0] != '$') {
+ toDestDirPath += "/";
+ }
+ toDestDirPath += file;
+ return toDestDirPath;
+}
+
+void cmInstallTargetGenerator::PreReplacementTweaks(std::ostream& os,
+ Indent const& indent,
+ const std::string& config,
+ std::string const& file)
+{
+ this->AddRPathCheckRule(os, indent, config, file);
+}
+
+void cmInstallTargetGenerator::PostReplacementTweaks(std::ostream& os,
+ Indent const& indent,
+ const std::string& config,
+ std::string const& file)
+{
+ this->AddInstallNamePatchRule(os, indent, config, file);
+ this->AddChrpathPatchRule(os, indent, config, file);
+ this->AddUniversalInstallRule(os, indent, file);
+ this->AddRanlibRule(os, indent, file);
+ this->AddStripRule(os, indent, file);
+}
+
+void cmInstallTargetGenerator::AddInstallNamePatchRule(
+ std::ostream& os, Indent const& indent, const std::string& config,
+ std::string const& toDestDirPath)
+{
+ if (this->ImportLibrary ||
+ !(this->Target->GetType() == cmState::SHARED_LIBRARY ||
+ this->Target->GetType() == cmState::MODULE_LIBRARY ||
+ this->Target->GetType() == cmState::EXECUTABLE)) {
+ return;
+ }
+
+ // Fix the install_name settings in installed binaries.
+ std::string installNameTool =
+ this->Target->Target->GetMakefile()->GetSafeDefinition(
+ "CMAKE_INSTALL_NAME_TOOL");
+
+ if (installNameTool.empty()) {
+ return;
+ }
+
+ // Build a map of build-tree install_name to install-tree install_name for
+ // shared libraries linked to this target.
+ std::map<std::string, std::string> install_name_remap;
+ if (cmComputeLinkInformation* cli =
+ this->Target->GetLinkInformation(config)) {
+ std::set<cmGeneratorTarget const*> const& sharedLibs =
+ cli->GetSharedLibrariesLinked();
+ for (std::set<cmGeneratorTarget const*>::const_iterator j =
+ sharedLibs.begin();
+ j != sharedLibs.end(); ++j) {
+ cmGeneratorTarget const* tgt = *j;
+
+ // The install_name of an imported target does not change.
+ if (tgt->IsImported()) {
+ continue;
+ }
+
+ // If the build tree and install tree use different path
+ // components of the install_name field then we need to create a
+ // mapping to be applied after installation.
+ std::string for_build = tgt->GetInstallNameDirForBuildTree(config);
+ std::string for_install = tgt->GetInstallNameDirForInstallTree();
+ if (for_build != for_install) {
+ // The directory portions differ. Append the filename to
+ // create the mapping.
+ std::string fname = this->GetInstallFilename(tgt, config, NameSO);
+
+ // Map from the build-tree install_name.
+ for_build += fname;
+
+ // Map to the install-tree install_name.
+ for_install += fname;
+
+ // Store the mapping entry.
+ install_name_remap[for_build] = for_install;
+ }
+ }
+ }
+
+ // Edit the install_name of the target itself if necessary.
+ std::string new_id;
+ if (this->Target->GetType() == cmState::SHARED_LIBRARY) {
+ std::string for_build =
+ this->Target->GetInstallNameDirForBuildTree(config);
+ std::string for_install = this->Target->GetInstallNameDirForInstallTree();
+
+ if (this->Target->IsFrameworkOnApple() && for_install.empty()) {
+ // Frameworks seem to have an id corresponding to their own full
+ // path.
+ // ...
+ // for_install = fullDestPath_without_DESTDIR_or_name;
+ }
+
+ // If the install name will change on installation set the new id
+ // on the installed file.
+ if (for_build != for_install) {
+ // Prepare to refer to the install-tree install_name.
+ new_id = for_install;
+ new_id += this->GetInstallFilename(this->Target, config, NameSO);
+ }
+ }
+
+ // Write a rule to run install_name_tool to set the install-tree
+ // install_name value and references.
+ if (!new_id.empty() || !install_name_remap.empty()) {
+ os << indent << "execute_process(COMMAND \"" << installNameTool;
+ os << "\"";
+ if (!new_id.empty()) {
+ os << "\n" << indent << " -id \"" << new_id << "\"";
+ }
+ for (std::map<std::string, std::string>::const_iterator i =
+ install_name_remap.begin();
+ i != install_name_remap.end(); ++i) {
+ os << "\n"
+ << indent << " -change \"" << i->first << "\" \"" << i->second
+ << "\"";
+ }
+ os << "\n" << indent << " \"" << toDestDirPath << "\")\n";
+ }
+}
+
+void cmInstallTargetGenerator::AddRPathCheckRule(
+ std::ostream& os, Indent const& indent, const std::string& config,
+ std::string const& toDestDirPath)
+{
+ // Skip the chrpath if the target does not need it.
+ if (this->ImportLibrary || !this->Target->IsChrpathUsed(config)) {
+ return;
+ }
+ // Skip if on Apple
+ if (this->Target->Target->GetMakefile()->IsOn(
+ "CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ return;
+ }
+
+ // Get the link information for this target.
+ // It can provide the RPATH.
+ cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
+ if (!cli) {
+ return;
+ }
+
+ // Get the install RPATH from the link information.
+ std::string newRpath = cli->GetChrpathString();
+
+ // Write a rule to remove the installed file if its rpath is not the
+ // new rpath. This is needed for existing build/install trees when
+ // the installed rpath changes but the file is not rebuilt.
+ /* clang-format off */
+ os << indent << "file(RPATH_CHECK\n"
+ << indent << " FILE \"" << toDestDirPath << "\"\n"
+ << indent << " RPATH \"" << newRpath << "\")\n";
+ /* clang-format on */
+}
+
+void cmInstallTargetGenerator::AddChrpathPatchRule(
+ std::ostream& os, Indent const& indent, const std::string& config,
+ std::string const& toDestDirPath)
+{
+ // Skip the chrpath if the target does not need it.
+ if (this->ImportLibrary || !this->Target->IsChrpathUsed(config)) {
+ return;
+ }
+
+ // Get the link information for this target.
+ // It can provide the RPATH.
+ cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
+ if (!cli) {
+ return;
+ }
+
+ cmMakefile* mf = this->Target->Target->GetMakefile();
+
+ if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ // If using install_name_tool, set up the rules to modify the rpaths.
+ std::string installNameTool =
+ mf->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
+
+ std::vector<std::string> oldRuntimeDirs, newRuntimeDirs;
+ cli->GetRPath(oldRuntimeDirs, false);
+ cli->GetRPath(newRuntimeDirs, true);
+
+ std::string darwin_major_version_s =
+ mf->GetSafeDefinition("DARWIN_MAJOR_VERSION");
+
+ std::istringstream ss(darwin_major_version_s);
+ int darwin_major_version;
+ ss >> darwin_major_version;
+ if (!ss.fail() && darwin_major_version <= 9 &&
+ (!oldRuntimeDirs.empty() || !newRuntimeDirs.empty())) {
+ std::ostringstream msg;
+ msg
+ << "WARNING: Target \"" << this->Target->GetName()
+ << "\" has runtime paths which cannot be changed during install. "
+ << "To change runtime paths, OS X version 10.6 or newer is required. "
+ << "Therefore, runtime paths will not be changed when installing. "
+ << "CMAKE_BUILD_WITH_INSTALL_RPATH may be used to work around"
+ " this limitation.";
+ mf->IssueMessage(cmake::WARNING, msg.str());
+ } else {
+ // Note: These paths are kept unique to avoid
+ // install_name_tool corruption.
+ std::set<std::string> runpaths;
+ for (std::vector<std::string>::const_iterator i = oldRuntimeDirs.begin();
+ i != oldRuntimeDirs.end(); ++i) {
+ std::string runpath =
+ mf->GetGlobalGenerator()->ExpandCFGIntDir(*i, config);
+
+ if (runpaths.find(runpath) == runpaths.end()) {
+ runpaths.insert(runpath);
+ os << indent << "execute_process(COMMAND " << installNameTool
+ << "\n";
+ os << indent << " -delete_rpath \"" << runpath << "\"\n";
+ os << indent << " \"" << toDestDirPath << "\")\n";
+ }
+ }
+
+ runpaths.clear();
+ for (std::vector<std::string>::const_iterator i = newRuntimeDirs.begin();
+ i != newRuntimeDirs.end(); ++i) {
+ std::string runpath =
+ mf->GetGlobalGenerator()->ExpandCFGIntDir(*i, config);
+
+ if (runpaths.find(runpath) == runpaths.end()) {
+ os << indent << "execute_process(COMMAND " << installNameTool
+ << "\n";
+ os << indent << " -add_rpath \"" << runpath << "\"\n";
+ os << indent << " \"" << toDestDirPath << "\")\n";
+ }
+ }
+ }
+ } else {
+ // Construct the original rpath string to be replaced.
+ std::string oldRpath = cli->GetRPathString(false);
+
+ // Get the install RPATH from the link information.
+ std::string newRpath = cli->GetChrpathString();
+
+ // Skip the rule if the paths are identical
+ if (oldRpath == newRpath) {
+ return;
+ }
+
+ // Write a rule to run chrpath to set the install-tree RPATH
+ os << indent << "file(RPATH_CHANGE\n"
+ << indent << " FILE \"" << toDestDirPath << "\"\n"
+ << indent << " OLD_RPATH \"" << oldRpath << "\"\n"
+ << indent << " NEW_RPATH \"" << newRpath << "\")\n";
+ }
+}
+
+void cmInstallTargetGenerator::AddStripRule(std::ostream& os,
+ Indent const& indent,
+ const std::string& toDestDirPath)
+{
+
+ // don't strip static and import libraries, because it removes the only
+ // symbol table they have so you can't link to them anymore
+ if (this->Target->GetType() == cmState::STATIC_LIBRARY ||
+ this->ImportLibrary) {
+ return;
+ }
+
+ // Don't handle OSX Bundles.
+ if (this->Target->Target->GetMakefile()->IsOn("APPLE") &&
+ this->Target->GetPropertyAsBool("MACOSX_BUNDLE")) {
+ return;
+ }
+
+ if (!this->Target->Target->GetMakefile()->IsSet("CMAKE_STRIP")) {
+ return;
+ }
+
+ os << indent << "if(CMAKE_INSTALL_DO_STRIP)\n";
+ os << indent << " execute_process(COMMAND \""
+ << this->Target->Target->GetMakefile()->GetDefinition("CMAKE_STRIP")
+ << "\" \"" << toDestDirPath << "\")\n";
+ os << indent << "endif()\n";
+}
+
+void cmInstallTargetGenerator::AddRanlibRule(std::ostream& os,
+ Indent const& indent,
+ const std::string& toDestDirPath)
+{
+ // Static libraries need ranlib on this platform.
+ if (this->Target->GetType() != cmState::STATIC_LIBRARY) {
+ return;
+ }
+
+ // Perform post-installation processing on the file depending
+ // on its type.
+ if (!this->Target->Target->GetMakefile()->IsOn("APPLE")) {
+ return;
+ }
+
+ std::string ranlib =
+ this->Target->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
+ if (ranlib.empty()) {
+ return;
+ }
+
+ os << indent << "execute_process(COMMAND \"" << ranlib << "\" \""
+ << toDestDirPath << "\")\n";
+}
+
+void cmInstallTargetGenerator::AddUniversalInstallRule(
+ std::ostream& os, Indent const& indent, const std::string& toDestDirPath)
+{
+ cmMakefile const* mf = this->Target->Target->GetMakefile();
+
+ if (!mf->PlatformIsAppleIos() || !mf->IsOn("XCODE")) {
+ return;
+ }
+
+ const char* xcodeVersion = mf->GetDefinition("XCODE_VERSION");
+ if (!xcodeVersion ||
+ cmSystemTools::VersionCompareGreater("6", xcodeVersion)) {
+ return;
+ }
+
+ switch (this->Target->GetType()) {
+ case cmState::EXECUTABLE:
+ case cmState::STATIC_LIBRARY:
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ break;
+
+ default:
+ return;
+ }
+
+ if (!this->Target->Target->GetPropertyAsBool("IOS_INSTALL_COMBINED")) {
+ return;
+ }
+
+ os << indent << "include(CMakeIOSInstallCombined)\n";
+ os << indent << "ios_install_combined("
+ << "\"" << this->Target->Target->GetName() << "\" "
+ << "\"" << toDestDirPath << "\")\n";
+}
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
new file mode 100644
index 0000000..b1c28b8
--- /dev/null
+++ b/Source/cmInstallTargetGenerator.h
@@ -0,0 +1,111 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmInstallTargetGenerator_h
+#define cmInstallTargetGenerator_h
+
+#include "cmInstallGenerator.h"
+
+class cmGeneratorTarget;
+
+/** \class cmInstallTargetGenerator
+ * \brief Generate target installation rules.
+ */
+class cmInstallTargetGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallTargetGenerator(std::string const& targetName, const char* dest,
+ bool implib, const char* file_permissions,
+ std::vector<std::string> const& configurations,
+ const char* component, MessageLevel message,
+ bool exclude_from_all, bool optional);
+ ~cmInstallTargetGenerator() CM_OVERRIDE;
+
+ /** Select the policy for installing shared library linkable name
+ symlinks. */
+ enum NamelinkModeType
+ {
+ NamelinkModeNone,
+ NamelinkModeOnly,
+ NamelinkModeSkip
+ };
+ void SetNamelinkMode(NamelinkModeType mode) { this->NamelinkMode = mode; }
+ NamelinkModeType GetNamelinkMode() const { return this->NamelinkMode; }
+
+ std::string GetInstallFilename(const std::string& config) const;
+
+ enum NameType
+ {
+ NameNormal,
+ NameImplib,
+ NameSO,
+ NameReal
+ };
+
+ static std::string GetInstallFilename(const cmGeneratorTarget* target,
+ const std::string& config,
+ NameType nameType = NameNormal);
+
+ void Compute(cmLocalGenerator* lg) CM_OVERRIDE;
+
+ cmGeneratorTarget* GetTarget() const { return this->Target; }
+
+ bool IsImportLibrary() const { return this->ImportLibrary; }
+
+ std::string GetDestination(std::string const& config) const;
+
+protected:
+ void GenerateScript(std::ostream& os) CM_OVERRIDE;
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent const& indent) CM_OVERRIDE;
+ typedef void (cmInstallTargetGenerator::*TweakMethod)(std::ostream&,
+ Indent const&,
+ const std::string&,
+ std::string const&);
+ void AddTweak(std::ostream& os, Indent const& indent,
+ const std::string& config, std::string const& file,
+ TweakMethod tweak);
+ void AddTweak(std::ostream& os, Indent const& indent,
+ const std::string& config,
+ std::vector<std::string> const& files, TweakMethod tweak);
+ std::string GetDestDirPath(std::string const& file);
+ void PreReplacementTweaks(std::ostream& os, Indent const& indent,
+ const std::string& config,
+ std::string const& file);
+ void PostReplacementTweaks(std::ostream& os, Indent const& indent,
+ const std::string& config,
+ std::string const& file);
+ void AddInstallNamePatchRule(std::ostream& os, Indent const& indent,
+ const std::string& config,
+ const std::string& toDestDirPath);
+ void AddChrpathPatchRule(std::ostream& os, Indent const& indent,
+ const std::string& config,
+ std::string const& toDestDirPath);
+ void AddRPathCheckRule(std::ostream& os, Indent const& indent,
+ const std::string& config,
+ std::string const& toDestDirPath);
+
+ void AddStripRule(std::ostream& os, Indent const& indent,
+ const std::string& toDestDirPath);
+ void AddRanlibRule(std::ostream& os, Indent const& indent,
+ const std::string& toDestDirPath);
+ void AddUniversalInstallRule(std::ostream& os, Indent const& indent,
+ const std::string& toDestDirPath);
+
+ std::string TargetName;
+ cmGeneratorTarget* Target;
+ std::string FilePermissions;
+ NamelinkModeType NamelinkMode;
+ bool ImportLibrary;
+ bool Optional;
+};
+
+#endif
diff --git a/Source/cmInstallTargetsCommand.cxx b/Source/cmInstallTargetsCommand.cxx
new file mode 100644
index 0000000..056ea24
--- /dev/null
+++ b/Source/cmInstallTargetsCommand.cxx
@@ -0,0 +1,55 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmInstallTargetsCommand.h"
+
+// cmExecutableCommand
+bool cmInstallTargetsCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Enable the install target.
+ this->Makefile->GetGlobalGenerator()->EnableInstallTarget();
+
+ cmTargets& tgts = this->Makefile->GetTargets();
+ std::vector<std::string>::const_iterator s = args.begin();
+ ++s;
+ std::string runtime_dir = "/bin";
+ for (; s != args.end(); ++s) {
+ if (*s == "RUNTIME_DIRECTORY") {
+ ++s;
+ if (s == args.end()) {
+ this->SetError("called with RUNTIME_DIRECTORY but no actual "
+ "directory");
+ return false;
+ }
+
+ runtime_dir = *s;
+ } else if (tgts.find(*s) != tgts.end()) {
+ tgts[*s].SetInstallPath(args[0].c_str());
+ tgts[*s].SetRuntimeInstallPath(runtime_dir.c_str());
+ tgts[*s].SetHaveInstallRule(true);
+ } else {
+ std::string str = "Cannot find target: \"" + *s + "\" to install.";
+ this->SetError(str);
+ return false;
+ }
+ }
+
+ this->Makefile->GetGlobalGenerator()->AddInstallComponent(
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"));
+
+ return true;
+}
diff --git a/Source/cmInstallTargetsCommand.h b/Source/cmInstallTargetsCommand.h
new file mode 100644
index 0000000..b7d7f33
--- /dev/null
+++ b/Source/cmInstallTargetsCommand.h
@@ -0,0 +1,47 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmInstallTargetsCommand_h
+#define cmInstallTargetsCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmInstallTargetsCommand
+ * \brief Specifies where to install some targets
+ *
+ * cmInstallTargetsCommand specifies the relative path where a list of
+ * targets should be installed. The targets can be executables or
+ * libraries.
+ */
+class cmInstallTargetsCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmInstallTargetsCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "install_targets"; }
+
+ cmTypeMacro(cmInstallTargetsCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmInstallType.h b/Source/cmInstallType.h
new file mode 100644
index 0000000..a837368
--- /dev/null
+++ b/Source/cmInstallType.h
@@ -0,0 +1,29 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmInstallType_h
+#define cmInstallType_h
+
+/**
+ * Enumerate types known to file(INSTALL).
+ */
+enum cmInstallType
+{
+ cmInstallType_EXECUTABLE,
+ cmInstallType_STATIC_LIBRARY,
+ cmInstallType_SHARED_LIBRARY,
+ cmInstallType_MODULE_LIBRARY,
+ cmInstallType_FILES,
+ cmInstallType_PROGRAMS,
+ cmInstallType_DIRECTORY
+};
+
+#endif
diff --git a/Source/cmInstalledFile.cxx b/Source/cmInstalledFile.cxx
new file mode 100644
index 0000000..bfc5cf1
--- /dev/null
+++ b/Source/cmInstalledFile.cxx
@@ -0,0 +1,126 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmInstalledFile.h"
+
+#include "cmAlgorithms.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+cmInstalledFile::cmInstalledFile()
+ : NameExpression(CM_NULLPTR)
+{
+}
+
+cmInstalledFile::~cmInstalledFile()
+{
+ if (NameExpression) {
+ delete NameExpression;
+ }
+}
+
+cmInstalledFile::Property::Property()
+{
+}
+
+cmInstalledFile::Property::~Property()
+{
+ cmDeleteAll(this->ValueExpressions);
+}
+
+void cmInstalledFile::SetName(cmMakefile* mf, const std::string& name)
+{
+ cmListFileBacktrace backtrace = mf->GetBacktrace();
+ cmGeneratorExpression ge(backtrace);
+
+ this->Name = name;
+ this->NameExpression = ge.Parse(name).release();
+}
+
+std::string const& cmInstalledFile::GetName() const
+{
+ return this->Name;
+}
+
+cmCompiledGeneratorExpression const& cmInstalledFile::GetNameExpression() const
+{
+ return *(this->NameExpression);
+}
+
+void cmInstalledFile::RemoveProperty(const std::string& prop)
+{
+ this->Properties.erase(prop);
+}
+
+void cmInstalledFile::SetProperty(cmMakefile const* mf,
+ const std::string& prop, const char* value)
+{
+ this->RemoveProperty(prop);
+ this->AppendProperty(mf, prop, value);
+}
+
+void cmInstalledFile::AppendProperty(cmMakefile const* mf,
+ const std::string& prop,
+ const char* value, bool /*asString*/)
+{
+ cmListFileBacktrace backtrace = mf->GetBacktrace();
+ cmGeneratorExpression ge(backtrace);
+
+ Property& property = this->Properties[prop];
+ property.ValueExpressions.push_back(ge.Parse(value).release());
+}
+
+bool cmInstalledFile::HasProperty(const std::string& prop) const
+{
+ return this->Properties.find(prop) != this->Properties.end();
+}
+
+bool cmInstalledFile::GetProperty(const std::string& prop,
+ std::string& value) const
+{
+ PropertyMapType::const_iterator i = this->Properties.find(prop);
+ if (i == this->Properties.end()) {
+ return false;
+ }
+
+ Property const& property = i->second;
+
+ std::string output;
+ std::string separator;
+
+ for (ExpressionVectorType::const_iterator j =
+ property.ValueExpressions.begin();
+ j != property.ValueExpressions.end(); ++j) {
+ output += separator;
+ output += (*j)->GetInput();
+ separator = ";";
+ }
+
+ value = output;
+ return true;
+}
+
+bool cmInstalledFile::GetPropertyAsBool(const std::string& prop) const
+{
+ std::string value;
+ bool isSet = this->GetProperty(prop, value);
+ return isSet && cmSystemTools::IsOn(value.c_str());
+}
+
+void cmInstalledFile::GetPropertyAsList(const std::string& prop,
+ std::vector<std::string>& list) const
+{
+ std::string value;
+ this->GetProperty(prop, value);
+
+ list.clear();
+ cmSystemTools::ExpandListArgument(value, list);
+}
diff --git a/Source/cmInstalledFile.h b/Source/cmInstalledFile.h
new file mode 100644
index 0000000..00ff611
--- /dev/null
+++ b/Source/cmInstalledFile.h
@@ -0,0 +1,75 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmInstalledFile_h
+#define cmInstalledFile_h
+
+#include "cmGeneratorExpression.h"
+
+/** \class cmInstalledFile
+ * \brief Represents a file intended for installation.
+ *
+ * cmInstalledFile represents a file intended for installation.
+ */
+class cmInstalledFile
+{
+public:
+ typedef CM_AUTO_PTR<cmCompiledGeneratorExpression>
+ CompiledGeneratorExpressionPtrType;
+
+ typedef std::vector<cmCompiledGeneratorExpression*> ExpressionVectorType;
+
+ struct Property
+ {
+ Property();
+ ~Property();
+
+ ExpressionVectorType ValueExpressions;
+ };
+
+ typedef std::map<std::string, Property> PropertyMapType;
+
+ cmInstalledFile();
+
+ ~cmInstalledFile();
+
+ void RemoveProperty(const std::string& prop);
+
+ void SetProperty(cmMakefile const* mf, const std::string& prop,
+ const char* value);
+
+ void AppendProperty(cmMakefile const* mf, const std::string& prop,
+ const char* value, bool asString = false);
+
+ bool HasProperty(const std::string& prop) const;
+
+ bool GetProperty(const std::string& prop, std::string& value) const;
+
+ bool GetPropertyAsBool(const std::string& prop) const;
+
+ void GetPropertyAsList(const std::string& prop,
+ std::vector<std::string>& list) const;
+
+ void SetName(cmMakefile* mf, const std::string& name);
+
+ std::string const& GetName() const;
+
+ cmCompiledGeneratorExpression const& GetNameExpression() const;
+
+ PropertyMapType const& GetProperties() const { return this->Properties; }
+
+private:
+ std::string Name;
+ cmCompiledGeneratorExpression* NameExpression;
+ PropertyMapType Properties;
+};
+
+#endif
diff --git a/Source/cmLinkDirectoriesCommand.cxx b/Source/cmLinkDirectoriesCommand.cxx
new file mode 100644
index 0000000..a33b429
--- /dev/null
+++ b/Source/cmLinkDirectoriesCommand.cxx
@@ -0,0 +1,65 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmLinkDirectoriesCommand.h"
+
+// cmLinkDirectoriesCommand
+bool cmLinkDirectoriesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ return true;
+ }
+
+ for (std::vector<std::string>::const_iterator i = args.begin();
+ i != args.end(); ++i) {
+ this->AddLinkDir(*i);
+ }
+ return true;
+}
+
+void cmLinkDirectoriesCommand::AddLinkDir(std::string const& dir)
+{
+ std::string unixPath = dir;
+ cmSystemTools::ConvertToUnixSlashes(unixPath);
+ if (!cmSystemTools::FileIsFullPath(unixPath.c_str())) {
+ bool convertToAbsolute = false;
+ std::ostringstream e;
+ /* clang-format off */
+ e << "This command specifies the relative path\n"
+ << " " << unixPath << "\n"
+ << "as a link directory.\n";
+ /* clang-format on */
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0015)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0015);
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, e.str());
+ case cmPolicies::OLD:
+ // OLD behavior does not convert
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0015);
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ case cmPolicies::NEW:
+ // NEW behavior converts
+ convertToAbsolute = true;
+ break;
+ }
+ if (convertToAbsolute) {
+ std::string tmp = this->Makefile->GetCurrentSourceDirectory();
+ tmp += "/";
+ tmp += unixPath;
+ unixPath = tmp;
+ }
+ }
+ this->Makefile->AppendProperty("LINK_DIRECTORIES", unixPath.c_str());
+}
diff --git a/Source/cmLinkDirectoriesCommand.h b/Source/cmLinkDirectoriesCommand.h
new file mode 100644
index 0000000..721d663
--- /dev/null
+++ b/Source/cmLinkDirectoriesCommand.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLinkDirectoriesCommand_h
+#define cmLinkDirectoriesCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmLinkDirectoriesCommand
+ * \brief Define a list of directories containing files to link.
+ *
+ * cmLinkDirectoriesCommand is used to specify a list
+ * of directories containing files to link into executable(s).
+ * Note that the command supports the use of CMake built-in variables
+ * such as CMAKE_BINARY_DIR and CMAKE_SOURCE_DIR.
+ */
+class cmLinkDirectoriesCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmLinkDirectoriesCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "link_directories"; }
+
+ cmTypeMacro(cmLinkDirectoriesCommand, cmCommand);
+
+private:
+ void AddLinkDir(std::string const& dir);
+};
+
+#endif
diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h
new file mode 100644
index 0000000..8aa3981
--- /dev/null
+++ b/Source/cmLinkItem.h
@@ -0,0 +1,175 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmLinkItem_h
+#define cmLinkItem_h
+
+#include "cmListFileCache.h"
+#include "cmSystemTools.h"
+
+class cmGeneratorTarget;
+
+// Basic information about each link item.
+class cmLinkItem : public std::string
+{
+ typedef std::string std_string;
+
+public:
+ cmLinkItem()
+ : std_string()
+ , Target(CM_NULLPTR)
+ {
+ }
+ cmLinkItem(const std_string& n, cmGeneratorTarget const* t)
+ : std_string(n)
+ , Target(t)
+ {
+ }
+ cmLinkItem(cmLinkItem const& r)
+ : std_string(r)
+ , Target(r.Target)
+ {
+ }
+ cmGeneratorTarget const* Target;
+};
+
+class cmLinkImplItem : public cmLinkItem
+{
+public:
+ cmLinkImplItem()
+ : cmLinkItem()
+ , Backtrace()
+ , FromGenex(false)
+ {
+ }
+ cmLinkImplItem(std::string const& n, cmGeneratorTarget const* t,
+ cmListFileBacktrace const& bt, bool fromGenex)
+ : cmLinkItem(n, t)
+ , Backtrace(bt)
+ , FromGenex(fromGenex)
+ {
+ }
+ cmLinkImplItem(cmLinkImplItem const& r)
+ : cmLinkItem(r)
+ , Backtrace(r.Backtrace)
+ , FromGenex(r.FromGenex)
+ {
+ }
+ cmListFileBacktrace Backtrace;
+ bool FromGenex;
+};
+
+/** The link implementation specifies the direct library
+ dependencies needed by the object files of the target. */
+struct cmLinkImplementationLibraries
+{
+ // Libraries linked directly in this configuration.
+ std::vector<cmLinkImplItem> Libraries;
+
+ // Libraries linked directly in other configurations.
+ // Needed only for OLD behavior of CMP0003.
+ std::vector<cmLinkItem> WrongConfigLibraries;
+};
+
+struct cmLinkInterfaceLibraries
+{
+ // Libraries listed in the interface.
+ std::vector<cmLinkItem> Libraries;
+};
+
+struct cmLinkInterface : public cmLinkInterfaceLibraries
+{
+ // Languages whose runtime libraries must be linked.
+ std::vector<std::string> Languages;
+
+ // Shared library dependencies needed for linking on some platforms.
+ std::vector<cmLinkItem> SharedDeps;
+
+ // Number of repetitions of a strongly connected component of two
+ // or more static libraries.
+ unsigned int Multiplicity;
+
+ // Libraries listed for other configurations.
+ // Needed only for OLD behavior of CMP0003.
+ std::vector<cmLinkItem> WrongConfigLibraries;
+
+ bool ImplementationIsInterface;
+
+ cmLinkInterface()
+ : Multiplicity(0)
+ , ImplementationIsInterface(false)
+ {
+ }
+};
+
+struct cmOptionalLinkInterface : public cmLinkInterface
+{
+ cmOptionalLinkInterface()
+ : LibrariesDone(false)
+ , AllDone(false)
+ , Exists(false)
+ , HadHeadSensitiveCondition(false)
+ , ExplicitLibraries(CM_NULLPTR)
+ {
+ }
+ bool LibrariesDone;
+ bool AllDone;
+ bool Exists;
+ bool HadHeadSensitiveCondition;
+ const char* ExplicitLibraries;
+};
+
+struct cmHeadToLinkInterfaceMap
+ : public std::map<cmGeneratorTarget const*, cmOptionalLinkInterface>
+{
+};
+
+struct cmLinkImplementation : public cmLinkImplementationLibraries
+{
+ // Languages whose runtime libraries must be linked.
+ std::vector<std::string> Languages;
+};
+
+// Cache link implementation computation from each configuration.
+struct cmOptionalLinkImplementation : public cmLinkImplementation
+{
+ cmOptionalLinkImplementation()
+ : LibrariesDone(false)
+ , LanguagesDone(false)
+ , HadHeadSensitiveCondition(false)
+ {
+ }
+ bool LibrariesDone;
+ bool LanguagesDone;
+ bool HadHeadSensitiveCondition;
+};
+
+/** Compute the link type to use for the given configuration. */
+inline cmTargetLinkLibraryType CMP0003_ComputeLinkType(
+ const std::string& config, std::vector<std::string> const& debugConfigs)
+{
+ // No configuration is always optimized.
+ if (config.empty()) {
+ return OPTIMIZED_LibraryType;
+ }
+
+ // Check if any entry in the list matches this configuration.
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ if (std::find(debugConfigs.begin(), debugConfigs.end(), configUpper) !=
+ debugConfigs.end()) {
+ return DEBUG_LibraryType;
+ }
+ // The current configuration is not a debug configuration.
+ return OPTIMIZED_LibraryType;
+}
+
+#endif
diff --git a/Source/cmLinkLibrariesCommand.cxx b/Source/cmLinkLibrariesCommand.cxx
new file mode 100644
index 0000000..5d23d6a
--- /dev/null
+++ b/Source/cmLinkLibrariesCommand.cxx
@@ -0,0 +1,47 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmLinkLibrariesCommand.h"
+
+// cmLinkLibrariesCommand
+bool cmLinkLibrariesCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ return true;
+ }
+ // add libraries, nothe that there is an optional prefix
+ // of debug and optimized than can be used
+ for (std::vector<std::string>::const_iterator i = args.begin();
+ i != args.end(); ++i) {
+ if (*i == "debug") {
+ ++i;
+ if (i == args.end()) {
+ this->SetError("The \"debug\" argument must be followed by "
+ "a library");
+ return false;
+ }
+ this->Makefile->AddLinkLibrary(*i, DEBUG_LibraryType);
+ } else if (*i == "optimized") {
+ ++i;
+ if (i == args.end()) {
+ this->SetError("The \"optimized\" argument must be followed by "
+ "a library");
+ return false;
+ }
+ this->Makefile->AddLinkLibrary(*i, OPTIMIZED_LibraryType);
+ } else {
+ this->Makefile->AddLinkLibrary(*i);
+ }
+ }
+
+ return true;
+}
diff --git a/Source/cmLinkLibrariesCommand.h b/Source/cmLinkLibrariesCommand.h
new file mode 100644
index 0000000..45cc4d7
--- /dev/null
+++ b/Source/cmLinkLibrariesCommand.h
@@ -0,0 +1,47 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLinkLibrariesCommand_h
+#define cmLinkLibrariesCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmLinkLibrariesCommand
+ * \brief Specify a list of libraries to link into executables.
+ *
+ * cmLinkLibrariesCommand is used to specify a list of libraries to link
+ * into executable(s) or shared objects. The names of the libraries
+ * should be those defined by the LIBRARY(library) command(s).
+ */
+class cmLinkLibrariesCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmLinkLibrariesCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "link_libraries"; }
+
+ cmTypeMacro(cmLinkLibrariesCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmLinkedTree.h b/Source/cmLinkedTree.h
new file mode 100644
index 0000000..6b31074
--- /dev/null
+++ b/Source/cmLinkedTree.h
@@ -0,0 +1,200 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLinkedTree_h
+#define cmLinkedTree_h
+
+#include "cmStandardIncludes.h"
+
+#include <assert.h>
+
+/**
+ @brief A adaptor for traversing a tree structure in a vector
+
+ This class is not intended to be wholly generic like a standard library
+ container adaptor. Mostly it exists to facilitate code sharing for the
+ needs of the cmState. For example, the Truncate() method is a specific
+ requirement of the cmState.
+
+ An empty cmLinkedTree provides a Root() method, and an Push() method,
+ each of which return iterators. A Tree can be built up by extending
+ from the root, and then extending from any other iterator.
+
+ An iterator resulting from this tree construction can be
+ forward-only-iterated toward the root. Extending the tree never
+ invalidates existing iterators.
+ */
+template <typename T>
+class cmLinkedTree
+{
+ typedef typename std::vector<T>::size_type PositionType;
+ typedef T* PointerType;
+ typedef T& ReferenceType;
+
+public:
+ class iterator : public std::iterator<std::forward_iterator_tag, T>
+ {
+ friend class cmLinkedTree;
+ cmLinkedTree* Tree;
+
+ // The Position is always 'one past the end'.
+ PositionType Position;
+
+ iterator(cmLinkedTree* tree, PositionType pos)
+ : Tree(tree)
+ , Position(pos)
+ {
+ }
+
+ public:
+ iterator()
+ : Tree(CM_NULLPTR)
+ , Position(0)
+ {
+ }
+
+ void operator++()
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ assert(this->Position <= this->Tree->Data.size());
+ assert(this->Position > 0);
+ this->Position = this->Tree->UpPositions[this->Position - 1];
+ }
+
+ PointerType operator->() const
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ assert(this->Position <= this->Tree->Data.size());
+ assert(this->Position > 0);
+ return this->Tree->GetPointer(this->Position - 1);
+ }
+
+ PointerType operator->()
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ assert(this->Position <= this->Tree->Data.size());
+ assert(this->Position > 0);
+ return this->Tree->GetPointer(this->Position - 1);
+ }
+
+ ReferenceType operator*() const
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ assert(this->Position <= this->Tree->Data.size());
+ assert(this->Position > 0);
+ return this->Tree->GetReference(this->Position - 1);
+ }
+
+ ReferenceType operator*()
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ assert(this->Position <= this->Tree->Data.size());
+ assert(this->Position > 0);
+ return this->Tree->GetReference(this->Position - 1);
+ }
+
+ bool operator==(iterator other) const
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ assert(this->Tree == other.Tree);
+ return this->Position == other.Position;
+ }
+
+ bool operator!=(iterator other) const
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ return !(*this == other);
+ }
+
+ bool IsValid() const
+ {
+ if (!this->Tree) {
+ return false;
+ }
+ return this->Position <= this->Tree->Data.size();
+ }
+
+ bool StrictWeakOrdered(iterator other) const
+ {
+ assert(this->Tree);
+ assert(this->Tree == other.Tree);
+ return this->Position < other.Position;
+ }
+ };
+
+ iterator Root() const
+ {
+ return iterator(const_cast<cmLinkedTree*>(this), 0);
+ }
+
+ iterator Push(iterator it) { return Push_impl(it, T()); }
+
+ iterator Push(iterator it, T t) { return Push_impl(it, t); }
+
+ bool IsLast(iterator it) { return it.Position == this->Data.size(); }
+
+ iterator Pop(iterator it)
+ {
+ assert(!this->Data.empty());
+ assert(this->UpPositions.size() == this->Data.size());
+ bool const isLast = this->IsLast(it);
+ ++it;
+ // If this is the last entry then no other entry can refer
+ // to it so we can drop its storage.
+ if (isLast) {
+ this->Data.pop_back();
+ this->UpPositions.pop_back();
+ }
+ return it;
+ }
+
+ iterator Truncate()
+ {
+ assert(this->UpPositions.size() > 0);
+ this->UpPositions.erase(this->UpPositions.begin() + 1,
+ this->UpPositions.end());
+ assert(this->Data.size() > 0);
+ this->Data.erase(this->Data.begin() + 1, this->Data.end());
+ return iterator(this, 1);
+ }
+
+ void Clear()
+ {
+ this->UpPositions.clear();
+ this->Data.clear();
+ }
+
+private:
+ T& GetReference(PositionType pos) { return this->Data[pos]; }
+
+ T* GetPointer(PositionType pos) { return &this->Data[pos]; }
+
+ iterator Push_impl(iterator it, T t)
+ {
+ assert(this->UpPositions.size() == this->Data.size());
+ assert(it.Position <= this->UpPositions.size());
+ this->UpPositions.push_back(it.Position);
+ this->Data.push_back(t);
+ return iterator(this, this->UpPositions.size());
+ }
+
+ std::vector<T> Data;
+ std::vector<PositionType> UpPositions;
+};
+
+#endif
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx
new file mode 100644
index 0000000..32e965d
--- /dev/null
+++ b/Source/cmListCommand.cxx
@@ -0,0 +1,546 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmListCommand.h"
+
+#include "cmAlgorithms.h"
+#include <cmsys/RegularExpression.hxx>
+#include <cmsys/SystemTools.hxx>
+
+#include <algorithm>
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h> // required for atoi
+bool cmListCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("must be called with at least two arguments.");
+ return false;
+ }
+
+ const std::string& subCommand = args[0];
+ if (subCommand == "LENGTH") {
+ return this->HandleLengthCommand(args);
+ }
+ if (subCommand == "GET") {
+ return this->HandleGetCommand(args);
+ }
+ if (subCommand == "APPEND") {
+ return this->HandleAppendCommand(args);
+ }
+ if (subCommand == "FIND") {
+ return this->HandleFindCommand(args);
+ }
+ if (subCommand == "INSERT") {
+ return this->HandleInsertCommand(args);
+ }
+ if (subCommand == "REMOVE_AT") {
+ return this->HandleRemoveAtCommand(args);
+ }
+ if (subCommand == "REMOVE_ITEM") {
+ return this->HandleRemoveItemCommand(args);
+ }
+ if (subCommand == "REMOVE_DUPLICATES") {
+ return this->HandleRemoveDuplicatesCommand(args);
+ }
+ if (subCommand == "SORT") {
+ return this->HandleSortCommand(args);
+ }
+ if (subCommand == "REVERSE") {
+ return this->HandleReverseCommand(args);
+ }
+ if (subCommand == "FILTER") {
+ return this->HandleFilterCommand(args);
+ }
+
+ std::string e = "does not recognize sub-command " + subCommand;
+ this->SetError(e);
+ return false;
+}
+
+bool cmListCommand::GetListString(std::string& listString,
+ const std::string& var)
+{
+ // get the old value
+ const char* cacheValue = this->Makefile->GetDefinition(var);
+ if (!cacheValue) {
+ return false;
+ }
+ listString = cacheValue;
+ return true;
+}
+
+bool cmListCommand::GetList(std::vector<std::string>& list,
+ const std::string& var)
+{
+ std::string listString;
+ if (!this->GetListString(listString, var)) {
+ return false;
+ }
+ // if the size of the list
+ if (listString.empty()) {
+ return true;
+ }
+ // expand the variable into a list
+ cmSystemTools::ExpandListArgument(listString, list, true);
+ // if no empty elements then just return
+ if (std::find(list.begin(), list.end(), std::string()) == list.end()) {
+ return true;
+ }
+ // if we have empty elements we need to check policy CMP0007
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0007)) {
+ case cmPolicies::WARN: {
+ // Default is to warn and use old behavior
+ // OLD behavior is to allow compatibility, so recall
+ // ExpandListArgument without the true which will remove
+ // empty values
+ list.clear();
+ cmSystemTools::ExpandListArgument(listString, list);
+ std::string warn = cmPolicies::GetPolicyWarning(cmPolicies::CMP0007);
+ warn += " List has value = [";
+ warn += listString;
+ warn += "].";
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, warn);
+ return true;
+ }
+ case cmPolicies::OLD:
+ // OLD behavior is to allow compatibility, so recall
+ // ExpandListArgument without the true which will remove
+ // empty values
+ list.clear();
+ cmSystemTools::ExpandListArgument(listString, list);
+ return true;
+ case cmPolicies::NEW:
+ return true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0007));
+ return false;
+ }
+ return true;
+}
+
+bool cmListCommand::HandleLengthCommand(std::vector<std::string> const& args)
+{
+ if (args.size() != 3) {
+ this->SetError("sub-command LENGTH requires two arguments.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ const std::string& variableName = args[args.size() - 1];
+ std::vector<std::string> varArgsExpanded;
+ // do not check the return value here
+ // if the list var is not found varArgsExpanded will have size 0
+ // and we will return 0
+ this->GetList(varArgsExpanded, listName);
+ size_t length = varArgsExpanded.size();
+ char buffer[1024];
+ sprintf(buffer, "%d", static_cast<int>(length));
+
+ this->Makefile->AddDefinition(variableName, buffer);
+ return true;
+}
+
+bool cmListCommand::HandleGetCommand(std::vector<std::string> const& args)
+{
+ if (args.size() < 4) {
+ this->SetError("sub-command GET requires at least three arguments.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ const std::string& variableName = args[args.size() - 1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!this->GetList(varArgsExpanded, listName)) {
+ this->Makefile->AddDefinition(variableName, "NOTFOUND");
+ return true;
+ }
+ // FIXME: Add policy to make non-existing lists an error like empty lists.
+ if (varArgsExpanded.empty()) {
+ this->SetError("GET given empty list");
+ return false;
+ }
+
+ std::string value;
+ size_t cc;
+ const char* sep = "";
+ size_t nitem = varArgsExpanded.size();
+ for (cc = 2; cc < args.size() - 1; cc++) {
+ int item = atoi(args[cc].c_str());
+ value += sep;
+ sep = ";";
+ if (item < 0) {
+ item = (int)nitem + item;
+ }
+ if (item < 0 || nitem <= (size_t)item) {
+ std::ostringstream str;
+ str << "index: " << item << " out of range (-" << nitem << ", "
+ << nitem - 1 << ")";
+ this->SetError(str.str());
+ return false;
+ }
+ value += varArgsExpanded[item];
+ }
+
+ this->Makefile->AddDefinition(variableName, value.c_str());
+ return true;
+}
+
+bool cmListCommand::HandleAppendCommand(std::vector<std::string> const& args)
+{
+ assert(args.size() >= 2);
+
+ // Skip if nothing to append.
+ if (args.size() < 3) {
+ return true;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::string listString;
+ this->GetListString(listString, listName);
+
+ if (!listString.empty() && !args.empty()) {
+ listString += ";";
+ }
+ listString += cmJoin(cmMakeRange(args).advance(2), ";");
+
+ this->Makefile->AddDefinition(listName, listString.c_str());
+ return true;
+}
+
+bool cmListCommand::HandleFindCommand(std::vector<std::string> const& args)
+{
+ if (args.size() != 4) {
+ this->SetError("sub-command FIND requires three arguments.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ const std::string& variableName = args[args.size() - 1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!this->GetList(varArgsExpanded, listName)) {
+ this->Makefile->AddDefinition(variableName, "-1");
+ return true;
+ }
+
+ std::vector<std::string>::iterator it =
+ std::find(varArgsExpanded.begin(), varArgsExpanded.end(), args[2]);
+ if (it != varArgsExpanded.end()) {
+ std::ostringstream indexStream;
+ indexStream << std::distance(varArgsExpanded.begin(), it);
+ this->Makefile->AddDefinition(variableName, indexStream.str().c_str());
+ return true;
+ }
+
+ this->Makefile->AddDefinition(variableName, "-1");
+ return true;
+}
+
+bool cmListCommand::HandleInsertCommand(std::vector<std::string> const& args)
+{
+ if (args.size() < 4) {
+ this->SetError("sub-command INSERT requires at least three arguments.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+
+ // expand the variable
+ int item = atoi(args[2].c_str());
+ std::vector<std::string> varArgsExpanded;
+ if ((!this->GetList(varArgsExpanded, listName) || varArgsExpanded.empty()) &&
+ item != 0) {
+ std::ostringstream str;
+ str << "index: " << item << " out of range (0, 0)";
+ this->SetError(str.str());
+ return false;
+ }
+
+ if (!varArgsExpanded.empty()) {
+ size_t nitem = varArgsExpanded.size();
+ if (item < 0) {
+ item = (int)nitem + item;
+ }
+ if (item < 0 || nitem <= (size_t)item) {
+ std::ostringstream str;
+ str << "index: " << item << " out of range (-" << varArgsExpanded.size()
+ << ", "
+ << (varArgsExpanded.empty() ? 0 : (varArgsExpanded.size() - 1))
+ << ")";
+ this->SetError(str.str());
+ return false;
+ }
+ }
+
+ varArgsExpanded.insert(varArgsExpanded.begin() + item, args.begin() + 3,
+ args.end());
+
+ std::string value = cmJoin(varArgsExpanded, ";");
+ this->Makefile->AddDefinition(listName, value.c_str());
+ return true;
+}
+
+bool cmListCommand::HandleRemoveItemCommand(
+ std::vector<std::string> const& args)
+{
+ if (args.size() < 3) {
+ this->SetError("sub-command REMOVE_ITEM requires two or more arguments.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!this->GetList(varArgsExpanded, listName)) {
+ this->SetError("sub-command REMOVE_ITEM requires list to be present.");
+ return false;
+ }
+
+ std::vector<std::string> remove(args.begin() + 2, args.end());
+ std::sort(remove.begin(), remove.end());
+ std::vector<std::string>::const_iterator remEnd =
+ std::unique(remove.begin(), remove.end());
+ std::vector<std::string>::const_iterator remBegin = remove.begin();
+
+ std::vector<std::string>::const_iterator argsEnd =
+ cmRemoveMatching(varArgsExpanded, cmMakeRange(remBegin, remEnd));
+ std::vector<std::string>::const_iterator argsBegin = varArgsExpanded.begin();
+ std::string value = cmJoin(cmMakeRange(argsBegin, argsEnd), ";");
+ this->Makefile->AddDefinition(listName, value.c_str());
+ return true;
+}
+
+bool cmListCommand::HandleReverseCommand(std::vector<std::string> const& args)
+{
+ assert(args.size() >= 2);
+ if (args.size() > 2) {
+ this->SetError("sub-command REVERSE only takes one argument.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!this->GetList(varArgsExpanded, listName)) {
+ this->SetError("sub-command REVERSE requires list to be present.");
+ return false;
+ }
+
+ std::string value = cmJoin(cmReverseRange(varArgsExpanded), ";");
+
+ this->Makefile->AddDefinition(listName, value.c_str());
+ return true;
+}
+
+bool cmListCommand::HandleRemoveDuplicatesCommand(
+ std::vector<std::string> const& args)
+{
+ assert(args.size() >= 2);
+ if (args.size() > 2) {
+ this->SetError("sub-command REMOVE_DUPLICATES only takes one argument.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!this->GetList(varArgsExpanded, listName)) {
+ this->SetError(
+ "sub-command REMOVE_DUPLICATES requires list to be present.");
+ return false;
+ }
+
+ std::vector<std::string>::const_iterator argsEnd =
+ cmRemoveDuplicates(varArgsExpanded);
+ std::vector<std::string>::const_iterator argsBegin = varArgsExpanded.begin();
+ std::string value = cmJoin(cmMakeRange(argsBegin, argsEnd), ";");
+
+ this->Makefile->AddDefinition(listName, value.c_str());
+ return true;
+}
+
+bool cmListCommand::HandleSortCommand(std::vector<std::string> const& args)
+{
+ assert(args.size() >= 2);
+ if (args.size() > 2) {
+ this->SetError("sub-command SORT only takes one argument.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!this->GetList(varArgsExpanded, listName)) {
+ this->SetError("sub-command SORT requires list to be present.");
+ return false;
+ }
+
+ std::sort(varArgsExpanded.begin(), varArgsExpanded.end());
+
+ std::string value = cmJoin(varArgsExpanded, ";");
+ this->Makefile->AddDefinition(listName, value.c_str());
+ return true;
+}
+
+bool cmListCommand::HandleRemoveAtCommand(std::vector<std::string> const& args)
+{
+ if (args.size() < 3) {
+ this->SetError("sub-command REMOVE_AT requires at least "
+ "two arguments.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!this->GetList(varArgsExpanded, listName)) {
+ this->SetError("sub-command REMOVE_AT requires list to be present.");
+ return false;
+ }
+ // FIXME: Add policy to make non-existing lists an error like empty lists.
+ if (varArgsExpanded.empty()) {
+ this->SetError("REMOVE_AT given empty list");
+ return false;
+ }
+
+ size_t cc;
+ std::vector<size_t> removed;
+ size_t nitem = varArgsExpanded.size();
+ for (cc = 2; cc < args.size(); ++cc) {
+ int item = atoi(args[cc].c_str());
+ if (item < 0) {
+ item = (int)nitem + item;
+ }
+ if (item < 0 || nitem <= (size_t)item) {
+ std::ostringstream str;
+ str << "index: " << item << " out of range (-" << nitem << ", "
+ << nitem - 1 << ")";
+ this->SetError(str.str());
+ return false;
+ }
+ removed.push_back(static_cast<size_t>(item));
+ }
+
+ std::sort(removed.begin(), removed.end());
+ std::vector<size_t>::const_iterator remEnd =
+ std::unique(removed.begin(), removed.end());
+ std::vector<size_t>::const_iterator remBegin = removed.begin();
+
+ std::vector<std::string>::const_iterator argsEnd =
+ cmRemoveIndices(varArgsExpanded, cmMakeRange(remBegin, remEnd));
+ std::vector<std::string>::const_iterator argsBegin = varArgsExpanded.begin();
+ std::string value = cmJoin(cmMakeRange(argsBegin, argsEnd), ";");
+
+ this->Makefile->AddDefinition(listName, value.c_str());
+ return true;
+}
+
+bool cmListCommand::HandleFilterCommand(std::vector<std::string> const& args)
+{
+ if (args.size() < 2) {
+ this->SetError("sub-command FILTER requires a list to be specified.");
+ return false;
+ }
+
+ if (args.size() < 3) {
+ this->SetError("sub-command FILTER requires an operator to be specified.");
+ return false;
+ }
+
+ if (args.size() < 4) {
+ this->SetError("sub-command FILTER requires a mode to be specified.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!this->GetList(varArgsExpanded, listName)) {
+ this->SetError("sub-command FILTER requires list to be present.");
+ return false;
+ }
+
+ const std::string& op = args[2];
+ bool includeMatches;
+ if (op == "INCLUDE") {
+ includeMatches = true;
+ } else if (op == "EXCLUDE") {
+ includeMatches = false;
+ } else {
+ this->SetError("sub-command FILTER does not recognize operator " + op);
+ return false;
+ }
+
+ const std::string& mode = args[3];
+ if (mode == "REGEX") {
+ if (args.size() != 5) {
+ this->SetError("sub-command FILTER, mode REGEX "
+ "requires five arguments.");
+ return false;
+ }
+ return this->FilterRegex(args, includeMatches, listName, varArgsExpanded);
+ }
+
+ this->SetError("sub-command FILTER does not recognize mode " + mode);
+ return false;
+}
+
+class MatchesRegex
+{
+public:
+ MatchesRegex(cmsys::RegularExpression& in_regex, bool in_includeMatches)
+ : regex(in_regex)
+ , includeMatches(in_includeMatches)
+ {
+ }
+
+ bool operator()(const std::string& target)
+ {
+ return regex.find(target) ^ includeMatches;
+ }
+
+private:
+ cmsys::RegularExpression& regex;
+ const bool includeMatches;
+};
+
+bool cmListCommand::FilterRegex(std::vector<std::string> const& args,
+ bool includeMatches,
+ std::string const& listName,
+ std::vector<std::string>& varArgsExpanded)
+{
+ const std::string& pattern = args[4];
+ cmsys::RegularExpression regex(pattern);
+ if (!regex.is_valid()) {
+ std::string error = "sub-command FILTER, mode REGEX ";
+ error += "failed to compile regex \"";
+ error += pattern;
+ error += "\".";
+ this->SetError(error);
+ return false;
+ }
+
+ std::vector<std::string>::iterator argsBegin = varArgsExpanded.begin();
+ std::vector<std::string>::iterator argsEnd = varArgsExpanded.end();
+ std::vector<std::string>::iterator newArgsEnd =
+ std::remove_if(argsBegin, argsEnd, MatchesRegex(regex, includeMatches));
+
+ std::string value = cmJoin(cmMakeRange(argsBegin, newArgsEnd), ";");
+ this->Makefile->AddDefinition(listName, value.c_str());
+ return true;
+}
diff --git a/Source/cmListCommand.h b/Source/cmListCommand.h
new file mode 100644
index 0000000..1c33c96
--- /dev/null
+++ b/Source/cmListCommand.h
@@ -0,0 +1,68 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmListCommand_h
+#define cmListCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmListCommand
+ * \brief Common list operations
+ *
+ */
+class cmListCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmListCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "list"; }
+
+ cmTypeMacro(cmListCommand, cmCommand);
+
+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 HandleFindCommand(std::vector<std::string> const& args);
+ bool HandleInsertCommand(std::vector<std::string> const& args);
+ bool HandleRemoveAtCommand(std::vector<std::string> const& args);
+ bool HandleRemoveItemCommand(std::vector<std::string> const& args);
+ bool HandleRemoveDuplicatesCommand(std::vector<std::string> const& args);
+ bool HandleSortCommand(std::vector<std::string> const& args);
+ bool HandleReverseCommand(std::vector<std::string> const& args);
+ bool HandleFilterCommand(std::vector<std::string> const& args);
+ bool FilterRegex(std::vector<std::string> const& args, bool includeMatches,
+ std::string const& listName,
+ std::vector<std::string>& varArgsExpanded);
+
+ bool GetList(std::vector<std::string>& list, const std::string& var);
+ bool GetListString(std::string& listString, const std::string& var);
+};
+
+#endif
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
new file mode 100644
index 0000000..28b3781
--- /dev/null
+++ b/Source/cmListFileCache.cxx
@@ -0,0 +1,453 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmListFileCache.h"
+
+#include "cmListFileLexer.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+struct cmListFileParser
+{
+ cmListFileParser(cmListFile* lf, cmMakefile* mf, const char* filename);
+ ~cmListFileParser();
+ void IssueFileOpenError(std::string const& text) const;
+ bool ParseFile();
+ bool ParseFunction(const char* name, long line);
+ bool AddArgument(cmListFileLexer_Token* token,
+ cmListFileArgument::Delimiter delim);
+ cmListFile* ListFile;
+ cmMakefile* Makefile;
+ const char* FileName;
+ cmListFileLexer* Lexer;
+ cmListFileFunction Function;
+ enum
+ {
+ SeparationOkay,
+ SeparationWarning,
+ SeparationError
+ } Separation;
+};
+
+cmListFileParser::cmListFileParser(cmListFile* lf, cmMakefile* mf,
+ const char* filename)
+ : ListFile(lf)
+ , Makefile(mf)
+ , FileName(filename)
+ , Lexer(cmListFileLexer_New())
+{
+}
+
+cmListFileParser::~cmListFileParser()
+{
+ cmListFileLexer_Delete(this->Lexer);
+}
+
+void cmListFileParser::IssueFileOpenError(const std::string& text) const
+{
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, text);
+}
+
+bool cmListFileParser::ParseFile()
+{
+ // Open the file.
+ cmListFileLexer_BOM bom;
+ if (!cmListFileLexer_SetFileName(this->Lexer, this->FileName, &bom)) {
+ this->IssueFileOpenError("cmListFileCache: error can not open file.");
+ return false;
+ }
+
+ // Verify the Byte-Order-Mark, if any.
+ if (bom != cmListFileLexer_BOM_None && bom != cmListFileLexer_BOM_UTF8) {
+ cmListFileLexer_SetFileName(this->Lexer, CM_NULLPTR, CM_NULLPTR);
+ this->IssueFileOpenError(
+ "File starts with a Byte-Order-Mark that is not UTF-8.");
+ return false;
+ }
+
+ // Use a simple recursive-descent parser to process the token
+ // stream.
+ bool haveNewline = true;
+ while (cmListFileLexer_Token* token = cmListFileLexer_Scan(this->Lexer)) {
+ if (token->type == cmListFileLexer_Token_Space) {
+ } else if (token->type == cmListFileLexer_Token_Newline) {
+ haveNewline = true;
+ } else if (token->type == cmListFileLexer_Token_CommentBracket) {
+ haveNewline = false;
+ } else if (token->type == cmListFileLexer_Token_Identifier) {
+ if (haveNewline) {
+ haveNewline = false;
+ if (this->ParseFunction(token->text, token->line)) {
+ this->ListFile->Functions.push_back(this->Function);
+ } else {
+ return false;
+ }
+ } else {
+ std::ostringstream error;
+ error << "Error in cmake code at\n"
+ << this->FileName << ":" << token->line << ":\n"
+ << "Parse error. Expected a newline, got "
+ << cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
+ << " with text \"" << token->text << "\".";
+ cmSystemTools::Error(error.str().c_str());
+ return false;
+ }
+ } else {
+ std::ostringstream error;
+ error << "Error in cmake code at\n"
+ << this->FileName << ":" << token->line << ":\n"
+ << "Parse error. Expected a command name, got "
+ << cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
+ << " with text \"" << token->text << "\".";
+ cmSystemTools::Error(error.str().c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmListFile::ParseFile(const char* filename, cmMakefile* mf)
+{
+ if (!cmSystemTools::FileExists(filename) ||
+ cmSystemTools::FileIsDirectory(filename)) {
+ return false;
+ }
+
+ bool parseError = false;
+
+ {
+ cmListFileParser parser(this, mf, filename);
+ parseError = !parser.ParseFile();
+ }
+
+ return !parseError;
+}
+
+bool cmListFileParser::ParseFunction(const char* name, long line)
+{
+ // Ininitialize a new function call.
+ this->Function = cmListFileFunction();
+ this->Function.Name = name;
+ this->Function.Line = line;
+
+ // Command name has already been parsed. Read the left paren.
+ cmListFileLexer_Token* token;
+ while ((token = cmListFileLexer_Scan(this->Lexer)) &&
+ token->type == cmListFileLexer_Token_Space) {
+ }
+ if (!token) {
+ std::ostringstream error;
+ /* clang-format off */
+ error << "Error in cmake code at\n" << this->FileName << ":"
+ << cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n"
+ << "Parse error. Function missing opening \"(\".";
+ /* clang-format on */
+ cmSystemTools::Error(error.str().c_str());
+ return false;
+ }
+ if (token->type != cmListFileLexer_Token_ParenLeft) {
+ std::ostringstream error;
+ error << "Error in cmake code at\n"
+ << this->FileName << ":"
+ << cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n"
+ << "Parse error. Expected \"(\", got "
+ << cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
+ << " with text \"" << token->text << "\".";
+ cmSystemTools::Error(error.str().c_str());
+ return false;
+ }
+
+ // Arguments.
+ unsigned long lastLine;
+ unsigned long parenDepth = 0;
+ this->Separation = SeparationOkay;
+ while ((lastLine = cmListFileLexer_GetCurrentLine(this->Lexer),
+ token = cmListFileLexer_Scan(this->Lexer))) {
+ if (token->type == cmListFileLexer_Token_Space ||
+ token->type == cmListFileLexer_Token_Newline) {
+ this->Separation = SeparationOkay;
+ continue;
+ }
+ if (token->type == cmListFileLexer_Token_ParenLeft) {
+ parenDepth++;
+ this->Separation = SeparationOkay;
+ if (!this->AddArgument(token, cmListFileArgument::Unquoted)) {
+ return false;
+ }
+ } else if (token->type == cmListFileLexer_Token_ParenRight) {
+ if (parenDepth == 0) {
+ return true;
+ }
+ parenDepth--;
+ this->Separation = SeparationOkay;
+ if (!this->AddArgument(token, cmListFileArgument::Unquoted)) {
+ return false;
+ }
+ this->Separation = SeparationWarning;
+ } else if (token->type == cmListFileLexer_Token_Identifier ||
+ token->type == cmListFileLexer_Token_ArgumentUnquoted) {
+ if (!this->AddArgument(token, cmListFileArgument::Unquoted)) {
+ return false;
+ }
+ this->Separation = SeparationWarning;
+ } else if (token->type == cmListFileLexer_Token_ArgumentQuoted) {
+ if (!this->AddArgument(token, cmListFileArgument::Quoted)) {
+ return false;
+ }
+ this->Separation = SeparationWarning;
+ } else if (token->type == cmListFileLexer_Token_ArgumentBracket) {
+ if (!this->AddArgument(token, cmListFileArgument::Bracket)) {
+ return false;
+ }
+ this->Separation = SeparationError;
+ } else if (token->type == cmListFileLexer_Token_CommentBracket) {
+ this->Separation = SeparationError;
+ } else {
+ // Error.
+ std::ostringstream error;
+ error << "Error in cmake code at\n"
+ << this->FileName << ":"
+ << cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n"
+ << "Parse error. Function missing ending \")\". "
+ << "Instead found "
+ << cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
+ << " with text \"" << token->text << "\".";
+ cmSystemTools::Error(error.str().c_str());
+ return false;
+ }
+ }
+
+ std::ostringstream error;
+ error << "Error in cmake code at\n"
+ << this->FileName << ":" << lastLine << ":\n"
+ << "Parse error. Function missing ending \")\". "
+ << "End of file reached.";
+ cmSystemTools::Error(error.str().c_str());
+
+ return false;
+}
+
+bool cmListFileParser::AddArgument(cmListFileLexer_Token* token,
+ cmListFileArgument::Delimiter delim)
+{
+ cmListFileArgument a(token->text, delim, token->line);
+ this->Function.Arguments.push_back(a);
+ if (this->Separation == SeparationOkay) {
+ return true;
+ }
+ bool isError = (this->Separation == SeparationError ||
+ delim == cmListFileArgument::Bracket);
+ std::ostringstream m;
+ /* clang-format off */
+ m << "Syntax " << (isError? "Error":"Warning") << " in cmake code at\n"
+ << " " << this->FileName << ":" << token->line << ":"
+ << token->column << "\n"
+ << "Argument not separated from preceding token by whitespace.";
+ /* clang-format on */
+ if (isError) {
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, m.str());
+ return false;
+ } else {
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str());
+ return true;
+ }
+}
+
+struct cmListFileBacktrace::Entry : public cmListFileContext
+{
+ Entry(cmListFileContext const& lfc, Entry* up)
+ : cmListFileContext(lfc)
+ , Up(up)
+ , RefCount(0)
+ {
+ if (this->Up) {
+ this->Up->Ref();
+ }
+ }
+ ~Entry()
+ {
+ if (this->Up) {
+ this->Up->Unref();
+ }
+ }
+ void Ref() { ++this->RefCount; }
+ void Unref()
+ {
+ if (--this->RefCount == 0) {
+ delete this;
+ }
+ }
+ Entry* Up;
+ unsigned int RefCount;
+};
+
+cmListFileBacktrace::cmListFileBacktrace(cmState::Snapshot bottom, Entry* up,
+ cmListFileContext const& lfc)
+ : Bottom(bottom)
+ , Cur(new Entry(lfc, up))
+{
+ assert(this->Bottom.IsValid());
+ this->Cur->Ref();
+}
+
+cmListFileBacktrace::cmListFileBacktrace(cmState::Snapshot bottom, Entry* cur)
+ : Bottom(bottom)
+ , Cur(cur)
+{
+ if (this->Cur) {
+ assert(this->Bottom.IsValid());
+ this->Cur->Ref();
+ }
+}
+
+cmListFileBacktrace::cmListFileBacktrace()
+ : Bottom()
+ , Cur(CM_NULLPTR)
+{
+}
+
+cmListFileBacktrace::cmListFileBacktrace(cmState::Snapshot snapshot)
+ : Bottom(snapshot.GetCallStackBottom())
+ , Cur(CM_NULLPTR)
+{
+}
+
+cmListFileBacktrace::cmListFileBacktrace(cmListFileBacktrace const& r)
+ : Bottom(r.Bottom)
+ , Cur(r.Cur)
+{
+ if (this->Cur) {
+ assert(this->Bottom.IsValid());
+ this->Cur->Ref();
+ }
+}
+
+cmListFileBacktrace& cmListFileBacktrace::operator=(
+ cmListFileBacktrace const& r)
+{
+ cmListFileBacktrace tmp(r);
+ std::swap(this->Cur, tmp.Cur);
+ std::swap(this->Bottom, tmp.Bottom);
+ return *this;
+}
+
+cmListFileBacktrace::~cmListFileBacktrace()
+{
+ if (this->Cur) {
+ this->Cur->Unref();
+ }
+}
+
+cmListFileBacktrace cmListFileBacktrace::Push(std::string const& file) const
+{
+ // We are entering a file-level scope but have not yet reached
+ // any specific line or command invocation within it. This context
+ // is useful to print when it is at the top but otherwise can be
+ // skipped during call stack printing.
+ cmListFileContext lfc;
+ lfc.FilePath = file;
+ return cmListFileBacktrace(this->Bottom, this->Cur, lfc);
+}
+
+cmListFileBacktrace cmListFileBacktrace::Push(
+ cmListFileContext const& lfc) const
+{
+ return cmListFileBacktrace(this->Bottom, this->Cur, lfc);
+}
+
+cmListFileBacktrace cmListFileBacktrace::Pop() const
+{
+ assert(this->Cur);
+ return cmListFileBacktrace(this->Bottom, this->Cur->Up);
+}
+
+cmListFileContext const& cmListFileBacktrace::Top() const
+{
+ if (this->Cur) {
+ return *this->Cur;
+ } else {
+ static cmListFileContext const empty;
+ return empty;
+ }
+}
+
+void cmListFileBacktrace::PrintTitle(std::ostream& out) const
+{
+ if (!this->Cur) {
+ return;
+ }
+ cmOutputConverter converter(this->Bottom);
+ cmListFileContext lfc = *this->Cur;
+ if (!this->Bottom.GetState()->GetIsInTryCompile()) {
+ lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME);
+ }
+ out << (lfc.Line ? " at " : " in ") << lfc;
+}
+
+void cmListFileBacktrace::PrintCallStack(std::ostream& out) const
+{
+ if (!this->Cur || !this->Cur->Up) {
+ return;
+ }
+
+ bool first = true;
+ cmOutputConverter converter(this->Bottom);
+ for (Entry* i = this->Cur->Up; i; i = i->Up) {
+ if (i->Name.empty()) {
+ // Skip this whole-file scope. When we get here we already will
+ // have printed a more-specific context within the file.
+ continue;
+ }
+ if (first) {
+ first = false;
+ out << "Call Stack (most recent call first):\n";
+ }
+ cmListFileContext lfc = *i;
+ if (!this->Bottom.GetState()->GetIsInTryCompile()) {
+ lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME);
+ }
+ out << " " << lfc << "\n";
+ }
+}
+
+std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc)
+{
+ os << lfc.FilePath;
+ if (lfc.Line) {
+ os << ":" << lfc.Line;
+ if (!lfc.Name.empty()) {
+ os << " (" << lfc.Name << ")";
+ }
+ }
+ return os;
+}
+
+bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs)
+{
+ if (lhs.Line != rhs.Line) {
+ return lhs.Line < rhs.Line;
+ }
+ return lhs.FilePath < rhs.FilePath;
+}
+
+bool operator==(const cmListFileContext& lhs, const cmListFileContext& rhs)
+{
+ return lhs.Line == rhs.Line && lhs.FilePath == rhs.FilePath;
+}
+
+bool operator!=(const cmListFileContext& lhs, const cmListFileContext& rhs)
+{
+ return !(lhs == rhs);
+}
diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h
new file mode 100644
index 0000000..f3e6f70
--- /dev/null
+++ b/Source/cmListFileCache.h
@@ -0,0 +1,166 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmListFileCache_h
+#define cmListFileCache_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmState.h"
+
+/** \class cmListFileCache
+ * \brief A class to cache list file contents.
+ *
+ * cmListFileCache is a class used to cache the contents of parsed
+ * cmake list files.
+ */
+
+class cmMakefile;
+
+struct cmCommandContext
+{
+ std::string Name;
+ long Line;
+ cmCommandContext()
+ : Name()
+ , Line(0)
+ {
+ }
+};
+
+struct cmListFileArgument
+{
+ enum Delimiter
+ {
+ Unquoted,
+ Quoted,
+ Bracket
+ };
+ cmListFileArgument()
+ : Value()
+ , Delim(Unquoted)
+ , Line(0)
+ {
+ }
+ cmListFileArgument(const cmListFileArgument& r)
+ : Value(r.Value)
+ , Delim(r.Delim)
+ , Line(r.Line)
+ {
+ }
+ cmListFileArgument(const std::string& v, Delimiter d, long line)
+ : Value(v)
+ , Delim(d)
+ , Line(line)
+ {
+ }
+ bool operator==(const cmListFileArgument& r) const
+ {
+ return (this->Value == r.Value) && (this->Delim == r.Delim);
+ }
+ bool operator!=(const cmListFileArgument& r) const { return !(*this == r); }
+ std::string Value;
+ Delimiter Delim;
+ long Line;
+};
+
+class cmListFileContext
+{
+public:
+ std::string Name;
+ std::string FilePath;
+ long Line;
+ cmListFileContext()
+ : Name()
+ , FilePath()
+ , Line(0)
+ {
+ }
+
+ static cmListFileContext FromCommandContext(cmCommandContext const& lfcc,
+ std::string const& fileName)
+ {
+ cmListFileContext lfc;
+ lfc.FilePath = fileName;
+ lfc.Line = lfcc.Line;
+ lfc.Name = lfcc.Name;
+ return lfc;
+ }
+};
+
+std::ostream& operator<<(std::ostream&, cmListFileContext const&);
+bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs);
+bool operator==(cmListFileContext const& lhs, cmListFileContext const& rhs);
+bool operator!=(cmListFileContext const& lhs, cmListFileContext const& rhs);
+
+struct cmListFileFunction : public cmCommandContext
+{
+ std::vector<cmListFileArgument> Arguments;
+};
+
+// Represent a backtrace (call stack). Provide value semantics
+// but use efficient reference-counting underneath to avoid copies.
+class cmListFileBacktrace
+{
+public:
+ // Default-constructed backtrace may not be used until after
+ // set via assignment from a backtrace constructed with a
+ // valid snapshot.
+ cmListFileBacktrace();
+
+ // Construct an empty backtrace whose bottom sits in the directory
+ // indicated by the given valid snapshot.
+ cmListFileBacktrace(cmState::Snapshot snapshot);
+
+ // Backtraces may be copied and assigned as values.
+ cmListFileBacktrace(cmListFileBacktrace const& r);
+ cmListFileBacktrace& operator=(cmListFileBacktrace const& r);
+ ~cmListFileBacktrace();
+
+ // Get a backtrace with the given file scope added to the top.
+ // May not be called until after construction with a valid snapshot.
+ cmListFileBacktrace Push(std::string const& file) const;
+
+ // Get a backtrace with the given call context added to the top.
+ // May not be called until after construction with a valid snapshot.
+ cmListFileBacktrace Push(cmListFileContext const& lfc) const;
+
+ // Get a backtrace with the top level removed.
+ // May not be called until after a matching Push.
+ cmListFileBacktrace Pop() const;
+
+ // Get the context at the top of the backtrace.
+ // Returns an empty context if the backtrace is empty.
+ cmListFileContext const& Top() const;
+
+ // Print the top of the backtrace.
+ void PrintTitle(std::ostream& out) const;
+
+ // Print the call stack below the top of the backtrace.
+ void PrintCallStack(std::ostream& out) const;
+
+private:
+ struct Entry;
+ cmState::Snapshot Bottom;
+ Entry* Cur;
+ cmListFileBacktrace(cmState::Snapshot bottom, Entry* up,
+ cmListFileContext const& lfc);
+ cmListFileBacktrace(cmState::Snapshot bottom, Entry* cur);
+};
+
+struct cmListFile
+{
+ bool ParseFile(const char* path, cmMakefile* mf);
+
+ std::vector<cmListFileFunction> Functions;
+};
+
+#endif
diff --git a/Source/cmListFileLexer.c b/Source/cmListFileLexer.c
new file mode 100644
index 0000000..bc1666e
--- /dev/null
+++ b/Source/cmListFileLexer.c
@@ -0,0 +1,2698 @@
+#line 2 "cmListFileLexer.c"
+
+#line 4 "cmListFileLexer.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 0
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE cmListFileLexer_yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+ * access to the local variable yy_act. Since yyless() is a macro, it would break
+ * existing scanners that call yyless() from OUTSIDE cmListFileLexer_yylex.
+ * One obvious solution it to make yy_act a global. I tried that, and saw
+ * a 5% performance hit in a non-yylineno scanner, because yy_act is
+ * normally declared as a register variable-- so it is not worth it.
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+ int yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+ }while(0)
+ #define YY_LINENO_REWIND_TO(dst) \
+ do {\
+ const char *p;\
+ for ( p = yy_cp-1; p >= (dst); --p)\
+ if ( *p == '\n' )\
+ --yylineno;\
+ }while(0)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via cmListFileLexer_yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void cmListFileLexer_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void cmListFileLexer_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmListFileLexer_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void cmListFileLexer_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmListFileLexer_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void cmListFileLexer_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void cmListFileLexer_yypop_buffer_state (yyscan_t yyscanner );
+
+static void cmListFileLexer_yyensure_buffer_stack (yyscan_t yyscanner );
+static void cmListFileLexer_yy_load_buffer_state (yyscan_t yyscanner );
+static void cmListFileLexer_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER cmListFileLexer_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE cmListFileLexer_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmListFileLexer_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE cmListFileLexer_yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+void *cmListFileLexer_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *cmListFileLexer_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void cmListFileLexer_yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer cmListFileLexer_yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ cmListFileLexer_yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ cmListFileLexer_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ cmListFileLexer_yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ cmListFileLexer_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cmListFileLexer_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+#if defined(__GNUC__) && __GNUC__ >= 3
+__attribute__((__noreturn__))
+#endif
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 24
+#define YY_END_OF_BUFFER 25
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[77] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 4, 4,
+ 25, 13, 22, 1, 16, 3, 13, 5, 6, 7,
+ 15, 23, 17, 19, 20, 21, 10, 11, 8, 12,
+ 9, 4, 13, 0, 13, 0, 22, 0, 0, 7,
+ 13, 0, 13, 0, 2, 0, 13, 17, 0, 18,
+ 10, 8, 4, 0, 14, 0, 0, 0, 0, 14,
+ 0, 0, 14, 0, 0, 0, 2, 14, 0, 0,
+ 0, 0, 0, 0, 0, 0
+ } ;
+
+static yyconst YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 5, 6, 7, 1, 1, 1, 8,
+ 9, 1, 1, 1, 1, 1, 1, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 1, 1, 1,
+ 11, 1, 1, 1, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 13, 14, 15, 1, 12, 1, 12, 12, 12, 12,
+
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst YY_CHAR yy_meta[16] =
+ { 0,
+ 1, 1, 2, 3, 4, 3, 1, 3, 5, 6,
+ 1, 6, 1, 1, 7
+ } ;
+
+static yyconst flex_uint16_t yy_base[95] =
+ { 0,
+ 0, 0, 13, 25, 14, 16, 17, 18, 90, 88,
+ 88, 39, 20, 237, 237, 74, 78, 237, 237, 13,
+ 54, 0, 71, 237, 237, 31, 0, 237, 73, 237,
+ 237, 0, 0, 65, 75, 0, 33, 30, 72, 0,
+ 0, 75, 70, 0, 74, 0, 0, 62, 70, 237,
+ 0, 63, 0, 85, 99, 65, 111, 62, 34, 0,
+ 54, 116, 0, 54, 127, 51, 237, 50, 0, 48,
+ 47, 39, 33, 29, 17, 237, 136, 143, 150, 157,
+ 164, 171, 178, 184, 191, 198, 201, 207, 214, 217,
+ 219, 225, 228, 230
+
+ } ;
+
+static yyconst flex_int16_t yy_def[95] =
+ { 0,
+ 76, 1, 77, 77, 78, 78, 79, 79, 80, 80,
+ 76, 76, 76, 76, 76, 76, 12, 76, 76, 12,
+ 76, 81, 82, 76, 76, 82, 83, 76, 76, 76,
+ 76, 84, 12, 85, 12, 86, 76, 76, 87, 20,
+ 12, 88, 12, 21, 76, 89, 12, 82, 82, 76,
+ 83, 76, 84, 85, 76, 54, 85, 90, 76, 55,
+ 87, 88, 55, 62, 88, 91, 76, 55, 92, 93,
+ 90, 94, 91, 93, 94, 0, 76, 76, 76, 76,
+ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
+ 76, 76, 76, 76
+
+ } ;
+
+static yyconst flex_uint16_t yy_nxt[253] =
+ { 0,
+ 12, 13, 14, 13, 15, 16, 17, 18, 19, 12,
+ 12, 20, 21, 22, 12, 24, 28, 25, 28, 28,
+ 28, 37, 40, 37, 40, 62, 26, 24, 29, 25,
+ 29, 31, 31, 50, 37, 48, 37, 54, 26, 33,
+ 59, 63, 45, 34, 59, 35, 45, 62, 33, 33,
+ 33, 33, 36, 33, 41, 55, 54, 58, 42, 63,
+ 43, 72, 60, 41, 44, 41, 45, 46, 41, 55,
+ 55, 56, 70, 52, 48, 49, 67, 66, 57, 63,
+ 60, 64, 58, 52, 49, 39, 38, 76, 65, 55,
+ 14, 56, 14, 76, 76, 76, 76, 76, 57, 55,
+
+ 76, 76, 76, 34, 76, 68, 76, 76, 55, 55,
+ 55, 55, 69, 55, 54, 76, 54, 76, 54, 54,
+ 63, 76, 64, 76, 76, 76, 76, 76, 76, 65,
+ 62, 76, 62, 76, 62, 62, 23, 23, 23, 23,
+ 23, 23, 23, 27, 27, 27, 27, 27, 27, 27,
+ 30, 30, 30, 30, 30, 30, 30, 32, 32, 32,
+ 32, 32, 32, 32, 47, 76, 47, 47, 47, 47,
+ 47, 48, 76, 48, 76, 48, 48, 48, 51, 76,
+ 51, 51, 51, 51, 53, 76, 53, 53, 53, 53,
+ 53, 54, 76, 76, 54, 76, 54, 54, 33, 76,
+
+ 33, 33, 33, 33, 33, 61, 61, 62, 76, 76,
+ 62, 76, 62, 62, 41, 76, 41, 41, 41, 41,
+ 41, 71, 71, 73, 73, 55, 76, 55, 55, 55,
+ 55, 55, 74, 74, 75, 75, 11, 76, 76, 76,
+ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
+ 76, 76
+ } ;
+
+static yyconst flex_int16_t yy_chk[253] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 3, 5, 3, 6, 7,
+ 8, 13, 20, 13, 20, 75, 3, 4, 5, 4,
+ 6, 7, 8, 26, 37, 26, 37, 74, 4, 12,
+ 38, 73, 38, 12, 59, 12, 59, 72, 12, 12,
+ 12, 12, 12, 12, 21, 71, 70, 68, 21, 66,
+ 21, 64, 61, 21, 21, 21, 21, 21, 21, 34,
+ 58, 34, 56, 52, 49, 48, 45, 43, 34, 42,
+ 39, 42, 35, 29, 23, 17, 16, 11, 42, 54,
+ 10, 54, 9, 0, 0, 0, 0, 0, 54, 55,
+
+ 0, 0, 0, 55, 0, 55, 0, 0, 55, 55,
+ 55, 55, 55, 55, 57, 0, 57, 0, 57, 57,
+ 62, 0, 62, 0, 0, 0, 0, 0, 0, 62,
+ 65, 0, 65, 0, 65, 65, 77, 77, 77, 77,
+ 77, 77, 77, 78, 78, 78, 78, 78, 78, 78,
+ 79, 79, 79, 79, 79, 79, 79, 80, 80, 80,
+ 80, 80, 80, 80, 81, 0, 81, 81, 81, 81,
+ 81, 82, 0, 82, 0, 82, 82, 82, 83, 0,
+ 83, 83, 83, 83, 84, 0, 84, 84, 84, 84,
+ 84, 85, 0, 0, 85, 0, 85, 85, 86, 0,
+
+ 86, 86, 86, 86, 86, 87, 87, 88, 0, 0,
+ 88, 0, 88, 88, 89, 0, 89, 89, 89, 89,
+ 89, 90, 90, 91, 91, 92, 0, 92, 92, 92,
+ 92, 92, 93, 93, 94, 94, 76, 76, 76, 76,
+ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
+ 76, 76
+ } ;
+
+/* Table of booleans, true if rule could match eol. */
+static yyconst flex_int32_t yy_rule_can_match_eol[25] =
+ { 0,
+1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1,
+ 0, 0, 0, 0, 0, };
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "cmListFileLexer.in.l"
+#line 2 "cmListFileLexer.in.l"
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex --prefix=cmListFileLexer_yy -ocmListFileLexer.c cmListFileLexer.in.l
+
+Modify cmListFileLexer.c:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmListFileLexer.c
+ - remove blank lines at end of file
+ - remove statement "yyscanner = NULL;" from cmListFileLexer_yylex_destroy
+ - remove all YY_BREAK lines occurring right after return statements
+ - remove unnecessary cast to (int) in yy_get_next_buffer
+
+*/
+
+#include "cmStandardLexer.h"
+#ifdef WIN32
+#include <cmsys/Encoding.h>
+#endif
+
+/* Setup the proper cmListFileLexer_yylex declaration. */
+#define YY_EXTRA_TYPE cmListFileLexer*
+#define YY_DECL int cmListFileLexer_yylex (yyscan_t yyscanner, cmListFileLexer* lexer)
+
+#include "cmListFileLexer.h"
+
+/*--------------------------------------------------------------------------*/
+struct cmListFileLexer_s
+{
+ cmListFileLexer_Token token;
+ yy_size_t bracket;
+ int comment;
+ int line;
+ int column;
+ int size;
+ FILE* file;
+ size_t cr;
+ char* string_buffer;
+ char* string_position;
+ int string_left;
+ yyscan_t scanner;
+};
+
+static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
+ int length);
+static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
+ int length);
+static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
+ size_t bufferSize);
+static void cmListFileLexerInit(cmListFileLexer* lexer);
+static void cmListFileLexerDestroy(cmListFileLexer* lexer);
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ { result = cmListFileLexerInput(cmListFileLexer_yyget_extra(yyscanner), buf, max_size); }
+
+/*--------------------------------------------------------------------------*/
+
+
+
+
+#line 628 "cmListFileLexer.c"
+
+#define INITIAL 0
+#define STRING 1
+#define BRACKET 2
+#define BRACKETEND 3
+#define COMMENT 4
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ yy_size_t yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+int cmListFileLexer_yylex_init (yyscan_t* scanner);
+
+int cmListFileLexer_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int cmListFileLexer_yylex_destroy (yyscan_t yyscanner );
+
+int cmListFileLexer_yyget_debug (yyscan_t yyscanner );
+
+void cmListFileLexer_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE cmListFileLexer_yyget_extra (yyscan_t yyscanner );
+
+void cmListFileLexer_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *cmListFileLexer_yyget_in (yyscan_t yyscanner );
+
+void cmListFileLexer_yyset_in (FILE * _in_str ,yyscan_t yyscanner );
+
+FILE *cmListFileLexer_yyget_out (yyscan_t yyscanner );
+
+void cmListFileLexer_yyset_out (FILE * _out_str ,yyscan_t yyscanner );
+
+yy_size_t cmListFileLexer_yyget_leng (yyscan_t yyscanner );
+
+char *cmListFileLexer_yyget_text (yyscan_t yyscanner );
+
+int cmListFileLexer_yyget_lineno (yyscan_t yyscanner );
+
+void cmListFileLexer_yyset_lineno (int _line_number ,yyscan_t yyscanner );
+
+int cmListFileLexer_yyget_column (yyscan_t yyscanner );
+
+void cmListFileLexer_yyset_column (int _column_no ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int cmListFileLexer_yywrap (yyscan_t yyscanner );
+#else
+extern int cmListFileLexer_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner);
+
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int cmListFileLexer_yylex (yyscan_t yyscanner);
+
+#define YY_DECL int cmListFileLexer_yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ cmListFileLexer_yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ cmListFileLexer_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ cmListFileLexer_yy_load_buffer_state(yyscanner );
+ }
+
+ {
+#line 88 "cmListFileLexer.in.l"
+
+
+#line 896 "cmListFileLexer.c"
+
+ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 77 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 237 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+ yy_size_t yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+ }
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+/* rule 1 can match eol */
+YY_RULE_SETUP
+#line 90 "cmListFileLexer.in.l"
+{
+ lexer->token.type = cmListFileLexer_Token_Newline;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ ++lexer->line;
+ lexer->column = 1;
+ BEGIN(INITIAL);
+ return 1;
+}
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+#line 99 "cmListFileLexer.in.l"
+{
+ const char* bracket = yytext;
+ lexer->comment = yytext[0] == '#';
+ if (lexer->comment) {
+ lexer->token.type = cmListFileLexer_Token_CommentBracket;
+ bracket += 1;
+ } else {
+ lexer->token.type = cmListFileLexer_Token_ArgumentBracket;
+ }
+ cmListFileLexerSetToken(lexer, "", 0);
+ lexer->bracket = strchr(bracket+1, '[') - bracket;
+ if (yytext[yyleng-1] == '\n') {
+ ++lexer->line;
+ lexer->column = 1;
+ } else {
+ lexer->column += yyleng;
+ }
+ BEGIN(BRACKET);
+}
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 119 "cmListFileLexer.in.l"
+{
+ lexer->column += yyleng;
+ BEGIN(COMMENT);
+}
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 124 "cmListFileLexer.in.l"
+{
+ lexer->column += yyleng;
+}
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 128 "cmListFileLexer.in.l"
+{
+ lexer->token.type = cmListFileLexer_Token_ParenLeft;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+case 6:
+YY_RULE_SETUP
+#line 135 "cmListFileLexer.in.l"
+{
+ lexer->token.type = cmListFileLexer_Token_ParenRight;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+case 7:
+YY_RULE_SETUP
+#line 142 "cmListFileLexer.in.l"
+{
+ lexer->token.type = cmListFileLexer_Token_Identifier;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+case 8:
+YY_RULE_SETUP
+#line 149 "cmListFileLexer.in.l"
+{
+ /* Handle ]]====]=======]*/
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ if (yyleng == lexer->bracket) {
+ BEGIN(BRACKETEND);
+ }
+}
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 158 "cmListFileLexer.in.l"
+{
+ lexer->column += yyleng;
+ /* Erase the partial bracket from the token. */
+ lexer->token.length -= lexer->bracket;
+ lexer->token.text[lexer->token.length] = 0;
+ BEGIN(INITIAL);
+ return 1;
+}
+case 10:
+YY_RULE_SETUP
+#line 167 "cmListFileLexer.in.l"
+{
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+}
+ YY_BREAK
+case 11:
+/* rule 11 can match eol */
+YY_RULE_SETUP
+#line 172 "cmListFileLexer.in.l"
+{
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ ++lexer->line;
+ lexer->column = 1;
+ BEGIN(BRACKET);
+}
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 179 "cmListFileLexer.in.l"
+{
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ BEGIN(BRACKET);
+}
+ YY_BREAK
+case YY_STATE_EOF(BRACKET):
+case YY_STATE_EOF(BRACKETEND):
+#line 185 "cmListFileLexer.in.l"
+{
+ lexer->token.type = cmListFileLexer_Token_BadBracket;
+ BEGIN(INITIAL);
+ return 1;
+}
+case 13:
+YY_RULE_SETUP
+#line 191 "cmListFileLexer.in.l"
+{
+ lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+case 14:
+YY_RULE_SETUP
+#line 198 "cmListFileLexer.in.l"
+{
+ lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+case 15:
+YY_RULE_SETUP
+#line 205 "cmListFileLexer.in.l"
+{
+ lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+case 16:
+YY_RULE_SETUP
+#line 212 "cmListFileLexer.in.l"
+{
+ lexer->token.type = cmListFileLexer_Token_ArgumentQuoted;
+ cmListFileLexerSetToken(lexer, "", 0);
+ lexer->column += yyleng;
+ BEGIN(STRING);
+}
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 219 "cmListFileLexer.in.l"
+{
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+}
+ YY_BREAK
+case 18:
+/* rule 18 can match eol */
+YY_RULE_SETUP
+#line 224 "cmListFileLexer.in.l"
+{
+ /* Continuation: text is not part of string */
+ ++lexer->line;
+ lexer->column = 1;
+}
+ YY_BREAK
+case 19:
+/* rule 19 can match eol */
+YY_RULE_SETUP
+#line 230 "cmListFileLexer.in.l"
+{
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ ++lexer->line;
+ lexer->column = 1;
+}
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 236 "cmListFileLexer.in.l"
+{
+ lexer->column += yyleng;
+ BEGIN(INITIAL);
+ return 1;
+}
+case 21:
+YY_RULE_SETUP
+#line 242 "cmListFileLexer.in.l"
+{
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+}
+ YY_BREAK
+case YY_STATE_EOF(STRING):
+#line 247 "cmListFileLexer.in.l"
+{
+ lexer->token.type = cmListFileLexer_Token_BadString;
+ BEGIN(INITIAL);
+ return 1;
+}
+case 22:
+YY_RULE_SETUP
+#line 253 "cmListFileLexer.in.l"
+{
+ lexer->token.type = cmListFileLexer_Token_Space;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+case 23:
+YY_RULE_SETUP
+#line 260 "cmListFileLexer.in.l"
+{
+ lexer->token.type = cmListFileLexer_Token_BadCharacter;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMENT):
+#line 267 "cmListFileLexer.in.l"
+{
+ lexer->token.type = cmListFileLexer_Token_None;
+ cmListFileLexerSetToken(lexer, 0, 0);
+ return 0;
+}
+case 24:
+YY_RULE_SETUP
+#line 273 "cmListFileLexer.in.l"
+ECHO;
+ YY_BREAK
+#line 1235 "cmListFileLexer.c"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * cmListFileLexer_yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( cmListFileLexer_yywrap(yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of cmListFileLexer_yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ yy_size_t number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (yy_size_t) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ cmListFileLexer_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ cmListFileLexer_yyrestart(yyin ,yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) cmListFileLexer_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 77 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 77 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 76);
+
+ (void)yyg;
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput (int c, char * yy_bp , yyscan_t yyscanner)
+{
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yyg->yy_hold_char;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ yy_size_t number_to_move = yyg->yy_n_chars + 2;
+ char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ if ( c == '\n' ){
+ --yylineno;
+ }
+
+ yyg->yytext_ptr = yy_bp;
+ yyg->yy_hold_char = *yy_cp;
+ yyg->yy_c_buf_p = yy_cp;
+}
+
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ cmListFileLexer_yyrestart(yyin ,yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( cmListFileLexer_yywrap(yyscanner ) )
+ return EOF;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ if ( c == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void cmListFileLexer_yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ cmListFileLexer_yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ cmListFileLexer_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ cmListFileLexer_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+ cmListFileLexer_yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void cmListFileLexer_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * cmListFileLexer_yypop_buffer_state();
+ * cmListFileLexer_yypush_buffer_state(new_buffer);
+ */
+ cmListFileLexer_yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ cmListFileLexer_yy_load_buffer_state(yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (cmListFileLexer_yywrap()) processing, but the only time this flag
+ * is looked at is after cmListFileLexer_yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void cmListFileLexer_yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE cmListFileLexer_yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) cmListFileLexer_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in cmListFileLexer_yy_create_buffer()" );
+
+ b->yy_buf_size = (yy_size_t)size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) cmListFileLexer_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in cmListFileLexer_yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ cmListFileLexer_yy_init_buffer(b,file ,yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with cmListFileLexer_yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void cmListFileLexer_yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ cmListFileLexer_yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+ cmListFileLexer_yyfree((void *) b ,yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a cmListFileLexer_yyrestart() or at EOF.
+ */
+ static void cmListFileLexer_yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ cmListFileLexer_yy_flush_buffer(b ,yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then cmListFileLexer_yy_init_buffer was _probably_
+ * called from cmListFileLexer_yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void cmListFileLexer_yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ cmListFileLexer_yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void cmListFileLexer_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ cmListFileLexer_yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from cmListFileLexer_yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from cmListFileLexer_yy_switch_to_buffer. */
+ cmListFileLexer_yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void cmListFileLexer_yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ cmListFileLexer_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ cmListFileLexer_yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void cmListFileLexer_yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)cmListFileLexer_yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in cmListFileLexer_yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)cmListFileLexer_yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in cmListFileLexer_yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cmListFileLexer_yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) cmListFileLexer_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in cmListFileLexer_yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ cmListFileLexer_yy_switch_to_buffer(b ,yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to cmListFileLexer_yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * cmListFileLexer_yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE cmListFileLexer_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+
+ return cmListFileLexer_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to cmListFileLexer_yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cmListFileLexer_yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ yy_size_t i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) cmListFileLexer_yyalloc(n ,yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in cmListFileLexer_yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = cmListFileLexer_yy_scan_buffer(buf,n ,yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in cmListFileLexer_yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE cmListFileLexer_yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int cmListFileLexer_yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int cmListFileLexer_yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *cmListFileLexer_yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *cmListFileLexer_yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+yy_size_t cmListFileLexer_yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *cmListFileLexer_yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void cmListFileLexer_yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param _line_number line number
+ * @param yyscanner The scanner object.
+ */
+void cmListFileLexer_yyset_lineno (int _line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "cmListFileLexer_yyset_lineno called with no buffer" );
+
+ yylineno = _line_number;
+}
+
+/** Set the current column.
+ * @param _column_no column number
+ * @param yyscanner The scanner object.
+ */
+void cmListFileLexer_yyset_column (int _column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "cmListFileLexer_yyset_column called with no buffer" );
+
+ yycolumn = _column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see cmListFileLexer_yy_switch_to_buffer
+ */
+void cmListFileLexer_yyset_in (FILE * _in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = _in_str ;
+}
+
+void cmListFileLexer_yyset_out (FILE * _out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = _out_str ;
+}
+
+int cmListFileLexer_yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void cmListFileLexer_yyset_debug (int _bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = _bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+/* User-visible API */
+
+/* cmListFileLexer_yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int cmListFileLexer_yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) cmListFileLexer_yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* cmListFileLexer_yylex_init_extra has the same functionality as cmListFileLexer_yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to cmListFileLexer_yyalloc in
+ * the yyextra field.
+ */
+
+int cmListFileLexer_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+ struct yyguts_t dummy_yyguts;
+
+ cmListFileLexer_yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) cmListFileLexer_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ cmListFileLexer_yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from cmListFileLexer_yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = 0;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = (char *) 0;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * cmListFileLexer_yylex_init()
+ */
+ return 0;
+}
+
+/* cmListFileLexer_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int cmListFileLexer_yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ cmListFileLexer_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ cmListFileLexer_yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ cmListFileLexer_yyfree(yyg->yy_buffer_stack ,yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ cmListFileLexer_yyfree(yyg->yy_start_stack ,yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * cmListFileLexer_yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ cmListFileLexer_yyfree ( yyscanner , yyscanner );
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *cmListFileLexer_yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ return (void *) malloc( size );
+}
+
+void *cmListFileLexer_yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void cmListFileLexer_yyfree (void * ptr , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ free( (char *) ptr ); /* see cmListFileLexer_yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 273 "cmListFileLexer.in.l"
+
+
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
+ int length)
+{
+ /* Set the token line and column number. */
+ lexer->token.line = lexer->line;
+ lexer->token.column = lexer->column;
+
+ /* Use the same buffer if possible. */
+ if (lexer->token.text) {
+ if (text && length < lexer->size) {
+ strcpy(lexer->token.text, text);
+ lexer->token.length = length;
+ return;
+ }
+ free(lexer->token.text);
+ lexer->token.text = 0;
+ lexer->size = 0;
+ }
+
+ /* Need to extend the buffer. */
+ if (text) {
+ lexer->token.text = strdup(text);
+ lexer->token.length = length;
+ lexer->size = length + 1;
+ } else {
+ lexer->token.length = 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
+ int length)
+{
+ char* temp;
+ int newSize;
+
+ /* If the appended text will fit in the buffer, do not reallocate. */
+ newSize = lexer->token.length + length + 1;
+ if (lexer->token.text && newSize <= lexer->size) {
+ strcpy(lexer->token.text + lexer->token.length, text);
+ lexer->token.length += length;
+ return;
+ }
+
+ /* We need to extend the buffer. */
+ temp = malloc(newSize);
+ if (lexer->token.text) {
+ memcpy(temp, lexer->token.text, lexer->token.length);
+ free(lexer->token.text);
+ }
+ memcpy(temp + lexer->token.length, text, length);
+ temp[lexer->token.length + length] = 0;
+ lexer->token.text = temp;
+ lexer->token.length += length;
+ lexer->size = newSize;
+}
+
+/*--------------------------------------------------------------------------*/
+static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
+ size_t bufferSize)
+{
+ if (lexer) {
+ if (lexer->file) {
+ /* Convert CRLF -> LF explicitly. The C FILE "t"ext mode
+ does not convert newlines on all platforms. Move any
+ trailing CR to the start of the buffer for the next read. */
+ size_t cr = lexer->cr;
+ size_t n;
+ buffer[0] = '\r';
+ n = fread(buffer + cr, 1, bufferSize - cr, lexer->file);
+ if (n) {
+ char* o = buffer;
+ const char* i = buffer;
+ const char* e;
+ n += cr;
+ cr = (buffer[n - 1] == '\r') ? 1 : 0;
+ e = buffer + n - cr;
+ while (i != e) {
+ if (i[0] == '\r' && i[1] == '\n') {
+ ++i;
+ }
+ *o++ = *i++;
+ }
+ n = o - buffer;
+ } else {
+ n = cr;
+ cr = 0;
+ }
+ lexer->cr = cr;
+ return n;
+ } else if (lexer->string_left) {
+ int length = lexer->string_left;
+ if ((int)bufferSize < length) {
+ length = (int)bufferSize;
+ }
+ memcpy(buffer, lexer->string_position, length);
+ lexer->string_position += length;
+ lexer->string_left -= length;
+ return length;
+ }
+ }
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerInit(cmListFileLexer* lexer)
+{
+ if (lexer->file || lexer->string_buffer) {
+ cmListFileLexer_yylex_init(&lexer->scanner);
+ cmListFileLexer_yyset_extra(lexer, lexer->scanner);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerDestroy(cmListFileLexer* lexer)
+{
+ cmListFileLexerSetToken(lexer, 0, 0);
+ if (lexer->file || lexer->string_buffer) {
+ cmListFileLexer_yylex_destroy(lexer->scanner);
+ if (lexer->file) {
+ fclose(lexer->file);
+ lexer->file = 0;
+ }
+ if (lexer->string_buffer) {
+ free(lexer->string_buffer);
+ lexer->string_buffer = 0;
+ lexer->string_left = 0;
+ lexer->string_position = 0;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+cmListFileLexer* cmListFileLexer_New()
+{
+ cmListFileLexer* lexer = (cmListFileLexer*)malloc(sizeof(cmListFileLexer));
+ if (!lexer) {
+ return 0;
+ }
+ memset(lexer, 0, sizeof(*lexer));
+ lexer->line = 1;
+ lexer->column = 1;
+ return lexer;
+}
+
+/*--------------------------------------------------------------------------*/
+void cmListFileLexer_Delete(cmListFileLexer* lexer)
+{
+ cmListFileLexer_SetFileName(lexer, 0, 0);
+ free(lexer);
+}
+
+/*--------------------------------------------------------------------------*/
+static cmListFileLexer_BOM cmListFileLexer_ReadBOM(FILE* f)
+{
+ unsigned char b[2];
+ if (fread(b, 1, 2, f) == 2) {
+ if (b[0] == 0xEF && b[1] == 0xBB) {
+ if (fread(b, 1, 1, f) == 1 && b[0] == 0xBF) {
+ return cmListFileLexer_BOM_UTF8;
+ }
+ } else if (b[0] == 0xFE && b[1] == 0xFF) {
+ /* UTF-16 BE */
+ return cmListFileLexer_BOM_UTF16BE;
+ } else if (b[0] == 0 && b[1] == 0) {
+ if (fread(b, 1, 2, f) == 2 && b[0] == 0xFE && b[1] == 0xFF) {
+ return cmListFileLexer_BOM_UTF32BE;
+ }
+ } else if (b[0] == 0xFF && b[1] == 0xFE) {
+ fpos_t p;
+ fgetpos(f, &p);
+ if (fread(b, 1, 2, f) == 2 && b[0] == 0 && b[1] == 0) {
+ return cmListFileLexer_BOM_UTF32LE;
+ }
+ fsetpos(f, &p);
+ return cmListFileLexer_BOM_UTF16LE;
+ }
+ }
+ rewind(f);
+ return cmListFileLexer_BOM_None;
+}
+
+/*--------------------------------------------------------------------------*/
+int cmListFileLexer_SetFileName(cmListFileLexer* lexer, const char* name,
+ cmListFileLexer_BOM* bom)
+{
+ int result = 1;
+ cmListFileLexerDestroy(lexer);
+ if (name) {
+#ifdef _WIN32
+ wchar_t* wname = cmsysEncoding_DupToWide(name);
+ lexer->file = _wfopen(wname, L"rb");
+ free(wname);
+#else
+ lexer->file = fopen(name, "rb");
+#endif
+ if (lexer->file) {
+ if (bom) {
+ *bom = cmListFileLexer_ReadBOM(lexer->file);
+ }
+ } else {
+ result = 0;
+ }
+ }
+ cmListFileLexerInit(lexer);
+ return result;
+}
+
+/*--------------------------------------------------------------------------*/
+int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text)
+{
+ int result = 1;
+ cmListFileLexerDestroy(lexer);
+ if (text) {
+ int length = (int)strlen(text);
+ lexer->string_buffer = (char*)malloc(length + 1);
+ if (lexer->string_buffer) {
+ strcpy(lexer->string_buffer, text);
+ lexer->string_position = lexer->string_buffer;
+ lexer->string_left = length;
+ } else {
+ result = 0;
+ }
+ }
+ cmListFileLexerInit(lexer);
+ return result;
+}
+
+/*--------------------------------------------------------------------------*/
+cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
+{
+ if (!lexer->file) {
+ return 0;
+ }
+ if (cmListFileLexer_yylex(lexer->scanner, lexer)) {
+ return &lexer->token;
+ } else {
+ cmListFileLexer_SetFileName(lexer, 0, 0);
+ return 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer)
+{
+ if (lexer->file) {
+ return lexer->line;
+ } else {
+ return 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer)
+{
+ if (lexer->file) {
+ return lexer->column;
+ } else {
+ return 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer,
+ cmListFileLexer_Type type)
+{
+ (void)lexer;
+ switch (type) {
+ case cmListFileLexer_Token_None:
+ return "nothing";
+ case cmListFileLexer_Token_Space:
+ return "space";
+ case cmListFileLexer_Token_Newline:
+ return "newline";
+ case cmListFileLexer_Token_Identifier:
+ return "identifier";
+ case cmListFileLexer_Token_ParenLeft:
+ return "left paren";
+ case cmListFileLexer_Token_ParenRight:
+ return "right paren";
+ case cmListFileLexer_Token_ArgumentUnquoted:
+ return "unquoted argument";
+ case cmListFileLexer_Token_ArgumentQuoted:
+ return "quoted argument";
+ case cmListFileLexer_Token_ArgumentBracket:
+ return "bracket argument";
+ case cmListFileLexer_Token_CommentBracket:
+ return "bracket comment";
+ case cmListFileLexer_Token_BadCharacter:
+ return "bad character";
+ case cmListFileLexer_Token_BadBracket:
+ return "unterminated bracket";
+ case cmListFileLexer_Token_BadString:
+ return "unterminated string";
+ }
+ return "unknown token";
+}
diff --git a/Source/cmListFileLexer.h b/Source/cmListFileLexer.h
new file mode 100644
index 0000000..88300e1
--- /dev/null
+++ b/Source/cmListFileLexer.h
@@ -0,0 +1,73 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmListFileLexer_h
+#define cmListFileLexer_h
+
+typedef enum cmListFileLexer_Type_e {
+ cmListFileLexer_Token_None,
+ cmListFileLexer_Token_Space,
+ cmListFileLexer_Token_Newline,
+ cmListFileLexer_Token_Identifier,
+ cmListFileLexer_Token_ParenLeft,
+ cmListFileLexer_Token_ParenRight,
+ cmListFileLexer_Token_ArgumentUnquoted,
+ cmListFileLexer_Token_ArgumentQuoted,
+ cmListFileLexer_Token_ArgumentBracket,
+ cmListFileLexer_Token_CommentBracket,
+ cmListFileLexer_Token_BadCharacter,
+ cmListFileLexer_Token_BadBracket,
+ cmListFileLexer_Token_BadString
+} cmListFileLexer_Type;
+
+typedef struct cmListFileLexer_Token_s cmListFileLexer_Token;
+struct cmListFileLexer_Token_s
+{
+ cmListFileLexer_Type type;
+ char* text;
+ int length;
+ int line;
+ int column;
+};
+
+enum cmListFileLexer_BOM_e
+{
+ cmListFileLexer_BOM_None,
+ cmListFileLexer_BOM_UTF8,
+ cmListFileLexer_BOM_UTF16BE,
+ cmListFileLexer_BOM_UTF16LE,
+ cmListFileLexer_BOM_UTF32BE,
+ cmListFileLexer_BOM_UTF32LE
+};
+typedef enum cmListFileLexer_BOM_e cmListFileLexer_BOM;
+
+typedef struct cmListFileLexer_s cmListFileLexer;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+cmListFileLexer* cmListFileLexer_New();
+int cmListFileLexer_SetFileName(cmListFileLexer*, const char*,
+ cmListFileLexer_BOM* bom);
+int cmListFileLexer_SetString(cmListFileLexer*, const char*);
+cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer*);
+long cmListFileLexer_GetCurrentLine(cmListFileLexer*);
+long cmListFileLexer_GetCurrentColumn(cmListFileLexer*);
+const char* cmListFileLexer_GetTypeAsString(cmListFileLexer*,
+ cmListFileLexer_Type);
+void cmListFileLexer_Delete(cmListFileLexer*);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/Source/cmListFileLexer.in.l b/Source/cmListFileLexer.in.l
new file mode 100644
index 0000000..6d44814
--- /dev/null
+++ b/Source/cmListFileLexer.in.l
@@ -0,0 +1,572 @@
+%{
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex --prefix=cmListFileLexer_yy -ocmListFileLexer.c cmListFileLexer.in.l
+
+Modify cmListFileLexer.c:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmListFileLexer.c
+ - remove blank lines at end of file
+ - remove statement "yyscanner = NULL;" from cmListFileLexer_yylex_destroy
+ - remove all YY_BREAK lines occurring right after return statements
+ - remove unnecessary cast to (int) in yy_get_next_buffer
+
+*/
+
+#include "cmStandardLexer.h"
+#ifdef WIN32
+#include <cmsys/Encoding.h>
+#endif
+
+/* Setup the proper cmListFileLexer_yylex declaration. */
+#define YY_EXTRA_TYPE cmListFileLexer*
+#define YY_DECL int cmListFileLexer_yylex (yyscan_t yyscanner, cmListFileLexer* lexer)
+
+#include "cmListFileLexer.h"
+
+/*--------------------------------------------------------------------------*/
+struct cmListFileLexer_s
+{
+ cmListFileLexer_Token token;
+ yy_size_t bracket;
+ int comment;
+ int line;
+ int column;
+ int size;
+ FILE* file;
+ size_t cr;
+ char* string_buffer;
+ char* string_position;
+ int string_left;
+ yyscan_t scanner;
+};
+
+static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
+ int length);
+static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
+ int length);
+static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
+ size_t bufferSize);
+static void cmListFileLexerInit(cmListFileLexer* lexer);
+static void cmListFileLexerDestroy(cmListFileLexer* lexer);
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ { result = cmListFileLexerInput(cmListFileLexer_yyget_extra(yyscanner), buf, max_size); }
+
+/*--------------------------------------------------------------------------*/
+%}
+
+%option reentrant
+%option yylineno
+%option noyywrap
+%pointer
+%x STRING
+%x BRACKET
+%x BRACKETEND
+%x COMMENT
+
+MAKEVAR \$\([A-Za-z0-9_]*\)
+UNQUOTED ([^ \t\r\n\(\)#\\\"[=]|\\.)
+LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t[=])*\"
+
+%%
+
+<INITIAL,COMMENT>\n {
+ lexer->token.type = cmListFileLexer_Token_Newline;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ ++lexer->line;
+ lexer->column = 1;
+ BEGIN(INITIAL);
+ return 1;
+}
+
+#?\[=*\[\n? {
+ const char* bracket = yytext;
+ lexer->comment = yytext[0] == '#';
+ if (lexer->comment) {
+ lexer->token.type = cmListFileLexer_Token_CommentBracket;
+ bracket += 1;
+ } else {
+ lexer->token.type = cmListFileLexer_Token_ArgumentBracket;
+ }
+ cmListFileLexerSetToken(lexer, "", 0);
+ lexer->bracket = strchr(bracket+1, '[') - bracket;
+ if (yytext[yyleng-1] == '\n') {
+ ++lexer->line;
+ lexer->column = 1;
+ } else {
+ lexer->column += yyleng;
+ }
+ BEGIN(BRACKET);
+}
+
+# {
+ lexer->column += yyleng;
+ BEGIN(COMMENT);
+}
+
+<COMMENT>.* {
+ lexer->column += yyleng;
+}
+
+\( {
+ lexer->token.type = cmListFileLexer_Token_ParenLeft;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+\) {
+ lexer->token.type = cmListFileLexer_Token_ParenRight;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+[A-Za-z_][A-Za-z0-9_]* {
+ lexer->token.type = cmListFileLexer_Token_Identifier;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+<BRACKET>\]=* {
+ /* Handle ]]====]=======]*/
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ if (yyleng == lexer->bracket) {
+ BEGIN(BRACKETEND);
+ }
+}
+
+<BRACKETEND>\] {
+ lexer->column += yyleng;
+ /* Erase the partial bracket from the token. */
+ lexer->token.length -= lexer->bracket;
+ lexer->token.text[lexer->token.length] = 0;
+ BEGIN(INITIAL);
+ return 1;
+}
+
+<BRACKET>([^]\n])+ {
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+}
+
+<BRACKET,BRACKETEND>\n {
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ ++lexer->line;
+ lexer->column = 1;
+ BEGIN(BRACKET);
+}
+
+<BRACKET,BRACKETEND>. {
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ BEGIN(BRACKET);
+}
+
+<BRACKET,BRACKETEND><<EOF>> {
+ lexer->token.type = cmListFileLexer_Token_BadBracket;
+ BEGIN(INITIAL);
+ return 1;
+}
+
+({UNQUOTED}|=|\[=*{UNQUOTED})({UNQUOTED}|[[=])* {
+ lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+({MAKEVAR}|{UNQUOTED}|=|\[=*{LEGACY})({LEGACY}|[[=])* {
+ lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+\[ {
+ lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+\" {
+ lexer->token.type = cmListFileLexer_Token_ArgumentQuoted;
+ cmListFileLexerSetToken(lexer, "", 0);
+ lexer->column += yyleng;
+ BEGIN(STRING);
+}
+
+<STRING>([^\\\n\"]|\\.)+ {
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+}
+
+<STRING>\\\n {
+ /* Continuation: text is not part of string */
+ ++lexer->line;
+ lexer->column = 1;
+}
+
+<STRING>\n {
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ ++lexer->line;
+ lexer->column = 1;
+}
+
+<STRING>\" {
+ lexer->column += yyleng;
+ BEGIN(INITIAL);
+ return 1;
+}
+
+<STRING>. {
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+}
+
+<STRING><<EOF>> {
+ lexer->token.type = cmListFileLexer_Token_BadString;
+ BEGIN(INITIAL);
+ return 1;
+}
+
+[ \t\r]+ {
+ lexer->token.type = cmListFileLexer_Token_Space;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+. {
+ lexer->token.type = cmListFileLexer_Token_BadCharacter;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+<<EOF>> {
+ lexer->token.type = cmListFileLexer_Token_None;
+ cmListFileLexerSetToken(lexer, 0, 0);
+ return 0;
+}
+
+%%
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
+ int length)
+{
+ /* Set the token line and column number. */
+ lexer->token.line = lexer->line;
+ lexer->token.column = lexer->column;
+
+ /* Use the same buffer if possible. */
+ if (lexer->token.text) {
+ if (text && length < lexer->size) {
+ strcpy(lexer->token.text, text);
+ lexer->token.length = length;
+ return;
+ }
+ free(lexer->token.text);
+ lexer->token.text = 0;
+ lexer->size = 0;
+ }
+
+ /* Need to extend the buffer. */
+ if (text) {
+ lexer->token.text = strdup(text);
+ lexer->token.length = length;
+ lexer->size = length + 1;
+ } else {
+ lexer->token.length = 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
+ int length)
+{
+ char* temp;
+ int newSize;
+
+ /* If the appended text will fit in the buffer, do not reallocate. */
+ newSize = lexer->token.length + length + 1;
+ if (lexer->token.text && newSize <= lexer->size) {
+ strcpy(lexer->token.text + lexer->token.length, text);
+ lexer->token.length += length;
+ return;
+ }
+
+ /* We need to extend the buffer. */
+ temp = malloc(newSize);
+ if (lexer->token.text) {
+ memcpy(temp, lexer->token.text, lexer->token.length);
+ free(lexer->token.text);
+ }
+ memcpy(temp + lexer->token.length, text, length);
+ temp[lexer->token.length + length] = 0;
+ lexer->token.text = temp;
+ lexer->token.length += length;
+ lexer->size = newSize;
+}
+
+/*--------------------------------------------------------------------------*/
+static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
+ size_t bufferSize)
+{
+ if (lexer) {
+ if (lexer->file) {
+ /* Convert CRLF -> LF explicitly. The C FILE "t"ext mode
+ does not convert newlines on all platforms. Move any
+ trailing CR to the start of the buffer for the next read. */
+ size_t cr = lexer->cr;
+ size_t n;
+ buffer[0] = '\r';
+ n = fread(buffer + cr, 1, bufferSize - cr, lexer->file);
+ if (n) {
+ char* o = buffer;
+ const char* i = buffer;
+ const char* e;
+ n += cr;
+ cr = (buffer[n - 1] == '\r') ? 1 : 0;
+ e = buffer + n - cr;
+ while (i != e) {
+ if (i[0] == '\r' && i[1] == '\n') {
+ ++i;
+ }
+ *o++ = *i++;
+ }
+ n = o - buffer;
+ } else {
+ n = cr;
+ cr = 0;
+ }
+ lexer->cr = cr;
+ return n;
+ } else if (lexer->string_left) {
+ int length = lexer->string_left;
+ if ((int)bufferSize < length) {
+ length = (int)bufferSize;
+ }
+ memcpy(buffer, lexer->string_position, length);
+ lexer->string_position += length;
+ lexer->string_left -= length;
+ return length;
+ }
+ }
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerInit(cmListFileLexer* lexer)
+{
+ if (lexer->file || lexer->string_buffer) {
+ cmListFileLexer_yylex_init(&lexer->scanner);
+ cmListFileLexer_yyset_extra(lexer, lexer->scanner);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerDestroy(cmListFileLexer* lexer)
+{
+ cmListFileLexerSetToken(lexer, 0, 0);
+ if (lexer->file || lexer->string_buffer) {
+ cmListFileLexer_yylex_destroy(lexer->scanner);
+ if (lexer->file) {
+ fclose(lexer->file);
+ lexer->file = 0;
+ }
+ if (lexer->string_buffer) {
+ free(lexer->string_buffer);
+ lexer->string_buffer = 0;
+ lexer->string_left = 0;
+ lexer->string_position = 0;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+cmListFileLexer* cmListFileLexer_New()
+{
+ cmListFileLexer* lexer = (cmListFileLexer*)malloc(sizeof(cmListFileLexer));
+ if (!lexer) {
+ return 0;
+ }
+ memset(lexer, 0, sizeof(*lexer));
+ lexer->line = 1;
+ lexer->column = 1;
+ return lexer;
+}
+
+/*--------------------------------------------------------------------------*/
+void cmListFileLexer_Delete(cmListFileLexer* lexer)
+{
+ cmListFileLexer_SetFileName(lexer, 0, 0);
+ free(lexer);
+}
+
+/*--------------------------------------------------------------------------*/
+static cmListFileLexer_BOM cmListFileLexer_ReadBOM(FILE* f)
+{
+ unsigned char b[2];
+ if (fread(b, 1, 2, f) == 2) {
+ if (b[0] == 0xEF && b[1] == 0xBB) {
+ if (fread(b, 1, 1, f) == 1 && b[0] == 0xBF) {
+ return cmListFileLexer_BOM_UTF8;
+ }
+ } else if (b[0] == 0xFE && b[1] == 0xFF) {
+ /* UTF-16 BE */
+ return cmListFileLexer_BOM_UTF16BE;
+ } else if (b[0] == 0 && b[1] == 0) {
+ if (fread(b, 1, 2, f) == 2 && b[0] == 0xFE && b[1] == 0xFF) {
+ return cmListFileLexer_BOM_UTF32BE;
+ }
+ } else if (b[0] == 0xFF && b[1] == 0xFE) {
+ fpos_t p;
+ fgetpos(f, &p);
+ if (fread(b, 1, 2, f) == 2 && b[0] == 0 && b[1] == 0) {
+ return cmListFileLexer_BOM_UTF32LE;
+ }
+ fsetpos(f, &p);
+ return cmListFileLexer_BOM_UTF16LE;
+ }
+ }
+ rewind(f);
+ return cmListFileLexer_BOM_None;
+}
+
+/*--------------------------------------------------------------------------*/
+int cmListFileLexer_SetFileName(cmListFileLexer* lexer, const char* name,
+ cmListFileLexer_BOM* bom)
+{
+ int result = 1;
+ cmListFileLexerDestroy(lexer);
+ if (name) {
+#ifdef _WIN32
+ wchar_t* wname = cmsysEncoding_DupToWide(name);
+ lexer->file = _wfopen(wname, L"rb");
+ free(wname);
+#else
+ lexer->file = fopen(name, "rb");
+#endif
+ if (lexer->file) {
+ if (bom) {
+ *bom = cmListFileLexer_ReadBOM(lexer->file);
+ }
+ } else {
+ result = 0;
+ }
+ }
+ cmListFileLexerInit(lexer);
+ return result;
+}
+
+/*--------------------------------------------------------------------------*/
+int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text)
+{
+ int result = 1;
+ cmListFileLexerDestroy(lexer);
+ if (text) {
+ int length = (int)strlen(text);
+ lexer->string_buffer = (char*)malloc(length + 1);
+ if (lexer->string_buffer) {
+ strcpy(lexer->string_buffer, text);
+ lexer->string_position = lexer->string_buffer;
+ lexer->string_left = length;
+ } else {
+ result = 0;
+ }
+ }
+ cmListFileLexerInit(lexer);
+ return result;
+}
+
+/*--------------------------------------------------------------------------*/
+cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
+{
+ if (!lexer->file) {
+ return 0;
+ }
+ if (cmListFileLexer_yylex(lexer->scanner, lexer)) {
+ return &lexer->token;
+ } else {
+ cmListFileLexer_SetFileName(lexer, 0, 0);
+ return 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer)
+{
+ if (lexer->file) {
+ return lexer->line;
+ } else {
+ return 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer)
+{
+ if (lexer->file) {
+ return lexer->column;
+ } else {
+ return 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer,
+ cmListFileLexer_Type type)
+{
+ (void)lexer;
+ switch (type) {
+ case cmListFileLexer_Token_None:
+ return "nothing";
+ case cmListFileLexer_Token_Space:
+ return "space";
+ case cmListFileLexer_Token_Newline:
+ return "newline";
+ case cmListFileLexer_Token_Identifier:
+ return "identifier";
+ case cmListFileLexer_Token_ParenLeft:
+ return "left paren";
+ case cmListFileLexer_Token_ParenRight:
+ return "right paren";
+ case cmListFileLexer_Token_ArgumentUnquoted:
+ return "unquoted argument";
+ case cmListFileLexer_Token_ArgumentQuoted:
+ return "quoted argument";
+ case cmListFileLexer_Token_ArgumentBracket:
+ return "bracket argument";
+ case cmListFileLexer_Token_CommentBracket:
+ return "bracket comment";
+ case cmListFileLexer_Token_BadCharacter:
+ return "bad character";
+ case cmListFileLexer_Token_BadBracket:
+ return "unterminated bracket";
+ case cmListFileLexer_Token_BadString:
+ return "unterminated string";
+ }
+ return "unknown token";
+}
diff --git a/Source/cmLoadCacheCommand.cxx b/Source/cmLoadCacheCommand.cxx
new file mode 100644
index 0000000..85188d1
--- /dev/null
+++ b/Source/cmLoadCacheCommand.cxx
@@ -0,0 +1,166 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmLoadCacheCommand.h"
+
+#include <cmsys/FStream.hxx>
+#include <cmsys/RegularExpression.hxx>
+
+// cmLoadCacheCommand
+bool cmLoadCacheCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with wrong number of arguments.");
+ }
+
+ if (args.size() >= 2 && args[1] == "READ_WITH_PREFIX") {
+ return this->ReadWithPrefix(args);
+ }
+
+ // Cache entries to be excluded from the import list.
+ // If this set is empty, all cache entries are brought in
+ // and they can not be overridden.
+ bool excludeFiles = false;
+ unsigned int i;
+ std::set<std::string> excludes;
+
+ for (i = 0; i < args.size(); i++) {
+ if (excludeFiles) {
+ excludes.insert(args[i]);
+ }
+ if (args[i] == "EXCLUDE") {
+ excludeFiles = true;
+ }
+ if (excludeFiles && (args[i] == "INCLUDE_INTERNALS")) {
+ break;
+ }
+ }
+
+ // Internal cache entries to be imported.
+ // If this set is empty, no internal cache entries are
+ // brought in.
+ bool includeFiles = false;
+ std::set<std::string> includes;
+
+ for (i = 0; i < args.size(); i++) {
+ if (includeFiles) {
+ includes.insert(args[i]);
+ }
+ if (args[i] == "INCLUDE_INTERNALS") {
+ includeFiles = true;
+ }
+ if (includeFiles && (args[i] == "EXCLUDE")) {
+ break;
+ }
+ }
+
+ // Loop over each build directory listed in the arguments. Each
+ // directory has a cache file.
+ for (i = 0; i < args.size(); i++) {
+ if ((args[i] == "EXCLUDE") || (args[i] == "INCLUDE_INTERNALS")) {
+ break;
+ }
+ this->Makefile->GetCMakeInstance()->LoadCache(args[i], false, excludes,
+ includes);
+ }
+
+ return true;
+}
+
+bool cmLoadCacheCommand::ReadWithPrefix(std::vector<std::string> const& args)
+{
+ // Make sure we have a prefix.
+ if (args.size() < 3) {
+ this->SetError("READ_WITH_PREFIX form must specify a prefix.");
+ return false;
+ }
+
+ // Make sure the cache file exists.
+ std::string cacheFile = args[0] + "/CMakeCache.txt";
+ if (!cmSystemTools::FileExists(cacheFile.c_str())) {
+ std::string e = "Cannot load cache file from " + cacheFile;
+ this->SetError(e);
+ return false;
+ }
+
+ // Prepare the table of variables to read.
+ this->Prefix = args[2];
+ this->VariablesToRead.insert(args.begin() + 3, args.end());
+
+ // Read the cache file.
+ cmsys::ifstream fin(cacheFile.c_str());
+
+ // This is a big hack read loop to overcome a buggy ifstream
+ // implementation on HP-UX. This should work on all platforms even
+ // for small buffer sizes.
+ const int bufferSize = 4096;
+ char buffer[bufferSize];
+ std::string line;
+ while (fin) {
+ // Read a block of the file.
+ fin.read(buffer, bufferSize);
+ if (fin.gcount()) {
+ // Parse for newlines directly.
+ const char* i = buffer;
+ const char* end = buffer + fin.gcount();
+ while (i != end) {
+ const char* begin = i;
+ while (i != end && *i != '\n') {
+ ++i;
+ }
+ if (i == begin || *(i - 1) != '\r') {
+ // Include this portion of the line.
+ line += std::string(begin, i - begin);
+ } else {
+ // Include this portion of the line.
+ // Don't include the \r in a \r\n pair.
+ line += std::string(begin, i - 1 - begin);
+ }
+ if (i != end) {
+ // Completed a line.
+ this->CheckLine(line.c_str());
+ line = "";
+
+ // Skip the newline character.
+ ++i;
+ }
+ }
+ }
+ }
+ if (!line.empty()) {
+ // Partial last line.
+ this->CheckLine(line.c_str());
+ }
+
+ return true;
+}
+
+void cmLoadCacheCommand::CheckLine(const char* line)
+{
+ // Check one line of the cache file.
+ std::string var;
+ std::string value;
+ cmState::CacheEntryType type = cmState::UNINITIALIZED;
+ if (cmake::ParseCacheEntry(line, var, value, type)) {
+ // Found a real entry. See if this one was requested.
+ if (this->VariablesToRead.find(var) != this->VariablesToRead.end()) {
+ // This was requested. Set this variable locally with the given
+ // prefix.
+ var = this->Prefix + var;
+ if (!value.empty()) {
+ this->Makefile->AddDefinition(var, value.c_str());
+ } else {
+ this->Makefile->RemoveDefinition(var);
+ }
+ }
+ }
+}
diff --git a/Source/cmLoadCacheCommand.h b/Source/cmLoadCacheCommand.h
new file mode 100644
index 0000000..0755809
--- /dev/null
+++ b/Source/cmLoadCacheCommand.h
@@ -0,0 +1,52 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLoadCacheCommand_h
+#define cmLoadCacheCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmLoadCacheCommand
+ * \brief load a cache file
+ *
+ * cmLoadCacheCommand loads the non internal values of a cache file
+ */
+class cmLoadCacheCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmLoadCacheCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "load_cache"; }
+
+ cmTypeMacro(cmLoadCacheCommand, cmCommand);
+
+protected:
+ std::set<std::string> VariablesToRead;
+ std::string Prefix;
+
+ bool ReadWithPrefix(std::vector<std::string> const& args);
+ void CheckLine(const char* line);
+};
+
+#endif
diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx
new file mode 100644
index 0000000..ddf6ce6
--- /dev/null
+++ b/Source/cmLoadCommandCommand.cxx
@@ -0,0 +1,265 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmLoadCommandCommand.h"
+
+#include "cmCPluginAPI.cxx"
+#include "cmCPluginAPI.h"
+#include "cmDynamicLoader.h"
+
+#include <cmsys/DynamicLoader.hxx>
+
+#include <stdlib.h>
+
+#ifdef __QNX__
+#include <malloc.h> /* for malloc/free on QNX */
+#endif
+
+#include <signal.h>
+extern "C" void TrapsForSignalsCFunction(int sig);
+
+// a class for loadabple commands
+class cmLoadedCommand : public cmCommand
+{
+public:
+ cmLoadedCommand()
+ {
+ memset(&this->info, 0, sizeof(this->info));
+ this->info.CAPI = &cmStaticCAPI;
+ }
+
+ ///! clean up any memory allocated by the plugin
+ ~cmLoadedCommand() CM_OVERRIDE;
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmLoadedCommand* newC = new cmLoadedCommand;
+ // we must copy when we clone
+ memcpy(&newC->info, &this->info, sizeof(info));
+ return newC;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&) CM_OVERRIDE;
+
+ /**
+ * This is called at the end after all the information
+ * specified by the command is accumulated. Most commands do
+ * not implement this method. At this point, reading and
+ * writing to the cache can be done.
+ */
+ void FinalPass() CM_OVERRIDE;
+ bool HasFinalPass() const CM_OVERRIDE
+ {
+ return this->info.FinalPass ? true : false;
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return info.Name; }
+
+ static const char* LastName;
+ static void TrapsForSignals(int sig)
+ {
+ fprintf(stderr, "CMake loaded command %s crashed with signal: %d.\n",
+ cmLoadedCommand::LastName, sig);
+ }
+ static void InstallSignalHandlers(const char* name, int remove = 0)
+ {
+ cmLoadedCommand::LastName = name;
+ if (!name) {
+ cmLoadedCommand::LastName = "????";
+ }
+
+ if (!remove) {
+ signal(SIGSEGV, TrapsForSignalsCFunction);
+#ifdef SIGBUS
+ signal(SIGBUS, TrapsForSignalsCFunction);
+#endif
+ signal(SIGILL, TrapsForSignalsCFunction);
+ } else {
+ signal(SIGSEGV, CM_NULLPTR);
+#ifdef SIGBUS
+ signal(SIGBUS, CM_NULLPTR);
+#endif
+ signal(SIGILL, CM_NULLPTR);
+ }
+ }
+
+ cmTypeMacro(cmLoadedCommand, cmCommand);
+
+ cmLoadedCommandInfo info;
+};
+
+extern "C" void TrapsForSignalsCFunction(int sig)
+{
+ cmLoadedCommand::TrapsForSignals(sig);
+}
+
+const char* cmLoadedCommand::LastName = CM_NULLPTR;
+
+bool cmLoadedCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (!info.InitialPass) {
+ return true;
+ }
+
+ // clear the error string
+ if (this->info.Error) {
+ free(this->info.Error);
+ }
+
+ // create argc and argv and then invoke the command
+ int argc = static_cast<int>(args.size());
+ char** argv = CM_NULLPTR;
+ if (argc) {
+ argv = (char**)malloc(argc * sizeof(char*));
+ }
+ int i;
+ for (i = 0; i < argc; ++i) {
+ argv[i] = strdup(args[i].c_str());
+ }
+ cmLoadedCommand::InstallSignalHandlers(info.Name);
+ int result =
+ info.InitialPass((void*)&info, (void*)this->Makefile, argc, argv);
+ cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
+ cmFreeArguments(argc, argv);
+
+ if (result) {
+ return true;
+ }
+
+ /* Initial Pass must have failed so set the error string */
+ if (this->info.Error) {
+ this->SetError(this->info.Error);
+ }
+ return false;
+}
+
+void cmLoadedCommand::FinalPass()
+{
+ if (this->info.FinalPass) {
+ cmLoadedCommand::InstallSignalHandlers(info.Name);
+ this->info.FinalPass((void*)&this->info, (void*)this->Makefile);
+ cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
+ }
+}
+
+cmLoadedCommand::~cmLoadedCommand()
+{
+ if (this->info.Destructor) {
+ cmLoadedCommand::InstallSignalHandlers(info.Name);
+ this->info.Destructor((void*)&this->info);
+ cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
+ }
+ if (this->info.Error) {
+ free(this->info.Error);
+ }
+}
+
+// cmLoadCommandCommand
+bool cmLoadCommandCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (this->Disallowed(
+ cmPolicies::CMP0031,
+ "The load_command command should not be called; see CMP0031.")) {
+ return true;
+ }
+ if (args.size() < 1) {
+ return true;
+ }
+
+ // Construct a variable to report what file was loaded, if any.
+ // Start by removing the definition in case of failure.
+ std::string reportVar = "CMAKE_LOADED_COMMAND_";
+ reportVar += args[0];
+ this->Makefile->RemoveDefinition(reportVar);
+
+ // the file must exist
+ std::string moduleName =
+ this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_PREFIX");
+ moduleName += "cm" + args[0];
+ moduleName +=
+ this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_SUFFIX");
+
+ // search for the file
+ std::vector<std::string> path;
+ for (unsigned int j = 1; j < args.size(); j++) {
+ // expand variables
+ std::string exp = args[j];
+ cmSystemTools::ExpandRegistryValues(exp);
+
+ // Glob the entry in case of wildcards.
+ cmSystemTools::GlobDirs(exp, path);
+ }
+
+ // Try to find the program.
+ std::string fullPath = cmSystemTools::FindFile(moduleName.c_str(), path);
+ if (fullPath == "") {
+ std::ostringstream e;
+ e << "Attempt to load command failed from file \"" << moduleName << "\"";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // try loading the shared library / dll
+ cmsys::DynamicLoader::LibraryHandle lib =
+ cmDynamicLoader::OpenLibrary(fullPath.c_str());
+ if (!lib) {
+ std::string err = "Attempt to load the library ";
+ err += fullPath + " failed.";
+ const char* error = cmsys::DynamicLoader::LastError();
+ if (error) {
+ err += " Additional error info is:\n";
+ err += error;
+ }
+ this->SetError(err);
+ return false;
+ }
+
+ // Report what file was loaded for this command.
+ this->Makefile->AddDefinition(reportVar, fullPath.c_str());
+
+ // find the init function
+ std::string initFuncName = args[0] + "Init";
+ CM_INIT_FUNCTION initFunction =
+ (CM_INIT_FUNCTION)cmsys::DynamicLoader::GetSymbolAddress(
+ lib, initFuncName.c_str());
+ if (!initFunction) {
+ initFuncName = "_";
+ initFuncName += args[0];
+ initFuncName += "Init";
+ initFunction = (CM_INIT_FUNCTION)(
+ cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName.c_str()));
+ }
+ // if the symbol is found call it to set the name on the
+ // function blocker
+ if (initFunction) {
+ // create a function blocker and set it up
+ cmLoadedCommand* f = new cmLoadedCommand();
+ (*initFunction)(&f->info);
+ this->Makefile->GetState()->AddCommand(f);
+ return true;
+ }
+ this->SetError("Attempt to load command failed. "
+ "No init function found.");
+ return false;
+}
diff --git a/Source/cmLoadCommandCommand.h b/Source/cmLoadCommandCommand.h
new file mode 100644
index 0000000..6552845
--- /dev/null
+++ b/Source/cmLoadCommandCommand.h
@@ -0,0 +1,27 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLoadCommandCommand_h
+#define cmLoadCommandCommand_h
+
+#include "cmCommand.h"
+
+class cmLoadCommandCommand : public cmCommand
+{
+public:
+ cmCommand* Clone() CM_OVERRIDE { return new cmLoadCommandCommand; }
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+ std::string GetName() const CM_OVERRIDE { return "load_command"; }
+ cmTypeMacro(cmLoadCommandCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx
new file mode 100644
index 0000000..5502296
--- /dev/null
+++ b/Source/cmLocalCommonGenerator.cxx
@@ -0,0 +1,84 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmLocalCommonGenerator.h"
+
+#include "cmMakefile.h"
+
+cmLocalCommonGenerator::cmLocalCommonGenerator(
+ cmGlobalGenerator* gg, cmMakefile* mf, cmOutputConverter::RelativeRoot wd)
+ : cmLocalGenerator(gg, mf)
+ , WorkingDirectory(wd)
+{
+}
+
+cmLocalCommonGenerator::~cmLocalCommonGenerator()
+{
+}
+
+void cmLocalCommonGenerator::SetConfigName()
+{
+ // Store the configuration name that will be generated.
+ if (const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) {
+ // Use the build type given by the user.
+ this->ConfigName = config;
+ } else {
+ // No configuration type given.
+ this->ConfigName = "";
+ }
+}
+
+std::string cmLocalCommonGenerator::GetTargetFortranFlags(
+ cmGeneratorTarget const* target, std::string const& config)
+{
+ std::string flags;
+
+ // Enable module output if necessary.
+ if (const char* modout_flag =
+ this->Makefile->GetDefinition("CMAKE_Fortran_MODOUT_FLAG")) {
+ this->AppendFlags(flags, modout_flag);
+ }
+
+ // Add a module output directory flag if necessary.
+ std::string mod_dir = target->GetFortranModuleDirectory();
+ if (!mod_dir.empty()) {
+ mod_dir =
+ this->Convert(mod_dir, this->WorkingDirectory, cmOutputConverter::SHELL);
+ } else {
+ mod_dir =
+ this->Makefile->GetSafeDefinition("CMAKE_Fortran_MODDIR_DEFAULT");
+ }
+ if (!mod_dir.empty()) {
+ const char* moddir_flag =
+ this->Makefile->GetRequiredDefinition("CMAKE_Fortran_MODDIR_FLAG");
+ std::string modflag = moddir_flag;
+ modflag += mod_dir;
+ this->AppendFlags(flags, modflag);
+ }
+
+ // If there is a separate module path flag then duplicate the
+ // include path with it. This compiler does not search the include
+ // path for modules.
+ if (const char* modpath_flag =
+ this->Makefile->GetDefinition("CMAKE_Fortran_MODPATH_FLAG")) {
+ std::vector<std::string> includes;
+ this->GetIncludeDirectories(includes, target, "C", config);
+ for (std::vector<std::string>::const_iterator idi = includes.begin();
+ idi != includes.end(); ++idi) {
+ std::string flg = modpath_flag;
+ flg +=
+ this->Convert(*idi, cmOutputConverter::NONE, cmOutputConverter::SHELL);
+ this->AppendFlags(flags, flg);
+ }
+ }
+
+ return flags;
+}
diff --git a/Source/cmLocalCommonGenerator.h b/Source/cmLocalCommonGenerator.h
new file mode 100644
index 0000000..0a8753d
--- /dev/null
+++ b/Source/cmLocalCommonGenerator.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLocalCommonGenerator_h
+#define cmLocalCommonGenerator_h
+
+#include "cmLocalGenerator.h"
+
+class cmCommonTargetGenerator;
+
+/** \class cmLocalCommonGenerator
+ * \brief Common infrastructure for Makefile and Ninja local generators.
+ */
+class cmLocalCommonGenerator : public cmLocalGenerator
+{
+public:
+ cmLocalCommonGenerator(cmGlobalGenerator* gg, cmMakefile* mf,
+ cmOutputConverter::RelativeRoot wd);
+ ~cmLocalCommonGenerator() CM_OVERRIDE;
+
+ std::string const& GetConfigName() { return this->ConfigName; }
+
+ cmOutputConverter::RelativeRoot GetWorkingDirectory() const
+ {
+ return this->WorkingDirectory;
+ }
+
+ std::string GetTargetFortranFlags(cmGeneratorTarget const* target,
+ std::string const& config) CM_OVERRIDE;
+
+protected:
+ cmOutputConverter::RelativeRoot WorkingDirectory;
+
+ void SetConfigName();
+ std::string ConfigName;
+
+ friend class cmCommonTargetGenerator;
+};
+
+#endif
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
new file mode 100644
index 0000000..ff767e6
--- /dev/null
+++ b/Source/cmLocalGenerator.cxx
@@ -0,0 +1,2803 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmLocalGenerator.h"
+
+#include "cmAlgorithms.h"
+#include "cmComputeLinkInformation.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpressionEvaluationFile.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallFilesGenerator.h"
+#include "cmInstallGenerator.h"
+#include "cmInstallScriptGenerator.h"
+#include "cmInstallTargetGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmTest.h"
+#include "cmTestGenerator.h"
+#include "cmVersion.h"
+#include "cmake.h"
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#define CM_LG_ENCODE_OBJECT_NAMES
+#include <cmsys/MD5.h>
+#endif
+
+#include <ctype.h> // for isalpha
+
+#include <assert.h>
+
+#if defined(__HAIKU__)
+#include <FindDirectory.h>
+#include <StorageDefs.h>
+#endif
+
+cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
+ : cmOutputConverter(makefile->GetStateSnapshot())
+ , StateSnapshot(makefile->GetStateSnapshot())
+ , DirectoryBacktrace(makefile->GetBacktrace())
+{
+ this->GlobalGenerator = gg;
+
+ this->Makefile = makefile;
+
+ this->AliasTargets = makefile->GetAliasTargets();
+
+ this->EmitUniversalBinaryFlags = true;
+ this->BackwardsCompatibility = 0;
+ this->BackwardsCompatibilityFinal = false;
+
+ this->ComputeObjectMaxPath();
+}
+
+cmLocalGenerator::~cmLocalGenerator()
+{
+ cmDeleteAll(this->GeneratorTargets);
+ cmDeleteAll(this->OwnedImportedGeneratorTargets);
+}
+
+void cmLocalGenerator::IssueMessage(cmake::MessageType t,
+ std::string const& text) const
+{
+ this->GetCMakeInstance()->IssueMessage(t, text, this->DirectoryBacktrace);
+}
+
+void cmLocalGenerator::ComputeObjectMaxPath()
+{
+// Choose a maximum object file name length.
+#if defined(_WIN32) || defined(__CYGWIN__)
+ this->ObjectPathMax = 250;
+#else
+ this->ObjectPathMax = 1000;
+#endif
+ const char* plen = this->Makefile->GetDefinition("CMAKE_OBJECT_PATH_MAX");
+ if (plen && *plen) {
+ unsigned int pmax;
+ if (sscanf(plen, "%u", &pmax) == 1) {
+ if (pmax >= 128) {
+ this->ObjectPathMax = pmax;
+ } else {
+ std::ostringstream w;
+ w << "CMAKE_OBJECT_PATH_MAX is set to " << pmax
+ << ", which is less than the minimum of 128. "
+ << "The value will be ignored.";
+ this->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ }
+ } else {
+ std::ostringstream w;
+ w << "CMAKE_OBJECT_PATH_MAX is set to \"" << plen
+ << "\", which fails to parse as a positive integer. "
+ << "The value will be ignored.";
+ this->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ }
+ }
+ this->ObjectMaxPathViolations.clear();
+}
+
+void cmLocalGenerator::TraceDependencies()
+{
+ std::vector<std::string> configs;
+ this->Makefile->GetConfigurations(configs);
+ if (configs.empty()) {
+ configs.push_back("");
+ }
+ for (std::vector<std::string>::const_iterator ci = configs.begin();
+ ci != configs.end(); ++ci) {
+ this->GlobalGenerator->CreateEvaluationSourceFiles(*ci);
+ }
+ // Generate the rule files for each target.
+ std::vector<cmGeneratorTarget*> targets = this->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
+ t != targets.end(); ++t) {
+ if ((*t)->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ (*t)->TraceDependencies();
+ }
+}
+
+void cmLocalGenerator::GenerateTestFiles()
+{
+ if (!this->Makefile->IsOn("CMAKE_TESTING_ENABLED")) {
+ return;
+ }
+
+ // Compute the set of configurations.
+ std::vector<std::string> configurationTypes;
+ const std::string& config =
+ this->Makefile->GetConfigurations(configurationTypes, false);
+
+ std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary();
+ file += "/";
+ file += "CTestTestfile.cmake";
+
+ cmGeneratedFileStream fout(file.c_str());
+ fout.SetCopyIfDifferent(true);
+
+ fout << "# CMake generated Testfile for " << std::endl
+ << "# Source directory: "
+ << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl
+ << "# Build directory: "
+ << this->StateSnapshot.GetDirectory().GetCurrentBinary() << std::endl
+ << "# " << std::endl
+ << "# This file includes the relevant testing commands "
+ << "required for " << std::endl
+ << "# testing this directory and lists subdirectories to "
+ << "be tested as well." << std::endl;
+
+ const char* testIncludeFile =
+ this->Makefile->GetProperty("TEST_INCLUDE_FILE");
+ if (testIncludeFile) {
+ fout << "include(\"" << testIncludeFile << "\")" << std::endl;
+ }
+
+ // Ask each test generator to write its code.
+ std::vector<cmTestGenerator*> const& testers =
+ this->Makefile->GetTestGenerators();
+ for (std::vector<cmTestGenerator*>::const_iterator gi = testers.begin();
+ gi != testers.end(); ++gi) {
+ (*gi)->Compute(this);
+ (*gi)->Generate(fout, config, configurationTypes);
+ }
+ size_t i;
+ std::vector<cmState::Snapshot> children =
+ this->Makefile->GetStateSnapshot().GetChildren();
+ for (i = 0; i < children.size(); ++i) {
+ // TODO: Use add_subdirectory instead?
+ fout << "subdirs(";
+ std::string outP = children[i].GetDirectory().GetCurrentBinary();
+ fout << this->Convert(outP, START_OUTPUT);
+ fout << ")" << std::endl;
+ }
+}
+
+void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
+{
+ std::vector<cmGeneratorExpressionEvaluationFile*> ef =
+ this->Makefile->GetEvaluationFiles();
+ for (std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator li =
+ ef.begin();
+ li != ef.end(); ++li) {
+ (*li)->CreateOutputFile(this, config);
+ }
+}
+
+void cmLocalGenerator::ProcessEvaluationFiles(
+ std::vector<std::string>& generatedFiles)
+{
+ std::vector<cmGeneratorExpressionEvaluationFile*> ef =
+ this->Makefile->GetEvaluationFiles();
+ for (std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator li =
+ ef.begin();
+ li != ef.end(); ++li) {
+ (*li)->Generate(this);
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return;
+ }
+ std::vector<std::string> files = (*li)->GetFiles();
+ std::sort(files.begin(), files.end());
+
+ std::vector<std::string> intersection;
+ std::set_intersection(files.begin(), files.end(), generatedFiles.begin(),
+ generatedFiles.end(),
+ std::back_inserter(intersection));
+ if (!intersection.empty()) {
+ cmSystemTools::Error("Files to be generated by multiple different "
+ "commands: ",
+ cmWrap('"', intersection, '"', " ").c_str());
+ 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());
+ }
+}
+
+void cmLocalGenerator::GenerateInstallRules()
+{
+ // Compute the install prefix.
+ const char* prefix = this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ std::string prefix_win32;
+ if (!prefix) {
+ if (!cmSystemTools::GetEnv("SystemDrive", prefix_win32)) {
+ prefix_win32 = "C:";
+ }
+ const char* project_name = this->Makefile->GetDefinition("PROJECT_NAME");
+ if (project_name && project_name[0]) {
+ prefix_win32 += "/Program Files/";
+ prefix_win32 += project_name;
+ } else {
+ prefix_win32 += "/InstalledCMakeProject";
+ }
+ prefix = prefix_win32.c_str();
+ }
+#elif defined(__HAIKU__)
+ char dir[B_PATH_NAME_LENGTH];
+ if (!prefix) {
+ if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) ==
+ B_OK) {
+ prefix = dir;
+ } else {
+ prefix = "/boot/system";
+ }
+ }
+#else
+ if (!prefix) {
+ prefix = "/usr/local";
+ }
+#endif
+ if (const char* stagingPrefix =
+ this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX")) {
+ prefix = stagingPrefix;
+ }
+
+ // Compute the set of configurations.
+ std::vector<std::string> configurationTypes;
+ const std::string& config =
+ this->Makefile->GetConfigurations(configurationTypes, false);
+
+ // Choose a default install configuration.
+ std::string default_config = config;
+ const char* default_order[] = { "RELEASE", "MINSIZEREL", "RELWITHDEBINFO",
+ "DEBUG", CM_NULLPTR };
+ for (const char** c = default_order; *c && default_config.empty(); ++c) {
+ for (std::vector<std::string>::iterator i = configurationTypes.begin();
+ i != configurationTypes.end(); ++i) {
+ if (cmSystemTools::UpperCase(*i) == *c) {
+ default_config = *i;
+ }
+ }
+ }
+ if (default_config.empty() && !configurationTypes.empty()) {
+ default_config = configurationTypes[0];
+ }
+
+ // Create the install script file.
+ std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary();
+ std::string homedir = this->GetState()->GetBinaryDirectory();
+ int toplevel_install = 0;
+ if (file == homedir) {
+ toplevel_install = 1;
+ }
+ file += "/cmake_install.cmake";
+ cmGeneratedFileStream fout(file.c_str());
+ fout.SetCopyIfDifferent(true);
+
+ // Write the header.
+ fout << "# Install script for directory: "
+ << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl
+ << std::endl;
+ fout << "# Set the install prefix" << std::endl
+ << "if(NOT DEFINED CMAKE_INSTALL_PREFIX)" << std::endl
+ << " set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")" << std::endl
+ << "endif()" << std::endl
+ << "string(REGEX REPLACE \"/$\" \"\" CMAKE_INSTALL_PREFIX "
+ << "\"${CMAKE_INSTALL_PREFIX}\")" << std::endl
+ << std::endl;
+
+ // Write support code for generating per-configuration install rules.
+ /* clang-format off */
+ fout <<
+ "# Set the install configuration name.\n"
+ "if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n"
+ " if(BUILD_TYPE)\n"
+ " string(REGEX REPLACE \"^[^A-Za-z0-9_]+\" \"\"\n"
+ " CMAKE_INSTALL_CONFIG_NAME \"${BUILD_TYPE}\")\n"
+ " else()\n"
+ " set(CMAKE_INSTALL_CONFIG_NAME \"" << default_config << "\")\n"
+ " endif()\n"
+ " message(STATUS \"Install configuration: "
+ "\\\"${CMAKE_INSTALL_CONFIG_NAME}\\\"\")\n"
+ "endif()\n"
+ "\n";
+ /* clang-format on */
+
+ // Write support code for dealing with component-specific installs.
+ /* clang-format off */
+ fout <<
+ "# Set the component getting installed.\n"
+ "if(NOT CMAKE_INSTALL_COMPONENT)\n"
+ " if(COMPONENT)\n"
+ " message(STATUS \"Install component: \\\"${COMPONENT}\\\"\")\n"
+ " set(CMAKE_INSTALL_COMPONENT \"${COMPONENT}\")\n"
+ " else()\n"
+ " set(CMAKE_INSTALL_COMPONENT)\n"
+ " endif()\n"
+ "endif()\n"
+ "\n";
+ /* clang-format on */
+
+ // Copy user-specified install options to the install code.
+ if (const char* so_no_exe =
+ this->Makefile->GetDefinition("CMAKE_INSTALL_SO_NO_EXE")) {
+ /* clang-format off */
+ fout <<
+ "# Install shared libraries without execute permission?\n"
+ "if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)\n"
+ " set(CMAKE_INSTALL_SO_NO_EXE \"" << so_no_exe << "\")\n"
+ "endif()\n"
+ "\n";
+ /* clang-format on */
+ }
+
+ // Ask each install generator to write its code.
+ std::vector<cmInstallGenerator*> const& installers =
+ this->Makefile->GetInstallGenerators();
+ for (std::vector<cmInstallGenerator*>::const_iterator gi =
+ installers.begin();
+ gi != installers.end(); ++gi) {
+ (*gi)->Generate(fout, config, configurationTypes);
+ }
+
+ // Write rules from old-style specification stored in targets.
+ this->GenerateTargetInstallRules(fout, config, configurationTypes);
+
+ // Include install scripts from subdirectories.
+ std::vector<cmState::Snapshot> children =
+ this->Makefile->GetStateSnapshot().GetChildren();
+ if (!children.empty()) {
+ fout << "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n";
+ fout << " # Include the install script for each subdirectory.\n";
+ for (std::vector<cmState::Snapshot>::const_iterator ci = children.begin();
+ ci != children.end(); ++ci) {
+ if (!ci->GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+ std::string odir = ci->GetDirectory().GetCurrentBinary();
+ cmSystemTools::ConvertToUnixSlashes(odir);
+ fout << " include(\"" << odir << "/cmake_install.cmake\")"
+ << std::endl;
+ }
+ }
+ fout << "\n";
+ fout << "endif()\n\n";
+ }
+
+ // Record the install manifest.
+ if (toplevel_install) {
+ /* clang-format off */
+ fout <<
+ "if(CMAKE_INSTALL_COMPONENT)\n"
+ " set(CMAKE_INSTALL_MANIFEST \"install_manifest_"
+ "${CMAKE_INSTALL_COMPONENT}.txt\")\n"
+ "else()\n"
+ " set(CMAKE_INSTALL_MANIFEST \"install_manifest.txt\")\n"
+ "endif()\n"
+ "\n"
+ "string(REPLACE \";\" \"\\n\" CMAKE_INSTALL_MANIFEST_CONTENT\n"
+ " \"${CMAKE_INSTALL_MANIFEST_FILES}\")\n"
+ "file(WRITE \"" << homedir << "/${CMAKE_INSTALL_MANIFEST}\"\n"
+ " \"${CMAKE_INSTALL_MANIFEST_CONTENT}\")\n";
+ /* clang-format on */
+ }
+}
+
+void cmLocalGenerator::AddGeneratorTarget(cmGeneratorTarget* gt)
+{
+ this->GeneratorTargets.push_back(gt);
+ this->GlobalGenerator->IndexGeneratorTarget(gt);
+}
+
+void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt)
+{
+ this->ImportedGeneratorTargets.push_back(gt);
+ this->GlobalGenerator->IndexGeneratorTarget(gt);
+}
+
+void cmLocalGenerator::AddOwnedImportedGeneratorTarget(cmGeneratorTarget* gt)
+{
+ this->OwnedImportedGeneratorTargets.push_back(gt);
+}
+
+struct NamedGeneratorTargetFinder
+{
+ NamedGeneratorTargetFinder(std::string const& name)
+ : Name(name)
+ {
+ }
+
+ bool operator()(cmGeneratorTarget* tgt)
+ {
+ return tgt->GetName() == this->Name;
+ }
+
+private:
+ std::string Name;
+};
+
+cmGeneratorTarget* cmLocalGenerator::FindLocalNonAliasGeneratorTarget(
+ const std::string& name) const
+{
+ std::vector<cmGeneratorTarget*>::const_iterator ti =
+ std::find_if(this->GeneratorTargets.begin(), this->GeneratorTargets.end(),
+ NamedGeneratorTargetFinder(name));
+ if (ti != this->GeneratorTargets.end()) {
+ return *ti;
+ }
+ return CM_NULLPTR;
+}
+
+void cmLocalGenerator::ComputeTargetManifest()
+{
+ // Collect the set of configuration types.
+ std::vector<std::string> configNames;
+ this->Makefile->GetConfigurations(configNames);
+ if (configNames.empty()) {
+ configNames.push_back("");
+ }
+
+ // Add our targets to the manifest for each configuration.
+ std::vector<cmGeneratorTarget*> targets = this->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
+ t != targets.end(); ++t) {
+ cmGeneratorTarget* target = *t;
+ if (target->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ for (std::vector<std::string>::iterator ci = configNames.begin();
+ ci != configNames.end(); ++ci) {
+ const char* config = ci->c_str();
+ target->ComputeTargetManifest(config);
+ }
+ }
+}
+
+bool cmLocalGenerator::IsRootMakefile() const
+{
+ return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid();
+}
+
+cmState* cmLocalGenerator::GetState() const
+{
+ return this->GlobalGenerator->GetCMakeInstance()->GetState();
+}
+
+cmState::Snapshot cmLocalGenerator::GetStateSnapshot() const
+{
+ return this->Makefile->GetStateSnapshot();
+}
+
+// List of variables that are replaced when
+// rules are expanced. These variables are
+// 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_CL_SHOWINCLUDES_PREFIX",
+ CM_NULLPTR
+};
+
+std::string cmLocalGenerator::ExpandRuleVariable(
+ std::string const& variable, const RuleVariables& replaceValues)
+{
+ if (replaceValues.LinkFlags) {
+ if (variable == "LINK_FLAGS") {
+ return replaceValues.LinkFlags;
+ }
+ }
+ if (replaceValues.Manifests) {
+ if (variable == "MANIFESTS") {
+ return replaceValues.Manifests;
+ }
+ }
+ if (replaceValues.Flags) {
+ if (variable == "FLAGS") {
+ return replaceValues.Flags;
+ }
+ }
+
+ if (replaceValues.Source) {
+ if (variable == "SOURCE") {
+ return replaceValues.Source;
+ }
+ }
+ if (replaceValues.PreprocessedSource) {
+ if (variable == "PREPROCESSED_SOURCE") {
+ return replaceValues.PreprocessedSource;
+ }
+ }
+ if (replaceValues.AssemblySource) {
+ if (variable == "ASSEMBLY_SOURCE") {
+ return replaceValues.AssemblySource;
+ }
+ }
+ if (replaceValues.Object) {
+ if (variable == "OBJECT") {
+ return replaceValues.Object;
+ }
+ }
+ if (replaceValues.ObjectDir) {
+ if (variable == "OBJECT_DIR") {
+ return replaceValues.ObjectDir;
+ }
+ }
+ if (replaceValues.ObjectFileDir) {
+ if (variable == "OBJECT_FILE_DIR") {
+ return replaceValues.ObjectFileDir;
+ }
+ }
+ if (replaceValues.Objects) {
+ if (variable == "OBJECTS") {
+ return replaceValues.Objects;
+ }
+ }
+ if (replaceValues.ObjectsQuoted) {
+ if (variable == "OBJECTS_QUOTED") {
+ return replaceValues.ObjectsQuoted;
+ }
+ }
+ if (replaceValues.Defines && variable == "DEFINES") {
+ return replaceValues.Defines;
+ }
+ if (replaceValues.Includes && variable == "INCLUDES") {
+ return replaceValues.Includes;
+ }
+ if (replaceValues.TargetPDB) {
+ if (variable == "TARGET_PDB") {
+ return replaceValues.TargetPDB;
+ }
+ }
+ if (replaceValues.TargetCompilePDB) {
+ if (variable == "TARGET_COMPILE_PDB") {
+ return replaceValues.TargetCompilePDB;
+ }
+ }
+ if (replaceValues.DependencyFile) {
+ if (variable == "DEP_FILE") {
+ return replaceValues.DependencyFile;
+ }
+ }
+
+ if (replaceValues.Target) {
+ if (variable == "TARGET_QUOTED") {
+ std::string targetQuoted = replaceValues.Target;
+ if (!targetQuoted.empty() && targetQuoted[0] != '\"') {
+ targetQuoted = '\"';
+ targetQuoted += replaceValues.Target;
+ targetQuoted += '\"';
+ }
+ return targetQuoted;
+ }
+ if (variable == "TARGET_UNQUOTED") {
+ std::string unquoted = replaceValues.Target;
+ std::string::size_type sz = unquoted.size();
+ if (sz > 2 && unquoted[0] == '\"' && unquoted[sz - 1] == '\"') {
+ unquoted = unquoted.substr(1, sz - 2);
+ }
+ return unquoted;
+ }
+ if (replaceValues.LanguageCompileFlags) {
+ if (variable == "LANGUAGE_COMPILE_FLAGS") {
+ return replaceValues.LanguageCompileFlags;
+ }
+ }
+ if (replaceValues.Target) {
+ if (variable == "TARGET") {
+ return replaceValues.Target;
+ }
+ }
+ if (variable == "TARGET_IMPLIB") {
+ return this->TargetImplib;
+ }
+ if (variable == "TARGET_VERSION_MAJOR") {
+ if (replaceValues.TargetVersionMajor) {
+ return replaceValues.TargetVersionMajor;
+ } else {
+ return "0";
+ }
+ }
+ if (variable == "TARGET_VERSION_MINOR") {
+ if (replaceValues.TargetVersionMinor) {
+ return replaceValues.TargetVersionMinor;
+ } else {
+ return "0";
+ }
+ }
+ if (replaceValues.Target) {
+ if (variable == "TARGET_BASE") {
+ // Strip the last extension off the target name.
+ std::string targetBase = replaceValues.Target;
+ std::string::size_type pos = targetBase.rfind('.');
+ if (pos != targetBase.npos) {
+ return targetBase.substr(0, pos);
+ } else {
+ return targetBase;
+ }
+ }
+ }
+ }
+ if (variable == "TARGET_SONAME" || variable == "SONAME_FLAG" ||
+ variable == "TARGET_INSTALLNAME_DIR") {
+ // All these variables depend on TargetSOName
+ if (replaceValues.TargetSOName) {
+ if (variable == "TARGET_SONAME") {
+ return replaceValues.TargetSOName;
+ }
+ if (variable == "SONAME_FLAG" && replaceValues.SONameFlag) {
+ return replaceValues.SONameFlag;
+ }
+ if (replaceValues.TargetInstallNameDir &&
+ variable == "TARGET_INSTALLNAME_DIR") {
+ return replaceValues.TargetInstallNameDir;
+ }
+ }
+ return "";
+ }
+ if (replaceValues.LinkLibraries) {
+ if (variable == "LINK_LIBRARIES") {
+ return replaceValues.LinkLibraries;
+ }
+ }
+ if (replaceValues.Language) {
+ if (variable == "LANGUAGE") {
+ return replaceValues.Language;
+ }
+ }
+ if (replaceValues.CMTarget) {
+ if (variable == "TARGET_NAME") {
+ return replaceValues.CMTarget->GetName();
+ }
+ if (variable == "TARGET_TYPE") {
+ return cmState::GetTargetTypeName(replaceValues.CMTarget->GetType());
+ }
+ }
+ if (replaceValues.Output) {
+ if (variable == "OUTPUT") {
+ return replaceValues.Output;
+ }
+ }
+ if (variable == "CMAKE_COMMAND") {
+ return this->Convert(cmSystemTools::GetCMakeCommand(), FULL, SHELL);
+ }
+ std::vector<std::string> enabledLanguages =
+ this->GetState()->GetEnabledLanguages();
+ // loop over language specific replace variables
+ int pos = 0;
+ while (ruleReplaceVars[pos]) {
+ for (std::vector<std::string>::iterator i = enabledLanguages.begin();
+ i != enabledLanguages.end(); ++i) {
+ const char* lang = i->c_str();
+ std::string actualReplace = ruleReplaceVars[pos];
+ // If this is the compiler then look for the extra variable
+ // _COMPILER_ARG1 which must be the first argument to the compiler
+ const char* compilerArg1 = CM_NULLPTR;
+ const char* compilerTarget = CM_NULLPTR;
+ const char* compilerOptionTarget = CM_NULLPTR;
+ const char* compilerExternalToolchain = CM_NULLPTR;
+ const char* compilerOptionExternalToolchain = CM_NULLPTR;
+ const char* compilerSysroot = CM_NULLPTR;
+ const char* compilerOptionSysroot = CM_NULLPTR;
+ if (actualReplace == "CMAKE_${LANG}_COMPILER") {
+ std::string arg1 = actualReplace + "_ARG1";
+ cmSystemTools::ReplaceString(arg1, "${LANG}", lang);
+ compilerArg1 = this->Makefile->GetDefinition(arg1);
+ compilerTarget = this->Makefile->GetDefinition(
+ std::string("CMAKE_") + lang + "_COMPILER_TARGET");
+ compilerOptionTarget = this->Makefile->GetDefinition(
+ std::string("CMAKE_") + lang + "_COMPILE_OPTIONS_TARGET");
+ compilerExternalToolchain = this->Makefile->GetDefinition(
+ std::string("CMAKE_") + lang + "_COMPILER_EXTERNAL_TOOLCHAIN");
+ compilerOptionExternalToolchain =
+ this->Makefile->GetDefinition(std::string("CMAKE_") + lang +
+ "_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN");
+ compilerSysroot = this->Makefile->GetDefinition("CMAKE_SYSROOT");
+ compilerOptionSysroot = this->Makefile->GetDefinition(
+ std::string("CMAKE_") + lang + "_COMPILE_OPTIONS_SYSROOT");
+ }
+ if (actualReplace.find("${LANG}") != actualReplace.npos) {
+ cmSystemTools::ReplaceString(actualReplace, "${LANG}", lang);
+ }
+ if (actualReplace == variable) {
+ std::string replace = this->Makefile->GetSafeDefinition(variable);
+ // if the variable is not a FLAG then treat it like a path
+ if (variable.find("_FLAG") == variable.npos) {
+ std::string ret = this->ConvertToOutputForExisting(replace);
+ // if there is a required first argument to the compiler add it
+ // to the compiler string
+ if (compilerArg1) {
+ ret += " ";
+ ret += compilerArg1;
+ }
+ if (compilerTarget && compilerOptionTarget) {
+ ret += " ";
+ ret += compilerOptionTarget;
+ ret += compilerTarget;
+ }
+ if (compilerExternalToolchain && compilerOptionExternalToolchain) {
+ ret += " ";
+ ret += compilerOptionExternalToolchain;
+ ret += this->EscapeForShell(compilerExternalToolchain, true);
+ }
+ if (compilerSysroot && compilerOptionSysroot) {
+ ret += " ";
+ ret += compilerOptionSysroot;
+ ret += this->EscapeForShell(compilerSysroot, true);
+ }
+ return ret;
+ }
+ return replace;
+ }
+ }
+ pos++;
+ }
+ return variable;
+}
+
+void cmLocalGenerator::ExpandRuleVariables(std::string& s,
+ const RuleVariables& replaceValues)
+{
+ if (replaceValues.RuleLauncher) {
+ this->InsertRuleLauncher(s, replaceValues.CMTarget,
+ replaceValues.RuleLauncher);
+ }
+ std::string::size_type start = s.find('<');
+ // no variables to expand
+ if (start == s.npos) {
+ return;
+ }
+ std::string::size_type pos = 0;
+ std::string expandedInput;
+ while (start != s.npos && start < s.size() - 2) {
+ std::string::size_type end = s.find('>', start);
+ // if we find a < with no > we are done
+ if (end == s.npos) {
+ return;
+ }
+ char c = s[start + 1];
+ // if the next char after the < is not A-Za-z then
+ // skip it and try to find the next < in the string
+ if (!isalpha(c)) {
+ start = s.find('<', start + 1);
+ } else {
+ // extract the var
+ std::string var = s.substr(start + 1, end - start - 1);
+ std::string replace = this->ExpandRuleVariable(var, replaceValues);
+ expandedInput += s.substr(pos, start - pos);
+ expandedInput += replace;
+ // move to next one
+ start = s.find('<', start + var.size() + 2);
+ pos = end + 1;
+ }
+ }
+ // add the rest of the input
+ expandedInput += s.substr(pos, s.size() - pos);
+ s = expandedInput;
+}
+
+const char* cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target,
+ const std::string& prop)
+{
+ if (target) {
+ return target->GetProperty(prop);
+ } else {
+ return this->Makefile->GetProperty(prop);
+ }
+}
+
+void cmLocalGenerator::InsertRuleLauncher(std::string& s,
+ cmGeneratorTarget* target,
+ const std::string& prop)
+{
+ if (const char* val = this->GetRuleLauncher(target, prop)) {
+ std::ostringstream wrapped;
+ wrapped << val << " " << s;
+ s = wrapped.str();
+ }
+}
+
+std::string cmLocalGenerator::ConvertToIncludeReference(
+ std::string const& path, OutputFormat format, bool forceFullPaths)
+{
+ static_cast<void>(forceFullPaths);
+ return this->ConvertToOutputForExisting(path, format);
+}
+
+std::string cmLocalGenerator::GetIncludeFlags(
+ const std::vector<std::string>& includes, cmGeneratorTarget* target,
+ const std::string& lang, bool forceFullPaths, bool forResponseFile,
+ const std::string& config)
+{
+ if (lang.empty()) {
+ return "";
+ }
+
+ OutputFormat shellFormat = forResponseFile ? RESPONSE : SHELL;
+ std::ostringstream includeFlags;
+
+ std::string flagVar = "CMAKE_INCLUDE_FLAG_";
+ flagVar += lang;
+ const char* includeFlag = this->Makefile->GetSafeDefinition(flagVar);
+ flagVar = "CMAKE_INCLUDE_FLAG_SEP_";
+ flagVar += lang;
+ const char* sep = this->Makefile->GetDefinition(flagVar);
+ bool quotePaths = false;
+ if (this->Makefile->GetDefinition("CMAKE_QUOTE_INCLUDE_PATHS")) {
+ quotePaths = true;
+ }
+ bool repeatFlag = true;
+ // should the include flag be repeated like ie. -IA -IB
+ if (!sep) {
+ sep = " ";
+ } else {
+ // if there is a separator then the flag is not repeated but is only
+ // given once i.e. -classpath a:b:c
+ repeatFlag = false;
+ }
+
+ // Support special system include flag if it is available and the
+ // normal flag is repeated for each directory.
+ std::string sysFlagVar = "CMAKE_INCLUDE_SYSTEM_FLAG_";
+ sysFlagVar += lang;
+ const char* sysIncludeFlag = CM_NULLPTR;
+ if (repeatFlag) {
+ sysIncludeFlag = this->Makefile->GetDefinition(sysFlagVar);
+ }
+
+ std::string fwSearchFlagVar = "CMAKE_";
+ fwSearchFlagVar += lang;
+ fwSearchFlagVar += "_FRAMEWORK_SEARCH_FLAG";
+ const char* fwSearchFlag = this->Makefile->GetDefinition(fwSearchFlagVar);
+
+ std::string sysFwSearchFlagVar = "CMAKE_";
+ sysFwSearchFlagVar += lang;
+ sysFwSearchFlagVar += "_SYSTEM_FRAMEWORK_SEARCH_FLAG";
+ const char* sysFwSearchFlag =
+ this->Makefile->GetDefinition(sysFwSearchFlagVar);
+
+ bool flagUsed = false;
+ std::set<std::string> emitted;
+#ifdef __APPLE__
+ emitted.insert("/System/Library/Frameworks");
+#endif
+ std::vector<std::string>::const_iterator i;
+ for (i = includes.begin(); i != includes.end(); ++i) {
+ if (fwSearchFlag && *fwSearchFlag && this->Makefile->IsOn("APPLE") &&
+ cmSystemTools::IsPathToFramework(i->c_str())) {
+ std::string frameworkDir = *i;
+ frameworkDir += "/../";
+ frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
+ if (emitted.insert(frameworkDir).second) {
+ if (sysFwSearchFlag && target &&
+ target->IsSystemIncludeDirectory(*i, config)) {
+ includeFlags << sysFwSearchFlag;
+ } else {
+ includeFlags << fwSearchFlag;
+ }
+ includeFlags << this->ConvertToOutputFormat(frameworkDir, shellFormat)
+ << " ";
+ }
+ continue;
+ }
+
+ if (!flagUsed || repeatFlag) {
+ if (sysIncludeFlag && target &&
+ target->IsSystemIncludeDirectory(*i, config)) {
+ includeFlags << sysIncludeFlag;
+ } else {
+ includeFlags << includeFlag;
+ }
+ flagUsed = true;
+ }
+ std::string includePath =
+ this->ConvertToIncludeReference(*i, shellFormat, forceFullPaths);
+ if (quotePaths && !includePath.empty() && includePath[0] != '\"') {
+ includeFlags << "\"";
+ }
+ includeFlags << includePath;
+ if (quotePaths && !includePath.empty() && includePath[0] != '\"') {
+ includeFlags << "\"";
+ }
+ includeFlags << sep;
+ }
+ std::string flags = includeFlags.str();
+ // remove trailing separators
+ if ((sep[0] != ' ') && !flags.empty() && flags[flags.size() - 1] == sep[0]) {
+ flags[flags.size() - 1] = ' ';
+ }
+ return flags;
+}
+
+void cmLocalGenerator::AddCompileDefinitions(std::set<std::string>& defines,
+ cmGeneratorTarget const* target,
+ const std::string& config,
+ const std::string& lang) const
+{
+ std::vector<std::string> targetDefines;
+ target->GetCompileDefinitions(targetDefines, config, lang);
+ this->AppendDefines(defines, targetDefines);
+}
+
+void cmLocalGenerator::AddCompileOptions(std::string& flags,
+ cmGeneratorTarget* target,
+ const std::string& lang,
+ const std::string& config)
+{
+ std::string langFlagRegexVar = std::string("CMAKE_") + lang + "_FLAG_REGEX";
+
+ if (const char* langFlagRegexStr =
+ this->Makefile->GetDefinition(langFlagRegexVar)) {
+ // Filter flags acceptable to this language.
+ cmsys::RegularExpression r(langFlagRegexStr);
+ std::vector<std::string> opts;
+ if (const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) {
+ cmSystemTools::ParseWindowsCommandLine(targetFlags, opts);
+ }
+ target->GetCompileOptions(opts, config, lang);
+ for (std::vector<std::string>::const_iterator i = opts.begin();
+ i != opts.end(); ++i) {
+ if (r.find(i->c_str())) {
+ // (Re-)Escape this flag. COMPILE_FLAGS were already parsed
+ // as a command line above, and COMPILE_OPTIONS are escaped.
+ this->AppendFlagEscape(flags, *i);
+ }
+ }
+ } else {
+ // Use all flags.
+ if (const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) {
+ // COMPILE_FLAGS are not escaped for historical reasons.
+ this->AppendFlags(flags, targetFlags);
+ }
+ std::vector<std::string> opts;
+ target->GetCompileOptions(opts, config, lang);
+ for (std::vector<std::string>::const_iterator i = opts.begin();
+ i != opts.end(); ++i) {
+ // COMPILE_OPTIONS are escaped.
+ this->AppendFlagEscape(flags, *i);
+ }
+ }
+ std::vector<std::string> features;
+ target->GetCompileFeatures(features, config);
+ for (std::vector<std::string>::const_iterator it = features.begin();
+ it != features.end(); ++it) {
+ if (!this->Makefile->AddRequiredTargetFeature(target->Target, *it)) {
+ return;
+ }
+ }
+
+ for (std::map<std::string, std::string>::const_iterator it =
+ target->GetMaxLanguageStandards().begin();
+ it != target->GetMaxLanguageStandards().end(); ++it) {
+ const char* standard = target->GetProperty(it->first + "_STANDARD");
+ if (!standard) {
+ continue;
+ }
+ if (this->Makefile->IsLaterStandard(it->first, standard, it->second)) {
+ std::ostringstream e;
+ e << "The COMPILE_FEATURES property of target \"" << target->GetName()
+ << "\" was evaluated when computing the link "
+ "implementation, and the \""
+ << it->first << "_STANDARD\" was \"" << it->second
+ << "\" for that computation. Computing the "
+ "COMPILE_FEATURES based on the link implementation resulted in a "
+ "higher \""
+ << it->first << "_STANDARD\" \"" << standard
+ << "\". "
+ "This is not permitted. The COMPILE_FEATURES may not both depend "
+ "on "
+ "and be depended on by the link implementation."
+ << std::endl;
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ }
+ this->AddCompilerRequirementFlag(flags, target, lang);
+}
+
+void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
+ cmGeneratorTarget const* target,
+ const std::string& lang,
+ const std::string& config,
+ bool stripImplicitInclDirs) const
+{
+ // Need to decide whether to automatically include the source and
+ // binary directories at the beginning of the include path.
+ bool includeSourceDir = false;
+ bool includeBinaryDir = false;
+
+ // When automatic include directories are requested for a build then
+ // include the source and binary directories at the beginning of the
+ // include path to approximate include file behavior for an
+ // in-source build. This does not account for the case of a source
+ // file in a subdirectory of the current source directory but we
+ // cannot fix this because not all native build tools support
+ // per-source-file include paths.
+ if (this->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR")) {
+ includeSourceDir = true;
+ includeBinaryDir = true;
+ }
+
+ // Do not repeat an include path.
+ std::set<std::string> emitted;
+
+ // Store the automatic include paths.
+ if (includeBinaryDir) {
+ std::string binDir = this->StateSnapshot.GetDirectory().GetCurrentBinary();
+ if (emitted.find(binDir) == emitted.end()) {
+ dirs.push_back(binDir);
+ emitted.insert(binDir);
+ }
+ }
+ if (includeSourceDir) {
+ std::string srcDir = this->StateSnapshot.GetDirectory().GetCurrentSource();
+ if (emitted.find(srcDir) == emitted.end()) {
+ dirs.push_back(srcDir);
+ emitted.insert(srcDir);
+ }
+ }
+
+ if (!target) {
+ return;
+ }
+
+ std::string rootPath = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
+
+ std::vector<std::string> implicitDirs;
+ // Load implicit include directories for this language.
+ std::string impDirVar = "CMAKE_";
+ impDirVar += lang;
+ impDirVar += "_IMPLICIT_INCLUDE_DIRECTORIES";
+ if (const char* value = this->Makefile->GetDefinition(impDirVar)) {
+ std::vector<std::string> impDirVec;
+ cmSystemTools::ExpandListArgument(value, impDirVec);
+ for (std::vector<std::string>::const_iterator i = impDirVec.begin();
+ i != impDirVec.end(); ++i) {
+ std::string d = rootPath + *i;
+ cmSystemTools::ConvertToUnixSlashes(d);
+ emitted.insert(d);
+ if (!stripImplicitInclDirs) {
+ implicitDirs.push_back(*i);
+ }
+ }
+ }
+
+ // Get the target-specific include directories.
+ std::vector<std::string> includes;
+
+ includes = target->GetIncludeDirectories(config, lang);
+
+ // Support putting all the in-project include directories first if
+ // it is requested by the project.
+ if (this->Makefile->IsOn("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")) {
+ const char* topSourceDir = this->GetState()->GetSourceDirectory();
+ const char* topBinaryDir = this->GetState()->GetBinaryDirectory();
+ for (std::vector<std::string>::const_iterator i = includes.begin();
+ i != includes.end(); ++i) {
+ // Emit this directory only if it is a subdirectory of the
+ // top-level source or binary tree.
+ if (cmSystemTools::ComparePath(*i, topSourceDir) ||
+ cmSystemTools::ComparePath(*i, topBinaryDir) ||
+ cmSystemTools::IsSubDirectory(*i, topSourceDir) ||
+ cmSystemTools::IsSubDirectory(*i, topBinaryDir)) {
+ if (emitted.insert(*i).second) {
+ dirs.push_back(*i);
+ }
+ }
+ }
+ }
+
+ // Construct the final ordered include directory list.
+ for (std::vector<std::string>::const_iterator i = includes.begin();
+ i != includes.end(); ++i) {
+ if (emitted.insert(*i).second) {
+ dirs.push_back(*i);
+ }
+ }
+
+ for (std::vector<std::string>::const_iterator i = implicitDirs.begin();
+ i != implicitDirs.end(); ++i) {
+ if (std::find(includes.begin(), includes.end(), *i) != includes.end()) {
+ dirs.push_back(*i);
+ }
+ }
+}
+
+void cmLocalGenerator::GetStaticLibraryFlags(std::string& flags,
+ std::string const& config,
+ cmGeneratorTarget* target)
+{
+ this->AppendFlags(
+ flags, this->Makefile->GetSafeDefinition("CMAKE_STATIC_LINKER_FLAGS"));
+ if (!config.empty()) {
+ std::string name = "CMAKE_STATIC_LINKER_FLAGS_" + config;
+ this->AppendFlags(flags, this->Makefile->GetSafeDefinition(name));
+ }
+ this->AppendFlags(flags, target->GetProperty("STATIC_LIBRARY_FLAGS"));
+ if (!config.empty()) {
+ std::string name = "STATIC_LIBRARY_FLAGS_" + config;
+ this->AppendFlags(flags, target->GetProperty(name));
+ }
+}
+
+void cmLocalGenerator::GetTargetFlags(
+ const std::string& config, std::string& linkLibs, std::string& flags,
+ std::string& linkFlags, std::string& frameworkPath, std::string& linkPath,
+ cmGeneratorTarget* target, bool useWatcomQuote)
+{
+ const std::string buildType = cmSystemTools::UpperCase(config);
+ const char* libraryLinkVariable =
+ "CMAKE_SHARED_LINKER_FLAGS"; // default to shared library
+
+ switch (target->GetType()) {
+ case cmState::STATIC_LIBRARY:
+ this->GetStaticLibraryFlags(linkFlags, buildType, target);
+ break;
+ case cmState::MODULE_LIBRARY:
+ libraryLinkVariable = "CMAKE_MODULE_LINKER_FLAGS";
+ case cmState::SHARED_LIBRARY: {
+ linkFlags = this->Makefile->GetSafeDefinition(libraryLinkVariable);
+ 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);
+ for (std::vector<cmSourceFile*>::const_iterator i = sources.begin();
+ i != sources.end(); ++i) {
+ cmSourceFile* sf = *i;
+ if (sf->GetExtension() == "def") {
+ linkFlags +=
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG");
+ linkFlags += this->Convert(sf->GetFullPath(), FULL, SHELL);
+ linkFlags += " ";
+ }
+ }
+ }
+ const char* targetLinkFlags = target->GetProperty("LINK_FLAGS");
+ if (targetLinkFlags) {
+ linkFlags += targetLinkFlags;
+ linkFlags += " ";
+ }
+ if (!buildType.empty()) {
+ std::string configLinkFlags = "LINK_FLAGS_";
+ configLinkFlags += buildType;
+ targetLinkFlags = target->GetProperty(configLinkFlags);
+ if (targetLinkFlags) {
+ linkFlags += targetLinkFlags;
+ linkFlags += " ";
+ }
+ }
+ this->OutputLinkLibraries(linkLibs, frameworkPath, linkPath, *target,
+ false, false, useWatcomQuote);
+ } break;
+ case cmState::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);
+ linkFlags += " ";
+ }
+ std::string linkLanguage = target->GetLinkerLanguage(buildType);
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error(
+ "CMake can not determine linker language for target: ",
+ target->GetName().c_str());
+ return;
+ }
+ this->AddLanguageFlags(flags, linkLanguage, buildType);
+ this->OutputLinkLibraries(linkLibs, frameworkPath, linkPath, *target,
+ false, false, useWatcomQuote);
+ if (cmSystemTools::IsOn(
+ this->Makefile->GetDefinition("BUILD_SHARED_LIBS"))) {
+ std::string sFlagVar = std::string("CMAKE_SHARED_BUILD_") +
+ linkLanguage + std::string("_FLAGS");
+ 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 += " ";
+ }
+ const char* targetLinkFlags = target->GetProperty("LINK_FLAGS");
+ if (targetLinkFlags) {
+ linkFlags += targetLinkFlags;
+ linkFlags += " ";
+ }
+ if (!buildType.empty()) {
+ std::string configLinkFlags = "LINK_FLAGS_";
+ configLinkFlags += buildType;
+ targetLinkFlags = target->GetProperty(configLinkFlags);
+ if (targetLinkFlags) {
+ linkFlags += targetLinkFlags;
+ linkFlags += " ";
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+}
+
+void cmLocalGenerator::GetTargetCompileFlags(cmGeneratorTarget* target,
+ std::string const& config,
+ std::string const& lang,
+ std::string& flags)
+{
+ cmMakefile* mf = this->GetMakefile();
+
+ // Add language-specific flags.
+ this->AddLanguageFlags(flags, lang, config);
+
+ if (target->GetFeatureAsBool("INTERPROCEDURAL_OPTIMIZATION", config)) {
+ this->AppendFeatureOptions(flags, lang, "IPO");
+ }
+
+ this->AddArchitectureFlags(flags, target, lang, config);
+
+ if (lang == "Fortran") {
+ this->AppendFlags(flags, this->GetTargetFortranFlags(target, config));
+ }
+
+ this->AddCMP0018Flags(flags, target, lang, config);
+ this->AddVisibilityPresetFlags(flags, target, lang);
+ this->AppendFlags(flags, mf->GetDefineFlags());
+ this->AppendFlags(flags, this->GetFrameworkFlags(lang, config, target));
+ this->AddCompileOptions(flags, target, lang, config);
+}
+
+static std::string GetFrameworkFlags(const std::string& lang,
+ const std::string& config,
+ cmGeneratorTarget* target)
+{
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ cmMakefile* mf = lg->GetMakefile();
+
+ if (!mf->IsOn("APPLE")) {
+ return std::string();
+ }
+
+ std::string fwSearchFlagVar = "CMAKE_" + lang + "_FRAMEWORK_SEARCH_FLAG";
+ const char* fwSearchFlag = mf->GetDefinition(fwSearchFlagVar);
+ if (!(fwSearchFlag && *fwSearchFlag)) {
+ return std::string();
+ }
+
+ std::set<std::string> emitted;
+#ifdef __APPLE__ /* don't insert this when crosscompiling e.g. to iphone */
+ emitted.insert("/System/Library/Frameworks");
+#endif
+ std::vector<std::string> includes;
+
+ lg->GetIncludeDirectories(includes, target, "C", config);
+ // check all include directories for frameworks as this
+ // will already have added a -F for the framework
+ for (std::vector<std::string>::iterator i = includes.begin();
+ i != includes.end(); ++i) {
+ if (lg->GetGlobalGenerator()->NameResolvesToFramework(*i)) {
+ std::string frameworkDir = *i;
+ frameworkDir += "/../";
+ frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
+ emitted.insert(frameworkDir);
+ }
+ }
+
+ std::string flags;
+ if (cmComputeLinkInformation* cli = target->GetLinkInformation(config)) {
+ std::vector<std::string> const& frameworks = cli->GetFrameworkPaths();
+ for (std::vector<std::string>::const_iterator i = frameworks.begin();
+ i != frameworks.end(); ++i) {
+ if (emitted.insert(*i).second) {
+ flags += fwSearchFlag;
+ flags += lg->ConvertToOutputFormat(*i, cmOutputConverter::SHELL);
+ flags += " ";
+ }
+ }
+ }
+ return flags;
+}
+
+std::string cmLocalGenerator::GetFrameworkFlags(std::string const& l,
+ std::string const& config,
+ cmGeneratorTarget* target)
+{
+ return ::GetFrameworkFlags(l, config, target);
+}
+
+void cmLocalGenerator::GetTargetDefines(cmGeneratorTarget const* target,
+ std::string const& config,
+ std::string const& lang,
+ std::set<std::string>& defines) const
+{
+ // Add the export symbol definition for shared library objects.
+ if (const char* exportMacro = target->GetExportMacro()) {
+ this->AppendDefines(defines, exportMacro);
+ }
+
+ // Add preprocessor definitions for this target and configuration.
+ this->AddCompileDefinitions(defines, target, config, lang.c_str());
+}
+
+std::string cmLocalGenerator::GetTargetFortranFlags(cmGeneratorTarget const*,
+ std::string const&)
+{
+ // Implemented by specific generators that override this.
+ return std::string();
+}
+
+std::string cmLocalGenerator::ConvertToLinkReference(std::string const& lib,
+ OutputFormat format)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // Work-ardound command line parsing limitations in MSVC 6.0
+ if (this->Makefile->IsOn("MSVC60")) {
+ // Search for the last space.
+ std::string::size_type pos = lib.rfind(' ');
+ if (pos != lib.npos) {
+ // Find the slash after the last space, if any.
+ pos = lib.find('/', pos);
+
+ // Convert the portion of the path with a space to a short path.
+ std::string sp;
+ if (cmSystemTools::GetShortPath(lib.substr(0, pos).c_str(), sp)) {
+ // Append the rest of the path with no space.
+ sp += lib.substr(pos);
+
+ // Convert to an output path.
+ return this->Convert(sp.c_str(), NONE, format);
+ }
+ }
+ }
+#endif
+
+ // Normal behavior.
+ return this->Convert(lib, START_OUTPUT, format);
+}
+
+/**
+ * Output the linking rules on a command line. For executables,
+ * targetLibrary should be a NULL pointer. For libraries, it should point
+ * to the name of the library. This will not link a library against itself.
+ */
+void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries,
+ std::string& frameworkPath,
+ std::string& linkPath,
+ cmGeneratorTarget& tgt, bool relink,
+ bool forResponseFile,
+ bool useWatcomQuote)
+{
+ OutputFormat shellFormat =
+ (forResponseFile) ? RESPONSE : ((useWatcomQuote) ? WATCOMQUOTE : SHELL);
+ bool escapeAllowMakeVars = !forResponseFile;
+ std::ostringstream fout;
+ std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ cmComputeLinkInformation* pcli = tgt.GetLinkInformation(config);
+ if (!pcli) {
+ return;
+ }
+ cmComputeLinkInformation& cli = *pcli;
+
+ // Collect library linking flags command line options.
+ std::string linkLibs;
+
+ std::string linkLanguage = cli.GetLinkLanguage();
+
+ std::string libPathFlag =
+ this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
+ std::string libPathTerminator =
+ this->Makefile->GetSafeDefinition("CMAKE_LIBRARY_PATH_TERMINATOR");
+
+ // Flags to link an executable to shared libraries.
+ if (tgt.GetType() == cmState::EXECUTABLE &&
+ this->StateSnapshot.GetState()->GetGlobalPropertyAsBool(
+ "TARGET_SUPPORTS_SHARED_LIBS")) {
+ bool add_shlib_flags = false;
+ switch (tgt.GetPolicyStatusCMP0065()) {
+ case cmPolicies::WARN:
+ if (!tgt.GetPropertyAsBool("ENABLE_EXPORTS") &&
+ this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0065")) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0065) << "\n"
+ "For compatibility with older versions of CMake, "
+ "additional flags may be added to export symbols on all "
+ "executables regardless of thier ENABLE_EXPORTS property.";
+ /* clang-format on */
+ this->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ }
+ case cmPolicies::OLD:
+ // OLD behavior is to always add the flags
+ add_shlib_flags = true;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->IssueMessage(
+ cmake::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0065));
+ case cmPolicies::NEW:
+ // NEW behavior is to only add the flags if ENABLE_EXPORTS is on
+ add_shlib_flags = tgt.GetPropertyAsBool("ENABLE_EXPORTS");
+ break;
+ }
+
+ if (add_shlib_flags) {
+ std::string linkFlagsVar = "CMAKE_SHARED_LIBRARY_LINK_";
+ linkFlagsVar += linkLanguage;
+ linkFlagsVar += "_FLAGS";
+ linkLibs = this->Makefile->GetSafeDefinition(linkFlagsVar);
+ linkLibs += " ";
+ }
+ }
+
+ // Append the framework search path flags.
+ std::string fwSearchFlagVar = "CMAKE_";
+ fwSearchFlagVar += linkLanguage;
+ fwSearchFlagVar += "_FRAMEWORK_SEARCH_FLAG";
+ const char* fwSearchFlag = this->Makefile->GetDefinition(fwSearchFlagVar);
+ if (fwSearchFlag && *fwSearchFlag) {
+ std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths();
+ for (std::vector<std::string>::const_iterator fdi = fwDirs.begin();
+ fdi != fwDirs.end(); ++fdi) {
+ frameworkPath += fwSearchFlag;
+ frameworkPath += this->Convert(*fdi, NONE, shellFormat);
+ frameworkPath += " ";
+ }
+ }
+
+ // Append the library search path flags.
+ std::vector<std::string> const& libDirs = cli.GetDirectories();
+ for (std::vector<std::string>::const_iterator libDir = libDirs.begin();
+ libDir != libDirs.end(); ++libDir) {
+ std::string libpath =
+ this->ConvertToOutputForExisting(*libDir, shellFormat);
+ linkPath += " " + libPathFlag;
+ linkPath += libpath;
+ linkPath += libPathTerminator;
+ linkPath += " ";
+ }
+
+ // Append the link items.
+ typedef cmComputeLinkInformation::ItemVector ItemVector;
+ ItemVector const& items = cli.GetItems();
+ for (ItemVector::const_iterator li = items.begin(); li != items.end();
+ ++li) {
+ if (li->Target && li->Target->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ if (li->IsPath) {
+ linkLibs += this->ConvertToLinkReference(li->Value, shellFormat);
+ } else {
+ linkLibs += li->Value;
+ }
+ linkLibs += " ";
+ }
+
+ // Write the library flags to the build rule.
+ fout << linkLibs;
+
+ // Check what kind of rpath flags to use.
+ if (cli.GetRuntimeSep().empty()) {
+ // Each rpath entry gets its own option ("-R a -R b -R c")
+ std::vector<std::string> runtimeDirs;
+ cli.GetRPath(runtimeDirs, relink);
+
+ std::string rpath;
+ for (std::vector<std::string>::iterator ri = runtimeDirs.begin();
+ ri != runtimeDirs.end(); ++ri) {
+ rpath += cli.GetRuntimeFlag();
+ rpath += this->Convert(*ri, NONE, shellFormat);
+ rpath += " ";
+ }
+ fout << rpath;
+ } else {
+ // All rpath entries are combined ("-Wl,-rpath,a:b:c").
+ std::string rpath = cli.GetRPathString(relink);
+
+ // Store the rpath option in the stream.
+ if (!rpath.empty()) {
+ fout << cli.GetRuntimeFlag();
+ fout << this->EscapeForShell(rpath, escapeAllowMakeVars);
+ fout << " ";
+ }
+ }
+
+ // Add the linker runtime search path if any.
+ std::string rpath_link = cli.GetRPathLinkString();
+ if (!cli.GetRPathLinkFlag().empty() && !rpath_link.empty()) {
+ fout << cli.GetRPathLinkFlag();
+ fout << this->EscapeForShell(rpath_link, escapeAllowMakeVars);
+ fout << " ";
+ }
+
+ // Add standard libraries for this language.
+ std::string standardLibsVar = "CMAKE_";
+ standardLibsVar += cli.GetLinkLanguage();
+ standardLibsVar += "_STANDARD_LIBRARIES";
+ if (const char* stdLibs = this->Makefile->GetDefinition(standardLibsVar)) {
+ fout << stdLibs << " ";
+ }
+
+ linkLibraries = fout.str();
+}
+
+void cmLocalGenerator::AddArchitectureFlags(std::string& flags,
+ cmGeneratorTarget const* target,
+ const std::string& lang,
+ const std::string& config)
+{
+ // Only add Mac OS X specific flags on Darwin platforms (OSX and iphone):
+ if (this->Makefile->IsOn("APPLE") && this->EmitUniversalBinaryFlags) {
+ std::vector<std::string> archs;
+ target->GetAppleArchs(config, archs);
+ const char* sysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT");
+ if (sysroot && sysroot[0] == '/' && !sysroot[1]) {
+ sysroot = CM_NULLPTR;
+ }
+ std::string sysrootFlagVar =
+ std::string("CMAKE_") + lang + "_SYSROOT_FLAG";
+ const char* sysrootFlag = this->Makefile->GetDefinition(sysrootFlagVar);
+ const char* deploymentTarget =
+ this->Makefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
+ std::string deploymentTargetFlagVar =
+ std::string("CMAKE_") + lang + "_OSX_DEPLOYMENT_TARGET_FLAG";
+ const char* deploymentTargetFlag =
+ this->Makefile->GetDefinition(deploymentTargetFlagVar);
+ if (!archs.empty() && !lang.empty() &&
+ (lang[0] == 'C' || lang[0] == 'F')) {
+ for (std::vector<std::string>::iterator i = archs.begin();
+ i != archs.end(); ++i) {
+ flags += " -arch ";
+ flags += *i;
+ }
+ }
+
+ if (sysrootFlag && *sysrootFlag && sysroot && *sysroot) {
+ flags += " ";
+ flags += sysrootFlag;
+ flags += " ";
+ flags += this->Convert(sysroot, NONE, SHELL);
+ }
+
+ if (deploymentTargetFlag && *deploymentTargetFlag && deploymentTarget &&
+ *deploymentTarget) {
+ flags += " ";
+ flags += deploymentTargetFlag;
+ flags += deploymentTarget;
+ }
+ }
+}
+
+void cmLocalGenerator::AddLanguageFlags(std::string& flags,
+ const std::string& lang,
+ const std::string& config)
+{
+ // Add language-specific flags.
+ std::string flagsVar = "CMAKE_";
+ flagsVar += lang;
+ flagsVar += "_FLAGS";
+ this->AddConfigVariableFlags(flags, flagsVar, config);
+}
+
+cmGeneratorTarget* cmLocalGenerator::FindGeneratorTargetToUse(
+ const std::string& name) const
+{
+ std::vector<cmGeneratorTarget*>::const_iterator imported = std::find_if(
+ this->ImportedGeneratorTargets.begin(),
+ this->ImportedGeneratorTargets.end(), NamedGeneratorTargetFinder(name));
+ if (imported != this->ImportedGeneratorTargets.end()) {
+ return *imported;
+ }
+
+ if (cmGeneratorTarget* t = this->FindLocalNonAliasGeneratorTarget(name)) {
+ return t;
+ }
+
+ return this->GetGlobalGenerator()->FindGeneratorTarget(name);
+}
+
+bool cmLocalGenerator::GetRealDependency(const std::string& inName,
+ const std::string& config,
+ std::string& dep)
+{
+ // Older CMake code may specify the dependency using the target
+ // output file rather than the target name. Such code would have
+ // been written before there was support for target properties that
+ // modify the name so stripping down to just the file name should
+ // produce the target name in this case.
+ std::string name = cmSystemTools::GetFilenameName(inName);
+
+ // If the input name is the empty string, there is no real
+ // dependency. Short-circuit the other checks:
+ if (name == "") {
+ return false;
+ }
+
+ if (cmSystemTools::GetFilenameLastExtension(name) == ".exe") {
+ name = cmSystemTools::GetFilenameWithoutLastExtension(name);
+ }
+
+ // Look for a CMake target with the given name.
+ if (cmGeneratorTarget* target = this->FindGeneratorTargetToUse(name)) {
+ // make sure it is not just a coincidence that the target name
+ // found is part of the inName
+ if (cmSystemTools::FileIsFullPath(inName.c_str())) {
+ std::string tLocation;
+ if (target->GetType() >= cmState::EXECUTABLE &&
+ target->GetType() <= cmState::MODULE_LIBRARY) {
+ tLocation = target->GetLocation(config);
+ tLocation = cmSystemTools::GetFilenamePath(tLocation);
+ tLocation = cmSystemTools::CollapseFullPath(tLocation);
+ }
+ std::string depLocation =
+ cmSystemTools::GetFilenamePath(std::string(inName));
+ depLocation = cmSystemTools::CollapseFullPath(depLocation);
+ if (depLocation != tLocation) {
+ // it is a full path to a depend that has the same name
+ // as a target but is in a different location so do not use
+ // the target as the depend
+ dep = inName;
+ return true;
+ }
+ }
+ switch (target->GetType()) {
+ case cmState::EXECUTABLE:
+ case cmState::STATIC_LIBRARY:
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ case cmState::UNKNOWN_LIBRARY:
+ dep = target->GetLocation(config);
+ return true;
+ case cmState::OBJECT_LIBRARY:
+ // An object library has no single file on which to depend.
+ // This was listed to get the target-level dependency.
+ return false;
+ case cmState::INTERFACE_LIBRARY:
+ // An interface library has no file on which to depend.
+ // This was listed to get the target-level dependency.
+ return false;
+ case cmState::UTILITY:
+ case cmState::GLOBAL_TARGET:
+ // A utility target has no file on which to depend. This was listed
+ // only to get the target-level dependency.
+ return false;
+ }
+ }
+
+ // The name was not that of a CMake target. It must name a file.
+ if (cmSystemTools::FileIsFullPath(inName.c_str())) {
+ // This is a full path. Return it as given.
+ dep = inName;
+ return true;
+ }
+
+ // Check for a source file in this directory that matches the
+ // dependency.
+ if (cmSourceFile* sf = this->Makefile->GetSource(inName)) {
+ dep = sf->GetFullPath();
+ return true;
+ }
+
+ // Treat the name as relative to the source directory in which it
+ // was given.
+ dep = this->StateSnapshot.GetDirectory().GetCurrentSource();
+ dep += "/";
+ dep += inName;
+ return true;
+}
+
+void cmLocalGenerator::AddSharedFlags(std::string& flags,
+ const std::string& lang, bool shared)
+{
+ std::string flagsVar;
+
+ // Add flags for dealing with shared libraries for this language.
+ if (shared) {
+ flagsVar = "CMAKE_SHARED_LIBRARY_";
+ flagsVar += lang;
+ flagsVar += "_FLAGS";
+ this->AppendFlags(flags, this->Makefile->GetDefinition(flagsVar));
+ }
+}
+
+void cmLocalGenerator::AddCompilerRequirementFlag(
+ std::string& flags, cmGeneratorTarget const* target, const std::string& lang)
+{
+ if (lang.empty()) {
+ return;
+ }
+ const char* defaultStd =
+ this->Makefile->GetDefinition("CMAKE_" + lang + "_STANDARD_DEFAULT");
+ if (!defaultStd || !*defaultStd) {
+ // This compiler has no notion of language standard levels.
+ return;
+ }
+ std::string stdProp = lang + "_STANDARD";
+ const char* standardProp = target->GetProperty(stdProp);
+ if (!standardProp) {
+ return;
+ }
+ std::string extProp = lang + "_EXTENSIONS";
+ std::string type = "EXTENSION";
+ bool ext = true;
+ if (const char* extPropValue = target->GetProperty(extProp)) {
+ if (cmSystemTools::IsOff(extPropValue)) {
+ ext = false;
+ type = "STANDARD";
+ }
+ }
+
+ if (target->GetPropertyAsBool(lang + "_STANDARD_REQUIRED")) {
+ std::string option_flag =
+ "CMAKE_" + lang + standardProp + "_" + type + "_COMPILE_OPTION";
+
+ const char* opt =
+ target->Target->GetMakefile()->GetDefinition(option_flag);
+ if (!opt) {
+ std::ostringstream e;
+ e << "Target \"" << target->GetName() << "\" requires the language "
+ "dialect \""
+ << lang << standardProp << "\" "
+ << (ext ? "(with compiler extensions)" : "")
+ << ", but CMake "
+ "does not know the compile flags to use to enable it.";
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ } else {
+ this->AppendFlagEscape(flags, opt);
+ }
+ return;
+ }
+
+ static std::map<std::string, std::vector<std::string> > langStdMap;
+ if (langStdMap.empty()) {
+ // Maintain sorted order, most recent first.
+ langStdMap["CXX"].push_back("14");
+ langStdMap["CXX"].push_back("11");
+ langStdMap["CXX"].push_back("98");
+
+ langStdMap["C"].push_back("11");
+ langStdMap["C"].push_back("99");
+ langStdMap["C"].push_back("90");
+ }
+
+ std::string standard(standardProp);
+
+ std::vector<std::string>& stds = langStdMap[lang];
+
+ std::vector<std::string>::const_iterator stdIt =
+ std::find(stds.begin(), stds.end(), standard);
+ if (stdIt == stds.end()) {
+ std::string e =
+ lang + "_STANDARD is set to invalid value '" + standard + "'";
+ this->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
+ cmake::FATAL_ERROR, e, target->GetBacktrace());
+ return;
+ }
+
+ std::vector<std::string>::const_iterator defaultStdIt =
+ std::find(stds.begin(), stds.end(), defaultStd);
+ if (defaultStdIt == stds.end()) {
+ std::string e = "CMAKE_" + lang +
+ "_STANDARD_DEFAULT is set to invalid value '" + std::string(defaultStd) +
+ "'";
+ this->IssueMessage(cmake::INTERNAL_ERROR, e);
+ return;
+ }
+
+ // Greater or equal because the standards are stored in
+ // backward chronological order.
+ if (stdIt >= defaultStdIt) {
+ std::string option_flag =
+ "CMAKE_" + lang + *stdIt + "_" + type + "_COMPILE_OPTION";
+
+ const char* opt =
+ target->Target->GetMakefile()->GetRequiredDefinition(option_flag);
+ this->AppendFlagEscape(flags, opt);
+ return;
+ }
+
+ for (; stdIt < defaultStdIt; ++stdIt) {
+ std::string option_flag =
+ "CMAKE_" + lang + *stdIt + "_" + type + "_COMPILE_OPTION";
+
+ if (const char* opt =
+ target->Target->GetMakefile()->GetDefinition(option_flag)) {
+ this->AppendFlagEscape(flags, opt);
+ return;
+ }
+ }
+}
+
+static void AddVisibilityCompileOption(std::string& flags,
+ cmGeneratorTarget const* target,
+ cmLocalGenerator* lg,
+ const std::string& lang,
+ std::string* warnCMP0063)
+{
+ std::string compileOption = "CMAKE_" + lang + "_COMPILE_OPTIONS_VISIBILITY";
+ const char* opt = lg->GetMakefile()->GetDefinition(compileOption);
+ if (!opt) {
+ return;
+ }
+ std::string flagDefine = lang + "_VISIBILITY_PRESET";
+
+ const char* prop = target->GetProperty(flagDefine);
+ if (!prop) {
+ return;
+ }
+ if (warnCMP0063) {
+ *warnCMP0063 += " " + flagDefine + "\n";
+ return;
+ }
+ if (strcmp(prop, "hidden") != 0 && strcmp(prop, "default") != 0 &&
+ strcmp(prop, "protected") != 0 && strcmp(prop, "internal") != 0) {
+ std::ostringstream e;
+ e << "Target " << target->GetName() << " uses unsupported value \"" << prop
+ << "\" for " << flagDefine << ".";
+ cmSystemTools::Error(e.str().c_str());
+ return;
+ }
+ std::string option = std::string(opt) + prop;
+ lg->AppendFlags(flags, option);
+}
+
+static void AddInlineVisibilityCompileOption(std::string& flags,
+ cmGeneratorTarget const* target,
+ cmLocalGenerator* lg,
+ std::string* warnCMP0063)
+{
+ std::string compileOption =
+ "CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN";
+ const char* opt = lg->GetMakefile()->GetDefinition(compileOption);
+ if (!opt) {
+ return;
+ }
+
+ bool prop = target->GetPropertyAsBool("VISIBILITY_INLINES_HIDDEN");
+ if (!prop) {
+ return;
+ }
+ if (warnCMP0063) {
+ *warnCMP0063 += " VISIBILITY_INLINES_HIDDEN\n";
+ return;
+ }
+ lg->AppendFlags(flags, opt);
+}
+
+void cmLocalGenerator::AddVisibilityPresetFlags(
+ std::string& flags, cmGeneratorTarget const* target, const std::string& lang)
+{
+ if (lang.empty()) {
+ return;
+ }
+
+ std::string warnCMP0063;
+ std::string* pWarnCMP0063 = CM_NULLPTR;
+ if (target->GetType() != cmState::SHARED_LIBRARY &&
+ target->GetType() != cmState::MODULE_LIBRARY &&
+ !target->IsExecutableWithExports()) {
+ switch (target->GetPolicyStatusCMP0063()) {
+ case cmPolicies::OLD:
+ return;
+ case cmPolicies::WARN:
+ pWarnCMP0063 = &warnCMP0063;
+ break;
+ default:
+ break;
+ }
+ }
+
+ AddVisibilityCompileOption(flags, target, this, lang, pWarnCMP0063);
+
+ if (lang == "CXX") {
+ AddInlineVisibilityCompileOption(flags, target, this, pWarnCMP0063);
+ }
+
+ if (!warnCMP0063.empty() && this->WarnCMP0063.insert(target).second) {
+ std::ostringstream w;
+ /* clang-format off */
+ w <<
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0063) << "\n"
+ "Target \"" << target->GetName() << "\" of "
+ "type \"" << cmState::GetTargetTypeName(target->GetType()) << "\" "
+ "has the following visibility properties set for " << lang << ":\n" <<
+ warnCMP0063 <<
+ "For compatibility CMake is not honoring them for this target.";
+ /* clang-format on */
+ target->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+ cmake::AUTHOR_WARNING, w.str(), target->GetBacktrace());
+ }
+}
+
+void cmLocalGenerator::AddCMP0018Flags(std::string& flags,
+ cmGeneratorTarget const* target,
+ std::string const& lang,
+ const std::string& config)
+{
+ int targetType = target->GetType();
+
+ bool shared = ((targetType == cmState::SHARED_LIBRARY) ||
+ (targetType == cmState::MODULE_LIBRARY));
+
+ if (this->GetShouldUseOldFlags(shared, lang)) {
+ this->AddSharedFlags(flags, lang, shared);
+ } else {
+ if (target->GetType() == cmState::OBJECT_LIBRARY) {
+ if (target->GetPropertyAsBool("POSITION_INDEPENDENT_CODE")) {
+ this->AddPositionIndependentFlags(flags, lang, targetType);
+ }
+ return;
+ }
+
+ if (target->GetLinkInterfaceDependentBoolProperty(
+ "POSITION_INDEPENDENT_CODE", config)) {
+ this->AddPositionIndependentFlags(flags, lang, targetType);
+ }
+ if (shared) {
+ this->AppendFeatureOptions(flags, lang, "DLL");
+ }
+ }
+}
+
+bool cmLocalGenerator::GetShouldUseOldFlags(bool shared,
+ const std::string& lang) const
+{
+ std::string originalFlags =
+ this->GlobalGenerator->GetSharedLibFlagsForLanguage(lang);
+ if (shared) {
+ std::string flagsVar = "CMAKE_SHARED_LIBRARY_";
+ flagsVar += lang;
+ flagsVar += "_FLAGS";
+ const char* flags = this->Makefile->GetSafeDefinition(flagsVar);
+
+ if (flags && flags != originalFlags) {
+ switch (this->GetPolicyStatus(cmPolicies::CMP0018)) {
+ case cmPolicies::WARN: {
+ std::ostringstream e;
+ e << "Variable " << flagsVar
+ << " has been modified. CMake "
+ "will ignore the POSITION_INDEPENDENT_CODE target property for "
+ "shared libraries and will use the "
+ << flagsVar
+ << " variable "
+ "instead. This may cause errors if the original content of "
+ << flagsVar << " was removed.\n"
+ << cmPolicies::GetPolicyWarning(cmPolicies::CMP0018);
+
+ this->IssueMessage(cmake::AUTHOR_WARNING, e.str());
+ // fall through to OLD behaviour
+ }
+ case cmPolicies::OLD:
+ return true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+void cmLocalGenerator::AddPositionIndependentFlags(std::string& flags,
+ std::string const& lang,
+ int targetType)
+{
+ const char* picFlags = CM_NULLPTR;
+
+ if (targetType == cmState::EXECUTABLE) {
+ std::string flagsVar = "CMAKE_";
+ flagsVar += lang;
+ flagsVar += "_COMPILE_OPTIONS_PIE";
+ picFlags = this->Makefile->GetSafeDefinition(flagsVar);
+ }
+ if (!picFlags) {
+ std::string flagsVar = "CMAKE_";
+ flagsVar += lang;
+ flagsVar += "_COMPILE_OPTIONS_PIC";
+ picFlags = this->Makefile->GetSafeDefinition(flagsVar);
+ }
+ if (picFlags) {
+ std::vector<std::string> options;
+ cmSystemTools::ExpandListArgument(picFlags, options);
+ for (std::vector<std::string>::const_iterator oi = options.begin();
+ oi != options.end(); ++oi) {
+ this->AppendFlagEscape(flags, *oi);
+ }
+ }
+}
+
+void cmLocalGenerator::AddConfigVariableFlags(std::string& flags,
+ const std::string& var,
+ const std::string& config)
+{
+ // Add the flags from the variable itself.
+ std::string flagsVar = var;
+ this->AppendFlags(flags, this->Makefile->GetDefinition(flagsVar));
+ // Add the flags from the build-type specific variable.
+ if (!config.empty()) {
+ flagsVar += "_";
+ flagsVar += cmSystemTools::UpperCase(config);
+ this->AppendFlags(flags, this->Makefile->GetDefinition(flagsVar));
+ }
+}
+
+void cmLocalGenerator::AppendFlags(std::string& flags,
+ const std::string& newFlags)
+{
+ if (!newFlags.empty()) {
+ if (!flags.empty()) {
+ flags += " ";
+ }
+ flags += newFlags;
+ }
+}
+
+void cmLocalGenerator::AppendFlags(std::string& flags, const char* newFlags)
+{
+ if (newFlags && *newFlags) {
+ this->AppendFlags(flags, std::string(newFlags));
+ }
+}
+
+void cmLocalGenerator::AppendFlagEscape(std::string& flags,
+ const std::string& rawFlag)
+{
+ this->AppendFlags(flags, this->EscapeForShell(rawFlag));
+}
+
+void cmLocalGenerator::AppendDefines(std::set<std::string>& defines,
+ const char* defines_list) const
+{
+ // Short-circuit if there are no definitions.
+ if (!defines_list) {
+ return;
+ }
+
+ // Expand the list of definitions.
+ std::vector<std::string> defines_vec;
+ cmSystemTools::ExpandListArgument(defines_list, defines_vec);
+ this->AppendDefines(defines, defines_vec);
+}
+
+void cmLocalGenerator::AppendDefines(
+ std::set<std::string>& defines,
+ const std::vector<std::string>& defines_vec) const
+{
+ for (std::vector<std::string>::const_iterator di = defines_vec.begin();
+ di != defines_vec.end(); ++di) {
+ // Skip unsupported definitions.
+ if (!this->CheckDefinition(*di)) {
+ continue;
+ }
+ defines.insert(*di);
+ }
+}
+
+void cmLocalGenerator::JoinDefines(const std::set<std::string>& defines,
+ std::string& definesString,
+ const std::string& lang)
+{
+ // Lookup the define flag for the current language.
+ std::string dflag = "-D";
+ if (!lang.empty()) {
+ std::string defineFlagVar = "CMAKE_";
+ defineFlagVar += lang;
+ defineFlagVar += "_DEFINE_FLAG";
+ const char* df = this->Makefile->GetDefinition(defineFlagVar);
+ if (df && *df) {
+ 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) {
+ // Append the definition with proper escaping.
+ std::string def = dflag;
+ if (this->GetState()->UseWatcomWMake()) {
+ // The Watcom compiler does its own command line parsing instead
+ // of using the windows shell rules. Definitions are one of
+ // -DNAME
+ // -DNAME=<cpp-token>
+ // -DNAME="c-string with spaces and other characters(?@#$)"
+ //
+ // Watcom will properly parse each of these cases from the
+ // 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) {
+ if (*c == '$' || *c == '#') {
+ def += '$';
+ }
+ def += *c;
+ }
+ } 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);
+ if (eq != defineIt->npos) {
+ def += "=";
+ def += this->EscapeForShell(defineIt->c_str() + eq + 1, true);
+ }
+ }
+ definesString += itemSeparator;
+ itemSeparator = " ";
+ definesString += def;
+ }
+}
+
+void cmLocalGenerator::AppendFeatureOptions(std::string& flags,
+ const std::string& lang,
+ const char* feature)
+{
+ std::string optVar = "CMAKE_";
+ optVar += lang;
+ optVar += "_COMPILE_OPTIONS_";
+ optVar += feature;
+ if (const char* optionList = this->Makefile->GetDefinition(optVar)) {
+ std::vector<std::string> options;
+ cmSystemTools::ExpandListArgument(optionList, options);
+ for (std::vector<std::string>::const_iterator oi = options.begin();
+ oi != options.end(); ++oi) {
+ this->AppendFlagEscape(flags, *oi);
+ }
+ }
+}
+
+const char* cmLocalGenerator::GetFeature(const std::string& feature,
+ const std::string& config)
+{
+ std::string featureName = feature;
+ // TODO: Define accumulation policy for features (prepend, append, replace).
+ // Currently we always replace.
+ if (!config.empty()) {
+ featureName += "_";
+ featureName += cmSystemTools::UpperCase(config);
+ }
+ cmState::Snapshot snp = this->StateSnapshot;
+ while (snp.IsValid()) {
+ if (const char* value = snp.GetDirectory().GetProperty(featureName)) {
+ return value;
+ }
+ snp = snp.GetBuildsystemDirectoryParent();
+ }
+ return CM_NULLPTR;
+}
+
+std::string cmLocalGenerator::GetProjectName() const
+{
+ return this->StateSnapshot.GetProjectName();
+}
+
+std::string cmLocalGenerator::ConstructComment(
+ cmCustomCommandGenerator const& ccg, const char* default_comment)
+{
+ // Check for a comment provided with the command.
+ if (ccg.GetComment()) {
+ return ccg.GetComment();
+ }
+
+ // Construct a reasonable default comment if possible.
+ if (!ccg.GetOutputs().empty()) {
+ std::string comment;
+ comment = "Generating ";
+ const char* sep = "";
+ for (std::vector<std::string>::const_iterator o = ccg.GetOutputs().begin();
+ o != ccg.GetOutputs().end(); ++o) {
+ comment += sep;
+ comment += this->Convert(*o, cmOutputConverter::START_OUTPUT);
+ sep = ", ";
+ }
+ return comment;
+ }
+
+ // Otherwise use the provided default.
+ return default_comment;
+}
+
+class cmInstallTargetGeneratorLocal : public cmInstallTargetGenerator
+{
+public:
+ cmInstallTargetGeneratorLocal(cmLocalGenerator* lg, std::string const& t,
+ const char* dest, bool implib)
+ : cmInstallTargetGenerator(
+ t, dest, implib, "", std::vector<std::string>(), "Unspecified",
+ cmInstallGenerator::SelectMessageLevel(lg->GetMakefile()), false,
+ false)
+ {
+ this->Compute(lg);
+ }
+};
+
+void cmLocalGenerator::GenerateTargetInstallRules(
+ std::ostream& os, const std::string& config,
+ std::vector<std::string> const& configurationTypes)
+{
+ // Convert the old-style install specification from each target to
+ // an install generator and run it.
+ std::vector<cmGeneratorTarget*> tgts = this->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator l = tgts.begin();
+ l != tgts.end(); ++l) {
+ if ((*l)->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+
+ // Include the user-specified pre-install script for this target.
+ if (const char* preinstall = (*l)->GetProperty("PRE_INSTALL_SCRIPT")) {
+ cmInstallScriptGenerator g(preinstall, false, CM_NULLPTR, false);
+ g.Generate(os, config, configurationTypes);
+ }
+
+ // Install this target if a destination is given.
+ if ((*l)->Target->GetInstallPath() != "") {
+ // Compute the full install destination. Note that converting
+ // to unix slashes also removes any trailing slash.
+ // We also skip over the leading slash given by the user.
+ std::string destination = (*l)->Target->GetInstallPath().substr(1);
+ cmSystemTools::ConvertToUnixSlashes(destination);
+ if (destination.empty()) {
+ destination = ".";
+ }
+
+ // Generate the proper install generator for this target type.
+ switch ((*l)->GetType()) {
+ case cmState::EXECUTABLE:
+ case cmState::STATIC_LIBRARY:
+ case cmState::MODULE_LIBRARY: {
+ // Use a target install generator.
+ cmInstallTargetGeneratorLocal g(this, (*l)->GetName(),
+ destination.c_str(), false);
+ g.Generate(os, config, configurationTypes);
+ } break;
+ case cmState::SHARED_LIBRARY: {
+#if defined(_WIN32) || defined(__CYGWIN__)
+ // Special code to handle DLL. Install the import library
+ // to the normal destination and the DLL to the runtime
+ // destination.
+ cmInstallTargetGeneratorLocal g1(this, (*l)->GetName(),
+ destination.c_str(), true);
+ g1.Generate(os, config, configurationTypes);
+ // We also skip over the leading slash given by the user.
+ destination = (*l)->Target->GetRuntimeInstallPath().substr(1);
+ cmSystemTools::ConvertToUnixSlashes(destination);
+ cmInstallTargetGeneratorLocal g2(this, (*l)->GetName(),
+ destination.c_str(), false);
+ g2.Generate(os, config, configurationTypes);
+#else
+ // Use a target install generator.
+ cmInstallTargetGeneratorLocal g(this, (*l)->GetName(),
+ destination.c_str(), false);
+ g.Generate(os, config, configurationTypes);
+#endif
+ } break;
+ default:
+ break;
+ }
+ }
+
+ // Include the user-specified post-install script for this target.
+ if (const char* postinstall = (*l)->GetProperty("POST_INSTALL_SCRIPT")) {
+ cmInstallScriptGenerator g(postinstall, false, CM_NULLPTR, false);
+ g.Generate(os, config, configurationTypes);
+ }
+ }
+}
+
+#if defined(CM_LG_ENCODE_OBJECT_NAMES)
+static std::string cmLocalGeneratorMD5(const char* input)
+{
+ char md5out[32];
+ cmsysMD5* md5 = cmsysMD5_New();
+ cmsysMD5_Initialize(md5);
+ cmsysMD5_Append(md5, reinterpret_cast<unsigned char const*>(input), -1);
+ cmsysMD5_FinalizeHex(md5, md5out);
+ cmsysMD5_Delete(md5);
+ return std::string(md5out, 32);
+}
+
+static bool cmLocalGeneratorShortenObjectName(std::string& objName,
+ std::string::size_type max_len)
+{
+ // Replace the beginning of the path portion of the object name with
+ // its own md5 sum.
+ std::string::size_type pos =
+ objName.find('/', objName.size() - max_len + 32);
+ if (pos != objName.npos) {
+ std::string md5name = cmLocalGeneratorMD5(objName.substr(0, pos).c_str());
+ md5name += objName.substr(pos);
+ objName = md5name;
+
+ // The object name is now short enough.
+ return true;
+ } else {
+ // The object name could not be shortened enough.
+ return false;
+ }
+}
+
+bool cmLocalGeneratorCheckObjectName(std::string& objName,
+ std::string::size_type dir_len,
+ std::string::size_type max_total_len)
+{
+ // Enforce the maximum file name length if possible.
+ std::string::size_type max_obj_len = max_total_len;
+ if (dir_len < max_total_len) {
+ max_obj_len = max_total_len - dir_len;
+ if (objName.size() > max_obj_len) {
+ // The current object file name is too long. Try to shorten it.
+ return cmLocalGeneratorShortenObjectName(objName, max_obj_len);
+ } else {
+ // The object file name is short enough.
+ return true;
+ }
+ } else {
+ // The build directory in which the object will be stored is
+ // already too deep.
+ return false;
+ }
+}
+#endif
+
+std::string& cmLocalGenerator::CreateSafeUniqueObjectFileName(
+ const std::string& sin, std::string const& dir_max)
+{
+ // Look for an existing mapped name for this object file.
+ std::map<std::string, std::string>::iterator it =
+ this->UniqueObjectNamesMap.find(sin);
+
+ // If no entry exists create one.
+ if (it == this->UniqueObjectNamesMap.end()) {
+ // Start with the original name.
+ std::string ssin = sin;
+
+ // Avoid full paths by removing leading slashes.
+ ssin.erase(0, ssin.find_first_not_of('/'));
+
+ // Avoid full paths by removing colons.
+ std::replace(ssin.begin(), ssin.end(), ':', '_');
+
+ // Avoid relative paths that go up the tree.
+ cmSystemTools::ReplaceString(ssin, "../", "__/");
+
+ // Avoid spaces.
+ std::replace(ssin.begin(), ssin.end(), ' ', '_');
+
+ // Mangle the name if necessary.
+ if (this->Makefile->IsOn("CMAKE_MANGLE_OBJECT_FILE_NAMES")) {
+ bool done;
+ int cc = 0;
+ char rpstr[100];
+ sprintf(rpstr, "_p_");
+ cmSystemTools::ReplaceString(ssin, "+", rpstr);
+ std::string sssin = sin;
+ do {
+ done = true;
+ for (it = this->UniqueObjectNamesMap.begin();
+ it != this->UniqueObjectNamesMap.end(); ++it) {
+ if (it->second == ssin) {
+ done = false;
+ }
+ }
+ if (done) {
+ break;
+ }
+ sssin = ssin;
+ cmSystemTools::ReplaceString(ssin, "_p_", rpstr);
+ sprintf(rpstr, "_p%d_", cc++);
+ } while (!done);
+ }
+
+#if defined(CM_LG_ENCODE_OBJECT_NAMES)
+ if (!cmLocalGeneratorCheckObjectName(ssin, dir_max.size(),
+ this->ObjectPathMax)) {
+ // Warn if this is the first time the path has been seen.
+ if (this->ObjectMaxPathViolations.insert(dir_max).second) {
+ std::ostringstream m;
+ /* clang-format off */
+ m << "The object file directory\n"
+ << " " << dir_max << "\n"
+ << "has " << dir_max.size() << " characters. "
+ << "The maximum full path to an object file is "
+ << this->ObjectPathMax << " characters "
+ << "(see CMAKE_OBJECT_PATH_MAX). "
+ << "Object file\n"
+ << " " << ssin << "\n"
+ << "cannot be safely placed under this directory. "
+ << "The build may not work correctly.";
+ /* clang-format on */
+ this->IssueMessage(cmake::WARNING, m.str());
+ }
+ }
+#else
+ (void)dir_max;
+#endif
+
+ // Insert the newly mapped object file name.
+ std::map<std::string, std::string>::value_type e(sin, ssin);
+ it = this->UniqueObjectNamesMap.insert(e).first;
+ }
+
+ // Return the map entry.
+ return it->second;
+}
+
+void cmLocalGenerator::ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>&, cmGeneratorTarget const*)
+{
+}
+
+bool cmLocalGenerator::IsWindowsShell() const
+{
+ return this->GetState()->UseWindowsShell();
+}
+
+bool cmLocalGenerator::IsWatcomWMake() const
+{
+ return this->GetState()->UseWatcomWMake();
+}
+
+bool cmLocalGenerator::IsMinGWMake() const
+{
+ return this->GetState()->UseMinGWMake();
+}
+
+bool cmLocalGenerator::IsNMake() const
+{
+ return this->GetState()->UseNMake();
+}
+
+std::string cmLocalGenerator::GetObjectFileNameWithoutTarget(
+ const cmSourceFile& source, std::string const& dir_max,
+ bool* hasSourceExtension)
+{
+ // Construct the object file name using the full path to the source
+ // file which is its only unique identification.
+ const char* fullPath = source.GetFullPath().c_str();
+
+ // Try referencing the source relative to the source tree.
+ std::string relFromSource = this->Convert(fullPath, START);
+ assert(!relFromSource.empty());
+ bool relSource = !cmSystemTools::FileIsFullPath(relFromSource.c_str());
+ bool subSource = relSource && relFromSource[0] != '.';
+
+ // Try referencing the source relative to the binary tree.
+ std::string relFromBinary = this->Convert(fullPath, START_OUTPUT);
+ assert(!relFromBinary.empty());
+ bool relBinary = !cmSystemTools::FileIsFullPath(relFromBinary.c_str());
+ bool subBinary = relBinary && relFromBinary[0] != '.';
+
+ // Select a nice-looking reference to the source file to construct
+ // the object file name.
+ std::string objectName;
+ if ((relSource && !relBinary) || (subSource && !subBinary)) {
+ objectName = relFromSource;
+ } else if ((relBinary && !relSource) || (subBinary && !subSource)) {
+ objectName = relFromBinary;
+ } else if (relFromBinary.length() < relFromSource.length()) {
+ objectName = relFromBinary;
+ } else {
+ objectName = relFromSource;
+ }
+
+ // if it is still a full path check for the try compile case
+ // try compile never have in source sources, and should not
+ // have conflicting source file names in the same target
+ if (cmSystemTools::FileIsFullPath(objectName.c_str())) {
+ if (this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) {
+ objectName = cmSystemTools::GetFilenameName(source.GetFullPath());
+ }
+ }
+
+ // Replace the original source file extension with the object file
+ // extension.
+ bool keptSourceExtension = true;
+ if (!source.GetPropertyAsBool("KEEP_EXTENSION")) {
+ // Decide whether this language wants to replace the source
+ // extension with the object extension. For CMake 2.4
+ // compatibility do this by default.
+ bool replaceExt = this->NeedBackwardsCompatibility_2_4();
+ if (!replaceExt) {
+ std::string lang = source.GetLanguage();
+ if (!lang.empty()) {
+ std::string repVar = "CMAKE_";
+ repVar += lang;
+ repVar += "_OUTPUT_EXTENSION_REPLACE";
+ replaceExt = this->Makefile->IsOn(repVar);
+ }
+ }
+
+ // Remove the source extension if it is to be replaced.
+ if (replaceExt) {
+ keptSourceExtension = false;
+ std::string::size_type dot_pos = objectName.rfind('.');
+ if (dot_pos != std::string::npos) {
+ objectName = objectName.substr(0, dot_pos);
+ }
+ }
+
+ // Store the new extension.
+ objectName += this->GlobalGenerator->GetLanguageOutputExtension(source);
+ }
+ if (hasSourceExtension) {
+ *hasSourceExtension = keptSourceExtension;
+ }
+
+ // Convert to a safe name.
+ return this->CreateSafeUniqueObjectFileName(objectName, dir_max);
+}
+
+std::string cmLocalGenerator::GetSourceFileLanguage(const cmSourceFile& source)
+{
+ return source.GetLanguage();
+}
+
+cmake* cmLocalGenerator::GetCMakeInstance() const
+{
+ return this->GlobalGenerator->GetCMakeInstance();
+}
+
+const char* cmLocalGenerator::GetSourceDirectory() const
+{
+ return this->GetCMakeInstance()->GetHomeDirectory();
+}
+
+const char* cmLocalGenerator::GetBinaryDirectory() const
+{
+ return this->GetCMakeInstance()->GetHomeOutputDirectory();
+}
+
+const char* cmLocalGenerator::GetCurrentBinaryDirectory() const
+{
+ return this->StateSnapshot.GetDirectory().GetCurrentBinary();
+}
+
+const char* cmLocalGenerator::GetCurrentSourceDirectory() const
+{
+ return this->StateSnapshot.GetDirectory().GetCurrentSource();
+}
+
+std::string cmLocalGenerator::GetTargetDirectory(
+ const cmGeneratorTarget*) const
+{
+ cmSystemTools::Error("GetTargetDirectory"
+ " called on cmLocalGenerator");
+ return "";
+}
+
+KWIML_INT_uint64_t cmLocalGenerator::GetBackwardsCompatibility()
+{
+ // The computed version may change until the project is fully
+ // configured.
+ if (!this->BackwardsCompatibilityFinal) {
+ unsigned int major = 0;
+ unsigned int minor = 0;
+ unsigned int patch = 0;
+ if (const char* value =
+ this->Makefile->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY")) {
+ switch (sscanf(value, "%u.%u.%u", &major, &minor, &patch)) {
+ case 2:
+ patch = 0;
+ break;
+ case 1:
+ minor = 0;
+ patch = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ this->BackwardsCompatibility = CMake_VERSION_ENCODE(major, minor, patch);
+ this->BackwardsCompatibilityFinal = true;
+ }
+
+ return this->BackwardsCompatibility;
+}
+
+bool cmLocalGenerator::NeedBackwardsCompatibility_2_4()
+{
+ // Check the policy to decide whether to pay attention to this
+ // variable.
+ switch (this->GetPolicyStatus(cmPolicies::CMP0001)) {
+ case cmPolicies::WARN:
+ // WARN is just OLD without warning because user code does not
+ // always affect whether this check is done.
+ case cmPolicies::OLD:
+ // Old behavior is to check the variable.
+ break;
+ case cmPolicies::NEW:
+ // New behavior is to ignore the variable.
+ return false;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ // This will never be the case because the only way to require
+ // the setting is to require the user to specify version policy
+ // 2.6 or higher. Once we add that requirement then this whole
+ // method can be removed anyway.
+ return false;
+ }
+
+ // Compatibility is needed if CMAKE_BACKWARDS_COMPATIBILITY is set
+ // equal to or lower than the given version.
+ KWIML_INT_uint64_t actual_compat = this->GetBackwardsCompatibility();
+ return (actual_compat && actual_compat <= CMake_VERSION_ENCODE(2, 4, 255));
+}
+
+cmPolicies::PolicyStatus cmLocalGenerator::GetPolicyStatus(
+ cmPolicies::PolicyID id) const
+{
+ return this->Makefile->GetPolicyStatus(id);
+}
+
+bool cmLocalGenerator::CheckDefinition(std::string const& define) const
+{
+ // Many compilers do not support -DNAME(arg)=sdf so we disable it.
+ std::string::size_type pos = define.find_first_of("(=");
+ if (pos != std::string::npos) {
+ if (define[pos] == '(') {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "WARNING: Function-style preprocessor definitions may not be "
+ << "passed on the compiler command line because many compilers "
+ << "do not support it.\n"
+ << "CMake is dropping a preprocessor definition: " << define << "\n"
+ << "Consider defining the macro in a (configured) header file.\n";
+ /* clang-format on */
+ cmSystemTools::Message(e.str().c_str());
+ return false;
+ }
+ }
+
+ // Many compilers do not support # in the value so we disable it.
+ if (define.find_first_of('#') != define.npos) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "WARNING: Preprocessor definitions containing '#' may not be "
+ << "passed on the compiler command line because many compilers "
+ << "do not support it.\n"
+ << "CMake is dropping a preprocessor definition: " << define << "\n"
+ << "Consider defining the macro in a (configured) header file.\n";
+ /* clang-format on */
+ cmSystemTools::Message(e.str().c_str());
+ return false;
+ }
+
+ // Assume it is supported.
+ return true;
+}
+
+static void cmLGInfoProp(cmMakefile* mf, cmGeneratorTarget* target,
+ const std::string& prop)
+{
+ if (const char* val = target->GetProperty(prop)) {
+ mf->AddDefinition(prop, val);
+ }
+}
+
+void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target,
+ const std::string& targetName,
+ const char* fname)
+{
+ // Find the Info.plist template.
+ const char* in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST");
+ std::string inFile = (in && *in) ? in : "MacOSXBundleInfo.plist.in";
+ if (!cmSystemTools::FileIsFullPath(inFile.c_str())) {
+ std::string inMod = this->Makefile->GetModulesFile(inFile.c_str());
+ if (!inMod.empty()) {
+ inFile = inMod;
+ }
+ }
+ if (!cmSystemTools::FileExists(inFile.c_str(), true)) {
+ std::ostringstream e;
+ e << "Target " << target->GetName() << " Info.plist template \"" << inFile
+ << "\" could not be found.";
+ cmSystemTools::Error(e.str().c_str());
+ return;
+ }
+
+ // Convert target properties to variables in an isolated makefile
+ // scope to configure the file. If properties are set they will
+ // override user make variables. If not the configuration will fall
+ // back to the directory-level values set by the user.
+ cmMakefile* mf = this->Makefile;
+ cmMakefile::ScopePushPop varScope(mf);
+ mf->AddDefinition("MACOSX_BUNDLE_EXECUTABLE_NAME", targetName.c_str());
+ cmLGInfoProp(mf, target, "MACOSX_BUNDLE_INFO_STRING");
+ cmLGInfoProp(mf, target, "MACOSX_BUNDLE_ICON_FILE");
+ cmLGInfoProp(mf, target, "MACOSX_BUNDLE_GUI_IDENTIFIER");
+ cmLGInfoProp(mf, target, "MACOSX_BUNDLE_LONG_VERSION_STRING");
+ cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_NAME");
+ 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);
+}
+
+void cmLocalGenerator::GenerateFrameworkInfoPList(
+ cmGeneratorTarget* target, const std::string& targetName, const char* fname)
+{
+ // Find the Info.plist template.
+ const char* in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST");
+ std::string inFile = (in && *in) ? in : "MacOSXFrameworkInfo.plist.in";
+ if (!cmSystemTools::FileIsFullPath(inFile.c_str())) {
+ std::string inMod = this->Makefile->GetModulesFile(inFile.c_str());
+ if (!inMod.empty()) {
+ inFile = inMod;
+ }
+ }
+ if (!cmSystemTools::FileExists(inFile.c_str(), true)) {
+ std::ostringstream e;
+ e << "Target " << target->GetName() << " Info.plist template \"" << inFile
+ << "\" could not be found.";
+ cmSystemTools::Error(e.str().c_str());
+ return;
+ }
+
+ // Convert target properties to variables in an isolated makefile
+ // scope to configure the file. If properties are set they will
+ // override user make variables. If not the configuration will fall
+ // back to the directory-level values set by the user.
+ cmMakefile* mf = this->Makefile;
+ cmMakefile::ScopePushPop varScope(mf);
+ mf->AddDefinition("MACOSX_FRAMEWORK_NAME", targetName.c_str());
+ cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_ICON_FILE");
+ 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);
+}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
new file mode 100644
index 0000000..fa4bb30
--- /dev/null
+++ b/Source/cmLocalGenerator.h
@@ -0,0 +1,418 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLocalGenerator_h
+#define cmLocalGenerator_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmOutputConverter.h"
+#include "cmState.h"
+#include "cmake.h"
+
+class cmMakefile;
+class cmGlobalGenerator;
+class cmGeneratorTarget;
+class cmTargetManifest;
+class cmSourceFile;
+class cmCustomCommand;
+class cmCustomCommandGenerator;
+
+/** \class cmLocalGenerator
+ * \brief Create required build files for a directory.
+ *
+ * Subclasses of this abstract class generate makefiles, DSP, etc for various
+ * platforms. This class should never be constructed directly. A
+ * GlobalGenerator will create it and invoke the appropriate commands on it.
+ */
+class cmLocalGenerator : public cmOutputConverter
+{
+public:
+ cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile);
+ virtual ~cmLocalGenerator();
+
+ /**
+ * Generate the makefile for this directory.
+ */
+ virtual void Generate() {}
+
+ virtual void ComputeHomeRelativeOutputPath() {}
+
+ /**
+ * Calls TraceVSDependencies() on all targets of this generator.
+ */
+ void TraceDependencies();
+
+ virtual void AddHelperCommands() {}
+
+ /**
+ * Generate the install rules files in this directory.
+ */
+ void GenerateInstallRules();
+
+ /**
+ * Generate the test files for tests.
+ */
+ void GenerateTestFiles();
+
+ /**
+ * Generate a manifest of target files that will be built.
+ */
+ void ComputeTargetManifest();
+
+ bool IsRootMakefile() const;
+
+ ///! Get the makefile for this generator
+ cmMakefile* GetMakefile() { return this->Makefile; }
+
+ ///! Get the makefile for this generator, const version
+ const cmMakefile* GetMakefile() const { return this->Makefile; }
+
+ ///! Get the GlobalGenerator this is associated with
+ cmGlobalGenerator* GetGlobalGenerator() { return this->GlobalGenerator; }
+ const cmGlobalGenerator* GetGlobalGenerator() const
+ {
+ return this->GlobalGenerator;
+ }
+
+ cmState* GetState() const;
+ cmState::Snapshot GetStateSnapshot() const;
+
+ void AddArchitectureFlags(std::string& flags,
+ cmGeneratorTarget const* target,
+ const std::string& lang,
+ const std::string& config);
+
+ void AddLanguageFlags(std::string& flags, const std::string& lang,
+ const std::string& config);
+ void AddCMP0018Flags(std::string& flags, cmGeneratorTarget const* target,
+ std::string const& lang, const std::string& config);
+ void AddVisibilityPresetFlags(std::string& flags,
+ cmGeneratorTarget const* target,
+ const std::string& lang);
+ void AddConfigVariableFlags(std::string& flags, const std::string& var,
+ const std::string& config);
+ void AddCompilerRequirementFlag(std::string& flags,
+ cmGeneratorTarget const* target,
+ const std::string& lang);
+ ///! Append flags to a string.
+ virtual void AppendFlags(std::string& flags, const std::string& newFlags);
+ virtual void AppendFlags(std::string& flags, const char* newFlags);
+ virtual void AppendFlagEscape(std::string& flags,
+ const std::string& rawFlag);
+ ///! 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,
+ bool forceFullPaths = false,
+ bool forResponseFile = false,
+ const std::string& config = "");
+
+ const std::vector<cmGeneratorTarget*>& GetGeneratorTargets() const
+ {
+ return this->GeneratorTargets;
+ }
+
+ const std::vector<cmGeneratorTarget*>& GetImportedGeneratorTargets() const
+ {
+ return this->ImportedGeneratorTargets;
+ }
+
+ void AddGeneratorTarget(cmGeneratorTarget* gt);
+ void AddImportedGeneratorTarget(cmGeneratorTarget* gt);
+ void AddOwnedImportedGeneratorTarget(cmGeneratorTarget* gt);
+
+ cmGeneratorTarget* FindLocalNonAliasGeneratorTarget(
+ const std::string& name) const;
+ cmGeneratorTarget* FindGeneratorTargetToUse(const std::string& name) const;
+
+ /**
+ * Encode a list of preprocessor definitions for the compiler
+ * command line.
+ */
+ void AppendDefines(std::set<std::string>& defines,
+ const char* defines_list) const;
+ void AppendDefines(std::set<std::string>& defines,
+ std::string defines_list) const
+ {
+ this->AppendDefines(defines, defines_list.c_str());
+ }
+ void AppendDefines(std::set<std::string>& defines,
+ const std::vector<std::string>& defines_vec) const;
+
+ /**
+ * Join a set of defines into a definesString with a space separator.
+ */
+ void JoinDefines(const std::set<std::string>& defines,
+ std::string& definesString, const std::string& lang);
+
+ /** Lookup and append options associated with a particular feature. */
+ void AppendFeatureOptions(std::string& flags, const std::string& lang,
+ const char* feature);
+
+ const char* GetFeature(const std::string& feature,
+ const std::string& config);
+
+ /** \brief Get absolute path to dependency \a name
+ *
+ * Translate a dependency as given in CMake code to the name to
+ * appear in a generated build file.
+ * - If \a name is a utility target, returns false.
+ * - If \a name is a CMake target, it will be transformed to the real output
+ * location of that target for the given configuration.
+ * - If \a name is the full path to a file, it will be returned.
+ * - Otherwise \a name is treated as a relative path with respect to
+ * the source directory of this generator. This should only be
+ * used for dependencies of custom commands.
+ */
+ bool GetRealDependency(const std::string& name, const std::string& config,
+ std::string& dep);
+
+ virtual std::string ConvertToIncludeReference(
+ std::string const& path,
+ cmOutputConverter::OutputFormat format = cmOutputConverter::SHELL,
+ bool forceFullPaths = false);
+
+ /** Called from command-line hook to clear dependencies. */
+ virtual void ClearDependencies(cmMakefile* /* mf */, bool /* verbose */) {}
+
+ /** Called from command-line hook to update dependencies. */
+ virtual bool UpdateDependencies(const char* /* tgtInfo */, bool /*verbose*/,
+ bool /*color*/)
+ {
+ return true;
+ }
+
+ /** Get the include flags for the current makefile and language. */
+ void GetIncludeDirectories(std::vector<std::string>& dirs,
+ cmGeneratorTarget const* target,
+ const std::string& lang = "C",
+ const std::string& config = "",
+ bool stripImplicitInclDirs = true) const;
+ void AddCompileOptions(std::string& flags, cmGeneratorTarget* target,
+ const std::string& lang, const std::string& config);
+ void AddCompileDefinitions(std::set<std::string>& defines,
+ cmGeneratorTarget const* target,
+ const std::string& config,
+ const std::string& lang) const;
+
+ std::string GetProjectName() const;
+
+ /** Compute the language used to compile the given source file. */
+ std::string GetSourceFileLanguage(const cmSourceFile& source);
+
+ // Fill the vector with the target names for the object files,
+ // preprocessed files and assembly files.
+ void GetIndividualFileTargets(std::vector<std::string>&) {}
+
+ // Create a struct to hold the varibles passed into
+ // ExpandRuleVariables
+ struct RuleVariables
+ {
+ RuleVariables() { memset(this, 0, sizeof(*this)); }
+ cmGeneratorTarget* CMTarget;
+ const char* TargetPDB;
+ const char* TargetCompilePDB;
+ const char* TargetVersionMajor;
+ const char* TargetVersionMinor;
+ const char* Language;
+ const char* Objects;
+ const char* Target;
+ const char* LinkLibraries;
+ const char* Source;
+ const char* AssemblySource;
+ const char* PreprocessedSource;
+ const char* Output;
+ const char* Object;
+ const char* ObjectDir;
+ const char* ObjectFileDir;
+ const char* Flags;
+ const char* ObjectsQuoted;
+ const char* SONameFlag;
+ const char* TargetSOName;
+ const char* TargetInstallNameDir;
+ const char* LinkFlags;
+ const char* Manifests;
+ const char* LanguageCompileFlags;
+ const char* Defines;
+ const char* Includes;
+ const char* RuleLauncher;
+ const char* DependencyFile;
+ const char* FilterPrefix;
+ };
+
+ /**
+ * Get the relative path from the generator output directory to a
+ * per-target support directory.
+ */
+ virtual std::string GetTargetDirectory(
+ cmGeneratorTarget const* target) const;
+
+ /**
+ * Get the level of backwards compatibility requested by the project
+ * in this directory. This is the value of the CMake variable
+ * CMAKE_BACKWARDS_COMPATIBILITY whose format is
+ * "major.minor[.patch]". The returned integer is encoded as
+ *
+ * CMake_VERSION_ENCODE(major, minor, patch)
+ *
+ * and is monotonically increasing with the CMake version.
+ */
+ KWIML_INT_uint64_t GetBackwardsCompatibility();
+
+ /**
+ * Test whether compatibility is set to a given version or lower.
+ */
+ bool NeedBackwardsCompatibility_2_4();
+
+ cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id) const;
+
+ cmake* GetCMakeInstance() const;
+
+ const char* GetSourceDirectory() const;
+ const char* GetBinaryDirectory() const;
+
+ const char* GetCurrentBinaryDirectory() const;
+ const char* GetCurrentSourceDirectory() const;
+
+ /**
+ * Generate a Mac OS X application bundle Info.plist file.
+ */
+ void GenerateAppleInfoPList(cmGeneratorTarget* target,
+ const std::string& targetName,
+ const char* fname);
+
+ /**
+ * Generate a Mac OS X framework Info.plist file.
+ */
+ void GenerateFrameworkInfoPList(cmGeneratorTarget* target,
+ const std::string& targetName,
+ const char* fname);
+ /** Construct a comment for a custom command. */
+ std::string ConstructComment(cmCustomCommandGenerator const& ccg,
+ const char* default_comment = "");
+ // Compute object file names.
+ std::string GetObjectFileNameWithoutTarget(
+ const cmSourceFile& source, std::string const& dir_max,
+ bool* hasSourceExtension = CM_NULLPTR);
+
+ /** Fill out the static linker flags for the given target. */
+ void GetStaticLibraryFlags(std::string& flags, std::string const& config,
+ cmGeneratorTarget* target);
+
+ /** Fill out these strings for the given target. Libraries to link,
+ * flags, and linkflags. */
+ void GetTargetFlags(const std::string& config, std::string& linkLibs,
+ std::string& flags, std::string& linkFlags,
+ std::string& frameworkPath, std::string& linkPath,
+ cmGeneratorTarget* target, bool useWatcomQuote);
+ void GetTargetDefines(cmGeneratorTarget const* target,
+ std::string const& config, std::string const& lang,
+ std::set<std::string>& defines) const;
+ void GetTargetCompileFlags(cmGeneratorTarget* target,
+ std::string const& config,
+ std::string const& lang, std::string& flags);
+
+ std::string GetFrameworkFlags(std::string const& l,
+ std::string const& config,
+ cmGeneratorTarget* target);
+ virtual std::string GetTargetFortranFlags(cmGeneratorTarget const* target,
+ std::string const& config);
+
+ virtual void ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt = CM_NULLPTR);
+
+ bool IsWindowsShell() const;
+ bool IsWatcomWMake() const;
+ bool IsMinGWMake() const;
+ bool IsNMake() const;
+
+ void IssueMessage(cmake::MessageType t, std::string const& text) const;
+
+ void CreateEvaluationFileOutputs(const std::string& config);
+ void ProcessEvaluationFiles(std::vector<std::string>& generatedFiles);
+
+protected:
+ ///! put all the libraries for a target on into the given stream
+ void OutputLinkLibraries(std::string& linkLibraries,
+ std::string& frameworkPath, std::string& linkPath,
+ cmGeneratorTarget&, bool relink,
+ bool forResponseFile, bool useWatcomQuote);
+
+ // Expand rule variables in CMake of the type found in language rules
+ void ExpandRuleVariables(std::string& string,
+ const RuleVariables& replaceValues);
+ // Expand rule variables in a single string
+ std::string ExpandRuleVariable(std::string const& variable,
+ const RuleVariables& replaceValues);
+
+ const char* GetRuleLauncher(cmGeneratorTarget* target,
+ const std::string& prop);
+ void InsertRuleLauncher(std::string& s, cmGeneratorTarget* target,
+ const std::string& prop);
+
+ // Handle old-style install rules stored in the targets.
+ void GenerateTargetInstallRules(
+ std::ostream& os, const std::string& config,
+ std::vector<std::string> const& configurationTypes);
+
+ std::string& CreateSafeUniqueObjectFileName(const std::string& sin,
+ std::string const& dir_max);
+
+ virtual std::string ConvertToLinkReference(
+ std::string const& lib,
+ cmOutputConverter::OutputFormat format = cmOutputConverter::SHELL);
+
+ /** Check whether the native build system supports the given
+ definition. Issues a warning. */
+ virtual bool CheckDefinition(std::string const& define) const;
+
+ cmMakefile* Makefile;
+ cmState::Snapshot StateSnapshot;
+ cmListFileBacktrace DirectoryBacktrace;
+ cmGlobalGenerator* GlobalGenerator;
+ std::map<std::string, std::string> UniqueObjectNamesMap;
+ std::string::size_type ObjectPathMax;
+ std::set<std::string> ObjectMaxPathViolations;
+
+ std::set<cmGeneratorTarget const*> WarnCMP0063;
+ std::vector<cmGeneratorTarget*> GeneratorTargets;
+ std::vector<cmGeneratorTarget*> ImportedGeneratorTargets;
+ std::vector<cmGeneratorTarget*> OwnedImportedGeneratorTargets;
+ std::map<std::string, std::string> AliasTargets;
+
+ bool EmitUniversalBinaryFlags;
+
+ // Hack for ExpandRuleVariable until object-oriented version is
+ // committed.
+ std::string TargetImplib;
+
+ KWIML_INT_uint64_t BackwardsCompatibility;
+ bool BackwardsCompatibilityFinal;
+
+private:
+ void AddSharedFlags(std::string& flags, const std::string& lang,
+ bool shared);
+ bool GetShouldUseOldFlags(bool shared, const std::string& lang) const;
+ void AddPositionIndependentFlags(std::string& flags, std::string const& l,
+ int targetType);
+
+ void ComputeObjectMaxPath();
+};
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+bool cmLocalGeneratorCheckObjectName(std::string& objName,
+ std::string::size_type dir_len,
+ std::string::size_type max_total_len);
+#endif
+
+#endif
diff --git a/Source/cmLocalGhsMultiGenerator.cxx b/Source/cmLocalGhsMultiGenerator.cxx
new file mode 100644
index 0000000..01537dd
--- /dev/null
+++ b/Source/cmLocalGhsMultiGenerator.cxx
@@ -0,0 +1,42 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Geoffrey Viola <geoffrey.viola@asirobots.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmLocalGhsMultiGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGhsMultiTargetGenerator.h"
+#include "cmGlobalGhsMultiGenerator.h"
+#include "cmMakefile.h"
+
+cmLocalGhsMultiGenerator::cmLocalGhsMultiGenerator(cmGlobalGenerator* gg,
+ cmMakefile* mf)
+ : cmLocalGenerator(gg, mf)
+{
+}
+
+cmLocalGhsMultiGenerator::~cmLocalGhsMultiGenerator()
+{
+}
+
+void cmLocalGhsMultiGenerator::Generate()
+{
+ std::vector<cmGeneratorTarget*> tgts = this->GetGeneratorTargets();
+
+ for (std::vector<cmGeneratorTarget*>::iterator l = tgts.begin();
+ l != tgts.end(); ++l) {
+ if ((*l)->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ cmGhsMultiTargetGenerator tg(*l);
+ tg.Generate();
+ }
+}
diff --git a/Source/cmLocalGhsMultiGenerator.h b/Source/cmLocalGhsMultiGenerator.h
new file mode 100644
index 0000000..b6a9a33
--- /dev/null
+++ b/Source/cmLocalGhsMultiGenerator.h
@@ -0,0 +1,38 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Geoffrey Viola <geoffrey.viola@asirobots.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLocalGhsMultiGenerator_h
+#define cmLocalGhsMultiGenerator_h
+
+#include "cmLocalGenerator.h"
+
+class cmGeneratedFileStream;
+
+/** \class cmLocalGhsMultiGenerator
+ * \brief Write Green Hills MULTI project files.
+ *
+ * cmLocalGhsMultiGenerator produces a set of .gpj
+ * file for each target in its mirrored directory.
+ */
+class cmLocalGhsMultiGenerator : public cmLocalGenerator
+{
+public:
+ cmLocalGhsMultiGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
+
+ virtual ~cmLocalGhsMultiGenerator();
+
+ /**
+ * Generate the makefile for this directory.
+ */
+ virtual void Generate();
+};
+
+#endif
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
new file mode 100644
index 0000000..0f488a6
--- /dev/null
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -0,0 +1,504 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
+ Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmLocalNinjaGenerator.h"
+
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmMakefile.h"
+#include "cmNinjaTargetGenerator.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmake.h"
+
+#include <assert.h>
+
+cmLocalNinjaGenerator::cmLocalNinjaGenerator(cmGlobalGenerator* gg,
+ cmMakefile* mf)
+ : cmLocalCommonGenerator(gg, mf, cmOutputConverter::HOME_OUTPUT)
+ , HomeRelativeOutputPath("")
+{
+ this->TargetImplib = "$TARGET_IMPLIB";
+}
+
+// Virtual public methods.
+
+cmLocalNinjaGenerator::~cmLocalNinjaGenerator()
+{
+}
+
+void cmLocalNinjaGenerator::Generate()
+{
+ // Compute the path to use when referencing the current output
+ // directory from the top output directory.
+ this->HomeRelativeOutputPath = this->Convert(
+ this->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT);
+ if (this->HomeRelativeOutputPath == ".") {
+ this->HomeRelativeOutputPath = "";
+ }
+
+ this->SetConfigName();
+
+ this->WriteProcessedMakefile(this->GetBuildFileStream());
+#ifdef NINJA_GEN_VERBOSE_FILES
+ this->WriteProcessedMakefile(this->GetRulesFileStream());
+#endif
+
+ // We do that only once for the top CMakeLists.txt file.
+ if (this->IsRootMakefile()) {
+ this->WriteBuildFileTop();
+
+ this->WritePools(this->GetRulesFileStream());
+
+ const std::string showIncludesPrefix =
+ this->GetMakefile()->GetSafeDefinition("CMAKE_CL_SHOWINCLUDES_PREFIX");
+ if (!showIncludesPrefix.empty()) {
+ cmGlobalNinjaGenerator::WriteComment(this->GetRulesFileStream(),
+ "localized /showIncludes string");
+ this->GetRulesFileStream() << "msvc_deps_prefix = " << showIncludesPrefix
+ << "\n\n";
+ }
+ }
+
+ std::vector<cmGeneratorTarget*> targets = this->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
+ t != targets.end(); ++t) {
+ if ((*t)->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ cmNinjaTargetGenerator* tg = cmNinjaTargetGenerator::New(*t);
+ if (tg) {
+ tg->Generate();
+ // Add the target to "all" if required.
+ if (!this->GetGlobalNinjaGenerator()->IsExcluded(
+ this->GetGlobalNinjaGenerator()->GetLocalGenerators()[0], *t)) {
+ this->GetGlobalNinjaGenerator()->AddDependencyToAll(*t);
+ }
+ delete tg;
+ }
+ }
+
+ this->WriteCustomCommandBuildStatements();
+}
+
+// TODO: Picked up from cmLocalUnixMakefileGenerator3. Refactor it.
+std::string cmLocalNinjaGenerator::GetTargetDirectory(
+ cmGeneratorTarget const* target) const
+{
+ std::string dir = cmake::GetCMakeFilesDirectoryPostSlash();
+ dir += target->GetName();
+#if defined(__VMS)
+ dir += "_dir";
+#else
+ dir += ".dir";
+#endif
+ return dir;
+}
+
+// Non-virtual public methods.
+
+const cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator()
+ const
+{
+ return static_cast<const cmGlobalNinjaGenerator*>(
+ this->GetGlobalGenerator());
+}
+
+cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator()
+{
+ return static_cast<cmGlobalNinjaGenerator*>(this->GetGlobalGenerator());
+}
+
+// Virtual protected methods.
+
+std::string cmLocalNinjaGenerator::ConvertToLinkReference(
+ std::string const& lib, cmOutputConverter::OutputFormat format)
+{
+ std::string path = this->GetGlobalNinjaGenerator()->ConvertToNinjaPath(lib);
+ return this->ConvertToOutputFormat(path, format);
+}
+
+std::string cmLocalNinjaGenerator::ConvertToIncludeReference(
+ std::string const& path, cmOutputConverter::OutputFormat format,
+ bool forceFullPaths)
+{
+ return this->Convert(path, forceFullPaths ? cmOutputConverter::FULL
+ : cmOutputConverter::HOME_OUTPUT,
+ format);
+}
+
+// Private methods.
+
+cmGeneratedFileStream& cmLocalNinjaGenerator::GetBuildFileStream() const
+{
+ return *this->GetGlobalNinjaGenerator()->GetBuildFileStream();
+}
+
+cmGeneratedFileStream& cmLocalNinjaGenerator::GetRulesFileStream() const
+{
+ return *this->GetGlobalNinjaGenerator()->GetRulesFileStream();
+}
+
+const cmake* cmLocalNinjaGenerator::GetCMakeInstance() const
+{
+ return this->GetGlobalGenerator()->GetCMakeInstance();
+}
+
+cmake* cmLocalNinjaGenerator::GetCMakeInstance()
+{
+ return this->GetGlobalGenerator()->GetCMakeInstance();
+}
+
+void cmLocalNinjaGenerator::WriteBuildFileTop()
+{
+ // For the build file.
+ this->WriteProjectHeader(this->GetBuildFileStream());
+ this->WriteNinjaRequiredVersion(this->GetBuildFileStream());
+ this->WriteNinjaFilesInclusion(this->GetBuildFileStream());
+
+ // For the rule file.
+ this->WriteProjectHeader(this->GetRulesFileStream());
+}
+
+void cmLocalNinjaGenerator::WriteProjectHeader(std::ostream& os)
+{
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << "# Project: " << this->GetProjectName() << std::endl
+ << "# Configuration: " << this->ConfigName << std::endl;
+ cmGlobalNinjaGenerator::WriteDivider(os);
+}
+
+void cmLocalNinjaGenerator::WriteNinjaRequiredVersion(std::ostream& os)
+{
+ // Default required version
+ std::string requiredVersion =
+ this->GetGlobalNinjaGenerator()->RequiredNinjaVersion();
+
+ // Ninja generator uses the 'console' pool if available (>= 1.5)
+ if (this->GetGlobalNinjaGenerator()->SupportsConsolePool()) {
+ requiredVersion =
+ this->GetGlobalNinjaGenerator()->RequiredNinjaVersionForConsolePool();
+ }
+
+ cmGlobalNinjaGenerator::WriteComment(
+ os, "Minimal version of Ninja required by this file");
+ os << "ninja_required_version = " << requiredVersion << std::endl
+ << std::endl;
+}
+
+void cmLocalNinjaGenerator::WritePools(std::ostream& os)
+{
+ cmGlobalNinjaGenerator::WriteDivider(os);
+
+ const char* jobpools =
+ this->GetCMakeInstance()->GetState()->GetGlobalProperty("JOB_POOLS");
+ if (jobpools) {
+ cmGlobalNinjaGenerator::WriteComment(
+ os, "Pools defined by global property JOB_POOLS");
+ std::vector<std::string> pools;
+ cmSystemTools::ExpandListArgument(jobpools, pools);
+ for (size_t i = 0; i < pools.size(); ++i) {
+ const std::string pool = pools[i];
+ const std::string::size_type eq = pool.find('=');
+ unsigned int jobs;
+ if (eq != std::string::npos &&
+ sscanf(pool.c_str() + eq, "=%u", &jobs) == 1) {
+ os << "pool " << pool.substr(0, eq) << std::endl;
+ os << " depth = " << jobs << std::endl;
+ os << std::endl;
+ } else {
+ cmSystemTools::Error("Invalid pool defined by property 'JOB_POOLS': ",
+ pool.c_str());
+ }
+ }
+ }
+}
+
+void cmLocalNinjaGenerator::WriteNinjaFilesInclusion(std::ostream& os)
+{
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << "# Include auxiliary files.\n"
+ << "\n";
+ cmGlobalNinjaGenerator* ng = this->GetGlobalNinjaGenerator();
+ std::string const ninjaRulesFile =
+ ng->NinjaOutputPath(cmGlobalNinjaGenerator::NINJA_RULES_FILE);
+ std::string const rulesFilePath =
+ ng->EncodeIdent(ng->EncodePath(ninjaRulesFile), os);
+ cmGlobalNinjaGenerator::WriteInclude(os, rulesFilePath,
+ "Include rules file.");
+ os << "\n";
+}
+
+void cmLocalNinjaGenerator::ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt)
+{
+ for (std::map<cmSourceFile const*, std::string>::iterator si =
+ mapping.begin();
+ si != mapping.end(); ++si) {
+ cmSourceFile const* sf = si->first;
+ si->second =
+ this->GetObjectFileNameWithoutTarget(*sf, gt->ObjectDirectory);
+ }
+}
+
+void cmLocalNinjaGenerator::WriteProcessedMakefile(std::ostream& os)
+{
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << "# Write statements declared in CMakeLists.txt:" << std::endl
+ << "# " << this->Makefile->GetDefinition("CMAKE_CURRENT_LIST_FILE")
+ << std::endl;
+ if (this->IsRootMakefile()) {
+ os << "# Which is the root file." << std::endl;
+ }
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << std::endl;
+}
+
+void cmLocalNinjaGenerator::AppendTargetOutputs(cmGeneratorTarget* target,
+ cmNinjaDeps& outputs)
+{
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(target, outputs);
+}
+
+void cmLocalNinjaGenerator::AppendTargetDepends(cmGeneratorTarget* target,
+ cmNinjaDeps& outputs)
+{
+ this->GetGlobalNinjaGenerator()->AppendTargetDepends(target, outputs);
+}
+
+void cmLocalNinjaGenerator::AppendCustomCommandDeps(
+ cmCustomCommandGenerator const& ccg, cmNinjaDeps& ninjaDeps)
+{
+ const std::vector<std::string>& deps = ccg.GetDepends();
+ for (std::vector<std::string>::const_iterator i = deps.begin();
+ i != deps.end(); ++i) {
+ std::string dep;
+ if (this->GetRealDependency(*i, this->GetConfigName(), dep)) {
+ ninjaDeps.push_back(
+ this->GetGlobalNinjaGenerator()->ConvertToNinjaPath(dep));
+ }
+ }
+}
+
+std::string cmLocalNinjaGenerator::BuildCommandLine(
+ const std::vector<std::string>& cmdLines)
+{
+ // If we have no commands but we need to build a command anyway, use ":".
+ // This happens when building a POST_BUILD value for link targets that
+ // don't use POST_BUILD.
+ if (cmdLines.empty()) {
+#ifdef _WIN32
+ return "cd .";
+#else
+ return ":";
+#endif
+ }
+
+ std::ostringstream cmd;
+ for (std::vector<std::string>::const_iterator li = cmdLines.begin();
+ li != cmdLines.end(); ++li)
+#ifdef _WIN32
+ {
+ if (li != cmdLines.begin()) {
+ cmd << " && ";
+ } else if (cmdLines.size() > 1) {
+ cmd << "cmd.exe /C \"";
+ }
+ cmd << *li;
+ }
+ if (cmdLines.size() > 1) {
+ cmd << "\"";
+ }
+#else
+ {
+ if (li != cmdLines.begin()) {
+ cmd << " && ";
+ }
+ cmd << *li;
+ }
+#endif
+ return cmd.str();
+}
+
+void cmLocalNinjaGenerator::AppendCustomCommandLines(
+ cmCustomCommandGenerator const& ccg, std::vector<std::string>& cmdLines)
+{
+ if (ccg.GetNumberOfCommands() > 0) {
+ std::string wd = ccg.GetWorkingDirectory();
+ if (wd.empty()) {
+ wd = this->GetCurrentBinaryDirectory();
+ }
+
+ std::ostringstream cdCmd;
+#ifdef _WIN32
+ std::string cdStr = "cd /D ";
+#else
+ std::string cdStr = "cd ";
+#endif
+ cdCmd << cdStr
+ << this->ConvertToOutputFormat(wd, cmOutputConverter::SHELL);
+ cmdLines.push_back(cdCmd.str());
+ }
+
+ std::string launcher = this->MakeCustomLauncher(ccg);
+
+ for (unsigned i = 0; i != ccg.GetNumberOfCommands(); ++i) {
+ cmdLines.push_back(launcher +
+ this->ConvertToOutputFormat(ccg.GetCommand(i),
+ cmOutputConverter::SHELL));
+
+ std::string& cmd = cmdLines.back();
+ ccg.AppendArguments(i, cmd);
+ }
+}
+
+void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
+ cmCustomCommand const* cc, const cmNinjaDeps& orderOnlyDeps)
+{
+ if (this->GetGlobalNinjaGenerator()->SeenCustomCommand(cc)) {
+ return;
+ }
+
+ cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), this);
+
+ 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");
+ }
+ }
+
+#if 0
+#error TODO: Once CC in an ExternalProject target must provide the \
+ file of each imported target that has an add_dependencies pointing \
+ at us. How to know which ExternalProject step actually provides it?
+#endif
+ std::transform(outputs.begin(), outputs.end(), ninjaOutputs.begin(),
+ this->GetGlobalNinjaGenerator()->MapToNinjaPath());
+ std::transform(byproducts.begin(), byproducts.end(),
+ ninjaOutputs.begin() + outputs.size(),
+ this->GetGlobalNinjaGenerator()->MapToNinjaPath());
+ this->AppendCustomCommandDeps(ccg, ninjaDeps);
+
+ for (cmNinjaDeps::iterator i = ninjaOutputs.begin(); i != ninjaOutputs.end();
+ ++i) {
+ this->GetGlobalNinjaGenerator()->SeenCustomCommandOutput(*i);
+ }
+
+ 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());
+ } else {
+ this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild(
+ this->BuildCommandLine(cmdLines), this->ConstructComment(ccg),
+ "Custom command for " + ninjaOutputs[0], cc->GetUsesTerminal(),
+ /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, ninjaDeps,
+ orderOnlyDeps);
+ }
+}
+
+void cmLocalNinjaGenerator::AddCustomCommandTarget(cmCustomCommand const* cc,
+ cmGeneratorTarget* target)
+{
+ CustomCommandTargetMap::value_type v(cc, std::set<cmGeneratorTarget*>());
+ std::pair<CustomCommandTargetMap::iterator, bool> ins =
+ this->CustomCommandTargets.insert(v);
+ if (ins.second) {
+ this->CustomCommands.push_back(cc);
+ }
+ ins.first->second.insert(target);
+}
+
+void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements()
+{
+ for (std::vector<cmCustomCommand const*>::iterator vi =
+ this->CustomCommands.begin();
+ vi != this->CustomCommands.end(); ++vi) {
+ CustomCommandTargetMap::iterator i = this->CustomCommandTargets.find(*vi);
+ assert(i != this->CustomCommandTargets.end());
+
+ // A custom command may appear on multiple targets. However, some build
+ // systems exist where the target dependencies on some of the targets are
+ // overspecified, leading to a dependency cycle. If we assume all target
+ // dependencies are a superset of the true target dependencies for this
+ // custom command, we can take the set intersection of all target
+ // dependencies to obtain a correct dependency list.
+ //
+ // FIXME: This won't work in certain obscure scenarios involving indirect
+ // dependencies.
+ std::set<cmGeneratorTarget*>::iterator j = i->second.begin();
+ assert(j != i->second.end());
+ std::vector<std::string> ccTargetDeps;
+ this->AppendTargetDepends(*j, ccTargetDeps);
+ std::sort(ccTargetDeps.begin(), ccTargetDeps.end());
+ ++j;
+
+ for (; j != i->second.end(); ++j) {
+ std::vector<std::string> jDeps, depsIntersection;
+ this->AppendTargetDepends(*j, jDeps);
+ std::sort(jDeps.begin(), jDeps.end());
+ std::set_intersection(ccTargetDeps.begin(), ccTargetDeps.end(),
+ jDeps.begin(), jDeps.end(),
+ std::back_inserter(depsIntersection));
+ ccTargetDeps = depsIntersection;
+ }
+
+ this->WriteCustomCommandBuildStatement(i->first, ccTargetDeps);
+ }
+}
+
+std::string cmLocalNinjaGenerator::MakeCustomLauncher(
+ cmCustomCommandGenerator const& ccg)
+{
+ const char* property = "RULE_LAUNCH_CUSTOM";
+ const char* property_value = this->Makefile->GetProperty(property);
+
+ if (!property_value || !*property_value) {
+ return std::string();
+ }
+
+ // Expand rules in the empty string. It may insert the launcher and
+ // perform replacements.
+ RuleVariables vars;
+ vars.RuleLauncher = property;
+ std::string output;
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ if (!outputs.empty()) {
+ cmOutputConverter::RelativeRoot relative_root =
+ ccg.GetWorkingDirectory().empty() ? cmOutputConverter::START_OUTPUT
+ : cmOutputConverter::NONE;
+
+ output =
+ this->Convert(outputs[0], relative_root, cmOutputConverter::SHELL);
+ }
+ vars.Output = output.c_str();
+
+ std::string launcher;
+ this->ExpandRuleVariables(launcher, vars);
+ if (!launcher.empty()) {
+ launcher += " ";
+ }
+
+ return launcher;
+}
diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h
new file mode 100644
index 0000000..6e61087
--- /dev/null
+++ b/Source/cmLocalNinjaGenerator.h
@@ -0,0 +1,116 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
+ Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLocalNinjaGenerator_h
+#define cmLocalNinjaGenerator_h
+
+#include "cmLocalCommonGenerator.h"
+
+#include "cmNinjaTypes.h"
+
+class cmCustomCommandGenerator;
+class cmGlobalNinjaGenerator;
+class cmGeneratedFileStream;
+class cmake;
+
+/**
+ * \class cmLocalNinjaGenerator
+ * \brief Write a local build.ninja file.
+ *
+ * cmLocalNinjaGenerator produces a local build.ninja file from its
+ * member Makefile.
+ */
+class cmLocalNinjaGenerator : public cmLocalCommonGenerator
+{
+public:
+ cmLocalNinjaGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
+
+ ~cmLocalNinjaGenerator() CM_OVERRIDE;
+
+ void Generate() CM_OVERRIDE;
+
+ std::string GetTargetDirectory(cmGeneratorTarget const* target) const
+ CM_OVERRIDE;
+
+ const cmGlobalNinjaGenerator* GetGlobalNinjaGenerator() const;
+ cmGlobalNinjaGenerator* GetGlobalNinjaGenerator();
+
+ const cmake* GetCMakeInstance() const;
+ cmake* GetCMakeInstance();
+
+ /// @returns the relative path between the HomeOutputDirectory and this
+ /// local generators StartOutputDirectory.
+ std::string GetHomeRelativeOutputPath() const
+ {
+ return this->HomeRelativeOutputPath;
+ }
+
+ void ExpandRuleVariables(std::string& string,
+ const RuleVariables& replaceValues)
+ {
+ cmLocalGenerator::ExpandRuleVariables(string, replaceValues);
+ }
+
+ std::string BuildCommandLine(const std::vector<std::string>& cmdLines);
+
+ void AppendTargetOutputs(cmGeneratorTarget* target, cmNinjaDeps& outputs);
+ void AppendTargetDepends(cmGeneratorTarget* target, cmNinjaDeps& outputs);
+
+ void AddCustomCommandTarget(cmCustomCommand const* cc,
+ cmGeneratorTarget* target);
+ void AppendCustomCommandLines(cmCustomCommandGenerator const& ccg,
+ std::vector<std::string>& cmdLines);
+ void AppendCustomCommandDeps(cmCustomCommandGenerator const& ccg,
+ cmNinjaDeps& ninjaDeps);
+
+ std::string ConvertToLinkReference(std::string const& lib,
+ cmOutputConverter::OutputFormat format =
+ cmOutputConverter::SHELL) CM_OVERRIDE;
+
+ void ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt = CM_NULLPTR) CM_OVERRIDE;
+
+protected:
+ std::string ConvertToIncludeReference(
+ std::string const& path,
+ cmOutputConverter::OutputFormat format = cmOutputConverter::SHELL,
+ bool forceFullPaths = false) CM_OVERRIDE;
+
+private:
+ cmGeneratedFileStream& GetBuildFileStream() const;
+ cmGeneratedFileStream& GetRulesFileStream() const;
+
+ void WriteBuildFileTop();
+ void WriteProjectHeader(std::ostream& os);
+ void WriteNinjaRequiredVersion(std::ostream& os);
+ void WriteNinjaFilesInclusion(std::ostream& os);
+ void WriteProcessedMakefile(std::ostream& os);
+ void WritePools(std::ostream& os);
+
+ void WriteCustomCommandRule();
+ void WriteCustomCommandBuildStatement(cmCustomCommand const* cc,
+ const cmNinjaDeps& orderOnlyDeps);
+
+ void WriteCustomCommandBuildStatements();
+
+ std::string MakeCustomLauncher(cmCustomCommandGenerator const& ccg);
+
+ std::string HomeRelativeOutputPath;
+
+ typedef std::map<cmCustomCommand const*, std::set<cmGeneratorTarget*> >
+ CustomCommandTargetMap;
+ CustomCommandTargetMap CustomCommandTargets;
+ std::vector<cmCustomCommand const*> CustomCommands;
+};
+
+#endif // ! cmLocalNinjaGenerator_h
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
new file mode 100644
index 0000000..75970772
--- /dev/null
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -0,0 +1,2087 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmLocalUnixMakefileGenerator3.h"
+
+#include "cmAlgorithms.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmFileTimeComparison.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmMakefileTargetGenerator.h"
+#include "cmSourceFile.h"
+#include "cmVersion.h"
+#include "cmake.h"
+
+// Include dependency scanners for supported languages. Only the
+// C/C++ scanner is needed for bootstrapping CMake.
+#include "cmDependsC.h"
+#ifdef CMAKE_BUILD_WITH_CMAKE
+#include "cmDependsFortran.h"
+#include "cmDependsJava.h"
+#endif
+
+#include <cm_auto_ptr.hxx>
+#include <cmsys/Terminal.h>
+
+#include <algorithm>
+#include <queue>
+
+// Escape special characters in Makefile dependency lines
+class cmMakeSafe
+{
+public:
+ cmMakeSafe(const char* s)
+ : Data(s)
+ {
+ }
+ cmMakeSafe(std::string const& s)
+ : Data(s.c_str())
+ {
+ }
+
+private:
+ const char* Data;
+ friend std::ostream& operator<<(std::ostream& os, cmMakeSafe const& self)
+ {
+ for (const char* c = self.Data; *c; ++c) {
+ switch (*c) {
+ case '=':
+ os << "$(EQUALS)";
+ break;
+ default:
+ os << *c;
+ break;
+ }
+ }
+ return os;
+ }
+};
+
+// Helper function used below.
+static std::string cmSplitExtension(std::string const& in, std::string& base)
+{
+ std::string ext;
+ std::string::size_type dot_pos = in.rfind('.');
+ if (dot_pos != std::string::npos) {
+ // Remove the extension first in case &base == &in.
+ ext = in.substr(dot_pos, std::string::npos);
+ base = in.substr(0, dot_pos);
+ } else {
+ base = in;
+ }
+ return ext;
+}
+
+cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3(
+ cmGlobalGenerator* gg, cmMakefile* mf)
+ : cmLocalCommonGenerator(gg, mf, cmOutputConverter::START_OUTPUT)
+{
+ this->MakefileVariableSize = 0;
+ this->ColorMakefile = false;
+ this->SkipPreprocessedSourceRules = false;
+ this->SkipAssemblySourceRules = false;
+ this->MakeCommandEscapeTargetTwice = false;
+ this->BorlandMakeCurlyHack = false;
+}
+
+cmLocalUnixMakefileGenerator3::~cmLocalUnixMakefileGenerator3()
+{
+}
+
+void cmLocalUnixMakefileGenerator3::Generate()
+{
+ this->SetConfigName();
+
+ // Record whether some options are enabled to avoid checking many
+ // times later.
+ if (!this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) {
+ this->ColorMakefile = this->Makefile->IsOn("CMAKE_COLOR_MAKEFILE");
+ }
+ this->SkipPreprocessedSourceRules =
+ this->Makefile->IsOn("CMAKE_SKIP_PREPROCESSED_SOURCE_RULES");
+ this->SkipAssemblySourceRules =
+ this->Makefile->IsOn("CMAKE_SKIP_ASSEMBLY_SOURCE_RULES");
+
+ // Generate the rule files for each target.
+ std::vector<cmGeneratorTarget*> targets = this->GetGeneratorTargets();
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
+ t != targets.end(); ++t) {
+ if ((*t)->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ CM_AUTO_PTR<cmMakefileTargetGenerator> tg(
+ cmMakefileTargetGenerator::New(*t));
+ if (tg.get()) {
+ tg->WriteRuleFiles();
+ gg->RecordTargetProgress(tg.get());
+ }
+ }
+
+ // write the local Makefile
+ this->WriteLocalMakefile();
+
+ // Write the cmake file with information for this directory.
+ this->WriteDirectoryInformationFile();
+}
+
+void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath()
+{
+ // Compute the path to use when referencing the current output
+ // directory from the top output directory.
+ this->HomeRelativeOutputPath = this->Convert(
+ this->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT);
+ if (this->HomeRelativeOutputPath == ".") {
+ this->HomeRelativeOutputPath = "";
+ }
+ if (!this->HomeRelativeOutputPath.empty()) {
+ this->HomeRelativeOutputPath += "/";
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt)
+{
+ for (std::map<cmSourceFile const*, std::string>::iterator si =
+ mapping.begin();
+ si != mapping.end(); ++si) {
+ cmSourceFile const* sf = si->first;
+ si->second =
+ this->GetObjectFileNameWithoutTarget(*sf, gt->ObjectDirectory);
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::GetLocalObjectFiles(
+ std::map<std::string, LocalObjectInfo>& localObjectFiles)
+{
+ std::vector<cmGeneratorTarget*> targets = this->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator ti = targets.begin();
+ ti != targets.end(); ++ti) {
+ cmGeneratorTarget* gt = *ti;
+ if (gt->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ std::vector<cmSourceFile const*> objectSources;
+ gt->GetObjectSources(
+ objectSources, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ // Compute full path to object file directory for this target.
+ std::string dir;
+ dir += gt->LocalGenerator->GetCurrentBinaryDirectory();
+ dir += "/";
+ dir += this->GetTargetDirectory(gt);
+ dir += "/";
+ // Compute the name of each object file.
+ for (std::vector<cmSourceFile const*>::iterator si = objectSources.begin();
+ si != objectSources.end(); ++si) {
+ cmSourceFile const* sf = *si;
+ bool hasSourceExtension = true;
+ std::string objectName =
+ this->GetObjectFileNameWithoutTarget(*sf, dir, &hasSourceExtension);
+ if (cmSystemTools::FileIsFullPath(objectName.c_str())) {
+ objectName = cmSystemTools::GetFilenameName(objectName);
+ }
+ LocalObjectInfo& info = localObjectFiles[objectName];
+ info.HasSourceExtension = hasSourceExtension;
+ info.push_back(LocalObjectEntry(gt, sf->GetLanguage()));
+ }
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::GetIndividualFileTargets(
+ std::vector<std::string>& targets)
+{
+ std::map<std::string, LocalObjectInfo> localObjectFiles;
+ this->GetLocalObjectFiles(localObjectFiles);
+ for (std::map<std::string, LocalObjectInfo>::iterator lo =
+ localObjectFiles.begin();
+ lo != localObjectFiles.end(); ++lo) {
+ targets.push_back(lo->first);
+
+ std::string::size_type dot_pos = lo->first.rfind(".");
+ std::string base = lo->first.substr(0, dot_pos);
+ if (lo->second.HasPreprocessRule) {
+ targets.push_back(base + ".i");
+ }
+
+ if (lo->second.HasAssembleRule) {
+ targets.push_back(base + ".s");
+ }
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::WriteLocalMakefile()
+{
+ // generate the includes
+ std::string ruleFileName = "Makefile";
+
+ // Open the rule file. This should be copy-if-different because the
+ // rules may depend on this file itself.
+ std::string ruleFileNameFull = this->ConvertToFullPath(ruleFileName);
+ cmGeneratedFileStream ruleFileStream(ruleFileNameFull.c_str());
+ if (!ruleFileStream) {
+ return;
+ }
+ // always write the top makefile
+ if (!this->IsRootMakefile()) {
+ ruleFileStream.SetCopyIfDifferent(true);
+ }
+
+ // write the all rules
+ this->WriteLocalAllRules(ruleFileStream);
+
+ // only write local targets unless at the top Keep track of targets already
+ // listed.
+ std::set<std::string> emittedTargets;
+ if (!this->IsRootMakefile()) {
+ // write our targets, and while doing it collect up the object
+ // file rules
+ this->WriteLocalMakefileTargets(ruleFileStream, emittedTargets);
+ } else {
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ gg->WriteConvenienceRules(ruleFileStream, emittedTargets);
+ }
+
+ bool do_preprocess_rules = this->GetCreatePreprocessedSourceRules();
+ bool do_assembly_rules = this->GetCreateAssemblySourceRules();
+
+ std::map<std::string, LocalObjectInfo> localObjectFiles;
+ this->GetLocalObjectFiles(localObjectFiles);
+
+ // now write out the object rules
+ // for each object file name
+ for (std::map<std::string, LocalObjectInfo>::iterator lo =
+ localObjectFiles.begin();
+ lo != localObjectFiles.end(); ++lo) {
+ // Add a convenience rule for building the object file.
+ this->WriteObjectConvenienceRule(ruleFileStream,
+ "target to build an object file",
+ lo->first.c_str(), lo->second);
+
+ // Check whether preprocessing and assembly rules make sense.
+ // They make sense only for C and C++ sources.
+ bool lang_has_preprocessor = false;
+ bool lang_has_assembly = false;
+
+ for (std::vector<LocalObjectEntry>::const_iterator ei = lo->second.begin();
+ ei != lo->second.end(); ++ei) {
+ if (ei->Language == "C" || ei->Language == "CXX" ||
+ ei->Language == "Fortran") {
+ // Right now, C, C++ and Fortran have both a preprocessor and the
+ // ability to generate assembly code
+ lang_has_preprocessor = true;
+ lang_has_assembly = true;
+ break;
+ }
+ }
+
+ // Add convenience rules for preprocessed and assembly files.
+ if (lang_has_preprocessor && do_preprocess_rules) {
+ std::string::size_type dot_pos = lo->first.rfind(".");
+ std::string base = lo->first.substr(0, dot_pos);
+ this->WriteObjectConvenienceRule(ruleFileStream,
+ "target to preprocess a source file",
+ (base + ".i").c_str(), lo->second);
+ lo->second.HasPreprocessRule = true;
+ }
+
+ if (lang_has_assembly && do_assembly_rules) {
+ std::string::size_type dot_pos = lo->first.rfind(".");
+ std::string base = lo->first.substr(0, dot_pos);
+ this->WriteObjectConvenienceRule(
+ ruleFileStream, "target to generate assembly for a file",
+ (base + ".s").c_str(), lo->second);
+ lo->second.HasAssembleRule = true;
+ }
+ }
+
+ // add a help target as long as there isn;t a real target named help
+ if (emittedTargets.insert("help").second) {
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ gg->WriteHelpRule(ruleFileStream, this);
+ }
+
+ this->WriteSpecialTargetsBottom(ruleFileStream);
+}
+
+void cmLocalUnixMakefileGenerator3::WriteObjectConvenienceRule(
+ std::ostream& ruleFileStream, const char* comment, const char* output,
+ LocalObjectInfo const& info)
+{
+ // If the rule includes the source file extension then create a
+ // version that has the extension removed. The help should include
+ // only the version without source extension.
+ bool inHelp = true;
+ if (info.HasSourceExtension) {
+ // Remove the last extension. This should be kept.
+ std::string outBase1 = output;
+ std::string outExt1 = cmSplitExtension(outBase1, outBase1);
+
+ // Now remove the source extension and put back the last
+ // extension.
+ std::string outNoExt;
+ cmSplitExtension(outBase1, outNoExt);
+ outNoExt += outExt1;
+
+ // Add a rule to drive the rule below.
+ std::vector<std::string> depends;
+ depends.push_back(output);
+ std::vector<std::string> no_commands;
+ this->WriteMakeRule(ruleFileStream, CM_NULLPTR, outNoExt, depends,
+ no_commands, true, true);
+ inHelp = false;
+ }
+
+ // Recursively make the rule for each target using the object file.
+ std::vector<std::string> commands;
+ for (std::vector<LocalObjectEntry>::const_iterator t = info.begin();
+ t != info.end(); ++t) {
+ std::string tgtMakefileName = this->GetRelativeTargetDirectory(t->Target);
+ std::string targetName = tgtMakefileName;
+ tgtMakefileName += "/build.make";
+ targetName += "/";
+ targetName += output;
+ commands.push_back(
+ this->GetRecursiveMakeCall(tgtMakefileName.c_str(), targetName));
+ }
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ cmOutputConverter::START_OUTPUT);
+
+ // Write the rule to the makefile.
+ std::vector<std::string> no_depends;
+ this->WriteMakeRule(ruleFileStream, comment, output, no_depends, commands,
+ true, inHelp);
+}
+
+void cmLocalUnixMakefileGenerator3::WriteLocalMakefileTargets(
+ std::ostream& ruleFileStream, std::set<std::string>& emitted)
+{
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+
+ // for each target we just provide a rule to cd up to the top and do a make
+ // on the target
+ std::vector<cmGeneratorTarget*> targets = this->GetGeneratorTargets();
+ std::string localName;
+ for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
+ t != targets.end(); ++t) {
+ if (((*t)->GetType() == cmState::EXECUTABLE) ||
+ ((*t)->GetType() == cmState::STATIC_LIBRARY) ||
+ ((*t)->GetType() == cmState::SHARED_LIBRARY) ||
+ ((*t)->GetType() == cmState::MODULE_LIBRARY) ||
+ ((*t)->GetType() == cmState::OBJECT_LIBRARY) ||
+ ((*t)->GetType() == cmState::UTILITY)) {
+ emitted.insert((*t)->GetName());
+
+ // for subdirs add a rule to build this specific target by name.
+ localName = this->GetRelativeTargetDirectory(*t);
+ localName += "/rule";
+ commands.clear();
+ depends.clear();
+
+ // Build the target for this pass.
+ std::string makefile2 = cmake::GetCMakeFilesDirectoryPostSlash();
+ makefile2 += "Makefile2";
+ commands.push_back(
+ this->GetRecursiveMakeCall(makefile2.c_str(), localName));
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ cmOutputConverter::START_OUTPUT);
+ this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
+ localName, depends, commands, true);
+
+ // Add a target with the canonical name (no prefix, suffix or path).
+ if (localName != (*t)->GetName()) {
+ commands.clear();
+ depends.push_back(localName);
+ this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
+ (*t)->GetName(), depends, commands, true);
+ }
+
+ // Add a fast rule to build the target
+ std::string makefileName = this->GetRelativeTargetDirectory(*t);
+ makefileName += "/build.make";
+ // make sure the makefile name is suitable for a makefile
+ std::string makeTargetName = this->GetRelativeTargetDirectory(*t);
+ makeTargetName += "/build";
+ localName = (*t)->GetName();
+ localName += "/fast";
+ depends.clear();
+ commands.clear();
+ commands.push_back(
+ this->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ cmOutputConverter::START_OUTPUT);
+ this->WriteMakeRule(ruleFileStream, "fast build rule for target.",
+ localName, depends, commands, true);
+
+ // Add a local name for the rule to relink the target before
+ // installation.
+ if ((*t)->NeedRelinkBeforeInstall(this->ConfigName)) {
+ makeTargetName = this->GetRelativeTargetDirectory(*t);
+ makeTargetName += "/preinstall";
+ localName = (*t)->GetName();
+ localName += "/preinstall";
+ depends.clear();
+ commands.clear();
+ commands.push_back(
+ this->GetRecursiveMakeCall(makefile2.c_str(), makeTargetName));
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ cmOutputConverter::START_OUTPUT);
+ this->WriteMakeRule(ruleFileStream,
+ "Manual pre-install relink rule for target.",
+ localName, depends, commands, true);
+ }
+ }
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::WriteDirectoryInformationFile()
+{
+ std::string infoFileName = this->GetCurrentBinaryDirectory();
+ infoFileName += cmake::GetCMakeFilesDirectory();
+ infoFileName += "/CMakeDirectoryInformation.cmake";
+
+ // Open the output file.
+ cmGeneratedFileStream infoFileStream(infoFileName.c_str());
+ if (!infoFileStream) {
+ return;
+ }
+
+ infoFileStream.SetCopyIfDifferent(true);
+ // Write the do not edit header.
+ this->WriteDisclaimer(infoFileStream);
+
+ // Setup relative path conversion tops.
+ /* clang-format off */
+ infoFileStream
+ << "# Relative path conversion top directories.\n"
+ << "set(CMAKE_RELATIVE_PATH_TOP_SOURCE \""
+ << this->StateSnapshot.GetDirectory().GetRelativePathTopSource()
+ << "\")\n"
+ << "set(CMAKE_RELATIVE_PATH_TOP_BINARY \""
+ << this->StateSnapshot.GetDirectory().GetRelativePathTopBinary()
+ << "\")\n"
+ << "\n";
+ /* clang-format on */
+
+ // Tell the dependency scanner to use unix paths if necessary.
+ if (cmSystemTools::GetForceUnixPaths()) {
+ /* clang-format off */
+ infoFileStream
+ << "# Force unix paths in dependencies.\n"
+ << "set(CMAKE_FORCE_UNIX_PATHS 1)\n"
+ << "\n";
+ /* clang-format on */
+ }
+
+ // Store the include regular expressions for this directory.
+ infoFileStream << "\n"
+ << "# The C and CXX include file regular expressions for "
+ << "this directory.\n";
+ infoFileStream << "set(CMAKE_C_INCLUDE_REGEX_SCAN ";
+ this->WriteCMakeArgument(infoFileStream,
+ this->Makefile->GetIncludeRegularExpression());
+ infoFileStream << ")\n";
+ infoFileStream << "set(CMAKE_C_INCLUDE_REGEX_COMPLAIN ";
+ this->WriteCMakeArgument(infoFileStream,
+ this->Makefile->GetComplainRegularExpression());
+ infoFileStream << ")\n";
+ infoFileStream
+ << "set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN})\n";
+ infoFileStream << "set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN "
+ "${CMAKE_C_INCLUDE_REGEX_COMPLAIN})\n";
+}
+
+std::string cmLocalUnixMakefileGenerator3::ConvertToFullPath(
+ const std::string& localPath)
+{
+ std::string dir = this->GetCurrentBinaryDirectory();
+ dir += "/";
+ dir += localPath;
+ return dir;
+}
+
+const std::string& cmLocalUnixMakefileGenerator3::GetHomeRelativeOutputPath()
+{
+ return this->HomeRelativeOutputPath;
+}
+
+void cmLocalUnixMakefileGenerator3::WriteMakeRule(
+ std::ostream& os, const char* comment, const std::string& target,
+ const std::vector<std::string>& depends,
+ const std::vector<std::string>& commands, bool symbolic, bool in_help)
+{
+ // Make sure there is a target.
+ if (target.empty()) {
+ cmSystemTools::Error("No target for WriteMakeRule! called with comment: ",
+ comment);
+ return;
+ }
+
+ std::string replace;
+
+ // Write the comment describing the rule in the makefile.
+ if (comment) {
+ replace = comment;
+ std::string::size_type lpos = 0;
+ std::string::size_type rpos;
+ while ((rpos = replace.find('\n', lpos)) != std::string::npos) {
+ os << "# " << replace.substr(lpos, rpos - lpos) << "\n";
+ lpos = rpos + 1;
+ }
+ os << "# " << replace.substr(lpos) << "\n";
+ }
+
+ // Construct the left hand side of the rule.
+ std::string tgt = this->Convert(target, cmOutputConverter::HOME_OUTPUT,
+ cmOutputConverter::MAKERULE);
+
+ const char* space = "";
+ if (tgt.size() == 1) {
+ // Add a space before the ":" to avoid drive letter confusion on
+ // Windows.
+ space = " ";
+ }
+
+ // Mark the rule as symbolic if requested.
+ if (symbolic) {
+ if (const char* sym =
+ this->Makefile->GetDefinition("CMAKE_MAKE_SYMBOLIC_RULE")) {
+ os << cmMakeSafe(tgt) << space << ": " << sym << "\n";
+ }
+ }
+
+ // Write the rule.
+ if (depends.empty()) {
+ // No dependencies. The commands will always run.
+ os << cmMakeSafe(tgt) << space << ":\n";
+ } else {
+ // Split dependencies into multiple rule lines. This allows for
+ // very long dependency lists even on older make implementations.
+ for (std::vector<std::string>::const_iterator dep = depends.begin();
+ dep != depends.end(); ++dep) {
+ replace = *dep;
+ replace = this->Convert(replace, cmOutputConverter::HOME_OUTPUT,
+ cmOutputConverter::MAKERULE);
+ os << cmMakeSafe(tgt) << space << ": " << cmMakeSafe(replace) << "\n";
+ }
+ }
+
+ // Write the list of commands.
+ os << cmWrap("\t", commands, "", "\n") << "\n";
+ if (symbolic && !this->IsWatcomWMake()) {
+ os << ".PHONY : " << cmMakeSafe(tgt) << "\n";
+ }
+ os << "\n";
+ // Add the output to the local help if requested.
+ if (in_help) {
+ this->LocalHelp.push_back(target);
+ }
+}
+
+std::string cmLocalUnixMakefileGenerator3::ConvertShellCommand(
+ std::string const& cmd, cmOutputConverter::RelativeRoot root)
+{
+ if (this->IsWatcomWMake() && cmSystemTools::FileIsFullPath(cmd.c_str()) &&
+ cmd.find_first_of("( )") != cmd.npos) {
+ // On Watcom WMake use the windows short path for the command
+ // name. This is needed to avoid funny quoting problems on
+ // lines with shell redirection operators.
+ std::string scmd;
+ if (cmSystemTools::GetShortPath(cmd, scmd)) {
+ return this->Convert(scmd, cmOutputConverter::NONE,
+ cmOutputConverter::SHELL);
+ }
+ }
+ return this->Convert(cmd, root, cmOutputConverter::SHELL);
+}
+
+void cmLocalUnixMakefileGenerator3::WriteMakeVariables(
+ std::ostream& makefileStream)
+{
+ this->WriteDivider(makefileStream);
+ makefileStream << "# Set environment variables for the build.\n"
+ << "\n";
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ if (gg->DefineWindowsNULL) {
+ makefileStream << "!IF \"$(OS)\" == \"Windows_NT\"\n"
+ << "NULL=\n"
+ << "!ELSE\n"
+ << "NULL=nul\n"
+ << "!ENDIF\n";
+ }
+ if (this->IsWindowsShell()) {
+ makefileStream << "SHELL = cmd.exe\n"
+ << "\n";
+ } else {
+#if !defined(__VMS)
+ /* clang-format off */
+ makefileStream
+ << "# The shell in which to execute make rules.\n"
+ << "SHELL = /bin/sh\n"
+ << "\n";
+/* clang-format on */
+#endif
+ }
+
+ /* clang-format off */
+ makefileStream
+ << "# The CMake executable.\n"
+ << "CMAKE_COMMAND = "
+ << this->ConvertShellCommand(cmSystemTools::GetCMakeCommand(),
+ cmOutputConverter::FULL)
+ << "\n"
+ << "\n";
+ makefileStream
+ << "# The command to remove a file.\n"
+ << "RM = "
+ << this->ConvertShellCommand(cmSystemTools::GetCMakeCommand(),
+ cmOutputConverter::FULL)
+ << " -E remove -f\n"
+ << "\n";
+ makefileStream
+ << "# Escaping for special characters.\n"
+ << "EQUALS = =\n"
+ << "\n";
+ makefileStream
+ << "# The top-level source directory on which CMake was run.\n"
+ << "CMAKE_SOURCE_DIR = "
+ << this->Convert(this->GetSourceDirectory(),
+ cmOutputConverter::FULL,
+ cmOutputConverter::SHELL)
+ << "\n"
+ << "\n";
+ makefileStream
+ << "# The top-level build directory on which CMake was run.\n"
+ << "CMAKE_BINARY_DIR = "
+ << this->Convert(this->GetBinaryDirectory(),
+ cmOutputConverter::FULL,
+ cmOutputConverter::SHELL)
+ << "\n"
+ << "\n";
+ /* clang-format on */
+}
+
+void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsTop(
+ std::ostream& makefileStream)
+{
+ this->WriteDivider(makefileStream);
+ makefileStream << "# Special targets provided by cmake.\n"
+ << "\n";
+
+ std::vector<std::string> no_commands;
+ std::vector<std::string> no_depends;
+
+ // Special target to cleanup operation of make tool.
+ // This should be the first target except for the default_target in
+ // the interface Makefile.
+ this->WriteMakeRule(makefileStream,
+ "Disable implicit rules so canonical targets will work.",
+ ".SUFFIXES", no_depends, no_commands, false);
+
+ if (!this->IsNMake() && !this->IsWatcomWMake() &&
+ !this->BorlandMakeCurlyHack) {
+ // turn off RCS and SCCS automatic stuff from gmake
+ makefileStream
+ << "# Remove some rules from gmake that .SUFFIXES does not remove.\n"
+ << "SUFFIXES =\n\n";
+ }
+ // Add a fake suffix to keep HP happy. Must be max 32 chars for SGI make.
+ std::vector<std::string> depends;
+ depends.push_back(".hpux_make_needs_suffix_list");
+ this->WriteMakeRule(makefileStream, CM_NULLPTR, ".SUFFIXES", depends,
+ no_commands, false);
+ if (this->IsWatcomWMake()) {
+ // Switch on WMake feature, if an error or interrupt occurs during
+ // makefile processing, the current target being made may be deleted
+ // without prompting (the same as command line -e option).
+ /* clang-format off */
+ makefileStream <<
+ "\n"
+ ".ERASE\n"
+ "\n"
+ ;
+ /* clang-format on */
+ }
+ if (this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")) {
+ /* clang-format off */
+ makefileStream
+ << "# Produce verbose output by default.\n"
+ << "VERBOSE = 1\n"
+ << "\n";
+ /* clang-format on */
+ }
+ if (this->IsWatcomWMake()) {
+ /* clang-format off */
+ makefileStream <<
+ "!ifndef VERBOSE\n"
+ ".SILENT\n"
+ "!endif\n"
+ "\n"
+ ;
+ /* clang-format on */
+ } else {
+ // Write special target to silence make output. This must be after
+ // the default target in case VERBOSE is set (which changes the
+ // name). The setting of CMAKE_VERBOSE_MAKEFILE to ON will cause a
+ // "VERBOSE=1" to be added as a make variable which will change the
+ // name of this special target. This gives a make-time choice to
+ // the user.
+ this->WriteMakeRule(makefileStream,
+ "Suppress display of executed commands.",
+ "$(VERBOSE).SILENT", no_depends, no_commands, false);
+ }
+
+ // Work-around for makes that drop rules that have no dependencies
+ // or commands.
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ std::string hack = gg->GetEmptyRuleHackDepends();
+ if (!hack.empty()) {
+ no_depends.push_back(hack);
+ }
+ std::string hack_cmd = gg->GetEmptyRuleHackCommand();
+ if (!hack_cmd.empty()) {
+ no_commands.push_back(hack_cmd);
+ }
+
+ // Special symbolic target that never exists to force dependers to
+ // run their rules.
+ this->WriteMakeRule(makefileStream, "A target that is always out of date.",
+ "cmake_force", no_depends, no_commands, true);
+
+ // Variables for reference by other rules.
+ this->WriteMakeVariables(makefileStream);
+}
+
+void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom(
+ std::ostream& makefileStream)
+{
+ this->WriteDivider(makefileStream);
+ makefileStream << "# Special targets to cleanup operation of make.\n"
+ << "\n";
+
+ // Write special "cmake_check_build_system" target to run cmake with
+ // the --check-build-system flag.
+ {
+ // Build command to run CMake to check if anything needs regenerating.
+ std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash();
+ cmakefileName += "Makefile.cmake";
+ std::string runRule =
+ "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)";
+ runRule += " --check-build-system ";
+ runRule += this->Convert(cmakefileName, cmOutputConverter::NONE,
+ cmOutputConverter::SHELL);
+ runRule += " 0";
+
+ std::vector<std::string> no_depends;
+ std::vector<std::string> commands;
+ commands.push_back(runRule);
+ if (!this->IsRootMakefile()) {
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ cmOutputConverter::START_OUTPUT);
+ }
+ this->WriteMakeRule(
+ makefileStream, "Special rule to run CMake to check the build system "
+ "integrity.\n"
+ "No rule that depends on this can have "
+ "commands that come from listfiles\n"
+ "because they might be regenerated.",
+ "cmake_check_build_system", no_depends, commands, true);
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::WriteConvenienceRule(
+ std::ostream& ruleFileStream, const std::string& realTarget,
+ const std::string& helpTarget)
+{
+ // A rule is only needed if the names are different.
+ if (realTarget != helpTarget) {
+ // The helper target depends on the real target.
+ std::vector<std::string> depends;
+ depends.push_back(realTarget);
+
+ // There are no commands.
+ std::vector<std::string> no_commands;
+
+ // Write the rule.
+ this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
+ helpTarget, depends, no_commands, true);
+ }
+}
+
+std::string cmLocalUnixMakefileGenerator3::GetRelativeTargetDirectory(
+ cmGeneratorTarget* target)
+{
+ std::string dir = this->HomeRelativeOutputPath;
+ dir += this->GetTargetDirectory(target);
+ return this->Convert(dir, cmOutputConverter::NONE,
+ cmOutputConverter::UNCHANGED);
+}
+
+void cmLocalUnixMakefileGenerator3::AppendFlags(std::string& flags,
+ const std::string& newFlags)
+{
+ if (this->IsWatcomWMake() && !newFlags.empty()) {
+ std::string newf = newFlags;
+ if (newf.find("\\\"") != newf.npos) {
+ cmSystemTools::ReplaceString(newf, "\\\"", "\"");
+ this->cmLocalGenerator::AppendFlags(flags, newf);
+ return;
+ }
+ }
+ this->cmLocalGenerator::AppendFlags(flags, newFlags);
+}
+
+void cmLocalUnixMakefileGenerator3::AppendFlags(std::string& flags,
+ const char* newFlags)
+{
+ this->cmLocalGenerator::AppendFlags(flags, newFlags);
+}
+
+void cmLocalUnixMakefileGenerator3::AppendRuleDepend(
+ std::vector<std::string>& depends, const char* ruleFileName)
+{
+ // Add a dependency on the rule file itself unless an option to skip
+ // it is specifically enabled by the user or project.
+ const char* nodep =
+ this->Makefile->GetDefinition("CMAKE_SKIP_RULE_DEPENDENCY");
+ if (!nodep || cmSystemTools::IsOff(nodep)) {
+ depends.push_back(ruleFileName);
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::AppendRuleDepends(
+ std::vector<std::string>& depends, std::vector<std::string> const& ruleFiles)
+{
+ // 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());
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::AppendCustomDepends(
+ std::vector<std::string>& depends, const std::vector<cmCustomCommand>& ccs)
+{
+ for (std::vector<cmCustomCommand>::const_iterator i = ccs.begin();
+ i != ccs.end(); ++i) {
+ cmCustomCommandGenerator ccg(*i, this->ConfigName, this);
+ this->AppendCustomDepend(depends, ccg);
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::AppendCustomDepend(
+ std::vector<std::string>& depends, cmCustomCommandGenerator const& ccg)
+{
+ for (std::vector<std::string>::const_iterator d = ccg.GetDepends().begin();
+ d != ccg.GetDepends().end(); ++d) {
+ // Lookup the real name of the dependency in case it is a CMake target.
+ std::string dep;
+ if (this->GetRealDependency(*d, this->ConfigName, dep)) {
+ depends.push_back(dep);
+ }
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::AppendCustomCommands(
+ std::vector<std::string>& commands, const std::vector<cmCustomCommand>& ccs,
+ cmGeneratorTarget* target, cmOutputConverter::RelativeRoot relative)
+{
+ for (std::vector<cmCustomCommand>::const_iterator i = ccs.begin();
+ i != ccs.end(); ++i) {
+ cmCustomCommandGenerator ccg(*i, this->ConfigName, this);
+ this->AppendCustomCommand(commands, ccg, target, true, relative);
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::AppendCustomCommand(
+ std::vector<std::string>& commands, cmCustomCommandGenerator const& ccg,
+ cmGeneratorTarget* target, bool echo_comment,
+ cmOutputConverter::RelativeRoot relative, std::ostream* content)
+{
+ // Optionally create a command to display the custom command's
+ // comment text. This is used for pre-build, pre-link, and
+ // post-build command comments. Custom build step commands have
+ // their comments generated elsewhere.
+ if (echo_comment) {
+ const char* comment = ccg.GetComment();
+ if (comment && *comment) {
+ this->AppendEcho(commands, comment,
+ cmLocalUnixMakefileGenerator3::EchoGenerate);
+ }
+ }
+
+ // if the command specified a working directory use it.
+ std::string dir = this->GetCurrentBinaryDirectory();
+ std::string workingDir = ccg.GetWorkingDirectory();
+ if (!workingDir.empty()) {
+ dir = workingDir;
+ }
+ if (content) {
+ *content << dir;
+ }
+
+ // Add each command line to the set of commands.
+ std::vector<std::string> commands1;
+ 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->IsWindowsShell()) {
+ std::string suffix;
+ if (cmd.size() > 4) {
+ suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size() - 4));
+ if (suffix == ".bat" || suffix == ".cmd") {
+ useCall = true;
+ }
+ }
+ }
+
+ 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('/') != cmd.npos;
+ if (workingDir.empty()) {
+ cmd = this->Convert(cmd, cmOutputConverter::START_OUTPUT);
+ }
+ bool has_slash = cmd.find('/') != cmd.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;
+ }
+ std::string launcher = this->MakeLauncher(
+ ccg, target, workingDir.empty() ? cmOutputConverter::START_OUTPUT
+ : cmOutputConverter::NONE);
+ cmd = launcher + this->ConvertShellCommand(cmd, cmOutputConverter::NONE);
+
+ ccg.AppendArguments(c, cmd);
+ if (content) {
+ // Rule content does not include the launcher.
+ *content << (cmd.c_str() + launcher.size());
+ }
+ if (this->BorlandMakeCurlyHack) {
+ // Borland Make has a very strange bug. If the first curly
+ // brace anywhere in the command string is a left curly, it
+ // must be written {{} instead of just {. Otherwise some
+ // curly braces are removed. The hack can be skipped if the
+ // first curly brace is the last character.
+ std::string::size_type lcurly = cmd.find('{');
+ if (lcurly != cmd.npos && lcurly < (cmd.size() - 1)) {
+ std::string::size_type rcurly = cmd.find('}');
+ if (rcurly == cmd.npos || rcurly > lcurly) {
+ // The first curly is a left curly. Use the hack.
+ std::string hack_cmd = cmd.substr(0, lcurly);
+ hack_cmd += "{{}";
+ hack_cmd += cmd.substr(lcurly + 1);
+ cmd = hack_cmd;
+ }
+ }
+ }
+ if (launcher.empty()) {
+ if (useCall) {
+ cmd = "call " + cmd;
+ } else if (this->IsNMake() && cmd[0] == '"') {
+ cmd = "echo >nul && " + cmd;
+ }
+ }
+ commands1.push_back(cmd);
+ }
+ }
+
+ // Setup the proper working directory for the commands.
+ this->CreateCDCommand(commands1, dir.c_str(), relative);
+
+ // push back the custom commands
+ commands.insert(commands.end(), commands1.begin(), commands1.end());
+}
+
+std::string cmLocalUnixMakefileGenerator3::MakeLauncher(
+ cmCustomCommandGenerator const& ccg, cmGeneratorTarget* target,
+ cmOutputConverter::RelativeRoot relative)
+{
+ // Short-circuit if there is no launcher.
+ const char* prop = "RULE_LAUNCH_CUSTOM";
+ const char* val = this->GetRuleLauncher(target, prop);
+ if (!(val && *val)) {
+ return "";
+ }
+
+ // Expand rules in the empty string. It may insert the launcher and
+ // perform replacements.
+ RuleVariables vars;
+ vars.RuleLauncher = prop;
+ vars.CMTarget = target;
+ std::string output;
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ if (!outputs.empty()) {
+ output = this->Convert(outputs[0], relative, cmOutputConverter::SHELL);
+ }
+ vars.Output = output.c_str();
+
+ std::string launcher;
+ this->ExpandRuleVariables(launcher, vars);
+ if (!launcher.empty()) {
+ launcher += " ";
+ }
+ return launcher;
+}
+
+void cmLocalUnixMakefileGenerator3::AppendCleanCommand(
+ std::vector<std::string>& commands, const std::vector<std::string>& files,
+ cmGeneratorTarget* target, const char* filename)
+{
+ std::string cleanfile = this->GetCurrentBinaryDirectory();
+ cleanfile += "/";
+ cleanfile += this->GetTargetDirectory(target);
+ cleanfile += "/cmake_clean";
+ if (filename) {
+ cleanfile += "_";
+ cleanfile += filename;
+ }
+ cleanfile += ".cmake";
+ std::string cleanfilePath =
+ this->Convert(cleanfile, cmOutputConverter::FULL);
+ cmsys::ofstream fout(cleanfilePath.c_str());
+ if (!fout) {
+ cmSystemTools::Error("Could not create ", cleanfilePath.c_str());
+ }
+ if (!files.empty()) {
+ fout << "file(REMOVE_RECURSE\n";
+ for (std::vector<std::string>::const_iterator f = files.begin();
+ f != files.end(); ++f) {
+ std::string fc = this->Convert(*f, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED);
+ fout << " " << cmOutputConverter::EscapeForCMake(fc) << "\n";
+ }
+ fout << ")\n";
+ }
+ std::string remove = "$(CMAKE_COMMAND) -P ";
+ remove += this->Convert(cleanfile, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+ commands.push_back(remove);
+
+ // For the main clean rule add per-language cleaning.
+ if (!filename) {
+ // Get the set of source languages in the target.
+ std::set<std::string> languages;
+ target->GetLanguages(
+ languages, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ /* clang-format off */
+ fout << "\n"
+ << "# Per-language clean rules from dependency scanning.\n"
+ << "foreach(lang " << cmJoin(languages, " ") << ")\n"
+ << " include(" << this->GetTargetDirectory(target)
+ << "/cmake_clean_${lang}.cmake OPTIONAL)\n"
+ << "endforeach()\n";
+ /* clang-format on */
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::AppendEcho(
+ std::vector<std::string>& commands, std::string const& text, EchoColor color,
+ EchoProgress const* progress)
+{
+ // Choose the color for the text.
+ std::string color_name;
+ if (this->GlobalGenerator->GetToolSupportsColor() && this->ColorMakefile) {
+ // See cmake::ExecuteEchoColor in cmake.cxx for these options.
+ // This color set is readable on both black and white backgrounds.
+ switch (color) {
+ case EchoNormal:
+ break;
+ case EchoDepend:
+ color_name = "--magenta --bold ";
+ break;
+ case EchoBuild:
+ color_name = "--green ";
+ break;
+ case EchoLink:
+ color_name = "--green --bold ";
+ break;
+ case EchoGenerate:
+ color_name = "--blue --bold ";
+ break;
+ case EchoGlobal:
+ color_name = "--cyan ";
+ break;
+ }
+ }
+
+ // Echo one line at a time.
+ std::string line;
+ line.reserve(200);
+ for (const char* c = text.c_str();; ++c) {
+ if (*c == '\n' || *c == '\0') {
+ // Avoid writing a blank last line on end-of-string.
+ if (*c != '\0' || !line.empty()) {
+ // Add a command to echo this line.
+ std::string cmd;
+ if (color_name.empty() && !progress) {
+ // Use the native echo command.
+ cmd = "@echo ";
+ cmd += this->EscapeForShell(line, false, true);
+ } else {
+ // Use cmake to echo the text in color.
+ cmd = "@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) ";
+ cmd += color_name;
+ if (progress) {
+ cmd += "--progress-dir=";
+ cmd += this->Convert(progress->Dir, cmOutputConverter::FULL,
+ cmOutputConverter::SHELL);
+ cmd += " ";
+ cmd += "--progress-num=";
+ cmd += progress->Arg;
+ cmd += " ";
+ }
+ cmd += this->EscapeForShell(line);
+ }
+ commands.push_back(cmd);
+ }
+
+ // Reset the line to emtpy.
+ line = "";
+
+ // Progress appears only on first line.
+ progress = CM_NULLPTR;
+
+ // Terminate on end-of-string.
+ if (*c == '\0') {
+ return;
+ }
+ } else if (*c != '\r') {
+ // Append this character to the current line.
+ line += *c;
+ }
+ }
+}
+
+std::string cmLocalUnixMakefileGenerator3::CreateMakeVariable(
+ const std::string& sin, const std::string& s2)
+{
+ std::string s = sin;
+ std::string unmodified = s;
+ unmodified += s2;
+ // if there is no restriction on the length of make variables
+ // and there are no "." characters in the string, then return the
+ // unmodified combination.
+ if ((!this->MakefileVariableSize && unmodified.find('.') == s.npos) &&
+ (!this->MakefileVariableSize && unmodified.find('+') == s.npos) &&
+ (!this->MakefileVariableSize && unmodified.find('-') == s.npos)) {
+ return unmodified;
+ }
+
+ // see if the variable has been defined before and return
+ // the modified version of the variable
+ std::map<std::string, std::string>::iterator i =
+ this->MakeVariableMap.find(unmodified);
+ if (i != this->MakeVariableMap.end()) {
+ return i->second;
+ }
+ // start with the unmodified variable
+ std::string ret = unmodified;
+ // if this there is no value for this->MakefileVariableSize then
+ // the string must have bad characters in it
+ if (!this->MakefileVariableSize) {
+ std::replace(ret.begin(), ret.end(), '.', '_');
+ cmSystemTools::ReplaceString(ret, "-", "__");
+ cmSystemTools::ReplaceString(ret, "+", "___");
+ int ni = 0;
+ char buffer[5];
+ // make sure the _ version is not already used, if
+ // it is used then add number to the end of the variable
+ while (this->ShortMakeVariableMap.count(ret) && ni < 1000) {
+ ++ni;
+ sprintf(buffer, "%04d", ni);
+ ret = unmodified + buffer;
+ }
+ this->ShortMakeVariableMap[ret] = "1";
+ this->MakeVariableMap[unmodified] = ret;
+ return ret;
+ }
+
+ // if the string is greater than 32 chars it is an invalid variable name
+ // for borland make
+ if (static_cast<int>(ret.size()) > this->MakefileVariableSize) {
+ int keep = this->MakefileVariableSize - 8;
+ int size = keep + 3;
+ std::string str1 = s;
+ std::string str2 = s2;
+ // we must shorten the combined string by 4 characters
+ // keep no more than 24 characters from the second string
+ if (static_cast<int>(str2.size()) > keep) {
+ str2 = str2.substr(0, keep);
+ }
+ if (static_cast<int>(str1.size()) + static_cast<int>(str2.size()) > size) {
+ str1 = str1.substr(0, size - str2.size());
+ }
+ char buffer[5];
+ int ni = 0;
+ sprintf(buffer, "%04d", ni);
+ ret = str1 + str2 + buffer;
+ while (this->ShortMakeVariableMap.count(ret) && ni < 1000) {
+ ++ni;
+ sprintf(buffer, "%04d", ni);
+ ret = str1 + str2 + buffer;
+ }
+ if (ni == 1000) {
+ cmSystemTools::Error("Borland makefile variable length too long");
+ return unmodified;
+ }
+ // once an unused variable is found
+ this->ShortMakeVariableMap[ret] = "1";
+ }
+ // always make an entry into the unmodified to variable map
+ this->MakeVariableMap[unmodified] = ret;
+ return ret;
+}
+
+bool cmLocalUnixMakefileGenerator3::UpdateDependencies(const char* tgtInfo,
+ bool verbose,
+ bool color)
+{
+ // read in the target info file
+ if (!this->Makefile->ReadListFile(tgtInfo) ||
+ cmSystemTools::GetErrorOccuredFlag()) {
+ cmSystemTools::Error("Target DependInfo.cmake file not found");
+ }
+
+ // 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";
+
+ // 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();
+ {
+ int result;
+ if (!ftc->FileTimeCompare(internalDependFile.c_str(), tgtInfo, &result) ||
+ result < 0) {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Dependee \"" << tgtInfo << "\" is newer than depender \""
+ << internalDependFile << "\"." << std::endl;
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ needRescanDependInfo = true;
+ }
+ }
+
+ // 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 += cmake::GetCMakeFilesDirectory();
+ dirInfoFile += "/CMakeDirectoryInformation.cmake";
+ {
+ int result;
+ if (!ftc->FileTimeCompare(internalDependFile.c_str(), dirInfoFile.c_str(),
+ &result) ||
+ result < 0) {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Dependee \"" << dirInfoFile << "\" is newer than depender \""
+ << internalDependFile << "\"." << std::endl;
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ needRescanDirInfo = true;
+ }
+ }
+
+ // Check the implicit dependencies to see if they are up to date.
+ // 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;
+ bool needRescanDependencies = false;
+ if (!needRescanDirInfo) {
+ cmDependsC checker;
+ checker.SetVerbose(verbose);
+ checker.SetFileComparison(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.
+ // We don't do that if the CMakeDirectoryInformation.cmake file has
+ // changed, because then potentially all dependencies have changed.
+ // This information is given later on to cmDependsC, which then only
+ // rescans the files where it did not get valid dependencies via this
+ // dependency vector. This means that in the normal case, when only
+ // few or one file have been edited, then also only this one file is
+ // actually scanned again, instead of all files for this target.
+ needRescanDependencies = !checker.Check(
+ dependFile.c_str(), internalDependFile.c_str(), validDependencies);
+ }
+
+ if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
+ // The dependencies must be regenerated.
+ std::string targetName = cmSystemTools::GetFilenameName(dir);
+ targetName = targetName.substr(0, targetName.length() - 4);
+ std::string message = "Scanning dependencies of target ";
+ message += targetName;
+ cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
+ cmsysTerminal_Color_ForegroundBold,
+ message.c_str(), true, color);
+
+ return this->ScanDependencies(dir.c_str(), validDependencies);
+ }
+
+ // The dependencies are already up-to-date.
+ return true;
+}
+
+bool cmLocalUnixMakefileGenerator3::ScanDependencies(
+ const char* targetDir,
+ std::map<std::string, cmDepends::DependencyVector>& validDeps)
+{
+ // Read the directory information file.
+ cmMakefile* mf = this->Makefile;
+ bool haveDirectoryInfo = false;
+ std::string dirInfoFile = this->GetCurrentBinaryDirectory();
+ dirInfoFile += cmake::GetCMakeFilesDirectory();
+ dirInfoFile += "/CMakeDirectoryInformation.cmake";
+ if (mf->ReadListFile(dirInfoFile.c_str()) &&
+ !cmSystemTools::GetErrorOccuredFlag()) {
+ haveDirectoryInfo = true;
+ }
+
+ // Lookup useful directory information.
+ if (haveDirectoryInfo) {
+ // Test whether we need to force Unix paths.
+ if (const char* force = mf->GetDefinition("CMAKE_FORCE_UNIX_PATHS")) {
+ if (!cmSystemTools::IsOff(force)) {
+ cmSystemTools::SetForceUnixPaths(true);
+ }
+ }
+
+ // Setup relative path top directories.
+ if (const char* relativePathTopSource =
+ mf->GetDefinition("CMAKE_RELATIVE_PATH_TOP_SOURCE")) {
+ this->StateSnapshot.GetDirectory().SetRelativePathTopSource(
+ relativePathTopSource);
+ }
+ if (const char* relativePathTopBinary =
+ mf->GetDefinition("CMAKE_RELATIVE_PATH_TOP_BINARY")) {
+ this->StateSnapshot.GetDirectory().SetRelativePathTopBinary(
+ relativePathTopBinary);
+ }
+ } else {
+ cmSystemTools::Error("Directory Information file not found");
+ }
+
+ // create the file stream for the depends file
+ std::string dir = targetDir;
+
+ // 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 = dir;
+ ruleFileNameFull += "/depend.make";
+ cmGeneratedFileStream ruleFileStream(ruleFileNameFull.c_str());
+ ruleFileStream.SetCopyIfDifferent(true);
+ if (!ruleFileStream) {
+ return false;
+ }
+
+ // 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 = dir;
+ internalRuleFileNameFull += "/depend.internal";
+ cmGeneratedFileStream internalRuleFileStream(
+ internalRuleFileNameFull.c_str());
+ if (!internalRuleFileStream) {
+ return false;
+ }
+
+ this->WriteDisclaimer(ruleFileStream);
+ this->WriteDisclaimer(internalRuleFileStream);
+
+ // for each language we need to scan, scan it
+ const char* langStr = mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES");
+ std::vector<std::string> langs;
+ cmSystemTools::ExpandListArgument(langStr, langs);
+ for (std::vector<std::string>::iterator li = langs.begin();
+ li != langs.end(); ++li) {
+ // construct the checker
+ std::string lang = *li;
+
+ // Create the scanner for this language
+ cmDepends* scanner = CM_NULLPTR;
+ if (lang == "C" || lang == "CXX" || lang == "RC" || lang == "ASM") {
+ // TODO: Handle RC (resource files) dependencies correctly.
+ scanner = new cmDependsC(this, targetDir, lang, &validDeps);
+ }
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ else if (lang == "Fortran") {
+ scanner = new cmDependsFortran(this);
+ } else if (lang == "Java") {
+ scanner = new cmDependsJava();
+ }
+#endif
+
+ if (scanner) {
+ scanner->SetLocalGenerator(this);
+ scanner->SetFileComparison(
+ this->GlobalGenerator->GetCMakeInstance()->GetFileComparison());
+ scanner->SetLanguage(lang);
+ scanner->SetTargetDirectory(dir.c_str());
+ scanner->Write(ruleFileStream, internalRuleFileStream);
+
+ // free the scanner for this language
+ delete scanner;
+ }
+ }
+
+ return true;
+}
+
+void cmLocalUnixMakefileGenerator3::CheckMultipleOutputs(bool verbose)
+{
+ cmMakefile* mf = this->Makefile;
+
+ // Get the string listing the multiple output pairs.
+ const char* pairs_string = mf->GetDefinition("CMAKE_MULTIPLE_OUTPUT_PAIRS");
+ if (!pairs_string) {
+ return;
+ }
+
+ // Convert the string to a list and preserve empty entries.
+ std::vector<std::string> pairs;
+ cmSystemTools::ExpandListArgument(pairs_string, pairs, true);
+ for (std::vector<std::string>::const_iterator i = pairs.begin();
+ i != pairs.end() && (i + 1) != pairs.end();) {
+ const std::string& depender = *i++;
+ const std::string& dependee = *i++;
+
+ // If the depender is missing then delete the dependee to make
+ // sure both will be regenerated.
+ if (cmSystemTools::FileExists(dependee.c_str()) &&
+ !cmSystemTools::FileExists(depender.c_str())) {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Deleting primary custom command output \"" << dependee
+ << "\" because another output \"" << depender
+ << "\" does not exist." << std::endl;
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ cmSystemTools::RemoveFile(dependee);
+ }
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::WriteLocalAllRules(
+ std::ostream& ruleFileStream)
+{
+ this->WriteDisclaimer(ruleFileStream);
+
+ // Write the main entry point target. This must be the VERY first
+ // target so that make with no arguments will run it.
+ {
+ // Just depend on the all target to drive the build.
+ std::vector<std::string> depends;
+ std::vector<std::string> no_commands;
+ depends.push_back("all");
+
+ // Write the rule.
+ this->WriteMakeRule(ruleFileStream,
+ "Default target executed when no arguments are "
+ "given to make.",
+ "default_target", depends, no_commands, true);
+
+ // Help out users that try "gmake target1 target2 -j".
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ if (gg->AllowNotParallel()) {
+ std::vector<std::string> no_depends;
+ this->WriteMakeRule(ruleFileStream, "Allow only one \"make -f "
+ "Makefile2\" at a time, but pass "
+ "parallelism.",
+ ".NOTPARALLEL", no_depends, no_commands, false);
+ }
+ }
+
+ this->WriteSpecialTargetsTop(ruleFileStream);
+
+ // Include the progress variables for the target.
+ // Write all global targets
+ this->WriteDivider(ruleFileStream);
+ ruleFileStream << "# Targets provided globally by CMake.\n"
+ << "\n";
+ std::vector<cmGeneratorTarget*> targets = this->GetGeneratorTargets();
+ std::vector<cmGeneratorTarget*>::iterator glIt;
+ for (glIt = targets.begin(); glIt != targets.end(); ++glIt) {
+ if ((*glIt)->GetType() == cmState::GLOBAL_TARGET) {
+ std::string targetString =
+ "Special rule for the target " + (*glIt)->GetName();
+ std::vector<std::string> commands;
+ std::vector<std::string> depends;
+
+ const char* text = (*glIt)->GetProperty("EchoString");
+ if (!text) {
+ text = "Running external command ...";
+ }
+ depends.insert(depends.end(), (*glIt)->GetUtilities().begin(),
+ (*glIt)->GetUtilities().end());
+ this->AppendEcho(commands, text,
+ cmLocalUnixMakefileGenerator3::EchoGlobal);
+
+ cmGeneratorTarget* gt = *glIt;
+
+ // Global targets store their rules in pre- and post-build commands.
+ this->AppendCustomDepends(depends, gt->GetPreBuildCommands());
+ this->AppendCustomDepends(depends, gt->GetPostBuildCommands());
+ this->AppendCustomCommands(commands, gt->GetPreBuildCommands(), gt,
+ cmOutputConverter::START_OUTPUT);
+ this->AppendCustomCommands(commands, gt->GetPostBuildCommands(), gt,
+ cmOutputConverter::START_OUTPUT);
+ std::string targetName = gt->GetName();
+ this->WriteMakeRule(ruleFileStream, targetString.c_str(), targetName,
+ depends, commands, true);
+
+ // Provide a "/fast" version of the target.
+ depends.clear();
+ if ((targetName == "install") || (targetName == "install_local") ||
+ (targetName == "install_strip")) {
+ // Provide a fast install target that does not depend on all
+ // but has the same command.
+ depends.push_back("preinstall/fast");
+ } else {
+ // Just forward to the real target so at least it will work.
+ depends.push_back(targetName);
+ commands.clear();
+ }
+ targetName += "/fast";
+ this->WriteMakeRule(ruleFileStream, targetString.c_str(), targetName,
+ depends, commands, true);
+ }
+ }
+
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+
+ // Write the all rule.
+ std::string recursiveTarget = this->GetCurrentBinaryDirectory();
+ recursiveTarget += "/all";
+
+ depends.push_back("cmake_check_build_system");
+
+ std::string progressDir = this->GetBinaryDirectory();
+ progressDir += cmake::GetCMakeFilesDirectory();
+ {
+ std::ostringstream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
+ progCmd << this->Convert(progressDir, cmOutputConverter::FULL,
+ cmOutputConverter::SHELL);
+
+ std::string progressFile = cmake::GetCMakeFilesDirectory();
+ progressFile += "/progress.marks";
+ std::string progressFileNameFull = this->ConvertToFullPath(progressFile);
+ progCmd << " "
+ << this->Convert(progressFileNameFull, cmOutputConverter::FULL,
+ cmOutputConverter::SHELL);
+ commands.push_back(progCmd.str());
+ }
+ std::string mf2Dir = cmake::GetCMakeFilesDirectoryPostSlash();
+ mf2Dir += "Makefile2";
+ commands.push_back(
+ this->GetRecursiveMakeCall(mf2Dir.c_str(), recursiveTarget));
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ cmOutputConverter::START_OUTPUT);
+ {
+ std::ostringstream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
+ progCmd << this->Convert(progressDir, cmOutputConverter::FULL,
+ cmOutputConverter::SHELL);
+ progCmd << " 0";
+ commands.push_back(progCmd.str());
+ }
+ this->WriteMakeRule(ruleFileStream, "The main all target", "all", depends,
+ commands, true);
+
+ // Write the clean rule.
+ recursiveTarget = this->GetCurrentBinaryDirectory();
+ recursiveTarget += "/clean";
+ commands.clear();
+ depends.clear();
+ commands.push_back(
+ this->GetRecursiveMakeCall(mf2Dir.c_str(), recursiveTarget));
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ cmOutputConverter::START_OUTPUT);
+ this->WriteMakeRule(ruleFileStream, "The main clean target", "clean",
+ depends, commands, true);
+ commands.clear();
+ depends.clear();
+ depends.push_back("clean");
+ this->WriteMakeRule(ruleFileStream, "The main clean target", "clean/fast",
+ depends, commands, true);
+
+ // Write the preinstall rule.
+ recursiveTarget = this->GetCurrentBinaryDirectory();
+ recursiveTarget += "/preinstall";
+ commands.clear();
+ depends.clear();
+ const char* noall =
+ this->Makefile->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
+ if (!noall || cmSystemTools::IsOff(noall)) {
+ // Drive the build before installing.
+ depends.push_back("all");
+ } else {
+ // At least make sure the build system is up to date.
+ depends.push_back("cmake_check_build_system");
+ }
+ commands.push_back(
+ this->GetRecursiveMakeCall(mf2Dir.c_str(), recursiveTarget));
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ cmOutputConverter::START_OUTPUT);
+ this->WriteMakeRule(ruleFileStream, "Prepare targets for installation.",
+ "preinstall", depends, commands, true);
+ depends.clear();
+ this->WriteMakeRule(ruleFileStream, "Prepare targets for installation.",
+ "preinstall/fast", depends, commands, true);
+
+ // write the depend rule, really a recompute depends rule
+ depends.clear();
+ commands.clear();
+ std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash();
+ cmakefileName += "Makefile.cmake";
+ std::string runRule =
+ "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)";
+ runRule += " --check-build-system ";
+ runRule += this->Convert(cmakefileName, cmOutputConverter::NONE,
+ cmOutputConverter::SHELL);
+ runRule += " 1";
+ commands.push_back(runRule);
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ cmOutputConverter::START_OUTPUT);
+ this->WriteMakeRule(ruleFileStream, "clear depends", "depend", depends,
+ commands, true);
+}
+
+void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf,
+ bool verbose)
+{
+ // Get the list of target files to check
+ const char* infoDef = mf->GetDefinition("CMAKE_DEPEND_INFO_FILES");
+ if (!infoDef) {
+ return;
+ }
+ std::vector<std::string> files;
+ cmSystemTools::ExpandListArgument(infoDef, files);
+
+ // Each depend information file corresponds to a target. Clear the
+ // dependencies for that target.
+ cmDepends clearer;
+ clearer.SetVerbose(verbose);
+ for (std::vector<std::string>::iterator l = files.begin(); l != files.end();
+ ++l) {
+ std::string dir = cmSystemTools::GetFilenamePath(*l);
+
+ // Clear the implicit dependency makefile.
+ std::string dependFile = dir + "/depend.make";
+ clearer.Clear(dependFile.c_str());
+
+ // Remove the internal dependency check file to force
+ // regeneration.
+ std::string internalDependFile = dir + "/depend.internal";
+ cmSystemTools::RemoveFile(internalDependFile);
+ }
+}
+
+namespace {
+// Helper predicate for removing absolute paths that don't point to the
+// source or binary directory. It is used when CMAKE_DEPENDS_IN_PROJECT_ONLY
+// is set ON, to only consider in-project dependencies during the build.
+class NotInProjectDir
+{
+public:
+ // Constructor with the source and binary directory's path
+ NotInProjectDir(const std::string& sourceDir, const std::string& binaryDir)
+ : SourceDir(sourceDir)
+ , BinaryDir(binaryDir)
+ {
+ }
+
+ // Operator evaluating the predicate
+ bool operator()(const std::string& path) const
+ {
+ // Keep all relative paths:
+ if (!cmSystemTools::FileIsFullPath(path)) {
+ return false;
+ }
+ // If it's an absolute path, check if it starts with the source
+ // direcotory:
+ return (
+ !(IsInDirectory(SourceDir, path) || IsInDirectory(BinaryDir, path)));
+ }
+
+private:
+ // Helper function used by the predicate
+ static bool IsInDirectory(const std::string& baseDir,
+ const std::string& testDir)
+ {
+ // First check if the test directory "starts with" the base directory:
+ if (testDir.find(baseDir) != 0) {
+ return false;
+ }
+ // If it does, then check that it's either the same string, or that the
+ // next character is a slash:
+ return ((testDir.size() == baseDir.size()) ||
+ (testDir[baseDir.size()] == '/'));
+ }
+
+ // The path to the source directory
+ std::string SourceDir;
+ // The path to the binary directory
+ std::string BinaryDir;
+};
+}
+
+void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo(
+ std::ostream& cmakefileStream, cmGeneratorTarget* target)
+{
+ ImplicitDependLanguageMap const& implicitLangs =
+ this->GetImplicitDepends(target);
+
+ // list the languages
+ cmakefileStream
+ << "# The set of languages for which implicit dependencies are needed:\n";
+ cmakefileStream << "set(CMAKE_DEPENDS_LANGUAGES\n";
+ for (ImplicitDependLanguageMap::const_iterator l = implicitLangs.begin();
+ l != implicitLangs.end(); ++l) {
+ cmakefileStream << " \"" << l->first << "\"\n";
+ }
+ cmakefileStream << " )\n";
+
+ // now list the files for each language
+ cmakefileStream
+ << "# The set of files for implicit dependencies of each language:\n";
+ for (ImplicitDependLanguageMap::const_iterator l = implicitLangs.begin();
+ l != implicitLangs.end(); ++l) {
+ cmakefileStream << "set(CMAKE_DEPENDS_CHECK_" << l->first << "\n";
+ ImplicitDependFileMap const& implicitPairs = l->second;
+
+ // for each file pair
+ for (ImplicitDependFileMap::const_iterator pi = implicitPairs.begin();
+ pi != implicitPairs.end(); ++pi) {
+ for (cmDepends::DependencyVector::const_iterator di = pi->second.begin();
+ di != pi->second.end(); ++di) {
+ cmakefileStream << " \"" << *di << "\" ";
+ cmakefileStream << "\"" << pi->first << "\"\n";
+ }
+ }
+ cmakefileStream << " )\n";
+
+ // Tell the dependency scanner what compiler is used.
+ std::string cidVar = "CMAKE_";
+ cidVar += l->first;
+ cidVar += "_COMPILER_ID";
+ const char* cid = this->Makefile->GetDefinition(cidVar);
+ if (cid && *cid) {
+ cmakefileStream << "set(CMAKE_" << l->first << "_COMPILER_ID \"" << cid
+ << "\")\n";
+ }
+
+ // Build a list of preprocessor definitions for the target.
+ std::set<std::string> defines;
+ this->AddCompileDefinitions(defines, target, this->ConfigName, l->first);
+ if (!defines.empty()) {
+ /* clang-format off */
+ cmakefileStream
+ << "\n"
+ << "# Preprocessor definitions for this target.\n"
+ << "set(CMAKE_TARGET_DEFINITIONS_" << l->first << "\n";
+ /* clang-format on */
+ for (std::set<std::string>::const_iterator di = defines.begin();
+ di != defines.end(); ++di) {
+ cmakefileStream << " " << cmOutputConverter::EscapeForCMake(*di)
+ << "\n";
+ }
+ cmakefileStream << " )\n";
+ }
+
+ // Target-specific include directories:
+ cmakefileStream << "\n"
+ << "# The include file search paths:\n";
+ cmakefileStream << "set(CMAKE_" << l->first << "_TARGET_INCLUDE_PATH\n";
+ std::vector<std::string> includes;
+
+ const std::string& config =
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ this->GetIncludeDirectories(includes, target, l->first, config);
+ if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) {
+ const char* sourceDir = this->GetState()->GetSourceDirectory();
+ const char* binaryDir = this->GetState()->GetBinaryDirectory();
+ std::vector<std::string>::iterator itr =
+ std::remove_if(includes.begin(), includes.end(),
+ ::NotInProjectDir(sourceDir, binaryDir));
+ includes.erase(itr, includes.end());
+ }
+ for (std::vector<std::string>::iterator i = includes.begin();
+ i != includes.end(); ++i) {
+ cmakefileStream << " \""
+ << this->Convert(*i, cmOutputConverter::HOME_OUTPUT)
+ << "\"\n";
+ }
+ cmakefileStream << " )\n";
+ }
+
+ // Store include transform rule properties. Write the directory
+ // rules first because they may be overridden by later target rules.
+ std::vector<std::string> transformRules;
+ if (const char* xform =
+ this->Makefile->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
+ cmSystemTools::ExpandListArgument(xform, transformRules);
+ }
+ if (const char* xform =
+ target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
+ cmSystemTools::ExpandListArgument(xform, transformRules);
+ }
+ if (!transformRules.empty()) {
+ cmakefileStream << "set(CMAKE_INCLUDE_TRANSFORMS\n";
+ for (std::vector<std::string>::const_iterator tri = transformRules.begin();
+ tri != transformRules.end(); ++tri) {
+ cmakefileStream << " " << cmOutputConverter::EscapeForCMake(*tri)
+ << "\n";
+ }
+ cmakefileStream << " )\n";
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::WriteDisclaimer(std::ostream& os)
+{
+ os << "# CMAKE generated file: DO NOT EDIT!\n"
+ << "# Generated by \"" << this->GlobalGenerator->GetName() << "\""
+ << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
+ << cmVersion::GetMinorVersion() << "\n\n";
+}
+
+std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall(
+ const char* makefile, const std::string& tgt)
+{
+ // Call make on the given file.
+ std::string cmd;
+ cmd += "$(MAKE) -f ";
+ cmd +=
+ this->Convert(makefile, cmOutputConverter::NONE, cmOutputConverter::SHELL);
+ cmd += " ";
+
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ // Pass down verbosity level.
+ if (!gg->MakeSilentFlag.empty()) {
+ cmd += gg->MakeSilentFlag;
+ cmd += " ";
+ }
+
+ // Most unix makes will pass the command line flags to make down to
+ // sub-invoked makes via an environment variable. However, some
+ // makes do not support that, so you have to pass the flags
+ // explicitly.
+ if (gg->PassMakeflags) {
+ cmd += "-$(MAKEFLAGS) ";
+ }
+
+ // Add the target.
+ if (!tgt.empty()) {
+ // The make target is always relative to the top of the build tree.
+ std::string tgt2 = this->Convert(tgt, cmOutputConverter::HOME_OUTPUT);
+
+ // The target may have been written with windows paths.
+ cmSystemTools::ConvertToOutputSlashes(tgt2);
+
+ // Escape one extra time if the make tool requires it.
+ if (this->MakeCommandEscapeTargetTwice) {
+ tgt2 = this->EscapeForShell(tgt2, true, false);
+ }
+
+ // The target name is now a string that should be passed verbatim
+ // on the command line.
+ cmd += this->EscapeForShell(tgt2, true, false);
+ }
+ return cmd;
+}
+
+void cmLocalUnixMakefileGenerator3::WriteDivider(std::ostream& os)
+{
+ os << "#======================================"
+ << "=======================================\n";
+}
+
+void cmLocalUnixMakefileGenerator3::WriteCMakeArgument(std::ostream& os,
+ const char* s)
+{
+ // Write the given string to the stream with escaping to get it back
+ // into CMake through the lexical scanner.
+ os << "\"";
+ for (const char* c = s; *c; ++c) {
+ if (*c == '\\') {
+ os << "\\\\";
+ } else if (*c == '"') {
+ os << "\\\"";
+ } else {
+ os << *c;
+ }
+ }
+ os << "\"";
+}
+
+std::string cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath(
+ const char* p, bool useWatcomQuote)
+{
+ // Split the path into its components.
+ std::vector<std::string> components;
+ cmSystemTools::SplitPath(p, components);
+
+ // Open the quoted result.
+ std::string result;
+ if (useWatcomQuote) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ result = "'";
+#else
+ result = "\"'";
+#endif
+ } else {
+ result = "\"";
+ }
+
+ // Return an empty path if there are no components.
+ if (!components.empty()) {
+ // Choose a slash direction and fix root component.
+ const char* slash = "/";
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (!cmSystemTools::GetForceUnixPaths()) {
+ slash = "\\";
+ for (std::string::iterator i = components[0].begin();
+ i != components[0].end(); ++i) {
+ if (*i == '/') {
+ *i = '\\';
+ }
+ }
+ }
+#endif
+
+ // Begin the quoted result with the root component.
+ result += components[0];
+
+ if (components.size() > 1) {
+ // Now add the rest of the components separated by the proper slash
+ // direction for this platform.
+ std::vector<std::string>::const_iterator compEnd = std::remove(
+ components.begin() + 1, components.end() - 1, std::string());
+ std::vector<std::string>::const_iterator compStart =
+ components.begin() + 1;
+ result += cmJoin(cmMakeRange(compStart, compEnd), slash);
+ // Only the last component can be empty to avoid double slashes.
+ result += slash;
+ result += components.back();
+ }
+ }
+
+ // Close the quoted result.
+ if (useWatcomQuote) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ result += "'";
+#else
+ result += "'\"";
+#endif
+ } else {
+ result += "\"";
+ }
+
+ return result;
+}
+
+std::string cmLocalUnixMakefileGenerator3::GetTargetDirectory(
+ cmGeneratorTarget const* target) const
+{
+ std::string dir = cmake::GetCMakeFilesDirectoryPostSlash();
+ dir += target->GetName();
+#if defined(__VMS)
+ dir += "_dir";
+#else
+ dir += ".dir";
+#endif
+ return dir;
+}
+
+cmLocalUnixMakefileGenerator3::ImplicitDependLanguageMap const&
+cmLocalUnixMakefileGenerator3::GetImplicitDepends(const cmGeneratorTarget* tgt)
+{
+ return this->ImplicitDepends[tgt->GetName()];
+}
+
+void cmLocalUnixMakefileGenerator3::AddImplicitDepends(
+ const cmGeneratorTarget* tgt, const std::string& lang, const char* obj,
+ const char* src)
+{
+ this->ImplicitDepends[tgt->GetName()][lang][obj].push_back(src);
+}
+
+void cmLocalUnixMakefileGenerator3::CreateCDCommand(
+ std::vector<std::string>& commands, const char* tgtDir,
+ cmOutputConverter::RelativeRoot relRetDir)
+{
+ const char* retDir = this->GetRelativeRootPath(relRetDir);
+
+ // do we need to cd?
+ if (!strcmp(tgtDir, retDir)) {
+ return;
+ }
+
+ // In a Windows shell we must change drive letter too. The shell
+ // used by NMake and Borland make does not support "cd /d" so this
+ // feature simply cannot work with them (Borland make does not even
+ // support changing the drive letter with just "d:").
+ const char* cd_cmd = this->IsMinGWMake() ? "cd /d " : "cd ";
+
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ if (!gg->UnixCD) {
+ // On Windows we must perform each step separately and then change
+ // back because the shell keeps the working directory between
+ // commands.
+ std::string cmd = cd_cmd;
+ cmd += this->ConvertToOutputForExisting(tgtDir);
+ commands.insert(commands.begin(), cmd);
+
+ // Change back to the starting directory.
+ cmd = cd_cmd;
+ cmd += this->ConvertToOutputForExisting(relRetDir);
+ commands.push_back(cmd);
+ } else {
+ // On UNIX we must construct a single shell command to change
+ // directory and build because make resets the directory between
+ // each command.
+ std::string outputForExisting = this->ConvertToOutputForExisting(tgtDir);
+ std::string prefix = cd_cmd + outputForExisting + " && ";
+ std::transform(commands.begin(), commands.end(), commands.begin(),
+ std::bind1st(std::plus<std::string>(), prefix));
+ }
+}
diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h
new file mode 100644
index 0000000..42d1d91
--- /dev/null
+++ b/Source/cmLocalUnixMakefileGenerator3.h
@@ -0,0 +1,321 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLocalUnixMakefileGenerator3_h
+#define cmLocalUnixMakefileGenerator3_h
+
+#include "cmLocalCommonGenerator.h"
+
+// for cmDepends::DependencyVector
+#include "cmDepends.h"
+
+class cmCustomCommand;
+class cmCustomCommandGenerator;
+class cmDepends;
+class cmMakefileTargetGenerator;
+class cmSourceFile;
+
+/** \class cmLocalUnixMakefileGenerator3
+ * \brief Write a LocalUnix makefiles.
+ *
+ * cmLocalUnixMakefileGenerator3 produces a LocalUnix makefile from its
+ * member Makefile.
+ */
+class cmLocalUnixMakefileGenerator3 : public cmLocalCommonGenerator
+{
+public:
+ cmLocalUnixMakefileGenerator3(cmGlobalGenerator* gg, cmMakefile* mf);
+ ~cmLocalUnixMakefileGenerator3() CM_OVERRIDE;
+
+ void ComputeHomeRelativeOutputPath() CM_OVERRIDE;
+
+ /**
+ * Generate the makefile for this directory.
+ */
+ void Generate() CM_OVERRIDE;
+
+ // this returns the relative path between the HomeOutputDirectory and this
+ // local generators StartOutputDirectory
+ const std::string& GetHomeRelativeOutputPath();
+
+ // Write out a make rule
+ void WriteMakeRule(std::ostream& os, const char* comment,
+ const std::string& target,
+ const std::vector<std::string>& depends,
+ const std::vector<std::string>& commands, bool symbolic,
+ bool in_help = false);
+
+ // write the main variables used by the makefiles
+ void WriteMakeVariables(std::ostream& makefileStream);
+
+ /**
+ * Set max makefile variable size, default is 0 which means unlimited.
+ */
+ void SetMakefileVariableSize(int s) { this->MakefileVariableSize = s; }
+
+ /**
+ * Set whether passing a make target on a command line requires an
+ * extra level of escapes.
+ */
+ void SetMakeCommandEscapeTargetTwice(bool b)
+ {
+ this->MakeCommandEscapeTargetTwice = b;
+ }
+
+ /**
+ * Set whether the Borland curly brace command line hack should be
+ * applied.
+ */
+ void SetBorlandMakeCurlyHack(bool b) { this->BorlandMakeCurlyHack = b; }
+
+ // used in writing out Cmake files such as WriteDirectoryInformation
+ static void WriteCMakeArgument(std::ostream& os, const char* s);
+
+ /** creates the common disclaimer text at the top of each makefile */
+ void WriteDisclaimer(std::ostream& os);
+
+ // write a comment line #====... in the stream
+ void WriteDivider(std::ostream& os);
+
+ /** used to create a recursive make call */
+ std::string GetRecursiveMakeCall(const char* makefile,
+ const std::string& tgt);
+
+ // append flags to a string
+ void AppendFlags(std::string& flags,
+ const std::string& newFlags) CM_OVERRIDE;
+ void AppendFlags(std::string& flags, const char* newFlags) CM_OVERRIDE;
+
+ // append an echo command
+ enum EchoColor
+ {
+ EchoNormal,
+ EchoDepend,
+ EchoBuild,
+ EchoLink,
+ EchoGenerate,
+ EchoGlobal
+ };
+ struct EchoProgress
+ {
+ std::string Dir;
+ std::string Arg;
+ };
+ void AppendEcho(std::vector<std::string>& commands, std::string const& text,
+ EchoColor color = EchoNormal,
+ EchoProgress const* = CM_NULLPTR);
+
+ /** Get whether the makefile is to have color. */
+ bool GetColorMakefile() const { return this->ColorMakefile; }
+
+ std::string GetTargetDirectory(cmGeneratorTarget const* target) const
+ CM_OVERRIDE;
+
+ // create a command that cds to the start dir then runs the commands
+ void CreateCDCommand(std::vector<std::string>& commands,
+ const char* targetDir,
+ cmOutputConverter::RelativeRoot returnDir);
+
+ static std::string ConvertToQuotedOutputPath(const char* p,
+ bool useWatcomQuote);
+
+ std::string CreateMakeVariable(const std::string& sin,
+ const std::string& s2in);
+
+ /** Called from command-line hook to bring dependencies up to date
+ for a target. */
+ bool UpdateDependencies(const char* tgtInfo, bool verbose,
+ bool color) CM_OVERRIDE;
+
+ /** Called from command-line hook to clear dependencies. */
+ void ClearDependencies(cmMakefile* mf, bool verbose) CM_OVERRIDE;
+
+ /** write some extra rules such as make test etc */
+ void WriteSpecialTargetsTop(std::ostream& makefileStream);
+ void WriteSpecialTargetsBottom(std::ostream& makefileStream);
+
+ std::string GetRelativeTargetDirectory(cmGeneratorTarget* target);
+
+ // 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 ImplicitDependLanguageMap
+ : public std::map<std::string, ImplicitDependFileMap>
+ {
+ };
+ struct ImplicitDependTargetMap
+ : public std::map<std::string, ImplicitDependLanguageMap>
+ {
+ };
+ ImplicitDependLanguageMap const& GetImplicitDepends(
+ cmGeneratorTarget const* tgt);
+
+ void AddImplicitDepends(cmGeneratorTarget const* tgt,
+ const std::string& lang, const char* obj,
+ const char* src);
+
+ // write the target rules for the local Makefile into the stream
+ void WriteLocalAllRules(std::ostream& ruleFileStream);
+
+ std::vector<std::string> const& GetLocalHelp() { return this->LocalHelp; }
+
+ /** Get whether to create rules to generate preprocessed and
+ assembly sources. This could be converted to a variable lookup
+ later. */
+ bool GetCreatePreprocessedSourceRules()
+ {
+ return !this->SkipPreprocessedSourceRules;
+ }
+ bool GetCreateAssemblySourceRules()
+ {
+ return !this->SkipAssemblySourceRules;
+ }
+
+ // Fill the vector with the target names for the object files,
+ // preprocessed files and assembly files. Currently only used by the
+ // Eclipse generator.
+ void GetIndividualFileTargets(std::vector<std::string>& targets);
+
+protected:
+ void WriteLocalMakefile();
+
+ // write the target rules for the local Makefile into the stream
+ void WriteLocalMakefileTargets(std::ostream& ruleFileStream,
+ std::set<std::string>& emitted);
+
+ // this method Writes the Directory information files
+ void WriteDirectoryInformationFile();
+
+ // write the depend info
+ void WriteDependLanguageInfo(std::ostream& cmakefileStream,
+ cmGeneratorTarget* tgt);
+
+ // write the local help rule
+ void WriteHelpRule(std::ostream& ruleFileStream);
+
+ // this converts a file name that is relative to the StartOuputDirectory
+ // into a full path
+ std::string ConvertToFullPath(const std::string& localPath);
+
+ void WriteConvenienceRule(std::ostream& ruleFileStream,
+ const std::string& realTarget,
+ const std::string& helpTarget);
+
+ void WriteTargetDependRule(std::ostream& ruleFileStream,
+ cmGeneratorTarget* target);
+ void WriteTargetCleanRule(std::ostream& ruleFileStream,
+ cmGeneratorTarget* target,
+ const std::vector<std::string>& files);
+ void WriteTargetRequiresRule(std::ostream& ruleFileStream,
+ cmGeneratorTarget* target,
+ const std::vector<std::string>& objects);
+
+ void AppendRuleDepend(std::vector<std::string>& depends,
+ const char* ruleFileName);
+ void AppendRuleDepends(std::vector<std::string>& depends,
+ std::vector<std::string> const& ruleFiles);
+ void AppendCustomDepends(std::vector<std::string>& depends,
+ const std::vector<cmCustomCommand>& ccs);
+ void AppendCustomDepend(std::vector<std::string>& depends,
+ cmCustomCommandGenerator const& cc);
+ void AppendCustomCommands(
+ std::vector<std::string>& commands,
+ const std::vector<cmCustomCommand>& ccs, cmGeneratorTarget* target,
+ cmOutputConverter::RelativeRoot relative = cmOutputConverter::HOME_OUTPUT);
+ void AppendCustomCommand(
+ std::vector<std::string>& commands, cmCustomCommandGenerator const& ccg,
+ cmGeneratorTarget* target, bool echo_comment = false,
+ cmOutputConverter::RelativeRoot relative = cmOutputConverter::HOME_OUTPUT,
+ std::ostream* content = CM_NULLPTR);
+ void AppendCleanCommand(std::vector<std::string>& commands,
+ const std::vector<std::string>& files,
+ cmGeneratorTarget* target,
+ const char* filename = CM_NULLPTR);
+
+ // Helper methods for dependeny updates.
+ bool ScanDependencies(
+ const char* targetDir,
+ std::map<std::string, cmDepends::DependencyVector>& validDeps);
+ void CheckMultipleOutputs(bool verbose);
+
+private:
+ std::string ConvertShellCommand(std::string const& cmd,
+ cmOutputConverter::RelativeRoot root);
+ std::string MakeLauncher(cmCustomCommandGenerator const& ccg,
+ cmGeneratorTarget* target,
+ cmOutputConverter::RelativeRoot relative);
+
+ void ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt = CM_NULLPTR) CM_OVERRIDE;
+
+ friend class cmMakefileTargetGenerator;
+ friend class cmMakefileExecutableTargetGenerator;
+ friend class cmMakefileLibraryTargetGenerator;
+ friend class cmMakefileUtilityTargetGenerator;
+ friend class cmGlobalUnixMakefileGenerator3;
+
+ ImplicitDependTargetMap ImplicitDepends;
+
+ std::string HomeRelativeOutputPath;
+
+ struct LocalObjectEntry
+ {
+ cmGeneratorTarget* Target;
+ std::string Language;
+ LocalObjectEntry()
+ : Target(CM_NULLPTR)
+ , Language()
+ {
+ }
+ LocalObjectEntry(cmGeneratorTarget* t, const std::string& lang)
+ : Target(t)
+ , Language(lang)
+ {
+ }
+ };
+ struct LocalObjectInfo : public std::vector<LocalObjectEntry>
+ {
+ bool HasSourceExtension;
+ bool HasPreprocessRule;
+ bool HasAssembleRule;
+ LocalObjectInfo()
+ : HasSourceExtension(false)
+ , HasPreprocessRule(false)
+ , HasAssembleRule(false)
+ {
+ }
+ };
+ void GetLocalObjectFiles(
+ std::map<std::string, LocalObjectInfo>& localObjectFiles);
+
+ void WriteObjectConvenienceRule(std::ostream& ruleFileStream,
+ const char* comment, const char* output,
+ LocalObjectInfo const& info);
+
+ std::vector<std::string> LocalHelp;
+
+ /* does the work for each target */
+ std::map<std::string, std::string> MakeVariableMap;
+ std::map<std::string, std::string> ShortMakeVariableMap;
+
+ int MakefileVariableSize;
+ bool MakeCommandEscapeTargetTwice;
+ bool BorlandMakeCurlyHack;
+ bool ColorMakefile;
+ bool SkipPreprocessedSourceRules;
+ bool SkipAssemblySourceRules;
+};
+
+#endif
diff --git a/Source/cmLocalVisualStudio10Generator.cxx b/Source/cmLocalVisualStudio10Generator.cxx
new file mode 100644
index 0000000..37b5505
--- /dev/null
+++ b/Source/cmLocalVisualStudio10Generator.cxx
@@ -0,0 +1,111 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmLocalVisualStudio10Generator.h"
+
+#include "cmGlobalVisualStudio10Generator.h"
+#include "cmMakefile.h"
+#include "cmVisualStudio10TargetGenerator.h"
+#include "cmXMLParser.h"
+#include <cm_expat.h>
+
+class cmVS10XMLParser : public cmXMLParser
+{
+public:
+ virtual void EndElement(const std::string& /* name */) {}
+ virtual void CharacterDataHandler(const char* data, int length)
+ {
+ if (this->DoGUID) {
+ this->GUID.assign(data + 1, length - 2);
+ this->DoGUID = false;
+ }
+ }
+ virtual void StartElement(const std::string& name, const char**)
+ {
+ // once the GUID is found do nothing
+ if (!this->GUID.empty()) {
+ return;
+ }
+ if ("ProjectGUID" == name || "ProjectGuid" == name) {
+ this->DoGUID = true;
+ }
+ }
+ int InitializeParser()
+ {
+ this->DoGUID = false;
+ int ret = cmXMLParser::InitializeParser();
+ if (ret == 0) {
+ return ret;
+ }
+ // visual studio projects have a strange encoding, but it is
+ // really utf-8
+ XML_SetEncoding(static_cast<XML_Parser>(this->Parser), "utf-8");
+ return 1;
+ }
+ std::string GUID;
+ bool DoGUID;
+};
+
+cmLocalVisualStudio10Generator::cmLocalVisualStudio10Generator(
+ cmGlobalGenerator* gg, cmMakefile* mf)
+ : cmLocalVisualStudio7Generator(gg, mf)
+{
+}
+
+cmLocalVisualStudio10Generator::~cmLocalVisualStudio10Generator()
+{
+}
+
+void cmLocalVisualStudio10Generator::Generate()
+{
+
+ std::vector<cmGeneratorTarget*> tgts = this->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator l = tgts.begin();
+ l != tgts.end(); ++l) {
+ if ((*l)->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ if (static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator)
+ ->TargetIsFortranOnly(*l)) {
+ this->CreateSingleVCProj((*l)->GetName().c_str(), *l);
+ } else {
+ cmVisualStudio10TargetGenerator tg(
+ *l, static_cast<cmGlobalVisualStudio10Generator*>(
+ this->GetGlobalGenerator()));
+ tg.Generate();
+ }
+ }
+ this->WriteStampFiles();
+}
+
+void cmLocalVisualStudio10Generator::ReadAndStoreExternalGUID(
+ const std::string& name, const char* path)
+{
+ cmVS10XMLParser parser;
+ parser.ParseFile(path);
+
+ // if we can not find a GUID then we will generate one later
+ if (parser.GUID.empty()) {
+ return;
+ }
+
+ std::string guidStoreName = name;
+ guidStoreName += "_GUID_CMAKE";
+ // save the GUID in the cache
+ this->GlobalGenerator->GetCMakeInstance()->AddCacheEntry(
+ guidStoreName.c_str(), parser.GUID.c_str(), "Stored GUID",
+ cmState::INTERNAL);
+}
+
+const char* cmLocalVisualStudio10Generator::ReportErrorLabel() const
+{
+ return ":VCEnd";
+}
diff --git a/Source/cmLocalVisualStudio10Generator.h b/Source/cmLocalVisualStudio10Generator.h
new file mode 100644
index 0000000..6ec894c
--- /dev/null
+++ b/Source/cmLocalVisualStudio10Generator.h
@@ -0,0 +1,44 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLocalVisualStudio10Generator_h
+#define cmLocalVisualStudio10Generator_h
+
+#include "cmLocalVisualStudio7Generator.h"
+
+/** \class cmLocalVisualStudio10Generator
+ * \brief Write Visual Studio 10 project files.
+ *
+ * cmLocalVisualStudio10Generator produces a Visual Studio 10 project
+ * file for each target in its directory.
+ */
+class cmLocalVisualStudio10Generator : public cmLocalVisualStudio7Generator
+{
+public:
+ ///! Set cache only and recurse to false by default.
+ cmLocalVisualStudio10Generator(cmGlobalGenerator* gg, cmMakefile* mf);
+
+ virtual ~cmLocalVisualStudio10Generator();
+
+ /**
+ * Generate the makefile for this directory.
+ */
+ virtual void Generate();
+ virtual void ReadAndStoreExternalGUID(const std::string& name,
+ const char* path);
+
+protected:
+ virtual const char* ReportErrorLabel() const;
+ virtual bool CustomCommandUseLocal() const { return true; }
+
+private:
+};
+#endif
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
new file mode 100644
index 0000000..c38e99c
--- /dev/null
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -0,0 +1,2152 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmLocalVisualStudio7Generator.h"
+
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalVisualStudio7Generator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include "cmake.h"
+#include <cm_expat.h>
+
+#include "cmComputeLinkInformation.h"
+#include "cmGeneratedFileStream.h"
+
+#include <ctype.h> // for isspace
+
+static bool cmLVS7G_IsFAT(const char* dir);
+
+class cmLocalVisualStudio7GeneratorInternals
+{
+public:
+ cmLocalVisualStudio7GeneratorInternals(cmLocalVisualStudio7Generator* e)
+ : LocalGenerator(e)
+ {
+ }
+ typedef cmComputeLinkInformation::ItemVector ItemVector;
+ void OutputLibraries(std::ostream& fout, ItemVector const& libs);
+ void OutputObjects(std::ostream& fout, cmGeneratorTarget* t,
+ const char* isep = 0);
+
+private:
+ cmLocalVisualStudio7Generator* LocalGenerator;
+};
+
+extern cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[];
+
+static void cmConvertToWindowsSlash(std::string& s)
+{
+ std::string::size_type pos = 0;
+ while ((pos = s.find('/', pos)) != std::string::npos) {
+ s[pos] = '\\';
+ pos++;
+ }
+}
+
+cmLocalVisualStudio7Generator::cmLocalVisualStudio7Generator(
+ cmGlobalGenerator* gg, cmMakefile* mf)
+ : cmLocalVisualStudioGenerator(gg, mf)
+{
+ this->Internal = new cmLocalVisualStudio7GeneratorInternals(this);
+}
+
+cmLocalVisualStudio7Generator::~cmLocalVisualStudio7Generator()
+{
+ delete this->Internal;
+}
+
+void cmLocalVisualStudio7Generator::AddHelperCommands()
+{
+ // Now create GUIDs for targets
+ std::vector<cmGeneratorTarget*> tgts = this->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator l = tgts.begin();
+ l != tgts.end(); ++l) {
+ if ((*l)->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ const char* path = (*l)->GetProperty("EXTERNAL_MSPROJECT");
+ if (path) {
+ this->ReadAndStoreExternalGUID((*l)->GetName().c_str(), path);
+ }
+ }
+
+ this->FixGlobalTargets();
+}
+
+void cmLocalVisualStudio7Generator::Generate()
+{
+ this->WriteProjectFiles();
+ this->WriteStampFiles();
+}
+
+void cmLocalVisualStudio7Generator::AddCMakeListsRules()
+{
+ // Create the regeneration custom rule.
+ if (!this->Makefile->IsOn("CMAKE_SUPPRESS_REGENERATION")) {
+ // Create a rule to regenerate the build system when the target
+ // specification source changes.
+ if (cmSourceFile* sf = this->CreateVCProjBuildRule()) {
+ // Add the rule to targets that need it.
+ std::vector<cmGeneratorTarget*> tgts = this->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator l = tgts.begin();
+ l != tgts.end(); ++l) {
+ if ((*l)->GetType() == cmState::GLOBAL_TARGET) {
+ continue;
+ }
+ if ((*l)->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
+ (*l)->AddSource(sf->GetFullPath());
+ }
+ }
+ }
+ }
+}
+
+void cmLocalVisualStudio7Generator::FixGlobalTargets()
+{
+ // Visual Studio .NET 2003 Service Pack 1 will not run post-build
+ // commands for targets in which no sources are built. Add dummy
+ // rules to force these targets to build.
+ std::vector<cmGeneratorTarget*> tgts = this->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator l = tgts.begin();
+ l != tgts.end(); l++) {
+ if ((*l)->GetType() == cmState::GLOBAL_TARGET) {
+ std::vector<std::string> no_depends;
+ cmCustomCommandLine force_command;
+ force_command.push_back("cd");
+ force_command.push_back(".");
+ cmCustomCommandLines force_commands;
+ force_commands.push_back(force_command);
+ std::string no_main_dependency = "";
+ std::string force = this->GetCurrentBinaryDirectory();
+ force += cmake::GetCMakeFilesDirectory();
+ force += "/";
+ force += (*l)->GetName();
+ force += "_force";
+ if (cmSourceFile* file = this->Makefile->AddCustomCommandToOutput(
+ force.c_str(), no_depends, no_main_dependency, force_commands, " ",
+ 0, true)) {
+ (*l)->AddSource(file->GetFullPath());
+ }
+ }
+ }
+}
+
+// TODO
+// for CommandLine= need to repleace quotes with &quot
+// write out configurations
+void cmLocalVisualStudio7Generator::WriteProjectFiles()
+{
+ // If not an in source build, then create the output directory
+ if (strcmp(this->GetCurrentBinaryDirectory(), this->GetSourceDirectory()) !=
+ 0) {
+ if (!cmSystemTools::MakeDirectory(this->GetCurrentBinaryDirectory())) {
+ cmSystemTools::Error("Error creating directory ",
+ this->GetCurrentBinaryDirectory());
+ }
+ }
+
+ // Get the set of targets in this directory.
+ std::vector<cmGeneratorTarget*> tgts = this->GetGeneratorTargets();
+
+ // Create the project file for each target.
+ for (std::vector<cmGeneratorTarget*>::iterator l = tgts.begin();
+ l != tgts.end(); l++) {
+ if ((*l)->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ // INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace
+ // so don't build a projectfile for it
+ if (!(*l)->GetProperty("EXTERNAL_MSPROJECT")) {
+ this->CreateSingleVCProj((*l)->GetName().c_str(), *l);
+ }
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteStampFiles()
+{
+ // Touch a timestamp file used to determine when the project file is
+ // out of date.
+ std::string stampName = this->GetCurrentBinaryDirectory();
+ stampName += cmake::GetCMakeFilesDirectory();
+ cmSystemTools::MakeDirectory(stampName.c_str());
+ stampName += "/";
+ stampName += "generate.stamp";
+ cmsys::ofstream stamp(stampName.c_str());
+ stamp << "# CMake generation timestamp file for this directory.\n";
+
+ // Create a helper file so CMake can determine when it is run
+ // through the rule created by CreateVCProjBuildRule whether it
+ // really needs to regenerate the project. This file lists its own
+ // dependencies. If any file listed in it is newer than itself then
+ // CMake must rerun. Otherwise the project files are up to date and
+ // the stamp file can just be touched.
+ std::string depName = stampName;
+ depName += ".depend";
+ cmsys::ofstream depFile(depName.c_str());
+ depFile << "# CMake generation dependency list for this directory.\n";
+ std::vector<std::string> const& listFiles = this->Makefile->GetListFiles();
+ for (std::vector<std::string>::const_iterator lf = listFiles.begin();
+ lf != listFiles.end(); ++lf) {
+ depFile << *lf << std::endl;
+ }
+}
+
+void cmLocalVisualStudio7Generator::CreateSingleVCProj(
+ const std::string& lname, cmGeneratorTarget* target)
+{
+ cmGlobalVisualStudioGenerator* gg =
+ static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
+ this->FortranProject = gg->TargetIsFortranOnly(target);
+ this->WindowsCEProject = gg->TargetsWindowsCE();
+
+ // Intel Fortran for VS10 uses VS9 format ".vfproj" files.
+ cmGlobalVisualStudioGenerator::VSVersion realVersion = gg->GetVersion();
+ if (this->FortranProject &&
+ gg->GetVersion() >= cmGlobalVisualStudioGenerator::VS10) {
+ gg->SetVersion(cmGlobalVisualStudioGenerator::VS9);
+ }
+
+ // add to the list of projects
+ target->Target->SetProperty("GENERATOR_FILE_NAME", lname.c_str());
+ // create the dsp.cmake file
+ std::string fname;
+ fname = this->GetCurrentBinaryDirectory();
+ fname += "/";
+ fname += lname;
+ if (this->FortranProject) {
+ fname += ".vfproj";
+ } else {
+ fname += ".vcproj";
+ }
+
+ // Generate the project file and replace it atomically with
+ // copy-if-different. We use a separate timestamp so that the IDE
+ // does not reload project files unnecessarily.
+ cmGeneratedFileStream fout(fname.c_str());
+ fout.SetCopyIfDifferent(true);
+ this->WriteVCProjFile(fout, lname, target);
+ if (fout.Close()) {
+ this->GlobalGenerator->FileReplacedDuringGenerate(fname);
+ }
+
+ gg->SetVersion(realVersion);
+}
+
+cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
+{
+ std::string stampName = this->GetCurrentBinaryDirectory();
+ stampName += "/";
+ stampName += cmake::GetCMakeFilesDirectoryPostSlash();
+ stampName += "generate.stamp";
+ cmCustomCommandLine commandLine;
+ commandLine.push_back(cmSystemTools::GetCMakeCommand());
+ std::string makefileIn = this->GetCurrentSourceDirectory();
+ makefileIn += "/";
+ makefileIn += "CMakeLists.txt";
+ makefileIn = cmSystemTools::CollapseFullPath(makefileIn.c_str());
+ if (!cmSystemTools::FileExists(makefileIn.c_str())) {
+ return 0;
+ }
+ std::string comment = "Building Custom Rule ";
+ comment += makefileIn;
+ std::string args;
+ args = "-H";
+ args += this->GetSourceDirectory();
+ commandLine.push_back(args);
+ args = "-B";
+ args += this->GetBinaryDirectory();
+ commandLine.push_back(args);
+ commandLine.push_back("--check-stamp-file");
+ std::string stampFilename = this->Convert(
+ stampName.c_str(), cmOutputConverter::FULL, cmOutputConverter::SHELL);
+ commandLine.push_back(stampFilename.c_str());
+
+ std::vector<std::string> const& listFiles = this->Makefile->GetListFiles();
+
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(commandLine);
+ const char* no_working_directory = 0;
+ std::string fullpathStampName = this->Convert(
+ stampName.c_str(), cmOutputConverter::FULL, cmOutputConverter::UNCHANGED);
+ this->Makefile->AddCustomCommandToOutput(
+ fullpathStampName.c_str(), listFiles, makefileIn.c_str(), commandLines,
+ comment.c_str(), no_working_directory, true);
+ if (cmSourceFile* file = this->Makefile->GetSource(makefileIn.c_str())) {
+ return file;
+ } else {
+ cmSystemTools::Error("Error adding rule for ", makefileIn.c_str());
+ return 0;
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs,
+ 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);
+ }
+ fout << "\t</Configurations>\n";
+}
+cmVS7FlagTable cmLocalVisualStudio7GeneratorFortranFlagTable[] = {
+ { "Preprocess", "fpp", "Run Preprocessor on files", "preprocessYes", 0 },
+ { "SuppressStartupBanner", "nologo", "SuppressStartupBanner", "true", 0 },
+ { "SourceFileFormat", "fixed", "Use Fixed Format", "fileFormatFixed", 0 },
+ { "SourceFileFormat", "free", "Use Free Format", "fileFormatFree", 0 },
+ { "DebugInformationFormat", "Zi", "full debug", "debugEnabled", 0 },
+ { "DebugInformationFormat", "debug:full", "full debug", "debugEnabled", 0 },
+ { "DebugInformationFormat", "Z7", "c7 compat", "debugOldStyleInfo", 0 },
+ { "DebugInformationFormat", "Zd", "line numbers", "debugLineInfoOnly", 0 },
+ { "Optimization", "Od", "disable optimization", "optimizeDisabled", 0 },
+ { "Optimization", "O1", "min space", "optimizeMinSpace", 0 },
+ { "Optimization", "O3", "full optimize", "optimizeFull", 0 },
+ { "GlobalOptimizations", "Og", "global optimize", "true", 0 },
+ { "InlineFunctionExpansion", "Ob0", "", "expandDisable", 0 },
+ { "InlineFunctionExpansion", "Ob1", "", "expandOnlyInline", 0 },
+ { "FavorSizeOrSpeed", "Os", "", "favorSize", 0 },
+ { "OmitFramePointers", "Oy-", "", "false", 0 },
+ { "OptimizeForProcessor", "GB", "", "procOptimizeBlended", 0 },
+ { "OptimizeForProcessor", "G5", "", "procOptimizePentium", 0 },
+ { "OptimizeForProcessor", "G6", "", "procOptimizePentiumProThruIII", 0 },
+ { "UseProcessorExtensions", "QzxK", "", "codeForStreamingSIMD", 0 },
+ { "OptimizeForProcessor", "QaxN", "", "codeForPentium4", 0 },
+ { "OptimizeForProcessor", "QaxB", "", "codeForPentiumM", 0 },
+ { "OptimizeForProcessor", "QaxP", "", "codeForCodeNamedPrescott", 0 },
+ { "OptimizeForProcessor", "QaxT", "", "codeForCore2Duo", 0 },
+ { "OptimizeForProcessor", "QxK", "", "codeExclusivelyStreamingSIMD", 0 },
+ { "OptimizeForProcessor", "QxN", "", "codeExclusivelyPentium4", 0 },
+ { "OptimizeForProcessor", "QxB", "", "codeExclusivelyPentiumM", 0 },
+ { "OptimizeForProcessor", "QxP", "", "codeExclusivelyCodeNamedPrescott", 0 },
+ { "OptimizeForProcessor", "QxT", "", "codeExclusivelyCore2Duo", 0 },
+ { "OptimizeForProcessor", "QxO", "", "codeExclusivelyCore2StreamingSIMD",
+ 0 },
+ { "OptimizeForProcessor", "QxS", "", "codeExclusivelyCore2StreamingSIMD4",
+ 0 },
+ { "OpenMP", "Qopenmp", "", "OpenMPParallelCode", 0 },
+ { "OpenMP", "Qopenmp-stubs", "", "OpenMPSequentialCode", 0 },
+ { "Traceback", "traceback", "", "true", 0 },
+ { "Traceback", "notraceback", "", "false", 0 },
+ { "FloatingPointExceptionHandling", "fpe:0", "", "fpe0", 0 },
+ { "FloatingPointExceptionHandling", "fpe:1", "", "fpe1", 0 },
+ { "FloatingPointExceptionHandling", "fpe:3", "", "fpe3", 0 },
+
+ { "MultiProcessorCompilation", "MP", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "ProcessorNumber", "MP", "Multi-processor Compilation", "",
+ cmVS7FlagTable::UserValueRequired },
+
+ { "ModulePath", "module:", "", "", cmVS7FlagTable::UserValueRequired },
+ { "LoopUnrolling", "Qunroll:", "", "", cmVS7FlagTable::UserValueRequired },
+ { "AutoParallelThreshold", "Qpar-threshold:", "", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "HeapArrays", "heap-arrays:", "", "", cmVS7FlagTable::UserValueRequired },
+ { "ObjectText", "bintext:", "", "", cmVS7FlagTable::UserValueRequired },
+ { "Parallelization", "Qparallel", "", "true", 0 },
+ { "PrefetchInsertion", "Qprefetch-", "", "false", 0 },
+ { "BufferedIO", "assume:buffered_io", "", "true", 0 },
+ { "CallingConvention", "iface:stdcall", "", "callConventionStdCall", 0 },
+ { "CallingConvention", "iface:cref", "", "callConventionCRef", 0 },
+ { "CallingConvention", "iface:stdref", "", "callConventionStdRef", 0 },
+ { "CallingConvention", "iface:stdcall", "", "callConventionStdCall", 0 },
+ { "CallingConvention", "iface:cvf", "", "callConventionCVF", 0 },
+ { "EnableRecursion", "recursive", "", "true", 0 },
+ { "ReentrantCode", "reentrancy", "", "true", 0 },
+ // done up to Language
+ { 0, 0, 0, 0, 0 }
+};
+// fill the table here currently the comment field is not used for
+// anything other than documentation NOTE: Make sure the longer
+// commandFlag comes FIRST!
+cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[] = {
+ // option flags (some flags map to the same option)
+ { "BasicRuntimeChecks", "GZ", "Stack frame checks", "1", 0 },
+ { "BasicRuntimeChecks", "RTCsu", "Both stack and uninitialized checks", "3",
+ 0 },
+ { "BasicRuntimeChecks", "RTCs", "Stack frame checks", "1", 0 },
+ { "BasicRuntimeChecks", "RTCu", "Uninitialized Variables ", "2", 0 },
+ { "BasicRuntimeChecks", "RTC1", "Both stack and uninitialized checks", "3",
+ 0 },
+ { "DebugInformationFormat", "Z7", "debug format", "1", 0 },
+ { "DebugInformationFormat", "Zd", "debug format", "2", 0 },
+ { "DebugInformationFormat", "Zi", "debug format", "3", 0 },
+ { "DebugInformationFormat", "ZI", "debug format", "4", 0 },
+ { "EnableEnhancedInstructionSet", "arch:SSE2", "Use sse2 instructions", "2",
+ 0 },
+ { "EnableEnhancedInstructionSet", "arch:SSE", "Use sse instructions", "1",
+ 0 },
+ { "FloatingPointModel", "fp:precise", "Use precise floating point model",
+ "0", 0 },
+ { "FloatingPointModel", "fp:strict", "Use strict floating point model", "1",
+ 0 },
+ { "FloatingPointModel", "fp:fast", "Use fast floating point model", "2", 0 },
+ { "FavorSizeOrSpeed", "Ot", "Favor fast code", "1", 0 },
+ { "FavorSizeOrSpeed", "Os", "Favor small code", "2", 0 },
+ { "CompileAs", "TC", "Compile as c code", "1", 0 },
+ { "CompileAs", "TP", "Compile as c++ code", "2", 0 },
+ { "Optimization", "Od", "Non Debug", "0", 0 },
+ { "Optimization", "O1", "Min Size", "1", 0 },
+ { "Optimization", "O2", "Max Speed", "2", 0 },
+ { "Optimization", "Ox", "Max Optimization", "3", 0 },
+ { "OptimizeForProcessor", "GB", "Blended processor mode", "0", 0 },
+ { "OptimizeForProcessor", "G5", "Pentium", "1", 0 },
+ { "OptimizeForProcessor", "G6", "PPro PII PIII", "2", 0 },
+ { "OptimizeForProcessor", "G7", "Pentium 4 or Athlon", "3", 0 },
+ { "InlineFunctionExpansion", "Ob0", "no inlines", "0", 0 },
+ { "InlineFunctionExpansion", "Ob1", "when inline keyword", "1", 0 },
+ { "InlineFunctionExpansion", "Ob2", "any time you can inline", "2", 0 },
+ { "RuntimeLibrary", "MTd", "Multithreaded debug", "1", 0 },
+ { "RuntimeLibrary", "MT", "Multithreaded", "0", 0 },
+ { "RuntimeLibrary", "MDd", "Multithreaded dll debug", "3", 0 },
+ { "RuntimeLibrary", "MD", "Multithreaded dll", "2", 0 },
+ { "RuntimeLibrary", "MLd", "Single Thread debug", "5", 0 },
+ { "RuntimeLibrary", "ML", "Single Thread", "4", 0 },
+ { "StructMemberAlignment", "Zp16", "struct align 16 byte ", "5", 0 },
+ { "StructMemberAlignment", "Zp1", "struct align 1 byte ", "1", 0 },
+ { "StructMemberAlignment", "Zp2", "struct align 2 byte ", "2", 0 },
+ { "StructMemberAlignment", "Zp4", "struct align 4 byte ", "3", 0 },
+ { "StructMemberAlignment", "Zp8", "struct align 8 byte ", "4", 0 },
+ { "WarningLevel", "W0", "Warning level", "0", 0 },
+ { "WarningLevel", "W1", "Warning level", "1", 0 },
+ { "WarningLevel", "W2", "Warning level", "2", 0 },
+ { "WarningLevel", "W3", "Warning level", "3", 0 },
+ { "WarningLevel", "W4", "Warning level", "4", 0 },
+ { "DisableSpecificWarnings", "wd", "Disable specific warnings", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // Precompiled header and related options. Note that the
+ // UsePrecompiledHeader entries are marked as "Continue" so that the
+ // corresponding PrecompiledHeaderThrough entry can be found.
+ { "UsePrecompiledHeader", "Yc", "Create Precompiled Header", "1",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeaderThrough", "Yc", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "PrecompiledHeaderFile", "Fp", "Generated Precompiled Header", "",
+ cmVS7FlagTable::UserValue },
+ // The YX and Yu options are in a per-global-generator table because
+ // their values differ based on the VS IDE version.
+ { "ForcedIncludeFiles", "FI", "Forced include files", "",
+ cmVS7FlagTable::UserValueRequired | cmVS7FlagTable::SemicolonAppendable },
+
+ { "AssemblerListingLocation", "Fa", "ASM List Location", "",
+ cmVS7FlagTable::UserValue },
+ { "ProgramDataBaseFileName", "Fd", "Program Database File Name", "",
+ cmVS7FlagTable::UserValue },
+
+ // boolean flags
+ { "BufferSecurityCheck", "GS", "Buffer security check", "true", 0 },
+ { "BufferSecurityCheck", "GS-", "Turn off Buffer security check", "false",
+ 0 },
+ { "Detect64BitPortabilityProblems", "Wp64",
+ "Detect 64-bit Portability Problems", "true", 0 },
+ { "EnableFiberSafeOptimizations", "GT", "Enable Fiber-safe Optimizations",
+ "true", 0 },
+ { "EnableFunctionLevelLinking", "Gy", "EnableFunctionLevelLinking", "true",
+ 0 },
+ { "EnableIntrinsicFunctions", "Oi", "EnableIntrinsicFunctions", "true", 0 },
+ { "GlobalOptimizations", "Og", "Global Optimize", "true", 0 },
+ { "ImproveFloatingPointConsistency", "Op", "ImproveFloatingPointConsistency",
+ "true", 0 },
+ { "MinimalRebuild", "Gm", "minimal rebuild", "true", 0 },
+ { "OmitFramePointers", "Oy", "OmitFramePointers", "true", 0 },
+ { "OptimizeForWindowsApplication", "GA", "Optimize for windows", "true", 0 },
+ { "RuntimeTypeInfo", "GR", "Turn on Run time type information for c++",
+ "true", 0 },
+ { "RuntimeTypeInfo", "GR-", "Turn off Run time type information for c++",
+ "false", 0 },
+ { "SmallerTypeCheck", "RTCc", "smaller type check", "true", 0 },
+ { "SuppressStartupBanner", "nologo", "SuppressStartupBanner", "true", 0 },
+ { "WholeProgramOptimization", "GL", "Enables whole program optimization",
+ "true", 0 },
+ { "WholeProgramOptimization", "GL-", "Disables whole program optimization",
+ "false", 0 },
+ { "WarnAsError", "WX", "Treat warnings as errors", "true", 0 },
+ { "BrowseInformation", "FR", "Generate browse information", "1", 0 },
+ { "StringPooling", "GF", "Enable StringPooling", "true", 0 },
+ { 0, 0, 0, 0, 0 }
+};
+
+cmVS7FlagTable cmLocalVisualStudio7GeneratorLinkFlagTable[] = {
+ // option flags (some flags map to the same option)
+ { "GenerateManifest", "MANIFEST:NO", "disable manifest generation", "false",
+ 0 },
+ { "GenerateManifest", "MANIFEST", "enable manifest generation", "true", 0 },
+ { "LinkIncremental", "INCREMENTAL:NO", "link incremental", "1", 0 },
+ { "LinkIncremental", "INCREMENTAL:YES", "link incremental", "2", 0 },
+ { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK:NO", "", "false", 0 },
+ { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK", "", "true", 0 },
+ { "DataExecutionPrevention", "NXCOMPAT:NO",
+ "Not known to work with Windows Data Execution Prevention", "1", 0 },
+ { "DataExecutionPrevention", "NXCOMPAT",
+ "Known to work with Windows Data Execution Prevention", "2", 0 },
+ { "DelaySign", "DELAYSIGN:NO", "", "false", 0 },
+ { "DelaySign", "DELAYSIGN", "", "true", 0 },
+ { "EntryPointSymbol", "ENTRY:", "sets the starting address", "",
+ cmVS7FlagTable::UserValue },
+ { "IgnoreDefaultLibraryNames", "NODEFAULTLIB:", "default libs to ignore", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "IgnoreAllDefaultLibraries", "NODEFAULTLIB", "ignore all default libs",
+ "true", 0 },
+ { "FixedBaseAddress", "FIXED:NO", "Generate a relocation section", "1", 0 },
+ { "FixedBaseAddress", "FIXED", "Image must be loaded at a fixed address",
+ "2", 0 },
+ { "EnableCOMDATFolding", "OPT:NOICF", "Do not remove redundant COMDATs", "1",
+ 0 },
+ { "EnableCOMDATFolding", "OPT:ICF", "Remove redundant COMDATs", "2", 0 },
+ { "ResourceOnlyDLL", "NOENTRY", "Create DLL with no entry point", "true",
+ 0 },
+ { "OptimizeReferences", "OPT:NOREF", "Keep unreferenced data", "1", 0 },
+ { "OptimizeReferences", "OPT:REF", "Eliminate unreferenced data", "2", 0 },
+ { "Profile", "PROFILE", "", "true", 0 },
+ { "RandomizedBaseAddress", "DYNAMICBASE:NO",
+ "Image may not be rebased at load-time", "1", 0 },
+ { "RandomizedBaseAddress", "DYNAMICBASE",
+ "Image may be rebased at load-time", "2", 0 },
+ { "SetChecksum", "RELEASE", "Enable setting checksum in header", "true", 0 },
+ { "SupportUnloadOfDelayLoadedDLL", "DELAY:UNLOAD", "", "true", 0 },
+ { "TargetMachine", "MACHINE:I386", "Machine x86", "1", 0 },
+ { "TargetMachine", "MACHINE:X86", "Machine x86", "1", 0 },
+ { "TargetMachine", "MACHINE:AM33", "Machine AM33", "2", 0 },
+ { "TargetMachine", "MACHINE:ARM", "Machine ARM", "3", 0 },
+ { "TargetMachine", "MACHINE:EBC", "Machine EBC", "4", 0 },
+ { "TargetMachine", "MACHINE:IA64", "Machine IA64", "5", 0 },
+ { "TargetMachine", "MACHINE:M32R", "Machine M32R", "6", 0 },
+ { "TargetMachine", "MACHINE:MIPS", "Machine MIPS", "7", 0 },
+ { "TargetMachine", "MACHINE:MIPS16", "Machine MIPS16", "8", 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU)", "Machine MIPSFPU", "9", 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU16", "Machine MIPSFPU16", "10", 0 },
+ { "TargetMachine", "MACHINE:MIPSR41XX", "Machine MIPSR41XX", "11", 0 },
+ { "TargetMachine", "MACHINE:SH3", "Machine SH3", "12", 0 },
+ { "TargetMachine", "MACHINE:SH3DSP", "Machine SH3DSP", "13", 0 },
+ { "TargetMachine", "MACHINE:SH4", "Machine SH4", "14", 0 },
+ { "TargetMachine", "MACHINE:SH5", "Machine SH5", "15", 0 },
+ { "TargetMachine", "MACHINE:THUMB", "Machine THUMB", "16", 0 },
+ { "TargetMachine", "MACHINE:X64", "Machine x64", "17", 0 },
+ { "TurnOffAssemblyGeneration", "NOASSEMBLY",
+ "No assembly even if CLR information is present in objects.", "true", 0 },
+ { "ModuleDefinitionFile", "DEF:", "add an export def file", "",
+ cmVS7FlagTable::UserValue },
+ { "GenerateMapFile", "MAP", "enable generation of map file", "true", 0 },
+ { 0, 0, 0, 0, 0 }
+};
+
+cmVS7FlagTable cmLocalVisualStudio7GeneratorFortranLinkFlagTable[] = {
+ { "LinkIncremental", "INCREMENTAL:NO", "link incremental",
+ "linkIncrementalNo", 0 },
+ { "LinkIncremental", "INCREMENTAL:YES", "link incremental",
+ "linkIncrementalYes", 0 },
+ { 0, 0, 0, 0, 0 }
+};
+
+// Helper class to write build event <Tool .../> elements.
+class cmLocalVisualStudio7Generator::EventWriter
+{
+public:
+ EventWriter(cmLocalVisualStudio7Generator* lg, const std::string& config,
+ std::ostream& os)
+ : LG(lg)
+ , Config(config)
+ , Stream(os)
+ , First(true)
+ {
+ }
+ void Start(const char* tool)
+ {
+ this->First = true;
+ this->Stream << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"";
+ }
+ 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);
+ }
+ }
+ void Write(cmCustomCommand const& cc)
+ {
+ cmCustomCommandGenerator ccg(cc, this->Config, this->LG);
+ if (this->First) {
+ const char* comment = ccg.GetComment();
+ if (comment && *comment) {
+ this->Stream << "\nDescription=\"" << this->LG->EscapeForXML(comment)
+ << "\"";
+ }
+ this->Stream << "\nCommandLine=\"";
+ this->First = false;
+ } else {
+ this->Stream << this->LG->EscapeForXML("\n");
+ }
+ std::string script = this->LG->ConstructScript(ccg);
+ this->Stream << this->LG->EscapeForXML(script.c_str());
+ }
+
+private:
+ cmLocalVisualStudio7Generator* LG;
+ std::string Config;
+ std::ostream& Stream;
+ bool First;
+};
+
+void cmLocalVisualStudio7Generator::WriteConfiguration(
+ std::ostream& fout, const std::string& configName,
+ const std::string& libName, cmGeneratorTarget* target)
+{
+ const char* mfcFlag = this->Makefile->GetDefinition("CMAKE_MFC_FLAG");
+ if (!mfcFlag) {
+ mfcFlag = "0";
+ }
+ cmGlobalVisualStudio7Generator* gg =
+ static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
+ fout << "\t\t<Configuration\n"
+ << "\t\t\tName=\"" << configName << "|" << gg->GetPlatformName()
+ << "\"\n";
+ // This is an internal type to Visual Studio, it seems that:
+ // 4 == static library
+ // 2 == dll
+ // 1 == executable
+ // 10 == utility
+ const char* configType = "10";
+ const char* projectType = 0;
+ bool targetBuilds = true;
+
+ switch (target->GetType()) {
+ case cmState::OBJECT_LIBRARY:
+ targetBuilds = false; // no manifest tool for object library
+ case cmState::STATIC_LIBRARY:
+ projectType = "typeStaticLibrary";
+ configType = "4";
+ break;
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ projectType = "typeDynamicLibrary";
+ configType = "2";
+ break;
+ case cmState::EXECUTABLE:
+ configType = "1";
+ break;
+ case cmState::UTILITY:
+ case cmState::GLOBAL_TARGET:
+ configType = "10";
+ default:
+ targetBuilds = false;
+ break;
+ }
+ if (this->FortranProject && projectType) {
+ configType = projectType;
+ }
+ std::string flags;
+ if (strcmp(configType, "10") != 0) {
+ const std::string& linkLanguage =
+ (this->FortranProject ? std::string("Fortran")
+ : target->GetLinkerLanguage(configName));
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error(
+ "CMake can not determine linker language for target: ",
+ target->GetName().c_str());
+ return;
+ }
+ if (linkLanguage == "C" || linkLanguage == "CXX" ||
+ linkLanguage == "Fortran") {
+ std::string baseFlagVar = "CMAKE_";
+ baseFlagVar += linkLanguage;
+ baseFlagVar += "_FLAGS";
+ flags = this->Makefile->GetRequiredDefinition(baseFlagVar.c_str());
+ std::string flagVar =
+ baseFlagVar + std::string("_") + cmSystemTools::UpperCase(configName);
+ flags += " ";
+ flags += this->Makefile->GetRequiredDefinition(flagVar.c_str());
+ }
+ // set the correct language
+ if (linkLanguage == "C") {
+ flags += " /TC ";
+ }
+ if (linkLanguage == "CXX") {
+ flags += " /TP ";
+ }
+
+ // Add the target-specific flags.
+ this->AddCompileOptions(flags, target, linkLanguage, configName);
+ }
+
+ if (this->FortranProject) {
+ switch (cmOutputConverter::GetFortranFormat(
+ target->GetProperty("Fortran_FORMAT"))) {
+ case cmOutputConverter::FortranFormatFixed:
+ flags += " -fixed";
+ break;
+ case cmOutputConverter::FortranFormatFree:
+ flags += " -free";
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Get preprocessor definitions for this directory.
+ std::string defineFlags = this->Makefile->GetDefineFlags();
+ Options::Tool t = Options::Compiler;
+ cmVS7FlagTable const* table = cmLocalVisualStudio7GeneratorFlagTable;
+ if (this->FortranProject) {
+ t = Options::FortranCompiler;
+ table = cmLocalVisualStudio7GeneratorFortranFlagTable;
+ }
+ Options targetOptions(this, t, table, gg->ExtraFlagTable);
+ targetOptions.FixExceptionHandlingDefault();
+ std::string asmLocation = configName + "/";
+ targetOptions.AddFlag("AssemblerListingLocation", asmLocation.c_str());
+ targetOptions.Parse(flags.c_str());
+ targetOptions.Parse(defineFlags.c_str());
+ targetOptions.ParseFinish();
+ std::vector<std::string> targetDefines;
+ target->GetCompileDefinitions(targetDefines, configName, "CXX");
+ targetOptions.AddDefines(targetDefines);
+ targetOptions.SetVerboseMakefile(
+ this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
+
+ // Add a definition for the configuration name.
+ std::string configDefine = "CMAKE_INTDIR=\"";
+ configDefine += configName;
+ configDefine += "\"";
+ targetOptions.AddDefine(configDefine);
+
+ // Add the export symbol definition for shared library objects.
+ if (const char* exportMacro = target->GetExportMacro()) {
+ targetOptions.AddDefine(exportMacro);
+ }
+
+ // The intermediate directory name consists of a directory for the
+ // target and a subdirectory for the configuration name.
+ std::string intermediateDir = this->GetTargetDirectory(target);
+ intermediateDir += "/";
+ intermediateDir += configName;
+
+ if (target->GetType() < cmState::UTILITY) {
+ std::string const& outDir = target->GetType() == cmState::OBJECT_LIBRARY
+ ? intermediateDir
+ : target->GetDirectory(configName);
+ /* clang-format off */
+ fout << "\t\t\tOutputDirectory=\""
+ << this->ConvertToXMLOutputPathSingle(outDir.c_str()) << "\"\n";
+ /* clang-format on */
+ }
+
+ /* clang-format off */
+ fout << "\t\t\tIntermediateDirectory=\""
+ << this->ConvertToXMLOutputPath(intermediateDir.c_str())
+ << "\"\n"
+ << "\t\t\tConfigurationType=\"" << configType << "\"\n"
+ << "\t\t\tUseOfMFC=\"" << mfcFlag << "\"\n"
+ << "\t\t\tATLMinimizesCRunTimeLibraryUsage=\"false\"\n";
+ /* clang-format on */
+
+ if (this->FortranProject) {
+ // Intel Fortran >= 15.0 uses TargetName property.
+ std::string targetNameFull = target->GetFullName(configName);
+ std::string targetName =
+ cmSystemTools::GetFilenameWithoutLastExtension(targetNameFull);
+ std::string targetExt =
+ cmSystemTools::GetFilenameLastExtension(targetNameFull);
+ /* clang-format off */
+ fout <<
+ "\t\t\tTargetName=\"" << this->EscapeForXML(targetName) << "\"\n"
+ "\t\t\tTargetExt=\"" << this->EscapeForXML(targetExt) << "\"\n"
+ ;
+ /* clang-format on */
+ }
+
+ // If unicode is enabled change the character set to unicode, if not
+ // then default to MBCS.
+ if (targetOptions.UsingUnicode()) {
+ fout << "\t\t\tCharacterSet=\"1\">\n";
+ } else if (targetOptions.UsingSBCS()) {
+ fout << "\t\t\tCharacterSet=\"0\">\n";
+ } else {
+ fout << "\t\t\tCharacterSet=\"2\">\n";
+ }
+ const char* tool = "VCCLCompilerTool";
+ if (this->FortranProject) {
+ tool = "VFFortranCompilerTool";
+ }
+ fout << "\t\t\t<Tool\n"
+ << "\t\t\t\tName=\"" << tool << "\"\n";
+ if (this->FortranProject) {
+ const char* target_mod_dir =
+ target->GetProperty("Fortran_MODULE_DIRECTORY");
+ std::string modDir;
+ if (target_mod_dir) {
+ modDir = this->Convert(target_mod_dir, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED);
+ } else {
+ modDir = ".";
+ }
+ fout << "\t\t\t\tModulePath=\""
+ << this->ConvertToXMLOutputPath(modDir.c_str())
+ << "\\$(ConfigurationName)\"\n";
+ }
+ targetOptions.OutputAdditionalOptions(fout, "\t\t\t\t", "\n");
+ fout << "\t\t\t\tAdditionalIncludeDirectories=\"";
+ std::vector<std::string> includes;
+ this->GetIncludeDirectories(includes, target, "C", configName);
+ std::vector<std::string>::iterator i = includes.begin();
+ for (; i != includes.end(); ++i) {
+ // output the include path
+ std::string ipath = this->ConvertToXMLOutputPath(i->c_str());
+ fout << ipath << ";";
+ // if this is fortran then output the include with
+ // a ConfigurationName on the end of it.
+ if (this->FortranProject) {
+ ipath = i->c_str();
+ ipath += "/$(ConfigurationName)";
+ ipath = this->ConvertToXMLOutputPath(ipath.c_str());
+ fout << ipath << ";";
+ }
+ }
+ fout << "\"\n";
+ targetOptions.OutputFlagMap(fout, "\t\t\t\t");
+ targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n", "CXX");
+ fout << "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n";
+ if (target->GetType() <= cmState::OBJECT_LIBRARY) {
+ // Specify the compiler program database file if configured.
+ std::string pdb = target->GetCompilePDBPath(configName);
+ if (!pdb.empty()) {
+ fout << "\t\t\t\tProgramDataBaseFileName=\""
+ << this->ConvertToXMLOutputPathSingle(pdb.c_str()) << "\"\n";
+ }
+ }
+ fout << "/>\n"; // end of <Tool Name=VCCLCompilerTool
+ if (gg->IsMasmEnabled() && !this->FortranProject) {
+ Options masmOptions(this, Options::MasmCompiler, 0, 0);
+ /* clang-format off */
+ fout <<
+ "\t\t\t<Tool\n"
+ "\t\t\t\tName=\"MASM\"\n"
+ "\t\t\t\tIncludePaths=\""
+ ;
+ /* clang-format on */
+ const char* sep = "";
+ for (i = includes.begin(); i != includes.end(); ++i) {
+ std::string inc = *i;
+ cmConvertToWindowsSlash(inc);
+ fout << sep << this->EscapeForXML(inc);
+ sep = ";";
+ }
+ fout << "\"\n";
+ // Use same preprocessor definitions as VCCLCompilerTool.
+ targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n",
+ "ASM_MASM");
+ masmOptions.OutputFlagMap(fout, "\t\t\t\t");
+ /* clang-format off */
+ fout <<
+ "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n"
+ "\t\t\t/>\n";
+ /* clang-format on */
+ }
+ tool = "VCCustomBuildTool";
+ if (this->FortranProject) {
+ tool = "VFCustomBuildTool";
+ }
+ fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"/>\n";
+ tool = "VCResourceCompilerTool";
+ if (this->FortranProject) {
+ tool = "VFResourceCompilerTool";
+ }
+ fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n"
+ << "\t\t\t\tAdditionalIncludeDirectories=\"";
+ for (i = includes.begin(); i != includes.end(); ++i) {
+ std::string ipath = this->ConvertToXMLOutputPath(i->c_str());
+ fout << ipath << ";";
+ }
+ // add the -D flags to the RC tool
+ fout << "\"";
+ targetOptions.OutputPreprocessorDefinitions(fout, "\n\t\t\t\t", "", "RC");
+ fout << "/>\n";
+ tool = "VCMIDLTool";
+ if (this->FortranProject) {
+ tool = "VFMIDLTool";
+ }
+ fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n";
+ fout << "\t\t\t\tAdditionalIncludeDirectories=\"";
+ for (i = includes.begin(); i != includes.end(); ++i) {
+ std::string ipath = this->ConvertToXMLOutputPath(i->c_str());
+ fout << ipath << ";";
+ }
+ fout << "\"\n";
+ fout << "\t\t\t\tMkTypLibCompatible=\"false\"\n";
+ if (gg->GetPlatformName() == "x64") {
+ fout << "\t\t\t\tTargetEnvironment=\"3\"\n";
+ } else if (gg->GetPlatformName() == "ia64") {
+ fout << "\t\t\t\tTargetEnvironment=\"2\"\n";
+ } else {
+ fout << "\t\t\t\tTargetEnvironment=\"1\"\n";
+ }
+ fout << "\t\t\t\tGenerateStublessProxies=\"true\"\n";
+ fout << "\t\t\t\tTypeLibraryName=\"$(InputName).tlb\"\n";
+ fout << "\t\t\t\tOutputDirectory=\"$(IntDir)\"\n";
+ fout << "\t\t\t\tHeaderFileName=\"$(InputName).h\"\n";
+ fout << "\t\t\t\tDLLDataFileName=\"\"\n";
+ fout << "\t\t\t\tInterfaceIdentifierFileName=\"$(InputName)_i.c\"\n";
+ fout << "\t\t\t\tProxyFileName=\"$(InputName)_p.c\"/>\n";
+ // end of <Tool Name=VCMIDLTool
+
+ // Add manifest tool settings.
+ if (targetBuilds &&
+ this->GetVersion() >= cmGlobalVisualStudioGenerator::VS8) {
+ const char* manifestTool = "VCManifestTool";
+ if (this->FortranProject) {
+ manifestTool = "VFManifestTool";
+ }
+ /* clang-format off */
+ fout <<
+ "\t\t\t<Tool\n"
+ "\t\t\t\tName=\"" << manifestTool << "\"";
+ /* clang-format on */
+
+ std::vector<cmSourceFile const*> manifest_srcs;
+ 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();
+ fout << this->ConvertToXMLOutputPath(m.c_str()) << ";";
+ }
+ fout << "\"";
+ }
+
+ // Check if we need the FAT32 workaround.
+ // Check the filesystem type where the target will be written.
+ if (cmLVS7G_IsFAT(target->GetDirectory(configName).c_str())) {
+ // Add a flag telling the manifest tool to use a workaround
+ // for FAT32 file systems, which can cause an empty manifest
+ // to be embedded into the resulting executable. See CMake
+ // bug #2617.
+ fout << "\n\t\t\t\tUseFAT32Workaround=\"true\"";
+ }
+ fout << "/>\n";
+ }
+
+ this->OutputTargetRules(fout, configName, target, libName);
+ this->OutputBuildTool(fout, configName, target, targetOptions);
+ this->OutputDeploymentDebuggerTool(fout, configName, target);
+ fout << "\t\t</Configuration>\n";
+}
+
+std::string cmLocalVisualStudio7Generator::GetBuildTypeLinkerFlags(
+ std::string rootLinkerFlags, const std::string& configName)
+{
+ std::string configTypeUpper = cmSystemTools::UpperCase(configName);
+ std::string extraLinkOptionsBuildTypeDef =
+ rootLinkerFlags + "_" + configTypeUpper;
+
+ std::string extraLinkOptionsBuildType =
+ this->Makefile->GetRequiredDefinition(
+ extraLinkOptionsBuildTypeDef.c_str());
+
+ return extraLinkOptionsBuildType;
+}
+
+void cmLocalVisualStudio7Generator::OutputBuildTool(
+ std::ostream& fout, const std::string& configName, cmGeneratorTarget* target,
+ const Options& targetOptions)
+{
+ cmGlobalVisualStudio7Generator* gg =
+ static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
+ std::string temp;
+ std::string extraLinkOptions;
+ if (target->GetType() == cmState::EXECUTABLE) {
+ extraLinkOptions =
+ this->Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS") +
+ std::string(" ") +
+ GetBuildTypeLinkerFlags("CMAKE_EXE_LINKER_FLAGS", configName);
+ }
+ if (target->GetType() == cmState::SHARED_LIBRARY) {
+ extraLinkOptions =
+ this->Makefile->GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS") +
+ std::string(" ") +
+ GetBuildTypeLinkerFlags("CMAKE_SHARED_LINKER_FLAGS", configName);
+ }
+ if (target->GetType() == cmState::MODULE_LIBRARY) {
+ extraLinkOptions =
+ this->Makefile->GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS") +
+ std::string(" ") +
+ GetBuildTypeLinkerFlags("CMAKE_MODULE_LINKER_FLAGS", configName);
+ }
+
+ const char* targetLinkFlags = target->GetProperty("LINK_FLAGS");
+ if (targetLinkFlags) {
+ extraLinkOptions += " ";
+ extraLinkOptions += targetLinkFlags;
+ }
+ std::string configTypeUpper = cmSystemTools::UpperCase(configName);
+ std::string linkFlagsConfig = "LINK_FLAGS_";
+ linkFlagsConfig += configTypeUpper;
+ targetLinkFlags = target->GetProperty(linkFlagsConfig.c_str());
+ if (targetLinkFlags) {
+ extraLinkOptions += " ";
+ extraLinkOptions += targetLinkFlags;
+ }
+ Options linkOptions(this, Options::Linker);
+ if (this->FortranProject) {
+ linkOptions.AddTable(cmLocalVisualStudio7GeneratorFortranLinkFlagTable);
+ }
+ linkOptions.AddTable(cmLocalVisualStudio7GeneratorLinkFlagTable);
+
+ linkOptions.Parse(extraLinkOptions.c_str());
+ if (!this->ModuleDefinitionFile.empty()) {
+ std::string defFile = this->ConvertToOutputFormat(
+ this->ModuleDefinitionFile, cmOutputConverter::SHELL);
+ linkOptions.AddFlag("ModuleDefinitionFile", defFile.c_str());
+ }
+
+ if (target->GetType() == cmState::SHARED_LIBRARY &&
+ this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS")) {
+ if (target->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS")) {
+ linkOptions.AddFlag("ModuleDefinitionFile", "$(IntDir)/exportall.def");
+ }
+ }
+ switch (target->GetType()) {
+ case cmState::UNKNOWN_LIBRARY:
+ break;
+ case cmState::OBJECT_LIBRARY: {
+ std::string libpath = this->GetTargetDirectory(target);
+ libpath += "/";
+ libpath += configName;
+ libpath += "/";
+ libpath += target->GetName();
+ libpath += ".lib";
+ const char* tool =
+ this->FortranProject ? "VFLibrarianTool" : "VCLibrarianTool";
+ fout << "\t\t\t<Tool\n"
+ << "\t\t\t\tName=\"" << tool << "\"\n";
+ fout << "\t\t\t\tOutputFile=\""
+ << this->ConvertToXMLOutputPathSingle(libpath.c_str()) << "\"/>\n";
+ break;
+ }
+ case cmState::STATIC_LIBRARY: {
+ std::string targetNameFull = target->GetFullName(configName);
+ std::string libpath = target->GetDirectory(configName);
+ libpath += "/";
+ libpath += targetNameFull;
+ const char* tool = "VCLibrarianTool";
+ if (this->FortranProject) {
+ tool = "VFLibrarianTool";
+ }
+ fout << "\t\t\t<Tool\n"
+ << "\t\t\t\tName=\"" << tool << "\"\n";
+
+ if (this->GetVersion() < cmGlobalVisualStudioGenerator::VS8 ||
+ this->FortranProject) {
+ std::ostringstream libdeps;
+ this->Internal->OutputObjects(libdeps, target);
+ if (!libdeps.str().empty()) {
+ fout << "\t\t\t\tAdditionalDependencies=\"" << libdeps.str()
+ << "\"\n";
+ }
+ }
+ std::string libflags;
+ this->GetStaticLibraryFlags(libflags, configTypeUpper, target);
+ if (!libflags.empty()) {
+ fout << "\t\t\t\tAdditionalOptions=\"" << libflags << "\"\n";
+ }
+ fout << "\t\t\t\tOutputFile=\""
+ << this->ConvertToXMLOutputPathSingle(libpath.c_str()) << "\"/>\n";
+ break;
+ }
+ case cmState::SHARED_LIBRARY:
+ case cmState::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);
+
+ // Compute the link library and directory information.
+ cmComputeLinkInformation* pcli = target->GetLinkInformation(configName);
+ if (!pcli) {
+ return;
+ }
+ cmComputeLinkInformation& cli = *pcli;
+ std::string linkLanguage = cli.GetLinkLanguage();
+
+ // Compute the variable name to lookup standard libraries for this
+ // language.
+ std::string standardLibsVar = "CMAKE_";
+ standardLibsVar += linkLanguage;
+ standardLibsVar += "_STANDARD_LIBRARIES";
+ const char* tool = "VCLinkerTool";
+ if (this->FortranProject) {
+ tool = "VFLinkerTool";
+ }
+ fout << "\t\t\t<Tool\n"
+ << "\t\t\t\tName=\"" << tool << "\"\n";
+ if (!gg->NeedLinkLibraryDependencies(target)) {
+ fout << "\t\t\t\tLinkLibraryDependencies=\"false\"\n";
+ }
+ linkOptions.OutputAdditionalOptions(fout, "\t\t\t\t", "\n");
+ // Use the NOINHERIT macro to avoid getting VS project default
+ // libraries which may be set by the user to something bad.
+ fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
+ << this->Makefile->GetSafeDefinition(standardLibsVar.c_str());
+ if (this->GetVersion() < cmGlobalVisualStudioGenerator::VS8 ||
+ this->FortranProject) {
+ this->Internal->OutputObjects(fout, target, " ");
+ }
+ fout << " ";
+ this->Internal->OutputLibraries(fout, cli.GetItems());
+ fout << "\"\n";
+ temp = target->GetDirectory(configName);
+ temp += "/";
+ temp += targetNameFull;
+ fout << "\t\t\t\tOutputFile=\""
+ << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
+ this->WriteTargetVersionAttribute(fout, target);
+ linkOptions.OutputFlagMap(fout, "\t\t\t\t");
+ fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
+ this->OutputLibraryDirectories(fout, cli.GetDirectories());
+ fout << "\"\n";
+ temp = target->GetPDBDirectory(configName);
+ temp += "/";
+ temp += targetNamePDB;
+ fout << "\t\t\t\tProgramDatabaseFile=\""
+ << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
+ if (targetOptions.IsDebug()) {
+ fout << "\t\t\t\tGenerateDebugInformation=\"true\"\n";
+ }
+ if (this->WindowsCEProject) {
+ if (this->GetVersion() < cmGlobalVisualStudioGenerator::VS9) {
+ fout << "\t\t\t\tSubSystem=\"9\"\n";
+ } else {
+ fout << "\t\t\t\tSubSystem=\"8\"\n";
+ }
+ }
+ std::string stackVar = "CMAKE_";
+ stackVar += linkLanguage;
+ stackVar += "_STACK_SIZE";
+ const char* stackVal = this->Makefile->GetDefinition(stackVar.c_str());
+ if (stackVal) {
+ fout << "\t\t\t\tStackReserveSize=\"" << stackVal << "\"\n";
+ }
+ temp = target->GetDirectory(configName, true);
+ temp += "/";
+ temp += targetNameImport;
+ fout << "\t\t\t\tImportLibrary=\""
+ << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"";
+ if (this->FortranProject) {
+ fout << "\n\t\t\t\tLinkDLL=\"true\"";
+ }
+ fout << "/>\n";
+ } break;
+ case cmState::EXECUTABLE: {
+ std::string targetName;
+ std::string targetNameFull;
+ std::string targetNameImport;
+ std::string targetNamePDB;
+ target->GetExecutableNames(targetName, targetNameFull, targetNameImport,
+ targetNamePDB, configName);
+
+ // Compute the link library and directory information.
+ cmComputeLinkInformation* pcli = target->GetLinkInformation(configName);
+ if (!pcli) {
+ return;
+ }
+ cmComputeLinkInformation& cli = *pcli;
+ std::string linkLanguage = cli.GetLinkLanguage();
+
+ bool isWin32Executable = target->GetPropertyAsBool("WIN32_EXECUTABLE");
+
+ // Compute the variable name to lookup standard libraries for this
+ // language.
+ std::string standardLibsVar = "CMAKE_";
+ standardLibsVar += linkLanguage;
+ standardLibsVar += "_STANDARD_LIBRARIES";
+ const char* tool = "VCLinkerTool";
+ if (this->FortranProject) {
+ tool = "VFLinkerTool";
+ }
+ fout << "\t\t\t<Tool\n"
+ << "\t\t\t\tName=\"" << tool << "\"\n";
+ if (!gg->NeedLinkLibraryDependencies(target)) {
+ fout << "\t\t\t\tLinkLibraryDependencies=\"false\"\n";
+ }
+ linkOptions.OutputAdditionalOptions(fout, "\t\t\t\t", "\n");
+ // Use the NOINHERIT macro to avoid getting VS project default
+ // libraries which may be set by the user to something bad.
+ fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
+ << this->Makefile->GetSafeDefinition(standardLibsVar.c_str());
+ if (this->GetVersion() < cmGlobalVisualStudioGenerator::VS8 ||
+ this->FortranProject) {
+ this->Internal->OutputObjects(fout, target, " ");
+ }
+ fout << " ";
+ this->Internal->OutputLibraries(fout, cli.GetItems());
+ fout << "\"\n";
+ temp = target->GetDirectory(configName);
+ temp += "/";
+ temp += targetNameFull;
+ fout << "\t\t\t\tOutputFile=\""
+ << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
+ this->WriteTargetVersionAttribute(fout, target);
+ linkOptions.OutputFlagMap(fout, "\t\t\t\t");
+ fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
+ this->OutputLibraryDirectories(fout, cli.GetDirectories());
+ fout << "\"\n";
+ std::string path = this->ConvertToXMLOutputPathSingle(
+ target->GetPDBDirectory(configName).c_str());
+ fout << "\t\t\t\tProgramDatabaseFile=\"" << path << "/" << targetNamePDB
+ << "\"\n";
+ if (targetOptions.IsDebug()) {
+ fout << "\t\t\t\tGenerateDebugInformation=\"true\"\n";
+ }
+ if (this->WindowsCEProject) {
+ if (this->GetVersion() < cmGlobalVisualStudioGenerator::VS9) {
+ fout << "\t\t\t\tSubSystem=\"9\"\n";
+ } else {
+ fout << "\t\t\t\tSubSystem=\"8\"\n";
+ }
+
+ if (!linkOptions.GetFlag("EntryPointSymbol")) {
+ const char* entryPointSymbol = targetOptions.UsingUnicode()
+ ? (isWin32Executable ? "wWinMainCRTStartup" : "mainWCRTStartup")
+ : (isWin32Executable ? "WinMainCRTStartup" : "mainACRTStartup");
+ fout << "\t\t\t\tEntryPointSymbol=\"" << entryPointSymbol << "\"\n";
+ }
+ } else if (this->FortranProject) {
+ fout << "\t\t\t\tSubSystem=\""
+ << (isWin32Executable ? "subSystemWindows" : "subSystemConsole")
+ << "\"\n";
+ } else {
+ fout << "\t\t\t\tSubSystem=\"" << (isWin32Executable ? "2" : "1")
+ << "\"\n";
+ }
+ std::string stackVar = "CMAKE_";
+ stackVar += linkLanguage;
+ stackVar += "_STACK_SIZE";
+ const char* stackVal = this->Makefile->GetDefinition(stackVar.c_str());
+ if (stackVal) {
+ fout << "\t\t\t\tStackReserveSize=\"" << stackVal << "\"";
+ }
+ temp = target->GetDirectory(configName, true);
+ temp += "/";
+ temp += targetNameImport;
+ fout << "\t\t\t\tImportLibrary=\""
+ << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"/>\n";
+ break;
+ }
+ case cmState::UTILITY:
+ case cmState::GLOBAL_TARGET:
+ case cmState::INTERFACE_LIBRARY:
+ break;
+ }
+}
+
+void cmLocalVisualStudio7Generator::OutputDeploymentDebuggerTool(
+ std::ostream& fout, std::string const& config, cmGeneratorTarget* target)
+{
+ if (this->WindowsCEProject) {
+ if (const char* dir = target->GetProperty("DEPLOYMENT_REMOTE_DIRECTORY")) {
+ /* clang-format off */
+ fout <<
+ "\t\t\t<DeploymentTool\n"
+ "\t\t\t\tForceDirty=\"-1\"\n"
+ "\t\t\t\tRemoteDirectory=\"" << this->EscapeForXML(dir) << "\"\n"
+ "\t\t\t\tRegisterOutput=\"0\"\n"
+ "\t\t\t\tAdditionalFiles=\"\"/>\n"
+ ;
+ /* clang-format on */
+ std::string const exe =
+ dir + std::string("\\") + target->GetFullName(config);
+ /* clang-format off */
+ fout <<
+ "\t\t\t<DebuggerTool\n"
+ "\t\t\t\tRemoteExecutable=\"" << this->EscapeForXML(exe) << "\"\n"
+ "\t\t\t\tArguments=\"\"\n"
+ "\t\t\t/>\n"
+ ;
+ /* clang-format on */
+ }
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteTargetVersionAttribute(
+ std::ostream& fout, cmGeneratorTarget* gt)
+{
+ int major;
+ int minor;
+ gt->GetTargetVersion(major, minor);
+ fout << "\t\t\t\tVersion=\"" << major << "." << minor << "\"\n";
+}
+
+void cmLocalVisualStudio7GeneratorInternals::OutputLibraries(
+ std::ostream& fout, ItemVector const& libs)
+{
+ cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
+ for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) {
+ if (l->IsPath) {
+ std::string rel =
+ lg->Convert(l->Value.c_str(), cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED);
+ fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " ";
+ } else if (!l->Target ||
+ l->Target->GetType() != cmState::INTERFACE_LIBRARY) {
+ fout << l->Value << " ";
+ }
+ }
+}
+
+void cmLocalVisualStudio7GeneratorInternals::OutputObjects(
+ std::ostream& fout, cmGeneratorTarget* gt, const char* isep)
+{
+ // VS < 8 does not support per-config source locations so we
+ // list object library content on the link line instead.
+ cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
+ std::vector<std::string> objs;
+ gt->UseObjectLibraries(objs, "");
+ const char* sep = isep ? isep : "";
+ for (std::vector<std::string>::const_iterator oi = objs.begin();
+ oi != objs.end(); ++oi) {
+ std::string rel = lg->Convert(oi->c_str(), cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED);
+ fout << sep << lg->ConvertToXMLOutputPath(rel.c_str());
+ sep = " ";
+ }
+}
+
+void cmLocalVisualStudio7Generator::OutputLibraryDirectories(
+ std::ostream& fout, std::vector<std::string> const& dirs)
+{
+ const char* comma = "";
+ for (std::vector<std::string>::const_iterator d = dirs.begin();
+ d != dirs.end(); ++d) {
+ // Remove any trailing slash and skip empty paths.
+ std::string dir = *d;
+ if (dir[dir.size() - 1] == '/') {
+ dir = dir.substr(0, dir.size() - 1);
+ }
+ if (dir.empty()) {
+ continue;
+ }
+
+ // Switch to a relative path specification if it is shorter.
+ if (cmSystemTools::FileIsFullPath(dir.c_str())) {
+ std::string rel =
+ this->Convert(dir.c_str(), cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED);
+ if (rel.size() < dir.size()) {
+ dir = rel;
+ }
+ }
+
+ // First search a configuration-specific subdirectory and then the
+ // original directory.
+ fout << comma
+ << this->ConvertToXMLOutputPath(
+ (dir + "/$(ConfigurationName)").c_str())
+ << "," << this->ConvertToXMLOutputPath(dir.c_str());
+ comma = ",";
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
+ const std::string& libName,
+ cmGeneratorTarget* target)
+{
+ std::vector<std::string> configs;
+ this->Makefile->GetConfigurations(configs);
+
+ // We may be modifying the source groups temporarily, so make a copy.
+ std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
+
+ // get the classes from the source lists then add them to the groups
+ this->ModuleDefinitionFile = "";
+ std::vector<cmSourceFile*> classes;
+ if (!target->GetConfigCommonSourceFiles(classes)) {
+ return;
+ }
+ for (std::vector<cmSourceFile*>::const_iterator i = classes.begin();
+ i != classes.end(); i++) {
+ if (!(*i)->GetObjectLibrary().empty()) {
+ continue;
+ }
+ // Add the file to the list of sources.
+ std::string source = (*i)->GetFullPath();
+ if (cmSystemTools::UpperCase((*i)->GetExtension()) == "DEF") {
+ this->ModuleDefinitionFile = (*i)->GetFullPath();
+ }
+ cmSourceGroup* sourceGroup =
+ this->Makefile->FindSourceGroup(source.c_str(), sourceGroups);
+ sourceGroup->AssignSource(*i);
+ }
+
+ // open the project
+ this->WriteProjectStart(fout, libName, target, sourceGroups);
+ // write the configuration information
+ this->WriteConfigurations(fout, configs, libName, target);
+
+ fout << "\t<Files>\n";
+
+ // Loop through every source group.
+ for (unsigned int i = 0; i < sourceGroups.size(); ++i) {
+ cmSourceGroup sg = sourceGroups[i];
+ this->WriteGroup(&sg, target, fout, libName, configs);
+ }
+
+ if (this->GetVersion() >= cmGlobalVisualStudioGenerator::VS8 &&
+ !this->FortranProject) {
+ // VS >= 8 support per-config source locations so we
+ // list object library content as external objects.
+ std::vector<std::string> objs;
+ target->UseObjectLibraries(objs, "");
+ if (!objs.empty()) {
+ // TODO: Separate sub-filter for each object library used?
+ fout << "\t\t<Filter Name=\"Object Libraries\">\n";
+ for (std::vector<std::string>::const_iterator oi = objs.begin();
+ oi != objs.end(); ++oi) {
+ std::string o = this->ConvertToXMLOutputPathSingle(oi->c_str());
+ fout << "\t\t\t<File RelativePath=\"" << o << "\" />\n";
+ }
+ fout << "\t\t</Filter>\n";
+ }
+ }
+
+ fout << "\t</Files>\n";
+
+ // Write the VCProj file's footer.
+ this->WriteVCProjFooter(fout, target);
+}
+
+struct cmLVS7GFileConfig
+{
+ std::string ObjectName;
+ std::string CompileFlags;
+ std::string CompileDefs;
+ std::string CompileDefsConfig;
+ std::string AdditionalDeps;
+ bool ExcludedFromBuild;
+};
+
+class cmLocalVisualStudio7GeneratorFCInfo
+{
+public:
+ cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg,
+ cmGeneratorTarget* target,
+ cmSourceFile const& sf,
+ std::vector<std::string> const& configs);
+ std::map<std::string, cmLVS7GFileConfig> FileConfigMap;
+};
+
+cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
+ cmLocalVisualStudio7Generator* lg, cmGeneratorTarget* gt,
+ cmSourceFile const& sf, std::vector<std::string> const& configs)
+{
+ std::string objectName;
+ if (gt->HasExplicitObjectName(&sf)) {
+ objectName = gt->GetObjectName(&sf);
+ }
+
+ // Compute per-source, per-config information.
+ for (std::vector<std::string>::const_iterator i = configs.begin();
+ i != configs.end(); ++i) {
+ std::string configUpper = cmSystemTools::UpperCase(*i);
+ cmLVS7GFileConfig fc;
+ bool needfc = false;
+ if (!objectName.empty()) {
+ fc.ObjectName = objectName;
+ needfc = true;
+ }
+ if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) {
+ fc.CompileFlags = cflags;
+ needfc = true;
+ }
+ if (lg->FortranProject) {
+ switch (cmOutputConverter::GetFortranFormat(
+ sf.GetProperty("Fortran_FORMAT"))) {
+ case cmOutputConverter::FortranFormatFixed:
+ fc.CompileFlags = "-fixed " + fc.CompileFlags;
+ needfc = true;
+ break;
+ case cmOutputConverter::FortranFormatFree:
+ fc.CompileFlags = "-free " + fc.CompileFlags;
+ needfc = true;
+ break;
+ default:
+ break;
+ }
+ }
+ if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) {
+ fc.CompileDefs = cdefs;
+ needfc = true;
+ }
+ std::string defPropName = "COMPILE_DEFINITIONS_";
+ defPropName += configUpper;
+ if (const char* ccdefs = sf.GetProperty(defPropName.c_str())) {
+ fc.CompileDefsConfig = ccdefs;
+ needfc = true;
+ }
+
+ // Check for extra object-file dependencies.
+ if (const char* deps = sf.GetProperty("OBJECT_DEPENDS")) {
+ std::vector<std::string> depends;
+ cmSystemTools::ExpandListArgument(deps, depends);
+ const char* sep = "";
+ for (std::vector<std::string>::iterator j = depends.begin();
+ j != depends.end(); ++j) {
+ fc.AdditionalDeps += sep;
+ fc.AdditionalDeps += lg->ConvertToXMLOutputPath(j->c_str());
+ sep = ";";
+ needfc = true;
+ }
+ }
+
+ std::string lang =
+ lg->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str());
+ const std::string& sourceLang = lg->GetSourceFileLanguage(sf);
+ const std::string& linkLanguage = gt->GetLinkerLanguage(i->c_str());
+ bool needForceLang = false;
+ // source file does not match its extension language
+ if (lang != sourceLang) {
+ needForceLang = true;
+ lang = sourceLang;
+ }
+ // If HEADER_FILE_ONLY is set, we must suppress this generation in
+ // the project file
+ fc.ExcludedFromBuild = (sf.GetPropertyAsBool("HEADER_FILE_ONLY"));
+ if (fc.ExcludedFromBuild) {
+ needfc = true;
+ }
+
+ // if the source file does not match the linker language
+ // then force c or c++
+ if (needForceLang || (linkLanguage != lang)) {
+ if (lang == "CXX") {
+ // force a C++ file type
+ fc.CompileFlags += " /TP ";
+ needfc = true;
+ } else if (lang == "C") {
+ // force to c
+ fc.CompileFlags += " /TC ";
+ needfc = true;
+ }
+ }
+
+ if (needfc) {
+ this->FileConfigMap[*i] = fc;
+ }
+ }
+}
+
+std::string cmLocalVisualStudio7Generator::ComputeLongestObjectDirectory(
+ cmGeneratorTarget const* target) const
+{
+ std::vector<std::string> configs;
+ target->Target->GetMakefile()->GetConfigurations(configs);
+
+ // Compute the maximum length configuration name.
+ std::string config_max;
+ for (std::vector<std::string>::iterator i = configs.begin();
+ i != configs.end(); ++i) {
+ if (i->size() > config_max.size()) {
+ config_max = *i;
+ }
+ }
+
+ // Compute the maximum length full path to the intermediate
+ // files directory for any configuration. This is used to construct
+ // object file names that do not produce paths that are too long.
+ std::string dir_max;
+ dir_max += this->GetCurrentBinaryDirectory();
+ dir_max += "/";
+ dir_max += this->GetTargetDirectory(target);
+ dir_max += "/";
+ dir_max += config_max;
+ dir_max += "/";
+ return dir_max;
+}
+
+bool cmLocalVisualStudio7Generator::WriteGroup(
+ const cmSourceGroup* sg, cmGeneratorTarget* target, std::ostream& fout,
+ const std::string& libName, std::vector<std::string> const& configs)
+{
+ cmGlobalVisualStudio7Generator* gg =
+ static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
+ const std::vector<const cmSourceFile*>& sourceFiles = sg->GetSourceFiles();
+ std::vector<cmSourceGroup> const& children = sg->GetGroupChildren();
+
+ // Write the children to temporary output.
+ bool hasChildrenWithSources = false;
+ std::ostringstream tmpOut;
+ for (unsigned int i = 0; i < children.size(); ++i) {
+ if (this->WriteGroup(&children[i], target, tmpOut, libName, configs)) {
+ hasChildrenWithSources = true;
+ }
+ }
+
+ // If the group is empty, don't write it at all.
+ if (sourceFiles.empty() && !hasChildrenWithSources) {
+ return false;
+ }
+
+ // If the group has a name, write the header.
+ std::string name = sg->GetName();
+ if (name != "") {
+ this->WriteVCProjBeginGroup(fout, name.c_str(), "");
+ }
+
+ // 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();
+ FCInfo fcinfo(this, target, *(*sf), configs);
+
+ if (source != libName || target->GetType() == cmState::UTILITY ||
+ target->GetType() == cmState::GLOBAL_TARGET) {
+ fout << "\t\t\t<File\n";
+ std::string d = this->ConvertToXMLOutputPathSingle(source.c_str());
+ // 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()) {
+ this->WriteCustomRule(fout, configs, source.c_str(), *command, fcinfo);
+ } else if (!fcinfo.FileConfigMap.empty()) {
+ const char* aCompilerTool = "VCCLCompilerTool";
+ const char* ppLang = "CXX";
+ if (this->FortranProject) {
+ aCompilerTool = "VFFortranCompilerTool";
+ }
+ std::string const& lang = (*sf)->GetLanguage();
+ std::string ext = (*sf)->GetExtension();
+ ext = cmSystemTools::LowerCase(ext);
+ if (ext == "idl") {
+ aCompilerTool = "VCMIDLTool";
+ if (this->FortranProject) {
+ aCompilerTool = "VFMIDLTool";
+ }
+ }
+ if (ext == "rc") {
+ aCompilerTool = "VCResourceCompilerTool";
+ ppLang = "RC";
+ if (this->FortranProject) {
+ aCompilerTool = "VFResourceCompilerTool";
+ }
+ }
+ if (ext == "def") {
+ aCompilerTool = "VCCustomBuildTool";
+ if (this->FortranProject) {
+ aCompilerTool = "VFCustomBuildTool";
+ }
+ }
+ if (gg->IsMasmEnabled() && !this->FortranProject &&
+ lang == "ASM_MASM") {
+ aCompilerTool = "MASM";
+ }
+ for (std::map<std::string, cmLVS7GFileConfig>::const_iterator fci =
+ fcinfo.FileConfigMap.begin();
+ fci != fcinfo.FileConfigMap.end(); ++fci) {
+ cmLVS7GFileConfig const& fc = fci->second;
+ fout << "\t\t\t\t<FileConfiguration\n"
+ << "\t\t\t\t\tName=\"" << fci->first << "|"
+ << gg->GetPlatformName() << "\"";
+ if (fc.ExcludedFromBuild) {
+ fout << " ExcludedFromBuild=\"true\"";
+ }
+ fout << ">\n";
+ fout << "\t\t\t\t\t<Tool\n"
+ << "\t\t\t\t\tName=\"" << aCompilerTool << "\"\n";
+ if (!fc.CompileFlags.empty() || !fc.CompileDefs.empty() ||
+ !fc.CompileDefsConfig.empty()) {
+ Options::Tool tool = Options::Compiler;
+ cmVS7FlagTable const* table =
+ cmLocalVisualStudio7GeneratorFlagTable;
+ if (this->FortranProject) {
+ tool = Options::FortranCompiler;
+ table = cmLocalVisualStudio7GeneratorFortranFlagTable;
+ }
+ Options fileOptions(this, tool, table, gg->ExtraFlagTable);
+ fileOptions.Parse(fc.CompileFlags.c_str());
+ fileOptions.AddDefines(fc.CompileDefs.c_str());
+ fileOptions.AddDefines(fc.CompileDefsConfig.c_str());
+ fileOptions.OutputAdditionalOptions(fout, "\t\t\t\t\t", "\n");
+ fileOptions.OutputFlagMap(fout, "\t\t\t\t\t");
+ fileOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t\t", "\n",
+ ppLang);
+ }
+ if (!fc.AdditionalDeps.empty()) {
+ fout << "\t\t\t\t\tAdditionalDependencies=\"" << fc.AdditionalDeps
+ << "\"\n";
+ }
+ if (!fc.ObjectName.empty()) {
+ fout << "\t\t\t\t\tObjectFile=\"$(IntDir)/" << fc.ObjectName
+ << "\"\n";
+ }
+ fout << "\t\t\t\t\t/>\n"
+ << "\t\t\t\t</FileConfiguration>\n";
+ }
+ }
+ fout << "\t\t\t</File>\n";
+ }
+ }
+
+ // If the group has children with source files, write the children.
+ if (hasChildrenWithSources) {
+ fout << tmpOut.str();
+ }
+
+ // If the group has a name, write the footer.
+ if (name != "") {
+ this->WriteVCProjEndGroup(fout);
+ }
+
+ return true;
+}
+
+void cmLocalVisualStudio7Generator::WriteCustomRule(
+ std::ostream& fout, std::vector<std::string> const& configs,
+ const char* source, const cmCustomCommand& command, FCInfo& fcinfo)
+{
+ cmGlobalVisualStudio7Generator* gg =
+ static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
+
+ // Write the rule for each configuration.
+ const char* compileTool = "VCCLCompilerTool";
+ if (this->FortranProject) {
+ compileTool = "VFCLCompilerTool";
+ }
+ const char* customTool = "VCCustomBuildTool";
+ 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];
+ fout << "\t\t\t\t<FileConfiguration\n";
+ fout << "\t\t\t\t\tName=\"" << *i << "|" << gg->GetPlatformName()
+ << "\">\n";
+ if (!fc.CompileFlags.empty()) {
+ fout << "\t\t\t\t\t<Tool\n"
+ << "\t\t\t\t\tName=\"" << compileTool << "\"\n"
+ << "\t\t\t\t\tAdditionalOptions=\""
+ << this->EscapeForXML(fc.CompileFlags.c_str()) << "\"/>\n";
+ }
+
+ std::string comment = this->ConstructComment(ccg);
+ std::string script = this->ConstructScript(ccg);
+ if (this->FortranProject) {
+ cmSystemTools::ReplaceString(script, "$(Configuration)", i->c_str());
+ }
+ /* clang-format off */
+ fout << "\t\t\t\t\t<Tool\n"
+ << "\t\t\t\t\tName=\"" << customTool << "\"\n"
+ << "\t\t\t\t\tDescription=\""
+ << this->EscapeForXML(comment.c_str()) << "\"\n"
+ << "\t\t\t\t\tCommandLine=\""
+ << this->EscapeForXML(script.c_str()) << "\"\n"
+ << "\t\t\t\t\tAdditionalDependencies=\"";
+ /* clang-format on */
+ if (ccg.GetDepends().empty()) {
+ // There are no real dependencies. Produce an artificial one to
+ // make sure the rule runs reliably.
+ if (!cmSystemTools::FileExists(source)) {
+ cmsys::ofstream depout(source);
+ depout << "Artificial dependency for a custom command.\n";
+ }
+ 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) {
+ // 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)) {
+ fout << this->ConvertToXMLOutputPath(dep.c_str()) << ";";
+ }
+ }
+ }
+ fout << "\"\n";
+ fout << "\t\t\t\t\tOutputs=\"";
+ if (ccg.GetOutputs().empty()) {
+ fout << source << "_force";
+ } 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());
+ sep = ";";
+ }
+ }
+ fout << "\"/>\n";
+ fout << "\t\t\t\t</FileConfiguration>\n";
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteVCProjBeginGroup(std::ostream& fout,
+ const char* group,
+ const char*)
+{
+ /* clang-format off */
+ fout << "\t\t<Filter\n"
+ << "\t\t\tName=\"" << group << "\"\n"
+ << "\t\t\tFilter=\"\">\n";
+ /* clang-format on */
+}
+
+void cmLocalVisualStudio7Generator::WriteVCProjEndGroup(std::ostream& fout)
+{
+ fout << "\t\t</Filter>\n";
+}
+
+// look for custom rules on a target and collect them together
+void cmLocalVisualStudio7Generator::OutputTargetRules(
+ std::ostream& fout, const std::string& configName, cmGeneratorTarget* target,
+ const std::string& /*libName*/)
+{
+ if (target->GetType() > cmState::GLOBAL_TARGET) {
+ return;
+ }
+ EventWriter event(this, configName, fout);
+
+ // Add pre-build event.
+ const char* tool =
+ this->FortranProject ? "VFPreBuildEventTool" : "VCPreBuildEventTool";
+ event.Start(tool);
+ event.Write(target->GetPreBuildCommands());
+ event.Finish();
+
+ // Add pre-link event.
+ tool = this->FortranProject ? "VFPreLinkEventTool" : "VCPreLinkEventTool";
+ event.Start(tool);
+ bool addedPrelink = false;
+ if (target->GetType() == cmState::SHARED_LIBRARY &&
+ this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS")) {
+ if (target->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS")) {
+ addedPrelink = true;
+ std::vector<cmCustomCommand> commands = target->GetPreLinkCommands();
+ cmGlobalVisualStudioGenerator* gg =
+ static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
+ gg->AddSymbolExportCommand(target, commands, configName);
+ event.Write(commands);
+ }
+ }
+ if (!addedPrelink) {
+ event.Write(target->GetPreLinkCommands());
+ }
+ CM_AUTO_PTR<cmCustomCommand> pcc(
+ this->MaybeCreateImplibDir(target, configName, this->FortranProject));
+ if (pcc.get()) {
+ event.Write(*pcc);
+ }
+ event.Finish();
+
+ // Add post-build event.
+ tool =
+ this->FortranProject ? "VFPostBuildEventTool" : "VCPostBuildEventTool";
+ event.Start(tool);
+ event.Write(target->GetPostBuildCommands());
+ event.Finish();
+}
+
+void cmLocalVisualStudio7Generator::WriteProjectSCC(std::ostream& fout,
+ cmGeneratorTarget* target)
+{
+ // if we have all the required Source code control tags
+ // then add that to the project
+ const char* vsProjectname = target->GetProperty("VS_SCC_PROJECTNAME");
+ const char* vsLocalpath = target->GetProperty("VS_SCC_LOCALPATH");
+ const char* vsProvider = target->GetProperty("VS_SCC_PROVIDER");
+
+ if (vsProvider && vsLocalpath && vsProjectname) {
+ /* clang-format off */
+ fout << "\tSccProjectName=\"" << vsProjectname << "\"\n"
+ << "\tSccLocalPath=\"" << vsLocalpath << "\"\n"
+ << "\tSccProvider=\"" << vsProvider << "\"\n";
+ /* clang-format on */
+
+ const char* vsAuxPath = target->GetProperty("VS_SCC_AUXPATH");
+ if (vsAuxPath) {
+ fout << "\tSccAuxPath=\"" << vsAuxPath << "\"\n";
+ }
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteProjectStartFortran(
+ std::ostream& fout, const std::string& libName, cmGeneratorTarget* target)
+{
+
+ cmGlobalVisualStudio7Generator* gg =
+ static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
+ /* clang-format off */
+ fout << "<?xml version=\"1.0\" encoding = \""
+ << gg->Encoding() << "\"?>\n"
+ << "<VisualStudioProject\n"
+ << "\tProjectCreator=\"Intel Fortran\"\n"
+ << "\tVersion=\"" << gg->GetIntelProjectVersion() << "\"\n";
+ /* clang-format on */
+ const char* keyword = target->GetProperty("VS_KEYWORD");
+ if (!keyword) {
+ keyword = "Console Application";
+ }
+ const char* projectType = 0;
+ switch (target->GetType()) {
+ case cmState::STATIC_LIBRARY:
+ projectType = "typeStaticLibrary";
+ if (keyword) {
+ keyword = "Static Library";
+ }
+ break;
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ projectType = "typeDynamicLibrary";
+ if (!keyword) {
+ keyword = "Dll";
+ }
+ break;
+ case cmState::EXECUTABLE:
+ if (!keyword) {
+ keyword = "Console Application";
+ }
+ projectType = 0;
+ break;
+ case cmState::UTILITY:
+ case cmState::GLOBAL_TARGET:
+ default:
+ break;
+ }
+ if (projectType) {
+ fout << "\tProjectType=\"" << projectType << "\"\n";
+ }
+ this->WriteProjectSCC(fout, target);
+ /* clang-format off */
+ fout<< "\tKeyword=\"" << keyword << "\">\n"
+ << "\tProjectGUID=\"{" << gg->GetGUID(libName.c_str()) << "}\">\n"
+ << "\t<Platforms>\n"
+ << "\t\t<Platform\n\t\t\tName=\"" << gg->GetPlatformName() << "\"/>\n"
+ << "\t</Platforms>\n";
+ /* clang-format on */
+}
+
+void cmLocalVisualStudio7Generator::WriteProjectStart(
+ std::ostream& fout, const std::string& libName, cmGeneratorTarget* target,
+ std::vector<cmSourceGroup>&)
+{
+ if (this->FortranProject) {
+ this->WriteProjectStartFortran(fout, libName, target);
+ return;
+ }
+
+ cmGlobalVisualStudio7Generator* gg =
+ static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
+
+ /* clang-format off */
+ fout << "<?xml version=\"1.0\" encoding = \""
+ << gg->Encoding() << "\"?>\n"
+ << "<VisualStudioProject\n"
+ << "\tProjectType=\"Visual C++\"\n";
+ /* clang-format on */
+ if (gg->GetVersion() == cmGlobalVisualStudioGenerator::VS71) {
+ fout << "\tVersion=\"7.10\"\n";
+ } else {
+ fout << "\tVersion=\"" << (gg->GetVersion() / 10) << ".00\"\n";
+ }
+ const char* projLabel = target->GetProperty("PROJECT_LABEL");
+ if (!projLabel) {
+ projLabel = libName.c_str();
+ }
+ const char* keyword = target->GetProperty("VS_KEYWORD");
+ if (!keyword) {
+ keyword = "Win32Proj";
+ }
+ fout << "\tName=\"" << projLabel << "\"\n";
+ if (gg->GetVersion() >= cmGlobalVisualStudioGenerator::VS8) {
+ fout << "\tProjectGUID=\"{" << gg->GetGUID(libName.c_str()) << "}\"\n";
+ }
+ this->WriteProjectSCC(fout, target);
+ if (const char* targetFrameworkVersion =
+ target->GetProperty("VS_DOTNET_TARGET_FRAMEWORK_VERSION")) {
+ fout << "\tTargetFrameworkVersion=\"" << targetFrameworkVersion << "\"\n";
+ }
+ /* clang-format off */
+ fout << "\tKeyword=\"" << keyword << "\">\n"
+ << "\t<Platforms>\n"
+ << "\t\t<Platform\n\t\t\tName=\"" << gg->GetPlatformName() << "\"/>\n"
+ << "\t</Platforms>\n";
+ /* clang-format on */
+ if (gg->IsMasmEnabled()) {
+ /* clang-format off */
+ fout <<
+ "\t<ToolFiles>\n"
+ "\t\t<DefaultToolFile\n"
+ "\t\t\tFileName=\"masm.rules\"\n"
+ "\t\t/>\n"
+ "\t</ToolFiles>\n"
+ ;
+ /* clang-format on */
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteVCProjFooter(
+ std::ostream& fout, cmGeneratorTarget* target)
+{
+ 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);
+ if (name != "") {
+ /* clang-format off */
+ fout << "\t\t<Global\n"
+ << "\t\t\tName=\"" << name << "\"\n"
+ << "\t\t\tValue=\"" << target->GetProperty(*i) << "\"\n"
+ << "\t\t/>\n";
+ /* clang-format on */
+ }
+ }
+ }
+
+ fout << "\t</Globals>\n"
+ << "</VisualStudioProject>\n";
+}
+
+std::string cmLocalVisualStudio7GeneratorEscapeForXML(const std::string& s)
+{
+ std::string ret = s;
+ cmSystemTools::ReplaceString(ret, "&", "&amp;");
+ cmSystemTools::ReplaceString(ret, "\"", "&quot;");
+ cmSystemTools::ReplaceString(ret, "<", "&lt;");
+ cmSystemTools::ReplaceString(ret, ">", "&gt;");
+ cmSystemTools::ReplaceString(ret, "\n", "&#x0D;&#x0A;");
+ return ret;
+}
+
+std::string cmLocalVisualStudio7Generator::EscapeForXML(const std::string& s)
+{
+ return cmLocalVisualStudio7GeneratorEscapeForXML(s);
+}
+
+std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPath(
+ const char* path)
+{
+ std::string ret =
+ this->ConvertToOutputFormat(path, cmOutputConverter::SHELL);
+ cmSystemTools::ReplaceString(ret, "&", "&amp;");
+ cmSystemTools::ReplaceString(ret, "\"", "&quot;");
+ cmSystemTools::ReplaceString(ret, "<", "&lt;");
+ cmSystemTools::ReplaceString(ret, ">", "&gt;");
+ return ret;
+}
+
+std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPathSingle(
+ const char* path)
+{
+ std::string ret =
+ this->ConvertToOutputFormat(path, cmOutputConverter::SHELL);
+ cmSystemTools::ReplaceString(ret, "\"", "");
+ cmSystemTools::ReplaceString(ret, "&", "&amp;");
+ cmSystemTools::ReplaceString(ret, "<", "&lt;");
+ cmSystemTools::ReplaceString(ret, ">", "&gt;");
+ return ret;
+}
+
+// This class is used to parse an existing vs 7 project
+// and extract the GUID
+class cmVS7XMLParser : public cmXMLParser
+{
+public:
+ virtual void EndElement(const std::string& /* name */) {}
+ virtual void StartElement(const std::string& name, const char** atts)
+ {
+ // once the GUID is found do nothing
+ if (!this->GUID.empty()) {
+ return;
+ }
+ int i = 0;
+ if ("VisualStudioProject" == name) {
+ while (atts[i]) {
+ if (strcmp(atts[i], "ProjectGUID") == 0) {
+ if (atts[i + 1]) {
+ this->GUID = atts[i + 1];
+ this->GUID = this->GUID.substr(1, this->GUID.size() - 2);
+ } else {
+ this->GUID = "";
+ }
+ return;
+ }
+ ++i;
+ }
+ }
+ }
+ int InitializeParser()
+ {
+ int ret = cmXMLParser::InitializeParser();
+ if (ret == 0) {
+ return ret;
+ }
+ // visual studio projects have a strange encoding, but it is
+ // really utf-8
+ XML_SetEncoding(static_cast<XML_Parser>(this->Parser), "utf-8");
+ return 1;
+ }
+ std::string GUID;
+};
+
+void cmLocalVisualStudio7Generator::ReadAndStoreExternalGUID(
+ const std::string& name, const char* path)
+{
+ cmVS7XMLParser parser;
+ parser.ParseFile(path);
+ // if we can not find a GUID then we will generate one later
+ if (parser.GUID.empty()) {
+ return;
+ }
+ std::string guidStoreName = name;
+ guidStoreName += "_GUID_CMAKE";
+ // save the GUID in the cache
+ this->GlobalGenerator->GetCMakeInstance()->AddCacheEntry(
+ guidStoreName.c_str(), parser.GUID.c_str(), "Stored GUID",
+ cmState::INTERNAL);
+}
+
+std::string cmLocalVisualStudio7Generator::GetTargetDirectory(
+ cmGeneratorTarget const* target) const
+{
+ std::string dir;
+ dir += target->GetName();
+ dir += ".dir";
+ return dir;
+}
+
+#include <windows.h>
+static bool cmLVS7G_IsFAT(const char* dir)
+{
+ if (dir[0] && dir[1] == ':') {
+ char volRoot[4] = "_:/";
+ volRoot[0] = dir[0];
+ char fsName[16];
+ if (GetVolumeInformationA(volRoot, 0, 0, 0, 0, 0, fsName, 16) &&
+ strstr(fsName, "FAT") != 0) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h
new file mode 100644
index 0000000..6d1d0fb
--- /dev/null
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -0,0 +1,139 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLocalVisualStudio7Generator_h
+#define cmLocalVisualStudio7Generator_h
+
+#include "cmLocalVisualStudioGenerator.h"
+
+#include "cmVisualStudioGeneratorOptions.h"
+
+class cmSourceFile;
+class cmCustomCommand;
+class cmSourceGroup;
+
+class cmLocalVisualStudio7GeneratorOptions;
+class cmLocalVisualStudio7GeneratorFCInfo;
+class cmLocalVisualStudio7GeneratorInternals;
+
+/** \class cmLocalVisualStudio7Generator
+ * \brief Write Visual Studio .NET project files.
+ *
+ * cmLocalVisualStudio7Generator produces a Visual Studio .NET project
+ * file for each target in its directory.
+ */
+class cmLocalVisualStudio7Generator : public cmLocalVisualStudioGenerator
+{
+public:
+ ///! Set cache only and recurse to false by default.
+ cmLocalVisualStudio7Generator(cmGlobalGenerator* gg, cmMakefile* mf);
+
+ virtual ~cmLocalVisualStudio7Generator();
+
+ virtual void AddHelperCommands();
+
+ /**
+ * Generate the makefile for this directory.
+ */
+ virtual void Generate();
+
+ enum BuildType
+ {
+ STATIC_LIBRARY,
+ DLL,
+ EXECUTABLE,
+ WIN32_EXECUTABLE,
+ UTILITY
+ };
+
+ /**
+ * Specify the type of the build: static, dll, or executable.
+ */
+ void SetBuildType(BuildType, const std::string& name);
+
+ virtual std::string GetTargetDirectory(
+ cmGeneratorTarget const* target) const;
+ cmSourceFile* CreateVCProjBuildRule();
+ void WriteStampFiles();
+ virtual std::string ComputeLongestObjectDirectory(
+ cmGeneratorTarget const*) const;
+
+ virtual void ReadAndStoreExternalGUID(const std::string& name,
+ const char* path);
+ virtual void AddCMakeListsRules();
+
+protected:
+ void CreateSingleVCProj(const std::string& lname, cmGeneratorTarget* tgt);
+
+private:
+ typedef cmVisualStudioGeneratorOptions Options;
+ typedef cmLocalVisualStudio7GeneratorFCInfo FCInfo;
+ std::string GetBuildTypeLinkerFlags(std::string rootLinkerFlags,
+ const std::string& configName);
+ void FixGlobalTargets();
+ void WriteProjectFiles();
+ void WriteVCProjHeader(std::ostream& fout, const std::string& libName,
+ cmGeneratorTarget* tgt,
+ std::vector<cmSourceGroup>& sgs);
+ void WriteVCProjFooter(std::ostream& fout, cmGeneratorTarget* target);
+ void WriteVCProjFile(std::ostream& fout, const std::string& libName,
+ cmGeneratorTarget* tgt);
+ void WriteConfigurations(std::ostream& fout,
+ std::vector<std::string> const& configs,
+ const std::string& libName, cmGeneratorTarget* tgt);
+ void WriteConfiguration(std::ostream& fout, const std::string& configName,
+ const std::string& libName, cmGeneratorTarget* tgt);
+ std::string EscapeForXML(const std::string& s);
+ std::string ConvertToXMLOutputPath(const char* path);
+ std::string ConvertToXMLOutputPathSingle(const char* path);
+ void OutputTargetRules(std::ostream& fout, const std::string& configName,
+ cmGeneratorTarget* target,
+ const std::string& libName);
+ void OutputBuildTool(std::ostream& fout, const std::string& configName,
+ cmGeneratorTarget* t, const Options& targetOptions);
+ void OutputDeploymentDebuggerTool(std::ostream& fout,
+ std::string const& config,
+ cmGeneratorTarget* target);
+ void OutputLibraryDirectories(std::ostream& fout,
+ std::vector<std::string> const& dirs);
+ void WriteProjectSCC(std::ostream& fout, cmGeneratorTarget* target);
+ void WriteProjectStart(std::ostream& fout, const std::string& libName,
+ cmGeneratorTarget* tgt,
+ std::vector<cmSourceGroup>& sgs);
+ void WriteProjectStartFortran(std::ostream& fout, const std::string& libName,
+ cmGeneratorTarget* tgt);
+ void WriteVCProjBeginGroup(std::ostream& fout, const char* group,
+ const char* filter);
+ void WriteVCProjEndGroup(std::ostream& fout);
+
+ void WriteCustomRule(std::ostream& fout,
+ std::vector<std::string> const& configs,
+ const char* source, const cmCustomCommand& command,
+ FCInfo& fcinfo);
+ void WriteTargetVersionAttribute(std::ostream& fout, cmGeneratorTarget* gt);
+
+ bool WriteGroup(const cmSourceGroup* sg, cmGeneratorTarget* target,
+ std::ostream& fout, const std::string& libName,
+ std::vector<std::string> const& configs);
+
+ friend class cmLocalVisualStudio7GeneratorFCInfo;
+ friend class cmLocalVisualStudio7GeneratorInternals;
+
+ class EventWriter;
+ friend class EventWriter;
+
+ std::string ModuleDefinitionFile;
+ bool FortranProject;
+ bool WindowsCEProject;
+ cmLocalVisualStudio7GeneratorInternals* Internal;
+};
+
+#endif
diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx
new file mode 100644
index 0000000..bdb1c2b
--- /dev/null
+++ b/Source/cmLocalVisualStudioGenerator.cxx
@@ -0,0 +1,234 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmLocalVisualStudioGenerator.h"
+
+#include "cmCustomCommandGenerator.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmSystemTools.h"
+#include "windows.h"
+
+cmLocalVisualStudioGenerator::cmLocalVisualStudioGenerator(
+ cmGlobalGenerator* gg, cmMakefile* mf)
+ : cmLocalGenerator(gg, mf)
+{
+}
+
+cmLocalVisualStudioGenerator::~cmLocalVisualStudioGenerator()
+{
+}
+
+cmGlobalVisualStudioGenerator::VSVersion
+cmLocalVisualStudioGenerator::GetVersion() const
+{
+ cmGlobalVisualStudioGenerator* gg =
+ static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
+ return gg->GetVersion();
+}
+
+void cmLocalVisualStudioGenerator::ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt)
+{
+ std::string dir_max = this->ComputeLongestObjectDirectory(gt);
+
+ // Count the number of object files with each name. Note that
+ // windows file names are not case sensitive.
+ std::map<std::string, int> counts;
+
+ for (std::map<cmSourceFile const*, std::string>::iterator si =
+ mapping.begin();
+ si != mapping.end(); ++si) {
+ cmSourceFile const* sf = si->first;
+ std::string objectNameLower = cmSystemTools::LowerCase(
+ cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
+ objectNameLower += this->GlobalGenerator->GetLanguageOutputExtension(*sf);
+ counts[objectNameLower] += 1;
+ }
+
+ // For all source files producing duplicate names we need unique
+ // object name computation.
+
+ for (std::map<cmSourceFile const*, std::string>::iterator si =
+ mapping.begin();
+ si != mapping.end(); ++si) {
+ cmSourceFile const* sf = si->first;
+ std::string objectName =
+ cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
+ objectName += this->GlobalGenerator->GetLanguageOutputExtension(*sf);
+ if (counts[cmSystemTools::LowerCase(objectName)] > 1) {
+ const_cast<cmGeneratorTarget*>(gt)->AddExplicitObjectName(sf);
+ objectName = this->GetObjectFileNameWithoutTarget(*sf, dir_max);
+ }
+ si->second = objectName;
+ }
+}
+
+CM_AUTO_PTR<cmCustomCommand>
+cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmGeneratorTarget* target,
+ const std::string& config,
+ bool isFortran)
+{
+ CM_AUTO_PTR<cmCustomCommand> pcc;
+
+ // If an executable exports symbols then VS wants to create an
+ // import library but forgets to create the output directory.
+ // The Intel Fortran plugin always forgets to the directory.
+ if (target->GetType() != cmState::EXECUTABLE &&
+ !(isFortran && target->GetType() == cmState::SHARED_LIBRARY)) {
+ return pcc;
+ }
+ std::string outDir = target->GetDirectory(config, false);
+ std::string impDir = target->GetDirectory(config, true);
+ if (impDir == outDir) {
+ return pcc;
+ }
+
+ // Add a pre-build event to create the directory.
+ cmCustomCommandLine command;
+ command.push_back(cmSystemTools::GetCMakeCommand());
+ command.push_back("-E");
+ command.push_back("make_directory");
+ command.push_back(impDir);
+ std::vector<std::string> no_output;
+ std::vector<std::string> no_byproducts;
+ std::vector<std::string> no_depends;
+ cmCustomCommandLines commands;
+ commands.push_back(command);
+ pcc.reset(new cmCustomCommand(0, no_output, no_byproducts, no_depends,
+ commands, 0, 0));
+ pcc->SetEscapeOldStyle(false);
+ pcc->SetEscapeAllowMakeVars(true);
+ return pcc;
+}
+
+const char* cmLocalVisualStudioGenerator::ReportErrorLabel() const
+{
+ return ":VCReportError";
+}
+
+const char* cmLocalVisualStudioGenerator::GetReportErrorLabel() const
+{
+ return this->ReportErrorLabel();
+}
+
+std::string cmLocalVisualStudioGenerator::ConstructScript(
+ cmCustomCommandGenerator const& ccg, const std::string& newline_text)
+{
+ bool useLocal = this->CustomCommandUseLocal();
+ std::string workingDirectory = ccg.GetWorkingDirectory();
+ RelativeRoot relativeRoot = workingDirectory.empty() ? START_OUTPUT : NONE;
+
+ // Avoid leading or trailing newlines.
+ std::string newline = "";
+
+ // Line to check for error between commands.
+ std::string check_error = newline_text;
+ if (useLocal) {
+ check_error += "if %errorlevel% neq 0 goto :cmEnd";
+ } else {
+ check_error += "if errorlevel 1 goto ";
+ check_error += this->GetReportErrorLabel();
+ }
+
+ // Store the script in a string.
+ std::string script;
+
+ // Open a local context.
+ if (useLocal) {
+ script += newline;
+ newline = newline_text;
+ script += "setlocal";
+ }
+
+ if (!workingDirectory.empty()) {
+ // Change the working directory.
+ script += newline;
+ newline = newline_text;
+ script += "cd ";
+ script += this->Convert(workingDirectory, FULL, SHELL);
+ script += check_error;
+
+ // Change the working drive.
+ if (workingDirectory.size() > 1 && workingDirectory[1] == ':') {
+ script += newline;
+ newline = newline_text;
+ script += workingDirectory[0];
+ script += workingDirectory[1];
+ script += check_error;
+ }
+ }
+
+ // for visual studio IDE add extra stuff to the PATH
+ // if CMAKE_MSVCIDE_RUN_PATH is set.
+ if (this->Makefile->GetDefinition("MSVC_IDE")) {
+ const char* extraPath =
+ this->Makefile->GetDefinition("CMAKE_MSVCIDE_RUN_PATH");
+ if (extraPath) {
+ script += newline;
+ newline = newline_text;
+ script += "set PATH=";
+ script += extraPath;
+ script += ";%PATH%";
+ }
+ }
+
+ // Write each command on a single line.
+ for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
+ // Start a new line.
+ script += newline;
+ newline = newline_text;
+
+ // Add this command line.
+ std::string cmd = ccg.GetCommand(c);
+
+ // Use "call " before any invocations of .bat or .cmd files
+ // invoked as custom commands.
+ //
+ std::string suffix;
+ if (cmd.size() > 4) {
+ suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size() - 4));
+ if (suffix == ".bat" || suffix == ".cmd") {
+ script += "call ";
+ }
+ }
+
+ script += this->Convert(cmd.c_str(), relativeRoot, SHELL);
+ ccg.AppendArguments(c, script);
+
+ // After each custom command, check for an error result.
+ // If there was an error, jump to the VCReportError label,
+ // skipping the run of any subsequent commands in this
+ // sequence.
+ script += check_error;
+ }
+
+ // Close the local context.
+ if (useLocal) {
+ script += newline;
+ script += ":cmEnd";
+ script += newline;
+ script += "endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone";
+ script += newline;
+ script += ":cmErrorLevel";
+ script += newline;
+ script += "exit /b %1";
+ script += newline;
+ script += ":cmDone";
+ script += newline;
+ script += "if %errorlevel% neq 0 goto ";
+ script += this->GetReportErrorLabel();
+ }
+
+ return script;
+}
diff --git a/Source/cmLocalVisualStudioGenerator.h b/Source/cmLocalVisualStudioGenerator.h
new file mode 100644
index 0000000..87acda2
--- /dev/null
+++ b/Source/cmLocalVisualStudioGenerator.h
@@ -0,0 +1,67 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLocalVisualStudioGenerator_h
+#define cmLocalVisualStudioGenerator_h
+
+#include "cmLocalGenerator.h"
+
+#include "cmGlobalVisualStudioGenerator.h"
+
+#include <cm_auto_ptr.hxx>
+
+class cmSourceFile;
+class cmSourceGroup;
+class cmCustomCommand;
+class cmCustomCommandGenerator;
+
+/** \class cmLocalVisualStudioGenerator
+ * \brief Base class for Visual Studio generators.
+ *
+ * cmLocalVisualStudioGenerator provides functionality common to all
+ * Visual Studio generators.
+ */
+class cmLocalVisualStudioGenerator : public cmLocalGenerator
+{
+public:
+ cmLocalVisualStudioGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
+ virtual ~cmLocalVisualStudioGenerator();
+
+ /** Construct a script from the given list of command lines. */
+ std::string ConstructScript(cmCustomCommandGenerator const& ccg,
+ const std::string& newline = "\n");
+
+ /** Label to which to jump in a batch file after a failed step in a
+ sequence of custom commands. */
+ const char* GetReportErrorLabel() const;
+
+ cmGlobalVisualStudioGenerator::VSVersion GetVersion() const;
+
+ virtual std::string ComputeLongestObjectDirectory(
+ cmGeneratorTarget const*) const = 0;
+
+ virtual void AddCMakeListsRules() = 0;
+
+ virtual void ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* = 0);
+
+protected:
+ virtual const char* ReportErrorLabel() const;
+ virtual bool CustomCommandUseLocal() const { return false; }
+
+ /** Construct a custom command to make exe import lib dir. */
+ CM_AUTO_PTR<cmCustomCommand> MaybeCreateImplibDir(cmGeneratorTarget* target,
+ const std::string& config,
+ bool isFortran);
+};
+
+#endif
diff --git a/Source/cmLocalXCodeGenerator.cxx b/Source/cmLocalXCodeGenerator.cxx
new file mode 100644
index 0000000..db87946
--- /dev/null
+++ b/Source/cmLocalXCodeGenerator.cxx
@@ -0,0 +1,92 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmLocalXCodeGenerator.h"
+
+#include "cmGlobalXCodeGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+
+cmLocalXCodeGenerator::cmLocalXCodeGenerator(cmGlobalGenerator* gg,
+ cmMakefile* mf)
+ : cmLocalGenerator(gg, mf)
+{
+ // the global generator does this, so do not
+ // put these flags into the language flags
+ this->EmitUniversalBinaryFlags = false;
+}
+
+cmLocalXCodeGenerator::~cmLocalXCodeGenerator()
+{
+}
+
+std::string cmLocalXCodeGenerator::GetTargetDirectory(
+ cmGeneratorTarget const*) const
+{
+ // No per-target directory for this generator (yet).
+ return "";
+}
+
+void cmLocalXCodeGenerator::AppendFlagEscape(std::string& flags,
+ const std::string& rawFlag)
+{
+ cmGlobalXCodeGenerator* gg =
+ static_cast<cmGlobalXCodeGenerator*>(this->GlobalGenerator);
+ gg->AppendFlag(flags, rawFlag);
+}
+
+void cmLocalXCodeGenerator::Generate()
+{
+ cmLocalGenerator::Generate();
+
+ std::vector<cmGeneratorTarget*> targets = this->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator iter = targets.begin();
+ iter != targets.end(); ++iter) {
+ (*iter)->HasMacOSXRpathInstallNameDir("");
+ }
+}
+
+void cmLocalXCodeGenerator::GenerateInstallRules()
+{
+ cmLocalGenerator::GenerateInstallRules();
+
+ std::vector<cmGeneratorTarget*> targets = this->GetGeneratorTargets();
+ for (std::vector<cmGeneratorTarget*>::iterator iter = targets.begin();
+ iter != targets.end(); ++iter) {
+ (*iter)->HasMacOSXRpathInstallNameDir("");
+ }
+}
+
+void cmLocalXCodeGenerator::ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const*)
+{
+ // Count the number of object files with each name. Warn about duplicate
+ // names since Xcode names them uniquely automatically with a numeric suffix
+ // to avoid exact duplicate file names. Note that Mac file names are not
+ // typically case sensitive, hence the LowerCase.
+ std::map<std::string, int> counts;
+ for (std::map<cmSourceFile const*, std::string>::iterator si =
+ mapping.begin();
+ si != mapping.end(); ++si) {
+ cmSourceFile const* sf = si->first;
+ std::string objectName =
+ cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
+ objectName += ".o";
+
+ std::string objectNameLower = cmSystemTools::LowerCase(objectName);
+ counts[objectNameLower] += 1;
+ if (2 == counts[objectNameLower]) {
+ // TODO: emit warning about duplicate name?
+ }
+ si->second = objectName;
+ }
+}
diff --git a/Source/cmLocalXCodeGenerator.h b/Source/cmLocalXCodeGenerator.h
new file mode 100644
index 0000000..da3558e
--- /dev/null
+++ b/Source/cmLocalXCodeGenerator.h
@@ -0,0 +1,43 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLocalXCodeGenerator_h
+#define cmLocalXCodeGenerator_h
+
+#include "cmLocalGenerator.h"
+
+/** \class cmLocalXCodeGenerator
+ * \brief Write a local Xcode project
+ *
+ * cmLocalXCodeGenerator produces a LocalUnix makefile from its
+ * member Makefile.
+ */
+class cmLocalXCodeGenerator : public cmLocalGenerator
+{
+public:
+ ///! Set cache only and recurse to false by default.
+ cmLocalXCodeGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
+
+ virtual ~cmLocalXCodeGenerator();
+ virtual std::string GetTargetDirectory(
+ cmGeneratorTarget const* target) const;
+ virtual void AppendFlagEscape(std::string& flags,
+ const std::string& rawFlag);
+ virtual void Generate();
+ virtual void GenerateInstallRules();
+ virtual void ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt = 0);
+
+private:
+};
+
+#endif
diff --git a/Source/cmLocale.h b/Source/cmLocale.h
new file mode 100644
index 0000000..f922c03
--- /dev/null
+++ b/Source/cmLocale.h
@@ -0,0 +1,32 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmLocale_h
+#define cmLocale_h
+
+#include "cmStandardIncludes.h"
+
+#include <locale.h>
+
+class cmLocaleRAII
+{
+ const char* OldLocale;
+
+public:
+ cmLocaleRAII()
+ : OldLocale(setlocale(LC_CTYPE, CM_NULLPTR))
+ {
+ setlocale(LC_CTYPE, "");
+ }
+ ~cmLocaleRAII() { setlocale(LC_CTYPE, this->OldLocale); }
+};
+
+#endif
diff --git a/Source/cmMachO.cxx b/Source/cmMachO.cxx
new file mode 100644
index 0000000..314760e
--- /dev/null
+++ b/Source/cmMachO.cxx
@@ -0,0 +1,370 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmStandardIncludes.h" // to get CMAKE_USE_MACH_PARSER first
+
+#include "cmMachO.h"
+
+#include <cmsys/FStream.hxx>
+
+// Include the Mach-O format information system header.
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+
+/**
+
+ https://developer.apple.com/library/mac/documentation/
+ DeveloperTools/Conceptual/MachORuntime/index.html
+
+ A Mach-O file has 3 major regions: header, load commands and segments.
+ Data Structures are provided from <mach-o/loader.h> which
+ correspond to the file structure.
+
+ The header can be either a struct mach_header or struct mach_header_64.
+ One can peek at the first 4 bytes to identify the type of header.
+
+ Following is the load command region which starts with
+ struct load_command, and is followed by n number of load commands.
+
+ In the case of a universal binary (an archive of multiple Mach-O files),
+ the file begins with a struct fat_header and is followed by multiple
+ struct fat_arch instances. The struct fat_arch indicates the offset
+ for each Mach-O file.
+
+ */
+
+namespace {
+
+// peek in the file
+template <typename T>
+bool peek(cmsys::ifstream& fin, T& v)
+{
+ std::streampos p = fin.tellg();
+ if (!fin.read(reinterpret_cast<char*>(&v), sizeof(T))) {
+ return false;
+ }
+ fin.seekg(p);
+ return fin.good();
+}
+
+// read from the file and fill a data structure
+template <typename T>
+bool read(cmsys::ifstream& fin, T& v)
+{
+ if (!fin.read(reinterpret_cast<char*>(&v), sizeof(T))) {
+ return false;
+ }
+ return true;
+}
+
+// read from the file and fill multiple data structures where
+// the vector has been resized
+template <typename T>
+bool read(cmsys::ifstream& fin, std::vector<T>& v)
+{
+ // nothing to read
+ if (v.empty()) {
+ return true;
+ }
+ if (!fin.read(reinterpret_cast<char*>(&v[0]), sizeof(T) * v.size())) {
+ return false;
+ }
+ return true;
+}
+}
+
+// Contains header and load commands for a single Mach-O file
+class cmMachOHeaderAndLoadCommands
+{
+public:
+ // A load_command and its associated data
+ struct RawLoadCommand
+ {
+ uint32_t type(const cmMachOHeaderAndLoadCommands* m) const
+ {
+ if (this->LoadCommand.size() < sizeof(load_command)) {
+ return 0;
+ }
+ const load_command* cmd =
+ reinterpret_cast<const load_command*>(&this->LoadCommand[0]);
+ return m->swap(cmd->cmd);
+ }
+ std::vector<char> LoadCommand;
+ };
+
+ cmMachOHeaderAndLoadCommands(bool _swap)
+ : Swap(_swap)
+ {
+ }
+ virtual ~cmMachOHeaderAndLoadCommands() {}
+
+ virtual bool read_mach_o(cmsys::ifstream& fin) = 0;
+
+ const std::vector<RawLoadCommand>& load_commands() const
+ {
+ return this->LoadCommands;
+ }
+
+ uint32_t swap(uint32_t v) const
+ {
+ if (this->Swap) {
+ char* c = reinterpret_cast<char*>(&v);
+ std::swap(c[0], c[3]);
+ std::swap(c[1], c[2]);
+ }
+ return v;
+ }
+
+protected:
+ bool read_load_commands(uint32_t ncmds, uint32_t sizeofcmds,
+ cmsys::ifstream& fin);
+
+ bool Swap;
+ std::vector<RawLoadCommand> LoadCommands;
+};
+
+// Implementation for reading Mach-O header and load commands.
+// This is 32 or 64 bit arch specific.
+template <class T>
+class cmMachOHeaderAndLoadCommandsImpl : public cmMachOHeaderAndLoadCommands
+{
+public:
+ cmMachOHeaderAndLoadCommandsImpl(bool _swap)
+ : cmMachOHeaderAndLoadCommands(_swap)
+ {
+ }
+ bool read_mach_o(cmsys::ifstream& fin)
+ {
+ if (!read(fin, this->Header)) {
+ return false;
+ }
+ this->Header.cputype = swap(this->Header.cputype);
+ this->Header.cpusubtype = swap(this->Header.cpusubtype);
+ this->Header.filetype = swap(this->Header.filetype);
+ this->Header.ncmds = swap(this->Header.ncmds);
+ this->Header.sizeofcmds = swap(this->Header.sizeofcmds);
+ this->Header.flags = swap(this->Header.flags);
+
+ return read_load_commands(this->Header.ncmds, this->Header.sizeofcmds,
+ fin);
+ }
+
+protected:
+ T Header;
+};
+
+bool cmMachOHeaderAndLoadCommands::read_load_commands(uint32_t ncmds,
+ uint32_t sizeofcmds,
+ cmsys::ifstream& fin)
+{
+ uint32_t size_read = 0;
+ this->LoadCommands.resize(ncmds);
+ for (uint32_t i = 0; i < ncmds; i++) {
+ load_command lc;
+ if (!peek(fin, lc)) {
+ return false;
+ }
+ lc.cmd = swap(lc.cmd);
+ lc.cmdsize = swap(lc.cmdsize);
+ size_read += lc.cmdsize;
+
+ RawLoadCommand& c = this->LoadCommands[i];
+ c.LoadCommand.resize(lc.cmdsize);
+ if (!read(fin, c.LoadCommand)) {
+ return false;
+ }
+ }
+
+ if (size_read != sizeofcmds) {
+ this->LoadCommands.clear();
+ return false;
+ }
+
+ return true;
+}
+
+class cmMachOInternal
+{
+public:
+ cmMachOInternal(const char* fname);
+ ~cmMachOInternal();
+
+ // read a Mach-O file
+ bool read_mach_o(uint32_t file_offset);
+
+ // the file we are reading
+ cmsys::ifstream Fin;
+
+ // The archs in the universal binary
+ // If the binary is not a universal binary, this will be empty.
+ std::vector<fat_arch> FatArchs;
+
+ // the error message while parsing
+ std::string ErrorMessage;
+
+ // the list of Mach-O's
+ std::vector<cmMachOHeaderAndLoadCommands*> MachOList;
+};
+
+cmMachOInternal::cmMachOInternal(const char* fname)
+ : Fin(fname)
+{
+ // Quit now if the file could not be opened.
+ if (!this->Fin || !this->Fin.get()) {
+ this->ErrorMessage = "Error opening input file.";
+ return;
+ }
+
+ if (!this->Fin.seekg(0)) {
+ this->ErrorMessage = "Error seeking to beginning of file.";
+ return;
+ }
+
+ // Read the binary identification block.
+ uint32_t magic = 0;
+ if (!peek(this->Fin, magic)) {
+ this->ErrorMessage = "Error reading Mach-O identification.";
+ return;
+ }
+
+ // Verify the binary identification.
+ if (!(magic == MH_CIGAM || magic == MH_MAGIC || magic == MH_CIGAM_64 ||
+ magic == MH_MAGIC_64 || magic == FAT_CIGAM || magic == FAT_MAGIC)) {
+ this->ErrorMessage = "File does not have a valid Mach-O identification.";
+ return;
+ }
+
+ if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
+ // this is a universal binary
+ fat_header header;
+ if (!read(this->Fin, header)) {
+ this->ErrorMessage = "Error reading fat header.";
+ return;
+ }
+
+ // read fat_archs
+ this->FatArchs.resize(OSSwapBigToHostInt32(header.nfat_arch));
+ if (!read(this->Fin, this->FatArchs)) {
+ this->ErrorMessage = "Error reading fat header archs.";
+ return;
+ }
+
+ // parse each Mach-O file
+ for (size_t i = 0; i < this->FatArchs.size(); i++) {
+ const fat_arch& arch = this->FatArchs[i];
+ if (!this->read_mach_o(OSSwapBigToHostInt32(arch.offset))) {
+ return;
+ }
+ }
+ } else {
+ // parse Mach-O file at the beginning of the file
+ this->read_mach_o(0);
+ }
+}
+
+cmMachOInternal::~cmMachOInternal()
+{
+ for (size_t i = 0; i < this->MachOList.size(); i++) {
+ delete this->MachOList[i];
+ }
+}
+
+bool cmMachOInternal::read_mach_o(uint32_t file_offset)
+{
+ if (!this->Fin.seekg(file_offset)) {
+ this->ErrorMessage = "Failed to locate Mach-O content.";
+ return false;
+ }
+
+ uint32_t magic;
+ if (!peek(this->Fin, magic)) {
+ this->ErrorMessage = "Error reading Mach-O identification.";
+ return false;
+ }
+
+ cmMachOHeaderAndLoadCommands* f = NULL;
+ if (magic == MH_CIGAM || magic == MH_MAGIC) {
+ bool swap = false;
+ if (magic == MH_CIGAM) {
+ swap = true;
+ }
+ f = new cmMachOHeaderAndLoadCommandsImpl<mach_header>(swap);
+ } else if (magic == MH_CIGAM_64 || magic == MH_MAGIC_64) {
+ bool swap = false;
+ if (magic == MH_CIGAM_64) {
+ swap = true;
+ }
+ f = new cmMachOHeaderAndLoadCommandsImpl<mach_header_64>(swap);
+ }
+
+ if (f && f->read_mach_o(this->Fin)) {
+ this->MachOList.push_back(f);
+ } else {
+ delete f;
+ this->ErrorMessage = "Failed to read Mach-O header.";
+ return false;
+ }
+
+ return true;
+}
+
+//============================================================================
+// External class implementation.
+
+cmMachO::cmMachO(const char* fname)
+ : Internal(0)
+{
+ this->Internal = new cmMachOInternal(fname);
+}
+
+cmMachO::~cmMachO()
+{
+ delete this->Internal;
+}
+
+std::string const& cmMachO::GetErrorMessage() const
+{
+ return this->Internal->ErrorMessage;
+}
+
+bool cmMachO::Valid() const
+{
+ return !this->Internal->MachOList.empty();
+}
+
+bool cmMachO::GetInstallName(std::string& install_name)
+{
+ if (this->Internal->MachOList.empty()) {
+ return false;
+ }
+
+ // grab the first Mach-O and get the install name from that one
+ cmMachOHeaderAndLoadCommands* macho = this->Internal->MachOList[0];
+ for (size_t i = 0; i < macho->load_commands().size(); i++) {
+ const cmMachOHeaderAndLoadCommands::RawLoadCommand& cmd =
+ macho->load_commands()[i];
+ uint32_t lc_cmd = cmd.type(macho);
+ if (lc_cmd == LC_ID_DYLIB || lc_cmd == LC_LOAD_WEAK_DYLIB ||
+ lc_cmd == LC_LOAD_DYLIB) {
+ if (sizeof(dylib_command) < cmd.LoadCommand.size()) {
+ uint32_t namelen = cmd.LoadCommand.size() - sizeof(dylib_command);
+ install_name.assign(&cmd.LoadCommand[sizeof(dylib_command)], namelen);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void cmMachO::PrintInfo(std::ostream& /*os*/) const
+{
+}
diff --git a/Source/cmMachO.h b/Source/cmMachO.h
new file mode 100644
index 0000000..327c1ce
--- /dev/null
+++ b/Source/cmMachO.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmMachO_h
+#define cmMachO_h
+
+#if !defined(CMAKE_USE_MACH_PARSER)
+#error "This file may be included only if CMAKE_USE_MACH_PARSER is enabled."
+#endif
+
+class cmMachOInternal;
+
+/** \class cmMachO
+ * \brief Executable and Link Format (Mach-O) parser.
+ */
+class cmMachO
+{
+public:
+ /** Construct with the name of the Mach-O input file to parse. */
+ cmMachO(const char* fname);
+
+ /** Destruct. */
+ ~cmMachO();
+
+ /** Get the error message if any. */
+ std::string const& GetErrorMessage() const;
+
+ /** Boolean conversion. True if the Mach-O file is valid. */
+ operator bool() const { return this->Valid(); }
+
+ /** Get Install name from binary **/
+ bool GetInstallName(std::string& install_name);
+
+ /** Print human-readable information about the Mach-O file. */
+ void PrintInfo(std::ostream& os) const;
+
+private:
+ friend class cmMachOInternal;
+ bool Valid() const;
+ cmMachOInternal* Internal;
+};
+
+#endif
diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx
new file mode 100644
index 0000000..ee9dc8a
--- /dev/null
+++ b/Source/cmMacroCommand.cxx
@@ -0,0 +1,249 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmMacroCommand.h"
+
+#include "cmAlgorithms.h"
+#include "cmake.h"
+
+// define the class for macro commands
+class cmMacroHelperCommand : public cmCommand
+{
+public:
+ cmMacroHelperCommand() {}
+
+ ///! clean up any memory allocated by the macro
+ ~cmMacroHelperCommand() CM_OVERRIDE {}
+
+ /**
+ * This is used to avoid including this command
+ * in documentation. This is mainly used by
+ * cmMacroHelperCommand and cmFunctionHelperCommand
+ * which cannot provide appropriate documentation.
+ */
+ bool ShouldAppearInDocumentation() const CM_OVERRIDE { return false; }
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmMacroHelperCommand* newC = new cmMacroHelperCommand;
+ // we must copy when we clone
+ newC->Args = this->Args;
+ newC->Functions = this->Functions;
+ newC->FilePath = this->FilePath;
+ newC->Policies = this->Policies;
+ return newC;
+ }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InvokeInitialPass(const std::vector<cmListFileArgument>& args,
+ cmExecutionStatus&) CM_OVERRIDE;
+
+ bool InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&) CM_OVERRIDE
+ {
+ return false;
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return this->Args[0]; }
+
+ cmTypeMacro(cmMacroHelperCommand, cmCommand);
+
+ std::vector<std::string> Args;
+ std::vector<cmListFileFunction> Functions;
+ cmPolicies::PolicyMap Policies;
+ std::string FilePath;
+};
+
+bool cmMacroHelperCommand::InvokeInitialPass(
+ const std::vector<cmListFileArgument>& args, cmExecutionStatus& inStatus)
+{
+ // Expand the argument list to the macro.
+ std::vector<std::string> expandedArgs;
+ this->Makefile->ExpandArguments(args, expandedArgs);
+
+ // make sure the number of arguments passed is at least the number
+ // required by the signature
+ if (expandedArgs.size() < this->Args.size() - 1) {
+ std::string errorMsg =
+ "Macro invoked with incorrect arguments for macro named: ";
+ errorMsg += this->Args[0];
+ this->SetError(errorMsg);
+ return false;
+ }
+
+ cmMakefile::MacroPushPop macroScope(this->Makefile, this->FilePath,
+ this->Policies);
+
+ // set the value of argc
+ std::ostringstream argcDefStream;
+ argcDefStream << expandedArgs.size();
+ std::string argcDef = argcDefStream.str();
+
+ std::vector<std::string>::const_iterator eit =
+ expandedArgs.begin() + (this->Args.size() - 1);
+ std::string expandedArgn = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
+ std::string expandedArgv = cmJoin(expandedArgs, ";");
+ std::vector<std::string> variables;
+ variables.reserve(this->Args.size() - 1);
+ for (unsigned int j = 1; j < this->Args.size(); ++j) {
+ variables.push_back("${" + this->Args[j] + "}");
+ }
+ std::vector<std::string> argVs;
+ argVs.reserve(expandedArgs.size());
+ char argvName[60];
+ for (unsigned int j = 0; j < expandedArgs.size(); ++j) {
+ sprintf(argvName, "${ARGV%i}", j);
+ argVs.push_back(argvName);
+ }
+ // Invoke all the functions that were collected in the block.
+ cmListFileFunction newLFF;
+ // for each function
+ for (unsigned int c = 0; c < this->Functions.size(); ++c) {
+ // Replace the formal arguments and then invoke the command.
+ newLFF.Arguments.clear();
+ newLFF.Arguments.reserve(this->Functions[c].Arguments.size());
+ newLFF.Name = this->Functions[c].Name;
+ newLFF.Line = this->Functions[c].Line;
+
+ // for each argument of the current function
+ for (std::vector<cmListFileArgument>::iterator k =
+ this->Functions[c].Arguments.begin();
+ k != this->Functions[c].Arguments.end(); ++k) {
+ cmListFileArgument arg;
+ arg.Value = k->Value;
+ if (k->Delim != cmListFileArgument::Bracket) {
+ // replace formal arguments
+ for (unsigned int j = 0; j < variables.size(); ++j) {
+ cmSystemTools::ReplaceString(arg.Value, variables[j],
+ expandedArgs[j]);
+ }
+ // replace argc
+ cmSystemTools::ReplaceString(arg.Value, "${ARGC}", argcDef);
+
+ cmSystemTools::ReplaceString(arg.Value, "${ARGN}", expandedArgn);
+ cmSystemTools::ReplaceString(arg.Value, "${ARGV}", expandedArgv);
+
+ // if the current argument of the current function has ${ARGV in it
+ // then try replacing ARGV values
+ if (arg.Value.find("${ARGV") != std::string::npos) {
+ for (unsigned int t = 0; t < expandedArgs.size(); ++t) {
+ cmSystemTools::ReplaceString(arg.Value, argVs[t], expandedArgs[t]);
+ }
+ }
+ }
+ arg.Delim = k->Delim;
+ arg.Line = k->Line;
+ newLFF.Arguments.push_back(arg);
+ }
+ cmExecutionStatus status;
+ if (!this->Makefile->ExecuteCommand(newLFF, status) ||
+ status.GetNestedError()) {
+ // The error message should have already included the call stack
+ // so we do not need to report an error here.
+ macroScope.Quiet();
+ inStatus.SetNestedError(true);
+ return false;
+ }
+ if (status.GetReturnInvoked()) {
+ inStatus.SetReturnInvoked(true);
+ return true;
+ }
+ if (status.GetBreakInvoked()) {
+ inStatus.SetBreakInvoked(true);
+ return true;
+ }
+ }
+ return true;
+}
+
+bool cmMacroFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
+ cmMakefile& mf,
+ cmExecutionStatus&)
+{
+ // record commands until we hit the ENDMACRO
+ // at the ENDMACRO call we shift gears and start looking for invocations
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(), "macro")) {
+ this->Depth++;
+ } else if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endmacro")) {
+ // if this is the endmacro for this macro then execute
+ if (!this->Depth) {
+ mf.AppendProperty("MACROS", this->Args[0].c_str());
+ // create a new command and add it to cmake
+ cmMacroHelperCommand* f = new cmMacroHelperCommand();
+ f->Args = this->Args;
+ f->Functions = this->Functions;
+ f->FilePath = this->GetStartingContext().FilePath;
+ mf.RecordPolicies(f->Policies);
+ std::string newName = "_" + this->Args[0];
+ mf.GetState()->RenameCommand(this->Args[0], newName);
+ mf.GetState()->AddCommand(f);
+
+ // remove the function blocker now that the macro is defined
+ mf.RemoveFunctionBlocker(this, lff);
+ return true;
+ } else {
+ // decrement for each nested macro that ends
+ this->Depth--;
+ }
+ }
+
+ // if it wasn't an endmacro and we are not executing then we must be
+ // recording
+ this->Functions.push_back(lff);
+ return true;
+}
+
+bool cmMacroFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
+ cmMakefile& mf)
+{
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endmacro")) {
+ std::vector<std::string> expandedArguments;
+ mf.ExpandArguments(lff.Arguments, expandedArguments,
+ this->GetStartingContext().FilePath.c_str());
+ // if the endmacro has arguments make sure they
+ // match the arguments of the macro
+ if ((expandedArguments.empty() ||
+ (expandedArguments[0] == this->Args[0]))) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool cmMacroCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // create a function blocker
+ cmMacroFunctionBlocker* f = new cmMacroFunctionBlocker();
+ f->Args.insert(f->Args.end(), args.begin(), args.end());
+ this->Makefile->AddFunctionBlocker(f);
+ return true;
+}
diff --git a/Source/cmMacroCommand.h b/Source/cmMacroCommand.h
new file mode 100644
index 0000000..541b54f
--- /dev/null
+++ b/Source/cmMacroCommand.h
@@ -0,0 +1,62 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmMacroCommand_h
+#define cmMacroCommand_h
+
+#include "cmCommand.h"
+
+#include "cmFunctionBlocker.h"
+
+class cmMacroFunctionBlocker : public cmFunctionBlocker
+{
+public:
+ cmMacroFunctionBlocker() { this->Depth = 0; }
+ ~cmMacroFunctionBlocker() CM_OVERRIDE {}
+ bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf,
+ cmExecutionStatus&) CM_OVERRIDE;
+ bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) CM_OVERRIDE;
+
+ std::vector<std::string> Args;
+ std::vector<cmListFileFunction> Functions;
+ int Depth;
+};
+
+/// Starts macro() ... endmacro() block
+class cmMacroCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmMacroCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "macro"; }
+
+ cmTypeMacro(cmMacroCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmMakeDirectoryCommand.cxx b/Source/cmMakeDirectoryCommand.cxx
new file mode 100644
index 0000000..574dbf0
--- /dev/null
+++ b/Source/cmMakeDirectoryCommand.cxx
@@ -0,0 +1,31 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmMakeDirectoryCommand.h"
+
+// cmMakeDirectoryCommand
+bool cmMakeDirectoryCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() != 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ if (!this->Makefile->CanIWriteThisFile(args[0].c_str())) {
+ std::string e = "attempted to create a directory: " + args[0] +
+ " into a source directory.";
+ this->SetError(e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ cmSystemTools::MakeDirectory(args[0].c_str());
+ return true;
+}
diff --git a/Source/cmMakeDirectoryCommand.h b/Source/cmMakeDirectoryCommand.h
new file mode 100644
index 0000000..de4ab8b
--- /dev/null
+++ b/Source/cmMakeDirectoryCommand.h
@@ -0,0 +1,54 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmMakeDirectoryCommand_h
+#define cmMakeDirectoryCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmMakeDirectoryCommand
+ * \brief Specify auxiliary source code directories.
+ *
+ * cmMakeDirectoryCommand specifies source code directories
+ * that must be built as part of this build process. This directories
+ * are not recursively processed like the SUBDIR command (cmSubdirCommand).
+ * A side effect of this command is to create a subdirectory in the build
+ * directory structure.
+ */
+class cmMakeDirectoryCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmMakeDirectoryCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "make_directory"; }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ cmTypeMacro(cmMakeDirectoryCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
new file mode 100644
index 0000000..0d550dd
--- /dev/null
+++ b/Source/cmMakefile.cxx
@@ -0,0 +1,4539 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmMakefile.h"
+
+#include "cmCommand.h"
+#include "cmCommandArgumentParserHelper.h"
+#include "cmCommands.h"
+#include "cmFunctionBlocker.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionEvaluationFile.h"
+#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
+#include "cmOutputConverter.h"
+#include "cmSourceFile.h"
+#include "cmSourceFileLocation.h"
+#include "cmState.h"
+#include "cmSystemTools.h"
+#include "cmTest.h"
+#include "cmVersion.h"
+#ifdef CMAKE_BUILD_WITH_CMAKE
+#include "cmVariableWatch.h"
+#endif
+#include "cmAlgorithms.h"
+#include "cmInstallGenerator.h"
+#include "cmTestGenerator.h"
+#include "cmake.h"
+#include <stdlib.h> // required for atoi
+
+#include <cm_auto_ptr.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/RegularExpression.hxx>
+#include <cmsys/SystemTools.hxx>
+
+#include <assert.h>
+#include <ctype.h> // for isspace
+#include <list>
+
+// default is not to be building executables
+cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator,
+ cmState::Snapshot const& snapshot)
+ : GlobalGenerator(globalGenerator)
+ , StateSnapshot(snapshot)
+ , Backtrace(snapshot)
+{
+ this->IsSourceFileTryCompile = false;
+
+ this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused();
+ this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars();
+
+ this->SuppressWatches = false;
+
+ // Setup the default include complaint regular expression (match nothing).
+ this->ComplainFileRegularExpression = "^$";
+
+ this->DefineFlags = " ";
+
+ this->cmDefineRegex.compile("#cmakedefine[ \t]+([A-Za-z_0-9]*)");
+ this->cmDefine01Regex.compile("#cmakedefine01[ \t]+([A-Za-z_0-9]*)");
+ this->cmAtVarRegex.compile("(@[A-Za-z_0-9/.+-]+@)");
+ this->cmNamedCurly.compile("^[A-Za-z0-9/_.+-]+{");
+
+ this->StateSnapshot =
+ this->StateSnapshot.GetState()->CreatePolicyScopeSnapshot(
+ this->StateSnapshot);
+
+ // Enter a policy level for this directory.
+ this->PushPolicy();
+
+ // push empty loop block
+ this->PushLoopBlockBarrier();
+
+ // By default the check is not done. It is enabled by
+ // cmListFileCache in the top level if necessary.
+ this->CheckCMP0000 = false;
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ this->AddSourceGroup("", "^.*$");
+ this->AddSourceGroup("Source Files",
+ "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|f|f90|for|fpp"
+ "|ftn|m|mm|rc|def|r|odl|idl|hpj|bat)$");
+ this->AddSourceGroup("Header Files", CM_HEADER_REGEX);
+ this->AddSourceGroup("CMake Rules", "\\.rule$");
+ this->AddSourceGroup("Resources", "\\.plist$");
+ this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
+#endif
+}
+
+cmMakefile::~cmMakefile()
+{
+ cmDeleteAll(this->InstallGenerators);
+ cmDeleteAll(this->TestGenerators);
+ cmDeleteAll(this->SourceFiles);
+ cmDeleteAll(this->Tests);
+ cmDeleteAll(this->ImportedTargetsOwned);
+ cmDeleteAll(this->FinalPassCommands);
+ cmDeleteAll(this->FunctionBlockers);
+ cmDeleteAll(this->EvaluationFiles);
+}
+
+void cmMakefile::IssueMessage(cmake::MessageType t,
+ std::string const& text) const
+{
+ // Collect context information.
+ if (!this->ExecutionStatusStack.empty()) {
+ if ((t == cmake::FATAL_ERROR) || (t == cmake::INTERNAL_ERROR)) {
+ this->ExecutionStatusStack.back()->SetNestedError(true);
+ }
+ }
+ this->GetCMakeInstance()->IssueMessage(t, text, this->GetBacktrace());
+}
+
+cmStringRange cmMakefile::GetIncludeDirectoriesEntries() const
+{
+ return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries();
+}
+
+cmBacktraceRange cmMakefile::GetIncludeDirectoriesBacktraces() const
+{
+ return this->StateSnapshot.GetDirectory()
+ .GetIncludeDirectoriesEntryBacktraces();
+}
+
+cmStringRange cmMakefile::GetCompileOptionsEntries() const
+{
+ return this->StateSnapshot.GetDirectory().GetCompileOptionsEntries();
+}
+
+cmBacktraceRange cmMakefile::GetCompileOptionsBacktraces() const
+{
+ return this->StateSnapshot.GetDirectory().GetCompileOptionsEntryBacktraces();
+}
+
+cmStringRange cmMakefile::GetCompileDefinitionsEntries() const
+{
+ return this->StateSnapshot.GetDirectory().GetCompileDefinitionsEntries();
+}
+
+cmBacktraceRange cmMakefile::GetCompileDefinitionsBacktraces() const
+{
+ return this->StateSnapshot.GetDirectory()
+ .GetCompileDefinitionsEntryBacktraces();
+}
+
+cmListFileBacktrace cmMakefile::GetBacktrace() const
+{
+ return this->Backtrace;
+}
+
+cmListFileBacktrace cmMakefile::GetBacktrace(cmCommandContext const& cc) const
+{
+ cmListFileContext lfc;
+ lfc.Name = cc.Name;
+ lfc.Line = cc.Line;
+ lfc.FilePath = this->StateSnapshot.GetExecutionListFile();
+ return this->Backtrace.Push(lfc);
+}
+
+cmListFileContext cmMakefile::GetExecutionContext() const
+{
+ cmListFileContext const& cur = this->Backtrace.Top();
+ cmListFileContext lfc;
+ lfc.Name = cur.Name;
+ lfc.Line = cur.Line;
+ lfc.FilePath = this->StateSnapshot.GetExecutionListFile();
+ return lfc;
+}
+
+void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const
+{
+ // Check if current file in the list of requested to trace...
+ std::vector<std::string> const& trace_only_this_files =
+ this->GetCMakeInstance()->GetTraceSources();
+ std::string const& full_path = this->GetExecutionFilePath();
+ 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);
+ trace = (pos != std::string::npos) &&
+ ((pos + i->size()) == full_path.size()) &&
+ (only_filename == cmSystemTools::GetFilenameName(*i));
+ }
+ // Do nothing if current file wasn't requested for trace...
+ if (!trace) {
+ return;
+ }
+ }
+
+ std::ostringstream msg;
+ msg << full_path << "(" << lff.Line << "): ";
+ msg << lff.Name << "(";
+ bool expand = this->GetCMakeInstance()->GetTraceExpand();
+ std::string temp;
+ for (std::vector<cmListFileArgument>::const_iterator i =
+ lff.Arguments.begin();
+ i != lff.Arguments.end(); ++i) {
+ if (expand) {
+ temp = i->Value;
+ this->ExpandVariablesInString(temp);
+ msg << temp;
+ } else {
+ msg << i->Value;
+ }
+ msg << " ";
+ }
+ msg << ")";
+ cmSystemTools::Message(msg.str().c_str());
+}
+
+// Helper class to make sure the call stack is valid.
+class cmMakefileCall
+{
+public:
+ cmMakefileCall(cmMakefile* mf, cmCommandContext const& cc,
+ cmExecutionStatus& status)
+ : Makefile(mf)
+ {
+ cmListFileContext const& lfc = cmListFileContext::FromCommandContext(
+ cc, this->Makefile->StateSnapshot.GetExecutionListFile());
+ this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc);
+ this->Makefile->ExecutionStatusStack.push_back(&status);
+ }
+
+ ~cmMakefileCall()
+ {
+ this->Makefile->ExecutionStatusStack.pop_back();
+ this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
+ }
+
+private:
+ cmMakefile* Makefile;
+};
+
+bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
+ cmExecutionStatus& status)
+{
+ bool result = true;
+
+ // quick return if blocked
+ if (this->IsFunctionBlocked(lff, status)) {
+ // No error.
+ return result;
+ }
+
+ std::string name = lff.Name;
+
+ // Place this call on the call stack.
+ cmMakefileCall stack_manager(this, lff, status);
+ static_cast<void>(stack_manager);
+
+ // Lookup the command prototype.
+ if (cmCommand* proto = this->GetState()->GetCommand(name)) {
+ // Clone the prototype.
+ CM_AUTO_PTR<cmCommand> pcmd(proto->Clone());
+ pcmd->SetMakefile(this);
+
+ // Decide whether to invoke the command.
+ if (pcmd->GetEnabled() && !cmSystemTools::GetFatalErrorOccured() &&
+ (this->GetCMakeInstance()->GetWorkingMode() != cmake::SCRIPT_MODE ||
+ pcmd->IsScriptable()))
+
+ {
+ // if trace is enabled, print out invoke information
+ if (this->GetCMakeInstance()->GetTrace()) {
+ this->PrintCommandTrace(lff);
+ }
+ // Try invoking the command.
+ bool invokeSucceeded = pcmd->InvokeInitialPass(lff.Arguments, status);
+ bool hadNestedError = status.GetNestedError();
+ if (!invokeSucceeded || hadNestedError) {
+ if (!hadNestedError) {
+ // The command invocation requested that we report an error.
+ this->IssueMessage(cmake::FATAL_ERROR, pcmd->GetError());
+ }
+ result = false;
+ if (this->GetCMakeInstance()->GetWorkingMode() != cmake::NORMAL_MODE) {
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ } else if (pcmd->HasFinalPass()) {
+ // use the command
+ this->FinalPassCommands.push_back(pcmd.release());
+ }
+ } else if (this->GetCMakeInstance()->GetWorkingMode() ==
+ cmake::SCRIPT_MODE &&
+ !pcmd->IsScriptable()) {
+ std::string error = "Command ";
+ error += pcmd->GetName();
+ error += "() is not scriptable";
+ this->IssueMessage(cmake::FATAL_ERROR, error);
+ result = false;
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ } else {
+ if (!cmSystemTools::GetFatalErrorOccured()) {
+ std::string error = "Unknown CMake command \"";
+ error += lff.Name;
+ error += "\".";
+ this->IssueMessage(cmake::FATAL_ERROR, error);
+ result = false;
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ }
+
+ return result;
+}
+
+class cmMakefile::IncludeScope
+{
+public:
+ IncludeScope(cmMakefile* mf, std::string const& filenametoread,
+ bool noPolicyScope);
+ ~IncludeScope();
+ void Quiet() { this->ReportError = false; }
+private:
+ cmMakefile* Makefile;
+ bool NoPolicyScope;
+ bool CheckCMP0011;
+ bool ReportError;
+ void EnforceCMP0011();
+};
+
+cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf,
+ std::string const& filenametoread,
+ bool noPolicyScope)
+ : Makefile(mf)
+ , NoPolicyScope(noPolicyScope)
+ , CheckCMP0011(false)
+ , ReportError(true)
+{
+ this->Makefile->Backtrace = this->Makefile->Backtrace.Push(filenametoread);
+
+ this->Makefile->PushFunctionBlockerBarrier();
+
+ this->Makefile->StateSnapshot =
+ this->Makefile->GetState()->CreateIncludeFileSnapshot(
+ this->Makefile->StateSnapshot, filenametoread);
+ if (!this->NoPolicyScope) {
+ // Check CMP0011 to determine the policy scope type.
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011)) {
+ case cmPolicies::WARN:
+ // We need to push a scope to detect whether the script sets
+ // any policies that would affect the includer and therefore
+ // requires a warning. We use a weak scope to simulate OLD
+ // behavior by allowing policy changes to affect the includer.
+ this->Makefile->PushPolicy(true);
+ this->CheckCMP0011 = true;
+ break;
+ case cmPolicies::OLD:
+ // OLD behavior is to not push a scope at all.
+ this->NoPolicyScope = true;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ // We should never make this policy required, but we handle it
+ // here just in case.
+ this->CheckCMP0011 = true;
+ case cmPolicies::NEW:
+ // NEW behavior is to push a (strong) scope.
+ this->Makefile->PushPolicy();
+ break;
+ }
+ }
+}
+
+cmMakefile::IncludeScope::~IncludeScope()
+{
+ if (!this->NoPolicyScope) {
+ // If we need to enforce policy CMP0011 then the top entry is the
+ // one we pushed above. If the entry is empty, then the included
+ // script did not set any policies that might affect the includer so
+ // we do not need to enforce the policy.
+ if (this->CheckCMP0011 &&
+ !this->Makefile->StateSnapshot.HasDefinedPolicyCMP0011()) {
+ this->CheckCMP0011 = false;
+ }
+
+ // Pop the scope we pushed for the script.
+ this->Makefile->PopPolicy();
+
+ // We enforce the policy after the script's policy stack entry has
+ // been removed.
+ if (this->CheckCMP0011) {
+ this->EnforceCMP0011();
+ }
+ }
+ this->Makefile->PopSnapshot(this->ReportError);
+
+ this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
+
+ this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
+}
+
+void cmMakefile::IncludeScope::EnforceCMP0011()
+{
+ // We check the setting of this policy again because the included
+ // script might actually set this policy for its includer.
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011)) {
+ case cmPolicies::WARN:
+ // Warn because the user did not set this policy.
+ {
+ std::ostringstream w;
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0011) << "\n"
+ << "The included script\n "
+ << this->Makefile->GetExecutionFilePath() << "\n"
+ << "affects policy settings. "
+ << "CMake is implying the NO_POLICY_SCOPE option for compatibility, "
+ << "so the effects are applied to the including context.";
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ }
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS: {
+ std::ostringstream e;
+ /* clang-format off */
+ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0011) << "\n"
+ << "The included script\n "
+ << this->Makefile->GetExecutionFilePath() << "\n"
+ << "affects policy settings, so it requires this policy to be set.";
+ /* clang-format on */
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ } break;
+ case cmPolicies::OLD:
+ case cmPolicies::NEW:
+ // The script set this policy. We assume the purpose of the
+ // script is to initialize policies for its includer, and since
+ // the policy is now set for later scripts, we do not warn.
+ break;
+ }
+}
+
+bool cmMakefile::ReadDependentFile(const char* filename, bool noPolicyScope)
+{
+ this->AddDefinition("CMAKE_PARENT_LIST_FILE",
+ this->GetDefinition("CMAKE_CURRENT_LIST_FILE"));
+ std::string filenametoread = cmSystemTools::CollapseFullPath(
+ filename, this->GetCurrentSourceDirectory());
+
+ IncludeScope incScope(this, filenametoread, noPolicyScope);
+
+ cmListFile listFile;
+ if (!listFile.ParseFile(filenametoread.c_str(), this)) {
+ return false;
+ }
+
+ this->ReadListFile(listFile, filenametoread);
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ incScope.Quiet();
+ }
+ return true;
+}
+
+class cmMakefile::ListFileScope
+{
+public:
+ ListFileScope(cmMakefile* mf, std::string const& filenametoread)
+ : Makefile(mf)
+ , ReportError(true)
+ {
+ this->Makefile->Backtrace = this->Makefile->Backtrace.Push(filenametoread);
+
+ this->Makefile->StateSnapshot =
+ this->Makefile->GetState()->CreateInlineListFileSnapshot(
+ this->Makefile->StateSnapshot, filenametoread);
+ assert(this->Makefile->StateSnapshot.IsValid());
+
+ this->Makefile->PushFunctionBlockerBarrier();
+ }
+
+ ~ListFileScope()
+ {
+ this->Makefile->PopSnapshot(this->ReportError);
+ this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
+ this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
+ }
+
+ void Quiet() { this->ReportError = false; }
+private:
+ cmMakefile* Makefile;
+ bool ReportError;
+};
+
+bool cmMakefile::ReadListFile(const char* filename)
+{
+ std::string filenametoread = cmSystemTools::CollapseFullPath(
+ filename, this->GetCurrentSourceDirectory());
+
+ ListFileScope scope(this, filenametoread);
+
+ cmListFile listFile;
+ if (!listFile.ParseFile(filenametoread.c_str(), this)) {
+ return false;
+ }
+
+ this->ReadListFile(listFile, filenametoread);
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ scope.Quiet();
+ }
+ return true;
+}
+
+void cmMakefile::ReadListFile(cmListFile const& listFile,
+ std::string const& filenametoread)
+{
+ // add this list file to the list of dependencies
+ this->ListFiles.push_back(filenametoread);
+
+ std::string currentParentFile =
+ this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE");
+ std::string currentFile = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE");
+
+ this->AddDefinition("CMAKE_CURRENT_LIST_FILE", filenametoread.c_str());
+ this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
+ cmSystemTools::GetFilenamePath(filenametoread).c_str());
+
+ this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
+ this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
+ this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");
+
+ // Run the parsed commands.
+ const size_t numberFunctions = listFile.Functions.size();
+ for (size_t i = 0; i < numberFunctions; ++i) {
+ cmExecutionStatus status;
+ this->ExecuteCommand(listFile.Functions[i], status);
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ break;
+ }
+ if (status.GetReturnInvoked()) {
+ // Exit early due to return command.
+ break;
+ }
+ }
+ this->CheckForUnusedVariables();
+
+ this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile.c_str());
+ this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile.c_str());
+ this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
+ cmSystemTools::GetFilenamePath(currentFile).c_str());
+ this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
+ this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
+ this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");
+}
+
+void cmMakefile::EnforceDirectoryLevelRules() const
+{
+ // Diagnose a violation of CMP0000 if necessary.
+ if (this->CheckCMP0000) {
+ std::ostringstream msg;
+ msg << "No cmake_minimum_required command is present. "
+ << "A line of code such as\n"
+ << " cmake_minimum_required(VERSION " << cmVersion::GetMajorVersion()
+ << "." << cmVersion::GetMinorVersion() << ")\n"
+ << "should be added at the top of the file. "
+ << "The version specified may be lower if you wish to "
+ << "support older CMake versions for this project. "
+ << "For more information run "
+ << "\"cmake --help-policy CMP0000\".";
+ switch (this->GetPolicyStatus(cmPolicies::CMP0000)) {
+ case cmPolicies::WARN:
+ // Warn because the user did not provide a mimimum required
+ // version.
+ this->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING,
+ msg.str(), this->Backtrace);
+ case cmPolicies::OLD:
+ // OLD behavior is to use policy version 2.4 set in
+ // cmListFileCache.
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // NEW behavior is to issue an error.
+ this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, msg.str(),
+ this->Backtrace);
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+ }
+}
+
+void cmMakefile::AddEvaluationFile(
+ const std::string& inputFile,
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> outputName,
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> condition, bool inputIsContent)
+{
+ this->EvaluationFiles.push_back(new cmGeneratorExpressionEvaluationFile(
+ inputFile, outputName, condition, inputIsContent));
+}
+
+std::vector<cmGeneratorExpressionEvaluationFile*>
+cmMakefile::GetEvaluationFiles() const
+{
+ return this->EvaluationFiles;
+}
+
+std::vector<cmExportBuildFileGenerator*>
+cmMakefile::GetExportBuildFileGenerators() const
+{
+ return this->ExportBuildFileGenerators;
+}
+
+void cmMakefile::RemoveExportBuildFileGeneratorCMP0024(
+ cmExportBuildFileGenerator* gen)
+{
+ std::vector<cmExportBuildFileGenerator*>::iterator it =
+ std::find(this->ExportBuildFileGenerators.begin(),
+ this->ExportBuildFileGenerators.end(), gen);
+ if (it != this->ExportBuildFileGenerators.end()) {
+ this->ExportBuildFileGenerators.erase(it);
+ }
+}
+
+void cmMakefile::AddExportBuildFileGenerator(cmExportBuildFileGenerator* gen)
+{
+ this->ExportBuildFileGenerators.push_back(gen);
+}
+
+namespace {
+struct file_not_persistent
+{
+ bool operator()(const std::string& path) const
+ {
+ return !(path.find("CMakeTmp") == path.npos &&
+ cmSystemTools::FileExists(path.c_str()));
+ }
+};
+}
+
+void cmMakefile::FinalPass()
+{
+ // do all the variable expansions here
+ this->ExpandVariablesCMP0019();
+
+ // give all the commands a chance to do something
+ // after the file has been parsed before generation
+ for (std::vector<cmCommand*>::iterator i = this->FinalPassCommands.begin();
+ i != this->FinalPassCommands.end(); ++i) {
+ (*i)->FinalPass();
+ }
+
+ // go through all configured files and see which ones still exist.
+ // we don't want cmake to re-run if a configured file is created and deleted
+ // during processing as that would make it a transient file that can't
+ // influence the build process
+
+ // remove_if will move all items that don't have a valid file name to the
+ // back of the vector
+ std::vector<std::string>::iterator new_output_files_end = std::remove_if(
+ this->OutputFiles.begin(), this->OutputFiles.end(), file_not_persistent());
+ // we just have to erase all items at the back
+ this->OutputFiles.erase(new_output_files_end, this->OutputFiles.end());
+
+ // if a configured file is used as input for another configured file,
+ // and then deleted it will show up in the input list files so we
+ // need to scan those too
+ std::vector<std::string>::iterator new_list_files_end = std::remove_if(
+ this->ListFiles.begin(), this->ListFiles.end(), file_not_persistent());
+
+ this->ListFiles.erase(new_list_files_end, this->ListFiles.end());
+}
+
+// Generate the output file
+void cmMakefile::ConfigureFinalPass()
+{
+ this->FinalPass();
+ const char* oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
+ if (oldValue &&
+ cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, oldValue, "2.4")) {
+ this->GetCMakeInstance()->IssueMessage(
+ cmake::FATAL_ERROR,
+ "You have set CMAKE_BACKWARDS_COMPATIBILITY to a CMake version less "
+ "than 2.4. This version of CMake only supports backwards compatibility "
+ "with CMake 2.4 or later. For compatibility with older versions please "
+ "use any CMake 2.8.x release or lower.",
+ this->Backtrace);
+ }
+}
+
+void cmMakefile::AddCustomCommandToTarget(
+ const std::string& target, const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type,
+ const char* comment, const char* workingDir, bool escapeOldStyle,
+ bool uses_terminal)
+{
+ // Find the target to which to add the custom command.
+ cmTargets::iterator ti = this->Targets.find(target);
+
+ if (ti == this->Targets.end()) {
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ bool issueMessage = false;
+ std::ostringstream e;
+ switch (this->GetPolicyStatus(cmPolicies::CMP0040)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0040) << "\n";
+ issueMessage = true;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ issueMessage = true;
+ messageType = cmake::FATAL_ERROR;
+ }
+
+ if (issueMessage) {
+ if (cmTarget const* t = this->FindTargetToUse(target)) {
+ if (t->IsImported()) {
+ e << "TARGET '" << target
+ << "' is IMPORTED and does not build here.";
+ } else {
+ e << "TARGET '" << target << "' was not created in this directory.";
+ }
+ } else {
+ e << "No TARGET '" << target
+ << "' has been created in this directory.";
+ }
+ IssueMessage(messageType, e.str());
+ }
+
+ return;
+ }
+
+ if (ti->second.GetType() == cmState::OBJECT_LIBRARY) {
+ std::ostringstream e;
+ e << "Target \"" << target
+ << "\" is an OBJECT library "
+ "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ if (ti->second.GetType() == cmState::INTERFACE_LIBRARY) {
+ std::ostringstream e;
+ e << "Target \"" << target
+ << "\" is an INTERFACE library "
+ "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+
+ // Always create the byproduct sources and mark them generated.
+ for (std::vector<std::string>::const_iterator o = byproducts.begin();
+ o != byproducts.end(); ++o) {
+ if (cmSourceFile* out = this->GetOrCreateSource(*o, true)) {
+ out->SetProperty("GENERATED", "1");
+ }
+ }
+
+ // Add the command to the appropriate build step for the target.
+ std::vector<std::string> no_output;
+ cmCustomCommand cc(this, no_output, byproducts, depends, commandLines,
+ comment, workingDir);
+ cc.SetEscapeOldStyle(escapeOldStyle);
+ cc.SetEscapeAllowMakeVars(true);
+ cc.SetUsesTerminal(uses_terminal);
+ switch (type) {
+ case cmTarget::PRE_BUILD:
+ ti->second.AddPreBuildCommand(cc);
+ break;
+ case cmTarget::PRE_LINK:
+ ti->second.AddPreLinkCommand(cc);
+ break;
+ case cmTarget::POST_BUILD:
+ ti->second.AddPostBuildCommand(cc);
+ break;
+ }
+}
+
+cmSourceFile* cmMakefile::AddCustomCommandToOutput(
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ 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)
+{
+ // Make sure there is at least one output.
+ if (outputs.empty()) {
+ cmSystemTools::Error("Attempt to add a custom rule with no output!");
+ return CM_NULLPTR;
+ }
+
+ // Validate custom commands. TODO: More strict?
+ for (cmCustomCommandLines::const_iterator i = commandLines.begin();
+ i != commandLines.end(); ++i) {
+ cmCustomCommandLine const& cl = *i;
+ if (!cl.empty() && !cl[0].empty() && cl[0][0] == '"') {
+ std::ostringstream e;
+ e << "COMMAND may not contain literal quotes:\n " << cl[0] << "\n";
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return CM_NULLPTR;
+ }
+ }
+
+ // Choose a source file on which to store the custom command.
+ cmSourceFile* file = CM_NULLPTR;
+ if (!commandLines.empty() && !main_dependency.empty()) {
+ // The main dependency was specified. Use it unless a different
+ // custom command already used it.
+ file = this->GetSource(main_dependency);
+ if (file && file->GetCustomCommand() && !replace) {
+ // The main dependency already has a custom command.
+ if (commandLines == file->GetCustomCommand()->GetCommandLines()) {
+ // The existing custom command is identical. Silently ignore
+ // the duplicate.
+ return file;
+ } else {
+ // The existing custom command is different. We need to
+ // generate a rule file for this new command.
+ file = CM_NULLPTR;
+ }
+ } else if (!file) {
+ file = this->CreateSource(main_dependency);
+ }
+ }
+
+ // Generate a rule file if the main dependency is not available.
+ if (!file) {
+ cmGlobalGenerator* gg = this->GetGlobalGenerator();
+
+ // Construct a rule file associated with the first output produced.
+ std::string outName = gg->GenerateRuleFile(outputs[0]);
+
+ // Check if the rule file already exists.
+ file = this->GetSource(outName);
+ 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.");
+ }
+ return file;
+ }
+
+ // Create a cmSourceFile for the rule file.
+ if (!file) {
+ file = this->CreateSource(outName, true);
+ }
+ file->SetProperty("__CMAKE_RULE", "1");
+ }
+
+ // Always create the output sources and mark them generated.
+ for (std::vector<std::string>::const_iterator o = outputs.begin();
+ o != outputs.end(); ++o) {
+ if (cmSourceFile* out = this->GetOrCreateSource(*o, true)) {
+ out->SetProperty("GENERATED", "1");
+ }
+ }
+ for (std::vector<std::string>::const_iterator o = byproducts.begin();
+ o != byproducts.end(); ++o) {
+ if (cmSourceFile* out = this->GetOrCreateSource(*o, true)) {
+ out->SetProperty("GENERATED", "1");
+ }
+ }
+
+ // Attach the custom command to the file.
+ if (file) {
+ // Construct a complete list of dependencies.
+ std::vector<std::string> depends2(depends);
+ if (!main_dependency.empty()) {
+ depends2.push_back(main_dependency);
+ }
+
+ cmCustomCommand* cc = new cmCustomCommand(
+ this, outputs, byproducts, depends2, commandLines, comment, workingDir);
+ cc->SetEscapeOldStyle(escapeOldStyle);
+ cc->SetEscapeAllowMakeVars(true);
+ cc->SetUsesTerminal(uses_terminal);
+ file->SetCustomCommand(cc);
+ this->UpdateOutputToSourceMap(outputs, file);
+ }
+ return file;
+}
+
+void cmMakefile::UpdateOutputToSourceMap(
+ std::vector<std::string> const& outputs, cmSourceFile* source)
+{
+ for (std::vector<std::string>::const_iterator o = outputs.begin();
+ o != outputs.end(); ++o) {
+ this->UpdateOutputToSourceMap(*o, source);
+ }
+}
+
+void cmMakefile::UpdateOutputToSourceMap(std::string const& output,
+ cmSourceFile* source)
+{
+ OutputToSourceMap::iterator i = this->OutputToSource.find(output);
+ if (i != this->OutputToSource.end()) {
+ // Multiple custom commands produce the same output but may
+ // be attached to a different source file (MAIN_DEPENDENCY).
+ // LinearGetSourceFileWithOutput would return the first one,
+ // so keep the mapping for the first one.
+ //
+ // TODO: Warn the user about this case. However, the VS 8 generator
+ // triggers it for separate generate.stamp rules in ZERO_CHECK and
+ // individual targets.
+ return;
+ }
+ this->OutputToSource[output] = source;
+}
+
+cmSourceFile* cmMakefile::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,
+ bool escapeOldStyle, bool uses_terminal)
+{
+ std::vector<std::string> outputs;
+ outputs.push_back(output);
+ std::vector<std::string> no_byproducts;
+ return this->AddCustomCommandToOutput(
+ outputs, no_byproducts, depends, main_dependency, commandLines, comment,
+ workingDir, replace, escapeOldStyle, uses_terminal);
+}
+
+void cmMakefile::AddCustomCommandOldStyle(
+ const std::string& target, const std::vector<std::string>& outputs,
+ const std::vector<std::string>& depends, const std::string& source,
+ const cmCustomCommandLines& commandLines, const char* comment)
+{
+ // Translate the old-style signature to one of the new-style
+ // signatures.
+ if (source == target) {
+ // In the old-style signature if the source and target were the
+ // same then it added a post-build rule to the target. Preserve
+ // this behavior.
+ std::vector<std::string> no_byproducts;
+ this->AddCustomCommandToTarget(target, no_byproducts, depends,
+ commandLines, cmTarget::POST_BUILD, comment,
+ CM_NULLPTR);
+ return;
+ }
+
+ // Each output must get its own copy of this rule.
+ cmsys::RegularExpression sourceFiles("\\.(C|M|c|c\\+\\+|cc|cpp|cxx|m|mm|"
+ "rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|"
+ "hm|hpp|hxx|in|txx|inl)$");
+ for (std::vector<std::string>::const_iterator oi = outputs.begin();
+ oi != outputs.end(); ++oi) {
+ // Get the name of this output.
+ const char* output = oi->c_str();
+ cmSourceFile* sf;
+
+ // Choose whether to use a main dependency.
+ if (sourceFiles.find(source)) {
+ // The source looks like a real file. Use it as the main dependency.
+ sf = this->AddCustomCommandToOutput(output, depends, source,
+ commandLines, comment, CM_NULLPTR);
+ } else {
+ // The source may not be a real file. Do not use a main dependency.
+ std::string no_main_dependency = "";
+ std::vector<std::string> depends2 = depends;
+ depends2.push_back(source);
+ sf = this->AddCustomCommandToOutput(output, depends2, no_main_dependency,
+ commandLines, comment, CM_NULLPTR);
+ }
+
+ // If the rule was added to the source (and not a .rule file),
+ // then add the source to the target to make sure the rule is
+ // included.
+ if (sf && !sf->GetPropertyAsBool("__CMAKE_RULE")) {
+ if (this->Targets.find(target) != this->Targets.end()) {
+ this->Targets[target].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());
+ return;
+ }
+ }
+ }
+}
+
+cmTarget* cmMakefile::AddUtilityCommand(
+ const std::string& utilityName, bool excludeFromAll,
+ const std::vector<std::string>& depends, const char* workingDirectory,
+ const char* command, const char* arg1, const char* arg2, const char* arg3,
+ const char* arg4)
+{
+ // Construct the command line for the custom command.
+ cmCustomCommandLine commandLine;
+ commandLine.push_back(command);
+ if (arg1) {
+ commandLine.push_back(arg1);
+ }
+ if (arg2) {
+ commandLine.push_back(arg2);
+ }
+ if (arg3) {
+ commandLine.push_back(arg3);
+ }
+ if (arg4) {
+ commandLine.push_back(arg4);
+ }
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(commandLine);
+
+ // Call the real signature of this method.
+ return this->AddUtilityCommand(utilityName, excludeFromAll, workingDirectory,
+ depends, commandLines);
+}
+
+cmTarget* cmMakefile::AddUtilityCommand(
+ const std::string& utilityName, bool excludeFromAll,
+ const char* workingDirectory, const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, bool escapeOldStyle,
+ const char* comment, bool uses_terminal)
+{
+ std::vector<std::string> no_byproducts;
+ return this->AddUtilityCommand(utilityName, excludeFromAll, workingDirectory,
+ no_byproducts, depends, commandLines,
+ escapeOldStyle, comment, uses_terminal);
+}
+
+cmTarget* cmMakefile::AddUtilityCommand(
+ const std::string& utilityName, bool excludeFromAll,
+ 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)
+{
+ // Create a target instance for this utility.
+ cmTarget* target = this->AddNewTarget(cmState::UTILITY, utilityName);
+ if (excludeFromAll) {
+ target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
+ }
+ if (!comment) {
+ // Use an empty comment to avoid generation of default comment.
+ comment = "";
+ }
+
+ // Store the custom command in the target.
+ if (!commandLines.empty() || !depends.empty()) {
+ std::string force = this->GetCurrentBinaryDirectory();
+ force += cmake::GetCMakeFilesDirectory();
+ force += "/";
+ force += utilityName;
+ std::vector<std::string> forced;
+ forced.push_back(force);
+ std::string no_main_dependency = "";
+ bool no_replace = false;
+ this->AddCustomCommandToOutput(
+ forced, byproducts, depends, no_main_dependency, commandLines, comment,
+ workingDirectory, no_replace, escapeOldStyle, uses_terminal);
+ 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());
+ }
+
+ // Always create the byproduct sources and mark them generated.
+ for (std::vector<std::string>::const_iterator o = byproducts.begin();
+ o != byproducts.end(); ++o) {
+ if (cmSourceFile* out = this->GetOrCreateSource(*o, true)) {
+ out->SetProperty("GENERATED", "1");
+ }
+ }
+ }
+ return target;
+}
+
+void cmMakefile::AddDefineFlag(const char* flag)
+{
+ if (!flag) {
+ return;
+ }
+
+ // Update the string used for the old DEFINITIONS property.
+ this->AddDefineFlag(flag, this->DefineFlagsOrig);
+
+ // If this is really a definition, update COMPILE_DEFINITIONS.
+ if (this->ParseDefineFlag(flag, false)) {
+ return;
+ }
+
+ // Add this flag that does not look like a definition.
+ this->AddDefineFlag(flag, this->DefineFlags);
+}
+
+void cmMakefile::AddDefineFlag(const char* flag, std::string& dflags)
+{
+ // remove any \n\r
+ std::string::size_type initSize = dflags.size();
+ dflags += std::string(" ") + flag;
+ std::string::iterator flagStart = dflags.begin() + initSize + 1;
+ std::replace(flagStart, dflags.end(), '\n', ' ');
+ std::replace(flagStart, dflags.end(), '\r', ' ');
+}
+
+void cmMakefile::RemoveDefineFlag(const char* flag)
+{
+ // Check the length of the flag to remove.
+ std::string::size_type len = strlen(flag);
+ if (len < 1) {
+ return;
+ }
+
+ // Update the string used for the old DEFINITIONS property.
+ this->RemoveDefineFlag(flag, len, this->DefineFlagsOrig);
+
+ // If this is really a definition, update COMPILE_DEFINITIONS.
+ if (this->ParseDefineFlag(flag, true)) {
+ return;
+ }
+
+ // Remove this flag that does not look like a definition.
+ this->RemoveDefineFlag(flag, len, this->DefineFlags);
+}
+
+void cmMakefile::RemoveDefineFlag(const char* flag, std::string::size_type len,
+ std::string& dflags)
+{
+ // Remove all instances of the flag that are surrounded by
+ // whitespace or the beginning/end of the string.
+ for (std::string::size_type lpos = dflags.find(flag, 0);
+ lpos != std::string::npos; lpos = dflags.find(flag, lpos)) {
+ std::string::size_type rpos = lpos + len;
+ if ((lpos <= 0 || isspace(dflags[lpos - 1])) &&
+ (rpos >= dflags.size() || isspace(dflags[rpos]))) {
+ dflags.erase(lpos, len);
+ } else {
+ ++lpos;
+ }
+ }
+}
+
+void cmMakefile::AddCompileOption(const char* option)
+{
+ this->AppendProperty("COMPILE_OPTIONS", option);
+}
+
+bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove)
+{
+ // Create a regular expression to match valid definitions.
+ static cmsys::RegularExpression valid("^[-/]D[A-Za-z_][A-Za-z0-9_]*(=.*)?$");
+
+ // Make sure the definition matches.
+ if (!valid.find(def.c_str())) {
+ return false;
+ }
+
+ // Definitions with non-trivial values require a policy check.
+ static cmsys::RegularExpression trivial(
+ "^[-/]D[A-Za-z_][A-Za-z0-9_]*(=[A-Za-z0-9_.]+)?$");
+ if (!trivial.find(def.c_str())) {
+ // This definition has a non-trivial value.
+ switch (this->GetPolicyStatus(cmPolicies::CMP0005)) {
+ case cmPolicies::WARN:
+ this->IssueMessage(cmake::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0005));
+ case cmPolicies::OLD:
+ // OLD behavior is to not escape the value. We should not
+ // convert the definition to use the property.
+ return false;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->IssueMessage(
+ cmake::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0005));
+ return false;
+ case cmPolicies::NEW:
+ // NEW behavior is to escape the value. Proceed to convert it
+ // to an entry in the property.
+ break;
+ }
+ }
+
+ // Get the definition part after the flag.
+ const char* define = def.c_str() + 2;
+
+ if (remove) {
+ if (const char* cdefs = this->GetProperty("COMPILE_DEFINITIONS")) {
+ // Expand the list.
+ std::vector<std::string> defs;
+ cmSystemTools::ExpandListArgument(cdefs, defs);
+
+ // Recompose the list without the definition.
+ std::vector<std::string>::const_iterator defEnd =
+ std::remove(defs.begin(), defs.end(), define);
+ std::vector<std::string>::const_iterator defBegin = defs.begin();
+ std::string ndefs = cmJoin(cmMakeRange(defBegin, defEnd), ";");
+
+ // Store the new list.
+ this->SetProperty("COMPILE_DEFINITIONS", ndefs.c_str());
+ }
+ } else {
+ // Append the definition to the directory property.
+ this->AppendProperty("COMPILE_DEFINITIONS", define);
+ }
+
+ return true;
+}
+
+void cmMakefile::AddLinkLibrary(const std::string& lib,
+ cmTargetLinkLibraryType llt)
+{
+ cmTarget::LibraryID tmp;
+ tmp.first = lib;
+ tmp.second = llt;
+ this->LinkLibraries.push_back(tmp);
+}
+
+void cmMakefile::AddLinkLibraryForTarget(const std::string& target,
+ const std::string& lib,
+ cmTargetLinkLibraryType llt)
+{
+ cmTargets::iterator i = this->Targets.find(target);
+ if (i != this->Targets.end()) {
+ cmTarget* tgt = this->GetGlobalGenerator()->FindTarget(lib);
+ if (tgt) {
+ // if it is not a static or shared library then you can not link to it
+ if (!((tgt->GetType() == cmState::STATIC_LIBRARY) ||
+ (tgt->GetType() == cmState::SHARED_LIBRARY) ||
+ (tgt->GetType() == cmState::INTERFACE_LIBRARY) ||
+ tgt->IsExecutableWithExports())) {
+ std::ostringstream e;
+ e << "Target \"" << lib << "\" of type "
+ << cmState::GetTargetTypeName(tgt->GetType())
+ << " may not be linked into another target. "
+ << "One may link only to STATIC or SHARED libraries, or "
+ << "to executables with the ENABLE_EXPORTS property set.";
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ }
+ }
+ i->second.AddLinkLibrary(*this, target, lib, llt);
+ } else {
+ std::ostringstream e;
+ e << "Attempt to add link library \"" << lib << "\" to target \"" << target
+ << "\" which is not built in this directory.";
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ }
+}
+
+void cmMakefile::AddLinkDirectoryForTarget(const std::string& target,
+ const std::string& d)
+{
+ cmTargets::iterator i = this->Targets.find(target);
+ if (i != this->Targets.end()) {
+ if (this->IsAlias(target)) {
+ std::ostringstream e;
+ e << "ALIAS target \"" << target << "\" "
+ << "may not be linked into another target.";
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ i->second.AddLinkDirectory(d);
+ } else {
+ cmSystemTools::Error(
+ "Attempt to add link directories to non-existent target: ",
+ target.c_str(), " for directory ", d.c_str());
+ }
+}
+
+void cmMakefile::AddLinkLibrary(const std::string& lib)
+{
+ this->AddLinkLibrary(lib, GENERAL_LibraryType);
+}
+
+void cmMakefile::InitializeFromParent(cmMakefile* parent)
+{
+ this->SystemIncludeDirectories = parent->SystemIncludeDirectories;
+
+ // define flags
+ this->DefineFlags = parent->DefineFlags;
+ this->DefineFlagsOrig = parent->DefineFlagsOrig;
+
+ // Include transform property. There is no per-config version.
+ {
+ const char* prop = "IMPLICIT_DEPENDS_INCLUDE_TRANSFORM";
+ this->SetProperty(prop, parent->GetProperty(prop));
+ }
+
+ // compile definitions property and per-config versions
+ cmPolicies::PolicyStatus polSt = this->GetPolicyStatus(cmPolicies::CMP0043);
+ if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
+ this->SetProperty("COMPILE_DEFINITIONS",
+ parent->GetProperty("COMPILE_DEFINITIONS"));
+ std::vector<std::string> configs;
+ this->GetConfigurations(configs);
+ for (std::vector<std::string>::const_iterator ci = configs.begin();
+ ci != configs.end(); ++ci) {
+ std::string defPropName = "COMPILE_DEFINITIONS_";
+ defPropName += cmSystemTools::UpperCase(*ci);
+ const char* prop = parent->GetProperty(defPropName);
+ this->SetProperty(defPropName, prop);
+ }
+ }
+
+ // link libraries
+ this->LinkLibraries = parent->LinkLibraries;
+
+ // link directories
+ this->SetProperty("LINK_DIRECTORIES",
+ parent->GetProperty("LINK_DIRECTORIES"));
+
+ // the initial project name
+ this->StateSnapshot.SetProjectName(parent->StateSnapshot.GetProjectName());
+
+ // Copy include regular expressions.
+ this->ComplainFileRegularExpression = parent->ComplainFileRegularExpression;
+
+ // Imported targets.
+ this->ImportedTargets = parent->ImportedTargets;
+}
+
+void cmMakefile::PushFunctionScope(std::string const& fileName,
+ const cmPolicies::PolicyMap& pm)
+{
+ this->StateSnapshot = this->GetState()->CreateFunctionCallSnapshot(
+ this->StateSnapshot, fileName);
+ assert(this->StateSnapshot.IsValid());
+
+ this->PushLoopBlockBarrier();
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ this->GetGlobalGenerator()->GetFileLockPool().PushFunctionScope();
+#endif
+
+ this->PushFunctionBlockerBarrier();
+
+ this->PushPolicy(true, pm);
+}
+
+void cmMakefile::PopFunctionScope(bool reportError)
+{
+ this->PopPolicy();
+
+ this->PopSnapshot(reportError);
+
+ this->PopFunctionBlockerBarrier(reportError);
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ this->GetGlobalGenerator()->GetFileLockPool().PopFunctionScope();
+#endif
+
+ this->PopLoopBlockBarrier();
+
+ this->CheckForUnusedVariables();
+}
+
+void cmMakefile::PushMacroScope(std::string const& fileName,
+ const cmPolicies::PolicyMap& pm)
+{
+ this->StateSnapshot =
+ this->GetState()->CreateMacroCallSnapshot(this->StateSnapshot, fileName);
+ assert(this->StateSnapshot.IsValid());
+
+ this->PushFunctionBlockerBarrier();
+
+ this->PushPolicy(true, pm);
+}
+
+void cmMakefile::PopMacroScope(bool reportError)
+{
+ this->PopPolicy();
+ this->PopSnapshot(reportError);
+
+ this->PopFunctionBlockerBarrier(reportError);
+}
+
+bool cmMakefile::IsRootMakefile() const
+{
+ return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid();
+}
+
+class cmMakefile::BuildsystemFileScope
+{
+public:
+ BuildsystemFileScope(cmMakefile* mf)
+ : Makefile(mf)
+ , ReportError(true)
+ {
+ std::string currentStart =
+ this->Makefile->StateSnapshot.GetDirectory().GetCurrentSource();
+ currentStart += "/CMakeLists.txt";
+ this->Makefile->StateSnapshot.SetListFile(currentStart);
+ this->Makefile->StateSnapshot =
+ this->Makefile->StateSnapshot.GetState()->CreatePolicyScopeSnapshot(
+ this->Makefile->StateSnapshot);
+ this->Makefile->PushFunctionBlockerBarrier();
+
+ this->GG = mf->GetGlobalGenerator();
+ this->CurrentMakefile = this->GG->GetCurrentMakefile();
+ this->Snapshot = this->GG->GetCMakeInstance()->GetCurrentSnapshot();
+ this->GG->GetCMakeInstance()->SetCurrentSnapshot(this->Snapshot);
+ this->GG->SetCurrentMakefile(mf);
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ this->GG->GetFileLockPool().PushFileScope();
+#endif
+ }
+
+ ~BuildsystemFileScope()
+ {
+ this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
+ this->Makefile->PopSnapshot(this->ReportError);
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ this->GG->GetFileLockPool().PopFileScope();
+#endif
+ this->GG->SetCurrentMakefile(this->CurrentMakefile);
+ this->GG->GetCMakeInstance()->SetCurrentSnapshot(this->Snapshot);
+ }
+
+ void Quiet() { this->ReportError = false; }
+private:
+ cmMakefile* Makefile;
+ cmGlobalGenerator* GG;
+ cmMakefile* CurrentMakefile;
+ cmState::Snapshot Snapshot;
+ bool ReportError;
+};
+
+void cmMakefile::Configure()
+{
+ std::string currentStart =
+ this->StateSnapshot.GetDirectory().GetCurrentSource();
+ currentStart += "/CMakeLists.txt";
+
+ // Add the bottom of all backtraces within this directory.
+ // We will never pop this scope because it should be available
+ // for messages during the generate step too.
+ this->Backtrace = this->Backtrace.Push(currentStart);
+
+ BuildsystemFileScope scope(this);
+
+ // make sure the CMakeFiles dir is there
+ std::string filesDir = this->StateSnapshot.GetDirectory().GetCurrentBinary();
+ filesDir += cmake::GetCMakeFilesDirectory();
+ cmSystemTools::MakeDirectory(filesDir.c_str());
+
+ assert(cmSystemTools::FileExists(currentStart.c_str(), true));
+ this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentStart.c_str());
+
+ cmListFile listFile;
+ if (!listFile.ParseFile(currentStart.c_str(), this)) {
+ return;
+ }
+ if (this->IsRootMakefile()) {
+ bool hasVersion = false;
+ // search for the right policy command
+ for (std::vector<cmListFileFunction>::iterator i =
+ listFile.Functions.begin();
+ i != listFile.Functions.end(); ++i) {
+ if (cmSystemTools::LowerCase(i->Name) == "cmake_minimum_required") {
+ hasVersion = true;
+ break;
+ }
+ }
+ // if no policy command is found this is an error if they use any
+ // non advanced functions or a lot of functions
+ if (!hasVersion) {
+ bool isProblem = true;
+ if (listFile.Functions.size() < 30) {
+ // the list of simple commands DO NOT ADD TO THIS LIST!!!!!
+ // these commands must have backwards compatibility forever and
+ // and that is a lot longer than your tiny mind can comprehend mortal
+ std::set<std::string> allowedCommands;
+ allowedCommands.insert("project");
+ allowedCommands.insert("set");
+ allowedCommands.insert("if");
+ allowedCommands.insert("endif");
+ allowedCommands.insert("else");
+ allowedCommands.insert("elseif");
+ allowedCommands.insert("add_executable");
+ allowedCommands.insert("add_library");
+ allowedCommands.insert("target_link_libraries");
+ allowedCommands.insert("option");
+ allowedCommands.insert("message");
+ isProblem = false;
+ for (std::vector<cmListFileFunction>::iterator i =
+ listFile.Functions.begin();
+ i != listFile.Functions.end(); ++i) {
+ std::string name = cmSystemTools::LowerCase(i->Name);
+ if (allowedCommands.find(name) == allowedCommands.end()) {
+ isProblem = true;
+ break;
+ }
+ }
+ }
+
+ if (isProblem) {
+ // Tell the top level cmMakefile to diagnose
+ // this violation of CMP0000.
+ this->SetCheckCMP0000(true);
+
+ // Implicitly set the version for the user.
+ this->SetPolicyVersion("2.4");
+ }
+ }
+ bool hasProject = false;
+ // search for a project command
+ for (std::vector<cmListFileFunction>::iterator i =
+ listFile.Functions.begin();
+ i != listFile.Functions.end(); ++i) {
+ if (cmSystemTools::LowerCase(i->Name) == "project") {
+ hasProject = true;
+ break;
+ }
+ }
+ // if no project command is found, add one
+ if (!hasProject) {
+ cmListFileFunction project;
+ project.Name = "PROJECT";
+ cmListFileArgument prj("Project", cmListFileArgument::Unquoted, 0);
+ project.Arguments.push_back(prj);
+ listFile.Functions.insert(listFile.Functions.begin(), project);
+ }
+ }
+
+ this->ReadListFile(listFile, currentStart);
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ scope.Quiet();
+ }
+
+ // at the end handle any old style subdirs
+ std::vector<cmMakefile*> subdirs = this->UnConfiguredDirectories;
+
+ // for each subdir recurse
+ std::vector<cmMakefile*>::iterator sdi = subdirs.begin();
+ for (; sdi != subdirs.end(); ++sdi) {
+ (*sdi)->StateSnapshot.InitializeFromParent_ForSubdirsCommand();
+ this->ConfigureSubDirectory(*sdi);
+ }
+
+ this->AddCMakeDependFilesFromUser();
+}
+
+void cmMakefile::ConfigureSubDirectory(cmMakefile* mf)
+{
+ mf->InitializeFromParent(this);
+ std::string currentStart = mf->GetCurrentSourceDirectory();
+ if (this->GetCMakeInstance()->GetDebugOutput()) {
+ std::string msg = " Entering ";
+ msg += currentStart;
+ cmSystemTools::Message(msg.c_str());
+ }
+
+ std::string const currentStartFile = currentStart + "/CMakeLists.txt";
+ if (!cmSystemTools::FileExists(currentStartFile, true)) {
+ // The file is missing. Check policy CMP0014.
+ std::ostringstream e;
+ /* clang-format off */
+ e << "The source directory\n"
+ << " " << currentStart << "\n"
+ << "does not contain a CMakeLists.txt file.";
+ /* clang-format on */
+ switch (this->GetPolicyStatus(cmPolicies::CMP0014)) {
+ case cmPolicies::WARN:
+ // Print the warning.
+ /* clang-format off */
+ e << "\n"
+ << "CMake does not support this case but it used "
+ << "to work accidentally and is being allowed for "
+ << "compatibility."
+ << "\n"
+ << cmPolicies::GetPolicyWarning(cmPolicies::CMP0014);
+ /* clang-format on */
+ this->IssueMessage(cmake::AUTHOR_WARNING, e.str());
+ case cmPolicies::OLD:
+ // OLD behavior does not warn.
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ e << "\n" << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0014);
+ case cmPolicies::NEW:
+ // NEW behavior prints the error.
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ }
+ return;
+ }
+ // finally configure the subdir
+ mf->Configure();
+
+ if (this->GetCMakeInstance()->GetDebugOutput()) {
+ std::string msg = " Returning to ";
+ msg += this->GetCurrentSourceDirectory();
+ cmSystemTools::Message(msg.c_str());
+ }
+}
+
+void cmMakefile::AddSubDirectory(const std::string& srcPath,
+ const std::string& binPath,
+ bool excludeFromAll, bool immediate)
+{
+ // Make sure the binary directory is unique.
+ if (!this->EnforceUniqueDir(srcPath, binPath)) {
+ return;
+ }
+
+ cmState::Snapshot newSnapshot =
+ this->GetState()->CreateBuildsystemDirectorySnapshot(this->StateSnapshot);
+
+ newSnapshot.GetDirectory().SetCurrentSource(srcPath);
+ newSnapshot.GetDirectory().SetCurrentBinary(binPath);
+
+ cmSystemTools::MakeDirectory(binPath.c_str());
+
+ cmMakefile* subMf = new cmMakefile(this->GlobalGenerator, newSnapshot);
+ this->GetGlobalGenerator()->AddMakefile(subMf);
+
+ if (excludeFromAll) {
+ subMf->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
+ }
+
+ if (immediate) {
+ this->ConfigureSubDirectory(subMf);
+ } else {
+ this->UnConfiguredDirectories.push_back(subMf);
+ }
+}
+
+const char* cmMakefile::GetCurrentSourceDirectory() const
+{
+ return this->StateSnapshot.GetDirectory().GetCurrentSource();
+}
+
+const char* cmMakefile::GetCurrentBinaryDirectory() const
+{
+ return this->StateSnapshot.GetDirectory().GetCurrentBinary();
+}
+
+std::vector<cmTarget*> cmMakefile::GetImportedTargets() const
+{
+ std::vector<cmTarget*> tgts;
+ tgts.reserve(this->ImportedTargets.size());
+ for (TargetMap::const_iterator it = this->ImportedTargets.begin();
+ it != this->ImportedTargets.end(); ++it) {
+ tgts.push_back(it->second);
+ }
+ return tgts;
+}
+
+void cmMakefile::AddIncludeDirectories(const std::vector<std::string>& incs,
+ bool before)
+{
+ if (incs.empty()) {
+ return;
+ }
+
+ cmListFileBacktrace lfbt = this->GetBacktrace();
+ std::string entryString = cmJoin(incs, ";");
+ if (before) {
+ this->StateSnapshot.GetDirectory().PrependIncludeDirectoriesEntry(
+ entryString, lfbt);
+ } else {
+ this->StateSnapshot.GetDirectory().AppendIncludeDirectoriesEntry(
+ entryString, lfbt);
+ }
+
+ // Property on each target:
+ for (cmTargets::iterator l = this->Targets.begin(); l != this->Targets.end();
+ ++l) {
+ cmTarget& t = l->second;
+ t.InsertInclude(entryString, lfbt, before);
+ }
+}
+
+void cmMakefile::AddSystemIncludeDirectories(const std::set<std::string>& incs)
+{
+ if (incs.empty()) {
+ return;
+ }
+
+ this->SystemIncludeDirectories.insert(incs.begin(), incs.end());
+
+ for (cmTargets::iterator l = this->Targets.begin(); l != this->Targets.end();
+ ++l) {
+ cmTarget& t = l->second;
+ t.AddSystemIncludeDirectories(incs);
+ }
+}
+
+void cmMakefile::AddDefinition(const std::string& name, const char* value)
+{
+ if (!value) {
+ return;
+ }
+
+ if (this->VariableInitialized(name)) {
+ this->LogUnused("changing definition", name);
+ }
+ this->StateSnapshot.SetDefinition(name, value);
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ cmVariableWatch* vv = this->GetVariableWatch();
+ if (vv) {
+ vv->VariableAccessed(name, cmVariableWatch::VARIABLE_MODIFIED_ACCESS,
+ value, this);
+ }
+#endif
+}
+
+void cmMakefile::AddCacheDefinition(const std::string& name, const char* value,
+ const char* doc,
+ cmState::CacheEntryType type, bool force)
+{
+ const char* existingValue = this->GetState()->GetInitializedCacheValue(name);
+ // must be outside the following if() to keep it alive long enough
+ std::string nvalue;
+
+ if (existingValue &&
+ (this->GetState()->GetCacheEntryType(name) == cmState::UNINITIALIZED)) {
+ // if this is not a force, then use the value from the cache
+ // if it is a force, then use the value being passed in
+ if (!force) {
+ value = existingValue;
+ }
+ if (type == cmState::PATH || type == cmState::FILEPATH) {
+ std::vector<std::string>::size_type cc;
+ std::vector<std::string> files;
+ nvalue = value ? value : "";
+
+ cmSystemTools::ExpandListArgument(nvalue, files);
+ nvalue = "";
+ for (cc = 0; cc < files.size(); cc++) {
+ if (!cmSystemTools::IsOff(files[cc].c_str())) {
+ files[cc] = cmSystemTools::CollapseFullPath(files[cc]);
+ }
+ if (cc > 0) {
+ nvalue += ";";
+ }
+ nvalue += files[cc];
+ }
+
+ this->GetCMakeInstance()->AddCacheEntry(name, nvalue.c_str(), doc, type);
+ nvalue = this->GetState()->GetInitializedCacheValue(name);
+ value = nvalue.c_str();
+ }
+ }
+ this->GetCMakeInstance()->AddCacheEntry(name, value, doc, type);
+ // if there was a definition then remove it
+ this->StateSnapshot.RemoveDefinition(name);
+}
+
+void cmMakefile::AddDefinition(const std::string& name, bool value)
+{
+ if (this->VariableInitialized(name)) {
+ this->LogUnused("changing definition", name);
+ }
+
+ this->StateSnapshot.SetDefinition(name, value ? "ON" : "OFF");
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ cmVariableWatch* vv = this->GetVariableWatch();
+ if (vv) {
+ vv->VariableAccessed(name, cmVariableWatch::VARIABLE_MODIFIED_ACCESS,
+ value ? "ON" : "OFF", this);
+ }
+#endif
+}
+
+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);
+ }
+}
+
+void cmMakefile::MarkVariableAsUsed(const std::string& var)
+{
+ this->StateSnapshot.GetDefinition(var);
+}
+
+bool cmMakefile::VariableInitialized(const std::string& var) const
+{
+ return this->StateSnapshot.IsInitialized(var);
+}
+
+void cmMakefile::LogUnused(const char* reason, const std::string& name) const
+{
+ if (this->WarnUnused) {
+ std::string path;
+ if (!this->ExecutionStatusStack.empty()) {
+ path = this->GetExecutionContext().FilePath;
+ } else {
+ path = this->GetCurrentSourceDirectory();
+ path += "/CMakeLists.txt";
+ }
+
+ if (this->CheckSystemVars ||
+ cmSystemTools::IsSubDirectory(path, this->GetHomeDirectory()) ||
+ (cmSystemTools::IsSubDirectory(path, this->GetHomeOutputDirectory()) &&
+ !cmSystemTools::IsSubDirectory(path,
+ cmake::GetCMakeFilesDirectory()))) {
+ std::ostringstream msg;
+ msg << "unused variable (" << reason << ") \'" << name << "\'";
+ this->IssueMessage(cmake::AUTHOR_WARNING, msg.str());
+ }
+ }
+}
+
+void cmMakefile::RemoveDefinition(const std::string& name)
+{
+ if (this->VariableInitialized(name)) {
+ this->LogUnused("unsetting", name);
+ }
+ this->StateSnapshot.RemoveDefinition(name);
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ cmVariableWatch* vv = this->GetVariableWatch();
+ if (vv) {
+ vv->VariableAccessed(name, cmVariableWatch::VARIABLE_REMOVED_ACCESS,
+ CM_NULLPTR, this);
+ }
+#endif
+}
+
+void cmMakefile::RemoveCacheDefinition(const std::string& name)
+{
+ this->GetState()->RemoveCacheEntry(name);
+}
+
+void cmMakefile::SetProjectName(std::string const& p)
+{
+ this->StateSnapshot.SetProjectName(p);
+}
+
+void cmMakefile::AddGlobalLinkInformation(const std::string& name,
+ cmTarget& target)
+{
+ // for these targets do not add anything
+ switch (target.GetType()) {
+ case cmState::UTILITY:
+ case cmState::GLOBAL_TARGET:
+ case cmState::INTERFACE_LIBRARY:
+ return;
+ default:;
+ }
+ if (const char* linkDirsProp = this->GetProperty("LINK_DIRECTORIES")) {
+ std::vector<std::string> linkDirs;
+ cmSystemTools::ExpandListArgument(linkDirsProp, linkDirs);
+
+ for (std::vector<std::string>::iterator j = linkDirs.begin();
+ j != linkDirs.end(); ++j) {
+ std::string newdir = *j;
+ // remove trailing slashes
+ if (*j->rbegin() == '/') {
+ newdir = j->substr(0, j->size() - 1);
+ }
+ if (std::find(this->LinkDirectories.begin(), this->LinkDirectories.end(),
+ newdir) == this->LinkDirectories.end()) {
+ target.AddLinkDirectory(*j);
+ }
+ }
+ }
+ target.MergeLinkLibraries(*this, name, this->LinkLibraries);
+}
+
+void cmMakefile::AddAlias(const std::string& lname, std::string const& tgtName)
+{
+ this->AliasTargets[lname] = tgtName;
+ this->GetGlobalGenerator()->AddAlias(lname, tgtName);
+}
+
+cmTarget* cmMakefile::AddLibrary(const std::string& lname,
+ cmState::TargetType type,
+ const std::vector<std::string>& srcs,
+ bool excludeFromAll)
+{
+ // wrong type ? default to STATIC
+ if ((type != cmState::STATIC_LIBRARY) && (type != cmState::SHARED_LIBRARY) &&
+ (type != cmState::MODULE_LIBRARY) && (type != cmState::OBJECT_LIBRARY) &&
+ (type != cmState::INTERFACE_LIBRARY)) {
+ this->IssueMessage(cmake::INTERNAL_ERROR,
+ "cmMakefile::AddLibrary given invalid target type.");
+ type = cmState::STATIC_LIBRARY;
+ }
+
+ cmTarget* target = this->AddNewTarget(type, lname);
+ // Clear its dependencies. Otherwise, dependencies might persist
+ // over changes in CMakeLists.txt, making the information stale and
+ // hence useless.
+ target->ClearDependencyInformation(*this, lname);
+ if (excludeFromAll) {
+ target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
+ }
+ target->AddSources(srcs);
+ this->AddGlobalLinkInformation(lname, *target);
+ return target;
+}
+
+cmTarget* cmMakefile::AddExecutable(const char* exeName,
+ const std::vector<std::string>& srcs,
+ bool excludeFromAll)
+{
+ cmTarget* target = this->AddNewTarget(cmState::EXECUTABLE, exeName);
+ if (excludeFromAll) {
+ target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
+ }
+ target->AddSources(srcs);
+ this->AddGlobalLinkInformation(exeName, *target);
+ return target;
+}
+
+cmTarget* cmMakefile::AddNewTarget(cmState::TargetType type,
+ const std::string& name)
+{
+ cmTargets::iterator it =
+ this->Targets.insert(cmTargets::value_type(name, cmTarget())).first;
+ cmTarget& target = it->second;
+ target.SetType(type, name);
+ target.SetMakefile(this);
+ this->GetGlobalGenerator()->IndexTarget(&it->second);
+ return &it->second;
+}
+
+cmSourceFile* cmMakefile::LinearGetSourceFileWithOutput(
+ const std::string& name) const
+{
+ std::string out;
+
+ // look through all the source files that have custom commands
+ // and see if the custom command has the passed source file as an output
+ for (std::vector<cmSourceFile*>::const_iterator i =
+ this->SourceFiles.begin();
+ i != this->SourceFiles.end(); ++i) {
+ // does this source file have a custom command?
+ if ((*i)->GetCustomCommand()) {
+ // Does the output of the custom command match the source file name?
+ const std::vector<std::string>& outputs =
+ (*i)->GetCustomCommand()->GetOutputs();
+ for (std::vector<std::string>::const_iterator o = outputs.begin();
+ o != outputs.end(); ++o) {
+ out = *o;
+ std::string::size_type pos = out.rfind(name);
+ // If the output matches exactly
+ if (pos != out.npos && pos == out.size() - name.size() &&
+ (pos == 0 || out[pos - 1] == '/')) {
+ return *i;
+ }
+ }
+ }
+ }
+
+ // otherwise return NULL
+ return CM_NULLPTR;
+}
+
+cmSourceFile* cmMakefile::GetSourceFileWithOutput(
+ const std::string& name) const
+{
+ // If the queried path is not absolute we use the backward compatible
+ // linear-time search for an output with a matching suffix.
+ if (!cmSystemTools::FileIsFullPath(name.c_str())) {
+ return this->LinearGetSourceFileWithOutput(name);
+ }
+ // Otherwise we use an efficient lookup map.
+ OutputToSourceMap::const_iterator o = this->OutputToSource.find(name);
+ if (o != this->OutputToSource.end()) {
+ return (*o).second;
+ }
+ return CM_NULLPTR;
+}
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+cmSourceGroup* cmMakefile::GetSourceGroup(
+ const std::vector<std::string>& name) const
+{
+ cmSourceGroup* sg = CM_NULLPTR;
+
+ // first look for source group starting with the same as the one we want
+ for (std::vector<cmSourceGroup>::const_iterator sgIt =
+ this->SourceGroups.begin();
+ sgIt != this->SourceGroups.end(); ++sgIt) {
+ std::string sgName = sgIt->GetName();
+ if (sgName == name[0]) {
+ sg = const_cast<cmSourceGroup*>(&(*sgIt));
+ break;
+ }
+ }
+
+ if (sg != CM_NULLPTR) {
+ // iterate through its children to find match source group
+ for (unsigned int i = 1; i < name.size(); ++i) {
+ sg = sg->LookupChild(name[i].c_str());
+ if (sg == CM_NULLPTR) {
+ break;
+ }
+ }
+ }
+ return sg;
+}
+
+void cmMakefile::AddSourceGroup(const std::string& name, const char* regex)
+{
+ std::vector<std::string> nameVector;
+ nameVector.push_back(name);
+ this->AddSourceGroup(nameVector, regex);
+}
+
+void cmMakefile::AddSourceGroup(const std::vector<std::string>& name,
+ const char* regex)
+{
+ cmSourceGroup* sg = CM_NULLPTR;
+ std::vector<std::string> currentName;
+ int i = 0;
+ const int lastElement = static_cast<int>(name.size() - 1);
+ for (i = lastElement; i >= 0; --i) {
+ currentName.assign(name.begin(), name.begin() + i + 1);
+ sg = this->GetSourceGroup(currentName);
+ if (sg != CM_NULLPTR) {
+ break;
+ }
+ }
+
+ // i now contains the index of the last found component
+ if (i == lastElement) {
+ // group already exists, replace its regular expression
+ if (regex && sg) {
+ // We only want to set the regular expression. If there are already
+ // source files in the group, we don't want to remove them.
+ sg->SetGroupRegex(regex);
+ }
+ return;
+ } else if (i == -1) {
+ // group does not exist nor belong to any existing group
+ // add its first component
+ this->SourceGroups.push_back(cmSourceGroup(name[0].c_str(), regex));
+ sg = this->GetSourceGroup(currentName);
+ i = 0; // last component found
+ }
+ if (!sg) {
+ cmSystemTools::Error("Could not create source group ");
+ return;
+ }
+ // build the whole source group path
+ for (++i; i <= lastElement; ++i) {
+ sg->AddChild(
+ cmSourceGroup(name[i].c_str(), CM_NULLPTR, sg->GetFullName()));
+ sg = sg->LookupChild(name[i].c_str());
+ }
+
+ sg->SetGroupRegex(regex);
+}
+
+#endif
+
+static bool mightExpandVariablesCMP0019(const char* s)
+{
+ return s && *s && strstr(s, "${") && strchr(s, '}');
+}
+
+void cmMakefile::ExpandVariablesCMP0019()
+{
+ // Drop this ancient compatibility behavior with a policy.
+ cmPolicies::PolicyStatus pol = this->GetPolicyStatus(cmPolicies::CMP0019);
+ if (pol != cmPolicies::OLD && pol != cmPolicies::WARN) {
+ return;
+ }
+ std::ostringstream w;
+
+ const char* includeDirs = this->GetProperty("INCLUDE_DIRECTORIES");
+ if (mightExpandVariablesCMP0019(includeDirs)) {
+ std::string dirs = includeDirs;
+ this->ExpandVariablesInString(dirs, true, true);
+ if (pol == cmPolicies::WARN && dirs != includeDirs) {
+ /* clang-format off */
+ w << "Evaluated directory INCLUDE_DIRECTORIES\n"
+ << " " << includeDirs << "\n"
+ << "as\n"
+ << " " << dirs << "\n";
+ /* clang-format on */
+ }
+ this->SetProperty("INCLUDE_DIRECTORIES", dirs.c_str());
+ }
+
+ // Also for each target's INCLUDE_DIRECTORIES property:
+ for (cmTargets::iterator l = this->Targets.begin(); l != this->Targets.end();
+ ++l) {
+ cmTarget& t = l->second;
+ if (t.GetType() == cmState::INTERFACE_LIBRARY ||
+ t.GetType() == cmState::GLOBAL_TARGET) {
+ continue;
+ }
+ includeDirs = t.GetProperty("INCLUDE_DIRECTORIES");
+ if (mightExpandVariablesCMP0019(includeDirs)) {
+ std::string dirs = includeDirs;
+ this->ExpandVariablesInString(dirs, true, true);
+ if (pol == cmPolicies::WARN && dirs != includeDirs) {
+ /* clang-format off */
+ w << "Evaluated target " << t.GetName() << " INCLUDE_DIRECTORIES\n"
+ << " " << includeDirs << "\n"
+ << "as\n"
+ << " " << dirs << "\n";
+ /* clang-format on */
+ }
+ t.SetProperty("INCLUDE_DIRECTORIES", dirs.c_str());
+ }
+ }
+
+ if (const char* linkDirsProp = this->GetProperty("LINK_DIRECTORIES")) {
+ if (mightExpandVariablesCMP0019(linkDirsProp)) {
+ std::string d = linkDirsProp;
+ std::string orig = linkDirsProp;
+ this->ExpandVariablesInString(d, true, true);
+ if (pol == cmPolicies::WARN && d != orig) {
+ /* clang-format off */
+ w << "Evaluated link directories\n"
+ << " " << orig << "\n"
+ << "as\n"
+ << " " << d << "\n";
+ /* clang-format on */
+ }
+ }
+ }
+ for (cmTarget::LinkLibraryVectorType::iterator l =
+ this->LinkLibraries.begin();
+ l != this->LinkLibraries.end(); ++l) {
+ if (mightExpandVariablesCMP0019(l->first.c_str())) {
+ std::string orig = l->first;
+ this->ExpandVariablesInString(l->first, true, true);
+ if (pol == cmPolicies::WARN && l->first != orig) {
+ /* clang-format off */
+ w << "Evaluated link library\n"
+ << " " << orig << "\n"
+ << "as\n"
+ << " " << l->first << "\n";
+ /* clang-format on */
+ }
+ }
+ }
+
+ if (!w.str().empty()) {
+ std::ostringstream m;
+ /* clang-format off */
+ m << cmPolicies::GetPolicyWarning(cmPolicies::CMP0019)
+ << "\n"
+ << "The following variable evaluations were encountered:\n"
+ << w.str();
+ /* clang-format on */
+ this->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING, m.str(),
+ this->Backtrace);
+ }
+}
+
+bool cmMakefile::IsOn(const std::string& name) const
+{
+ const char* value = this->GetDefinition(name);
+ return cmSystemTools::IsOn(value);
+}
+
+bool cmMakefile::IsSet(const std::string& name) const
+{
+ const char* value = this->GetDefinition(name);
+ if (!value) {
+ return false;
+ }
+
+ if (!*value) {
+ return false;
+ }
+
+ if (cmSystemTools::IsNOTFOUND(value)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool cmMakefile::PlatformIs32Bit() const
+{
+ if (const char* sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) {
+ return atoi(sizeof_dptr) == 4;
+ }
+ return false;
+}
+
+bool cmMakefile::PlatformIs64Bit() const
+{
+ if (const char* sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) {
+ return atoi(sizeof_dptr) == 8;
+ }
+ return false;
+}
+
+bool cmMakefile::PlatformIsAppleIos() const
+{
+ std::string sdkRoot;
+ sdkRoot = this->GetSafeDefinition("CMAKE_OSX_SYSROOT");
+ sdkRoot = cmSystemTools::LowerCase(sdkRoot);
+
+ const std::string embedded[] = {
+ "appletvos", "appletvsimulator", "iphoneos",
+ "iphonesimulator", "watchos", "watchsimulator",
+ };
+
+ for (size_t i = 0; i < sizeof(embedded) / sizeof(embedded[0]); ++i) {
+ if (sdkRoot.find(embedded[i]) == 0 ||
+ sdkRoot.find(std::string("/") + embedded[i]) != std::string::npos) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const char* cmMakefile::GetSONameFlag(const std::string& language) const
+{
+ std::string name = "CMAKE_SHARED_LIBRARY_SONAME";
+ if (!language.empty()) {
+ name += "_";
+ name += language;
+ }
+ name += "_FLAG";
+ return GetDefinition(name);
+}
+
+bool cmMakefile::CanIWriteThisFile(const char* fileName) const
+{
+ if (!this->IsOn("CMAKE_DISABLE_SOURCE_CHANGES")) {
+ return true;
+ }
+ // If we are doing an in-source build, then the test will always fail
+ if (cmSystemTools::SameFile(this->GetHomeDirectory(),
+ this->GetHomeOutputDirectory())) {
+ return !this->IsOn("CMAKE_DISABLE_IN_SOURCE_BUILD");
+ }
+
+ return !cmSystemTools::IsSubDirectory(fileName, this->GetHomeDirectory()) ||
+ cmSystemTools::IsSubDirectory(fileName, this->GetHomeOutputDirectory());
+}
+
+const char* cmMakefile::GetRequiredDefinition(const std::string& name) const
+{
+ const char* ret = this->GetDefinition(name);
+ if (!ret) {
+ cmSystemTools::Error("Error required internal CMake variable not "
+ "set, cmake may be not be built correctly.\n",
+ "Missing variable is:\n", name.c_str());
+ return "";
+ }
+ return ret;
+}
+
+bool cmMakefile::IsDefinitionSet(const std::string& name) const
+{
+ const char* def = this->StateSnapshot.GetDefinition(name);
+ if (!def) {
+ def = this->GetState()->GetInitializedCacheValue(name);
+ }
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ if (cmVariableWatch* vv = this->GetVariableWatch()) {
+ if (!def) {
+ vv->VariableAccessed(
+ name, cmVariableWatch::UNKNOWN_VARIABLE_DEFINED_ACCESS, def, this);
+ }
+ }
+#endif
+ return def != CM_NULLPTR;
+}
+
+const char* cmMakefile::GetDefinition(const std::string& name) const
+{
+ const char* def = this->StateSnapshot.GetDefinition(name);
+ if (!def) {
+ def = this->GetState()->GetInitializedCacheValue(name);
+ }
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ cmVariableWatch* vv = this->GetVariableWatch();
+ if (vv && !this->SuppressWatches) {
+ bool const watch_function_executed = vv->VariableAccessed(
+ name, def ? cmVariableWatch::VARIABLE_READ_ACCESS
+ : cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS,
+ def, this);
+
+ if (watch_function_executed) {
+ // A callback was executed and may have caused re-allocation of the
+ // variable storage. Look it up again for now.
+ // FIXME: Refactor variable storage to avoid this problem.
+ def = this->StateSnapshot.GetDefinition(name);
+ if (!def) {
+ def = this->GetState()->GetInitializedCacheValue(name);
+ }
+ }
+ }
+#endif
+ return def;
+}
+
+const char* cmMakefile::GetSafeDefinition(const std::string& def) const
+{
+ const char* ret = this->GetDefinition(def);
+ if (!ret) {
+ return "";
+ }
+ return ret;
+}
+
+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());
+ std::sort(res.begin(), res.end());
+ return res;
+}
+
+const char* cmMakefile::ExpandVariablesInString(std::string& source) const
+{
+ return this->ExpandVariablesInString(source, false, false);
+}
+
+const char* cmMakefile::ExpandVariablesInString(
+ std::string& source, bool escapeQuotes, bool noEscapes, bool atOnly,
+ const char* filename, long line, bool removeEmpty, bool replaceAt) const
+{
+ bool compareResults = false;
+ cmake::MessageType mtype = cmake::LOG;
+ std::string errorstr;
+ std::string original;
+
+ // Sanity check the @ONLY mode.
+ if (atOnly && (!noEscapes || !removeEmpty)) {
+ // This case should never be called. At-only is for
+ // configure-file/string which always does no escapes.
+ this->IssueMessage(cmake::INTERNAL_ERROR,
+ "ExpandVariablesInString @ONLY called "
+ "on something with escapes.");
+ return source.c_str();
+ }
+
+ // Variables used in the WARN case.
+ std::string newResult;
+ std::string newErrorstr;
+ cmake::MessageType newError = cmake::LOG;
+
+ switch (this->GetPolicyStatus(cmPolicies::CMP0053)) {
+ case cmPolicies::WARN: {
+ // Save the original string for the warning.
+ original = source;
+ newResult = source;
+ compareResults = true;
+ // Suppress variable watches to avoid calling hooks twice. Suppress new
+ // dereferences since the OLD behavior is still what is actually used.
+ this->SuppressWatches = true;
+ newError = ExpandVariablesInStringNew(
+ newErrorstr, newResult, escapeQuotes, noEscapes, atOnly, filename,
+ line, removeEmpty, replaceAt);
+ this->SuppressWatches = false;
+ }
+ case cmPolicies::OLD:
+ mtype =
+ ExpandVariablesInStringOld(errorstr, source, escapeQuotes, noEscapes,
+ atOnly, filename, line, removeEmpty, true);
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ // Messaging here would be *very* verbose.
+ case cmPolicies::NEW:
+ mtype = ExpandVariablesInStringNew(errorstr, source, escapeQuotes,
+ noEscapes, atOnly, filename, line,
+ removeEmpty, replaceAt);
+ break;
+ }
+
+ // If it's an error in either case, just report the error...
+ if (mtype != cmake::LOG) {
+ if (mtype == cmake::FATAL_ERROR) {
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ this->IssueMessage(mtype, errorstr);
+ }
+ // ...otherwise, see if there's a difference that needs to be warned about.
+ else if (compareResults && (newResult != source || newError != mtype)) {
+ std::string msg = cmPolicies::GetPolicyWarning(cmPolicies::CMP0053);
+ msg += "\n";
+
+ std::string msg_input = original;
+ cmSystemTools::ReplaceString(msg_input, "\n", "\n ");
+ msg += "For input:\n '";
+ msg += msg_input;
+ msg += "'\n";
+
+ std::string msg_old = source;
+ cmSystemTools::ReplaceString(msg_old, "\n", "\n ");
+ msg += "the old evaluation rules produce:\n '";
+ msg += msg_old;
+ msg += "'\n";
+
+ if (newError == mtype) {
+ std::string msg_new = newResult;
+ cmSystemTools::ReplaceString(msg_new, "\n", "\n ");
+ msg += "but the new evaluation rules produce:\n '";
+ msg += msg_new;
+ msg += "'\n";
+ } else {
+ std::string msg_err = newErrorstr;
+ cmSystemTools::ReplaceString(msg_err, "\n", "\n ");
+ msg += "but the new evaluation rules produce an error:\n ";
+ msg += msg_err;
+ msg += "\n";
+ }
+
+ msg +=
+ "Using the old result for compatibility since the policy is not set.";
+
+ this->IssueMessage(cmake::AUTHOR_WARNING, msg);
+ }
+
+ return source.c_str();
+}
+
+cmake::MessageType cmMakefile::ExpandVariablesInStringOld(
+ std::string& errorstr, std::string& source, bool escapeQuotes,
+ bool noEscapes, bool atOnly, const char* filename, long line,
+ bool removeEmpty, bool replaceAt) const
+{
+ // Fast path strings without any special characters.
+ if (source.find_first_of("$@\\") == source.npos) {
+ return cmake::LOG;
+ }
+
+ // Special-case the @ONLY mode.
+ if (atOnly) {
+ // Store an original copy of the input.
+ std::string input = source;
+
+ // Start with empty output.
+ source = "";
+
+ // Look for one @VAR@ at a time.
+ const char* in = input.c_str();
+ while (this->cmAtVarRegex.find(in)) {
+ // Get the range of the string to replace.
+ const char* first = in + this->cmAtVarRegex.start();
+ const char* last = in + this->cmAtVarRegex.end();
+
+ // Store the unchanged part of the string now.
+ source.append(in, first - in);
+
+ // Lookup the definition of VAR.
+ std::string var(first + 1, last - first - 2);
+ if (const char* val = this->GetDefinition(var)) {
+ // Store the value in the output escaping as requested.
+ if (escapeQuotes) {
+ source.append(cmSystemTools::EscapeQuotes(val));
+ } else {
+ source.append(val);
+ }
+ }
+
+ // Continue looking for @VAR@ further along the string.
+ in = last;
+ }
+
+ // Append the rest of the unchanged part of the string.
+ source.append(in);
+
+ return cmake::LOG;
+ }
+
+ // This method replaces ${VAR} and @VAR@ where VAR is looked up
+ // with GetDefinition(), if not found in the map, nothing is expanded.
+ // It also supports the $ENV{VAR} syntax where VAR is looked up in
+ // the current environment variables.
+
+ cmCommandArgumentParserHelper parser;
+ parser.SetMakefile(this);
+ parser.SetLineFile(line, filename);
+ parser.SetEscapeQuotes(escapeQuotes);
+ parser.SetNoEscapeMode(noEscapes);
+ parser.SetReplaceAtSyntax(replaceAt);
+ parser.SetRemoveEmpty(removeEmpty);
+ int res = parser.ParseString(source.c_str(), 0);
+ const char* emsg = parser.GetError();
+ cmake::MessageType mtype = cmake::LOG;
+ if (res && !emsg[0]) {
+ source = parser.GetResult();
+ } else {
+ // Construct the main error message.
+ std::ostringstream error;
+ error << "Syntax error in cmake code ";
+ if (filename && line > 0) {
+ // This filename and line number may be more specific than the
+ // command context because one command invocation can have
+ // arguments on multiple lines.
+ error << "at\n"
+ << " " << filename << ":" << line << "\n";
+ }
+ error << "when parsing string\n"
+ << " " << source << "\n";
+ error << emsg;
+
+ // If the parser failed ("res" is false) then this is a real
+ // argument parsing error, so the policy applies. Otherwise the
+ // parser reported an error message without failing because the
+ // helper implementation is unhappy, which has always reported an
+ // error.
+ mtype = cmake::FATAL_ERROR;
+ if (!res) {
+ // This is a real argument parsing error. Use policy CMP0010 to
+ // decide whether it is an error.
+ switch (this->GetPolicyStatus(cmPolicies::CMP0010)) {
+ case cmPolicies::WARN:
+ error << "\n" << cmPolicies::GetPolicyWarning(cmPolicies::CMP0010);
+ case cmPolicies::OLD:
+ // OLD behavior is to just warn and continue.
+ mtype = cmake::AUTHOR_WARNING;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ error << "\n"
+ << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0010);
+ case cmPolicies::NEW:
+ // NEW behavior is to report the error.
+ break;
+ }
+ }
+ errorstr = error.str();
+ }
+ return mtype;
+}
+
+typedef enum { NORMAL, ENVIRONMENT, CACHE } t_domain;
+struct t_lookup
+{
+ t_lookup()
+ : domain(NORMAL)
+ , loc(0)
+ {
+ }
+ t_domain domain;
+ size_t loc;
+};
+
+cmake::MessageType cmMakefile::ExpandVariablesInStringNew(
+ std::string& errorstr, std::string& source, bool escapeQuotes,
+ bool noEscapes, bool atOnly, const char* filename, long line,
+ bool removeEmpty, bool replaceAt) const
+{
+ // This method replaces ${VAR} and @VAR@ where VAR is looked up
+ // with GetDefinition(), if not found in the map, nothing is expanded.
+ // It also supports the $ENV{VAR} syntax where VAR is looked up in
+ // the current environment variables.
+
+ const char* in = source.c_str();
+ const char* last = in;
+ std::string result;
+ result.reserve(source.size());
+ std::vector<t_lookup> openstack;
+ bool error = false;
+ bool done = false;
+ cmake::MessageType mtype = cmake::LOG;
+
+ cmState* state = this->GetCMakeInstance()->GetState();
+
+ do {
+ char inc = *in;
+ switch (inc) {
+ case '}':
+ if (!openstack.empty()) {
+ t_lookup var = openstack.back();
+ openstack.pop_back();
+ result.append(last, in - last);
+ std::string const& lookup = result.substr(var.loc);
+ const char* value = CM_NULLPTR;
+ std::string varresult;
+ static const std::string lineVar = "CMAKE_CURRENT_LIST_LINE";
+ switch (var.domain) {
+ case NORMAL:
+ if (filename && lookup == lineVar) {
+ std::ostringstream ostr;
+ ostr << line;
+ varresult = ostr.str();
+ } else {
+ value = this->GetDefinition(lookup);
+ }
+ break;
+ case ENVIRONMENT:
+ value = cmSystemTools::GetEnv(lookup.c_str());
+ break;
+ case CACHE:
+ value = state->GetCacheEntryValue(lookup);
+ break;
+ }
+ // Get the string we're meant to append to.
+ if (value) {
+ if (escapeQuotes) {
+ varresult = cmSystemTools::EscapeQuotes(value);
+ } else {
+ varresult = value;
+ }
+ } else if (!removeEmpty) {
+ // check to see if we need to print a warning
+ // if strict mode is on and the variable has
+ // not been "cleared"/initialized with a set(foo ) call
+ if (this->GetCMakeInstance()->GetWarnUninitialized() &&
+ !this->VariableInitialized(lookup)) {
+ if (this->CheckSystemVars ||
+ cmSystemTools::IsSubDirectory(filename,
+ this->GetHomeDirectory()) ||
+ cmSystemTools::IsSubDirectory(
+ filename, this->GetHomeOutputDirectory())) {
+ std::ostringstream msg;
+ msg << "uninitialized variable \'" << lookup << "\'";
+ this->IssueMessage(cmake::AUTHOR_WARNING, msg.str());
+ }
+ }
+ }
+ result.replace(var.loc, result.size() - var.loc, varresult);
+ // Start looking from here on out.
+ last = in + 1;
+ }
+ break;
+ case '$':
+ if (!atOnly) {
+ t_lookup lookup;
+ const char* next = in + 1;
+ const char* start = CM_NULLPTR;
+ char nextc = *next;
+ if (nextc == '{') {
+ // Looking for a variable.
+ start = in + 2;
+ lookup.domain = NORMAL;
+ } else if (nextc == '<') {
+ } else if (!nextc) {
+ result.append(last, next - last);
+ last = next;
+ } else if (cmHasLiteralPrefix(next, "ENV{")) {
+ // Looking for an environment variable.
+ start = in + 5;
+ lookup.domain = ENVIRONMENT;
+ } else if (cmHasLiteralPrefix(next, "CACHE{")) {
+ // Looking for a cache variable.
+ start = in + 7;
+ lookup.domain = CACHE;
+ } else {
+ if (this->cmNamedCurly.find(next)) {
+ errorstr = "Syntax $" +
+ std::string(next, this->cmNamedCurly.end()) +
+ "{} is not supported. Only ${}, $ENV{}, "
+ "and $CACHE{} are allowed.";
+ mtype = cmake::FATAL_ERROR;
+ error = true;
+ }
+ }
+ if (start) {
+ result.append(last, in - last);
+ last = start;
+ in = start - 1;
+ lookup.loc = result.size();
+ openstack.push_back(lookup);
+ }
+ break;
+ }
+ case '\\':
+ if (!noEscapes) {
+ const char* next = in + 1;
+ char nextc = *next;
+ if (nextc == 't') {
+ result.append(last, in - last);
+ result.append("\t");
+ last = next + 1;
+ } else if (nextc == 'n') {
+ result.append(last, in - last);
+ result.append("\n");
+ last = next + 1;
+ } else if (nextc == 'r') {
+ result.append(last, in - last);
+ result.append("\r");
+ last = next + 1;
+ } else if (nextc == ';' && openstack.empty()) {
+ // Handled in ExpandListArgument; pass the backslash literally.
+ } else if (isalnum(nextc) || nextc == '\0') {
+ errorstr += "Invalid character escape '\\";
+ if (nextc) {
+ errorstr += nextc;
+ errorstr += "'.";
+ } else {
+ errorstr += "' (at end of input).";
+ }
+ error = true;
+ } else {
+ // Take what we've found so far, skipping the escape character.
+ result.append(last, in - last);
+ // Start tracking from the next character.
+ last = in + 1;
+ }
+ // Skip the next character since it was escaped, but don't read past
+ // the end of the string.
+ if (*last) {
+ ++in;
+ }
+ }
+ break;
+ case '\n':
+ // Onto the next line.
+ ++line;
+ break;
+ case '\0':
+ done = true;
+ break;
+ case '@':
+ if (replaceAt) {
+ const char* nextAt = strchr(in + 1, '@');
+ if (nextAt && nextAt != in + 1 &&
+ nextAt ==
+ in + 1 + strspn(in + 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789/_.+-")) {
+ std::string variable(in + 1, nextAt - in - 1);
+ std::string varresult = this->GetSafeDefinition(variable);
+ if (escapeQuotes) {
+ varresult = cmSystemTools::EscapeQuotes(varresult);
+ }
+ // Skip over the variable.
+ result.append(last, in - last);
+ result.append(varresult);
+ in = nextAt;
+ last = in + 1;
+ break;
+ }
+ }
+ // Failed to find a valid @ expansion; treat it as literal.
+ /* FALLTHROUGH */
+ default: {
+ if (!openstack.empty() &&
+ !(isalnum(inc) || inc == '_' || inc == '/' || inc == '.' ||
+ inc == '+' || inc == '-')) {
+ errorstr += "Invalid character (\'";
+ errorstr += inc;
+ result.append(last, in - last);
+ errorstr += "\') in a variable name: "
+ "'" +
+ result.substr(openstack.back().loc) + "'";
+ mtype = cmake::FATAL_ERROR;
+ error = true;
+ }
+ break;
+ }
+ }
+ // Look at the next character.
+ } while (!error && !done && *++in);
+
+ // Check for open variable references yet.
+ if (!error && !openstack.empty()) {
+ // There's an open variable reference waiting. Policy CMP0010 flags
+ // whether this is an error or not. The new parser now enforces
+ // CMP0010 as well.
+ errorstr += "There is an unterminated variable reference.";
+ error = true;
+ }
+
+ if (error) {
+ std::ostringstream emsg;
+ emsg << "Syntax error in cmake code ";
+ if (filename) {
+ // This filename and line number may be more specific than the
+ // command context because one command invocation can have
+ // arguments on multiple lines.
+ emsg << "at\n"
+ << " " << filename << ":" << line << "\n";
+ }
+ emsg << "when parsing string\n"
+ << " " << source << "\n";
+ emsg << errorstr;
+ mtype = cmake::FATAL_ERROR;
+ errorstr = emsg.str();
+ } else {
+ // Append the rest of the unchanged part of the string.
+ result.append(last);
+
+ source = result;
+ }
+
+ return mtype;
+}
+
+void cmMakefile::RemoveVariablesInString(std::string& source,
+ bool atOnly) const
+{
+ if (!atOnly) {
+ cmsys::RegularExpression var("(\\${[A-Za-z_0-9]*})");
+ while (var.find(source)) {
+ source.erase(var.start(), var.end() - var.start());
+ }
+ }
+
+ if (!atOnly) {
+ cmsys::RegularExpression varb("(\\$ENV{[A-Za-z_0-9]*})");
+ while (varb.find(source)) {
+ source.erase(varb.start(), varb.end() - varb.start());
+ }
+ }
+ cmsys::RegularExpression var2("(@[A-Za-z_0-9]*@)");
+ while (var2.find(source)) {
+ source.erase(var2.start(), var2.end() - var2.start());
+ }
+}
+
+std::string cmMakefile::GetConfigurations(std::vector<std::string>& configs,
+ bool singleConfig) const
+{
+ if (this->GetGlobalGenerator()->IsMultiConfig()) {
+ if (const char* configTypes =
+ this->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
+ cmSystemTools::ExpandListArgument(configTypes, configs);
+ }
+ return "";
+ } else {
+ const std::string& buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ if (singleConfig && !buildType.empty()) {
+ configs.push_back(buildType);
+ }
+ return buildType;
+ }
+}
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+/**
+ * Find a source group whose regular expression matches the filename
+ * part of the given source name. Search backward through the list of
+ * source groups, and take the first matching group found. This way
+ * non-inherited SOURCE_GROUP commands will have precedence over
+ * inherited ones.
+ */
+cmSourceGroup* cmMakefile::FindSourceGroup(
+ const char* source, std::vector<cmSourceGroup>& groups) const
+{
+ // First search for a group that lists the file explicitly.
+ for (std::vector<cmSourceGroup>::reverse_iterator sg = groups.rbegin();
+ sg != groups.rend(); ++sg) {
+ cmSourceGroup* result = sg->MatchChildrenFiles(source);
+ if (result) {
+ return result;
+ }
+ }
+
+ // Now search for a group whose regex matches the file.
+ for (std::vector<cmSourceGroup>::reverse_iterator sg = groups.rbegin();
+ sg != groups.rend(); ++sg) {
+ cmSourceGroup* result = sg->MatchChildrenRegex(source);
+ if (result) {
+ return result;
+ }
+ }
+
+ // Shouldn't get here, but just in case, return the default group.
+ return &groups.front();
+}
+#endif
+
+bool cmMakefile::IsFunctionBlocked(const cmListFileFunction& lff,
+ cmExecutionStatus& status)
+{
+ // if there are no blockers get out of here
+ if (this->FunctionBlockers.begin() == this->FunctionBlockers.end()) {
+ return false;
+ }
+
+ // 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)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void cmMakefile::PushFunctionBlockerBarrier()
+{
+ this->FunctionBlockerBarriers.push_back(this->FunctionBlockers.size());
+}
+
+void cmMakefile::PopFunctionBlockerBarrier(bool reportError)
+{
+ // Remove any extra entries pushed on the barrier.
+ FunctionBlockersType::size_type barrier =
+ this->FunctionBlockerBarriers.back();
+ while (this->FunctionBlockers.size() > barrier) {
+ CM_AUTO_PTR<cmFunctionBlocker> fb(this->FunctionBlockers.back());
+ this->FunctionBlockers.pop_back();
+ if (reportError) {
+ // Report the context in which the unclosed block was opened.
+ cmListFileContext const& lfc = fb->GetStartingContext();
+ std::ostringstream e;
+ /* clang-format off */
+ e << "A logical block opening on the line\n"
+ << " " << lfc << "\n"
+ << "is not closed.";
+ /* clang-format on */
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ reportError = false;
+ }
+ }
+
+ // Remove the barrier.
+ this->FunctionBlockerBarriers.pop_back();
+}
+
+void cmMakefile::PushLoopBlock()
+{
+ assert(!this->LoopBlockCounter.empty());
+ this->LoopBlockCounter.top()++;
+}
+
+void cmMakefile::PopLoopBlock()
+{
+ assert(!this->LoopBlockCounter.empty());
+ assert(this->LoopBlockCounter.top() > 0);
+ this->LoopBlockCounter.top()--;
+}
+
+void cmMakefile::PushLoopBlockBarrier()
+{
+ this->LoopBlockCounter.push(0);
+}
+
+void cmMakefile::PopLoopBlockBarrier()
+{
+ assert(!this->LoopBlockCounter.empty());
+ assert(this->LoopBlockCounter.top() == 0);
+ this->LoopBlockCounter.pop();
+}
+
+bool cmMakefile::IsLoopBlock() const
+{
+ assert(!this->LoopBlockCounter.empty());
+ return !this->LoopBlockCounter.empty() && this->LoopBlockCounter.top() > 0;
+}
+
+std::string cmMakefile::GetExecutionFilePath() const
+{
+ assert(this->StateSnapshot.IsValid());
+ return this->StateSnapshot.GetExecutionListFile();
+}
+
+bool cmMakefile::ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
+ std::vector<std::string>& outArgs,
+ const char* filename) const
+{
+ std::string efp = this->GetExecutionFilePath();
+ if (!filename) {
+ filename = efp.c_str();
+ }
+ std::vector<cmListFileArgument>::const_iterator i;
+ std::string value;
+ outArgs.reserve(inArgs.size());
+ for (i = inArgs.begin(); i != inArgs.end(); ++i) {
+ // No expansion in a bracket argument.
+ if (i->Delim == cmListFileArgument::Bracket) {
+ outArgs.push_back(i->Value);
+ continue;
+ }
+ // Expand the variables in the argument.
+ value = i->Value;
+ this->ExpandVariablesInString(value, false, false, false, filename,
+ i->Line, false, false);
+
+ // If the argument is quoted, it should be one argument.
+ // Otherwise, it may be a list of arguments.
+ if (i->Delim == cmListFileArgument::Quoted) {
+ outArgs.push_back(value);
+ } else {
+ cmSystemTools::ExpandListArgument(value, outArgs);
+ }
+ }
+ return !cmSystemTools::GetFatalErrorOccured();
+}
+
+bool cmMakefile::ExpandArguments(
+ std::vector<cmListFileArgument> const& inArgs,
+ std::vector<cmExpandedCommandArgument>& outArgs, const char* filename) const
+{
+ std::string efp = this->GetExecutionFilePath();
+ if (!filename) {
+ filename = efp.c_str();
+ }
+ std::vector<cmListFileArgument>::const_iterator i;
+ std::string value;
+ outArgs.reserve(inArgs.size());
+ for (i = inArgs.begin(); i != inArgs.end(); ++i) {
+ // No expansion in a bracket argument.
+ if (i->Delim == cmListFileArgument::Bracket) {
+ outArgs.push_back(cmExpandedCommandArgument(i->Value, true));
+ continue;
+ }
+ // Expand the variables in the argument.
+ value = i->Value;
+ this->ExpandVariablesInString(value, false, false, false, filename,
+ i->Line, false, false);
+
+ // If the argument is quoted, it should be one argument.
+ // Otherwise, it may be a list of arguments.
+ if (i->Delim == cmListFileArgument::Quoted) {
+ outArgs.push_back(cmExpandedCommandArgument(value, true));
+ } else {
+ std::vector<std::string> stringArgs;
+ cmSystemTools::ExpandListArgument(value, stringArgs);
+ for (size_t j = 0; j < stringArgs.size(); ++j) {
+ outArgs.push_back(cmExpandedCommandArgument(stringArgs[j], false));
+ }
+ }
+ }
+ return !cmSystemTools::GetFatalErrorOccured();
+}
+
+void cmMakefile::AddFunctionBlocker(cmFunctionBlocker* fb)
+{
+ if (!this->ExecutionStatusStack.empty()) {
+ // Record the context in which the blocker is created.
+ fb->SetStartingContext(this->GetExecutionContext());
+ }
+
+ this->FunctionBlockers.push_back(fb);
+}
+
+CM_AUTO_PTR<cmFunctionBlocker> cmMakefile::RemoveFunctionBlocker(
+ cmFunctionBlocker* fb, const cmListFileFunction& lff)
+{
+ // Find the function blocker stack barrier for the current scope.
+ // We only remove a blocker whose index is not less than the barrier.
+ FunctionBlockersType::size_type barrier = 0;
+ if (!this->FunctionBlockerBarriers.empty()) {
+ barrier = this->FunctionBlockerBarriers.back();
+ }
+
+ // Search for the function blocker whose scope this command ends.
+ for (FunctionBlockersType::size_type i = this->FunctionBlockers.size();
+ i > barrier; --i) {
+ std::vector<cmFunctionBlocker*>::iterator pos =
+ this->FunctionBlockers.begin() + (i - 1);
+ if (*pos == fb) {
+ // Warn if the arguments do not match, but always remove.
+ if (!(*pos)->ShouldRemove(lff, *this)) {
+ cmListFileContext const& lfc = fb->GetStartingContext();
+ cmListFileContext closingContext =
+ cmListFileContext::FromCommandContext(lff, lfc.FilePath);
+ std::ostringstream e;
+ /* clang-format off */
+ e << "A logical block opening on the line\n"
+ << " " << lfc << "\n"
+ << "closes on the line\n"
+ << " " << closingContext << "\n"
+ << "with mis-matching arguments.";
+ /* clang-format on */
+ this->IssueMessage(cmake::AUTHOR_WARNING, e.str());
+ }
+ cmFunctionBlocker* b = *pos;
+ this->FunctionBlockers.erase(pos);
+ return CM_AUTO_PTR<cmFunctionBlocker>(b);
+ }
+ }
+
+ return CM_AUTO_PTR<cmFunctionBlocker>();
+}
+
+const char* cmMakefile::GetHomeDirectory() const
+{
+ return this->GetCMakeInstance()->GetHomeDirectory();
+}
+
+const char* cmMakefile::GetHomeOutputDirectory() const
+{
+ return this->GetCMakeInstance()->GetHomeOutputDirectory();
+}
+
+void cmMakefile::SetScriptModeFile(const char* scriptfile)
+{
+ this->AddDefinition("CMAKE_SCRIPT_MODE_FILE", scriptfile);
+}
+
+void cmMakefile::SetArgcArgv(const std::vector<std::string>& args)
+{
+ std::ostringstream strStream;
+ strStream << args.size();
+ this->AddDefinition("CMAKE_ARGC", strStream.str().c_str());
+ // this->MarkVariableAsUsed("CMAKE_ARGC");
+
+ for (unsigned int t = 0; t < args.size(); ++t) {
+ std::ostringstream tmpStream;
+ tmpStream << "CMAKE_ARGV" << t;
+ this->AddDefinition(tmpStream.str(), args[t].c_str());
+ // this->MarkVariableAsUsed(tmpStream.str().c_str());
+ }
+}
+
+cmSourceFile* cmMakefile::GetSource(const std::string& sourceName) const
+{
+ cmSourceFileLocation sfl(this, sourceName);
+ for (std::vector<cmSourceFile*>::const_iterator sfi =
+ this->SourceFiles.begin();
+ sfi != this->SourceFiles.end(); ++sfi) {
+ cmSourceFile* sf = *sfi;
+ if (sf->Matches(sfl)) {
+ return sf;
+ }
+ }
+ return CM_NULLPTR;
+}
+
+cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName,
+ bool generated)
+{
+ cmSourceFile* sf = new cmSourceFile(this, sourceName);
+ if (generated) {
+ sf->SetProperty("GENERATED", "1");
+ }
+ this->SourceFiles.push_back(sf);
+ return sf;
+}
+
+cmSourceFile* cmMakefile::GetOrCreateSource(const std::string& sourceName,
+ bool generated)
+{
+ if (cmSourceFile* esf = this->GetSource(sourceName)) {
+ return esf;
+ } else {
+ return this->CreateSource(sourceName, generated);
+ }
+}
+
+void cmMakefile::EnableLanguage(std::vector<std::string> const& lang,
+ bool optional)
+{
+ this->AddDefinition("CMAKE_CFG_INTDIR",
+ this->GetGlobalGenerator()->GetCMakeCFGIntDir());
+ this->GetGlobalGenerator()->EnableLanguage(lang, this, optional);
+}
+
+int cmMakefile::TryCompile(const std::string& srcdir,
+ const std::string& bindir,
+ const std::string& projectName,
+ const std::string& targetName, bool fast,
+ const std::vector<std::string>* cmakeArgs,
+ std::string& output)
+{
+ this->IsSourceFileTryCompile = fast;
+ // does the binary directory exist ? If not create it...
+ if (!cmSystemTools::FileIsDirectory(bindir)) {
+ cmSystemTools::MakeDirectory(bindir.c_str());
+ }
+
+ // change to the tests directory and run cmake
+ // use the cmake object instead of calling cmake
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::ChangeDirectory(bindir);
+
+ // make sure the same generator is used
+ // use this program as the cmake to be run, it should not
+ // be run that way but the cmake object requires a vailid path
+ cmake cm;
+ cm.SetIsInTryCompile(true);
+ cmGlobalGenerator* gg =
+ cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
+ if (!gg) {
+ cmSystemTools::Error(
+ "Internal CMake error, TryCompile bad GlobalGenerator");
+ // return to the original directory
+ cmSystemTools::ChangeDirectory(cwd);
+ this->IsSourceFileTryCompile = false;
+ return 1;
+ }
+ cm.SetGlobalGenerator(gg);
+
+ // do a configure
+ cm.SetHomeDirectory(srcdir);
+ cm.SetHomeOutputDirectory(bindir);
+ cm.SetGeneratorPlatform(this->GetCMakeInstance()->GetGeneratorPlatform());
+ cm.SetGeneratorToolset(this->GetCMakeInstance()->GetGeneratorToolset());
+ cm.LoadCache();
+ if (!gg->IsMultiConfig()) {
+ if (const char* config =
+ this->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION")) {
+ // Tell the single-configuration generator which one to use.
+ // Add this before the user-provided CMake arguments in case
+ // one of the arguments is -DCMAKE_BUILD_TYPE=...
+ cm.AddCacheEntry("CMAKE_BUILD_TYPE", config, "Build configuration",
+ cmState::STRING);
+ }
+ }
+ // if cmake args were provided then pass them in
+ if (cmakeArgs) {
+ // FIXME: Workaround to ignore unused CLI variables in try-compile.
+ //
+ // Ideally we should use SetArgs to honor options like --warn-unused-vars.
+ // However, there is a subtle problem when certain arguments are passed to
+ // a macro wrapping around try_compile or try_run that does not escape
+ // semicolons in its parameters but just passes ${ARGV} or ${ARGN}. In
+ // this case a list argument like "-DVAR=a;b" gets split into multiple
+ // cmake arguments "-DVAR=a" and "b". Currently SetCacheArgs ignores
+ // argument "b" and uses just "-DVAR=a", leading to a subtle bug in that
+ // the try_compile or try_run does not get the proper value of VAR. If we
+ // call SetArgs here then it would treat "b" as the source directory and
+ // cause an error such as "The source directory .../CMakeFiles/CMakeTmp/b
+ // does not exist", thus breaking the try_compile or try_run completely.
+ //
+ // Strictly speaking the bug is in the wrapper macro because the CMake
+ // language has always flattened nested lists and the macro should escape
+ // the semicolons in its arguments before forwarding them. However, this
+ // bug is so subtle that projects typically work anyway, usually because
+ // the value VAR=a is sufficient for the try_compile or try_run to get the
+ // correct result. Calling SetArgs here would break such projects that
+ // previously built. Instead we work around the issue by never reporting
+ // unused arguments and ignoring options such as --warn-unused-vars.
+ cm.SetWarnUnusedCli(false);
+ // cm.SetArgs(*cmakeArgs, true);
+
+ cm.SetCacheArgs(*cmakeArgs);
+ }
+ // to save time we pass the EnableLanguage info directly
+ gg->EnableLanguagesFromGenerator(this->GetGlobalGenerator(), this);
+ if (this->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
+ cm.AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "TRUE", "",
+ cmState::INTERNAL);
+ } else {
+ cm.AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "FALSE", "",
+ cmState::INTERNAL);
+ }
+ if (cm.Configure() != 0) {
+ cmSystemTools::Error(
+ "Internal CMake error, TryCompile configure of cmake failed");
+ // return to the original directory
+ cmSystemTools::ChangeDirectory(cwd);
+ this->IsSourceFileTryCompile = false;
+ return 1;
+ }
+
+ if (cm.Generate() != 0) {
+ cmSystemTools::Error(
+ "Internal CMake error, TryCompile generation of cmake failed");
+ // return to the original directory
+ cmSystemTools::ChangeDirectory(cwd);
+ this->IsSourceFileTryCompile = false;
+ return 1;
+ }
+
+ // finally call the generator to actually build the resulting project
+ int ret = this->GetGlobalGenerator()->TryCompile(
+ srcdir, bindir, projectName, targetName, fast, output, this);
+
+ cmSystemTools::ChangeDirectory(cwd);
+ this->IsSourceFileTryCompile = false;
+ return ret;
+}
+
+bool cmMakefile::GetIsSourceFileTryCompile() const
+{
+ return this->IsSourceFileTryCompile;
+}
+
+cmake* cmMakefile::GetCMakeInstance() const
+{
+ return this->GlobalGenerator->GetCMakeInstance();
+}
+
+cmGlobalGenerator* cmMakefile::GetGlobalGenerator() const
+{
+ return this->GlobalGenerator;
+}
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+cmVariableWatch* cmMakefile::GetVariableWatch() const
+{
+ if (this->GetCMakeInstance() &&
+ this->GetCMakeInstance()->GetVariableWatch()) {
+ return this->GetCMakeInstance()->GetVariableWatch();
+ }
+ return CM_NULLPTR;
+}
+#endif
+
+cmState* cmMakefile::GetState() const
+{
+ return this->GetCMakeInstance()->GetState();
+}
+
+void cmMakefile::DisplayStatus(const char* message, float s) const
+{
+ cmake* cm = this->GetCMakeInstance();
+ if (cm->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
+ // don't output any STATUS message in FIND_PACKAGE_MODE, since they will
+ // directly be fed to the compiler, which will be confused.
+ return;
+ }
+ cm->UpdateProgress(message, s);
+}
+
+std::string cmMakefile::GetModulesFile(const char* filename) const
+{
+ std::string result;
+
+ // We search the module always in CMAKE_ROOT and in CMAKE_MODULE_PATH,
+ // and then decide based on the policy setting which one to return.
+ // See CMP0017 for more details.
+ // The specific problem was that KDE 4.5.0 installs a
+ // FindPackageHandleStandardArgs.cmake which doesn't have the new features
+ // of FPHSA.cmake introduced in CMake 2.8.3 yet, and by setting
+ // CMAKE_MODULE_PATH also e.g. FindZLIB.cmake from cmake included
+ // FPHSA.cmake from kdelibs and not from CMake, and tried to use the
+ // new features, which were not there in the version from kdelibs, and so
+ // failed ("
+ std::string moduleInCMakeRoot;
+ std::string moduleInCMakeModulePath;
+
+ // Always search in CMAKE_MODULE_PATH:
+ const char* cmakeModulePath = this->GetDefinition("CMAKE_MODULE_PATH");
+ if (cmakeModulePath) {
+ std::vector<std::string> modulePath;
+ cmSystemTools::ExpandListArgument(cmakeModulePath, modulePath);
+
+ // Look through the possible module directories.
+ for (std::vector<std::string>::iterator i = modulePath.begin();
+ i != modulePath.end(); ++i) {
+ std::string itempl = *i;
+ cmSystemTools::ConvertToUnixSlashes(itempl);
+ itempl += "/";
+ itempl += filename;
+ if (cmSystemTools::FileExists(itempl.c_str())) {
+ moduleInCMakeModulePath = itempl;
+ break;
+ }
+ }
+ }
+
+ // Always search in the standard modules location.
+ moduleInCMakeRoot = cmSystemTools::GetCMakeRoot();
+ moduleInCMakeRoot += "/Modules/";
+ moduleInCMakeRoot += filename;
+ cmSystemTools::ConvertToUnixSlashes(moduleInCMakeRoot);
+ if (!cmSystemTools::FileExists(moduleInCMakeRoot.c_str())) {
+ moduleInCMakeRoot = "";
+ }
+
+ // Normally, prefer the files found in CMAKE_MODULE_PATH. Only when the file
+ // from which we are being called is located itself in CMAKE_ROOT, then
+ // prefer results from CMAKE_ROOT depending on the policy setting.
+ result = moduleInCMakeModulePath;
+ if (result.empty()) {
+ result = moduleInCMakeRoot;
+ }
+
+ if (!moduleInCMakeModulePath.empty() && !moduleInCMakeRoot.empty()) {
+ const char* currentFile = this->GetDefinition("CMAKE_CURRENT_LIST_FILE");
+ std::string mods = cmSystemTools::GetCMakeRoot() + "/Modules/";
+ if (currentFile && strncmp(currentFile, mods.c_str(), mods.size()) == 0) {
+ switch (this->GetPolicyStatus(cmPolicies::CMP0017)) {
+ case cmPolicies::WARN: {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "File " << currentFile << " includes "
+ << moduleInCMakeModulePath
+ << " (found via CMAKE_MODULE_PATH) which shadows "
+ << moduleInCMakeRoot << ". This may cause errors later on .\n"
+ << cmPolicies::GetPolicyWarning(cmPolicies::CMP0017);
+ /* clang-format on */
+
+ this->IssueMessage(cmake::AUTHOR_WARNING, e.str());
+ // break; // fall through to OLD behaviour
+ }
+ case cmPolicies::OLD:
+ result = moduleInCMakeModulePath;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ result = moduleInCMakeRoot;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+void cmMakefile::ConfigureString(const std::string& input, std::string& output,
+ bool atOnly, bool escapeQuotes) const
+{
+ // Split input to handle one line at a time.
+ std::string::const_iterator lineStart = input.begin();
+ while (lineStart != input.end()) {
+ // Find the end of this line.
+ std::string::const_iterator lineEnd = lineStart;
+ while (lineEnd != input.end() && *lineEnd != '\n') {
+ ++lineEnd;
+ }
+
+ // Copy the line.
+ std::string line(lineStart, lineEnd);
+
+ // Skip the newline character.
+ bool haveNewline = (lineEnd != input.end());
+ if (haveNewline) {
+ ++lineEnd;
+ }
+
+ // Replace #cmakedefine instances.
+ if (this->cmDefineRegex.find(line)) {
+ const char* def = this->GetDefinition(this->cmDefineRegex.match(1));
+ if (!cmSystemTools::IsOff(def)) {
+ cmSystemTools::ReplaceString(line, "#cmakedefine", "#define");
+ output += line;
+ } else {
+ output += "/* #undef ";
+ output += this->cmDefineRegex.match(1);
+ output += " */";
+ }
+ } else if (this->cmDefine01Regex.find(line)) {
+ const char* def = this->GetDefinition(this->cmDefine01Regex.match(1));
+ cmSystemTools::ReplaceString(line, "#cmakedefine01", "#define");
+ output += line;
+ if (!cmSystemTools::IsOff(def)) {
+ output += " 1";
+ } else {
+ output += " 0";
+ }
+ } else {
+ output += line;
+ }
+
+ if (haveNewline) {
+ output += "\n";
+ }
+
+ // Move to the next line.
+ lineStart = lineEnd;
+ }
+
+ // Perform variable replacements.
+ this->ExpandVariablesInString(output, escapeQuotes, true, atOnly, CM_NULLPTR,
+ -1, true, true);
+}
+
+int cmMakefile::ConfigureFile(const char* infile, const char* outfile,
+ bool copyonly, bool atOnly, bool escapeQuotes,
+ const cmNewLineStyle& newLine)
+{
+ int res = 1;
+ if (!this->CanIWriteThisFile(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.");
+ return 0;
+ }
+ std::string soutfile = outfile;
+ std::string sinfile = infile;
+ this->AddCMakeDependFile(sinfile);
+ cmSystemTools::ConvertToUnixSlashes(soutfile);
+
+ // Re-generate if non-temporary outputs are missing.
+ // when we finalize the configuration we will remove all
+ // output files that now don't exist.
+ this->AddCMakeOutputFile(soutfile);
+
+ mode_t perm = 0;
+ cmSystemTools::GetPermissions(sinfile.c_str(), perm);
+ std::string::size_type pos = soutfile.rfind('/');
+ if (pos != std::string::npos) {
+ std::string path = soutfile.substr(0, pos);
+ cmSystemTools::MakeDirectory(path.c_str());
+ }
+
+ if (copyonly) {
+ if (!cmSystemTools::CopyFileIfDifferent(sinfile.c_str(),
+ soutfile.c_str())) {
+ return 0;
+ }
+ } else {
+ std::string newLineCharacters;
+ std::ios::openmode omode = std::ios::out | std::ios::trunc;
+ if (newLine.IsValid()) {
+ newLineCharacters = newLine.GetCharacters();
+ omode |= std::ios::binary;
+ } else {
+ newLineCharacters = "\n";
+ }
+ std::string tempOutputFile = soutfile;
+ 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::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());
+ return 0;
+ }
+
+ cmsys::FStream::BOM bom = cmsys::FStream::ReadBOM(fin);
+ if (bom != cmsys::FStream::BOM_None && bom != cmsys::FStream::BOM_UTF8) {
+ std::ostringstream e;
+ e << "File starts with a Byte-Order-Mark that is not UTF-8:\n "
+ << sinfile;
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return 0;
+ }
+ // rewind to copy BOM to output file
+ fin.seekg(0);
+
+ // now copy input to output and expand variables in the
+ // input file at the same time
+ std::string inLine;
+ std::string outLine;
+ while (cmSystemTools::GetLineFromStream(fin, inLine)) {
+ outLine = "";
+ this->ConfigureString(inLine, outLine, atOnly, escapeQuotes);
+ fout << outLine << newLineCharacters;
+ }
+ // close the files before attempting to copy
+ fin.close();
+ fout.close();
+ if (!cmSystemTools::CopyFileIfDifferent(tempOutputFile.c_str(),
+ soutfile.c_str())) {
+ res = 0;
+ } else {
+ cmSystemTools::SetPermissions(soutfile.c_str(), perm);
+ }
+ cmSystemTools::RemoveFile(tempOutputFile);
+ }
+ return res;
+}
+
+void cmMakefile::SetProperty(const std::string& prop, const char* value)
+{
+ cmListFileBacktrace lfbt = this->GetBacktrace();
+ this->StateSnapshot.GetDirectory().SetProperty(prop, value, lfbt);
+}
+
+void cmMakefile::AppendProperty(const std::string& prop, const char* value,
+ bool asString)
+{
+ cmListFileBacktrace lfbt = this->GetBacktrace();
+ this->StateSnapshot.GetDirectory().AppendProperty(prop, value, asString,
+ lfbt);
+}
+
+const char* cmMakefile::GetProperty(const std::string& prop) const
+{
+ return this->StateSnapshot.GetDirectory().GetProperty(prop);
+}
+
+const char* cmMakefile::GetProperty(const std::string& prop, bool chain) const
+{
+ return this->StateSnapshot.GetDirectory().GetProperty(prop, chain);
+}
+
+bool cmMakefile::GetPropertyAsBool(const std::string& prop) const
+{
+ return cmSystemTools::IsOn(this->GetProperty(prop));
+}
+
+std::vector<std::string> cmMakefile::GetPropertyKeys() const
+{
+ return this->StateSnapshot.GetDirectory().GetPropertyKeys();
+}
+
+cmTarget* cmMakefile::FindLocalNonAliasTarget(const std::string& name) const
+{
+ cmTargets::iterator i = this->Targets.find(name);
+ if (i != this->Targets.end()) {
+ return &i->second;
+ }
+ return CM_NULLPTR;
+}
+
+cmTest* cmMakefile::CreateTest(const std::string& testName)
+{
+ cmTest* test = this->GetTest(testName);
+ if (test) {
+ return test;
+ }
+ test = new cmTest(this);
+ test->SetName(testName);
+ this->Tests[testName] = test;
+ return test;
+}
+
+cmTest* cmMakefile::GetTest(const std::string& testName) const
+{
+ std::map<std::string, cmTest*>::const_iterator mi =
+ this->Tests.find(testName);
+ if (mi != this->Tests.end()) {
+ return mi->second;
+ }
+ return CM_NULLPTR;
+}
+
+void cmMakefile::AddCMakeDependFilesFromUser()
+{
+ std::vector<std::string> deps;
+ if (const char* deps_str = this->GetProperty("CMAKE_CONFIGURE_DEPENDS")) {
+ cmSystemTools::ExpandListArgument(deps_str, deps);
+ }
+ for (std::vector<std::string>::iterator i = deps.begin(); i != deps.end();
+ ++i) {
+ if (cmSystemTools::FileIsFullPath(i->c_str())) {
+ this->AddCMakeDependFile(*i);
+ } else {
+ std::string f = this->GetCurrentSourceDirectory();
+ f += "/";
+ f += *i;
+ this->AddCMakeDependFile(f);
+ }
+ }
+}
+
+std::string cmMakefile::FormatListFileStack() const
+{
+ std::vector<std::string> listFiles;
+ cmState::Snapshot snp = this->StateSnapshot;
+ while (snp.IsValid()) {
+ listFiles.push_back(snp.GetExecutionListFile());
+ snp = snp.GetCallStackParent();
+ }
+ std::reverse(listFiles.begin(), listFiles.end());
+ std::ostringstream tmp;
+ size_t depth = listFiles.size();
+ if (depth > 0) {
+ std::vector<std::string>::const_iterator it = listFiles.end();
+ do {
+ if (depth != listFiles.size()) {
+ tmp << "\n ";
+ }
+ --it;
+ tmp << "[";
+ tmp << depth;
+ tmp << "]\t";
+ tmp << *it;
+ depth--;
+ } while (it != listFiles.begin());
+ }
+ return tmp.str();
+}
+
+void cmMakefile::PushScope()
+{
+ this->StateSnapshot =
+ this->GetState()->CreateVariableScopeSnapshot(this->StateSnapshot);
+ this->PushLoopBlockBarrier();
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ this->GetGlobalGenerator()->GetFileLockPool().PushFunctionScope();
+#endif
+}
+
+void cmMakefile::PopScope()
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ this->GetGlobalGenerator()->GetFileLockPool().PopFunctionScope();
+#endif
+
+ this->PopLoopBlockBarrier();
+
+ this->CheckForUnusedVariables();
+
+ this->PopSnapshot();
+}
+
+void cmMakefile::RaiseScope(const std::string& var, const char* varDef)
+{
+ if (var.empty()) {
+ return;
+ }
+
+ if (!this->StateSnapshot.RaiseScope(var, varDef)) {
+ std::ostringstream m;
+ m << "Cannot set \"" << var << "\": current scope has no parent.";
+ this->IssueMessage(cmake::AUTHOR_WARNING, m.str());
+ }
+}
+
+cmTarget* cmMakefile::AddImportedTarget(const std::string& name,
+ cmState::TargetType type, bool global)
+{
+ // Create the target.
+ CM_AUTO_PTR<cmTarget> target(new cmTarget);
+ target->SetType(type, name);
+ target->MarkAsImported(global);
+ target->SetMakefile(this);
+
+ // Add to the set of available imported targets.
+ this->ImportedTargets[name] = target.get();
+ this->GetGlobalGenerator()->IndexTarget(target.get());
+
+ // Transfer ownership to this cmMakefile object.
+ this->ImportedTargetsOwned.push_back(target.get());
+ return target.release();
+}
+
+cmTarget* cmMakefile::FindTargetToUse(const std::string& name,
+ bool excludeAliases) const
+{
+ // Look for an imported target. These take priority because they
+ // are more local in scope and do not have to be globally unique.
+ TargetMap::const_iterator imported = this->ImportedTargets.find(name);
+ if (imported != this->ImportedTargets.end()) {
+ return imported->second;
+ }
+
+ // Look for a target built in this directory.
+ if (cmTarget* t = this->FindLocalNonAliasTarget(name)) {
+ return t;
+ }
+
+ // Look for a target built in this project.
+ return this->GetGlobalGenerator()->FindTarget(name, excludeAliases);
+}
+
+bool cmMakefile::IsAlias(const std::string& name) const
+{
+ if (this->AliasTargets.find(name) != this->AliasTargets.end()) {
+ return true;
+ }
+ return this->GetGlobalGenerator()->IsAlias(name);
+}
+
+bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg,
+ bool isCustom) const
+{
+ if (this->IsAlias(name)) {
+ std::ostringstream e;
+ e << "cannot create target \"" << name
+ << "\" because an alias with the same name already exists.";
+ msg = e.str();
+ return false;
+ }
+ if (cmTarget* existing = this->FindTargetToUse(name)) {
+ // The name given conflicts with an existing target. Produce an
+ // error in a compatible way.
+ if (existing->IsImported()) {
+ // Imported targets were not supported in previous versions.
+ // This is new code, so we can make it an error.
+ std::ostringstream e;
+ e << "cannot create target \"" << name
+ << "\" because an imported target with the same name already exists.";
+ msg = e.str();
+ return false;
+ } else {
+ // target names must be globally unique
+ switch (this->GetPolicyStatus(cmPolicies::CMP0002)) {
+ case cmPolicies::WARN:
+ this->IssueMessage(
+ cmake::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0002));
+ case cmPolicies::OLD:
+ return true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->IssueMessage(
+ cmake::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0002));
+ return true;
+ case cmPolicies::NEW:
+ break;
+ }
+
+ // The conflict is with a non-imported target.
+ // Allow this if the user has requested support.
+ cmake* cm = this->GetCMakeInstance();
+ if (isCustom && existing->GetType() == cmState::UTILITY &&
+ this != existing->GetMakefile() &&
+ cm->GetState()->GetGlobalPropertyAsBool(
+ "ALLOW_DUPLICATE_CUSTOM_TARGETS")) {
+ return true;
+ }
+
+ // Produce an error that tells the user how to work around the
+ // problem.
+ std::ostringstream e;
+ e << "cannot create target \"" << name
+ << "\" because another target with the same name already exists. "
+ << "The existing target is ";
+ switch (existing->GetType()) {
+ case cmState::EXECUTABLE:
+ e << "an executable ";
+ break;
+ case cmState::STATIC_LIBRARY:
+ e << "a static library ";
+ break;
+ case cmState::SHARED_LIBRARY:
+ e << "a shared library ";
+ break;
+ case cmState::MODULE_LIBRARY:
+ e << "a module library ";
+ break;
+ case cmState::UTILITY:
+ e << "a custom target ";
+ break;
+ case cmState::INTERFACE_LIBRARY:
+ e << "an interface library ";
+ break;
+ default:
+ break;
+ }
+ e << "created in source directory \""
+ << existing->GetMakefile()->GetCurrentSourceDirectory() << "\". "
+ << "See documentation for policy CMP0002 for more details.";
+ msg = e.str();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmMakefile::EnforceUniqueDir(const std::string& srcPath,
+ const std::string& binPath) const
+{
+ // Make sure the binary directory is unique.
+ cmGlobalGenerator* gg = this->GetGlobalGenerator();
+ if (gg->BinaryDirectoryIsNew(binPath)) {
+ return true;
+ }
+ std::ostringstream e;
+ switch (this->GetPolicyStatus(cmPolicies::CMP0013)) {
+ case cmPolicies::WARN:
+ // Print the warning.
+ /* clang-format off */
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0013)
+ << "\n"
+ << "The binary directory\n"
+ << " " << binPath << "\n"
+ << "is already used to build a source directory. "
+ << "This command uses it to build source directory\n"
+ << " " << srcPath << "\n"
+ << "which can generate conflicting build files. "
+ << "CMake does not support this use case but it used "
+ << "to work accidentally and is being allowed for "
+ << "compatibility.";
+ /* clang-format on */
+ this->IssueMessage(cmake::AUTHOR_WARNING, e.str());
+ case cmPolicies::OLD:
+ // OLD behavior does not warn.
+ return true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0013) << "\n";
+ case cmPolicies::NEW:
+ // NEW behavior prints the error.
+ /* clang-format off */
+ e << "The binary directory\n"
+ << " " << binPath << "\n"
+ << "is already used to build a source directory. "
+ << "It cannot be used to build source directory\n"
+ << " " << srcPath << "\n"
+ << "Specify a unique binary directory name.";
+ /* clang-format on */
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ break;
+ }
+
+ return false;
+}
+
+void cmMakefile::AddQtUiFileWithOptions(cmSourceFile* sf)
+{
+ this->QtUiFilesWithOptions.push_back(sf);
+}
+
+std::vector<cmSourceFile*> cmMakefile::GetQtUiFilesWithOptions() const
+{
+ return this->QtUiFilesWithOptions;
+}
+
+static std::string const matchVariables[] = {
+ "CMAKE_MATCH_0", "CMAKE_MATCH_1", "CMAKE_MATCH_2", "CMAKE_MATCH_3",
+ "CMAKE_MATCH_4", "CMAKE_MATCH_5", "CMAKE_MATCH_6", "CMAKE_MATCH_7",
+ "CMAKE_MATCH_8", "CMAKE_MATCH_9"
+};
+
+static std::string const nMatchesVariable = "CMAKE_MATCH_COUNT";
+
+void cmMakefile::ClearMatches()
+{
+ const char* nMatchesStr = this->GetDefinition(nMatchesVariable);
+ if (!nMatchesStr) {
+ return;
+ }
+ int nMatches = atoi(nMatchesStr);
+ for (int i = 0; i <= nMatches; i++) {
+ std::string const& var = matchVariables[i];
+ std::string const& s = this->GetSafeDefinition(var);
+ if (!s.empty()) {
+ this->AddDefinition(var, "");
+ this->MarkVariableAsUsed(var);
+ }
+ }
+ this->AddDefinition(nMatchesVariable, "0");
+ this->MarkVariableAsUsed(nMatchesVariable);
+}
+
+void cmMakefile::StoreMatches(cmsys::RegularExpression& re)
+{
+ char highest = 0;
+ for (int i = 0; i < 10; i++) {
+ std::string const& m = re.match(i);
+ if (!m.empty()) {
+ std::string const& var = matchVariables[i];
+ this->AddDefinition(var, m.c_str());
+ this->MarkVariableAsUsed(var);
+ highest = static_cast<char>('0' + i);
+ }
+ }
+ char nMatches[] = { highest, '\0' };
+ this->AddDefinition(nMatchesVariable, nMatches);
+ this->MarkVariableAsUsed(nMatchesVariable);
+}
+
+cmState::Snapshot cmMakefile::GetStateSnapshot() const
+{
+ return this->StateSnapshot;
+}
+
+const char* cmMakefile::GetDefineFlagsCMP0059() const
+{
+ return this->DefineFlagsOrig.c_str();
+}
+
+cmPolicies::PolicyStatus cmMakefile::GetPolicyStatus(
+ cmPolicies::PolicyID id) const
+{
+ return this->StateSnapshot.GetPolicy(id);
+}
+
+bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var)
+{
+ // Check for an explicit CMAKE_POLICY_WARNING_CMP<NNNN> setting.
+ if (!var.empty()) {
+ if (const char* val = this->GetDefinition(var)) {
+ return cmSystemTools::IsOn(val);
+ }
+ }
+ // Enable optional policy warnings with --debug-output, --trace,
+ // or --trace-expand.
+ cmake* cm = this->GetCMakeInstance();
+ return cm->GetDebugOutput() || cm->GetTrace();
+}
+
+bool cmMakefile::SetPolicy(const char* id, cmPolicies::PolicyStatus status)
+{
+ cmPolicies::PolicyID pid;
+ if (!cmPolicies::GetPolicyID(id, /* out */ pid)) {
+ std::ostringstream e;
+ e << "Policy \"" << id << "\" is not known to this version of CMake.";
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ return this->SetPolicy(pid, status);
+}
+
+bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
+ cmPolicies::PolicyStatus status)
+{
+ // A REQUIRED_ALWAYS policy may be set only to NEW.
+ if (status != cmPolicies::NEW &&
+ cmPolicies::GetPolicyStatus(id) == cmPolicies::REQUIRED_ALWAYS) {
+ std::string msg = cmPolicies::GetRequiredAlwaysPolicyError(id);
+ this->IssueMessage(cmake::FATAL_ERROR, msg);
+ return false;
+ }
+
+ this->StateSnapshot.SetPolicy(id, status);
+ return true;
+}
+
+cmMakefile::PolicyPushPop::PolicyPushPop(cmMakefile* m)
+ : Makefile(m)
+{
+ this->Makefile->PushPolicy();
+}
+
+cmMakefile::PolicyPushPop::~PolicyPushPop()
+{
+ this->Makefile->PopPolicy();
+}
+
+void cmMakefile::PushPolicy(bool weak, cmPolicies::PolicyMap const& pm)
+{
+ this->StateSnapshot.PushPolicy(pm, weak);
+}
+
+void cmMakefile::PopPolicy()
+{
+ if (!this->StateSnapshot.PopPolicy()) {
+ this->IssueMessage(cmake::FATAL_ERROR,
+ "cmake_policy POP without matching PUSH");
+ }
+}
+
+void cmMakefile::PopSnapshot(bool reportError)
+{
+ // cmState::Snapshot manages nested policy scopes within it.
+ // Since the scope corresponding to the snapshot is closing,
+ // reject any still-open nested policy scopes with an error.
+ while (!this->StateSnapshot.CanPopPolicyScope()) {
+ if (reportError) {
+ this->IssueMessage(cmake::FATAL_ERROR,
+ "cmake_policy PUSH without matching POP");
+ reportError = false;
+ }
+ this->PopPolicy();
+ }
+
+ this->StateSnapshot = this->GetState()->Pop(this->StateSnapshot);
+ assert(this->StateSnapshot.IsValid());
+}
+
+bool cmMakefile::SetPolicyVersion(const char* version)
+{
+ return cmPolicies::ApplyPolicyVersion(this, version);
+}
+
+bool cmMakefile::HasCMP0054AlreadyBeenReported(
+ cmListFileContext const& context) const
+{
+ return !this->CMP0054ReportedIds.insert(context).second;
+}
+
+void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm)
+{
+ /* Record the setting of every policy. */
+ typedef cmPolicies::PolicyID PolicyID;
+ for (PolicyID pid = cmPolicies::CMP0000; pid != cmPolicies::CMPCOUNT;
+ pid = PolicyID(pid + 1)) {
+ pm.Set(pid, this->GetPolicyStatus(pid));
+ }
+}
+
+bool cmMakefile::IgnoreErrorsCMP0061() const
+{
+ bool ignoreErrors = true;
+ switch (this->GetPolicyStatus(cmPolicies::CMP0061)) {
+ case cmPolicies::WARN:
+ // No warning for this policy!
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ ignoreErrors = false;
+ break;
+ }
+ return ignoreErrors;
+}
+
+#define FEATURE_STRING(F) , #F
+static const char* const C_FEATURES[] = { CM_NULLPTR FOR_EACH_C_FEATURE(
+ FEATURE_STRING) };
+
+static const char* const CXX_FEATURES[] = { CM_NULLPTR FOR_EACH_CXX_FEATURE(
+ FEATURE_STRING) };
+#undef FEATURE_STRING
+
+static const char* const C_STANDARDS[] = { "90", "99", "11" };
+static const char* const CXX_STANDARDS[] = { "98", "11", "14" };
+
+bool cmMakefile::AddRequiredTargetFeature(cmTarget* target,
+ const std::string& feature,
+ std::string* error) const
+{
+ if (cmGeneratorExpression::Find(feature) != std::string::npos) {
+ target->AppendProperty("COMPILE_FEATURES", feature.c_str());
+ return true;
+ }
+
+ std::string lang;
+ if (!this->CompileFeatureKnown(target, feature, lang, error)) {
+ return false;
+ }
+
+ const char* features = this->CompileFeaturesAvailable(lang, error);
+ if (!features) {
+ return false;
+ }
+
+ std::vector<std::string> availableFeatures;
+ cmSystemTools::ExpandListArgument(features, availableFeatures);
+ if (std::find(availableFeatures.begin(), availableFeatures.end(), feature) ==
+ availableFeatures.end()) {
+ std::ostringstream e;
+ e << "The compiler feature \"" << feature << "\" is not known to " << lang
+ << " compiler\n\""
+ << this->GetDefinition("CMAKE_" + lang + "_COMPILER_ID")
+ << "\"\nversion "
+ << this->GetDefinition("CMAKE_" + lang + "_COMPILER_VERSION") << ".";
+ if (error) {
+ *error = e.str();
+ } else {
+ this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
+ this->Backtrace);
+ }
+ return false;
+ }
+
+ target->AppendProperty("COMPILE_FEATURES", feature.c_str());
+
+ return lang == "C"
+ ? this->AddRequiredTargetCFeature(target, feature, error)
+ : this->AddRequiredTargetCxxFeature(target, feature, error);
+}
+
+bool cmMakefile::CompileFeatureKnown(cmTarget const* target,
+ const std::string& feature,
+ std::string& lang,
+ std::string* error) const
+{
+ assert(cmGeneratorExpression::Find(feature) == std::string::npos);
+
+ bool isCFeature =
+ std::find_if(cmArrayBegin(C_FEATURES) + 1, cmArrayEnd(C_FEATURES),
+ cmStrCmp(feature)) != cmArrayEnd(C_FEATURES);
+ if (isCFeature) {
+ lang = "C";
+ return true;
+ }
+ bool isCxxFeature =
+ std::find_if(cmArrayBegin(CXX_FEATURES) + 1, cmArrayEnd(CXX_FEATURES),
+ cmStrCmp(feature)) != cmArrayEnd(CXX_FEATURES);
+ if (isCxxFeature) {
+ lang = "CXX";
+ return true;
+ }
+ std::ostringstream e;
+ if (error) {
+ e << "specified";
+ } else {
+ e << "Specified";
+ }
+ e << " unknown feature \"" << feature << "\" for "
+ "target \""
+ << target->GetName() << "\".";
+ if (error) {
+ *error = e.str();
+ } else {
+ this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
+ this->Backtrace);
+ }
+ return false;
+}
+
+const char* cmMakefile::CompileFeaturesAvailable(const std::string& lang,
+ std::string* error) const
+{
+ const char* featuresKnown =
+ this->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES");
+
+ if (!featuresKnown || !*featuresKnown) {
+ std::ostringstream e;
+ if (error) {
+ e << "no";
+ } else {
+ e << "No";
+ }
+ e << " known features for " << lang << " compiler\n\""
+ << this->GetDefinition("CMAKE_" + lang + "_COMPILER_ID")
+ << "\"\nversion "
+ << this->GetDefinition("CMAKE_" + lang + "_COMPILER_VERSION") << ".";
+ if (error) {
+ *error = e.str();
+ } else {
+ this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
+ this->Backtrace);
+ }
+ return CM_NULLPTR;
+ }
+ return featuresKnown;
+}
+
+bool cmMakefile::HaveStandardAvailable(cmTarget const* target,
+ std::string const& lang,
+ const std::string& feature) const
+{
+ return lang == "C" ? this->HaveCStandardAvailable(target, feature)
+ : this->HaveCxxStandardAvailable(target, feature);
+}
+
+bool cmMakefile::HaveCStandardAvailable(cmTarget const* target,
+ const std::string& feature) const
+{
+ const char* defaultCStandard =
+ this->GetDefinition("CMAKE_C_STANDARD_DEFAULT");
+ if (!defaultCStandard) {
+ std::ostringstream e;
+ e << "CMAKE_C_STANDARD_DEFAULT is not set. COMPILE_FEATURES support "
+ "not fully configured for this compiler.";
+ this->IssueMessage(cmake::INTERNAL_ERROR, e.str());
+ // Return true so the caller does not try to lookup the default standard.
+ return true;
+ }
+ if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS),
+ cmStrCmp(defaultCStandard)) == cmArrayEnd(C_STANDARDS)) {
+ std::ostringstream e;
+ e << "The CMAKE_C_STANDARD_DEFAULT variable contains an "
+ "invalid value: \""
+ << defaultCStandard << "\".";
+ this->IssueMessage(cmake::INTERNAL_ERROR, e.str());
+ return false;
+ }
+
+ bool needC90 = false;
+ bool needC99 = false;
+ bool needC11 = false;
+
+ this->CheckNeededCLanguage(feature, needC90, needC99, needC11);
+
+ const char* existingCStandard = target->GetProperty("C_STANDARD");
+ if (!existingCStandard) {
+ existingCStandard = defaultCStandard;
+ }
+
+ if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS),
+ cmStrCmp(existingCStandard)) == cmArrayEnd(C_STANDARDS)) {
+ std::ostringstream e;
+ e << "The C_STANDARD property on target \"" << target->GetName()
+ << "\" contained an invalid value: \"" << existingCStandard << "\".";
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ const char* const* existingCIt = existingCStandard
+ ? std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS),
+ cmStrCmp(existingCStandard))
+ : cmArrayEnd(C_STANDARDS);
+
+ if (needC11 && existingCStandard &&
+ existingCIt < std::find_if(cmArrayBegin(C_STANDARDS),
+ cmArrayEnd(C_STANDARDS), cmStrCmp("11"))) {
+ return false;
+ } else if (needC99 && existingCStandard &&
+ existingCIt < std::find_if(cmArrayBegin(C_STANDARDS),
+ cmArrayEnd(C_STANDARDS),
+ cmStrCmp("99"))) {
+ return false;
+ } else if (needC90 && existingCStandard &&
+ existingCIt < std::find_if(cmArrayBegin(C_STANDARDS),
+ cmArrayEnd(C_STANDARDS),
+ cmStrCmp("90"))) {
+ return false;
+ }
+ return true;
+}
+
+bool cmMakefile::IsLaterStandard(std::string const& lang,
+ std::string const& lhs,
+ std::string const& rhs)
+{
+ if (lang == "C") {
+ const char* const* rhsIt = std::find_if(
+ cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS), cmStrCmp(rhs));
+
+ return std::find_if(rhsIt, cmArrayEnd(C_STANDARDS), cmStrCmp(lhs)) !=
+ cmArrayEnd(C_STANDARDS);
+ }
+ const char* const* rhsIt = std::find_if(
+ cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), cmStrCmp(rhs));
+
+ return std::find_if(rhsIt, cmArrayEnd(CXX_STANDARDS), cmStrCmp(lhs)) !=
+ cmArrayEnd(CXX_STANDARDS);
+}
+
+bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target,
+ const std::string& feature) const
+{
+ const char* defaultCxxStandard =
+ this->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT");
+ if (!defaultCxxStandard) {
+ std::ostringstream e;
+ e << "CMAKE_CXX_STANDARD_DEFAULT is not set. COMPILE_FEATURES support "
+ "not fully configured for this compiler.";
+ this->IssueMessage(cmake::INTERNAL_ERROR, e.str());
+ // Return true so the caller does not try to lookup the default standard.
+ return true;
+ }
+ if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp(defaultCxxStandard)) ==
+ cmArrayEnd(CXX_STANDARDS)) {
+ std::ostringstream e;
+ e << "The CMAKE_CXX_STANDARD_DEFAULT variable contains an "
+ "invalid value: \""
+ << defaultCxxStandard << "\".";
+ this->IssueMessage(cmake::INTERNAL_ERROR, e.str());
+ return false;
+ }
+
+ bool needCxx98 = false;
+ bool needCxx11 = false;
+ bool needCxx14 = false;
+ this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14);
+
+ const char* existingCxxStandard = target->GetProperty("CXX_STANDARD");
+ if (!existingCxxStandard) {
+ existingCxxStandard = defaultCxxStandard;
+ }
+
+ if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp(existingCxxStandard)) ==
+ cmArrayEnd(CXX_STANDARDS)) {
+ std::ostringstream e;
+ e << "The CXX_STANDARD property on target \"" << target->GetName()
+ << "\" contained an invalid value: \"" << existingCxxStandard << "\".";
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ const char* const* existingCxxIt = existingCxxStandard
+ ? std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp(existingCxxStandard))
+ : cmArrayEnd(CXX_STANDARDS);
+
+ if (needCxx11 &&
+ existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS),
+ cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp("11"))) {
+ return false;
+ } else if (needCxx98 &&
+ existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS),
+ cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp("98"))) {
+ return false;
+ }
+ return true;
+}
+
+void cmMakefile::CheckNeededCxxLanguage(const std::string& feature,
+ bool& needCxx98, bool& needCxx11,
+ bool& needCxx14) const
+{
+ if (const char* propCxx98 =
+ this->GetDefinition("CMAKE_CXX98_COMPILE_FEATURES")) {
+ std::vector<std::string> props;
+ cmSystemTools::ExpandListArgument(propCxx98, props);
+ needCxx98 = std::find(props.begin(), props.end(), feature) != props.end();
+ }
+ if (const char* propCxx11 =
+ this->GetDefinition("CMAKE_CXX11_COMPILE_FEATURES")) {
+ std::vector<std::string> props;
+ cmSystemTools::ExpandListArgument(propCxx11, props);
+ needCxx11 = std::find(props.begin(), props.end(), feature) != props.end();
+ }
+ if (const char* propCxx14 =
+ this->GetDefinition("CMAKE_CXX14_COMPILE_FEATURES")) {
+ std::vector<std::string> props;
+ cmSystemTools::ExpandListArgument(propCxx14, props);
+ needCxx14 = std::find(props.begin(), props.end(), feature) != props.end();
+ }
+}
+
+bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target,
+ const std::string& feature,
+ std::string* error) const
+{
+ bool needCxx98 = false;
+ bool needCxx11 = false;
+ bool needCxx14 = false;
+
+ this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14);
+
+ const char* existingCxxStandard = target->GetProperty("CXX_STANDARD");
+ if (existingCxxStandard) {
+ if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp(existingCxxStandard)) ==
+ cmArrayEnd(CXX_STANDARDS)) {
+ std::ostringstream e;
+ e << "The CXX_STANDARD property on target \"" << target->GetName()
+ << "\" contained an invalid value: \"" << existingCxxStandard << "\".";
+ if (error) {
+ *error = e.str();
+ } else {
+ this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
+ this->Backtrace);
+ }
+ return false;
+ }
+ }
+ const char* const* existingCxxIt = existingCxxStandard
+ ? std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp(existingCxxStandard))
+ : cmArrayEnd(CXX_STANDARDS);
+
+ bool setCxx98 = needCxx98 && !existingCxxStandard;
+ bool setCxx11 = needCxx11 && !existingCxxStandard;
+ bool setCxx14 = needCxx14 && !existingCxxStandard;
+
+ if (needCxx14 && existingCxxStandard &&
+ existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS),
+ cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp("14"))) {
+ setCxx14 = true;
+ } else if (needCxx11 && existingCxxStandard &&
+ existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS),
+ cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp("11"))) {
+ setCxx11 = true;
+ } else if (needCxx98 && existingCxxStandard &&
+ existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS),
+ cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp("98"))) {
+ setCxx98 = true;
+ }
+
+ if (setCxx14) {
+ target->SetProperty("CXX_STANDARD", "14");
+ } else if (setCxx11) {
+ target->SetProperty("CXX_STANDARD", "11");
+ } else if (setCxx98) {
+ target->SetProperty("CXX_STANDARD", "98");
+ }
+ return true;
+}
+
+void cmMakefile::CheckNeededCLanguage(const std::string& feature,
+ bool& needC90, bool& needC99,
+ bool& needC11) const
+{
+ if (const char* propC90 =
+ this->GetDefinition("CMAKE_C90_COMPILE_FEATURES")) {
+ std::vector<std::string> props;
+ cmSystemTools::ExpandListArgument(propC90, props);
+ needC90 = std::find(props.begin(), props.end(), feature) != props.end();
+ }
+ if (const char* propC99 =
+ this->GetDefinition("CMAKE_C99_COMPILE_FEATURES")) {
+ std::vector<std::string> props;
+ cmSystemTools::ExpandListArgument(propC99, props);
+ needC99 = std::find(props.begin(), props.end(), feature) != props.end();
+ }
+ if (const char* propC11 =
+ this->GetDefinition("CMAKE_C11_COMPILE_FEATURES")) {
+ std::vector<std::string> props;
+ cmSystemTools::ExpandListArgument(propC11, props);
+ needC11 = std::find(props.begin(), props.end(), feature) != props.end();
+ }
+}
+
+bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target,
+ const std::string& feature,
+ std::string* error) const
+{
+ bool needC90 = false;
+ bool needC99 = false;
+ bool needC11 = false;
+
+ this->CheckNeededCLanguage(feature, needC90, needC99, needC11);
+
+ const char* existingCStandard = target->GetProperty("C_STANDARD");
+ if (existingCStandard) {
+ if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS),
+ cmStrCmp(existingCStandard)) == cmArrayEnd(C_STANDARDS)) {
+ std::ostringstream e;
+ e << "The C_STANDARD property on target \"" << target->GetName()
+ << "\" contained an invalid value: \"" << existingCStandard << "\".";
+ if (error) {
+ *error = e.str();
+ } else {
+ this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
+ this->Backtrace);
+ }
+ return false;
+ }
+ }
+ const char* const* existingCIt = existingCStandard
+ ? std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS),
+ cmStrCmp(existingCStandard))
+ : cmArrayEnd(C_STANDARDS);
+
+ bool setC90 = needC90 && !existingCStandard;
+ bool setC99 = needC99 && !existingCStandard;
+ bool setC11 = needC11 && !existingCStandard;
+
+ if (needC11 && existingCStandard &&
+ existingCIt < std::find_if(cmArrayBegin(C_STANDARDS),
+ cmArrayEnd(C_STANDARDS), cmStrCmp("11"))) {
+ setC11 = true;
+ } else if (needC99 && existingCStandard &&
+ existingCIt < std::find_if(cmArrayBegin(C_STANDARDS),
+ cmArrayEnd(C_STANDARDS),
+ cmStrCmp("99"))) {
+ setC99 = true;
+ } else if (needC90 && existingCStandard &&
+ existingCIt < std::find_if(cmArrayBegin(C_STANDARDS),
+ cmArrayEnd(C_STANDARDS),
+ cmStrCmp("90"))) {
+ setC90 = true;
+ }
+
+ if (setC11) {
+ target->SetProperty("C_STANDARD", "11");
+ } else if (setC99) {
+ target->SetProperty("C_STANDARD", "99");
+ } else if (setC90) {
+ target->SetProperty("C_STANDARD", "90");
+ }
+ return true;
+}
+
+cmMakefile::FunctionPushPop::FunctionPushPop(cmMakefile* mf,
+ const std::string& fileName,
+ cmPolicies::PolicyMap const& pm)
+ : Makefile(mf)
+ , ReportError(true)
+{
+ this->Makefile->PushFunctionScope(fileName, pm);
+}
+
+cmMakefile::FunctionPushPop::~FunctionPushPop()
+{
+ this->Makefile->PopFunctionScope(this->ReportError);
+}
+
+cmMakefile::MacroPushPop::MacroPushPop(cmMakefile* mf,
+ const std::string& fileName,
+ const cmPolicies::PolicyMap& pm)
+ : Makefile(mf)
+ , ReportError(true)
+{
+ this->Makefile->PushMacroScope(fileName, pm);
+}
+
+cmMakefile::MacroPushPop::~MacroPushPop()
+{
+ this->Makefile->PopMacroScope(this->ReportError);
+}
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
new file mode 100644
index 0000000..d07b4e1
--- /dev/null
+++ b/Source/cmMakefile.h
@@ -0,0 +1,960 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmMakefile_h
+#define cmMakefile_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmAlgorithms.h"
+#include "cmExecutionStatus.h"
+#include "cmExpandedCommandArgument.h"
+#include "cmListFileCache.h"
+#include "cmNewLineStyle.h"
+#include "cmState.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmSourceGroup.h"
+#endif
+
+#include <cm_auto_ptr.hxx>
+#include <cmsys/RegularExpression.hxx>
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+#include <unordered_map>
+#else
+#include <cmsys/hash_map.hxx>
+#endif
+#endif
+
+#include <stack>
+
+class cmFunctionBlocker;
+class cmCommand;
+class cmInstallGenerator;
+class cmSourceFile;
+class cmTest;
+class cmTestGenerator;
+class cmVariableWatch;
+class cmake;
+class cmMakefileCall;
+class cmCMakePolicyCommand;
+class cmGeneratorExpressionEvaluationFile;
+class cmExportBuildFileGenerator;
+
+/** \class cmMakefile
+ * \brief Process the input CMakeLists.txt file.
+ *
+ * Process and store into memory the input CMakeLists.txt file.
+ * Each CMakeLists.txt file is parsed and the commands found there
+ * are added into the build process.
+ */
+class cmMakefile
+{
+public:
+ /* Mark a variable as used */
+ void MarkVariableAsUsed(const std::string& var);
+ /* return true if a variable has been initialized */
+ bool VariableInitialized(const std::string&) const;
+
+ /**
+ * Construct an empty makefile.
+ */
+ cmMakefile(cmGlobalGenerator* globalGenerator,
+ const cmState::Snapshot& snapshot);
+
+ /**
+ * Destructor.
+ */
+ ~cmMakefile();
+
+ bool ReadListFile(const char* filename);
+
+ bool ReadDependentFile(const char* filename, bool noPolicyScope = true);
+
+ bool ProcessBuildsystemFile(const char* filename);
+
+ /**
+ * Add a function blocker to this makefile
+ */
+ void AddFunctionBlocker(cmFunctionBlocker* fb);
+
+ /// @return whether we are processing the top CMakeLists.txt file.
+ bool IsRootMakefile() const;
+
+ /**
+ * Remove the function blocker whose scope ends with the given command.
+ * This returns ownership of the function blocker object.
+ */
+ CM_AUTO_PTR<cmFunctionBlocker> RemoveFunctionBlocker(
+ cmFunctionBlocker* fb, const cmListFileFunction& lff);
+
+ /**
+ * Try running cmake and building a file. This is used for dynalically
+ * loaded commands, not as part of the usual build process.
+ */
+ int TryCompile(const std::string& srcdir, const std::string& bindir,
+ const std::string& projectName, const std::string& targetName,
+ bool fast, const std::vector<std::string>* cmakeArgs,
+ std::string& output);
+
+ bool GetIsSourceFileTryCompile() const;
+
+ /**
+ * Help enforce global target name uniqueness.
+ */
+ bool EnforceUniqueName(std::string const& name, std::string& msg,
+ bool isCustom = false) const;
+
+ /**
+ * Perform FinalPass, Library dependency analysis etc before output of the
+ * makefile.
+ */
+ void ConfigureFinalPass();
+
+ /**
+ * run the final pass on all commands.
+ */
+ void FinalPass();
+
+ /** Add a custom command to the build. */
+ void AddCustomCommandToTarget(const std::string& target,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines,
+ cmTarget::CustomCommandType type,
+ const char* comment, const char* workingDir,
+ bool escapeOldStyle = true,
+ bool uses_terminal = false);
+ cmSourceFile* AddCustomCommandToOutput(
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ 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);
+ 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);
+ void AddCustomCommandOldStyle(const std::string& target,
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& depends,
+ const std::string& source,
+ const cmCustomCommandLines& commandLines,
+ const char* comment);
+
+ /**
+ * Add a define flag to the build.
+ */
+ void AddDefineFlag(const char* definition);
+ void RemoveDefineFlag(const char* definition);
+ void AddCompileOption(const char* option);
+
+ /** Create a new imported target with the name and type given. */
+ cmTarget* AddImportedTarget(const std::string& name,
+ cmState::TargetType type, bool global);
+
+ cmTarget* AddNewTarget(cmState::TargetType type, const std::string& name);
+
+ /**
+ * Add an executable to the build.
+ */
+ cmTarget* AddExecutable(const char* exename,
+ const std::vector<std::string>& srcs,
+ bool excludeFromAll = false);
+
+ /**
+ * Add a utility to the build. A utiltity target is a command that
+ * is run every time the target is built.
+ */
+ cmTarget* AddUtilityCommand(
+ const std::string& utilityName, bool excludeFromAll,
+ const std::vector<std::string>& depends, const char* workingDirectory,
+ const char* command, const char* arg1 = CM_NULLPTR,
+ const char* arg2 = CM_NULLPTR, const char* arg3 = CM_NULLPTR,
+ const char* arg4 = CM_NULLPTR);
+ cmTarget* AddUtilityCommand(
+ const std::string& utilityName, bool excludeFromAll,
+ const char* workingDirectory, const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, bool escapeOldStyle = true,
+ const char* comment = CM_NULLPTR, bool uses_terminal = false);
+ cmTarget* AddUtilityCommand(
+ const std::string& utilityName, 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 = CM_NULLPTR, bool uses_terminal = false);
+
+ /**
+ * Add a link library to the build.
+ */
+ void AddLinkLibrary(const std::string&);
+ void AddLinkLibrary(const std::string&, cmTargetLinkLibraryType type);
+ void AddLinkLibraryForTarget(const std::string& tgt, const std::string&,
+ cmTargetLinkLibraryType type);
+ void AddLinkDirectoryForTarget(const std::string& tgt, const std::string& d);
+
+ /**
+ * Add a subdirectory to the build.
+ */
+ void AddSubDirectory(const std::string& fullSrcDir,
+ const std::string& fullBinDir, bool excludeFromAll,
+ bool immediate);
+
+ void Configure();
+
+ /**
+ * Configure a subdirectory
+ */
+ void ConfigureSubDirectory(cmMakefile* mf);
+
+ /**
+ * Add an include directory to the build.
+ */
+ void AddIncludeDirectories(const std::vector<std::string>& incs,
+ bool before = false);
+
+ /**
+ * Add a variable definition to the build. This variable
+ * 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.
+ void AddCacheDefinition(const std::string& name, const char* value,
+ const char* doc, cmState::CacheEntryType type,
+ bool force = false);
+
+ /**
+ * Add bool variable definition to the build.
+ */
+ void AddDefinition(const std::string& name, bool);
+
+ /**
+ * Remove a variable definition from the build. This is not valid
+ * for cache entries, and will only affect the current makefile.
+ */
+ void RemoveDefinition(const std::string& name);
+ ///! Remove a definition from the cache.
+ void RemoveCacheDefinition(const std::string& name);
+
+ /**
+ * Specify the name of the project for this build.
+ */
+ void SetProjectName(std::string const& name);
+
+ /** Get the configurations to be generated. */
+ std::string GetConfigurations(std::vector<std::string>& configs,
+ bool single = true) const;
+
+ /**
+ * Set the name of the library.
+ */
+ cmTarget* AddLibrary(const std::string& libname, cmState::TargetType type,
+ const std::vector<std::string>& srcs,
+ bool excludeFromAll = false);
+ void AddAlias(const std::string& libname, const std::string& tgt);
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ /**
+ * Add a root source group for consideration when adding a new source.
+ */
+ void AddSourceGroup(const std::string& name, const char* regex = CM_NULLPTR);
+
+ /**
+ * Add a source group for consideration when adding a new source.
+ * name is tokenized.
+ */
+ void AddSourceGroup(const std::vector<std::string>& name,
+ const char* regex = CM_NULLPTR);
+
+#endif
+
+ //@{
+ /**
+ * Set, Push, Pop policy values for CMake.
+ */
+ bool SetPolicy(cmPolicies::PolicyID id, cmPolicies::PolicyStatus status);
+ bool SetPolicy(const char* id, cmPolicies::PolicyStatus status);
+ cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id) const;
+ bool SetPolicyVersion(const char* version);
+ void RecordPolicies(cmPolicies::PolicyMap& pm);
+ //@}
+
+ /** Helper class to push and pop policies automatically. */
+ class PolicyPushPop
+ {
+ public:
+ PolicyPushPop(cmMakefile* m);
+ ~PolicyPushPop();
+
+ private:
+ cmMakefile* Makefile;
+ };
+ friend class PolicyPushPop;
+
+ /**
+ * Determine if the given context, name pair has already been reported
+ * in context of CMP0054.
+ */
+ bool HasCMP0054AlreadyBeenReported(const cmListFileContext& context) const;
+
+ bool IgnoreErrorsCMP0061() const;
+
+ const char* GetHomeDirectory() const;
+ const char* GetHomeOutputDirectory() const;
+
+ /**
+ * Set CMAKE_SCRIPT_MODE_FILE variable when running a -P script.
+ */
+ void SetScriptModeFile(const char* scriptfile);
+
+ /**
+ * Set CMAKE_ARGC, CMAKE_ARGV0 ... variables.
+ */
+ void SetArgcArgv(const std::vector<std::string>& args);
+
+ const char* GetCurrentSourceDirectory() const;
+ const char* GetCurrentBinaryDirectory() const;
+
+ //@}
+
+ /**
+ * Set a regular expression that include files must match
+ * in order to be considered as part of the depend information.
+ */
+ void SetIncludeRegularExpression(const char* regex)
+ {
+ this->SetProperty("INCLUDE_REGULAR_EXPRESSION", regex);
+ }
+ const char* GetIncludeRegularExpression() const
+ {
+ return this->GetProperty("INCLUDE_REGULAR_EXPRESSION");
+ }
+
+ /**
+ * Set a regular expression that include files that are not found
+ * must match in order to be considered a problem.
+ */
+ void SetComplainRegularExpression(const std::string& regex)
+ {
+ this->ComplainFileRegularExpression = regex;
+ }
+ const char* GetComplainRegularExpression() const
+ {
+ 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; }
+ const std::vector<cmTarget*>& GetOwnedImportedTargets() const
+ {
+ return this->ImportedTargetsOwned;
+ }
+ std::vector<cmTarget*> GetImportedTargets() const;
+
+ cmTarget* FindLocalNonAliasTarget(const std::string& name) const;
+
+ /** Find a target to use in place of the given name. The target
+ returned may be imported or built within the project. */
+ cmTarget* FindTargetToUse(const std::string& name,
+ bool excludeAliases = false) const;
+ bool IsAlias(const std::string& name) const;
+
+ std::map<std::string, std::string> GetAliasTargets() const
+ {
+ return this->AliasTargets;
+ }
+
+ /**
+ * Mark include directories as system directories.
+ */
+ void AddSystemIncludeDirectories(const std::set<std::string>& incs);
+
+ /** Get a cmSourceFile pointer for a given source name, if the name is
+ * not found, then a null pointer is returned.
+ */
+ cmSourceFile* GetSource(const std::string& sourceName) const;
+
+ /** Create the source file and return it. generated
+ * indicates if it is a generated file, this is used in determining
+ * how to create the source file instance e.g. name
+ */
+ cmSourceFile* CreateSource(const std::string& sourceName,
+ bool generated = false);
+
+ /** Get a cmSourceFile pointer for a given source name, if the name is
+ * not found, then create the source file and return it. generated
+ * indicates if it is a generated file, this is used in determining
+ * how to create the source file instance e.g. name
+ */
+ cmSourceFile* GetOrCreateSource(const std::string& sourceName,
+ bool generated = false);
+
+ /**
+ * Given a variable name, return its value (as a string).
+ * If the variable is not found in this makefile instance, the
+ * cache is then queried.
+ */
+ const char* GetDefinition(const std::string&) const;
+ const char* GetSafeDefinition(const std::string&) const;
+ const char* GetRequiredDefinition(const std::string& name) const;
+ bool IsDefinitionSet(const std::string&) const;
+ /**
+ * Get the list of all variables in the current space. If argument
+ * cacheonly is specified and is greater than 0, then only cache
+ * variables will be listed.
+ */
+ std::vector<std::string> GetDefinitions() const;
+
+ /**
+ * Test a boolean variable to see if it is true or false.
+ * If the variable is not found in this makefile instance, the
+ * cache is then queried.
+ * Returns false if no entry defined.
+ */
+ bool IsOn(const std::string& name) const;
+ bool IsSet(const std::string& name) const;
+
+ /** Return whether the target platform is 32-bit. */
+ bool PlatformIs32Bit() const;
+
+ /** Return whether the target platform is 64-bit. */
+ bool PlatformIs64Bit() const;
+
+ /** Return whether the target platform is Apple iOS. */
+ bool PlatformIsAppleIos() const;
+
+ /** Retrieve soname flag for the specified language if supported */
+ const char* GetSONameFlag(const std::string& language) const;
+
+ /**
+ * Get a list of preprocessor define flags.
+ */
+ const char* GetDefineFlags() const { return this->DefineFlags.c_str(); }
+
+ /**
+ * Make sure CMake can write this file
+ */
+ bool CanIWriteThisFile(const char* fileName) const;
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ /**
+ * Get the vector source groups.
+ */
+ const std::vector<cmSourceGroup>& GetSourceGroups() const
+ {
+ return this->SourceGroups;
+ }
+
+ /**
+ * Get the source group
+ */
+ cmSourceGroup* GetSourceGroup(const std::vector<std::string>& name) const;
+#endif
+
+ /**
+ * Get the vector of list files on which this makefile depends
+ */
+ const std::vector<std::string>& GetListFiles() const
+ {
+ return this->ListFiles;
+ }
+ ///! When the file changes cmake will be re-run from the build system.
+ void AddCMakeDependFile(const std::string& file)
+ {
+ this->ListFiles.push_back(file);
+ }
+ void AddCMakeDependFilesFromUser();
+
+ std::string FormatListFileStack() const;
+
+ /**
+ * Get the current context backtrace.
+ */
+ cmListFileBacktrace GetBacktrace() const;
+ cmListFileBacktrace GetBacktrace(cmCommandContext const& lfc) const;
+ cmListFileContext GetExecutionContext() const;
+
+ /**
+ * Get the vector of files created by this makefile
+ */
+ const std::vector<std::string>& GetOutputFiles() const
+ {
+ return this->OutputFiles;
+ }
+ void AddCMakeOutputFile(const std::string& file)
+ {
+ this->OutputFiles.push_back(file);
+ }
+
+ /**
+ * Expand all defined variables in the string.
+ * Defined variables come from the this->Definitions map.
+ * They are expanded with ${var} where var is the
+ * entry in the this->Definitions map. Also \@var\@ is
+ * expanded to match autoconf style expansions.
+ */
+ const char* ExpandVariablesInString(std::string& source) const;
+ const char* ExpandVariablesInString(std::string& source, bool escapeQuotes,
+ bool noEscapes, bool atOnly = false,
+ const char* filename = CM_NULLPTR,
+ long line = -1, bool removeEmpty = false,
+ bool replaceAt = false) const;
+
+ /**
+ * Remove any remaining variables in the string. Anything with ${var} or
+ * \@var\@ will be removed.
+ */
+ void RemoveVariablesInString(std::string& source, bool atOnly = false) const;
+
+ /**
+ * Expand variables in the makefiles ivars such as link directories etc
+ */
+ void ExpandVariablesCMP0019();
+
+ /**
+ * Replace variables and #cmakedefine lines in the given string.
+ * See cmConfigureFileCommand for details.
+ */
+ void ConfigureString(const std::string& input, std::string& output,
+ bool atOnly, bool escapeQuotes) const;
+
+ /**
+ * Copy file but change lines acording to ConfigureString
+ */
+ int ConfigureFile(const char* infile, const char* outfile, bool copyonly,
+ bool atOnly, bool escapeQuotes,
+ const cmNewLineStyle& = cmNewLineStyle());
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ /**
+ * find what source group this source is in
+ */
+ cmSourceGroup* FindSourceGroup(const char* source,
+ std::vector<cmSourceGroup>& groups) const;
+#endif
+
+ /**
+ * Print a command's invocation
+ */
+ void PrintCommandTrace(const cmListFileFunction& lff) const;
+
+ /**
+ * Execute a single CMake command. Returns true if the command
+ * succeeded or false if it failed.
+ */
+ bool ExecuteCommand(const cmListFileFunction& lff,
+ cmExecutionStatus& status);
+
+ ///! Enable support for named language, if nil then all languages are
+ /// enabled.
+ void EnableLanguage(std::vector<std::string> const& languages,
+ bool optional);
+
+ cmState* GetState() const;
+
+/**
+ * Get the variable watch. This is used to determine when certain variables
+ * are accessed.
+ */
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ cmVariableWatch* GetVariableWatch() const;
+#endif
+
+ ///! Display progress or status message.
+ void DisplayStatus(const char*, float) const;
+
+ /**
+ * Expand the given list file arguments into the full set after
+ * variable replacement and list expansion.
+ */
+ bool ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
+ std::vector<std::string>& outArgs,
+ const char* filename = CM_NULLPTR) const;
+
+ bool ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
+ std::vector<cmExpandedCommandArgument>& outArgs,
+ const char* filename = CM_NULLPTR) const;
+
+ /**
+ * Get the instance
+ */
+ cmake* GetCMakeInstance() const;
+ cmGlobalGenerator* GetGlobalGenerator() const;
+
+ /**
+ * Get all the source files this makefile knows about
+ */
+ const std::vector<cmSourceFile*>& GetSourceFiles() const
+ {
+ return this->SourceFiles;
+ }
+ std::vector<cmSourceFile*>& GetSourceFiles() { return this->SourceFiles; }
+
+ /**
+ * Is there a source file that has the provided source file as an output?
+ * if so then return it
+ */
+ cmSourceFile* GetSourceFileWithOutput(const std::string& outName) const;
+
+ ///! 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
+ * not found, then a null pointer is returned.
+ */
+ cmTest* GetTest(const std::string& testName) const;
+
+ /**
+ * Return a location of a file in cmake or custom modules directory
+ */
+ std::string GetModulesFile(const char* name) const;
+
+ ///! 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);
+ const char* GetProperty(const std::string& prop) const;
+ const char* GetProperty(const std::string& prop, bool chain) const;
+ bool GetPropertyAsBool(const std::string& prop) const;
+ std::vector<std::string> GetPropertyKeys() const;
+
+ ///! Initialize a makefile from its parent
+ void InitializeFromParent(cmMakefile* parent);
+
+ void AddInstallGenerator(cmInstallGenerator* g)
+ {
+ if (g) {
+ this->InstallGenerators.push_back(g);
+ }
+ }
+ std::vector<cmInstallGenerator*>& GetInstallGenerators()
+ {
+ return this->InstallGenerators;
+ }
+
+ void AddTestGenerator(cmTestGenerator* g)
+ {
+ if (g) {
+ this->TestGenerators.push_back(g);
+ }
+ }
+ const std::vector<cmTestGenerator*>& GetTestGenerators() const
+ {
+ return this->TestGenerators;
+ }
+
+ class FunctionPushPop
+ {
+ public:
+ FunctionPushPop(cmMakefile* mf, std::string const& fileName,
+ cmPolicies::PolicyMap const& pm);
+ ~FunctionPushPop();
+
+ void Quiet() { this->ReportError = false; }
+ private:
+ cmMakefile* Makefile;
+ bool ReportError;
+ };
+
+ class MacroPushPop
+ {
+ public:
+ MacroPushPop(cmMakefile* mf, std::string const& fileName,
+ cmPolicies::PolicyMap const& pm);
+ ~MacroPushPop();
+
+ void Quiet() { this->ReportError = false; }
+ private:
+ cmMakefile* Makefile;
+ bool ReportError;
+ };
+
+ void PushFunctionScope(std::string const& fileName,
+ cmPolicies::PolicyMap const& pm);
+ void PopFunctionScope(bool reportError);
+ void PushMacroScope(std::string const& fileName,
+ cmPolicies::PolicyMap const& pm);
+ void PopMacroScope(bool reportError);
+ void PushScope();
+ void PopScope();
+ void RaiseScope(const std::string& var, const char* value);
+
+ // push and pop loop scopes
+ void PushLoopBlockBarrier();
+ void PopLoopBlockBarrier();
+
+ /** Helper class to push and pop scopes automatically. */
+ class ScopePushPop
+ {
+ public:
+ ScopePushPop(cmMakefile* m)
+ : Makefile(m)
+ {
+ this->Makefile->PushScope();
+ }
+ ~ScopePushPop() { this->Makefile->PopScope(); }
+ private:
+ cmMakefile* Makefile;
+ };
+
+ void IssueMessage(cmake::MessageType t, std::string const& text) const;
+
+ /** Set whether or not to report a CMP0000 violation. */
+ void SetCheckCMP0000(bool b) { this->CheckCMP0000 = b; }
+
+ cmStringRange GetIncludeDirectoriesEntries() const;
+ cmBacktraceRange GetIncludeDirectoriesBacktraces() const;
+ cmStringRange GetCompileOptionsEntries() const;
+ cmBacktraceRange GetCompileOptionsBacktraces() const;
+ cmStringRange GetCompileDefinitionsEntries() const;
+ cmBacktraceRange GetCompileDefinitionsBacktraces() const;
+
+ void AddQtUiFileWithOptions(cmSourceFile* sf);
+ std::vector<cmSourceFile*> GetQtUiFilesWithOptions() const;
+
+ std::set<std::string> const& GetSystemIncludeDirectories() const
+ {
+ return this->SystemIncludeDirectories;
+ }
+
+ bool PolicyOptionalWarningEnabled(std::string const& var);
+
+ bool AddRequiredTargetFeature(cmTarget* target, const std::string& feature,
+ std::string* error = CM_NULLPTR) const;
+
+ bool CompileFeatureKnown(cmTarget const* target, const std::string& feature,
+ std::string& lang, std::string* error) const;
+
+ const char* CompileFeaturesAvailable(const std::string& lang,
+ std::string* error) const;
+
+ bool HaveStandardAvailable(cmTarget const* target, std::string const& lang,
+ const std::string& feature) const;
+
+ bool IsLaterStandard(std::string const& lang, std::string const& lhs,
+ std::string const& rhs);
+
+ void PushLoopBlock();
+ void PopLoopBlock();
+ bool IsLoopBlock() const;
+
+ void ClearMatches();
+ void StoreMatches(cmsys::RegularExpression& re);
+
+ cmState::Snapshot GetStateSnapshot() const;
+
+ const char* GetDefineFlagsCMP0059() const;
+
+ std::string GetExecutionFilePath() const;
+
+ void EnforceDirectoryLevelRules() const;
+
+ void AddEvaluationFile(const std::string& inputFile,
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> outputName,
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> condition,
+ bool inputIsContent);
+ std::vector<cmGeneratorExpressionEvaluationFile*> GetEvaluationFiles() const;
+
+ std::vector<cmExportBuildFileGenerator*> GetExportBuildFileGenerators()
+ const;
+ void RemoveExportBuildFileGeneratorCMP0024(cmExportBuildFileGenerator* gen);
+ void AddExportBuildFileGenerator(cmExportBuildFileGenerator* gen);
+
+protected:
+ // add link libraries and directories to the target
+ void AddGlobalLinkInformation(const std::string& name, cmTarget& target);
+
+ // Check for a an unused variable
+ void LogUnused(const char* reason, const std::string& name) const;
+
+ mutable std::set<cmListFileContext> CMP0054ReportedIds;
+
+ // libraries, classes, and executables
+ mutable cmTargets Targets;
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+ typedef std::unordered_map<std::string, cmTarget*> TargetMap;
+#else
+ typedef cmsys::hash_map<std::string, cmTarget*> TargetMap;
+#endif
+#else
+ typedef std::map<std::string, cmTarget*> TargetMap;
+#endif
+ std::map<std::string, std::string> AliasTargets;
+ std::vector<cmSourceFile*> SourceFiles;
+
+ // Tests
+ std::map<std::string, cmTest*> Tests;
+
+ // The link-library paths. Order matters, use std::vector (not std::set).
+ std::vector<std::string> LinkDirectories;
+
+ // The set of include directories that are marked as system include
+ // directories.
+ std::set<std::string> SystemIncludeDirectories;
+
+ std::vector<std::string> ListFiles;
+ std::vector<std::string> OutputFiles;
+
+ cmTarget::LinkLibraryVectorType LinkLibraries;
+
+ std::vector<cmInstallGenerator*> InstallGenerators;
+ std::vector<cmTestGenerator*> TestGenerators;
+
+ std::string ComplainFileRegularExpression;
+ std::string DefineFlags;
+
+ // Track the value of the computed DEFINITIONS property.
+ void AddDefineFlag(const char*, std::string&);
+ void RemoveDefineFlag(const char*, std::string::size_type, std::string&);
+ std::string DefineFlagsOrig;
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ std::vector<cmSourceGroup> SourceGroups;
+#endif
+
+ std::vector<cmCommand*> FinalPassCommands;
+ cmGlobalGenerator* GlobalGenerator;
+ bool IsFunctionBlocked(const cmListFileFunction& lff,
+ cmExecutionStatus& status);
+
+private:
+ cmMakefile(const cmMakefile& mf);
+ cmMakefile& operator=(const cmMakefile& mf);
+
+ cmState::Snapshot StateSnapshot;
+ cmListFileBacktrace Backtrace;
+
+ void ReadListFile(cmListFile const& listFile,
+ const std::string& filenametoread);
+
+ bool ParseDefineFlag(std::string const& definition, bool remove);
+
+ bool EnforceUniqueDir(const std::string& srcPath,
+ const std::string& binPath) const;
+
+ typedef std::vector<cmFunctionBlocker*> FunctionBlockersType;
+ FunctionBlockersType FunctionBlockers;
+ std::vector<FunctionBlockersType::size_type> FunctionBlockerBarriers;
+ void PushFunctionBlockerBarrier();
+ void PopFunctionBlockerBarrier(bool reportError = true);
+
+ std::stack<int> LoopBlockCounter;
+
+ mutable cmsys::RegularExpression cmDefineRegex;
+ mutable cmsys::RegularExpression cmDefine01Regex;
+ mutable cmsys::RegularExpression cmAtVarRegex;
+ mutable cmsys::RegularExpression cmNamedCurly;
+
+ std::vector<cmMakefile*> UnConfiguredDirectories;
+ std::vector<cmExportBuildFileGenerator*> ExportBuildFileGenerators;
+
+ std::vector<cmGeneratorExpressionEvaluationFile*> EvaluationFiles;
+
+ std::vector<cmExecutionStatus*> ExecutionStatusStack;
+ friend class cmMakefileCall;
+ friend class cmParseFileScope;
+
+ std::vector<cmTarget*> ImportedTargetsOwned;
+ TargetMap ImportedTargets;
+
+ // Internal policy stack management.
+ void PushPolicy(bool weak = false,
+ cmPolicies::PolicyMap const& pm = cmPolicies::PolicyMap());
+ void PopPolicy();
+ void PopSnapshot(bool reportError = true);
+ friend class cmCMakePolicyCommand;
+ class IncludeScope;
+ friend class IncludeScope;
+ class ListFileScope;
+ friend class ListFileScope;
+ class BuildsystemFileScope;
+ friend class BuildsystemFileScope;
+
+ // CMP0053 == old
+ cmake::MessageType ExpandVariablesInStringOld(
+ std::string& errorstr, std::string& source, bool escapeQuotes,
+ bool noEscapes, bool atOnly, const char* filename, long line,
+ bool removeEmpty, bool replaceAt) const;
+ // CMP0053 == new
+ cmake::MessageType ExpandVariablesInStringNew(
+ std::string& errorstr, std::string& source, bool escapeQuotes,
+ bool noEscapes, bool atOnly, const char* filename, long line,
+ bool removeEmpty, bool replaceAt) const;
+ /**
+ * Old version of GetSourceFileWithOutput(const std::string&) kept for
+ * backward-compatibility. It implements a linear search and support
+ * relative file paths. It is used as a fall back by
+ * GetSourceFileWithOutput(const std::string&).
+ */
+ cmSourceFile* LinearGetSourceFileWithOutput(const std::string& cname) const;
+
+// A map for fast output to input look up.
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+ typedef std::unordered_map<std::string, cmSourceFile*> OutputToSourceMap;
+#else
+ typedef cmsys::hash_map<std::string, cmSourceFile*> OutputToSourceMap;
+#endif
+#else
+ typedef std::map<std::string, cmSourceFile*> OutputToSourceMap;
+#endif
+ OutputToSourceMap OutputToSource;
+
+ void UpdateOutputToSourceMap(std::vector<std::string> const& outputs,
+ cmSourceFile* source);
+ void UpdateOutputToSourceMap(std::string const& output,
+ cmSourceFile* source);
+
+ std::vector<cmSourceFile*> QtUiFilesWithOptions;
+
+ bool AddRequiredTargetCFeature(cmTarget* target, const std::string& feature,
+ std::string* error = CM_NULLPTR) const;
+
+ bool AddRequiredTargetCxxFeature(cmTarget* target,
+ const std::string& feature,
+ std::string* error = CM_NULLPTR) const;
+
+ void CheckNeededCLanguage(const std::string& feature, bool& needC90,
+ bool& needC99, bool& needC11) const;
+ void CheckNeededCxxLanguage(const std::string& feature, bool& needCxx98,
+ bool& needCxx11, bool& needCxx14) const;
+
+ bool HaveCStandardAvailable(cmTarget const* target,
+ const std::string& feature) const;
+ bool HaveCxxStandardAvailable(cmTarget const* target,
+ const std::string& feature) const;
+
+ void CheckForUnusedVariables() const;
+
+ // Unused variable flags
+ bool WarnUnused;
+ bool CheckSystemVars;
+ bool CheckCMP0000;
+ bool IsSourceFileTryCompile;
+ mutable bool SuppressWatches;
+};
+
+#endif
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
new file mode 100644
index 0000000..9a37a33
--- /dev/null
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -0,0 +1,443 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmMakefileExecutableTargetGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmake.h"
+
+cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator(
+ cmGeneratorTarget* target)
+ : cmMakefileTargetGenerator(target)
+{
+ this->CustomCommandDriver = OnDepends;
+ this->GeneratorTarget->GetExecutableNames(
+ this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,
+ this->TargetNamePDB, this->ConfigName);
+
+ this->OSXBundleGenerator =
+ new cmOSXBundleGenerator(target, this->ConfigName);
+ this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
+}
+
+cmMakefileExecutableTargetGenerator::~cmMakefileExecutableTargetGenerator()
+{
+ delete this->OSXBundleGenerator;
+}
+
+void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
+{
+ // create the build.make file and directory, put in the common blocks
+ this->CreateRuleFile();
+
+ // write rules used to help build object files
+ this->WriteCommonCodeRules();
+
+ // write the per-target per-language flags
+ this->WriteTargetLanguageFlags();
+
+ // write in rules for object files and custom commands
+ this->WriteTargetBuildRules();
+
+ // write the link rules
+ this->WriteExecutableRule(false);
+ if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName)) {
+ // Write rules to link an installable version of the target.
+ this->WriteExecutableRule(true);
+ }
+
+ // Write the requires target.
+ this->WriteTargetRequiresRules();
+
+ // Write clean target
+ this->WriteTargetCleanRules();
+
+ // Write the dependency generation rule. This must be done last so
+ // that multiple output pair information is available.
+ this->WriteTargetDependRules();
+
+ // close the streams
+ this->CloseFileStreams();
+}
+
+void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
+{
+ std::vector<std::string> commands;
+
+ // Build list of dependencies.
+ std::vector<std::string> depends;
+ this->AppendLinkDepends(depends);
+
+ // 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);
+
+ // 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);
+ }
+ outpath += "/";
+ std::string outpathImp;
+ if (relink) {
+ outpath = this->Makefile->GetCurrentBinaryDirectory();
+ outpath += cmake::GetCMakeFilesDirectory();
+ outpath += "/CMakeRelink.dir";
+ cmSystemTools::MakeDirectory(outpath.c_str());
+ outpath += "/";
+ if (!targetNameImport.empty()) {
+ outpathImp = outpath;
+ }
+ } else {
+ cmSystemTools::MakeDirectory(outpath.c_str());
+ if (!targetNameImport.empty()) {
+ outpathImp = this->GeneratorTarget->GetDirectory(this->ConfigName, true);
+ cmSystemTools::MakeDirectory(outpathImp.c_str());
+ outpathImp += "/";
+ }
+ }
+
+ std::string compilePdbOutputPath =
+ this->GeneratorTarget->GetCompilePDBDirectory(this->ConfigName);
+ cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str());
+
+ std::string pdbOutputPath =
+ this->GeneratorTarget->GetPDBDirectory(this->ConfigName);
+ cmSystemTools::MakeDirectory(pdbOutputPath.c_str());
+ pdbOutputPath += "/";
+
+ std::string targetFullPath = outpath + targetName;
+ std::string targetFullPathReal = outpath + targetNameReal;
+ std::string targetFullPathPDB = pdbOutputPath + targetNamePDB;
+ std::string targetFullPathImport = outpathImp + targetNameImport;
+ std::string targetOutPathPDB = this->Convert(
+ targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL);
+ // Convert to the output path to use in constructing commands.
+ std::string targetOutPath = this->Convert(
+ targetFullPath, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL);
+ std::string targetOutPathReal =
+ this->Convert(targetFullPathReal, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+ std::string targetOutPathImport =
+ this->Convert(targetFullPathImport, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+
+ // Get the language to use for linking this executable.
+ std::string linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+
+ // Make sure we have a link language.
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error("Cannot determine link language for target \"",
+ this->GeneratorTarget->GetName().c_str(), "\".");
+ return;
+ }
+
+ this->NumberOfProgressActions++;
+ if (!this->NoRuleMessages) {
+ cmLocalUnixMakefileGenerator3::EchoProgress progress;
+ this->MakeEchoProgress(progress);
+ // Add the link message.
+ std::string buildEcho = "Linking ";
+ buildEcho += linkLanguage;
+ buildEcho += " executable ";
+ buildEcho += targetOutPath;
+ this->LocalGenerator->AppendEcho(
+ commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress);
+ }
+
+ // Build a list of compiler flags and linker flags.
+ std::string flags;
+ std::string linkFlags;
+
+ // Add flags to create an executable.
+ this->LocalGenerator->AddConfigVariableFlags(
+ linkFlags, "CMAKE_EXE_LINKER_FLAGS", this->ConfigName);
+
+ if (this->GeneratorTarget->GetPropertyAsBool("WIN32_EXECUTABLE")) {
+ this->LocalGenerator->AppendFlags(
+ linkFlags, this->Makefile->GetDefinition("CMAKE_CREATE_WIN32_EXE"));
+ } else {
+ this->LocalGenerator->AppendFlags(
+ linkFlags, this->Makefile->GetDefinition("CMAKE_CREATE_CONSOLE_EXE"));
+ }
+
+ // Add symbol export flags if necessary.
+ if (this->GeneratorTarget->IsExecutableWithExports()) {
+ std::string export_flag_var = "CMAKE_EXE_EXPORTS_";
+ export_flag_var += linkLanguage;
+ export_flag_var += "_FLAG";
+ this->LocalGenerator->AppendFlags(
+ linkFlags, this->Makefile->GetDefinition(export_flag_var));
+ }
+ if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE")) {
+ this->LocalGenerator->AppendFlags(linkFlags, " -Wl,--no-as-needed");
+ }
+
+ // Add language feature flags.
+ this->AddFeatureFlags(flags, linkLanguage);
+
+ this->LocalGenerator->AddArchitectureFlags(flags, this->GeneratorTarget,
+ linkLanguage, this->ConfigName);
+
+ // Add target-specific linker flags.
+ this->LocalGenerator->AppendFlags(
+ linkFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
+ std::string linkFlagsConfig = "LINK_FLAGS_";
+ linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
+ this->LocalGenerator->AppendFlags(
+ linkFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
+
+ this->AddModuleDefinitionFlag(linkFlags);
+
+ // Construct a list of files associated with this executable that
+ // may need to be cleaned.
+ std::vector<std::string> exeCleanFiles;
+ exeCleanFiles.push_back(this->Convert(targetFullPath,
+ cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED));
+#ifdef _WIN32
+ // There may be a manifest file for this target. Add it to the
+ // clean set just in case.
+ exeCleanFiles.push_back(this->Convert((targetFullPath + ".manifest").c_str(),
+ cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED));
+#endif
+ if (targetNameReal != targetName) {
+ exeCleanFiles.push_back(this->Convert(targetFullPathReal,
+ cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED));
+ }
+ if (!targetNameImport.empty()) {
+ exeCleanFiles.push_back(this->Convert(targetFullPathImport,
+ cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED));
+ std::string implib;
+ if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport,
+ implib)) {
+ exeCleanFiles.push_back(this->Convert(implib,
+ cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED));
+ }
+ }
+
+ // 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->Convert(targetFullPathPDB,
+ cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED));
+
+ // Add the pre-build and pre-link rules building but not when relinking.
+ if (!relink) {
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPreBuildCommands(),
+ this->GeneratorTarget);
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPreLinkCommands(),
+ this->GeneratorTarget);
+ }
+
+ // Determine whether a link script will be used.
+ bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
+
+ // Construct the main link rule.
+ std::vector<std::string> real_link_commands;
+ std::string linkRuleVar = "CMAKE_";
+ linkRuleVar += linkLanguage;
+ linkRuleVar += "_LINK_EXECUTABLE";
+ std::string linkRule = this->GetLinkRule(linkRuleVar);
+ std::vector<std::string> commands1;
+ cmSystemTools::ExpandListArgument(linkRule, real_link_commands);
+ if (this->GeneratorTarget->IsExecutableWithExports()) {
+ // If a separate rule for creating an import library is specified
+ // add it now.
+ std::string implibRuleVar = "CMAKE_";
+ implibRuleVar += linkLanguage;
+ implibRuleVar += "_CREATE_IMPORT_LIBRARY";
+ if (const char* rule = this->Makefile->GetDefinition(implibRuleVar)) {
+ cmSystemTools::ExpandListArgument(rule, real_link_commands);
+ }
+ }
+
+ // Select whether to use a response file for objects.
+ bool useResponseFileForObjects = false;
+ {
+ std::string responseVar = "CMAKE_";
+ responseVar += linkLanguage;
+ responseVar += "_USE_RESPONSE_FILE_FOR_OBJECTS";
+ if (this->Makefile->IsOn(responseVar)) {
+ useResponseFileForObjects = true;
+ }
+ }
+
+ // Select whether to use a response file for libraries.
+ bool useResponseFileForLibs = false;
+ {
+ std::string responseVar = "CMAKE_";
+ responseVar += linkLanguage;
+ responseVar += "_USE_RESPONSE_FILE_FOR_LIBRARIES";
+ if (this->Makefile->IsOn(responseVar)) {
+ useResponseFileForLibs = true;
+ }
+ }
+
+ // Expand the rule variables.
+ {
+ bool useWatcomQuote =
+ this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE");
+
+ // Set path conversion for link script shells.
+ this->LocalGenerator->SetLinkScriptShell(useLinkScript);
+
+ // Collect up flags to link in needed libraries.
+ std::string linkLibs;
+ this->CreateLinkLibs(linkLibs, relink, useResponseFileForLibs, depends,
+ useWatcomQuote);
+
+ // Construct object file lists that may be needed to expand the
+ // rule.
+ std::string buildObjs;
+ this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
+ buildObjs, depends, useWatcomQuote);
+
+ std::string manifests = this->GetManifests();
+
+ cmLocalGenerator::RuleVariables vars;
+ vars.RuleLauncher = "RULE_LAUNCH_LINK";
+ vars.CMTarget = this->GeneratorTarget;
+ vars.Language = linkLanguage.c_str();
+ vars.Objects = buildObjs.c_str();
+ std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
+ objectDir = this->Convert(objectDir, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+ vars.ObjectDir = objectDir.c_str();
+ cmOutputConverter::OutputFormat output = (useWatcomQuote)
+ ? cmOutputConverter::WATCOMQUOTE
+ : cmOutputConverter::SHELL;
+ std::string target = this->Convert(
+ targetFullPathReal, cmOutputConverter::START_OUTPUT, output);
+ vars.Target = target.c_str();
+ vars.TargetPDB = targetOutPathPDB.c_str();
+
+ // Setup the target version.
+ std::string targetVersionMajor;
+ std::string targetVersionMinor;
+ {
+ std::ostringstream majorStream;
+ std::ostringstream minorStream;
+ int major;
+ int minor;
+ this->GeneratorTarget->GetTargetVersion(major, minor);
+ majorStream << major;
+ minorStream << minor;
+ targetVersionMajor = majorStream.str();
+ targetVersionMinor = minorStream.str();
+ }
+ vars.TargetVersionMajor = targetVersionMajor.c_str();
+ vars.TargetVersionMinor = targetVersionMinor.c_str();
+
+ vars.LinkLibraries = linkLibs.c_str();
+ vars.Flags = flags.c_str();
+ vars.LinkFlags = linkFlags.c_str();
+ vars.Manifests = manifests.c_str();
+
+ if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE")) {
+ std::string cmakeCommand =
+ this->Convert(cmSystemTools::GetCMakeCommand(), cmLocalGenerator::NONE,
+ cmLocalGenerator::SHELL);
+ cmakeCommand += " -E __run_iwyu --lwyu=";
+ cmakeCommand += targetOutPathReal;
+ real_link_commands.push_back(cmakeCommand);
+ }
+
+ // Expand placeholders in the commands.
+ this->LocalGenerator->TargetImplib = targetOutPathImport;
+ for (std::vector<std::string>::iterator i = real_link_commands.begin();
+ i != real_link_commands.end(); ++i) {
+ this->LocalGenerator->ExpandRuleVariables(*i, vars);
+ }
+ this->LocalGenerator->TargetImplib = "";
+
+ // Restore path conversion to normal shells.
+ this->LocalGenerator->SetLinkScriptShell(false);
+ }
+
+ // Optionally convert the build rule to use a script to avoid long
+ // command lines in the make shell.
+ if (useLinkScript) {
+ // Use a link script.
+ const char* name = (relink ? "relink.txt" : "link.txt");
+ this->CreateLinkScript(name, real_link_commands, commands1, depends);
+ } else {
+ // No link script. Just use the link rule directly.
+ commands1 = real_link_commands;
+ }
+ this->LocalGenerator->CreateCDCommand(
+ commands1, this->Makefile->GetCurrentBinaryDirectory(),
+ cmOutputConverter::HOME_OUTPUT);
+ commands.insert(commands.end(), commands1.begin(), commands1.end());
+ commands1.clear();
+
+ // Add a rule to create necessary symlinks for the library.
+ if (targetOutPath != targetOutPathReal) {
+ std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_executable ";
+ symlink += targetOutPathReal;
+ symlink += " ";
+ symlink += targetOutPath;
+ commands1.push_back(symlink);
+ this->LocalGenerator->CreateCDCommand(
+ commands1, this->Makefile->GetCurrentBinaryDirectory(),
+ cmOutputConverter::HOME_OUTPUT);
+ commands.insert(commands.end(), commands1.begin(), commands1.end());
+ commands1.clear();
+ }
+
+ // Add the post-build rules when building but not when relinking.
+ if (!relink) {
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPostBuildCommands(),
+ this->GeneratorTarget);
+ }
+
+ // Write the build rule.
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR,
+ targetFullPathReal, depends, commands,
+ false);
+
+ // The symlink name for the target should depend on the real target
+ // so if the target version changes it rebuilds and recreates the
+ // symlink.
+ if (targetFullPath != targetFullPathReal) {
+ depends.clear();
+ commands.clear();
+ depends.push_back(targetFullPathReal);
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR,
+ targetFullPath, depends, commands,
+ false);
+ }
+
+ // Write the main driver rule to build everything in this target.
+ this->WriteTargetDriverRule(targetFullPath, relink);
+
+ // Clean all the possible executable names and symlinks.
+ this->CleanFiles.insert(this->CleanFiles.end(), exeCleanFiles.begin(),
+ exeCleanFiles.end());
+}
diff --git a/Source/cmMakefileExecutableTargetGenerator.h b/Source/cmMakefileExecutableTargetGenerator.h
new file mode 100644
index 0000000..39def27
--- /dev/null
+++ b/Source/cmMakefileExecutableTargetGenerator.h
@@ -0,0 +1,31 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmMakefileExecutableTargetGenerator_h
+#define cmMakefileExecutableTargetGenerator_h
+
+#include "cmMakefileTargetGenerator.h"
+
+class cmMakefileExecutableTargetGenerator : public cmMakefileTargetGenerator
+{
+public:
+ cmMakefileExecutableTargetGenerator(cmGeneratorTarget* target);
+ ~cmMakefileExecutableTargetGenerator() CM_OVERRIDE;
+
+ /* the main entry point for this class. Writes the Makefiles associated
+ with this target */
+ void WriteRuleFiles() CM_OVERRIDE;
+
+protected:
+ virtual void WriteExecutableRule(bool relink);
+};
+
+#endif
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
new file mode 100644
index 0000000..380fd7d
--- /dev/null
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -0,0 +1,774 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmMakefileLibraryTargetGenerator.h"
+
+#include "cmAlgorithms.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmake.h"
+
+cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator(
+ cmGeneratorTarget* target)
+ : cmMakefileTargetGenerator(target)
+{
+ this->CustomCommandDriver = OnDepends;
+ if (this->GeneratorTarget->GetType() != cmState::INTERFACE_LIBRARY) {
+ this->GeneratorTarget->GetLibraryNames(
+ this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
+ this->TargetNameImport, this->TargetNamePDB, this->ConfigName);
+ }
+
+ this->OSXBundleGenerator =
+ new cmOSXBundleGenerator(target, this->ConfigName);
+ this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
+}
+
+cmMakefileLibraryTargetGenerator::~cmMakefileLibraryTargetGenerator()
+{
+ delete this->OSXBundleGenerator;
+}
+
+void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
+{
+ // create the build.make file and directory, put in the common blocks
+ this->CreateRuleFile();
+
+ // write rules used to help build object files
+ this->WriteCommonCodeRules();
+
+ // write the per-target per-language flags
+ this->WriteTargetLanguageFlags();
+
+ // write in rules for object files and custom commands
+ this->WriteTargetBuildRules();
+
+ // write the link rules
+ // Write the rule for this target type.
+ switch (this->GeneratorTarget->GetType()) {
+ case cmState::STATIC_LIBRARY:
+ this->WriteStaticLibraryRules();
+ break;
+ case cmState::SHARED_LIBRARY:
+ this->WriteSharedLibraryRules(false);
+ if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName)) {
+ // Write rules to link an installable version of the target.
+ this->WriteSharedLibraryRules(true);
+ }
+ break;
+ case cmState::MODULE_LIBRARY:
+ this->WriteModuleLibraryRules(false);
+ if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName)) {
+ // Write rules to link an installable version of the target.
+ this->WriteModuleLibraryRules(true);
+ }
+ break;
+ case cmState::OBJECT_LIBRARY:
+ this->WriteObjectLibraryRules();
+ break;
+ default:
+ // If language is not known, this is an error.
+ cmSystemTools::Error("Unknown Library Type");
+ break;
+ }
+
+ // Write the requires target.
+ this->WriteTargetRequiresRules();
+
+ // Write clean target
+ this->WriteTargetCleanRules();
+
+ // Write the dependency generation rule. This must be done last so
+ // that multiple output pair information is available.
+ this->WriteTargetDependRules();
+
+ // close the streams
+ this->CloseFileStreams();
+}
+
+void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules()
+{
+ std::vector<std::string> commands;
+ std::vector<std::string> depends;
+
+ // Add post-build rules.
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPostBuildCommands(),
+ this->GeneratorTarget);
+
+ // Depend on the object files.
+ this->AppendObjectDepends(depends);
+
+ // Write the rule.
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR,
+ this->GeneratorTarget->GetName(),
+ depends, commands, true);
+
+ // Write the main driver rule to build everything in this target.
+ this->WriteTargetDriverRule(this->GeneratorTarget->GetName(), false);
+}
+
+void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
+{
+ std::string linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+ std::string linkRuleVar = "CMAKE_";
+ linkRuleVar += linkLanguage;
+ linkRuleVar += "_CREATE_STATIC_LIBRARY";
+
+ if (this->GetFeatureAsBool("INTERPROCEDURAL_OPTIMIZATION") &&
+ this->Makefile->GetDefinition(linkRuleVar + "_IPO")) {
+ linkRuleVar += "_IPO";
+ }
+
+ std::string extraFlags;
+ this->LocalGenerator->GetStaticLibraryFlags(
+ extraFlags, cmSystemTools::UpperCase(this->ConfigName),
+ this->GeneratorTarget);
+ this->WriteLibraryRules(linkRuleVar, extraFlags, false);
+}
+
+void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
+{
+ if (this->GeneratorTarget->IsFrameworkOnApple()) {
+ this->WriteFrameworkRules(relink);
+ return;
+ }
+ std::string linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+ std::string linkRuleVar = "CMAKE_";
+ linkRuleVar += linkLanguage;
+ linkRuleVar += "_CREATE_SHARED_LIBRARY";
+
+ std::string extraFlags;
+ this->LocalGenerator->AppendFlags(
+ extraFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
+ std::string linkFlagsConfig = "LINK_FLAGS_";
+ linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
+ this->LocalGenerator->AppendFlags(
+ extraFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
+
+ this->LocalGenerator->AddConfigVariableFlags(
+ extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName);
+ this->AddModuleDefinitionFlag(extraFlags);
+
+ if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE")) {
+ this->LocalGenerator->AppendFlags(extraFlags, " -Wl,--no-as-needed");
+ }
+ this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
+}
+
+void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
+{
+ std::string linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+ std::string linkRuleVar = "CMAKE_";
+ linkRuleVar += linkLanguage;
+ linkRuleVar += "_CREATE_SHARED_MODULE";
+
+ std::string extraFlags;
+ this->LocalGenerator->AppendFlags(
+ extraFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
+ std::string linkFlagsConfig = "LINK_FLAGS_";
+ linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
+ this->LocalGenerator->AppendFlags(
+ extraFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
+ this->LocalGenerator->AddConfigVariableFlags(
+ extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->ConfigName);
+ this->AddModuleDefinitionFlag(extraFlags);
+
+ this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
+}
+
+void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
+{
+ std::string linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+ std::string linkRuleVar = "CMAKE_";
+ linkRuleVar += linkLanguage;
+ linkRuleVar += "_CREATE_MACOSX_FRAMEWORK";
+
+ std::string extraFlags;
+ this->LocalGenerator->AppendFlags(
+ extraFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
+ std::string linkFlagsConfig = "LINK_FLAGS_";
+ linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
+ this->LocalGenerator->AppendFlags(
+ extraFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
+ this->LocalGenerator->AddConfigVariableFlags(
+ extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->ConfigName);
+
+ this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
+}
+
+void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
+ const std::string& linkRuleVar, const std::string& extraFlags, bool relink)
+{
+ // TODO: Merge the methods that call this method to avoid
+ // code duplication.
+ std::vector<std::string> commands;
+
+ // Build list of dependencies.
+ std::vector<std::string> depends;
+ this->AppendLinkDepends(depends);
+
+ // Get the language to use for linking this library.
+ std::string linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+
+ // Make sure we have a link language.
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error("Cannot determine link language for target \"",
+ this->GeneratorTarget->GetName().c_str(), "\".");
+ return;
+ }
+
+ // Create set of linking flags.
+ std::string linkFlags;
+ this->LocalGenerator->AppendFlags(linkFlags, extraFlags);
+
+ // Add OSX version flags, if any.
+ if (this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmState::MODULE_LIBRARY) {
+ this->AppendOSXVerFlag(linkFlags, linkLanguage, "COMPATIBILITY", true);
+ this->AppendOSXVerFlag(linkFlags, linkLanguage, "CURRENT", false);
+ }
+
+ // 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);
+
+ // 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);
+ outpath += "/";
+ } else if (this->GeneratorTarget->IsCFBundleOnApple()) {
+ outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
+ this->OSXBundleGenerator->CreateCFBundle(targetName, outpath);
+ outpath += "/";
+ } else if (relink) {
+ outpath = this->Makefile->GetCurrentBinaryDirectory();
+ outpath += cmake::GetCMakeFilesDirectory();
+ outpath += "/CMakeRelink.dir";
+ cmSystemTools::MakeDirectory(outpath.c_str());
+ outpath += "/";
+ if (!targetNameImport.empty()) {
+ outpathImp = outpath;
+ }
+ } else {
+ outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
+ cmSystemTools::MakeDirectory(outpath.c_str());
+ outpath += "/";
+ if (!targetNameImport.empty()) {
+ outpathImp = this->GeneratorTarget->GetDirectory(this->ConfigName, true);
+ cmSystemTools::MakeDirectory(outpathImp.c_str());
+ outpathImp += "/";
+ }
+ }
+
+ std::string compilePdbOutputPath =
+ this->GeneratorTarget->GetCompilePDBDirectory(this->ConfigName);
+ cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str());
+
+ std::string pdbOutputPath =
+ this->GeneratorTarget->GetPDBDirectory(this->ConfigName);
+ cmSystemTools::MakeDirectory(pdbOutputPath.c_str());
+ 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;
+
+ // Construct the output path version of the names for use in command
+ // arguments.
+ std::string targetOutPathPDB = this->Convert(
+ targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL);
+ std::string targetOutPath = this->Convert(
+ targetFullPath, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL);
+ std::string targetOutPathSO =
+ this->Convert(targetFullPathSO, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+ std::string targetOutPathReal =
+ this->Convert(targetFullPathReal, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+ std::string targetOutPathImport =
+ this->Convert(targetFullPathImport, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+
+ this->NumberOfProgressActions++;
+ if (!this->NoRuleMessages) {
+ cmLocalUnixMakefileGenerator3::EchoProgress progress;
+ this->MakeEchoProgress(progress);
+ // Add the link message.
+ std::string buildEcho = "Linking ";
+ buildEcho += linkLanguage;
+ switch (this->GeneratorTarget->GetType()) {
+ case cmState::STATIC_LIBRARY:
+ buildEcho += " static library ";
+ break;
+ case cmState::SHARED_LIBRARY:
+ buildEcho += " shared library ";
+ break;
+ case cmState::MODULE_LIBRARY:
+ if (this->GeneratorTarget->IsCFBundleOnApple()) {
+ buildEcho += " CFBundle";
+ }
+ buildEcho += " shared module ";
+ break;
+ default:
+ buildEcho += " library ";
+ break;
+ }
+ buildEcho += targetOutPath;
+ this->LocalGenerator->AppendEcho(
+ commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress);
+ }
+
+ const char* forbiddenFlagVar = CM_NULLPTR;
+ switch (this->GeneratorTarget->GetType()) {
+ case cmState::SHARED_LIBRARY:
+ forbiddenFlagVar = "_CREATE_SHARED_LIBRARY_FORBIDDEN_FLAGS";
+ break;
+ case cmState::MODULE_LIBRARY:
+ forbiddenFlagVar = "_CREATE_SHARED_MODULE_FORBIDDEN_FLAGS";
+ break;
+ default:
+ break;
+ }
+
+ // Clean files associated with this library.
+ std::vector<std::string> libCleanFiles;
+ libCleanFiles.push_back(this->Convert(targetFullPath,
+ cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED));
+ if (targetNameReal != targetName) {
+ libCleanFiles.push_back(this->Convert(targetFullPathReal,
+ cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED));
+ }
+ if (targetNameSO != targetName && targetNameSO != targetNameReal) {
+ libCleanFiles.push_back(this->Convert(targetFullPathSO,
+ cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED));
+ }
+ if (!targetNameImport.empty()) {
+ libCleanFiles.push_back(this->Convert(targetFullPathImport,
+ cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED));
+ std::string implib;
+ if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport,
+ implib)) {
+ libCleanFiles.push_back(this->Convert(implib,
+ cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED));
+ }
+ }
+
+ // 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->Convert(targetFullPathPDB,
+ cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED));
+
+#ifdef _WIN32
+ // There may be a manifest file for this target. Add it to the
+ // clean set just in case.
+ if (this->GeneratorTarget->GetType() != cmState::STATIC_LIBRARY) {
+ libCleanFiles.push_back(this->Convert(
+ (targetFullPath + ".manifest").c_str(), cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED));
+ }
+#endif
+
+ std::vector<std::string> commands1;
+ // Add a command to remove any existing files for this library.
+ // for static libs only
+ if (this->GeneratorTarget->GetType() == cmState::STATIC_LIBRARY) {
+ this->LocalGenerator->AppendCleanCommand(commands1, libCleanFiles,
+ this->GeneratorTarget, "target");
+ this->LocalGenerator->CreateCDCommand(
+ commands1, this->Makefile->GetCurrentBinaryDirectory(),
+ cmOutputConverter::HOME_OUTPUT);
+ commands.insert(commands.end(), commands1.begin(), commands1.end());
+ commands1.clear();
+ }
+
+ // Add the pre-build and pre-link rules building but not when relinking.
+ if (!relink) {
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPreBuildCommands(),
+ this->GeneratorTarget);
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPreLinkCommands(),
+ this->GeneratorTarget);
+ }
+
+ // Determine whether a link script will be used.
+ bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
+
+ // Select whether to use a response file for objects.
+ bool useResponseFileForObjects = false;
+ {
+ std::string responseVar = "CMAKE_";
+ responseVar += linkLanguage;
+ responseVar += "_USE_RESPONSE_FILE_FOR_OBJECTS";
+ if (this->Makefile->IsOn(responseVar)) {
+ useResponseFileForObjects = true;
+ }
+ }
+
+ // Select whether to use a response file for libraries.
+ bool useResponseFileForLibs = false;
+ {
+ std::string responseVar = "CMAKE_";
+ responseVar += linkLanguage;
+ responseVar += "_USE_RESPONSE_FILE_FOR_LIBRARIES";
+ if (this->Makefile->IsOn(responseVar)) {
+ useResponseFileForLibs = true;
+ }
+ }
+
+ // For static libraries there might be archiving rules.
+ bool haveStaticLibraryRule = false;
+ std::vector<std::string> archiveCreateCommands;
+ std::vector<std::string> archiveAppendCommands;
+ std::vector<std::string> archiveFinishCommands;
+ std::string::size_type archiveCommandLimit = std::string::npos;
+ if (this->GeneratorTarget->GetType() == cmState::STATIC_LIBRARY) {
+ haveStaticLibraryRule = this->Makefile->IsDefinitionSet(linkRuleVar);
+ std::string arCreateVar = "CMAKE_";
+ arCreateVar += linkLanguage;
+ arCreateVar += "_ARCHIVE_CREATE";
+ if (const char* rule = this->Makefile->GetDefinition(arCreateVar)) {
+ cmSystemTools::ExpandListArgument(rule, archiveCreateCommands);
+ }
+ std::string arAppendVar = "CMAKE_";
+ arAppendVar += linkLanguage;
+ arAppendVar += "_ARCHIVE_APPEND";
+ if (const char* rule = this->Makefile->GetDefinition(arAppendVar)) {
+ cmSystemTools::ExpandListArgument(rule, archiveAppendCommands);
+ }
+ std::string arFinishVar = "CMAKE_";
+ arFinishVar += linkLanguage;
+ arFinishVar += "_ARCHIVE_FINISH";
+ if (const char* rule = this->Makefile->GetDefinition(arFinishVar)) {
+ cmSystemTools::ExpandListArgument(rule, archiveFinishCommands);
+ }
+ }
+
+ // Decide whether to use archiving rules.
+ bool useArchiveRules = !haveStaticLibraryRule &&
+ !archiveCreateCommands.empty() && !archiveAppendCommands.empty();
+ if (useArchiveRules) {
+ // Archiving rules are always run with a link script.
+ useLinkScript = true;
+
+ // Archiving rules never use a response file.
+ useResponseFileForObjects = false;
+
+ // Limit the length of individual object lists to less than the
+ // 32K command line length limit on Windows. We could make this a
+ // platform file variable but this should work everywhere.
+ archiveCommandLimit = 30000;
+ }
+
+ // Expand the rule variables.
+ std::vector<std::string> real_link_commands;
+ {
+ bool useWatcomQuote =
+ this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE");
+
+ // Set path conversion for link script shells.
+ this->LocalGenerator->SetLinkScriptShell(useLinkScript);
+
+ // Collect up flags to link in needed libraries.
+ std::string linkLibs;
+ if (this->GeneratorTarget->GetType() != cmState::STATIC_LIBRARY) {
+ this->CreateLinkLibs(linkLibs, relink, useResponseFileForLibs, depends,
+ useWatcomQuote);
+ }
+
+ // Construct object file lists that may be needed to expand the
+ // rule.
+ std::string buildObjs;
+ this->CreateObjectLists(useLinkScript, useArchiveRules,
+ useResponseFileForObjects, buildObjs, depends,
+ useWatcomQuote);
+
+ // maybe create .def file from list of objects
+ if (this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY &&
+ this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS")) {
+ if (this->GeneratorTarget->GetPropertyAsBool(
+ "WINDOWS_EXPORT_ALL_SYMBOLS")) {
+ std::string name_of_def_file =
+ this->GeneratorTarget->GetSupportDirectory();
+ name_of_def_file +=
+ std::string("/") + this->GeneratorTarget->GetName();
+ name_of_def_file += ".def";
+ std::string cmd = cmSystemTools::GetCMakeCommand();
+ cmd = this->Convert(cmd, cmOutputConverter::NONE,
+ cmOutputConverter::SHELL);
+ cmd += " -E __create_def ";
+ cmd += this->Convert(name_of_def_file, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+ cmd += " ";
+ std::string objlist_file = name_of_def_file;
+ objlist_file += ".objs";
+ cmd += this->Convert(objlist_file, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+ real_link_commands.push_back(cmd);
+ // create a list of obj files for the -E __create_def to read
+ cmGeneratedFileStream fout(objlist_file.c_str());
+ for (std::vector<std::string>::const_iterator i =
+ this->Objects.begin();
+ i != this->Objects.end(); ++i) {
+ if (cmHasLiteralSuffix(*i, ".obj")) {
+ fout << *i << "\n";
+ }
+ }
+ for (std::vector<std::string>::const_iterator i =
+ this->ExternalObjects.begin();
+ i != this->ExternalObjects.end(); ++i) {
+ fout << *i << "\n";
+ }
+ // now add the def file link flag
+ linkFlags += " ";
+ linkFlags +=
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG");
+ linkFlags +=
+ this->Convert(name_of_def_file, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+ linkFlags += " ";
+ }
+ }
+
+ std::string manifests = this->GetManifests();
+
+ cmLocalGenerator::RuleVariables vars;
+ vars.TargetPDB = targetOutPathPDB.c_str();
+
+ // Setup the target version.
+ std::string targetVersionMajor;
+ std::string targetVersionMinor;
+ {
+ std::ostringstream majorStream;
+ std::ostringstream minorStream;
+ int major;
+ int minor;
+ this->GeneratorTarget->GetTargetVersion(major, minor);
+ majorStream << major;
+ minorStream << minor;
+ targetVersionMajor = majorStream.str();
+ targetVersionMinor = minorStream.str();
+ }
+ vars.TargetVersionMajor = targetVersionMajor.c_str();
+ vars.TargetVersionMinor = targetVersionMinor.c_str();
+
+ vars.RuleLauncher = "RULE_LAUNCH_LINK";
+ vars.CMTarget = this->GeneratorTarget;
+ vars.Language = linkLanguage.c_str();
+ vars.Objects = buildObjs.c_str();
+ std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
+ objectDir = this->Convert(objectDir, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+ vars.ObjectDir = objectDir.c_str();
+ cmOutputConverter::OutputFormat output = (useWatcomQuote)
+ ? cmOutputConverter::WATCOMQUOTE
+ : cmOutputConverter::SHELL;
+ std::string target = this->Convert(
+ targetFullPathReal, cmOutputConverter::START_OUTPUT, output);
+ vars.Target = target.c_str();
+ vars.LinkLibraries = linkLibs.c_str();
+ vars.ObjectsQuoted = buildObjs.c_str();
+ if (this->GeneratorTarget->HasSOName(this->ConfigName)) {
+ vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage);
+ vars.TargetSOName = targetNameSO.c_str();
+ }
+ vars.LinkFlags = linkFlags.c_str();
+
+ vars.Manifests = manifests.c_str();
+
+ // Compute the directory portion of the install_name setting.
+ std::string install_name_dir;
+ if (this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY) {
+ // Get the install_name directory for the build tree.
+ install_name_dir =
+ this->GeneratorTarget->GetInstallNameDirForBuildTree(this->ConfigName);
+
+ // Set the rule variable replacement value.
+ if (install_name_dir.empty()) {
+ vars.TargetInstallNameDir = "";
+ } else {
+ // Convert to a path for the native build tool.
+ install_name_dir = this->LocalGenerator->Convert(
+ install_name_dir, cmOutputConverter::NONE, cmOutputConverter::SHELL);
+ vars.TargetInstallNameDir = install_name_dir.c_str();
+ }
+ }
+
+ // Add language feature flags.
+ std::string langFlags;
+ this->AddFeatureFlags(langFlags, linkLanguage);
+
+ this->LocalGenerator->AddArchitectureFlags(
+ langFlags, this->GeneratorTarget, linkLanguage, this->ConfigName);
+
+ // remove any language flags that might not work with the
+ // particular os
+ if (forbiddenFlagVar) {
+ this->RemoveForbiddenFlags(forbiddenFlagVar, linkLanguage, langFlags);
+ }
+ vars.LanguageCompileFlags = langFlags.c_str();
+
+ // Construct the main link rule and expand placeholders.
+ this->LocalGenerator->TargetImplib = targetOutPathImport;
+ if (useArchiveRules) {
+ // Construct the individual object list strings.
+ std::vector<std::string> object_strings;
+ this->WriteObjectsStrings(object_strings, archiveCommandLimit);
+
+ // Create the archive with the first set of objects.
+ std::vector<std::string>::iterator osi = object_strings.begin();
+ {
+ vars.Objects = osi->c_str();
+ for (std::vector<std::string>::const_iterator i =
+ archiveCreateCommands.begin();
+ i != archiveCreateCommands.end(); ++i) {
+ std::string cmd = *i;
+ this->LocalGenerator->ExpandRuleVariables(cmd, vars);
+ real_link_commands.push_back(cmd);
+ }
+ }
+ // Append to the archive with the other object sets.
+ for (++osi; osi != object_strings.end(); ++osi) {
+ vars.Objects = osi->c_str();
+ for (std::vector<std::string>::const_iterator i =
+ archiveAppendCommands.begin();
+ i != archiveAppendCommands.end(); ++i) {
+ std::string cmd = *i;
+ this->LocalGenerator->ExpandRuleVariables(cmd, vars);
+ real_link_commands.push_back(cmd);
+ }
+ }
+ // Finish the archive.
+ vars.Objects = "";
+ for (std::vector<std::string>::const_iterator i =
+ archiveFinishCommands.begin();
+ i != archiveFinishCommands.end(); ++i) {
+ std::string cmd = *i;
+ this->LocalGenerator->ExpandRuleVariables(cmd, vars);
+ // If there is no ranlib the command will be ":". Skip it.
+ if (!cmd.empty() && cmd[0] != ':') {
+ real_link_commands.push_back(cmd);
+ }
+ }
+ } else {
+ // Get the set of commands.
+ std::string linkRule = this->GetLinkRule(linkRuleVar);
+ cmSystemTools::ExpandListArgument(linkRule, real_link_commands);
+ if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE") &&
+ (this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY)) {
+ std::string cmakeCommand =
+ this->Convert(cmSystemTools::GetCMakeCommand(),
+ cmLocalGenerator::NONE, cmLocalGenerator::SHELL);
+ cmakeCommand += " -E __run_iwyu --lwyu=";
+ cmakeCommand += targetOutPathReal;
+ real_link_commands.push_back(cmakeCommand);
+ }
+
+ // Expand placeholders.
+ for (std::vector<std::string>::iterator i = real_link_commands.begin();
+ i != real_link_commands.end(); ++i) {
+ this->LocalGenerator->ExpandRuleVariables(*i, vars);
+ }
+ }
+ this->LocalGenerator->TargetImplib = "";
+
+ // Restore path conversion to normal shells.
+ this->LocalGenerator->SetLinkScriptShell(false);
+ }
+
+ // Optionally convert the build rule to use a script to avoid long
+ // command lines in the make shell.
+ if (useLinkScript) {
+ // Use a link script.
+ const char* name = (relink ? "relink.txt" : "link.txt");
+ this->CreateLinkScript(name, real_link_commands, commands1, depends);
+ } else {
+ // No link script. Just use the link rule directly.
+ commands1 = real_link_commands;
+ }
+ this->LocalGenerator->CreateCDCommand(
+ commands1, this->Makefile->GetCurrentBinaryDirectory(),
+ cmOutputConverter::HOME_OUTPUT);
+ commands.insert(commands.end(), commands1.begin(), commands1.end());
+ commands1.clear();
+
+ // Add a rule to create necessary symlinks for the library.
+ // Frameworks are handled by cmOSXBundleGenerator.
+ if (targetOutPath != targetOutPathReal &&
+ !this->GeneratorTarget->IsFrameworkOnApple()) {
+ std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_library ";
+ symlink += targetOutPathReal;
+ symlink += " ";
+ symlink += targetOutPathSO;
+ symlink += " ";
+ symlink += targetOutPath;
+ commands1.push_back(symlink);
+ this->LocalGenerator->CreateCDCommand(
+ commands1, this->Makefile->GetCurrentBinaryDirectory(),
+ cmOutputConverter::HOME_OUTPUT);
+ commands.insert(commands.end(), commands1.begin(), commands1.end());
+ commands1.clear();
+ }
+
+ // Add the post-build rules when building but not when relinking.
+ if (!relink) {
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPostBuildCommands(),
+ this->GeneratorTarget);
+ }
+
+ // Compute the list of outputs.
+ std::vector<std::string> outputs(1, targetFullPathReal);
+ if (targetNameSO != targetNameReal) {
+ outputs.push_back(targetFullPathSO);
+ }
+ if (targetName != targetNameSO && targetName != targetNameReal) {
+ outputs.push_back(targetFullPath);
+ }
+
+ // Write the build rule.
+ this->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, outputs, depends,
+ commands, false);
+
+ // Write the main driver rule to build everything in this target.
+ this->WriteTargetDriverRule(targetFullPath, relink);
+
+ // Clean all the possible library names and symlinks.
+ this->CleanFiles.insert(this->CleanFiles.end(), libCleanFiles.begin(),
+ libCleanFiles.end());
+}
diff --git a/Source/cmMakefileLibraryTargetGenerator.h b/Source/cmMakefileLibraryTargetGenerator.h
new file mode 100644
index 0000000..935d8b1
--- /dev/null
+++ b/Source/cmMakefileLibraryTargetGenerator.h
@@ -0,0 +1,41 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmMakefileLibraryTargetGenerator_h
+#define cmMakefileLibraryTargetGenerator_h
+
+#include "cmMakefileTargetGenerator.h"
+
+class cmMakefileLibraryTargetGenerator : public cmMakefileTargetGenerator
+{
+public:
+ cmMakefileLibraryTargetGenerator(cmGeneratorTarget* target);
+ ~cmMakefileLibraryTargetGenerator() CM_OVERRIDE;
+
+ /* the main entry point for this class. Writes the Makefiles associated
+ with this target */
+ void WriteRuleFiles() CM_OVERRIDE;
+
+protected:
+ void WriteObjectLibraryRules();
+ void WriteStaticLibraryRules();
+ void WriteSharedLibraryRules(bool relink);
+ void WriteModuleLibraryRules(bool relink);
+ void WriteLibraryRules(const std::string& linkRule,
+ const std::string& extraFlags, bool relink);
+ // MacOSX Framework support methods
+ void WriteFrameworkRules(bool relink);
+
+ // Store the computd framework version for OS X Frameworks.
+ std::string FrameworkVersion;
+};
+
+#endif
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
new file mode 100644
index 0000000..2f9c4da
--- /dev/null
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -0,0 +1,1597 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmMakefileTargetGenerator.h"
+
+#include "cmAlgorithms.h"
+#include "cmComputeLinkInformation.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmake.h"
+
+#include "cmMakefileExecutableTargetGenerator.h"
+#include "cmMakefileLibraryTargetGenerator.h"
+#include "cmMakefileUtilityTargetGenerator.h"
+
+#include <ctype.h>
+
+cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target)
+ : cmCommonTargetGenerator(target)
+ , OSXBundleGenerator(CM_NULLPTR)
+ , MacOSXContentGenerator(CM_NULLPTR)
+{
+ this->BuildFileStream = CM_NULLPTR;
+ this->InfoFileStream = CM_NULLPTR;
+ this->FlagFileStream = CM_NULLPTR;
+ this->CustomCommandDriver = OnBuild;
+ this->LocalGenerator =
+ static_cast<cmLocalUnixMakefileGenerator3*>(target->GetLocalGenerator());
+ this->GlobalGenerator = static_cast<cmGlobalUnixMakefileGenerator3*>(
+ this->LocalGenerator->GetGlobalGenerator());
+ cmake* cm = this->GlobalGenerator->GetCMakeInstance();
+ this->NoRuleMessages = false;
+ if (const char* ruleStatus =
+ cm->GetState()->GetGlobalProperty("RULE_MESSAGES")) {
+ this->NoRuleMessages = cmSystemTools::IsOff(ruleStatus);
+ }
+ MacOSXContentGenerator = new MacOSXContentGeneratorType(this);
+}
+
+cmMakefileTargetGenerator::~cmMakefileTargetGenerator()
+{
+ delete MacOSXContentGenerator;
+}
+
+cmMakefileTargetGenerator* cmMakefileTargetGenerator::New(
+ cmGeneratorTarget* tgt)
+{
+ cmMakefileTargetGenerator* result = CM_NULLPTR;
+
+ switch (tgt->GetType()) {
+ case cmState::EXECUTABLE:
+ result = new cmMakefileExecutableTargetGenerator(tgt);
+ break;
+ case cmState::STATIC_LIBRARY:
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ case cmState::OBJECT_LIBRARY:
+ result = new cmMakefileLibraryTargetGenerator(tgt);
+ break;
+ case cmState::UTILITY:
+ result = new cmMakefileUtilityTargetGenerator(tgt);
+ break;
+ default:
+ return result;
+ // break; /* unreachable */
+ }
+ return result;
+}
+
+void cmMakefileTargetGenerator::CreateRuleFile()
+{
+ // Create a directory for this target.
+ this->TargetBuildDirectory =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ this->TargetBuildDirectoryFull =
+ this->LocalGenerator->ConvertToFullPath(this->TargetBuildDirectory);
+ cmSystemTools::MakeDirectory(this->TargetBuildDirectoryFull.c_str());
+
+ // Construct the rule file name.
+ this->BuildFileName = this->TargetBuildDirectory;
+ this->BuildFileName += "/build.make";
+ this->BuildFileNameFull = this->TargetBuildDirectoryFull;
+ this->BuildFileNameFull += "/build.make";
+
+ // Construct the rule file name.
+ this->ProgressFileNameFull = this->TargetBuildDirectoryFull;
+ this->ProgressFileNameFull += "/progress.make";
+
+ // reset the progress count
+ this->NumberOfProgressActions = 0;
+
+ // Open the rule file. This should be copy-if-different because the
+ // rules may depend on this file itself.
+ this->BuildFileStream =
+ new cmGeneratedFileStream(this->BuildFileNameFull.c_str());
+ this->BuildFileStream->SetCopyIfDifferent(true);
+ if (!this->BuildFileStream) {
+ return;
+ }
+ this->LocalGenerator->WriteDisclaimer(*this->BuildFileStream);
+ if (this->GlobalGenerator->AllowDeleteOnError()) {
+ std::vector<std::string> no_depends;
+ std::vector<std::string> no_commands;
+ this->LocalGenerator->WriteMakeRule(
+ *this->BuildFileStream, "Delete rule output on recipe failure.",
+ ".DELETE_ON_ERROR", no_depends, no_commands, false);
+ }
+ this->LocalGenerator->WriteSpecialTargetsTop(*this->BuildFileStream);
+}
+
+void cmMakefileTargetGenerator::WriteTargetBuildRules()
+{
+ 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")) {
+ cmGeneratorExpression ge;
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge =
+ ge.Parse(additional_clean_files);
+
+ cmSystemTools::ExpandListArgument(
+ cge->Evaluate(this->LocalGenerator, config, false, this->GeneratorTarget,
+ CM_NULLPTR, CM_NULLPTR),
+ this->CleanFiles);
+ }
+
+ // add custom commands to the clean rules?
+ const char* clean_no_custom = this->Makefile->GetProperty("CLEAN_NO_CUSTOM");
+ bool clean = cmSystemTools::IsOff(clean_no_custom);
+
+ // First generate the object rule files. Save a list of all object
+ // files for this target.
+ std::vector<cmSourceFile const*> customCommands;
+ this->GeneratorTarget->GetCustomCommands(customCommands, config);
+ for (std::vector<cmSourceFile const*>::const_iterator si =
+ customCommands.begin();
+ si != customCommands.end(); ++si) {
+ cmCustomCommandGenerator ccg(*(*si)->GetCustomCommand(), this->ConfigName,
+ this->LocalGenerator);
+ this->GenerateCustomRuleFile(ccg);
+ if (clean) {
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ for (std::vector<std::string>::const_iterator o = outputs.begin();
+ o != outputs.end(); ++o) {
+ this->CleanFiles.push_back(this->Convert(
+ *o, cmOutputConverter::START_OUTPUT, cmOutputConverter::UNCHANGED));
+ }
+ }
+ }
+ 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 (std::vector<cmSourceFile const*>::const_iterator si =
+ externalObjects.begin();
+ si != externalObjects.end(); ++si) {
+ this->ExternalObjects.push_back((*si)->GetFullPath());
+ }
+ std::vector<cmSourceFile const*> objectSources;
+ this->GeneratorTarget->GetObjectSources(objectSources, config);
+ for (std::vector<cmSourceFile const*>::const_iterator si =
+ objectSources.begin();
+ si != objectSources.end(); ++si) {
+ // Generate this object file's rule file.
+ this->WriteObjectRuleFiles(**si);
+ }
+}
+
+void cmMakefileTargetGenerator::WriteCommonCodeRules()
+{
+ const char* root = (this->Makefile->IsOn("CMAKE_MAKE_INCLUDE_FROM_ROOT")
+ ? "$(CMAKE_BINARY_DIR)/"
+ : "");
+
+ // Include the dependencies for the target.
+ std::string dependFileNameFull = this->TargetBuildDirectoryFull;
+ dependFileNameFull += "/depend.make";
+ *this->BuildFileStream
+ << "# Include any dependencies generated for this target.\n"
+ << this->GlobalGenerator->IncludeDirective << " " << root
+ << this->Convert(dependFileNameFull, cmOutputConverter::HOME_OUTPUT,
+ cmOutputConverter::MAKERULE)
+ << "\n\n";
+
+ if (!this->NoRuleMessages) {
+ // Include the progress variables for the target.
+ *this->BuildFileStream
+ << "# Include the progress variables for this target.\n"
+ << this->GlobalGenerator->IncludeDirective << " " << root
+ << this->Convert(this->ProgressFileNameFull,
+ cmOutputConverter::HOME_OUTPUT,
+ cmOutputConverter::MAKERULE)
+ << "\n\n";
+ }
+
+ // make sure the depend file exists
+ if (!cmSystemTools::FileExists(dependFileNameFull.c_str())) {
+ // Write an empty dependency file.
+ cmGeneratedFileStream depFileStream(dependFileNameFull.c_str());
+ depFileStream << "# Empty dependencies file for "
+ << this->GeneratorTarget->GetName() << ".\n"
+ << "# This may be replaced when dependencies are built."
+ << std::endl;
+ }
+
+ // Open the flags file. This should be copy-if-different because the
+ // rules may depend on this file itself.
+ this->FlagFileNameFull = this->TargetBuildDirectoryFull;
+ this->FlagFileNameFull += "/flags.make";
+ this->FlagFileStream =
+ new cmGeneratedFileStream(this->FlagFileNameFull.c_str());
+ this->FlagFileStream->SetCopyIfDifferent(true);
+ if (!this->FlagFileStream) {
+ return;
+ }
+ this->LocalGenerator->WriteDisclaimer(*this->FlagFileStream);
+
+ // Include the flags for the target.
+ *this->BuildFileStream
+ << "# Include the compile flags for this target's objects.\n"
+ << this->GlobalGenerator->IncludeDirective << " " << root
+ << this->Convert(this->FlagFileNameFull, cmOutputConverter::HOME_OUTPUT,
+ cmOutputConverter::MAKERULE)
+ << "\n\n";
+}
+
+void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
+{
+ // write language flags for target
+ std::set<std::string> languages;
+ this->GeneratorTarget->GetLanguages(
+ languages, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ // put the compiler in the rules.make file so that if it changes
+ // things rebuild
+ for (std::set<std::string>::const_iterator l = languages.begin();
+ l != languages.end(); ++l) {
+ std::string compiler = "CMAKE_";
+ compiler += *l;
+ compiler += "_COMPILER";
+ *this->FlagFileStream << "# compile " << *l << " with "
+ << this->Makefile->GetSafeDefinition(compiler)
+ << "\n";
+ }
+
+ for (std::set<std::string>::const_iterator l = languages.begin();
+ l != languages.end(); ++l) {
+ std::string flags = this->GetFlags(*l);
+ std::string defines = this->GetDefines(*l);
+ std::string includes = this->GetIncludes(*l);
+ // Escape comment characters so they do not terminate assignment.
+ cmSystemTools::ReplaceString(flags, "#", "\\#");
+ cmSystemTools::ReplaceString(defines, "#", "\\#");
+ cmSystemTools::ReplaceString(includes, "#", "\\#");
+ *this->FlagFileStream << *l << "_FLAGS = " << flags << "\n\n";
+ *this->FlagFileStream << *l << "_DEFINES = " << defines << "\n\n";
+ *this->FlagFileStream << *l << "_INCLUDES = " << includes << "\n\n";
+ }
+}
+
+void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()(
+ cmSourceFile const& source, const char* pkgloc)
+{
+ // Skip OS X content when not building a Framework or Bundle.
+ if (!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) {
+ return;
+ }
+
+ std::string macdir =
+ this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc);
+
+ // Get the input file location.
+ std::string const& input = source.GetFullPath();
+
+ // Get the output file location.
+ std::string output = macdir;
+ output += "/";
+ output += cmSystemTools::GetFilenameName(input);
+ this->Generator->CleanFiles.push_back(
+ this->Generator->Convert(output, cmOutputConverter::START_OUTPUT));
+ output = this->Generator->Convert(output, cmOutputConverter::HOME_OUTPUT);
+
+ // Create a rule to copy the content into the bundle.
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+ depends.push_back(input);
+ std::string copyEcho = "Copying OS X content ";
+ copyEcho += output;
+ this->Generator->LocalGenerator->AppendEcho(
+ commands, copyEcho, cmLocalUnixMakefileGenerator3::EchoBuild);
+ std::string copyCommand = "$(CMAKE_COMMAND) -E copy ";
+ copyCommand += this->Generator->Convert(input, cmOutputConverter::NONE,
+ cmOutputConverter::SHELL);
+ copyCommand += " ";
+ copyCommand += this->Generator->Convert(output, cmOutputConverter::NONE,
+ cmOutputConverter::SHELL);
+ commands.push_back(copyCommand);
+ this->Generator->LocalGenerator->WriteMakeRule(
+ *this->Generator->BuildFileStream, CM_NULLPTR, output, depends, commands,
+ false);
+ this->Generator->ExtraFiles.insert(output);
+}
+
+void cmMakefileTargetGenerator::WriteObjectRuleFiles(
+ cmSourceFile const& source)
+{
+ // Identify the language of the source file.
+ const std::string& lang =
+ this->LocalGenerator->GetSourceFileLanguage(source);
+ if (lang.empty()) {
+ // don't know anything about this file so skip it
+ return;
+ }
+
+ // Get the full path name of the object file.
+ std::string const& objectName =
+ this->GeneratorTarget->GetObjectName(&source);
+ std::string obj =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ obj += "/";
+ obj += objectName;
+
+ // Avoid generating duplicate rules.
+ if (this->ObjectFiles.find(obj) == this->ObjectFiles.end()) {
+ this->ObjectFiles.insert(obj);
+ } else {
+ std::ostringstream err;
+ err << "Warning: Source file \"" << source.GetFullPath()
+ << "\" is listed multiple times for target \""
+ << this->GeneratorTarget->GetName() << "\".";
+ cmSystemTools::Message(err.str().c_str(), "Warning");
+ return;
+ }
+
+ // Create the directory containing the object file. This may be a
+ // subdirectory under the target's directory.
+ std::string dir = cmSystemTools::GetFilenamePath(obj);
+ cmSystemTools::MakeDirectory(
+ this->LocalGenerator->ConvertToFullPath(dir).c_str());
+
+ // Save this in the target's list of object files.
+ this->Objects.push_back(obj);
+ this->CleanFiles.push_back(obj);
+
+ // TODO: Remove
+ // std::string relativeObj
+ //= this->LocalGenerator->GetHomeRelativeOutputPath();
+ // relativeObj += obj;
+
+ // we compute some depends when writing the depend.make that we will also
+ // use in the build.make, same with depMakeFile
+ std::vector<std::string> depends;
+
+ // generate the build rule file
+ this->WriteObjectBuildFile(obj, lang, source, depends);
+
+ // The object file should be checked for dependency integrity.
+ std::string objFullPath = this->LocalGenerator->GetCurrentBinaryDirectory();
+ objFullPath += "/";
+ objFullPath += obj;
+ objFullPath = this->Convert(objFullPath, cmOutputConverter::FULL);
+ std::string srcFullPath =
+ this->Convert(source.GetFullPath(), cmOutputConverter::FULL);
+ this->LocalGenerator->AddImplicitDepends(
+ this->GeneratorTarget, lang, objFullPath.c_str(), srcFullPath.c_str());
+}
+
+void cmMakefileTargetGenerator::WriteObjectBuildFile(
+ std::string& obj, const std::string& lang, cmSourceFile const& source,
+ std::vector<std::string>& depends)
+{
+ this->LocalGenerator->AppendRuleDepend(depends,
+ this->FlagFileNameFull.c_str());
+ this->LocalGenerator->AppendRuleDepends(depends,
+ this->FlagFileDepends[lang]);
+
+ // generate the depend scanning rule
+ this->WriteObjectDependRules(source, depends);
+
+ std::string relativeObj = this->LocalGenerator->GetHomeRelativeOutputPath();
+ relativeObj += obj;
+ // Write the build rule.
+
+ // Build the set of compiler flags.
+ std::string flags;
+
+ // Add language-specific flags.
+ std::string langFlags = "$(";
+ langFlags += lang;
+ langFlags += "_FLAGS)";
+ this->LocalGenerator->AppendFlags(flags, langFlags);
+
+ std::string configUpper =
+ cmSystemTools::UpperCase(this->LocalGenerator->GetConfigName());
+
+ // Add Fortran format flags.
+ if (lang == "Fortran") {
+ this->AppendFortranFormatFlags(flags, source);
+ }
+
+ // Add flags from source file properties.
+ if (source.GetProperty("COMPILE_FLAGS")) {
+ this->LocalGenerator->AppendFlags(flags,
+ source.GetProperty("COMPILE_FLAGS"));
+ *this->FlagFileStream << "# Custom flags: " << relativeObj
+ << "_FLAGS = " << source.GetProperty("COMPILE_FLAGS")
+ << "\n"
+ << "\n";
+ }
+
+ // Add language-specific defines.
+ std::set<std::string> defines;
+
+ // Add source-sepcific preprocessor definitions.
+ if (const char* compile_defs = source.GetProperty("COMPILE_DEFINITIONS")) {
+ this->LocalGenerator->AppendDefines(defines, compile_defs);
+ *this->FlagFileStream << "# Custom defines: " << relativeObj
+ << "_DEFINES = " << compile_defs << "\n"
+ << "\n";
+ }
+ std::string defPropName = "COMPILE_DEFINITIONS_";
+ defPropName += configUpper;
+ if (const char* config_compile_defs = source.GetProperty(defPropName)) {
+ this->LocalGenerator->AppendDefines(defines, config_compile_defs);
+ *this->FlagFileStream << "# Custom defines: " << relativeObj << "_DEFINES_"
+ << configUpper << " = " << config_compile_defs
+ << "\n"
+ << "\n";
+ }
+
+ // Get the output paths for source and object files.
+ std::string sourceFile = this->Convert(
+ source.GetFullPath(), cmOutputConverter::NONE, cmOutputConverter::SHELL);
+
+ // Construct the build message.
+ std::vector<std::string> no_commands;
+ std::vector<std::string> commands;
+
+ // add in a progress call if needed
+ this->NumberOfProgressActions++;
+
+ if (!this->NoRuleMessages) {
+ cmLocalUnixMakefileGenerator3::EchoProgress progress;
+ this->MakeEchoProgress(progress);
+ std::string buildEcho = "Building ";
+ buildEcho += lang;
+ buildEcho += " object ";
+ buildEcho += relativeObj;
+ this->LocalGenerator->AppendEcho(commands, buildEcho,
+ cmLocalUnixMakefileGenerator3::EchoBuild,
+ &progress);
+ }
+
+ std::string targetOutPathReal;
+ std::string targetOutPathPDB;
+ std::string targetOutPathCompilePDB;
+ {
+ std::string targetFullPathReal;
+ std::string targetFullPathPDB;
+ std::string targetFullPathCompilePDB;
+ if (this->GeneratorTarget->GetType() == cmState::EXECUTABLE ||
+ this->GeneratorTarget->GetType() == cmState::STATIC_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmState::MODULE_LIBRARY) {
+ targetFullPathReal =
+ this->GeneratorTarget->GetFullPath(this->ConfigName, false, true);
+ targetFullPathPDB =
+ this->GeneratorTarget->GetPDBDirectory(this->ConfigName);
+ targetFullPathPDB += "/";
+ targetFullPathPDB += this->GeneratorTarget->GetPDBName(this->ConfigName);
+ }
+ if (this->GeneratorTarget->GetType() <= cmState::OBJECT_LIBRARY) {
+ targetFullPathCompilePDB =
+ this->GeneratorTarget->GetCompilePDBPath(this->ConfigName);
+ if (targetFullPathCompilePDB.empty()) {
+ targetFullPathCompilePDB =
+ this->GeneratorTarget->GetSupportDirectory() + "/";
+ }
+ }
+
+ targetOutPathReal =
+ this->Convert(targetFullPathReal, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+ targetOutPathPDB = this->Convert(
+ targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL);
+ targetOutPathCompilePDB =
+ this->Convert(targetFullPathCompilePDB, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+
+ if (this->LocalGenerator->IsMinGWMake() &&
+ cmHasLiteralSuffix(targetOutPathCompilePDB, "\\")) {
+ // mingw32-make incorrectly interprets 'a\ b c' as 'a b' and 'c'
+ // (but 'a\ b "c"' as 'a\', 'b', and 'c'!). Workaround this by
+ // avoiding a trailing backslash in the argument.
+ targetOutPathCompilePDB[targetOutPathCompilePDB.size() - 1] = '/';
+ }
+ }
+ cmLocalGenerator::RuleVariables vars;
+ vars.RuleLauncher = "RULE_LAUNCH_COMPILE";
+ vars.CMTarget = this->GeneratorTarget;
+ vars.Language = lang.c_str();
+ vars.Target = targetOutPathReal.c_str();
+ vars.TargetPDB = targetOutPathPDB.c_str();
+ vars.TargetCompilePDB = targetOutPathCompilePDB.c_str();
+ vars.Source = sourceFile.c_str();
+ std::string shellObj =
+ this->Convert(obj, cmOutputConverter::NONE, cmOutputConverter::SHELL);
+ vars.Object = shellObj.c_str();
+ std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
+ objectDir = this->Convert(objectDir, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+ vars.ObjectDir = objectDir.c_str();
+ std::string objectFileDir = cmSystemTools::GetFilenamePath(obj);
+ objectFileDir = this->Convert(objectFileDir, cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::SHELL);
+ vars.ObjectFileDir = objectFileDir.c_str();
+ vars.Flags = flags.c_str();
+
+ std::string definesString = "$(";
+ definesString += lang;
+ definesString += "_DEFINES)";
+
+ this->LocalGenerator->JoinDefines(defines, definesString, lang);
+
+ vars.Defines = definesString.c_str();
+
+ std::string const includesString = "$(" + lang + "_INCLUDES)";
+ vars.Includes = includesString.c_str();
+
+ // At the moment, it is assumed that C, C++, and Fortran have both
+ // assembly and preprocessor capabilities. The same is true for the
+ // ability to export compile commands
+ bool lang_has_preprocessor =
+ ((lang == "C") || (lang == "CXX") || (lang == "Fortran"));
+ bool const lang_has_assembly = lang_has_preprocessor;
+ bool const lang_can_export_cmds = lang_has_preprocessor;
+
+ // Construct the compile rules.
+ {
+ std::string compileRuleVar = "CMAKE_";
+ compileRuleVar += lang;
+ compileRuleVar += "_COMPILE_OBJECT";
+ std::string compileRule =
+ this->Makefile->GetRequiredDefinition(compileRuleVar);
+ std::vector<std::string> compileCommands;
+ cmSystemTools::ExpandListArgument(compileRule, compileCommands);
+
+ if (this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS") &&
+ lang_can_export_cmds && compileCommands.size() == 1) {
+ std::string compileCommand = compileCommands[0];
+ this->LocalGenerator->ExpandRuleVariables(compileCommand, vars);
+ std::string workingDirectory = this->LocalGenerator->Convert(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ cmOutputConverter::FULL);
+ compileCommand.replace(compileCommand.find(langFlags), langFlags.size(),
+ this->GetFlags(lang));
+ std::string langDefines = std::string("$(") + lang + "_DEFINES)";
+ compileCommand.replace(compileCommand.find(langDefines),
+ langDefines.size(), this->GetDefines(lang));
+ std::string langIncludes = std::string("$(") + lang + "_INCLUDES)";
+ compileCommand.replace(compileCommand.find(langIncludes),
+ langIncludes.size(), this->GetIncludes(lang));
+ this->GlobalGenerator->AddCXXCompileCommand(
+ source.GetFullPath(), workingDirectory, compileCommand);
+ }
+
+ // Maybe insert an include-what-you-use runner.
+ if (!compileCommands.empty() && (lang == "C" || lang == "CXX")) {
+ std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE";
+ const char* iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
+ std::string const tidy_prop = lang + "_CLANG_TIDY";
+ const char* tidy = this->GeneratorTarget->GetProperty(tidy_prop);
+ if ((iwyu && *iwyu) || (tidy && *tidy)) {
+ std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_iwyu";
+ if (iwyu && *iwyu) {
+ run_iwyu += " --iwyu=";
+ run_iwyu += this->LocalGenerator->EscapeForShell(iwyu);
+ }
+ if (tidy && *tidy) {
+ run_iwyu += " --tidy=";
+ run_iwyu += this->LocalGenerator->EscapeForShell(tidy);
+ run_iwyu += " --source=";
+ run_iwyu += sourceFile;
+ }
+ run_iwyu += " -- ";
+ compileCommands.front().insert(0, run_iwyu);
+ }
+ }
+
+ // Maybe insert a compiler launcher like ccache or distcc
+ if (!compileCommands.empty() && (lang == "C" || lang == "CXX")) {
+ std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER";
+ const char* clauncher =
+ this->GeneratorTarget->GetProperty(clauncher_prop);
+ if (clauncher && *clauncher) {
+ std::vector<std::string> launcher_cmd;
+ cmSystemTools::ExpandListArgument(clauncher, launcher_cmd, true);
+ for (std::vector<std::string>::iterator i = launcher_cmd.begin(),
+ e = launcher_cmd.end();
+ i != e; ++i) {
+ *i = this->LocalGenerator->EscapeForShell(*i);
+ }
+ std::string const& run_launcher = cmJoin(launcher_cmd, " ") + " ";
+ compileCommands.front().insert(0, run_launcher);
+ }
+ }
+
+ // Expand placeholders in the commands.
+ for (std::vector<std::string>::iterator i = compileCommands.begin();
+ i != compileCommands.end(); ++i) {
+ this->LocalGenerator->ExpandRuleVariables(*i, vars);
+ }
+
+ // Change the command working directory to the local build tree.
+ this->LocalGenerator->CreateCDCommand(
+ compileCommands, this->LocalGenerator->GetCurrentBinaryDirectory(),
+ cmOutputConverter::HOME_OUTPUT);
+ commands.insert(commands.end(), compileCommands.begin(),
+ compileCommands.end());
+ }
+
+ // Check for extra outputs created by the compilation.
+ std::vector<std::string> outputs(1, relativeObj);
+ 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());
+ }
+
+ // Write the rule.
+ this->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, outputs, depends,
+ commands);
+
+ bool do_preprocess_rules = lang_has_preprocessor &&
+ this->LocalGenerator->GetCreatePreprocessedSourceRules();
+ bool do_assembly_rules =
+ lang_has_assembly && this->LocalGenerator->GetCreateAssemblySourceRules();
+ if (do_preprocess_rules || do_assembly_rules) {
+ std::vector<std::string> force_depends;
+ force_depends.push_back("cmake_force");
+ std::string::size_type dot_pos = relativeObj.rfind('.');
+ std::string relativeObjBase = relativeObj.substr(0, dot_pos);
+ dot_pos = obj.rfind('.');
+ std::string objBase = obj.substr(0, dot_pos);
+
+ if (do_preprocess_rules) {
+ commands.clear();
+ std::string relativeObjI = relativeObjBase + ".i";
+ std::string objI = objBase + ".i";
+
+ std::string preprocessEcho = "Preprocessing ";
+ preprocessEcho += lang;
+ preprocessEcho += " source to ";
+ preprocessEcho += objI;
+ this->LocalGenerator->AppendEcho(
+ commands, preprocessEcho, cmLocalUnixMakefileGenerator3::EchoBuild);
+
+ std::string preprocessRuleVar = "CMAKE_";
+ preprocessRuleVar += lang;
+ preprocessRuleVar += "_CREATE_PREPROCESSED_SOURCE";
+ if (const char* preprocessRule =
+ this->Makefile->GetDefinition(preprocessRuleVar)) {
+ std::vector<std::string> preprocessCommands;
+ cmSystemTools::ExpandListArgument(preprocessRule, preprocessCommands);
+
+ std::string shellObjI = this->Convert(objI, cmOutputConverter::NONE,
+ cmOutputConverter::SHELL);
+ vars.PreprocessedSource = shellObjI.c_str();
+
+ // Expand placeholders in the commands.
+ for (std::vector<std::string>::iterator i = preprocessCommands.begin();
+ i != preprocessCommands.end(); ++i) {
+ this->LocalGenerator->ExpandRuleVariables(*i, vars);
+ }
+
+ this->LocalGenerator->CreateCDCommand(
+ preprocessCommands,
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ cmOutputConverter::HOME_OUTPUT);
+ commands.insert(commands.end(), preprocessCommands.begin(),
+ preprocessCommands.end());
+ } else {
+ std::string cmd = "$(CMAKE_COMMAND) -E cmake_unimplemented_variable ";
+ cmd += preprocessRuleVar;
+ commands.push_back(cmd);
+ }
+
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR,
+ relativeObjI, force_depends,
+ commands, false);
+ }
+
+ if (do_assembly_rules) {
+ commands.clear();
+ std::string relativeObjS = relativeObjBase + ".s";
+ std::string objS = objBase + ".s";
+
+ std::string assemblyEcho = "Compiling ";
+ assemblyEcho += lang;
+ assemblyEcho += " source to assembly ";
+ assemblyEcho += objS;
+ this->LocalGenerator->AppendEcho(
+ commands, assemblyEcho, cmLocalUnixMakefileGenerator3::EchoBuild);
+
+ std::string assemblyRuleVar = "CMAKE_";
+ assemblyRuleVar += lang;
+ assemblyRuleVar += "_CREATE_ASSEMBLY_SOURCE";
+ if (const char* assemblyRule =
+ this->Makefile->GetDefinition(assemblyRuleVar)) {
+ std::vector<std::string> assemblyCommands;
+ cmSystemTools::ExpandListArgument(assemblyRule, assemblyCommands);
+
+ std::string shellObjS = this->Convert(objS, cmOutputConverter::NONE,
+ cmOutputConverter::SHELL);
+ vars.AssemblySource = shellObjS.c_str();
+
+ // Expand placeholders in the commands.
+ for (std::vector<std::string>::iterator i = assemblyCommands.begin();
+ i != assemblyCommands.end(); ++i) {
+ this->LocalGenerator->ExpandRuleVariables(*i, vars);
+ }
+
+ this->LocalGenerator->CreateCDCommand(
+ assemblyCommands, this->LocalGenerator->GetCurrentBinaryDirectory(),
+ cmOutputConverter::HOME_OUTPUT);
+ commands.insert(commands.end(), assemblyCommands.begin(),
+ assemblyCommands.end());
+ } else {
+ std::string cmd = "$(CMAKE_COMMAND) -E cmake_unimplemented_variable ";
+ cmd += assemblyRuleVar;
+ commands.push_back(cmd);
+ }
+
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR,
+ relativeObjS, force_depends,
+ commands, false);
+ }
+ }
+
+ // If the language needs provides-requires mode, create the
+ // corresponding targets.
+ std::string objectRequires = relativeObj;
+ objectRequires += ".requires";
+ std::vector<std::string> p_depends;
+ // always provide an empty requires target
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR,
+ objectRequires, p_depends, no_commands,
+ true);
+
+ // write a build rule to recursively build what this obj provides
+ std::string objectProvides = relativeObj;
+ objectProvides += ".provides";
+ std::string temp = relativeObj;
+ temp += ".provides.build";
+ std::vector<std::string> r_commands;
+ std::string tgtMakefileName =
+ this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget);
+ tgtMakefileName += "/build.make";
+ r_commands.push_back(
+ this->LocalGenerator->GetRecursiveMakeCall(tgtMakefileName.c_str(), temp));
+
+ p_depends.clear();
+ p_depends.push_back(objectRequires);
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR,
+ objectProvides, p_depends, r_commands,
+ true);
+
+ // write the provides.build rule dependency on the obj file
+ p_depends.clear();
+ p_depends.push_back(relativeObj);
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, temp,
+ p_depends, no_commands, false);
+}
+
+void cmMakefileTargetGenerator::WriteTargetRequiresRules()
+{
+ std::vector<std::string> depends;
+ std::vector<std::string> no_commands;
+
+ // Construct the name of the dependency generation target.
+ std::string depTarget =
+ this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget);
+ depTarget += "/requires";
+
+ // This target drives dependency generation for all object files.
+ std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath();
+ std::string objTarget;
+ for (std::vector<std::string>::const_iterator obj = this->Objects.begin();
+ obj != this->Objects.end(); ++obj) {
+ objTarget = relPath;
+ objTarget += *obj;
+ objTarget += ".requires";
+ depends.push_back(objTarget);
+ }
+
+ // Write the rule.
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR,
+ depTarget, depends, no_commands, true);
+}
+
+void cmMakefileTargetGenerator::WriteTargetCleanRules()
+{
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+
+ // Construct the clean target name.
+ std::string cleanTarget =
+ this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget);
+ cleanTarget += "/clean";
+
+ // Construct the clean command.
+ this->LocalGenerator->AppendCleanCommand(commands, this->CleanFiles,
+ this->GeneratorTarget);
+ this->LocalGenerator->CreateCDCommand(
+ commands, this->LocalGenerator->GetCurrentBinaryDirectory(),
+ cmOutputConverter::HOME_OUTPUT);
+
+ // Write the rule.
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR,
+ cleanTarget, depends, commands, true);
+}
+
+bool cmMakefileTargetGenerator::WriteMakeRule(
+ std::ostream& os, const char* comment,
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& depends,
+ const std::vector<std::string>& commands, bool in_help)
+{
+ bool symbolic = false;
+ if (outputs.empty()) {
+ return symbolic;
+ }
+
+ // Check whether we need to bother checking for a symbolic output.
+ bool need_symbolic = this->GlobalGenerator->GetNeedSymbolicMark();
+
+ // Check whether the first output is marked as symbolic.
+ if (need_symbolic) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(outputs[0])) {
+ symbolic = sf->GetPropertyAsBool("SYMBOLIC");
+ }
+ }
+
+ // We always attach the actual commands to the first output.
+ this->LocalGenerator->WriteMakeRule(os, comment, outputs[0], depends,
+ commands, symbolic, in_help);
+
+ // For single outputs, we are done.
+ if (outputs.size() == 1) {
+ return symbolic;
+ }
+
+ // For multiple outputs, make the extra ones depend on the first one.
+ std::vector<std::string> const output_depends(1, outputs[0]);
+ for (std::vector<std::string>::const_iterator o = outputs.begin() + 1;
+ o != outputs.end(); ++o) {
+ // Touch the extra output so "make" knows that it was updated,
+ // but only if the output was acually created.
+ std::string const out = this->Convert(*o, cmOutputConverter::HOME_OUTPUT,
+ cmOutputConverter::SHELL);
+ std::vector<std::string> output_commands;
+
+ bool o_symbolic = false;
+ if (need_symbolic) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(*o)) {
+ o_symbolic = sf->GetPropertyAsBool("SYMBOLIC");
+ }
+ }
+ symbolic = symbolic && o_symbolic;
+
+ if (!o_symbolic) {
+ output_commands.push_back("@$(CMAKE_COMMAND) -E touch_nocreate " + out);
+ }
+ this->LocalGenerator->WriteMakeRule(os, CM_NULLPTR, *o, 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]);
+ this->MultipleOutputPairs.insert(p);
+ }
+ }
+ return symbolic;
+}
+
+void cmMakefileTargetGenerator::WriteTargetDependRules()
+{
+ // must write the targets depend info file
+ std::string dir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ this->InfoFileNameFull = dir;
+ this->InfoFileNameFull += "/DependInfo.cmake";
+ this->InfoFileNameFull =
+ this->LocalGenerator->ConvertToFullPath(this->InfoFileNameFull);
+ this->InfoFileStream =
+ new cmGeneratedFileStream(this->InfoFileNameFull.c_str());
+ this->InfoFileStream->SetCopyIfDifferent(true);
+ if (!*this->InfoFileStream) {
+ return;
+ }
+ this->LocalGenerator->WriteDependLanguageInfo(*this->InfoFileStream,
+ this->GeneratorTarget);
+
+ // Store multiple output pairs in the depend info file.
+ if (!this->MultipleOutputPairs.empty()) {
+ /* clang-format off */
+ *this->InfoFileStream
+ << "\n"
+ << "# Pairs of files generated by the same build rule.\n"
+ << "set(CMAKE_MULTIPLE_OUTPUT_PAIRS\n";
+ /* clang-format on */
+ for (MultipleOutputPairsType::const_iterator pi =
+ this->MultipleOutputPairs.begin();
+ pi != this->MultipleOutputPairs.end(); ++pi) {
+ *this->InfoFileStream
+ << " " << cmOutputConverter::EscapeForCMake(pi->first) << " "
+ << cmOutputConverter::EscapeForCMake(pi->second) << "\n";
+ }
+ *this->InfoFileStream << " )\n\n";
+ }
+
+ // Store list of targets linked directly or transitively.
+ {
+ /* clang-format off */
+ *this->InfoFileStream
+ << "\n"
+ << "# Targets to which this target links.\n"
+ << "set(CMAKE_TARGET_LINKED_INFO_FILES\n";
+ /* clang-format on */
+ std::vector<std::string> dirs = this->GetLinkedTargetDirectories();
+ for (std::vector<std::string>::iterator i = dirs.begin(); i != dirs.end();
+ ++i) {
+ *this->InfoFileStream << " \"" << *i << "/DependInfo.cmake\"\n";
+ }
+ *this->InfoFileStream << " )\n";
+ }
+
+ /* clang-format off */
+ *this->InfoFileStream
+ << "\n"
+ << "# Fortran module output directory.\n"
+ << "set(CMAKE_Fortran_TARGET_MODULE_DIR \""
+ << this->GeneratorTarget->GetFortranModuleDirectory() << "\")\n";
+ /* clang-format on */
+
+ // and now write the rule to use it
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+
+ // Construct the name of the dependency generation target.
+ std::string depTarget =
+ this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget);
+ depTarget += "/depend";
+
+ // Add a command to call CMake to scan dependencies. CMake will
+ // touch the corresponding depends file after scanning dependencies.
+ std::ostringstream depCmd;
+// TODO: Account for source file properties and directory-level
+// definitions when scanning for dependencies.
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ // This platform supports symlinks, so cmSystemTools will translate
+ // paths. Make sure PWD is set to the original name of the home
+ // output directory to help cmSystemTools to create the same
+ // translation table for the dependency scanning process.
+ depCmd << "cd " << (this->LocalGenerator->Convert(
+ this->LocalGenerator->GetBinaryDirectory(),
+ cmOutputConverter::FULL, cmOutputConverter::SHELL))
+ << " && ";
+#endif
+ // Generate a call this signature:
+ //
+ // cmake -E cmake_depends <generator>
+ // <home-src-dir> <start-src-dir>
+ // <home-out-dir> <start-out-dir>
+ // <dep-info> --color=$(COLOR)
+ //
+ // This gives the dependency scanner enough information to recreate
+ // the state of our local generator sufficiently for its needs.
+ depCmd << "$(CMAKE_COMMAND) -E cmake_depends \""
+ << this->GlobalGenerator->GetName() << "\" "
+ << this->Convert(this->LocalGenerator->GetSourceDirectory(),
+ cmOutputConverter::FULL, cmOutputConverter::SHELL)
+ << " "
+ << this->Convert(this->LocalGenerator->GetCurrentSourceDirectory(),
+ cmOutputConverter::FULL, cmOutputConverter::SHELL)
+ << " "
+ << this->Convert(this->LocalGenerator->GetBinaryDirectory(),
+ cmOutputConverter::FULL, cmOutputConverter::SHELL)
+ << " "
+ << this->Convert(this->LocalGenerator->GetCurrentBinaryDirectory(),
+ cmOutputConverter::FULL, cmOutputConverter::SHELL)
+ << " "
+ << this->Convert(this->InfoFileNameFull, cmOutputConverter::FULL,
+ cmOutputConverter::SHELL);
+ if (this->LocalGenerator->GetColorMakefile()) {
+ depCmd << " --color=$(COLOR)";
+ }
+ commands.push_back(depCmd.str());
+
+ // Make sure all custom command outputs in this target are built.
+ if (this->CustomCommandDriver == OnDepends) {
+ this->DriveCustomCommands(depends);
+ }
+
+ // Write the rule.
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR,
+ depTarget, depends, commands, true);
+}
+
+void cmMakefileTargetGenerator::DriveCustomCommands(
+ std::vector<std::string>& depends)
+{
+ // Depend on all custom command outputs.
+ std::vector<cmSourceFile*> sources;
+ this->GeneratorTarget->GetSourceFiles(
+ sources, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ for (std::vector<cmSourceFile*>::const_iterator source = sources.begin();
+ source != sources.end(); ++source) {
+ 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());
+ }
+ }
+}
+
+void cmMakefileTargetGenerator::WriteObjectDependRules(
+ cmSourceFile const& source, std::vector<std::string>& depends)
+{
+ // Create the list of dependencies known at cmake time. These are
+ // shared between the object file and dependency scanning rule.
+ depends.push_back(source.GetFullPath());
+ if (const char* objectDeps = source.GetProperty("OBJECT_DEPENDS")) {
+ cmSystemTools::ExpandListArgument(objectDeps, depends);
+ }
+}
+
+void cmMakefileTargetGenerator::GenerateCustomRuleFile(
+ cmCustomCommandGenerator const& ccg)
+{
+ // Collect the commands.
+ std::vector<std::string> commands;
+ std::string comment = this->LocalGenerator->ConstructComment(ccg);
+ if (!comment.empty()) {
+ // add in a progress call if needed
+ this->NumberOfProgressActions++;
+ if (!this->NoRuleMessages) {
+ cmLocalUnixMakefileGenerator3::EchoProgress progress;
+ this->MakeEchoProgress(progress);
+ this->LocalGenerator->AppendEcho(
+ commands, comment, cmLocalUnixMakefileGenerator3::EchoGenerate,
+ &progress);
+ }
+ }
+
+ // Now append the actual user-specified commands.
+ std::ostringstream content;
+ this->LocalGenerator->AppendCustomCommand(
+ commands, ccg, this->GeneratorTarget, false,
+ cmOutputConverter::HOME_OUTPUT, &content);
+
+ // Collect the dependencies.
+ std::vector<std::string> depends;
+ this->LocalGenerator->AppendCustomDepend(depends, ccg);
+
+ // Write the rule.
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ bool symbolic = this->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR,
+ outputs, depends, commands);
+
+ // If the rule has changed make sure the output is rebuilt.
+ if (!symbolic) {
+ this->GlobalGenerator->AddRuleHash(ccg.GetOutputs(), content.str());
+ }
+
+ // Setup implicit dependency scanning.
+ for (cmCustomCommand::ImplicitDependsList::const_iterator idi =
+ ccg.GetCC().GetImplicitDepends().begin();
+ idi != ccg.GetCC().GetImplicitDepends().end(); ++idi) {
+ std::string objFullPath =
+ this->Convert(outputs[0], cmOutputConverter::FULL);
+ std::string srcFullPath =
+ this->Convert(idi->second, cmOutputConverter::FULL);
+ this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, idi->first,
+ objFullPath.c_str(),
+ srcFullPath.c_str());
+ }
+}
+
+void cmMakefileTargetGenerator::MakeEchoProgress(
+ cmLocalUnixMakefileGenerator3::EchoProgress& progress) const
+{
+ progress.Dir = this->LocalGenerator->GetBinaryDirectory();
+ progress.Dir += cmake::GetCMakeFilesDirectory();
+ std::ostringstream progressArg;
+ progressArg << "$(CMAKE_PROGRESS_" << this->NumberOfProgressActions << ")";
+ progress.Arg = progressArg.str();
+}
+
+void cmMakefileTargetGenerator::WriteObjectsVariable(
+ std::string& variableName, std::string& variableNameExternal,
+ bool useWatcomQuote)
+{
+ // Write a make variable assignment that lists all objects for the
+ // target.
+ variableName = this->LocalGenerator->CreateMakeVariable(
+ this->GeneratorTarget->GetName(), "_OBJECTS");
+ *this->BuildFileStream << "# Object files for target "
+ << this->GeneratorTarget->GetName() << "\n"
+ << variableName << " =";
+ std::string object;
+ const char* lineContinue =
+ this->Makefile->GetDefinition("CMAKE_MAKE_LINE_CONTINUE");
+ if (!lineContinue) {
+ lineContinue = "\\";
+ }
+ for (std::vector<std::string>::const_iterator i = this->Objects.begin();
+ i != this->Objects.end(); ++i) {
+ *this->BuildFileStream << " " << lineContinue << "\n";
+ *this->BuildFileStream << this->LocalGenerator->ConvertToQuotedOutputPath(
+ i->c_str(), useWatcomQuote);
+ }
+ *this->BuildFileStream << "\n";
+
+ // Write a make variable assignment that lists all external objects
+ // for the target.
+ variableNameExternal = this->LocalGenerator->CreateMakeVariable(
+ this->GeneratorTarget->GetName(), "_EXTERNAL_OBJECTS");
+ /* clang-format off */
+ *this->BuildFileStream
+ << "\n"
+ << "# External object files for target "
+ << this->GeneratorTarget->GetName() << "\n"
+ << variableNameExternal << " =";
+ /* clang-format on */
+ for (std::vector<std::string>::const_iterator i =
+ this->ExternalObjects.begin();
+ i != this->ExternalObjects.end(); ++i) {
+ object = this->Convert(*i, cmOutputConverter::START_OUTPUT);
+ *this->BuildFileStream << " " << lineContinue << "\n"
+ << this->Makefile->GetSafeDefinition(
+ "CMAKE_OBJECT_NAME");
+ *this->BuildFileStream << this->LocalGenerator->ConvertToQuotedOutputPath(
+ i->c_str(), useWatcomQuote);
+ }
+ *this->BuildFileStream << "\n"
+ << "\n";
+}
+
+void cmMakefileTargetGenerator::WriteObjectsString(std::string& buildObjs)
+{
+ std::vector<std::string> objStrings;
+ this->WriteObjectsStrings(objStrings);
+ buildObjs = objStrings[0];
+}
+
+class cmMakefileTargetGeneratorObjectStrings
+{
+public:
+ cmMakefileTargetGeneratorObjectStrings(std::vector<std::string>& strings,
+ cmLocalUnixMakefileGenerator3* lg,
+ std::string::size_type limit)
+ : Strings(strings)
+ , LocalGenerator(lg)
+ , LengthLimit(limit)
+ {
+ this->Space = "";
+ }
+ void Feed(std::string const& obj)
+ {
+ // Construct the name of the next object.
+ this->NextObject = this->LocalGenerator->Convert(
+ obj, cmOutputConverter::START_OUTPUT, cmOutputConverter::RESPONSE);
+
+ // Roll over to next string if the limit will be exceeded.
+ if (this->LengthLimit != std::string::npos &&
+ (this->CurrentString.length() + 1 + this->NextObject.length() >
+ this->LengthLimit)) {
+ this->Strings.push_back(this->CurrentString);
+ this->CurrentString = "";
+ this->Space = "";
+ }
+
+ // Separate from previous object.
+ this->CurrentString += this->Space;
+ this->Space = " ";
+
+ // Append this object.
+ this->CurrentString += this->NextObject;
+ }
+ void Done() { this->Strings.push_back(this->CurrentString); }
+private:
+ std::vector<std::string>& Strings;
+ cmLocalUnixMakefileGenerator3* LocalGenerator;
+ std::string::size_type LengthLimit;
+ std::string CurrentString;
+ std::string NextObject;
+ const char* Space;
+};
+
+void cmMakefileTargetGenerator::WriteObjectsStrings(
+ std::vector<std::string>& objStrings, std::string::size_type limit)
+{
+ cmMakefileTargetGeneratorObjectStrings helper(objStrings,
+ this->LocalGenerator, limit);
+ for (std::vector<std::string>::const_iterator i = this->Objects.begin();
+ i != this->Objects.end(); ++i) {
+ helper.Feed(*i);
+ }
+ for (std::vector<std::string>::const_iterator i =
+ this->ExternalObjects.begin();
+ i != this->ExternalObjects.end(); ++i) {
+ helper.Feed(*i);
+ }
+ helper.Done();
+}
+
+void cmMakefileTargetGenerator::WriteTargetDriverRule(
+ const std::string& main_output, bool relink)
+{
+ // Compute the name of the driver target.
+ std::string dir =
+ this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget);
+ std::string buildTargetRuleName = dir;
+ buildTargetRuleName += relink ? "/preinstall" : "/build";
+ buildTargetRuleName =
+ this->Convert(buildTargetRuleName, cmOutputConverter::HOME_OUTPUT,
+ cmOutputConverter::UNCHANGED);
+
+ // Build the list of target outputs to drive.
+ std::vector<std::string> depends;
+ depends.push_back(main_output);
+
+ const char* comment = CM_NULLPTR;
+ if (relink) {
+ // Setup the comment for the preinstall driver.
+ comment = "Rule to relink during preinstall.";
+ } else {
+ // Setup the comment for the main build driver.
+ comment = "Rule to build all files generated by this target.";
+
+ // Make sure all custom command outputs in this target are built.
+ if (this->CustomCommandDriver == OnBuild) {
+ this->DriveCustomCommands(depends);
+ }
+
+ // Make sure the extra files are built.
+ depends.insert(depends.end(), this->ExtraFiles.begin(),
+ this->ExtraFiles.end());
+ }
+
+ // Write the driver rule.
+ std::vector<std::string> no_commands;
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, comment,
+ buildTargetRuleName, depends,
+ no_commands, true);
+}
+
+void cmMakefileTargetGenerator::AppendTargetDepends(
+ std::vector<std::string>& depends)
+{
+ // Static libraries never depend on anything for linking.
+ if (this->GeneratorTarget->GetType() == cmState::STATIC_LIBRARY) {
+ return;
+ }
+
+ // Loop over all library dependencies.
+ const char* cfg = this->LocalGenerator->GetConfigName().c_str();
+ if (cmComputeLinkInformation* cli =
+ this->GeneratorTarget->GetLinkInformation(cfg)) {
+ std::vector<std::string> const& libDeps = cli->GetDepends();
+ depends.insert(depends.end(), libDeps.begin(), libDeps.end());
+ }
+}
+
+void cmMakefileTargetGenerator::AppendObjectDepends(
+ std::vector<std::string>& depends)
+{
+ // Add dependencies on the compiled object files.
+ std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath();
+ std::string objTarget;
+ for (std::vector<std::string>::const_iterator obj = this->Objects.begin();
+ obj != this->Objects.end(); ++obj) {
+ objTarget = relPath;
+ objTarget += *obj;
+ depends.push_back(objTarget);
+ }
+
+ // Add dependencies on the external object files.
+ depends.insert(depends.end(), this->ExternalObjects.begin(),
+ this->ExternalObjects.end());
+
+ // Add a dependency on the rule file itself.
+ this->LocalGenerator->AppendRuleDepend(depends,
+ this->BuildFileNameFull.c_str());
+}
+
+void cmMakefileTargetGenerator::AppendLinkDepends(
+ std::vector<std::string>& depends)
+{
+ this->AppendObjectDepends(depends);
+
+ // Add dependencies on targets that must be built first.
+ this->AppendTargetDepends(depends);
+
+ // Add a dependency on the link definitions file, if any.
+ if (this->ModuleDefinitionFile) {
+ depends.push_back(this->ModuleDefinitionFile->GetFullPath());
+ }
+
+ // Add a dependency on user-specified manifest files, if any.
+ std::vector<cmSourceFile const*> manifest_srcs;
+ this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName);
+ for (std::vector<cmSourceFile const*>::iterator mi = manifest_srcs.begin();
+ mi != manifest_srcs.end(); ++mi) {
+ depends.push_back((*mi)->GetFullPath());
+ }
+
+ // Add user-specified dependencies.
+ if (const char* linkDepends =
+ this->GeneratorTarget->GetProperty("LINK_DEPENDS")) {
+ cmSystemTools::ExpandListArgument(linkDepends, depends);
+ }
+}
+
+std::string cmMakefileTargetGenerator::GetLinkRule(
+ const std::string& linkRuleVar)
+{
+ std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar);
+ if (this->GeneratorTarget->HasImplibGNUtoMS()) {
+ std::string ruleVar = "CMAKE_";
+ ruleVar += this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+ ruleVar += "_GNUtoMS_RULE";
+ if (const char* rule = this->Makefile->GetDefinition(ruleVar)) {
+ linkRule += rule;
+ }
+ }
+ return linkRule;
+}
+
+void cmMakefileTargetGenerator::CloseFileStreams()
+{
+ delete this->BuildFileStream;
+ delete this->InfoFileStream;
+ delete this->FlagFileStream;
+}
+
+void cmMakefileTargetGenerator::RemoveForbiddenFlags(
+ const char* flagVar, const std::string& linkLang, std::string& linkFlags)
+{
+ // check for language flags that are not allowed at link time, and
+ // remove them, -w on darwin for gcc -w -dynamiclib sends -w to libtool
+ // which fails, there may be more]
+
+ std::string removeFlags = "CMAKE_";
+ removeFlags += linkLang;
+ removeFlags += flagVar;
+ std::string removeflags = this->Makefile->GetSafeDefinition(removeFlags);
+ std::vector<std::string> removeList;
+ cmSystemTools::ExpandListArgument(removeflags, removeList);
+
+ for (std::vector<std::string>::iterator i = removeList.begin();
+ i != removeList.end(); ++i) {
+ std::string tmp;
+ std::string::size_type lastPosition = 0;
+
+ for (;;) {
+ std::string::size_type position = linkFlags.find(*i, lastPosition);
+
+ if (position == std::string::npos) {
+ tmp += linkFlags.substr(lastPosition);
+ break;
+ } else {
+ std::string::size_type prefixLength = position - lastPosition;
+ tmp += linkFlags.substr(lastPosition, prefixLength);
+ lastPosition = position + i->length();
+
+ bool validFlagStart =
+ position == 0 || isspace(linkFlags[position - 1]);
+
+ bool validFlagEnd =
+ lastPosition == linkFlags.size() || isspace(linkFlags[lastPosition]);
+
+ if (!validFlagStart || !validFlagEnd) {
+ tmp += *i;
+ }
+ }
+ }
+
+ linkFlags = tmp;
+ }
+}
+
+void cmMakefileTargetGenerator::CreateLinkScript(
+ const char* name, std::vector<std::string> const& link_commands,
+ std::vector<std::string>& makefile_commands,
+ std::vector<std::string>& makefile_depends)
+{
+ // Create the link script file.
+ std::string linkScriptName = this->TargetBuildDirectoryFull;
+ linkScriptName += "/";
+ linkScriptName += name;
+ cmGeneratedFileStream linkScriptStream(linkScriptName.c_str());
+ linkScriptStream.SetCopyIfDifferent(true);
+ for (std::vector<std::string>::const_iterator cmd = link_commands.begin();
+ cmd != link_commands.end(); ++cmd) {
+ // Do not write out empty commands or commands beginning in the
+ // shell no-op ":".
+ if (!cmd->empty() && (*cmd)[0] != ':') {
+ linkScriptStream << *cmd << "\n";
+ }
+ }
+
+ // Create the makefile command to invoke the link script.
+ std::string link_command = "$(CMAKE_COMMAND) -E cmake_link_script ";
+ link_command += this->Convert(
+ linkScriptName, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL);
+ link_command += " --verbose=$(VERBOSE)";
+ makefile_commands.push_back(link_command);
+ makefile_depends.push_back(linkScriptName);
+}
+
+std::string cmMakefileTargetGenerator::CreateResponseFile(
+ const char* name, std::string const& options,
+ std::vector<std::string>& makefile_depends)
+{
+ // Create the response file.
+ std::string responseFileNameFull = this->TargetBuildDirectoryFull;
+ responseFileNameFull += "/";
+ responseFileNameFull += name;
+ cmGeneratedFileStream responseStream(responseFileNameFull.c_str());
+ responseStream.SetCopyIfDifferent(true);
+ responseStream << options << "\n";
+
+ // Add a dependency so the target will rebuild when the set of
+ // objects changes.
+ makefile_depends.push_back(responseFileNameFull);
+
+ // Construct the name to be used on the command line.
+ std::string responseFileName = this->TargetBuildDirectory;
+ responseFileName += "/";
+ responseFileName += name;
+ return responseFileName;
+}
+
+void cmMakefileTargetGenerator::CreateLinkLibs(
+ std::string& linkLibs, bool relink, bool useResponseFile,
+ std::vector<std::string>& makefile_depends, bool useWatcomQuote)
+{
+ std::string frameworkPath;
+ std::string linkPath;
+ this->LocalGenerator->OutputLinkLibraries(linkLibs, frameworkPath, linkPath,
+ *this->GeneratorTarget, relink,
+ useResponseFile, useWatcomQuote);
+ linkLibs = frameworkPath + linkPath + linkLibs;
+
+ if (useResponseFile && linkLibs.find_first_not_of(' ') != linkLibs.npos) {
+ // Lookup the response file reference flag.
+ std::string responseFlagVar = "CMAKE_";
+ responseFlagVar +=
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+ responseFlagVar += "_RESPONSE_FILE_LINK_FLAG";
+ const char* responseFlag = this->Makefile->GetDefinition(responseFlagVar);
+ if (!responseFlag) {
+ responseFlag = "@";
+ }
+
+ // Create this response file.
+ std::string link_rsp =
+ this->CreateResponseFile("linklibs.rsp", linkLibs, makefile_depends);
+
+ // Reference the response file.
+ linkLibs = responseFlag;
+ linkLibs += this->Convert(link_rsp, cmOutputConverter::NONE,
+ cmOutputConverter::SHELL);
+ }
+}
+
+void cmMakefileTargetGenerator::CreateObjectLists(
+ bool useLinkScript, bool useArchiveRules, bool useResponseFile,
+ std::string& buildObjs, std::vector<std::string>& makefile_depends,
+ bool useWatcomQuote)
+{
+ std::string variableName;
+ std::string variableNameExternal;
+ this->WriteObjectsVariable(variableName, variableNameExternal,
+ useWatcomQuote);
+ if (useResponseFile) {
+ // MSVC response files cannot exceed 128K.
+ std::string::size_type const responseFileLimit = 131000;
+
+ // Construct the individual object list strings.
+ std::vector<std::string> object_strings;
+ this->WriteObjectsStrings(object_strings, responseFileLimit);
+
+ // Lookup the response file reference flag.
+ std::string responseFlagVar = "CMAKE_";
+ responseFlagVar +=
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+ responseFlagVar += "_RESPONSE_FILE_LINK_FLAG";
+ const char* responseFlag = this->Makefile->GetDefinition(responseFlagVar);
+ if (!responseFlag) {
+ responseFlag = "@";
+ }
+
+ // Write a response file for each string.
+ const char* sep = "";
+ for (unsigned int i = 0; i < object_strings.size(); ++i) {
+ // Number the response files.
+ char rsp[32];
+ sprintf(rsp, "objects%u.rsp", i + 1);
+
+ // Create this response file.
+ std::string objects_rsp =
+ this->CreateResponseFile(rsp, object_strings[i], makefile_depends);
+
+ // Separate from previous response file references.
+ buildObjs += sep;
+ sep = " ";
+
+ // Reference the response file.
+ buildObjs += responseFlag;
+ buildObjs += this->Convert(objects_rsp, cmOutputConverter::NONE,
+ cmOutputConverter::SHELL);
+ }
+ } else if (useLinkScript) {
+ if (!useArchiveRules) {
+ this->WriteObjectsString(buildObjs);
+ }
+ } else {
+ buildObjs = "$(";
+ buildObjs += variableName;
+ buildObjs += ") $(";
+ buildObjs += variableNameExternal;
+ buildObjs += ")";
+ }
+}
+
+void cmMakefileTargetGenerator::AddIncludeFlags(std::string& flags,
+ const std::string& lang)
+{
+ std::string responseVar = "CMAKE_";
+ responseVar += lang;
+ responseVar += "_USE_RESPONSE_FILE_FOR_INCLUDES";
+ bool useResponseFile = this->Makefile->IsOn(responseVar);
+
+ std::vector<std::string> includes;
+ const std::string& config =
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
+ lang, config);
+
+ std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
+ includes, this->GeneratorTarget, lang, false, useResponseFile, config);
+ if (includeFlags.empty()) {
+ return;
+ }
+
+ if (useResponseFile) {
+ std::string name = "includes_";
+ name += lang;
+ name += ".rsp";
+ std::string arg = "@" +
+ this->CreateResponseFile(name.c_str(), includeFlags,
+ this->FlagFileDepends[lang]);
+ this->LocalGenerator->AppendFlags(flags, arg);
+ } else {
+ this->LocalGenerator->AppendFlags(flags, includeFlags);
+ }
+}
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
new file mode 100644
index 0000000..7749d8b
--- /dev/null
+++ b/Source/cmMakefileTargetGenerator.h
@@ -0,0 +1,244 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmMakefileTargetGenerator_h
+#define cmMakefileTargetGenerator_h
+
+#include "cmCommonTargetGenerator.h"
+
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmOSXBundleGenerator.h"
+
+class cmCustomCommandGenerator;
+class cmDepends;
+class cmGeneratorTarget;
+class cmGeneratedFileStream;
+class cmGlobalUnixMakefileGenerator3;
+class cmLocalUnixMakefileGenerator3;
+class cmMakefile;
+class cmSourceFile;
+
+/** \class cmMakefileTargetGenerator
+ * \brief Support Routines for writing makefiles
+ *
+ */
+class cmMakefileTargetGenerator : public cmCommonTargetGenerator
+{
+public:
+ // constructor to set the ivars
+ cmMakefileTargetGenerator(cmGeneratorTarget* target);
+ ~cmMakefileTargetGenerator() CM_OVERRIDE;
+
+ // construct using this factory call
+ static cmMakefileTargetGenerator* New(cmGeneratorTarget* tgt);
+
+ /* the main entry point for this class. Writes the Makefiles associated
+ with this target */
+ virtual void WriteRuleFiles() = 0;
+
+ /* return the number of actions that have progress reporting on them */
+ virtual unsigned long GetNumberOfProgressActions()
+ {
+ return this->NumberOfProgressActions;
+ }
+ std::string GetProgressFileNameFull() { return this->ProgressFileNameFull; }
+
+ cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; }
+
+protected:
+ // create the file and directory etc
+ void CreateRuleFile();
+
+ // outputs the rules for object files and custom commands used by
+ // this target
+ void WriteTargetBuildRules();
+
+ // write some common code at the top of build.make
+ void WriteCommonCodeRules();
+ void WriteTargetLanguageFlags();
+
+ // write the provide require rules for this target
+ void WriteTargetRequiresRules();
+
+ // write the clean rules for this target
+ void WriteTargetCleanRules();
+
+ // write the depend rules for this target
+ void WriteTargetDependRules();
+
+ // write rules for Mac OS X Application Bundle content.
+ struct MacOSXContentGeneratorType
+ : cmOSXBundleGenerator::MacOSXContentGeneratorType
+ {
+ MacOSXContentGeneratorType(cmMakefileTargetGenerator* gen)
+ : Generator(gen)
+ {
+ }
+
+ void operator()(cmSourceFile const& source,
+ const char* pkgloc) CM_OVERRIDE;
+
+ private:
+ cmMakefileTargetGenerator* Generator;
+ };
+ friend struct MacOSXContentGeneratorType;
+
+ // write the rules for an object
+ void WriteObjectRuleFiles(cmSourceFile const& source);
+
+ // write the build rule for an object
+ void WriteObjectBuildFile(std::string& obj, const std::string& lang,
+ cmSourceFile const& source,
+ std::vector<std::string>& depends);
+
+ // write the depend.make file for an object
+ void WriteObjectDependRules(cmSourceFile const& source,
+ std::vector<std::string>& depends);
+
+ // write the build rule for a custom command
+ void GenerateCustomRuleFile(cmCustomCommandGenerator const& ccg);
+
+ // write a rule to drive building of more than one output from
+ // another rule
+ void GenerateExtraOutput(const char* out, const char* in,
+ bool symbolic = false);
+
+ void MakeEchoProgress(cmLocalUnixMakefileGenerator3::EchoProgress&) const;
+
+ // write out the variable that lists the objects for this target
+ void WriteObjectsVariable(std::string& variableName,
+ std::string& variableNameExternal,
+ bool useWatcomQuote);
+ void WriteObjectsString(std::string& buildObjs);
+ void WriteObjectsStrings(std::vector<std::string>& objStrings,
+ std::string::size_type limit = std::string::npos);
+
+ // write the driver rule to build target outputs
+ void WriteTargetDriverRule(const std::string& main_output, bool relink);
+
+ void DriveCustomCommands(std::vector<std::string>& depends);
+
+ // append intertarget dependencies
+ void AppendTargetDepends(std::vector<std::string>& depends);
+
+ // Append object file dependencies.
+ void AppendObjectDepends(std::vector<std::string>& depends);
+
+ // Append link rule dependencies (objects, etc.).
+ void AppendLinkDepends(std::vector<std::string>& depends);
+
+ // Lookup the link rule for this target.
+ std::string GetLinkRule(const std::string& linkRuleVar);
+
+ /** Create a script to hold link rules and a command to invoke the
+ script at build time. */
+ void CreateLinkScript(const char* name,
+ std::vector<std::string> const& link_commands,
+ std::vector<std::string>& makefile_commands,
+ std::vector<std::string>& makefile_depends);
+
+ /** Create a response file with the given set of options. Returns
+ the relative path from the target build working directory to the
+ response file name. */
+ std::string CreateResponseFile(const char* name, std::string const& options,
+ std::vector<std::string>& makefile_depends);
+
+ /** Create list of flags for link libraries. */
+ void CreateLinkLibs(std::string& linkLibs, bool relink, bool useResponseFile,
+ std::vector<std::string>& makefile_depends,
+ bool useWatcomQuote);
+
+ /** Create lists of object files for linking and cleaning. */
+ void CreateObjectLists(bool useLinkScript, bool useArchiveRules,
+ bool useResponseFile, std::string& buildObjs,
+ std::vector<std::string>& makefile_depends,
+ bool useWatcomQuote);
+
+ void AddIncludeFlags(std::string& flags,
+ const std::string& lang) CM_OVERRIDE;
+
+ virtual void CloseFileStreams();
+ void RemoveForbiddenFlags(const char* flagVar, const std::string& linkLang,
+ std::string& linkFlags);
+ cmLocalUnixMakefileGenerator3* LocalGenerator;
+ cmGlobalUnixMakefileGenerator3* GlobalGenerator;
+
+ enum CustomCommandDriveType
+ {
+ OnBuild,
+ OnDepends,
+ OnUtility
+ };
+ CustomCommandDriveType CustomCommandDriver;
+
+ // the full path to the build file
+ std::string BuildFileName;
+ std::string BuildFileNameFull;
+
+ // the full path to the progress file
+ std::string ProgressFileNameFull;
+ unsigned long NumberOfProgressActions;
+ bool NoRuleMessages;
+
+ // the path to the directory the build file is in
+ std::string TargetBuildDirectory;
+ std::string TargetBuildDirectoryFull;
+
+ // the stream for the build file
+ cmGeneratedFileStream* BuildFileStream;
+
+ // the stream for the flag file
+ std::string FlagFileNameFull;
+ cmGeneratedFileStream* FlagFileStream;
+ class StringList : public std::vector<std::string>
+ {
+ };
+ std::map<std::string, StringList> FlagFileDepends;
+
+ // the stream for the info file
+ std::string InfoFileNameFull;
+ cmGeneratedFileStream* InfoFileStream;
+
+ // files to clean
+ std::vector<std::string> CleanFiles;
+
+ // objects used by this target
+ std::vector<std::string> Objects;
+ std::vector<std::string> ExternalObjects;
+
+ // Set of object file names that will be built in this directory.
+ std::set<std::string> ObjectFiles;
+
+ // Set of extra output files to be driven by the build.
+ std::set<std::string> ExtraFiles;
+
+ typedef std::map<std::string, std::string> MultipleOutputPairsType;
+ MultipleOutputPairsType MultipleOutputPairs;
+ bool WriteMakeRule(std::ostream& os, const char* comment,
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& depends,
+ const std::vector<std::string>& commands,
+ bool in_help = false);
+
+ // Target name info.
+ std::string TargetNameOut;
+ std::string TargetNameSO;
+ std::string TargetNameReal;
+ std::string TargetNameImport;
+ std::string TargetNamePDB;
+
+ // Mac OS X content info.
+ std::set<std::string> MacContentFolders;
+ cmOSXBundleGenerator* OSXBundleGenerator;
+ MacOSXContentGeneratorType* MacOSXContentGenerator;
+};
+
+#endif
diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx
new file mode 100644
index 0000000..27006ee
--- /dev/null
+++ b/Source/cmMakefileUtilityTargetGenerator.cxx
@@ -0,0 +1,114 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmMakefileUtilityTargetGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+
+cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator(
+ cmGeneratorTarget* target)
+ : cmMakefileTargetGenerator(target)
+{
+ this->CustomCommandDriver = OnUtility;
+ this->OSXBundleGenerator =
+ new cmOSXBundleGenerator(target, this->ConfigName);
+ this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
+}
+
+cmMakefileUtilityTargetGenerator::~cmMakefileUtilityTargetGenerator()
+{
+ delete this->OSXBundleGenerator;
+}
+
+void cmMakefileUtilityTargetGenerator::WriteRuleFiles()
+{
+ this->CreateRuleFile();
+
+ *this->BuildFileStream << "# Utility rule file for "
+ << this->GeneratorTarget->GetName() << ".\n\n";
+
+ if (!this->NoRuleMessages) {
+ const char* root = (this->Makefile->IsOn("CMAKE_MAKE_INCLUDE_FROM_ROOT")
+ ? "$(CMAKE_BINARY_DIR)/"
+ : "");
+ // Include the progress variables for the target.
+ *this->BuildFileStream
+ << "# Include the progress variables for this target.\n"
+ << this->GlobalGenerator->IncludeDirective << " " << root
+ << this->Convert(this->ProgressFileNameFull,
+ cmOutputConverter::HOME_OUTPUT,
+ cmOutputConverter::MAKERULE)
+ << "\n\n";
+ }
+
+ // write the custom commands for this target
+ this->WriteTargetBuildRules();
+
+ // Collect the commands and dependencies.
+ std::vector<std::string> commands;
+ std::vector<std::string> depends;
+
+ // Utility targets store their rules in pre- and post-build commands.
+ this->LocalGenerator->AppendCustomDepends(
+ depends, this->GeneratorTarget->GetPreBuildCommands());
+
+ this->LocalGenerator->AppendCustomDepends(
+ depends, this->GeneratorTarget->GetPostBuildCommands());
+
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPreBuildCommands(),
+ this->GeneratorTarget);
+
+ // Depend on all custom command outputs for sources
+ this->DriveCustomCommands(depends);
+
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPostBuildCommands(),
+ this->GeneratorTarget);
+
+ // Add dependencies on targets that must be built first.
+ this->AppendTargetDepends(depends);
+
+ // Add a dependency on the rule file itself.
+ this->LocalGenerator->AppendRuleDepend(depends,
+ this->BuildFileNameFull.c_str());
+
+ // If the rule is empty add the special empty rule dependency needed
+ // by some make tools.
+ if (depends.empty() && commands.empty()) {
+ std::string hack = this->GlobalGenerator->GetEmptyRuleHackDepends();
+ if (!hack.empty()) {
+ depends.push_back(hack);
+ }
+ }
+
+ // Write the rule.
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR,
+ this->GeneratorTarget->GetName(),
+ depends, commands, true);
+
+ // Write the main driver rule to build everything in this target.
+ this->WriteTargetDriverRule(this->GeneratorTarget->GetName(), false);
+
+ // Write clean target
+ this->WriteTargetCleanRules();
+
+ // Write the dependency generation rule. This must be done last so
+ // that multiple output pair information is available.
+ this->WriteTargetDependRules();
+
+ // close the streams
+ this->CloseFileStreams();
+}
diff --git a/Source/cmMakefileUtilityTargetGenerator.h b/Source/cmMakefileUtilityTargetGenerator.h
new file mode 100644
index 0000000..b41fb8b
--- /dev/null
+++ b/Source/cmMakefileUtilityTargetGenerator.h
@@ -0,0 +1,30 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmMakefileUtilityTargetGenerator_h
+#define cmMakefileUtilityTargetGenerator_h
+
+#include "cmMakefileTargetGenerator.h"
+
+class cmMakefileUtilityTargetGenerator : public cmMakefileTargetGenerator
+{
+public:
+ cmMakefileUtilityTargetGenerator(cmGeneratorTarget* target);
+ ~cmMakefileUtilityTargetGenerator() CM_OVERRIDE;
+
+ /* the main entry point for this class. Writes the Makefiles associated
+ with this target */
+ void WriteRuleFiles() CM_OVERRIDE;
+
+protected:
+};
+
+#endif
diff --git a/Source/cmMarkAsAdvancedCommand.cxx b/Source/cmMarkAsAdvancedCommand.cxx
new file mode 100644
index 0000000..2fb6a75
--- /dev/null
+++ b/Source/cmMarkAsAdvancedCommand.cxx
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmMarkAsAdvancedCommand.h"
+
+// cmMarkAsAdvancedCommand
+bool cmMarkAsAdvancedCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ unsigned int i = 0;
+ const char* value = "1";
+ bool overwrite = false;
+ if (args[0] == "CLEAR" || args[0] == "FORCE") {
+ overwrite = true;
+ if (args[0] == "CLEAR") {
+ value = "0";
+ }
+ i = 1;
+ }
+ for (; i < args.size(); ++i) {
+ std::string variable = args[i];
+ cmState* state = this->Makefile->GetState();
+ if (!state->GetCacheEntryValue(variable)) {
+ this->Makefile->GetCMakeInstance()->AddCacheEntry(
+ variable, CM_NULLPTR, CM_NULLPTR, cmState::UNINITIALIZED);
+ overwrite = true;
+ }
+ if (!state->GetCacheEntryValue(variable)) {
+ cmSystemTools::Error("This should never happen...");
+ return false;
+ }
+ if (!state->GetCacheEntryProperty(variable, "ADVANCED") || overwrite) {
+ state->SetCacheEntryProperty(variable, "ADVANCED", value);
+ }
+ }
+ return true;
+}
diff --git a/Source/cmMarkAsAdvancedCommand.h b/Source/cmMarkAsAdvancedCommand.h
new file mode 100644
index 0000000..bb1b83c
--- /dev/null
+++ b/Source/cmMarkAsAdvancedCommand.h
@@ -0,0 +1,53 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmMarkAsAdvancedCommand_h
+#define cmMarkAsAdvancedCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmMarkAsAdvancedCommand
+ * \brief mark_as_advanced command
+ *
+ * cmMarkAsAdvancedCommand implements the mark_as_advanced CMake command
+ */
+class cmMarkAsAdvancedCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmMarkAsAdvancedCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "mark_as_advanced"; }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ * mark_as_advanced() will have no effect in script mode, but this will
+ * make many of the modules usable in cmake/ctest scripts, (among them
+ * FindUnixMake.cmake used by the CTEST_BUILD command.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ cmTypeMacro(cmMarkAsAdvancedCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmMathCommand.cxx b/Source/cmMathCommand.cxx
new file mode 100644
index 0000000..ca8b926
--- /dev/null
+++ b/Source/cmMathCommand.cxx
@@ -0,0 +1,55 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmMathCommand.h"
+
+#include "cmExprParserHelper.h"
+
+bool cmMathCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("must be called with at least one argument.");
+ return false;
+ }
+ const std::string& subCommand = args[0];
+ if (subCommand == "EXPR") {
+ return this->HandleExprCommand(args);
+ }
+ std::string e = "does not recognize sub-command " + subCommand;
+ this->SetError(e);
+ return false;
+}
+
+bool cmMathCommand::HandleExprCommand(std::vector<std::string> const& args)
+{
+ if (args.size() != 3) {
+ this->SetError("EXPR called with incorrect arguments.");
+ return false;
+ }
+
+ const std::string& outputVariable = args[1];
+ const std::string& expression = args[2];
+
+ cmExprParserHelper helper;
+ if (!helper.ParseString(expression.c_str(), 0)) {
+ std::string e = "cannot parse the expression: \"" + expression + "\": ";
+ e += helper.GetError();
+ this->SetError(e);
+ return false;
+ }
+
+ char buffer[1024];
+ sprintf(buffer, "%d", helper.GetResult());
+
+ this->Makefile->AddDefinition(outputVariable, buffer);
+ return true;
+}
diff --git a/Source/cmMathCommand.h b/Source/cmMathCommand.h
new file mode 100644
index 0000000..b99e790
--- /dev/null
+++ b/Source/cmMathCommand.h
@@ -0,0 +1,49 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmMathCommand_h
+#define cmMathCommand_h
+
+#include "cmCommand.h"
+
+/// Mathematical expressions: math(EXPR ...) command.
+class cmMathCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmMathCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "math"; }
+
+ cmTypeMacro(cmMathCommand, cmCommand);
+
+protected:
+ bool HandleExprCommand(std::vector<std::string> const& args);
+};
+
+#endif
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
new file mode 100644
index 0000000..080880b
--- /dev/null
+++ b/Source/cmMessageCommand.cxx
@@ -0,0 +1,81 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmMessageCommand.h"
+
+// cmLibraryCommand
+bool cmMessageCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ std::vector<std::string>::const_iterator i = args.begin();
+
+ cmake::MessageType type = cmake::MESSAGE;
+ bool status = false;
+ bool fatal = false;
+ if (*i == "SEND_ERROR") {
+ type = cmake::FATAL_ERROR;
+ ++i;
+ } else if (*i == "FATAL_ERROR") {
+ fatal = true;
+ type = cmake::FATAL_ERROR;
+ ++i;
+ } else if (*i == "WARNING") {
+ type = cmake::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 = cmake::AUTHOR_ERROR;
+ } else if (!this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
+ type = cmake::AUTHOR_WARNING;
+ } else {
+ return true;
+ }
+ ++i;
+ } else if (*i == "STATUS") {
+ status = true;
+ ++i;
+ } else if (*i == "DEPRECATION") {
+ if (this->Makefile->IsOn("CMAKE_ERROR_DEPRECATED")) {
+ fatal = true;
+ type = cmake::DEPRECATION_ERROR;
+ } else if ((!this->Makefile->IsSet("CMAKE_WARN_DEPRECATED") ||
+ this->Makefile->IsOn("CMAKE_WARN_DEPRECATED"))) {
+ type = cmake::DEPRECATION_WARNING;
+ } else {
+ return true;
+ }
+ ++i;
+ }
+
+ std::string message = cmJoin(cmMakeRange(i, args.end()), std::string());
+
+ if (type != cmake::MESSAGE) {
+ // we've overriden the message type, above, so display it directly
+ cmake* cm = this->Makefile->GetCMakeInstance();
+ cm->DisplayMessage(type, message, this->Makefile->GetBacktrace());
+ } else {
+ if (status) {
+ this->Makefile->DisplayStatus(message.c_str(), -1);
+ } else {
+ cmSystemTools::Message(message.c_str());
+ }
+ }
+ if (fatal) {
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ return true;
+}
diff --git a/Source/cmMessageCommand.h b/Source/cmMessageCommand.h
new file mode 100644
index 0000000..61767a1
--- /dev/null
+++ b/Source/cmMessageCommand.h
@@ -0,0 +1,49 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmMessageCommand_h
+#define cmMessageCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmMessageCommand
+ * \brief Displays a message to the user
+ *
+ */
+class cmMessageCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmMessageCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "message"; }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ cmTypeMacro(cmMessageCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmNewLineStyle.cxx b/Source/cmNewLineStyle.cxx
new file mode 100644
index 0000000..c03f60d
--- /dev/null
+++ b/Source/cmNewLineStyle.cxx
@@ -0,0 +1,76 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2011 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmNewLineStyle.h"
+
+cmNewLineStyle::cmNewLineStyle()
+ : NewLineStyle(Invalid)
+{
+}
+
+bool cmNewLineStyle::IsValid() const
+{
+ return NewLineStyle != Invalid;
+}
+
+bool cmNewLineStyle::ReadFromArguments(const std::vector<std::string>& args,
+ std::string& errorString)
+{
+ NewLineStyle = Invalid;
+
+ for (size_t i = 0; i < args.size(); i++) {
+ if (args[i] == "NEWLINE_STYLE") {
+ size_t const styleIndex = i + 1;
+ if (args.size() > styleIndex) {
+ const std::string eol = args[styleIndex];
+ if (eol == "LF" || eol == "UNIX") {
+ NewLineStyle = LF;
+ return true;
+ } else if (eol == "CRLF" || eol == "WIN32" || eol == "DOS") {
+ NewLineStyle = CRLF;
+ return true;
+ } else {
+ errorString = "NEWLINE_STYLE sets an unknown style, only LF, "
+ "CRLF, UNIX, DOS, and WIN32 are supported";
+ return false;
+ }
+ } else {
+ errorString = "NEWLINE_STYLE must set a style: "
+ "LF, CRLF, UNIX, DOS, or WIN32";
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+const std::string cmNewLineStyle::GetCharacters() const
+{
+ switch (NewLineStyle) {
+ case Invalid:
+ return "";
+ case LF:
+ return "\n";
+ case CRLF:
+ return "\r\n";
+ }
+ return "";
+}
+
+void cmNewLineStyle::SetStyle(Style style)
+{
+ NewLineStyle = style;
+}
+
+cmNewLineStyle::Style cmNewLineStyle::GetStyle() const
+{
+ return NewLineStyle;
+}
diff --git a/Source/cmNewLineStyle.h b/Source/cmNewLineStyle.h
new file mode 100644
index 0000000..800f131
--- /dev/null
+++ b/Source/cmNewLineStyle.h
@@ -0,0 +1,45 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2011 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmNewLineStyle_h
+#define cmNewLineStyle_h
+
+#include "cmStandardIncludes.h"
+
+class cmNewLineStyle
+{
+public:
+ cmNewLineStyle();
+
+ enum Style
+ {
+ Invalid,
+ // LF = '\n', 0x0A, 10
+ // CR = '\r', 0x0D, 13
+ LF, // Unix
+ CRLF // Dos
+ };
+
+ void SetStyle(Style);
+ Style GetStyle() const;
+
+ bool IsValid() const;
+
+ bool ReadFromArguments(const std::vector<std::string>& args,
+ std::string& errorString);
+
+ const std::string GetCharacters() const;
+
+private:
+ Style NewLineStyle;
+};
+
+#endif
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
new file mode 100644
index 0000000..77d3901
--- /dev/null
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -0,0 +1,729 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
+ Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmNinjaNormalTargetGenerator.h"
+
+#include "cmAlgorithms.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmLocalNinjaGenerator.h"
+#include "cmMakefile.h"
+#include "cmOSXBundleGenerator.h"
+#include "cmSourceFile.h"
+
+#include <algorithm>
+#include <assert.h>
+#include <limits>
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
+ cmGeneratorTarget* target)
+ : cmNinjaTargetGenerator(target)
+ , TargetNameOut()
+ , TargetNameSO()
+ , TargetNameReal()
+ , TargetNameImport()
+ , TargetNamePDB()
+ , TargetLinkLanguage("")
+{
+ this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName());
+ if (target->GetType() == cmState::EXECUTABLE) {
+ this->GetGeneratorTarget()->GetExecutableNames(
+ this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,
+ this->TargetNamePDB, GetLocalGenerator()->GetConfigName());
+ } else {
+ this->GetGeneratorTarget()->GetLibraryNames(
+ this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
+ this->TargetNameImport, this->TargetNamePDB,
+ GetLocalGenerator()->GetConfigName());
+ }
+
+ if (target->GetType() != cmState::OBJECT_LIBRARY) {
+ // on Windows the output dir is already needed at compile time
+ // ensure the directory exists (OutDir test)
+ EnsureDirectoryExists(target->GetDirectory(this->GetConfigName()));
+ }
+
+ this->OSXBundleGenerator =
+ new cmOSXBundleGenerator(target, this->GetConfigName());
+ this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
+}
+
+cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator()
+{
+ delete this->OSXBundleGenerator;
+}
+
+void cmNinjaNormalTargetGenerator::Generate()
+{
+ if (this->TargetLinkLanguage.empty()) {
+ cmSystemTools::Error("CMake can not determine linker language for "
+ "target: ",
+ this->GetGeneratorTarget()->GetName().c_str());
+ return;
+ }
+
+ // Write the rules for each language.
+ this->WriteLanguagesRules();
+
+ // Write the build statements
+ this->WriteObjectBuildStatements();
+
+ if (this->GetGeneratorTarget()->GetType() == cmState::OBJECT_LIBRARY) {
+ this->WriteObjectLibStatement();
+ } else {
+ this->WriteLinkStatement();
+ }
+}
+
+void cmNinjaNormalTargetGenerator::WriteLanguagesRules()
+{
+#ifdef NINJA_GEN_VERBOSE_FILES
+ cmGlobalNinjaGenerator::WriteDivider(this->GetRulesFileStream());
+ this->GetRulesFileStream()
+ << "# Rules for each languages for "
+ << cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
+ << " target " << this->GetTargetName() << "\n\n";
+#endif
+
+ // Write rules for languages compiled in this target.
+ std::set<std::string> languages;
+ std::vector<cmSourceFile*> sourceFiles;
+ this->GetGeneratorTarget()->GetSourceFiles(
+ sourceFiles, this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ for (std::vector<cmSourceFile*>::const_iterator i = sourceFiles.begin();
+ i != sourceFiles.end(); ++i) {
+ const std::string& lang = (*i)->GetLanguage();
+ if (!lang.empty()) {
+ languages.insert(lang);
+ }
+ }
+ for (std::set<std::string>::const_iterator l = languages.begin();
+ l != languages.end(); ++l) {
+ this->WriteLanguageRules(*l);
+ }
+}
+
+const char* cmNinjaNormalTargetGenerator::GetVisibleTypeName() const
+{
+ switch (this->GetGeneratorTarget()->GetType()) {
+ case cmState::STATIC_LIBRARY:
+ return "static library";
+ case cmState::SHARED_LIBRARY:
+ return "shared library";
+ case cmState::MODULE_LIBRARY:
+ if (this->GetGeneratorTarget()->IsCFBundleOnApple()) {
+ return "CFBundle shared module";
+ } else {
+ return "shared module";
+ }
+ case cmState::EXECUTABLE:
+ return "executable";
+ default:
+ return CM_NULLPTR;
+ }
+}
+
+std::string cmNinjaNormalTargetGenerator::LanguageLinkerRule() const
+{
+ return this->TargetLinkLanguage + "_" +
+ cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) +
+ "_LINKER__" + cmGlobalNinjaGenerator::EncodeRuleName(
+ this->GetGeneratorTarget()->GetName());
+}
+
+struct cmNinjaRemoveNoOpCommands
+{
+ bool operator()(std::string const& cmd)
+ {
+ return cmd.empty() || cmd[0] == ':';
+ }
+};
+
+void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile)
+{
+ cmState::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)) {
+ cmLocalGenerator::RuleVariables vars;
+ vars.RuleLauncher = "RULE_LAUNCH_LINK";
+ vars.CMTarget = this->GetGeneratorTarget();
+ vars.Language = this->TargetLinkLanguage.c_str();
+
+ std::string responseFlag;
+ if (!useResponseFile) {
+ 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;
+
+ // build response file content
+ if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
+ rspcontent = "$in";
+ } else {
+ rspcontent = "$in_newline";
+ }
+ rspcontent += " $LINK_PATH $LINK_LIBRARIES";
+ vars.Objects = responseFlag.c_str();
+ vars.LinkLibraries = "";
+ }
+
+ vars.ObjectDir = "$OBJECT_DIR";
+
+ vars.Target = "$TARGET_FILE";
+
+ vars.SONameFlag = "$SONAME_FLAG";
+ vars.TargetSOName = "$SONAME";
+ vars.TargetInstallNameDir = "$INSTALLNAME_DIR";
+ vars.TargetPDB = "$TARGET_PDB";
+
+ // Setup the target version.
+ std::string targetVersionMajor;
+ std::string targetVersionMinor;
+ {
+ std::ostringstream majorStream;
+ std::ostringstream minorStream;
+ int major;
+ int minor;
+ this->GetGeneratorTarget()->GetTargetVersion(major, minor);
+ majorStream << major;
+ minorStream << minor;
+ targetVersionMajor = majorStream.str();
+ targetVersionMinor = minorStream.str();
+ }
+ vars.TargetVersionMajor = targetVersionMajor.c_str();
+ vars.TargetVersionMinor = targetVersionMinor.c_str();
+
+ vars.Flags = "$FLAGS";
+ vars.LinkFlags = "$LINK_FLAGS";
+ vars.Manifests = "$MANIFESTS";
+
+ std::string langFlags;
+ if (targetType != cmState::EXECUTABLE) {
+ langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS";
+ vars.LanguageCompileFlags = langFlags.c_str();
+ }
+
+ // Rule for linking library/executable.
+ std::vector<std::string> linkCmds = this->ComputeLinkCmd();
+ for (std::vector<std::string>::iterator i = linkCmds.begin();
+ i != linkCmds.end(); ++i) {
+ this->GetLocalGenerator()->ExpandRuleVariables(*i, vars);
+ }
+ {
+ // If there is no ranlib the command will be ":". Skip it.
+ std::vector<std::string>::iterator newEnd = std::remove_if(
+ linkCmds.begin(), linkCmds.end(), cmNinjaRemoveNoOpCommands());
+ linkCmds.erase(newEnd, linkCmds.end());
+ }
+
+ linkCmds.insert(linkCmds.begin(), "$PRE_LINK");
+ linkCmds.push_back("$POST_BUILD");
+ std::string linkCmd =
+ 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);
+ }
+
+ if (this->TargetNameOut != this->TargetNameReal &&
+ !this->GetGeneratorTarget()->IsFrameworkOnApple()) {
+ std::string cmakeCommand =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ if (targetType == cmState::EXECUTABLE) {
+ this->GetGlobalGenerator()->AddRule(
+ "CMAKE_SYMLINK_EXECUTABLE",
+ cmakeCommand + " -E cmake_symlink_executable"
+ " $in $out && $POST_BUILD",
+ "Creating executable symlink $out", "Rule for creating "
+ "executable symlink.",
+ /*depfile*/ "",
+ /*deptype*/ "",
+ /*rspfile*/ "",
+ /*rspcontent*/ "",
+ /*restat*/ "",
+ /*generator*/ false);
+ } else {
+ this->GetGlobalGenerator()->AddRule(
+ "CMAKE_SYMLINK_LIBRARY",
+ cmakeCommand + " -E cmake_symlink_library"
+ " $in $SONAME $out && $POST_BUILD",
+ "Creating library symlink $out", "Rule for creating "
+ "library symlink.",
+ /*depfile*/ "",
+ /*deptype*/ "",
+ /*rspfile*/ "",
+ /*rspcontent*/ "",
+ /*restat*/ "",
+ /*generator*/ false);
+ }
+ }
+}
+
+std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd()
+{
+ std::vector<std::string> linkCmds;
+ cmMakefile* mf = this->GetMakefile();
+ {
+ std::string linkCmdVar = this->GetGeneratorTarget()->GetCreateRuleVariable(
+ this->TargetLinkLanguage, this->GetConfigName());
+ const char* linkCmd = mf->GetDefinition(linkCmdVar);
+ if (linkCmd) {
+ cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
+ if (this->GetGeneratorTarget()->GetProperty("LINK_WHAT_YOU_USE")) {
+ std::string cmakeCommand =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
+ cmakeCommand += " -E __run_iwyu --lwyu=";
+ cmGeneratorTarget& gt = *this->GetGeneratorTarget();
+ const std::string cfgName = this->GetConfigName();
+ std::string targetOutput = ConvertToNinjaPath(gt.GetFullPath(cfgName));
+ std::string targetOutputReal =
+ this->ConvertToNinjaPath(gt.GetFullPath(cfgName,
+ /*implib=*/false,
+ /*realpath=*/true));
+ cmakeCommand += targetOutputReal;
+ cmakeCommand += " || true";
+ linkCmds.push_back(cmakeCommand);
+ }
+ return linkCmds;
+ }
+ }
+ switch (this->GetGeneratorTarget()->GetType()) {
+ case cmState::STATIC_LIBRARY: {
+ // We have archive link commands set. First, delete the existing archive.
+ {
+ std::string cmakeCommand =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ linkCmds.push_back(cmakeCommand + " -E remove $TARGET_FILE");
+ }
+ // TODO: Use ARCHIVE_APPEND for archives over a certain size.
+ {
+ std::string linkCmdVar = "CMAKE_";
+ linkCmdVar += this->TargetLinkLanguage;
+ linkCmdVar += "_ARCHIVE_CREATE";
+ const char* linkCmd = mf->GetRequiredDefinition(linkCmdVar);
+ cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
+ }
+ {
+ std::string linkCmdVar = "CMAKE_";
+ linkCmdVar += this->TargetLinkLanguage;
+ linkCmdVar += "_ARCHIVE_FINISH";
+ const char* linkCmd = mf->GetRequiredDefinition(linkCmdVar);
+ cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
+ }
+ return linkCmds;
+ }
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ case cmState::EXECUTABLE:
+ break;
+ default:
+ assert(0 && "Unexpected target type");
+ }
+ return std::vector<std::string>();
+}
+
+static int calculateCommandLineLengthLimit(int linkRuleLength)
+{
+ static int const limits[] = {
+#ifdef _WIN32
+ 8000,
+#endif
+#if defined(__APPLE__) || defined(__HAIKU__) || defined(__linux)
+ // for instance ARG_MAX is 2096152 on Ubuntu or 262144 on Mac
+ ((int)sysconf(_SC_ARG_MAX)) - 1000,
+#endif
+#if defined(__linux)
+ // #define MAX_ARG_STRLEN (PAGE_SIZE * 32) in Linux's binfmts.h
+ ((int)sysconf(_SC_PAGESIZE) * 32) - 1000,
+#endif
+ std::numeric_limits<int>::max()
+ };
+
+ size_t const arrSz = cmArraySize(limits);
+ int const sz = *std::min_element(limits, limits + arrSz);
+ if (sz == std::numeric_limits<int>::max()) {
+ return -1;
+ }
+
+ return sz - linkRuleLength;
+}
+
+void cmNinjaNormalTargetGenerator::WriteLinkStatement()
+{
+ cmGeneratorTarget& gt = *this->GetGeneratorTarget();
+ const std::string cfgName = this->GetConfigName();
+ std::string targetOutput = ConvertToNinjaPath(gt.GetFullPath(cfgName));
+ std::string targetOutputReal =
+ ConvertToNinjaPath(gt.GetFullPath(cfgName,
+ /*implib=*/false,
+ /*realpath=*/true));
+ std::string targetOutputImplib =
+ ConvertToNinjaPath(gt.GetFullPath(cfgName,
+ /*implib=*/true));
+
+ if (gt.IsAppBundleOnApple()) {
+ // Create the app bundle
+ std::string outpath = gt.GetDirectory(cfgName);
+ this->OSXBundleGenerator->CreateAppBundle(this->TargetNameOut, outpath);
+
+ // Calculate the output path
+ targetOutput = outpath;
+ targetOutput += "/";
+ targetOutput += this->TargetNameOut;
+ targetOutput = this->ConvertToNinjaPath(targetOutput);
+ targetOutputReal = outpath;
+ targetOutputReal += "/";
+ targetOutputReal += this->TargetNameReal;
+ targetOutputReal = this->ConvertToNinjaPath(targetOutputReal);
+ } else if (gt.IsFrameworkOnApple()) {
+ // Create the library framework.
+ this->OSXBundleGenerator->CreateFramework(this->TargetNameOut,
+ gt.GetDirectory(cfgName));
+ } else if (gt.IsCFBundleOnApple()) {
+ // Create the core foundation bundle.
+ this->OSXBundleGenerator->CreateCFBundle(this->TargetNameOut,
+ gt.GetDirectory(cfgName));
+ }
+
+ // Write comments.
+ cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
+ const cmState::TargetType targetType = gt.GetType();
+ this->GetBuildFileStream() << "# Link build statements for "
+ << cmState::GetTargetTypeName(targetType)
+ << " target " << this->GetTargetName() << "\n\n";
+
+ cmNinjaDeps emptyDeps;
+ cmNinjaVars vars;
+
+ // Compute the comment.
+ std::ostringstream comment;
+ comment << "Link the " << this->GetVisibleTypeName() << " "
+ << targetOutputReal;
+
+ // Compute outputs.
+ cmNinjaDeps outputs;
+ outputs.push_back(targetOutputReal);
+
+ // Compute specific libraries to link with.
+ cmNinjaDeps explicitDeps = this->GetObjects();
+ cmNinjaDeps implicitDeps = this->ComputeLinkDeps();
+
+ cmMakefile* mf = this->GetMakefile();
+
+ std::string frameworkPath;
+ std::string linkPath;
+ cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
+
+ std::string createRule = genTarget.GetCreateRuleVariable(
+ this->TargetLinkLanguage, this->GetConfigName());
+ bool useWatcomQuote = mf->IsOn(createRule + "_USE_WATCOM_QUOTE");
+ cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
+
+ vars["TARGET_FILE"] =
+ localGen.ConvertToOutputFormat(targetOutputReal, cmOutputConverter::SHELL);
+
+ localGen.GetTargetFlags(this->GetConfigName(), vars["LINK_LIBRARIES"],
+ vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath,
+ linkPath, &genTarget, useWatcomQuote);
+ if (this->GetMakefile()->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") &&
+ gt.GetType() == cmState::SHARED_LIBRARY) {
+ if (gt.GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS")) {
+ std::string name_of_def_file = gt.GetSupportDirectory();
+ name_of_def_file += "/" + gt.GetName();
+ name_of_def_file += ".def ";
+ vars["LINK_FLAGS"] += " /DEF:";
+ vars["LINK_FLAGS"] += this->GetLocalGenerator()->ConvertToOutputFormat(
+ name_of_def_file, cmOutputConverter::SHELL);
+ }
+ }
+
+ // Add OS X version flags, if any.
+ if (this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmState::MODULE_LIBRARY) {
+ this->AppendOSXVerFlag(vars["LINK_FLAGS"], this->TargetLinkLanguage,
+ "COMPATIBILITY", true);
+ this->AppendOSXVerFlag(vars["LINK_FLAGS"], this->TargetLinkLanguage,
+ "CURRENT", false);
+ }
+
+ this->addPoolNinjaVariable("JOB_POOL_LINK", &gt, vars);
+
+ this->AddModuleDefinitionFlag(vars["LINK_FLAGS"]);
+ vars["LINK_FLAGS"] =
+ cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]);
+
+ vars["MANIFESTS"] = this->GetManifests();
+
+ vars["LINK_PATH"] = frameworkPath + linkPath;
+ std::string lwyuFlags;
+ if (genTarget.GetProperty("LINK_WHAT_YOU_USE")) {
+ lwyuFlags = " -Wl,--no-as-needed";
+ }
+
+ // Compute architecture specific link flags. Yes, these go into a different
+ // variable for executables, probably due to a mistake made when duplicating
+ // code between the Makefile executable and library generators.
+ if (targetType == cmState::EXECUTABLE) {
+ std::string t = vars["FLAGS"];
+ localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
+ t += lwyuFlags;
+ vars["FLAGS"] = t;
+ } else {
+ std::string t = vars["ARCH_FLAGS"];
+ localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
+ vars["ARCH_FLAGS"] = t;
+ t = "";
+ t += lwyuFlags;
+ localGen.AddLanguageFlags(t, TargetLinkLanguage, cfgName);
+ vars["LANGUAGE_COMPILE_FLAGS"] = t;
+ }
+ if (this->GetGeneratorTarget()->HasSOName(cfgName)) {
+ vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage);
+ vars["SONAME"] = this->TargetNameSO;
+ if (targetType == cmState::SHARED_LIBRARY) {
+ std::string install_dir =
+ this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName);
+ if (!install_dir.empty()) {
+ vars["INSTALLNAME_DIR"] = localGen.Convert(
+ install_dir, cmOutputConverter::NONE, cmOutputConverter::SHELL);
+ }
+ }
+ }
+
+ cmNinjaDeps byproducts;
+
+ if (!this->TargetNameImport.empty()) {
+ const std::string impLibPath = localGen.ConvertToOutputFormat(
+ targetOutputImplib, cmOutputConverter::SHELL);
+ vars["TARGET_IMPLIB"] = impLibPath;
+ EnsureParentDirectoryExists(impLibPath);
+ if (genTarget.HasImportLibrary()) {
+ byproducts.push_back(targetOutputImplib);
+ }
+ }
+
+ if (!this->SetMsvcTargetPdbVariable(vars)) {
+ // It is common to place debug symbols at a specific place,
+ // so we need a plain target name in the rule available.
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetGeneratorTarget()->GetFullNameComponents(prefix, base, suffix);
+ std::string dbg_suffix = ".dbg";
+ // TODO: Where to document?
+ if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) {
+ dbg_suffix = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX");
+ }
+ vars["TARGET_PDB"] = base + suffix + dbg_suffix;
+ }
+
+ const std::string objPath = GetGeneratorTarget()->GetSupportDirectory();
+ vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
+ EnsureDirectoryExists(objPath);
+
+ if (this->GetGlobalGenerator()->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(), '\\', '/');
+ std::string& link_path = vars["LINK_PATH"];
+ std::replace(link_path.begin(), link_path.end(), '\\', '/');
+ }
+
+ const std::vector<cmCustomCommand>* cmdLists[3] = {
+ &gt.GetPreBuildCommands(), &gt.GetPreLinkCommands(),
+ &gt.GetPostBuildCommands()
+ };
+
+ std::vector<std::string> preLinkCmdLines, postBuildCmdLines;
+ std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines,
+ &preLinkCmdLines,
+ &postBuildCmdLines };
+
+ for (unsigned i = 0; i != 3; ++i) {
+ for (std::vector<cmCustomCommand>::const_iterator ci =
+ cmdLists[i]->begin();
+ ci != cmdLists[i]->end(); ++ci) {
+ cmCustomCommandGenerator ccg(*ci, cfgName, this->GetLocalGenerator());
+ localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]);
+ std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
+ std::transform(ccByproducts.begin(), ccByproducts.end(),
+ std::back_inserter(byproducts), MapToNinjaPath());
+ }
+ }
+
+ // maybe create .def file from list of objects
+ if (gt.GetType() == cmState::SHARED_LIBRARY &&
+ this->GetMakefile()->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS")) {
+ if (gt.GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS")) {
+ std::string cmakeCommand =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ std::string name_of_def_file = gt.GetSupportDirectory();
+ name_of_def_file += "/" + gt.GetName();
+ name_of_def_file += ".def";
+ std::string cmd = cmakeCommand;
+ cmd += " -E __create_def ";
+ cmd += this->GetLocalGenerator()->ConvertToOutputFormat(
+ name_of_def_file, cmOutputConverter::SHELL);
+ cmd += " ";
+ cmNinjaDeps objs = this->GetObjects();
+ std::string obj_list_file = name_of_def_file;
+ obj_list_file += ".objs";
+ cmd += this->GetLocalGenerator()->ConvertToOutputFormat(
+ obj_list_file, cmOutputConverter::SHELL);
+ preLinkCmdLines.push_back(cmd);
+ // create a list of obj files for the -E __create_def to read
+ cmGeneratedFileStream fout(obj_list_file.c_str());
+ for (cmNinjaDeps::iterator i = objs.begin(); i != objs.end(); ++i) {
+ if (cmHasLiteralSuffix(*i, ".obj")) {
+ fout << *i << "\n";
+ }
+ }
+ }
+ }
+ // If we have any PRE_LINK commands, we need to go back to HOME_OUTPUT for
+ // the link commands.
+ if (!preLinkCmdLines.empty()) {
+ const std::string homeOutDir = localGen.ConvertToOutputFormat(
+ localGen.GetBinaryDirectory(), cmOutputConverter::SHELL);
+ preLinkCmdLines.push_back("cd " + homeOutDir);
+ }
+
+ vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines);
+ std::string postBuildCmdLine = localGen.BuildCommandLine(postBuildCmdLines);
+
+ cmNinjaVars symlinkVars;
+ if (targetOutput == targetOutputReal) {
+ vars["POST_BUILD"] = postBuildCmdLine;
+ } else {
+ vars["POST_BUILD"] = ":";
+ symlinkVars["POST_BUILD"] = postBuildCmdLine;
+ }
+ cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator();
+
+ int commandLineLengthLimit = -1;
+ if (!this->ForceResponseFile()) {
+ commandLineLengthLimit = calculateCommandLineLengthLimit(
+ globalGen.GetRuleCmdLength(this->LanguageLinkerRule()));
+ }
+
+ const std::string rspfile =
+ std::string(cmake::GetCMakeFilesDirectoryPostSlash()) + gt.GetName() +
+ ".rsp";
+
+ // Gather order-only dependencies.
+ cmNinjaDeps orderOnlyDeps;
+ this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(),
+ orderOnlyDeps);
+
+ // Ninja should restat after linking if and only if there are byproducts.
+ vars["RESTAT"] = byproducts.empty() ? "" : "1";
+
+ for (cmNinjaDeps::const_iterator oi = byproducts.begin(),
+ oe = byproducts.end();
+ oi != oe; ++oi) {
+ this->GetGlobalGenerator()->SeenCustomCommandOutput(*oi);
+ outputs.push_back(*oi);
+ }
+
+ // Write the build statement for this target.
+ bool usedResponseFile = false;
+ globalGen.WriteBuild(this->GetBuildFileStream(), comment.str(),
+ this->LanguageLinkerRule(), outputs, explicitDeps,
+ implicitDeps, orderOnlyDeps, vars, rspfile,
+ commandLineLengthLimit, &usedResponseFile);
+ this->WriteLinkRule(usedResponseFile);
+
+ if (targetOutput != targetOutputReal && !gt.IsFrameworkOnApple()) {
+ if (targetType == cmState::EXECUTABLE) {
+ globalGen.WriteBuild(
+ this->GetBuildFileStream(),
+ "Create executable symlink " + targetOutput,
+ "CMAKE_SYMLINK_EXECUTABLE", cmNinjaDeps(1, targetOutput),
+ cmNinjaDeps(1, targetOutputReal), emptyDeps, emptyDeps, symlinkVars);
+ } else {
+ cmNinjaDeps symlinks;
+ std::string const soName =
+ this->ConvertToNinjaPath(this->GetTargetFilePath(this->TargetNameSO));
+ // If one link has to be created.
+ if (targetOutputReal == soName || targetOutput == soName) {
+ symlinkVars["SONAME"] = soName;
+ } else {
+ symlinkVars["SONAME"] = "";
+ symlinks.push_back(soName);
+ }
+ symlinks.push_back(targetOutput);
+ globalGen.WriteBuild(
+ this->GetBuildFileStream(), "Create library symlink " + targetOutput,
+ "CMAKE_SYMLINK_LIBRARY", symlinks, cmNinjaDeps(1, targetOutputReal),
+ emptyDeps, emptyDeps, symlinkVars);
+ }
+ }
+
+ // Add aliases for the file name and the target name.
+ globalGen.AddTargetAlias(this->TargetNameOut, &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);
+
+ // Add aliases for the target name.
+ this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
+ this->GetGeneratorTarget());
+}
diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h
new file mode 100644
index 0000000..f466e17
--- /dev/null
+++ b/Source/cmNinjaNormalTargetGenerator.h
@@ -0,0 +1,53 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
+ Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmNinjaNormalTargetGenerator_h
+#define cmNinjaNormalTargetGenerator_h
+
+#include "cmNinjaTargetGenerator.h"
+
+#include "cmNinjaTypes.h"
+
+#include <set>
+
+class cmSourceFile;
+class cmOSXBundleGenerator;
+class cmGeneratorTarget;
+
+class cmNinjaNormalTargetGenerator : public cmNinjaTargetGenerator
+{
+public:
+ cmNinjaNormalTargetGenerator(cmGeneratorTarget* target);
+ ~cmNinjaNormalTargetGenerator() CM_OVERRIDE;
+
+ void Generate() CM_OVERRIDE;
+
+private:
+ std::string LanguageLinkerRule() const;
+ const char* GetVisibleTypeName() const;
+ void WriteLanguagesRules();
+ void WriteLinkRule(bool useResponseFile);
+ void WriteLinkStatement();
+ void WriteObjectLibStatement();
+ std::vector<std::string> ComputeLinkCmd();
+
+private:
+ // Target name info.
+ std::string TargetNameOut;
+ std::string TargetNameSO;
+ std::string TargetNameReal;
+ std::string TargetNameImport;
+ std::string TargetNamePDB;
+ std::string TargetLinkLanguage;
+};
+
+#endif // ! cmNinjaNormalTargetGenerator_h
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
new file mode 100644
index 0000000..1d3e608
--- /dev/null
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -0,0 +1,745 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
+ Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmNinjaTargetGenerator.h"
+
+#include "cmAlgorithms.h"
+#include "cmComputeLinkInformation.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmLocalNinjaGenerator.h"
+#include "cmMakefile.h"
+#include "cmNinjaNormalTargetGenerator.h"
+#include "cmNinjaUtilityTargetGenerator.h"
+#include "cmSourceFile.h"
+#include "cmSystemTools.h"
+
+#include <algorithm>
+
+cmNinjaTargetGenerator* cmNinjaTargetGenerator::New(cmGeneratorTarget* target)
+{
+ switch (target->GetType()) {
+ case cmState::EXECUTABLE:
+ case cmState::SHARED_LIBRARY:
+ case cmState::STATIC_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ case cmState::OBJECT_LIBRARY:
+ return new cmNinjaNormalTargetGenerator(target);
+
+ case cmState::UTILITY:
+ return new cmNinjaUtilityTargetGenerator(target);
+ ;
+
+ case cmState::GLOBAL_TARGET: {
+ // We only want to process global targets that live in the home
+ // (i.e. top-level) directory. CMake creates copies of these targets
+ // in every directory, which we don't need.
+ if (strcmp(target->GetLocalGenerator()->GetCurrentSourceDirectory(),
+ target->GetLocalGenerator()->GetSourceDirectory()) == 0) {
+ return new cmNinjaUtilityTargetGenerator(target);
+ }
+ // else fallthrough
+ }
+
+ default:
+ return CM_NULLPTR;
+ }
+}
+
+cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmGeneratorTarget* target)
+ : cmCommonTargetGenerator(target)
+ , MacOSXContentGenerator(CM_NULLPTR)
+ , OSXBundleGenerator(CM_NULLPTR)
+ , MacContentFolders()
+ , LocalGenerator(
+ static_cast<cmLocalNinjaGenerator*>(target->GetLocalGenerator()))
+ , Objects()
+{
+ MacOSXContentGenerator = new MacOSXContentGeneratorType(this);
+}
+
+cmNinjaTargetGenerator::~cmNinjaTargetGenerator()
+{
+ delete this->MacOSXContentGenerator;
+}
+
+cmGeneratedFileStream& cmNinjaTargetGenerator::GetBuildFileStream() const
+{
+ return *this->GetGlobalGenerator()->GetBuildFileStream();
+}
+
+cmGeneratedFileStream& cmNinjaTargetGenerator::GetRulesFileStream() const
+{
+ return *this->GetGlobalGenerator()->GetRulesFileStream();
+}
+
+cmGlobalNinjaGenerator* cmNinjaTargetGenerator::GetGlobalGenerator() const
+{
+ return this->LocalGenerator->GetGlobalNinjaGenerator();
+}
+
+std::string cmNinjaTargetGenerator::LanguageCompilerRule(
+ const std::string& lang) const
+{
+ return lang + "_COMPILER__" +
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
+}
+
+std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget()
+{
+ return "cmake_order_depends_target_" + this->GetTargetName();
+}
+
+// TODO: Most of the code is picked up from
+// void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink),
+// void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
+// Refactor it.
+std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
+ cmSourceFile const* source, const std::string& language)
+{
+ std::string flags = this->GetFlags(language);
+
+ // Add Fortran format flags.
+ if (language == "Fortran") {
+ this->AppendFortranFormatFlags(flags, *source);
+ }
+
+ // Add source file specific flags.
+ this->LocalGenerator->AppendFlags(flags,
+ source->GetProperty("COMPILE_FLAGS"));
+
+ return flags;
+}
+
+void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags,
+ std::string const& language)
+{
+ std::vector<std::string> includes;
+ this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
+ language, this->GetConfigName());
+ // Add include directory flags.
+ std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
+ includes, this->GeneratorTarget, language,
+ language == "RC", // full include paths for RC needed by cmcldeps
+ false, this->GetConfigName());
+ if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
+ std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/');
+ }
+
+ this->LocalGenerator->AppendFlags(languageFlags, includeFlags);
+}
+
+bool cmNinjaTargetGenerator::NeedDepTypeMSVC(const std::string& lang) const
+{
+ return strcmp(this->GetMakefile()->GetSafeDefinition("CMAKE_NINJA_DEPTYPE_" +
+ lang),
+ "msvc") == 0;
+}
+
+// TODO: Refactor with
+// void cmMakefileTargetGenerator::WriteTargetLanguageFlags().
+std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source,
+ const std::string& language)
+{
+ std::set<std::string> defines;
+ this->LocalGenerator->AppendDefines(
+ defines, source->GetProperty("COMPILE_DEFINITIONS"));
+ {
+ std::string defPropName = "COMPILE_DEFINITIONS_";
+ defPropName += cmSystemTools::UpperCase(this->GetConfigName());
+ this->LocalGenerator->AppendDefines(defines,
+ source->GetProperty(defPropName));
+ }
+
+ std::string definesString = this->GetDefines(language);
+ this->LocalGenerator->JoinDefines(defines, definesString, language);
+
+ return definesString;
+}
+
+cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const
+{
+ // Static libraries never depend on other targets for linking.
+ if (this->GeneratorTarget->GetType() == cmState::STATIC_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmState::OBJECT_LIBRARY) {
+ return cmNinjaDeps();
+ }
+
+ cmComputeLinkInformation* cli =
+ this->GeneratorTarget->GetLinkInformation(this->GetConfigName());
+ if (!cli) {
+ return cmNinjaDeps();
+ }
+
+ const std::vector<std::string>& deps = cli->GetDepends();
+ cmNinjaDeps result(deps.size());
+ std::transform(deps.begin(), deps.end(), result.begin(), MapToNinjaPath());
+
+ // Add a dependency on the link definitions file, if any.
+ if (this->ModuleDefinitionFile) {
+ result.push_back(
+ this->ConvertToNinjaPath(this->ModuleDefinitionFile->GetFullPath()));
+ }
+
+ // Add a dependency on user-specified manifest files, if any.
+ std::vector<cmSourceFile const*> manifest_srcs;
+ this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName);
+ for (std::vector<cmSourceFile const*>::iterator mi = manifest_srcs.begin();
+ mi != manifest_srcs.end(); ++mi) {
+ result.push_back(this->ConvertToNinjaPath((*mi)->GetFullPath()));
+ }
+
+ // Add user-specified dependencies.
+ if (const char* linkDepends =
+ this->GeneratorTarget->GetProperty("LINK_DEPENDS")) {
+ std::vector<std::string> linkDeps;
+ cmSystemTools::ExpandListArgument(linkDepends, linkDeps);
+ std::transform(linkDeps.begin(), linkDeps.end(),
+ std::back_inserter(result), MapToNinjaPath());
+ }
+
+ return result;
+}
+
+std::string cmNinjaTargetGenerator::GetSourceFilePath(
+ cmSourceFile const* source) const
+{
+ return ConvertToNinjaPath(source->GetFullPath());
+}
+
+std::string cmNinjaTargetGenerator::GetObjectFilePath(
+ cmSourceFile const* source) const
+{
+ std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
+ if (!path.empty()) {
+ path += "/";
+ }
+ std::string const& objectName = this->GeneratorTarget->GetObjectName(source);
+ path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ path += "/";
+ path += objectName;
+ return path;
+}
+
+std::string cmNinjaTargetGenerator::GetTargetOutputDir() const
+{
+ std::string dir = this->GeneratorTarget->GetDirectory(this->GetConfigName());
+ return ConvertToNinjaPath(dir);
+}
+
+std::string cmNinjaTargetGenerator::GetTargetFilePath(
+ const std::string& name) const
+{
+ std::string path = this->GetTargetOutputDir();
+ if (path.empty() || path == ".") {
+ return name;
+ }
+ path += "/";
+ path += name;
+ return path;
+}
+
+std::string cmNinjaTargetGenerator::GetTargetName() const
+{
+ return this->GeneratorTarget->GetName();
+}
+
+bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const
+{
+ cmMakefile* mf = this->GetMakefile();
+ if (mf->GetDefinition("MSVC_C_ARCHITECTURE_ID") ||
+ mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID")) {
+ std::string pdbPath;
+ std::string compilePdbPath;
+ if (this->GeneratorTarget->GetType() == cmState::EXECUTABLE ||
+ this->GeneratorTarget->GetType() == cmState::STATIC_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmState::MODULE_LIBRARY) {
+ pdbPath = this->GeneratorTarget->GetPDBDirectory(this->GetConfigName());
+ pdbPath += "/";
+ pdbPath += this->GeneratorTarget->GetPDBName(this->GetConfigName());
+ }
+ if (this->GeneratorTarget->GetType() <= cmState::OBJECT_LIBRARY) {
+ compilePdbPath =
+ this->GeneratorTarget->GetCompilePDBPath(this->GetConfigName());
+ if (compilePdbPath.empty()) {
+ compilePdbPath = this->GeneratorTarget->GetSupportDirectory() + "/";
+ }
+ }
+
+ vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat(
+ ConvertToNinjaPath(pdbPath), cmOutputConverter::SHELL);
+ vars["TARGET_COMPILE_PDB"] =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ ConvertToNinjaPath(compilePdbPath), cmOutputConverter::SHELL);
+
+ EnsureParentDirectoryExists(pdbPath);
+ EnsureParentDirectoryExists(compilePdbPath);
+ return true;
+ }
+ return false;
+}
+
+void cmNinjaTargetGenerator::WriteLanguageRules(const std::string& language)
+{
+#ifdef NINJA_GEN_VERBOSE_FILES
+ this->GetRulesFileStream() << "# Rules for language " << language << "\n\n";
+#endif
+ this->WriteCompileRule(language);
+}
+
+void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
+{
+ cmLocalGenerator::RuleVariables vars;
+ vars.RuleLauncher = "RULE_LAUNCH_COMPILE";
+ vars.CMTarget = this->GetGeneratorTarget();
+ vars.Language = lang.c_str();
+ vars.Source = "$in";
+ vars.Object = "$out";
+ vars.Defines = "$DEFINES";
+ vars.Includes = "$INCLUDES";
+ vars.TargetPDB = "$TARGET_PDB";
+ vars.TargetCompilePDB = "$TARGET_COMPILE_PDB";
+ vars.ObjectDir = "$OBJECT_DIR";
+ vars.ObjectFileDir = "$OBJECT_FILE_DIR";
+
+ cmMakefile* mf = this->GetMakefile();
+
+ std::string flags = "$FLAGS";
+ std::string rspfile;
+ std::string rspcontent;
+ std::string responseFlag;
+
+ if (lang != "RC" && this->ForceResponseFile()) {
+ rspfile = "$RSP_FILE";
+ responseFlag = "@" + rspfile;
+ rspcontent = " $DEFINES $INCLUDES $FLAGS";
+ flags = responseFlag;
+ 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 (this->NeedDepTypeMSVC(lang)) {
+ deptype = "msvc";
+ depfile = "";
+ 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";
+ const std::string cl = mf->GetDefinition("CMAKE_C_COMPILER")
+ ? mf->GetSafeDefinition("CMAKE_C_COMPILER")
+ : mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
+ cldeps = "\"";
+ cldeps += cmSystemTools::GetCMClDepsCommand();
+ cldeps += "\" " + lang + " $in \"$DEP_FILE\" $out \"";
+ cldeps += mf->GetSafeDefinition("CMAKE_CL_SHOWINCLUDES_PREFIX");
+ cldeps += "\" \"" + cl + "\" ";
+ }
+ } else {
+ deptype = "gcc";
+ const char* langdeptype = mf->GetDefinition("CMAKE_NINJA_DEPTYPE_" + lang);
+ if (langdeptype) {
+ deptype = langdeptype;
+ }
+ depfile = "$DEP_FILE";
+ const std::string flagsName = "CMAKE_DEPFILE_FLAGS_" + lang;
+ std::string depfileFlags = mf->GetSafeDefinition(flagsName);
+ if (!depfileFlags.empty()) {
+ cmSystemTools::ReplaceString(depfileFlags, "<DEPFILE>", "$DEP_FILE");
+ cmSystemTools::ReplaceString(depfileFlags, "<OBJECT>", "$out");
+ cmSystemTools::ReplaceString(depfileFlags, "<CMAKE_C_COMPILER>",
+ mf->GetDefinition("CMAKE_C_COMPILER"));
+ flags += " " + depfileFlags;
+ }
+ }
+
+ vars.Flags = flags.c_str();
+ vars.DependencyFile = depfile.c_str();
+
+ // Rule for compiling object file.
+ const std::string cmdVar = std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
+ std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
+ std::vector<std::string> compileCmds;
+ cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
+
+ // Maybe insert an include-what-you-use runner.
+ if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) {
+ std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE";
+ const char* iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
+ std::string const tidy_prop = lang + "_CLANG_TIDY";
+ const char* tidy = this->GeneratorTarget->GetProperty(tidy_prop);
+ if ((iwyu && *iwyu) || (tidy && *tidy)) {
+ std::string run_iwyu = this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ run_iwyu += " -E __run_iwyu";
+ if (iwyu && *iwyu) {
+ run_iwyu += " --iwyu=";
+ run_iwyu += this->GetLocalGenerator()->EscapeForShell(iwyu);
+ }
+ if (tidy && *tidy) {
+ run_iwyu += " --tidy=";
+ run_iwyu += this->GetLocalGenerator()->EscapeForShell(tidy);
+ run_iwyu += " --source=$in";
+ }
+ run_iwyu += " -- ";
+ compileCmds.front().insert(0, run_iwyu);
+ }
+ }
+
+ // Maybe insert a compiler launcher like ccache or distcc
+ if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) {
+ std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER";
+ const char* clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
+ if (clauncher && *clauncher) {
+ std::vector<std::string> launcher_cmd;
+ cmSystemTools::ExpandListArgument(clauncher, launcher_cmd, true);
+ for (std::vector<std::string>::iterator i = launcher_cmd.begin(),
+ e = launcher_cmd.end();
+ i != e; ++i) {
+ *i = this->LocalGenerator->EscapeForShell(*i);
+ }
+ std::string const& run_launcher = cmJoin(launcher_cmd, " ") + " ";
+ compileCmds.front().insert(0, run_launcher);
+ }
+ }
+
+ if (!compileCmds.empty()) {
+ compileCmds.front().insert(0, cldeps);
+ }
+
+ for (std::vector<std::string>::iterator i = compileCmds.begin();
+ i != compileCmds.end(); ++i) {
+ this->GetLocalGenerator()->ExpandRuleVariables(*i, vars);
+ }
+
+ std::string cmdLine =
+ 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);
+}
+
+void cmNinjaTargetGenerator::WriteObjectBuildStatements()
+{
+ // Write comments.
+ cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
+ this->GetBuildFileStream()
+ << "# Object build statements for "
+ << 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 (std::vector<cmSourceFile const*>::const_iterator si =
+ customCommands.begin();
+ si != customCommands.end(); ++si) {
+ cmCustomCommand const* cc = (*si)->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 (std::vector<cmSourceFile const*>::const_iterator si =
+ externalObjects.begin();
+ si != externalObjects.end(); ++si) {
+ this->Objects.push_back(this->GetSourceFilePath(*si));
+ }
+
+ cmNinjaDeps orderOnlyDeps;
+ this->GetLocalGenerator()->AppendTargetDepends(this->GeneratorTarget,
+ orderOnlyDeps);
+
+ // 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 (std::vector<cmCustomCommand const*>::const_iterator cci =
+ this->CustomCommands.begin();
+ cci != this->CustomCommands.end(); ++cci) {
+ cmCustomCommand const* cc = *cci;
+ 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());
+ }
+
+ if (!orderOnlyDeps.empty()) {
+ cmNinjaDeps orderOnlyTarget;
+ orderOnlyTarget.push_back(this->OrderDependsTargetForTarget());
+ this->GetGlobalGenerator()->WritePhonyBuild(
+ this->GetBuildFileStream(),
+ "Order-only phony target for " + this->GetTargetName(), orderOnlyTarget,
+ cmNinjaDeps(), cmNinjaDeps(), orderOnlyDeps);
+ }
+ std::vector<cmSourceFile const*> objectSources;
+ this->GeneratorTarget->GetObjectSources(objectSources, config);
+ for (std::vector<cmSourceFile const*>::const_iterator si =
+ objectSources.begin();
+ si != objectSources.end(); ++si) {
+ this->WriteObjectBuildStatement(*si, !orderOnlyDeps.empty());
+ }
+
+ this->GetBuildFileStream() << "\n";
+}
+
+void cmNinjaTargetGenerator::WriteObjectBuildStatement(
+ cmSourceFile const* source, bool writeOrderDependsTargetForTarget)
+{
+ std::string const language = source->GetLanguage();
+ std::string const sourceFileName =
+ language == "RC" ? source->GetFullPath() : this->GetSourceFilePath(source);
+ std::string const objectDir =
+ this->ConvertToNinjaPath(this->GeneratorTarget->GetSupportDirectory());
+ std::string const objectFileName =
+ this->ConvertToNinjaPath(this->GetObjectFilePath(source));
+ std::string const objectFileDir =
+ cmSystemTools::GetFilenamePath(objectFileName);
+
+ cmNinjaVars vars;
+ vars["FLAGS"] = this->ComputeFlagsForObject(source, language);
+ vars["DEFINES"] = this->ComputeDefines(source, language);
+ vars["INCLUDES"] = this->GetIncludes(language);
+ if (!this->NeedDepTypeMSVC(language)) {
+ vars["DEP_FILE"] =
+ cmGlobalNinjaGenerator::EncodeDepfileSpace(objectFileName + ".d");
+ }
+
+ this->ExportObjectCompileCommand(
+ 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);
+ // Add this object to the list of object files.
+ this->Objects.push_back(objectFileName);
+
+ cmNinjaDeps explicitDeps;
+ explicitDeps.push_back(sourceFileName);
+
+ cmNinjaDeps implicitDeps;
+ if (const char* objectDeps = source->GetProperty("OBJECT_DEPENDS")) {
+ std::vector<std::string> depList;
+ cmSystemTools::ExpandListArgument(objectDeps, depList);
+ for (std::vector<std::string>::iterator odi = depList.begin();
+ odi != depList.end(); ++odi) {
+ if (cmSystemTools::FileIsFullPath(*odi)) {
+ *odi = cmSystemTools::CollapseFullPath(*odi);
+ }
+ }
+ std::transform(depList.begin(), depList.end(),
+ std::back_inserter(implicitDeps), MapToNinjaPath());
+ }
+
+ cmNinjaDeps orderOnlyDeps;
+ if (writeOrderDependsTargetForTarget) {
+ 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
+ // the target dependencies, OBJECT_DEPENDS or header file custom commands
+ // will rebuild the file.
+ if (source->GetPropertyAsBool("GENERATED") && !source->GetCustomCommand() &&
+ !this->GetGlobalGenerator()->HasCustomCommandOutput(sourceFileName)) {
+ this->GetGlobalGenerator()->AddAssumedSourceDependencies(sourceFileName,
+ orderOnlyDeps);
+ }
+
+ EnsureParentDirectoryExists(objectFileName);
+
+ vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
+ objectDir, cmOutputConverter::SHELL);
+ vars["OBJECT_FILE_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
+ objectFileDir, cmOutputConverter::SHELL);
+
+ this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
+ vars);
+
+ this->SetMsvcTargetPdbVariable(vars);
+
+ bool const isRC = (language == "RC");
+ int const commandLineLengthLimit =
+ ((!isRC && this->ForceResponseFile())) ? -1 : 0;
+ std::string const rspfile = objectFileName + ".rsp";
+
+ this->GetGlobalGenerator()->WriteBuild(
+ this->GetBuildFileStream(), comment, rule, outputs, explicitDeps,
+ implicitDeps, orderOnlyDeps, vars, rspfile, 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);
+ }
+}
+
+void cmNinjaTargetGenerator::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)
+{
+ if (!this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS")) {
+ return;
+ }
+
+ cmLocalGenerator::RuleVariables compileObjectVars;
+ compileObjectVars.Language = language.c_str();
+
+ std::string escapedSourceFileName = sourceFileName;
+
+ if (!cmSystemTools::FileIsFullPath(sourceFileName.c_str())) {
+ escapedSourceFileName = cmSystemTools::CollapseFullPath(
+ escapedSourceFileName, this->GetGlobalGenerator()
+ ->GetCMakeInstance()
+ ->GetHomeOutputDirectory());
+ }
+
+ escapedSourceFileName = this->LocalGenerator->ConvertToOutputFormat(
+ escapedSourceFileName, cmOutputConverter::SHELL);
+
+ compileObjectVars.Source = escapedSourceFileName.c_str();
+ compileObjectVars.Object = objectFileName.c_str();
+ compileObjectVars.ObjectDir = objectDir.c_str();
+ compileObjectVars.ObjectFileDir = objectFileDir.c_str();
+ compileObjectVars.Flags = flags.c_str();
+ compileObjectVars.Defines = defines.c_str();
+ compileObjectVars.Includes = includes.c_str();
+
+ // Rule for compiling object file.
+ std::string compileCmdVar = "CMAKE_";
+ compileCmdVar += language;
+ compileCmdVar += "_COMPILE_OBJECT";
+ std::string compileCmd =
+ this->GetMakefile()->GetRequiredDefinition(compileCmdVar);
+ std::vector<std::string> compileCmds;
+ cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
+
+ for (std::vector<std::string>::iterator i = compileCmds.begin();
+ i != compileCmds.end(); ++i) {
+ this->GetLocalGenerator()->ExpandRuleVariables(*i, compileObjectVars);
+ }
+
+ std::string cmdLine =
+ this->GetLocalGenerator()->BuildCommandLine(compileCmds);
+
+ this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName);
+}
+
+void cmNinjaTargetGenerator::EnsureDirectoryExists(
+ const std::string& path) const
+{
+ if (cmSystemTools::FileIsFullPath(path.c_str())) {
+ cmSystemTools::MakeDirectory(path.c_str());
+ } else {
+ cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
+ std::string fullPath =
+ std::string(gg->GetCMakeInstance()->GetHomeOutputDirectory());
+ // Also ensures their is a trailing slash.
+ gg->StripNinjaOutputPathPrefixAsSuffix(fullPath);
+ fullPath += path;
+ cmSystemTools::MakeDirectory(fullPath.c_str());
+ }
+}
+
+void cmNinjaTargetGenerator::EnsureParentDirectoryExists(
+ const std::string& path) const
+{
+ EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path));
+}
+
+void cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()(
+ cmSourceFile const& source, const char* pkgloc)
+{
+ // Skip OS X content when not building a Framework or Bundle.
+ if (!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) {
+ return;
+ }
+
+ std::string macdir =
+ this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc);
+
+ // Get the input file location.
+ std::string input = source.GetFullPath();
+ input = this->Generator->GetGlobalGenerator()->ConvertToNinjaPath(input);
+
+ // Get the output file location.
+ std::string output = macdir;
+ output += "/";
+ output += cmSystemTools::GetFilenameName(input);
+ output = this->Generator->GetGlobalGenerator()->ConvertToNinjaPath(output);
+
+ // Write a build statement to copy the content into the bundle.
+ this->Generator->GetGlobalGenerator()->WriteMacOSXContentBuild(input,
+ output);
+
+ // Add as a dependency to the target so that it gets called.
+ this->Generator->ExtraFiles.push_back(output);
+}
+
+void cmNinjaTargetGenerator::addPoolNinjaVariable(
+ const std::string& pool_property, cmGeneratorTarget* target,
+ cmNinjaVars& vars)
+{
+ const char* pool = target->GetProperty(pool_property);
+ if (pool) {
+ vars["pool"] = pool;
+ }
+}
+
+bool cmNinjaTargetGenerator::ForceResponseFile()
+{
+ static std::string const forceRspFile = "CMAKE_NINJA_FORCE_RESPONSE_FILE";
+ return (this->GetMakefile()->IsDefinitionSet(forceRspFile) ||
+ cmSystemTools::GetEnv(forceRspFile) != CM_NULLPTR);
+}
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
new file mode 100644
index 0000000..9740f0e
--- /dev/null
+++ b/Source/cmNinjaTargetGenerator.h
@@ -0,0 +1,164 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
+ Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmNinjaTargetGenerator_h
+#define cmNinjaTargetGenerator_h
+
+#include "cmCommonTargetGenerator.h"
+
+#include "cmGlobalNinjaGenerator.h"
+#include "cmLocalNinjaGenerator.h"
+#include "cmNinjaTypes.h"
+#include "cmOSXBundleGenerator.h"
+
+class cmTarget;
+class cmGeneratedFileStream;
+class cmGeneratorTarget;
+class cmMakefile;
+class cmSourceFile;
+class cmCustomCommand;
+
+class cmNinjaTargetGenerator : public cmCommonTargetGenerator
+{
+public:
+ /// Create a cmNinjaTargetGenerator according to the @a target's type.
+ static cmNinjaTargetGenerator* New(cmGeneratorTarget* target);
+
+ /// Build a NinjaTargetGenerator.
+ cmNinjaTargetGenerator(cmGeneratorTarget* target);
+
+ /// Destructor.
+ ~cmNinjaTargetGenerator() CM_OVERRIDE;
+
+ virtual void Generate() = 0;
+
+ std::string GetTargetName() const;
+
+ bool NeedDepTypeMSVC(const std::string& lang) const;
+
+protected:
+ bool SetMsvcTargetPdbVariable(cmNinjaVars&) const;
+
+ cmGeneratedFileStream& GetBuildFileStream() const;
+ cmGeneratedFileStream& GetRulesFileStream() const;
+
+ cmGeneratorTarget* GetGeneratorTarget() const
+ {
+ return this->GeneratorTarget;
+ }
+
+ cmLocalNinjaGenerator* GetLocalGenerator() const
+ {
+ return this->LocalGenerator;
+ }
+
+ cmGlobalNinjaGenerator* GetGlobalGenerator() const;
+
+ cmMakefile* GetMakefile() const { return this->Makefile; }
+
+ std::string LanguageCompilerRule(const std::string& lang) const;
+
+ std::string OrderDependsTargetForTarget();
+
+ std::string ComputeOrderDependsForTarget();
+
+ /**
+ * Compute the flags for compilation of object files for a given @a language.
+ * @note Generally it is the value of the variable whose name is computed
+ * by LanguageFlagsVarName().
+ */
+ std::string ComputeFlagsForObject(cmSourceFile const* source,
+ const std::string& language);
+
+ void AddIncludeFlags(std::string& flags,
+ std::string const& lang) CM_OVERRIDE;
+
+ std::string ComputeDefines(cmSourceFile const* source,
+ const std::string& language);
+
+ std::string ConvertToNinjaPath(const std::string& path) const
+ {
+ return this->GetGlobalGenerator()->ConvertToNinjaPath(path);
+ }
+ cmGlobalNinjaGenerator::MapToNinjaPathImpl MapToNinjaPath() const
+ {
+ return this->GetGlobalGenerator()->MapToNinjaPath();
+ }
+
+ /// @return the list of link dependency for the given target @a target.
+ cmNinjaDeps ComputeLinkDeps() const;
+
+ /// @return the source file path for the given @a source.
+ std::string GetSourceFilePath(cmSourceFile const* source) const;
+
+ /// @return the object file path for the given @a source.
+ std::string GetObjectFilePath(cmSourceFile const* source) const;
+
+ /// @return the file path where the target named @a name is generated.
+ std::string GetTargetFilePath(const std::string& name) const;
+
+ /// @return the output path for the target.
+ virtual std::string GetTargetOutputDir() const;
+
+ void WriteLanguageRules(const std::string& language);
+ void WriteCompileRule(const std::string& language);
+ void WriteObjectBuildStatements();
+ void WriteObjectBuildStatement(cmSourceFile const* source,
+ bool writeOrderDependsTargetForTarget);
+
+ 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);
+
+ cmNinjaDeps GetObjects() const { return this->Objects; }
+
+ void EnsureDirectoryExists(const std::string& dir) const;
+ void EnsureParentDirectoryExists(const std::string& path) const;
+
+ // write rules for Mac OS X Application Bundle content.
+ struct MacOSXContentGeneratorType
+ : cmOSXBundleGenerator::MacOSXContentGeneratorType
+ {
+ MacOSXContentGeneratorType(cmNinjaTargetGenerator* g)
+ : Generator(g)
+ {
+ }
+
+ void operator()(cmSourceFile const& source,
+ const char* pkgloc) CM_OVERRIDE;
+
+ private:
+ cmNinjaTargetGenerator* Generator;
+ };
+ friend struct MacOSXContentGeneratorType;
+
+ MacOSXContentGeneratorType* MacOSXContentGenerator;
+ // Properly initialized by sub-classes.
+ cmOSXBundleGenerator* OSXBundleGenerator;
+ std::set<std::string> MacContentFolders;
+
+ void addPoolNinjaVariable(const std::string& pool_property,
+ cmGeneratorTarget* target, cmNinjaVars& vars);
+
+ bool ForceResponseFile();
+
+private:
+ cmLocalNinjaGenerator* LocalGenerator;
+ /// List of object files for this target.
+ cmNinjaDeps Objects;
+ std::vector<cmCustomCommand const*> CustomCommands;
+ cmNinjaDeps ExtraFiles;
+};
+
+#endif // ! cmNinjaTargetGenerator_h
diff --git a/Source/cmNinjaTypes.h b/Source/cmNinjaTypes.h
new file mode 100644
index 0000000..82a5220
--- /dev/null
+++ b/Source/cmNinjaTypes.h
@@ -0,0 +1,21 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
+ Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmNinjaTypes_h
+#define cmNinjaTypes_h
+
+#include "cmStandardIncludes.h"
+
+typedef std::vector<std::string> cmNinjaDeps;
+typedef std::map<std::string, std::string> cmNinjaVars;
+
+#endif // ! cmNinjaTypes_h
diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx
new file mode 100644
index 0000000..c549646
--- /dev/null
+++ b/Source/cmNinjaUtilityTargetGenerator.cxx
@@ -0,0 +1,149 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
+ Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmNinjaUtilityTargetGenerator.h"
+
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+
+cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator(
+ cmGeneratorTarget* target)
+ : cmNinjaTargetGenerator(target)
+{
+}
+
+cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator()
+{
+}
+
+void cmNinjaUtilityTargetGenerator::Generate()
+{
+ std::string utilCommandName = cmake::GetCMakeFilesDirectoryPostSlash();
+ utilCommandName += this->GetTargetName() + ".util";
+ utilCommandName =
+ this->GetGlobalGenerator()->NinjaOutputPath(utilCommandName);
+
+ std::vector<std::string> commands;
+ cmNinjaDeps deps, outputs, util_outputs(1, utilCommandName);
+
+ const std::vector<cmCustomCommand>* cmdLists[2] = {
+ &this->GetGeneratorTarget()->GetPreBuildCommands(),
+ &this->GetGeneratorTarget()->GetPostBuildCommands()
+ };
+
+ bool uses_terminal = false;
+
+ for (unsigned i = 0; i != 2; ++i) {
+ for (std::vector<cmCustomCommand>::const_iterator ci =
+ cmdLists[i]->begin();
+ ci != cmdLists[i]->end(); ++ci) {
+ 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::vector<cmSourceFile*> sources;
+ std::string config =
+ this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ this->GetGeneratorTarget()->GetSourceFiles(sources, config);
+ for (std::vector<cmSourceFile*>::const_iterator source = sources.begin();
+ source != sources.end(); ++source) {
+ if (cmCustomCommand* 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());
+ }
+ }
+
+ this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
+ outputs);
+ this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(),
+ deps);
+
+ if (commands.empty()) {
+ this->GetGlobalGenerator()->WritePhonyBuild(
+ this->GetBuildFileStream(),
+ "Utility command for " + this->GetTargetName(), outputs, deps);
+ } else {
+ std::string command =
+ this->GetLocalGenerator()->BuildCommandLine(commands);
+ const char* echoStr =
+ this->GetGeneratorTarget()->GetProperty("EchoString");
+ std::string desc;
+ if (echoStr) {
+ desc = echoStr;
+ } else {
+ desc = "Running utility command for " + this->GetTargetName();
+ }
+
+ // TODO: fix problematic global targets. For now, search and replace the
+ // makefile vars.
+ cmSystemTools::ReplaceString(
+ command, "$(CMAKE_SOURCE_DIR)",
+ this->GetLocalGenerator()
+ ->ConvertToOutputFormat(
+ this->GetLocalGenerator()->GetSourceDirectory(),
+ cmOutputConverter::SHELL)
+ .c_str());
+ cmSystemTools::ReplaceString(
+ command, "$(CMAKE_BINARY_DIR)",
+ this->GetLocalGenerator()
+ ->ConvertToOutputFormat(
+ this->GetLocalGenerator()->GetBinaryDirectory(),
+ cmOutputConverter::SHELL)
+ .c_str());
+ cmSystemTools::ReplaceString(command, "$(ARGS)", "");
+
+ if (command.find('$') != std::string::npos) {
+ return;
+ }
+
+ for (cmNinjaDeps::const_iterator oi = util_outputs.begin(),
+ oe = util_outputs.end();
+ oi != oe; ++oi) {
+ this->GetGlobalGenerator()->SeenCustomCommandOutput(*oi);
+ }
+
+ this->GetGlobalGenerator()->WriteCustomCommandBuild(
+ command, desc, "Utility command for " + this->GetTargetName(),
+ uses_terminal,
+ /*restat*/ true, util_outputs, deps);
+
+ this->GetGlobalGenerator()->WritePhonyBuild(
+ this->GetBuildFileStream(), "", outputs,
+ cmNinjaDeps(1, utilCommandName));
+ }
+
+ this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
+ this->GetGeneratorTarget());
+}
diff --git a/Source/cmNinjaUtilityTargetGenerator.h b/Source/cmNinjaUtilityTargetGenerator.h
new file mode 100644
index 0000000..0c33a54
--- /dev/null
+++ b/Source/cmNinjaUtilityTargetGenerator.h
@@ -0,0 +1,31 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
+ Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmNinjaUtilityTargetGenerator_h
+#define cmNinjaUtilityTargetGenerator_h
+
+#include "cmNinjaTargetGenerator.h"
+
+#include "cmNinjaTypes.h"
+
+class cmSourceFile;
+
+class cmNinjaUtilityTargetGenerator : public cmNinjaTargetGenerator
+{
+public:
+ cmNinjaUtilityTargetGenerator(cmGeneratorTarget* target);
+ ~cmNinjaUtilityTargetGenerator() CM_OVERRIDE;
+
+ void Generate() CM_OVERRIDE;
+};
+
+#endif // ! cmNinjaUtilityTargetGenerator_h
diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx
new file mode 100644
index 0000000..dbfe6eb
--- /dev/null
+++ b/Source/cmOSXBundleGenerator.cxx
@@ -0,0 +1,228 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Nicolas Despres <nicolas.despres@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmOSXBundleGenerator.h"
+
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmTarget.h"
+
+#include <cassert>
+
+cmOSXBundleGenerator::cmOSXBundleGenerator(cmGeneratorTarget* target,
+ const std::string& configName)
+ : GT(target)
+ , Makefile(target->Target->GetMakefile())
+ , LocalGenerator(target->GetLocalGenerator())
+ , ConfigName(configName)
+ , MacContentFolders(CM_NULLPTR)
+{
+ if (this->MustSkip()) {
+ return;
+ }
+}
+
+bool cmOSXBundleGenerator::MustSkip()
+{
+ return !this->GT->HaveWellDefinedOutputFiles();
+}
+
+void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName,
+ std::string& outpath)
+{
+ if (this->MustSkip()) {
+ return;
+ }
+
+ // Compute bundle directory names.
+ std::string out = outpath;
+ out += "/";
+ out += this->GT->GetAppBundleDirectory(this->ConfigName, false);
+ cmSystemTools::MakeDirectory(out.c_str());
+ this->Makefile->AddCMakeOutputFile(out);
+
+ std::string newoutpath = out;
+
+ // Configure the Info.plist file. Note that it needs the executable name
+ // to be set.
+ std::string plist = outpath;
+ plist += "/";
+ plist += this->GT->GetAppBundleDirectory(this->ConfigName, true);
+ plist += "/Info.plist";
+ this->LocalGenerator->GenerateAppleInfoPList(this->GT, targetName,
+ plist.c_str());
+ this->Makefile->AddCMakeOutputFile(plist);
+ outpath = newoutpath;
+}
+
+void cmOSXBundleGenerator::CreateFramework(const std::string& targetName,
+ const std::string& outpath)
+{
+ if (this->MustSkip()) {
+ return;
+ }
+
+ assert(this->MacContentFolders);
+
+ // Compute the location of the top-level foo.framework directory.
+ std::string contentdir =
+ outpath + "/" + this->GT->GetFrameworkDirectory(this->ConfigName, true);
+ contentdir += "/";
+
+ std::string newoutpath =
+ outpath + "/" + this->GT->GetFrameworkDirectory(this->ConfigName, false);
+
+ std::string frameworkVersion = this->GT->GetFrameworkVersion();
+
+ // Configure the Info.plist file
+ std::string plist = newoutpath;
+ if (!this->Makefile->PlatformIsAppleIos()) {
+ // Put the Info.plist file into the Resources directory.
+ this->MacContentFolders->insert("Resources");
+ plist += "/Resources";
+ }
+ plist += "/Info.plist";
+ std::string name = cmSystemTools::GetFilenameName(targetName);
+ this->LocalGenerator->GenerateFrameworkInfoPList(this->GT, name,
+ plist.c_str());
+
+ // Generate Versions directory only for MacOSX frameworks
+ if (this->Makefile->PlatformIsAppleIos()) {
+ return;
+ }
+
+ // TODO: Use the cmMakefileTargetGenerator::ExtraFiles vector to
+ // drive rules to create these files at build time.
+ std::string oldName;
+ std::string newName;
+
+ // Make foo.framework/Versions
+ std::string versions = contentdir;
+ versions += "Versions";
+ cmSystemTools::MakeDirectory(versions.c_str());
+
+ // Make foo.framework/Versions/version
+ cmSystemTools::MakeDirectory(newoutpath.c_str());
+
+ // Current -> version
+ oldName = frameworkVersion;
+ newName = versions;
+ newName += "/Current";
+ cmSystemTools::RemoveFile(newName);
+ cmSystemTools::CreateSymlink(oldName, newName);
+ this->Makefile->AddCMakeOutputFile(newName);
+
+ // foo -> Versions/Current/foo
+ oldName = "Versions/Current/";
+ oldName += name;
+ newName = contentdir;
+ newName += name;
+ cmSystemTools::RemoveFile(newName);
+ cmSystemTools::CreateSymlink(oldName, newName);
+ this->Makefile->AddCMakeOutputFile(newName);
+
+ // Resources -> Versions/Current/Resources
+ if (this->MacContentFolders->find("Resources") !=
+ this->MacContentFolders->end()) {
+ oldName = "Versions/Current/Resources";
+ newName = contentdir;
+ newName += "Resources";
+ cmSystemTools::RemoveFile(newName);
+ cmSystemTools::CreateSymlink(oldName, newName);
+ this->Makefile->AddCMakeOutputFile(newName);
+ }
+
+ // Headers -> Versions/Current/Headers
+ if (this->MacContentFolders->find("Headers") !=
+ this->MacContentFolders->end()) {
+ oldName = "Versions/Current/Headers";
+ newName = contentdir;
+ newName += "Headers";
+ cmSystemTools::RemoveFile(newName);
+ cmSystemTools::CreateSymlink(oldName, newName);
+ this->Makefile->AddCMakeOutputFile(newName);
+ }
+
+ // PrivateHeaders -> Versions/Current/PrivateHeaders
+ if (this->MacContentFolders->find("PrivateHeaders") !=
+ this->MacContentFolders->end()) {
+ oldName = "Versions/Current/PrivateHeaders";
+ newName = contentdir;
+ newName += "PrivateHeaders";
+ cmSystemTools::RemoveFile(newName);
+ cmSystemTools::CreateSymlink(oldName, newName);
+ this->Makefile->AddCMakeOutputFile(newName);
+ }
+}
+
+void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName,
+ const std::string& root)
+{
+ if (this->MustSkip()) {
+ return;
+ }
+
+ // Compute bundle directory names.
+ std::string out = root;
+ out += "/";
+ out += this->GT->GetCFBundleDirectory(this->ConfigName, false);
+ cmSystemTools::MakeDirectory(out.c_str());
+ this->Makefile->AddCMakeOutputFile(out);
+
+ // Configure the Info.plist file. Note that it needs the executable name
+ // to be set.
+ std::string plist =
+ root + "/" + this->GT->GetCFBundleDirectory(this->ConfigName, true);
+ plist += "/Info.plist";
+ std::string name = cmSystemTools::GetFilenameName(targetName);
+ this->LocalGenerator->GenerateAppleInfoPList(this->GT, name, plist.c_str());
+ this->Makefile->AddCMakeOutputFile(plist);
+}
+
+void cmOSXBundleGenerator::GenerateMacOSXContentStatements(
+ std::vector<cmSourceFile const*> const& sources,
+ MacOSXContentGeneratorType* generator)
+{
+ if (this->MustSkip()) {
+ return;
+ }
+
+ for (std::vector<cmSourceFile const*>::const_iterator si = sources.begin();
+ si != sources.end(); ++si) {
+ cmGeneratorTarget::SourceFileFlags tsFlags =
+ this->GT->GetTargetSourceFileFlags(*si);
+ if (tsFlags.Type != cmGeneratorTarget::SourceFileTypeNormal) {
+ (*generator)(**si, tsFlags.MacFolder);
+ }
+ }
+}
+
+std::string cmOSXBundleGenerator::InitMacOSXContentDirectory(
+ const char* pkgloc)
+{
+ // Construct the full path to the content subdirectory.
+
+ std::string macdir = this->GT->GetMacContentDirectory(this->ConfigName,
+ /*implib*/ false);
+ macdir += "/";
+ macdir += pkgloc;
+ cmSystemTools::MakeDirectory(macdir.c_str());
+
+ // Record use of this content location. Only the first level
+ // directory is needed.
+ {
+ std::string loc = pkgloc;
+ loc = loc.substr(0, loc.find('/'));
+ this->MacContentFolders->insert(loc);
+ }
+
+ return macdir;
+}
diff --git a/Source/cmOSXBundleGenerator.h b/Source/cmOSXBundleGenerator.h
new file mode 100644
index 0000000..55a3c75
--- /dev/null
+++ b/Source/cmOSXBundleGenerator.h
@@ -0,0 +1,71 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Nicolas Despres <nicolas.despres@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmOSXBundleGenerator_h
+#define cmOSXBundleGenerator_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmSourceFile.h"
+
+#include <set>
+#include <string>
+
+class cmTarget;
+class cmMakefile;
+class cmLocalGenerator;
+class cmGeneratorTarget;
+
+class cmOSXBundleGenerator
+{
+public:
+ cmOSXBundleGenerator(cmGeneratorTarget* target,
+ const std::string& configName);
+
+ // create an app bundle at a given root, and return
+ // the directory within the bundle that contains the executable
+ void CreateAppBundle(const std::string& targetName, std::string& root);
+
+ // create a framework at a given root
+ void CreateFramework(const std::string& targetName, const std::string& root);
+
+ // create a cf bundle at a given root
+ void CreateCFBundle(const std::string& targetName, const std::string& root);
+
+ struct MacOSXContentGeneratorType
+ {
+ virtual ~MacOSXContentGeneratorType() {}
+ virtual void operator()(cmSourceFile const& source,
+ const char* pkgloc) = 0;
+ };
+
+ void GenerateMacOSXContentStatements(
+ std::vector<cmSourceFile const*> const& sources,
+ MacOSXContentGeneratorType* generator);
+ std::string InitMacOSXContentDirectory(const char* pkgloc);
+
+ void SetMacContentFolders(std::set<std::string>* macContentFolders)
+ {
+ this->MacContentFolders = macContentFolders;
+ }
+
+private:
+ bool MustSkip();
+
+private:
+ cmGeneratorTarget* GT;
+ cmMakefile* Makefile;
+ cmLocalGenerator* LocalGenerator;
+ std::string ConfigName;
+ std::set<std::string>* MacContentFolders;
+};
+
+#endif
diff --git a/Source/cmObject.h b/Source/cmObject.h
new file mode 100644
index 0000000..d883c52
--- /dev/null
+++ b/Source/cmObject.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmObject_h
+#define cmObject_h
+
+#include "cmStandardIncludes.h"
+
+/** \class cmObject
+ * \brief Superclass for all commands and other classes in CMake.
+ *
+ * cmObject is the base class for all classes in CMake. It defines some
+ * methods such as GetNameOfClass, IsA, SafeDownCast.
+ */
+class cmObject
+{
+public:
+ /**
+ * Need virtual destructor to destroy real command type.
+ */
+ virtual ~cmObject() {}
+
+ /**
+ * The class name of the command.
+ */
+ virtual const char* GetNameOfClass() = 0;
+
+ /**
+ * Returns true if this class is the given class, or a subclass of it.
+ */
+ static bool IsTypeOf(const char* type) { return !strcmp("cmObject", type); }
+
+ /**
+ * Returns true if this object is an instance of the given class or
+ * a subclass of it.
+ */
+ virtual bool IsA(const char* type) { return cmObject::IsTypeOf(type); }
+};
+
+#endif
diff --git a/Source/cmOptionCommand.cxx b/Source/cmOptionCommand.cxx
new file mode 100644
index 0000000..f6f0ec3
--- /dev/null
+++ b/Source/cmOptionCommand.cxx
@@ -0,0 +1,57 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmOptionCommand.h"
+
+// cmOptionCommand
+bool cmOptionCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ bool argError = false;
+ if (args.size() < 2) {
+ argError = true;
+ }
+ // for VTK 4.0 we have to support the option command with more than 3
+ // arguments if CMAKE_MINIMUM_REQUIRED_VERSION is not defined, if
+ // CMAKE_MINIMUM_REQUIRED_VERSION is defined, then we can have stricter
+ // checking.
+ if (this->Makefile->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
+ if (args.size() > 3) {
+ argError = true;
+ }
+ }
+ if (argError) {
+ std::string m = "called with incorrect number of arguments: ";
+ m += cmJoin(args, " ");
+ this->SetError(m);
+ return false;
+ }
+
+ std::string initialValue = "Off";
+ // Now check and see if the value has been stored in the cache
+ // already, if so use that value and don't look for the program
+ cmState* state = this->Makefile->GetState();
+ const char* existingValue = state->GetCacheEntryValue(args[0]);
+ if (existingValue) {
+ if (state->GetCacheEntryType(args[0]) != cmState::UNINITIALIZED) {
+ state->SetCacheEntryProperty(args[0], "HELPSTRING", args[1]);
+ return true;
+ }
+ initialValue = existingValue;
+ }
+ if (args.size() == 3) {
+ initialValue = args[2];
+ }
+ bool init = cmSystemTools::IsOn(initialValue.c_str());
+ this->Makefile->AddCacheDefinition(args[0], init ? "ON" : "OFF",
+ args[1].c_str(), cmState::BOOL);
+ return true;
+}
diff --git a/Source/cmOptionCommand.h b/Source/cmOptionCommand.h
new file mode 100644
index 0000000..6e6b076
--- /dev/null
+++ b/Source/cmOptionCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmOptionCommand_h
+#define cmOptionCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmOptionCommand
+ * \brief Provide an option to the user
+ *
+ * cmOptionCommand provides an option for the user to select
+ */
+class cmOptionCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmOptionCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "option"; }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ cmTypeMacro(cmOptionCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx
new file mode 100644
index 0000000..20f2246
--- /dev/null
+++ b/Source/cmOrderDirectories.cxx
@@ -0,0 +1,573 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmOrderDirectories.h"
+
+#include "cmAlgorithms.h"
+#include "cmGlobalGenerator.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <assert.h>
+
+#include <algorithm>
+
+/*
+Directory ordering computation.
+ - Useful to compute a safe runtime library path order
+ - Need runtime path for supporting INSTALL_RPATH_USE_LINK_PATH
+ - Need runtime path at link time to pickup transitive link dependencies
+ for shared libraries.
+*/
+
+class cmOrderDirectoriesConstraint
+{
+public:
+ cmOrderDirectoriesConstraint(cmOrderDirectories* od, std::string const& file)
+ : OD(od)
+ , GlobalGenerator(od->GlobalGenerator)
+ {
+ this->FullPath = file;
+
+ if (file.rfind(".framework") != std::string::npos) {
+ static cmsys::RegularExpression splitFramework(
+ "^(.*)/(.*).framework/(.*)$");
+ if (splitFramework.find(file) &&
+ (std::string::npos !=
+ splitFramework.match(3).find(splitFramework.match(2)))) {
+ this->Directory = splitFramework.match(1);
+ this->FileName =
+ std::string(file.begin() + this->Directory.size() + 1, file.end());
+ }
+ }
+
+ if (this->FileName.empty()) {
+ this->Directory = cmSystemTools::GetFilenamePath(file);
+ this->FileName = cmSystemTools::GetFilenameName(file);
+ }
+ }
+ virtual ~cmOrderDirectoriesConstraint() {}
+
+ void AddDirectory()
+ {
+ this->DirectoryIndex = this->OD->AddOriginalDirectory(this->Directory);
+ }
+
+ virtual void Report(std::ostream& e) = 0;
+
+ void FindConflicts(unsigned int index)
+ {
+ for (unsigned int i = 0; i < this->OD->OriginalDirectories.size(); ++i) {
+ // Check if this directory conflicts with the entry.
+ std::string const& dir = this->OD->OriginalDirectories[i];
+ if (!this->OD->IsSameDirectory(dir, this->Directory) &&
+ this->FindConflict(dir)) {
+ // The library will be found in this directory but this is not
+ // the directory named for it. Add an entry to make sure the
+ // desired directory comes before this one.
+ cmOrderDirectories::ConflictPair p(this->DirectoryIndex, index);
+ this->OD->ConflictGraph[i].push_back(p);
+ }
+ }
+ }
+
+ void FindImplicitConflicts(std::ostringstream& w)
+ {
+ bool first = true;
+ for (unsigned int i = 0; i < this->OD->OriginalDirectories.size(); ++i) {
+ // Check if this directory conflicts with the entry.
+ std::string const& dir = this->OD->OriginalDirectories[i];
+ if (dir != this->Directory &&
+ cmSystemTools::GetRealPath(dir) !=
+ cmSystemTools::GetRealPath(this->Directory) &&
+ this->FindConflict(dir)) {
+ // The library will be found in this directory but it is
+ // supposed to be found in an implicit search directory.
+ if (first) {
+ first = false;
+ w << " ";
+ this->Report(w);
+ w << " in " << this->Directory << " may be hidden by files in:\n";
+ }
+ w << " " << dir << "\n";
+ }
+ }
+ }
+
+protected:
+ virtual bool FindConflict(std::string const& dir) = 0;
+
+ bool FileMayConflict(std::string const& dir, std::string const& name);
+
+ cmOrderDirectories* OD;
+ cmGlobalGenerator* GlobalGenerator;
+
+ // The location in which the item is supposed to be found.
+ std::string FullPath;
+ std::string Directory;
+ std::string FileName;
+
+ // The index assigned to the directory.
+ int DirectoryIndex;
+};
+
+bool cmOrderDirectoriesConstraint::FileMayConflict(std::string const& dir,
+ std::string const& name)
+{
+ // Check if the file exists on disk.
+ std::string file = dir;
+ file += "/";
+ file += name;
+ if (cmSystemTools::FileExists(file.c_str(), true)) {
+ // The file conflicts only if it is not the same as the original
+ // file due to a symlink or hardlink.
+ return !cmSystemTools::SameFile(this->FullPath, file);
+ }
+
+ // Check if the file will be built by cmake.
+ std::set<std::string> const& files =
+ (this->GlobalGenerator->GetDirectoryContent(dir, false));
+ std::set<std::string>::const_iterator fi = files.find(name);
+ return fi != files.end();
+}
+
+class cmOrderDirectoriesConstraintSOName : public cmOrderDirectoriesConstraint
+{
+public:
+ cmOrderDirectoriesConstraintSOName(cmOrderDirectories* od,
+ std::string const& file,
+ const char* soname)
+ : cmOrderDirectoriesConstraint(od, file)
+ , SOName(soname ? soname : "")
+ {
+ if (this->SOName.empty()) {
+ // Try to guess the soname.
+ std::string soguess;
+ if (cmSystemTools::GuessLibrarySOName(file, soguess)) {
+ this->SOName = soguess;
+ }
+ }
+ }
+
+ void Report(std::ostream& e) CM_OVERRIDE
+ {
+ e << "runtime library [";
+ if (this->SOName.empty()) {
+ e << this->FileName;
+ } else {
+ e << this->SOName;
+ }
+ e << "]";
+ }
+
+ bool FindConflict(std::string const& dir) CM_OVERRIDE;
+
+private:
+ // The soname of the shared library if it is known.
+ std::string SOName;
+};
+
+bool cmOrderDirectoriesConstraintSOName::FindConflict(std::string const& dir)
+{
+ // Determine which type of check to do.
+ if (!this->SOName.empty()) {
+ // We have the library soname. Check if it will be found.
+ if (this->FileMayConflict(dir, this->SOName)) {
+ return true;
+ }
+ } else {
+ // We do not have the soname. Look for files in the directory
+ // that may conflict.
+ std::set<std::string> const& files =
+ (this->GlobalGenerator->GetDirectoryContent(dir, true));
+
+ // Get the set of files that might conflict. Since we do not
+ // know the soname just look at all files that start with the
+ // file name. Usually the soname starts with the library name.
+ std::string base = this->FileName;
+ std::set<std::string>::const_iterator first = files.lower_bound(base);
+ ++base[base.size() - 1];
+ std::set<std::string>::const_iterator last = files.upper_bound(base);
+ if (first != last) {
+ return true;
+ }
+ }
+ return false;
+}
+
+class cmOrderDirectoriesConstraintLibrary : public cmOrderDirectoriesConstraint
+{
+public:
+ cmOrderDirectoriesConstraintLibrary(cmOrderDirectories* od,
+ std::string const& file)
+ : cmOrderDirectoriesConstraint(od, file)
+ {
+ }
+
+ void Report(std::ostream& e) CM_OVERRIDE
+ {
+ e << "link library [" << this->FileName << "]";
+ }
+
+ bool FindConflict(std::string const& dir) CM_OVERRIDE;
+};
+
+bool cmOrderDirectoriesConstraintLibrary::FindConflict(std::string const& dir)
+{
+ // We have the library file name. Check if it will be found.
+ if (this->FileMayConflict(dir, this->FileName)) {
+ return true;
+ }
+
+ // Now check if the file exists with other extensions the linker
+ // might consider.
+ if (!this->OD->LinkExtensions.empty() &&
+ this->OD->RemoveLibraryExtension.find(this->FileName)) {
+ std::string lib = this->OD->RemoveLibraryExtension.match(1);
+ std::string ext = this->OD->RemoveLibraryExtension.match(2);
+ for (std::vector<std::string>::iterator i =
+ this->OD->LinkExtensions.begin();
+ i != this->OD->LinkExtensions.end(); ++i) {
+ if (*i != ext) {
+ std::string fname = lib;
+ fname += *i;
+ if (this->FileMayConflict(dir, fname)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+cmOrderDirectories::cmOrderDirectories(cmGlobalGenerator* gg,
+ const cmGeneratorTarget* target,
+ const char* purpose)
+{
+ this->GlobalGenerator = gg;
+ this->Target = target;
+ this->Purpose = purpose;
+ this->Computed = false;
+}
+
+cmOrderDirectories::~cmOrderDirectories()
+{
+ cmDeleteAll(this->ConstraintEntries);
+ cmDeleteAll(this->ImplicitDirEntries);
+}
+
+std::vector<std::string> const& cmOrderDirectories::GetOrderedDirectories()
+{
+ if (!this->Computed) {
+ this->Computed = true;
+ this->CollectOriginalDirectories();
+ this->FindConflicts();
+ this->OrderDirectories();
+ }
+ return this->OrderedDirectories;
+}
+
+void cmOrderDirectories::AddRuntimeLibrary(std::string const& fullPath,
+ const char* soname)
+{
+ // Add the runtime library at most once.
+ if (this->EmmittedConstraintSOName.insert(fullPath).second) {
+ // Implicit link directories need special handling.
+ if (!this->ImplicitDirectories.empty()) {
+ std::string dir = cmSystemTools::GetFilenamePath(fullPath);
+
+ if (fullPath.rfind(".framework") != std::string::npos) {
+ static cmsys::RegularExpression splitFramework(
+ "^(.*)/(.*).framework/(.*)$");
+ if (splitFramework.find(fullPath) &&
+ (std::string::npos !=
+ splitFramework.match(3).find(splitFramework.match(2)))) {
+ dir = splitFramework.match(1);
+ }
+ }
+
+ if (this->ImplicitDirectories.find(dir) !=
+ this->ImplicitDirectories.end()) {
+ this->ImplicitDirEntries.push_back(
+ new cmOrderDirectoriesConstraintSOName(this, fullPath, soname));
+ return;
+ }
+ }
+
+ // Construct the runtime information entry for this library.
+ this->ConstraintEntries.push_back(
+ new cmOrderDirectoriesConstraintSOName(this, fullPath, soname));
+ } else {
+ // This can happen if the same library is linked multiple times.
+ // In that case the runtime information check need be done only
+ // once anyway. For shared libs we could add a check in AddItem
+ // to not repeat them.
+ }
+}
+
+void cmOrderDirectories::AddLinkLibrary(std::string const& fullPath)
+{
+ // Link extension info is required for library constraints.
+ assert(!this->LinkExtensions.empty());
+
+ // Add the link library at most once.
+ if (this->EmmittedConstraintLibrary.insert(fullPath).second) {
+ // Implicit link directories need special handling.
+ if (!this->ImplicitDirectories.empty()) {
+ std::string dir = cmSystemTools::GetFilenamePath(fullPath);
+ if (this->ImplicitDirectories.find(dir) !=
+ this->ImplicitDirectories.end()) {
+ this->ImplicitDirEntries.push_back(
+ new cmOrderDirectoriesConstraintLibrary(this, fullPath));
+ return;
+ }
+ }
+
+ // Construct the link library entry.
+ this->ConstraintEntries.push_back(
+ new cmOrderDirectoriesConstraintLibrary(this, fullPath));
+ }
+}
+
+void cmOrderDirectories::AddUserDirectories(
+ std::vector<std::string> const& extra)
+{
+ this->UserDirectories.insert(this->UserDirectories.end(), extra.begin(),
+ extra.end());
+}
+
+void cmOrderDirectories::AddLanguageDirectories(
+ std::vector<std::string> const& dirs)
+{
+ this->LanguageDirectories.insert(this->LanguageDirectories.end(),
+ dirs.begin(), dirs.end());
+}
+
+void cmOrderDirectories::SetImplicitDirectories(
+ std::set<std::string> const& implicitDirs)
+{
+ this->ImplicitDirectories = implicitDirs;
+}
+
+void cmOrderDirectories::SetLinkExtensionInfo(
+ std::vector<std::string> const& linkExtensions,
+ std::string const& removeExtRegex)
+{
+ this->LinkExtensions = linkExtensions;
+ this->RemoveLibraryExtension.compile(removeExtRegex.c_str());
+}
+
+void cmOrderDirectories::CollectOriginalDirectories()
+{
+ // Add user directories specified for inclusion. These should be
+ // indexed first so their original order is preserved as much as
+ // possible subject to the constraints.
+ this->AddOriginalDirectories(this->UserDirectories);
+
+ // Add directories containing constraints.
+ for (unsigned int i = 0; i < this->ConstraintEntries.size(); ++i) {
+ this->ConstraintEntries[i]->AddDirectory();
+ }
+
+ // Add language runtime directories last.
+ this->AddOriginalDirectories(this->LanguageDirectories);
+}
+
+int cmOrderDirectories::AddOriginalDirectory(std::string const& dir)
+{
+ // Add the runtime directory with a unique index.
+ std::map<std::string, int>::iterator i = this->DirectoryIndex.find(dir);
+ if (i == this->DirectoryIndex.end()) {
+ std::map<std::string, int>::value_type entry(
+ dir, static_cast<int>(this->OriginalDirectories.size()));
+ i = this->DirectoryIndex.insert(entry).first;
+ this->OriginalDirectories.push_back(dir);
+ }
+
+ return i->second;
+}
+
+void cmOrderDirectories::AddOriginalDirectories(
+ std::vector<std::string> const& dirs)
+{
+ for (std::vector<std::string>::const_iterator di = dirs.begin();
+ di != dirs.end(); ++di) {
+ // We never explicitly specify implicit link directories.
+ if (this->ImplicitDirectories.find(*di) !=
+ this->ImplicitDirectories.end()) {
+ continue;
+ }
+
+ // Skip the empty string.
+ if (di->empty()) {
+ continue;
+ }
+
+ // Add this directory.
+ this->AddOriginalDirectory(*di);
+ }
+}
+
+struct cmOrderDirectoriesCompare
+{
+ typedef std::pair<int, int> ConflictPair;
+
+ // The conflict pair is unique based on just the directory
+ // (first). The second element is only used for displaying
+ // information about why the entry is present.
+ bool operator()(ConflictPair const& l, ConflictPair const& r)
+ {
+ return l.first == r.first;
+ }
+};
+
+void cmOrderDirectories::FindConflicts()
+{
+ // Allocate the conflict graph.
+ this->ConflictGraph.resize(this->OriginalDirectories.size());
+ this->DirectoryVisited.resize(this->OriginalDirectories.size(), 0);
+
+ // Find directories conflicting with each entry.
+ for (unsigned int i = 0; i < this->ConstraintEntries.size(); ++i) {
+ this->ConstraintEntries[i]->FindConflicts(i);
+ }
+
+ // Clean up the conflict graph representation.
+ for (std::vector<ConflictList>::iterator i = this->ConflictGraph.begin();
+ i != this->ConflictGraph.end(); ++i) {
+ // Sort the outgoing edges for each graph node so that the
+ // original order will be preserved as much as possible.
+ std::sort(i->begin(), i->end());
+
+ // Make the edge list unique so cycle detection will be reliable.
+ ConflictList::iterator last =
+ std::unique(i->begin(), i->end(), cmOrderDirectoriesCompare());
+ i->erase(last, i->end());
+ }
+
+ // Check items in implicit link directories.
+ this->FindImplicitConflicts();
+}
+
+void cmOrderDirectories::FindImplicitConflicts()
+{
+ // Check for items in implicit link directories that have conflicts
+ // in the explicit directories.
+ std::ostringstream conflicts;
+ for (unsigned int i = 0; i < this->ImplicitDirEntries.size(); ++i) {
+ this->ImplicitDirEntries[i]->FindImplicitConflicts(conflicts);
+ }
+
+ // Skip warning if there were no conflicts.
+ std::string text = conflicts.str();
+ if (text.empty()) {
+ return;
+ }
+
+ // Warn about the conflicts.
+ std::ostringstream w;
+ w << "Cannot generate a safe " << this->Purpose << " for target "
+ << this->Target->GetName()
+ << " because files in some directories may conflict with "
+ << " libraries in implicit directories:\n"
+ << text << "Some of these libraries may not be found correctly.";
+ this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
+ cmake::WARNING, w.str(), this->Target->GetBacktrace());
+}
+
+void cmOrderDirectories::OrderDirectories()
+{
+ // Allow a cycle to be diagnosed once.
+ this->CycleDiagnosed = false;
+ this->WalkId = 0;
+
+ // Iterate through the directories in the original order.
+ for (unsigned int i = 0; i < this->OriginalDirectories.size(); ++i) {
+ // Start a new DFS from this node.
+ ++this->WalkId;
+ this->VisitDirectory(i);
+ }
+}
+
+void cmOrderDirectories::VisitDirectory(unsigned int i)
+{
+ // Skip nodes already visited.
+ if (this->DirectoryVisited[i]) {
+ if (this->DirectoryVisited[i] == this->WalkId) {
+ // We have reached a node previously visited on this DFS.
+ // There is a cycle.
+ this->DiagnoseCycle();
+ }
+ return;
+ }
+
+ // We are now visiting this node so mark it.
+ this->DirectoryVisited[i] = this->WalkId;
+
+ // Visit the neighbors of the node first.
+ ConflictList const& clist = this->ConflictGraph[i];
+ for (ConflictList::const_iterator j = clist.begin(); j != clist.end(); ++j) {
+ this->VisitDirectory(j->first);
+ }
+
+ // Now that all directories required to come before this one have
+ // been emmitted, emit this directory.
+ this->OrderedDirectories.push_back(this->OriginalDirectories[i]);
+}
+
+void cmOrderDirectories::DiagnoseCycle()
+{
+ // Report the cycle at most once.
+ if (this->CycleDiagnosed) {
+ return;
+ }
+ this->CycleDiagnosed = true;
+
+ // Construct the message.
+ std::ostringstream e;
+ e << "Cannot generate a safe " << this->Purpose << " for target "
+ << this->Target->GetName()
+ << " because there is a cycle in the constraint graph:\n";
+
+ // Display the conflict graph.
+ for (unsigned int i = 0; i < this->ConflictGraph.size(); ++i) {
+ ConflictList const& clist = this->ConflictGraph[i];
+ e << " dir " << i << " is [" << this->OriginalDirectories[i] << "]\n";
+ for (ConflictList::const_iterator j = clist.begin(); j != clist.end();
+ ++j) {
+ e << " dir " << j->first << " must precede it due to ";
+ this->ConstraintEntries[j->second]->Report(e);
+ e << "\n";
+ }
+ }
+ e << "Some of these libraries may not be found correctly.";
+ this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
+ cmake::WARNING, e.str(), this->Target->GetBacktrace());
+}
+
+bool cmOrderDirectories::IsSameDirectory(std::string const& l,
+ std::string const& r)
+{
+ return this->GetRealPath(l) == this->GetRealPath(r);
+}
+
+std::string const& cmOrderDirectories::GetRealPath(std::string const& dir)
+{
+ std::map<std::string, std::string>::iterator i =
+ this->RealPaths.lower_bound(dir);
+ if (i == this->RealPaths.end() ||
+ this->RealPaths.key_comp()(dir, i->first)) {
+ typedef std::map<std::string, std::string>::value_type value_type;
+ i = this->RealPaths.insert(
+ i, value_type(dir, cmSystemTools::GetRealPath(dir)));
+ }
+ return i->second;
+}
diff --git a/Source/cmOrderDirectories.h b/Source/cmOrderDirectories.h
new file mode 100644
index 0000000..38e197c
--- /dev/null
+++ b/Source/cmOrderDirectories.h
@@ -0,0 +1,97 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmOrderDirectories_h
+#define cmOrderDirectories_h
+
+#include "cmStandardIncludes.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+class cmGlobalGenerator;
+class cmOrderDirectoriesConstraint;
+class cmOrderDirectoriesConstraintLibrary;
+class cmGeneratorTarget;
+
+/** \class cmOrderDirectories
+ * \brief Compute a safe runtime path order for a set of shared libraries.
+ */
+class cmOrderDirectories
+{
+public:
+ cmOrderDirectories(cmGlobalGenerator* gg, cmGeneratorTarget const* target,
+ const char* purpose);
+ ~cmOrderDirectories();
+ void AddRuntimeLibrary(std::string const& fullPath,
+ const char* soname = CM_NULLPTR);
+ void AddLinkLibrary(std::string const& fullPath);
+ void AddUserDirectories(std::vector<std::string> const& extra);
+ void AddLanguageDirectories(std::vector<std::string> const& dirs);
+ void SetImplicitDirectories(std::set<std::string> const& implicitDirs);
+ void SetLinkExtensionInfo(std::vector<std::string> const& linkExtensions,
+ std::string const& removeExtRegex);
+
+ std::vector<std::string> const& GetOrderedDirectories();
+
+private:
+ cmGlobalGenerator* GlobalGenerator;
+ cmGeneratorTarget const* Target;
+ std::string Purpose;
+
+ std::vector<std::string> OrderedDirectories;
+
+ std::vector<cmOrderDirectoriesConstraint*> ConstraintEntries;
+ std::vector<cmOrderDirectoriesConstraint*> ImplicitDirEntries;
+ std::vector<std::string> UserDirectories;
+ std::vector<std::string> LanguageDirectories;
+ cmsys::RegularExpression RemoveLibraryExtension;
+ std::vector<std::string> LinkExtensions;
+ std::set<std::string> ImplicitDirectories;
+ std::set<std::string> EmmittedConstraintSOName;
+ std::set<std::string> EmmittedConstraintLibrary;
+ std::vector<std::string> OriginalDirectories;
+ std::map<std::string, int> DirectoryIndex;
+ std::vector<int> DirectoryVisited;
+ void CollectOriginalDirectories();
+ int AddOriginalDirectory(std::string const& dir);
+ void AddOriginalDirectories(std::vector<std::string> const& dirs);
+ void FindConflicts();
+ void FindImplicitConflicts();
+ void OrderDirectories();
+ void VisitDirectory(unsigned int i);
+ void DiagnoseCycle();
+ int WalkId;
+ bool CycleDiagnosed;
+ bool Computed;
+
+ // Adjacency-list representation of runtime path ordering graph.
+ // This maps from directory to those that must come *before* it.
+ // Each entry that must come before is a pair. The first element is
+ // the index of the directory that must come first. The second
+ // element is the index of the runtime library that added the
+ // constraint.
+ typedef std::pair<int, int> ConflictPair;
+ struct ConflictList : public std::vector<ConflictPair>
+ {
+ };
+ std::vector<ConflictList> ConflictGraph;
+
+ // Compare directories after resolving symlinks.
+ bool IsSameDirectory(std::string const& l, std::string const& r);
+
+ std::string const& GetRealPath(std::string const& dir);
+ std::map<std::string, std::string> RealPaths;
+
+ friend class cmOrderDirectoriesConstraint;
+ friend class cmOrderDirectoriesConstraintLibrary;
+};
+
+#endif
diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx
new file mode 100644
index 0000000..411184c
--- /dev/null
+++ b/Source/cmOutputConverter.cxx
@@ -0,0 +1,726 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmOutputConverter.h"
+
+#include "cmAlgorithms.h"
+#include "cmake.h"
+
+#include <assert.h>
+#include <sstream>
+
+#include <ctype.h> /* isalpha */
+#include <string.h> /* strlen */
+
+cmOutputConverter::cmOutputConverter(cmState::Snapshot snapshot)
+ : StateSnapshot(snapshot)
+ , LinkScriptShell(false)
+{
+ assert(this->StateSnapshot.IsValid());
+}
+
+std::string cmOutputConverter::ConvertToOutputForExisting(
+ const std::string& remote, OutputFormat format) const
+{
+ // If this is a windows shell, the result has a space, and the path
+ // already exists, we can use a short-path to reference it without a
+ // space.
+ if (this->GetState()->UseWindowsShell() &&
+ remote.find(' ') != std::string::npos &&
+ cmSystemTools::FileExists(remote.c_str())) {
+ std::string tmp;
+ if (cmSystemTools::GetShortPath(remote, tmp)) {
+ return this->ConvertToOutputFormat(tmp, format);
+ }
+ }
+
+ // Otherwise, perform standard conversion.
+ return this->ConvertToOutputFormat(remote, format);
+}
+
+std::string cmOutputConverter::ConvertToOutputForExisting(
+ RelativeRoot remote, OutputFormat format) const
+{
+ // The relative root must have a path (i.e. not FULL or NONE)
+ assert(remote != FULL);
+ assert(remote != NONE);
+
+ const char* remotePath = this->GetRelativeRootPath(remote);
+ assert(remotePath != CM_NULLPTR);
+
+ return this->ConvertToOutputForExisting(remotePath, format);
+}
+
+const char* cmOutputConverter::GetRelativeRootPath(RelativeRoot relroot) const
+{
+ switch (relroot) {
+ case HOME:
+ return this->GetState()->GetSourceDirectory();
+ case START:
+ return this->StateSnapshot.GetDirectory().GetCurrentSource();
+ case HOME_OUTPUT:
+ return this->GetState()->GetBinaryDirectory();
+ case START_OUTPUT:
+ return this->StateSnapshot.GetDirectory().GetCurrentBinary();
+ default:
+ break;
+ }
+ return CM_NULLPTR;
+}
+
+std::string cmOutputConverter::Convert(const std::string& source,
+ RelativeRoot relative,
+ OutputFormat output) const
+{
+ // Convert the path to a relative path.
+ std::string result = source;
+
+ switch (relative) {
+ case HOME:
+ result = this->ConvertToRelativePath(
+ this->GetState()->GetSourceDirectoryComponents(), result);
+ break;
+ case START:
+ result = this->ConvertToRelativePath(
+ this->StateSnapshot.GetDirectory().GetCurrentSourceComponents(),
+ result);
+ break;
+ case HOME_OUTPUT:
+ result = this->ConvertToRelativePath(
+ this->GetState()->GetBinaryDirectoryComponents(), result);
+ break;
+ case START_OUTPUT:
+ result = this->ConvertToRelativePath(
+ this->StateSnapshot.GetDirectory().GetCurrentBinaryComponents(),
+ result);
+ break;
+ case FULL:
+ result = cmSystemTools::CollapseFullPath(result);
+ break;
+ case NONE:
+ break;
+ }
+ return this->ConvertToOutputFormat(result, output);
+}
+
+std::string cmOutputConverter::ConvertToOutputFormat(const std::string& source,
+ OutputFormat output) const
+{
+ std::string result = source;
+ // Convert it to an output path.
+ if (output == MAKERULE) {
+ result = cmSystemTools::ConvertToOutputPath(result.c_str());
+ } else if (output == SHELL || output == WATCOMQUOTE) {
+ result = this->ConvertDirectorySeparatorsForShell(source);
+ result = this->EscapeForShell(result, true, false, output == WATCOMQUOTE);
+ } else if (output == RESPONSE) {
+ result = this->EscapeForShell(result, false, false, false);
+ }
+ return result;
+}
+
+std::string cmOutputConverter::ConvertDirectorySeparatorsForShell(
+ const std::string& source) const
+{
+ std::string result = source;
+ // For the MSYS shell convert drive letters to posix paths, so
+ // that c:/some/path becomes /c/some/path. This is needed to
+ // avoid problems with the shell path translation.
+ if (this->GetState()->UseMSYSShell() && !this->LinkScriptShell) {
+ if (result.size() > 2 && result[1] == ':') {
+ result[1] = result[0];
+ result[0] = '/';
+ }
+ }
+ if (this->GetState()->UseWindowsShell()) {
+ std::replace(result.begin(), result.end(), '/', '\\');
+ }
+ return result;
+}
+
+std::string cmOutputConverter::Convert(RelativeRoot remote,
+ const std::string& local,
+ OutputFormat output) const
+{
+ // The relative root must have a path (i.e. not FULL or NONE)
+ assert(remote != FULL);
+ assert(remote != NONE);
+
+ const char* remotePath = this->GetRelativeRootPath(remote);
+ assert(remotePath != CM_NULLPTR);
+
+ if (local.empty()) {
+ return this->ConvertToOutputFormat(remotePath, output);
+ }
+
+ std::vector<std::string> components;
+ cmSystemTools::SplitPath(local, components);
+ std::string result = this->ConvertToRelativePath(components, remotePath);
+ return this->ConvertToOutputFormat(result, output);
+}
+
+static bool cmOutputConverterNotAbove(const char* a, const char* b)
+{
+ return (cmSystemTools::ComparePath(a, b) ||
+ cmSystemTools::IsSubDirectory(a, b));
+}
+
+std::string cmOutputConverter::ConvertToRelativePath(
+ const std::vector<std::string>& local, const std::string& in_remote,
+ bool force) const
+{
+ // The path should never be quoted.
+ assert(in_remote[0] != '\"');
+
+ // The local path should never have a trailing slash.
+ assert(!local.empty() && !(local[local.size() - 1] == ""));
+
+ // If the path is already relative then just return the path.
+ if (!cmSystemTools::FileIsFullPath(in_remote.c_str())) {
+ return in_remote;
+ }
+
+ if (!force) {
+ // Skip conversion if the path and local are not both in the source
+ // or both in the binary tree.
+ std::string local_path = cmSystemTools::JoinPath(local);
+ if (!((cmOutputConverterNotAbove(
+ local_path.c_str(),
+ this->StateSnapshot.GetDirectory().GetRelativePathTopBinary()) &&
+ cmOutputConverterNotAbove(
+ in_remote.c_str(),
+ this->StateSnapshot.GetDirectory().GetRelativePathTopBinary())) ||
+ (cmOutputConverterNotAbove(
+ local_path.c_str(),
+ this->StateSnapshot.GetDirectory().GetRelativePathTopSource()) &&
+ cmOutputConverterNotAbove(in_remote.c_str(),
+ this->StateSnapshot.GetDirectory()
+ .GetRelativePathTopSource())))) {
+ return in_remote;
+ }
+ }
+
+ // Identify the longest shared path component between the remote
+ // path and the local path.
+ std::vector<std::string> remote;
+ cmSystemTools::SplitPath(in_remote, remote);
+ unsigned int common = 0;
+ while (common < remote.size() && common < local.size() &&
+ cmSystemTools::ComparePath(remote[common], local[common])) {
+ ++common;
+ }
+
+ // If no part of the path is in common then return the full path.
+ if (common == 0) {
+ return in_remote;
+ }
+
+ // If the entire path is in common then just return a ".".
+ if (common == remote.size() && common == local.size()) {
+ return ".";
+ }
+
+ // If the entire path is in common except for a trailing slash then
+ // just return a "./".
+ if (common + 1 == remote.size() && remote[common].empty() &&
+ common == local.size()) {
+ return "./";
+ }
+
+ // Construct the relative path.
+ std::string relative;
+
+ // First add enough ../ to get up to the level of the shared portion
+ // of the path. Leave off the trailing slash. Note that the last
+ // component of local will never be empty because local should never
+ // have a trailing slash.
+ for (unsigned int i = common; i < local.size(); ++i) {
+ relative += "..";
+ if (i < local.size() - 1) {
+ relative += "/";
+ }
+ }
+
+ // Now add the portion of the destination path that is not included
+ // in the shared portion of the path. Add a slash the first time
+ // only if there was already something in the path. If there was a
+ // trailing slash in the input then the last iteration of the loop
+ // will add a slash followed by an empty string which will preserve
+ // the trailing slash in the output.
+
+ if (!relative.empty() && !remote.empty()) {
+ relative += "/";
+ }
+ relative += cmJoin(cmMakeRange(remote).advance(common), "/");
+
+ // Finally return the path.
+ return relative;
+}
+
+static bool cmOutputConverterIsShellOperator(const std::string& str)
+{
+ static std::set<std::string> shellOperators;
+ if (shellOperators.empty()) {
+ shellOperators.insert("<");
+ shellOperators.insert(">");
+ shellOperators.insert("<<");
+ shellOperators.insert(">>");
+ shellOperators.insert("|");
+ shellOperators.insert("||");
+ shellOperators.insert("&&");
+ shellOperators.insert("&>");
+ shellOperators.insert("1>");
+ shellOperators.insert("2>");
+ shellOperators.insert("2>&1");
+ shellOperators.insert("1>&2");
+ }
+ return shellOperators.count(str) > 0;
+}
+
+std::string cmOutputConverter::EscapeForShell(const std::string& str,
+ bool makeVars, bool forEcho,
+ bool useWatcomQuote) const
+{
+ // Do not escape shell operators.
+ if (cmOutputConverterIsShellOperator(str)) {
+ return str;
+ }
+
+ // Compute the flags for the target shell environment.
+ int flags = 0;
+ if (this->GetState()->UseWindowsVSIDE()) {
+ flags |= Shell_Flag_VSIDE;
+ } else if (!this->LinkScriptShell) {
+ flags |= Shell_Flag_Make;
+ }
+ if (makeVars) {
+ flags |= Shell_Flag_AllowMakeVariables;
+ }
+ if (forEcho) {
+ flags |= Shell_Flag_EchoWindows;
+ }
+ if (useWatcomQuote) {
+ flags |= Shell_Flag_WatcomQuote;
+ }
+ if (this->GetState()->UseWatcomWMake()) {
+ flags |= Shell_Flag_WatcomWMake;
+ }
+ if (this->GetState()->UseMinGWMake()) {
+ flags |= Shell_Flag_MinGWMake;
+ }
+ if (this->GetState()->UseNMake()) {
+ flags |= Shell_Flag_NMake;
+ }
+
+ return this->GetState()->UseWindowsShell()
+ ? Shell_GetArgumentForWindows(str.c_str(), flags)
+ : Shell_GetArgumentForUnix(str.c_str(), flags);
+}
+
+std::string cmOutputConverter::EscapeForCMake(const std::string& str)
+{
+ // Always double-quote the argument to take care of most escapes.
+ std::string result = "\"";
+ for (const char* c = str.c_str(); *c; ++c) {
+ if (*c == '"') {
+ // Escape the double quote to avoid ending the argument.
+ result += "\\\"";
+ } else if (*c == '$') {
+ // Escape the dollar to avoid expanding variables.
+ result += "\\$";
+ } else if (*c == '\\') {
+ // Escape the backslash to avoid other escapes.
+ result += "\\\\";
+ } else {
+ // Other characters will be parsed correctly.
+ result += *c;
+ }
+ }
+ result += "\"";
+ return result;
+}
+
+std::string cmOutputConverter::EscapeWindowsShellArgument(const char* arg,
+ int shell_flags)
+{
+ return Shell_GetArgumentForWindows(arg, shell_flags);
+}
+
+cmOutputConverter::FortranFormat cmOutputConverter::GetFortranFormat(
+ const char* value)
+{
+ FortranFormat format = FortranFormatNone;
+ if (value && *value) {
+ std::vector<std::string> fmt;
+ cmSystemTools::ExpandListArgument(value, fmt);
+ for (std::vector<std::string>::iterator fi = fmt.begin(); fi != fmt.end();
+ ++fi) {
+ if (*fi == "FIXED") {
+ format = FortranFormatFixed;
+ }
+ if (*fi == "FREE") {
+ format = FortranFormatFree;
+ }
+ }
+ }
+ return format;
+}
+
+void cmOutputConverter::SetLinkScriptShell(bool linkScriptShell)
+{
+ this->LinkScriptShell = linkScriptShell;
+}
+
+cmState* cmOutputConverter::GetState() const
+{
+ return this->StateSnapshot.GetState();
+}
+
+/*
+
+Notes:
+
+Make variable replacements open a can of worms. Sometimes they should
+be quoted and sometimes not. Sometimes their replacement values are
+already quoted.
+
+VS variables cause problems. In order to pass the referenced value
+with spaces the reference must be quoted. If the variable value ends
+in a backslash then it will escape the ending quote! In order to make
+the ending backslash appear we need this:
+
+ "$(InputDir)\"
+
+However if there is not a trailing backslash then this will put a
+quote in the value so we need:
+
+ "$(InputDir)"
+
+Make variable references are platform specific so we should probably
+just NOT quote them and let the listfile author deal with it.
+
+*/
+
+/*
+TODO: For windows echo:
+
+To display a pipe (|) or redirection character (< or >) when using the
+echo command, use a caret character immediately before the pipe or
+redirection character (for example, ^>, ^<, or ^| ). If you need to
+use the caret character itself (^), use two in a row (^^).
+*/
+
+int cmOutputConverter::Shell__CharIsWhitespace(char c)
+{
+ return ((c == ' ') || (c == '\t'));
+}
+
+int cmOutputConverter::Shell__CharNeedsQuotesOnUnix(char c)
+{
+ return ((c == '\'') || (c == '`') || (c == ';') || (c == '#') ||
+ (c == '&') || (c == '$') || (c == '(') || (c == ')') || (c == '~') ||
+ (c == '<') || (c == '>') || (c == '|') || (c == '*') || (c == '^') ||
+ (c == '\\'));
+}
+
+int cmOutputConverter::Shell__CharNeedsQuotesOnWindows(char c)
+{
+ return ((c == '\'') || (c == '#') || (c == '&') || (c == '<') ||
+ (c == '>') || (c == '|') || (c == '^'));
+}
+
+int cmOutputConverter::Shell__CharNeedsQuotes(char c, int isUnix, int flags)
+{
+ /* On Windows the built-in command shell echo never needs quotes. */
+ if (!isUnix && (flags & Shell_Flag_EchoWindows)) {
+ return 0;
+ }
+
+ /* On all platforms quotes are needed to preserve whitespace. */
+ if (Shell__CharIsWhitespace(c)) {
+ return 1;
+ }
+
+ if (isUnix) {
+ /* On UNIX several special characters need quotes to preserve them. */
+ if (Shell__CharNeedsQuotesOnUnix(c)) {
+ return 1;
+ }
+ } else {
+ /* On Windows several special characters need quotes to preserve them. */
+ if (Shell__CharNeedsQuotesOnWindows(c)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int cmOutputConverter::Shell__CharIsMakeVariableName(char c)
+{
+ return c && (c == '_' || isalpha(((int)c)));
+}
+
+const char* cmOutputConverter::Shell__SkipMakeVariables(const char* c)
+{
+ while (*c == '$' && *(c + 1) == '(') {
+ const char* skip = c + 2;
+ while (Shell__CharIsMakeVariableName(*skip)) {
+ ++skip;
+ }
+ if (*skip == ')') {
+ c = skip + 1;
+ } else {
+ break;
+ }
+ }
+ return c;
+}
+
+/*
+Allowing make variable replacements opens a can of worms. Sometimes
+they should be quoted and sometimes not. Sometimes their replacement
+values are already quoted or contain escapes.
+
+Some Visual Studio variables cause problems. In order to pass the
+referenced value with spaces the reference must be quoted. If the
+variable value ends in a backslash then it will escape the ending
+quote! In order to make the ending backslash appear we need this:
+
+ "$(InputDir)\"
+
+However if there is not a trailing backslash then this will put a
+quote in the value so we need:
+
+ "$(InputDir)"
+
+This macro decides whether we quote an argument just because it
+contains a make variable reference. This should be replaced with a
+flag later when we understand applications of this better.
+*/
+#define KWSYS_SYSTEM_SHELL_QUOTE_MAKE_VARIABLES 0
+
+int cmOutputConverter::Shell__ArgumentNeedsQuotes(const char* in, int isUnix,
+ int flags)
+{
+ /* The empty string needs quotes. */
+ if (!*in) {
+ return 1;
+ }
+
+ /* Scan the string for characters that require quoting. */
+ {
+ const char* c;
+ for (c = in; *c; ++c) {
+ /* Look for $(MAKEVAR) syntax if requested. */
+ if (flags & Shell_Flag_AllowMakeVariables) {
+#if KWSYS_SYSTEM_SHELL_QUOTE_MAKE_VARIABLES
+ const char* skip = Shell__SkipMakeVariables(c);
+ if (skip != c) {
+ /* We need to quote make variable references to preserve the
+ string with contents substituted in its place. */
+ return 1;
+ }
+#else
+ /* Skip over the make variable references if any are present. */
+ c = Shell__SkipMakeVariables(c);
+
+ /* Stop if we have reached the end of the string. */
+ if (!*c) {
+ break;
+ }
+#endif
+ }
+
+ /* Check whether this character needs quotes. */
+ if (Shell__CharNeedsQuotes(*c, isUnix, flags)) {
+ return 1;
+ }
+ }
+ }
+
+ /* On Windows some single character arguments need quotes. */
+ if (!isUnix && *in && !*(in + 1)) {
+ char c = *in;
+ if ((c == '?') || (c == '&') || (c == '^') || (c == '|') || (c == '#')) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+std::string cmOutputConverter::Shell__GetArgument(const char* in, int isUnix,
+ int flags)
+{
+ std::ostringstream out;
+
+ /* String iterator. */
+ const char* c;
+
+ /* Keep track of how many backslashes have been encountered in a row. */
+ int windows_backslashes = 0;
+
+ /* Whether the argument must be quoted. */
+ int needQuotes = Shell__ArgumentNeedsQuotes(in, isUnix, flags);
+ if (needQuotes) {
+ /* Add the opening quote for this argument. */
+ if (flags & Shell_Flag_WatcomQuote) {
+ if (isUnix) {
+ out << '"';
+ }
+ out << '\'';
+ } else {
+ out << '"';
+ }
+ }
+
+ /* Scan the string for characters that require escaping or quoting. */
+ for (c = in; *c; ++c) {
+ /* Look for $(MAKEVAR) syntax if requested. */
+ if (flags & Shell_Flag_AllowMakeVariables) {
+ const char* skip = Shell__SkipMakeVariables(c);
+ if (skip != c) {
+ /* Copy to the end of the make variable references. */
+ while (c != skip) {
+ out << *c++;
+ }
+
+ /* The make variable reference eliminates any escaping needed
+ for preceding backslashes. */
+ windows_backslashes = 0;
+
+ /* Stop if we have reached the end of the string. */
+ if (!*c) {
+ break;
+ }
+ }
+ }
+
+ /* Check whether this character needs escaping for the shell. */
+ if (isUnix) {
+ /* On Unix a few special characters need escaping even inside a
+ quoted argument. */
+ if (*c == '\\' || *c == '"' || *c == '`' || *c == '$') {
+ /* This character needs a backslash to escape it. */
+ out << '\\';
+ }
+ } else if (flags & Shell_Flag_EchoWindows) {
+ /* On Windows the built-in command shell echo never needs escaping. */
+ } else {
+ /* On Windows only backslashes and double-quotes need escaping. */
+ if (*c == '\\') {
+ /* Found a backslash. It may need to be escaped later. */
+ ++windows_backslashes;
+ } else if (*c == '"') {
+ /* Found a double-quote. Escape all immediately preceding
+ backslashes. */
+ while (windows_backslashes > 0) {
+ --windows_backslashes;
+ out << '\\';
+ }
+
+ /* Add the backslash to escape the double-quote. */
+ out << '\\';
+ } else {
+ /* We encountered a normal character. This eliminates any
+ escaping needed for preceding backslashes. */
+ windows_backslashes = 0;
+ }
+ }
+
+ /* Check whether this character needs escaping for a make tool. */
+ if (*c == '$') {
+ if (flags & Shell_Flag_Make) {
+ /* In Makefiles a dollar is written $$. The make tool will
+ replace it with just $ before passing it to the shell. */
+ out << "$$";
+ } else if (flags & Shell_Flag_VSIDE) {
+ /* In a VS IDE a dollar is written "$". If this is written in
+ an un-quoted argument it starts a quoted segment, inserts
+ the $ and ends the segment. If it is written in a quoted
+ argument it ends quoting, inserts the $ and restarts
+ quoting. Either way the $ is isolated from surrounding
+ text to avoid looking like a variable reference. */
+ out << "\"$\"";
+ } else {
+ /* Otherwise a dollar is written just $. */
+ out << '$';
+ }
+ } else if (*c == '#') {
+ if ((flags & Shell_Flag_Make) && (flags & Shell_Flag_WatcomWMake)) {
+ /* In Watcom WMake makefiles a pound is written $#. The make
+ tool will replace it with just # before passing it to the
+ shell. */
+ out << "$#";
+ } else {
+ /* Otherwise a pound is written just #. */
+ out << '#';
+ }
+ } else if (*c == '%') {
+ if ((flags & Shell_Flag_VSIDE) ||
+ ((flags & Shell_Flag_Make) &&
+ ((flags & Shell_Flag_MinGWMake) || (flags & Shell_Flag_NMake)))) {
+ /* In the VS IDE, NMake, or MinGW make a percent is written %%. */
+ out << "%%";
+ } else {
+ /* Otherwise a percent is written just %. */
+ out << '%';
+ }
+ } else if (*c == ';') {
+ if (flags & Shell_Flag_VSIDE) {
+ /* In a VS IDE a semicolon is written ";". If this is written
+ in an un-quoted argument it starts a quoted segment,
+ inserts the ; and ends the segment. If it is written in a
+ quoted argument it ends quoting, inserts the ; and restarts
+ quoting. Either way the ; is isolated. */
+ out << "\";\"";
+ } else {
+ /* Otherwise a semicolon is written just ;. */
+ out << ';';
+ }
+ } else {
+ /* Store this character. */
+ out << *c;
+ }
+ }
+
+ if (needQuotes) {
+ /* Add enough backslashes to escape any trailing ones. */
+ while (windows_backslashes > 0) {
+ --windows_backslashes;
+ out << '\\';
+ }
+
+ /* Add the closing quote for this argument. */
+ if (flags & Shell_Flag_WatcomQuote) {
+ out << '\'';
+ if (isUnix) {
+ out << '"';
+ }
+ } else {
+ out << '"';
+ }
+ }
+
+ return out.str();
+}
+
+std::string cmOutputConverter::Shell_GetArgumentForWindows(const char* in,
+ int flags)
+{
+ return Shell__GetArgument(in, 0, flags);
+}
+
+std::string cmOutputConverter::Shell_GetArgumentForUnix(const char* in,
+ int flags)
+{
+ return Shell__GetArgument(in, 1, flags);
+}
diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h
new file mode 100644
index 0000000..23f2e62
--- /dev/null
+++ b/Source/cmOutputConverter.h
@@ -0,0 +1,177 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmOutputConverter_h
+#define cmOutputConverter_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmGlobalGenerator.h"
+#include "cmState.h"
+
+class cmOutputConverter
+{
+public:
+ cmOutputConverter(cmState::Snapshot snapshot);
+
+ /**
+ * Convert something to something else. This is a centralized conversion
+ * routine used by the generators to handle relative paths and the like.
+ * The flags determine what is actually done.
+ *
+ * relative: treat the argument as a directory and convert it to make it
+ * relative or full or unchanged. If relative (HOME, START etc) then that
+ * specifies what it should be relative to.
+ *
+ * output: make the result suitable for output to a...
+ *
+ * optional: should any relative path operation be controlled by the rel
+ * path setting
+ */
+ enum RelativeRoot
+ {
+ NONE,
+ FULL,
+ HOME,
+ START,
+ HOME_OUTPUT,
+ START_OUTPUT
+ };
+ enum OutputFormat
+ {
+ UNCHANGED,
+ MAKERULE,
+ SHELL,
+ WATCOMQUOTE,
+ RESPONSE
+ };
+ std::string ConvertToOutputFormat(const std::string& source,
+ OutputFormat output) const;
+ std::string Convert(const std::string& remote, RelativeRoot local,
+ OutputFormat output = UNCHANGED) const;
+ std::string Convert(RelativeRoot remote, const std::string& local,
+ OutputFormat output = UNCHANGED) const;
+ std::string ConvertDirectorySeparatorsForShell(
+ const std::string& source) const;
+
+ /**
+ * Get path for the specified relative root.
+ */
+ const char* GetRelativeRootPath(RelativeRoot relroot) const;
+
+ ///! for existing files convert to output path and short path if spaces
+ std::string ConvertToOutputForExisting(const std::string& remote,
+ OutputFormat format = SHELL) const;
+
+ /** For existing path identified by RelativeRoot convert to output
+ path and short path if spaces. */
+ std::string ConvertToOutputForExisting(RelativeRoot remote,
+ OutputFormat format = SHELL) const;
+
+ void SetLinkScriptShell(bool linkScriptShell);
+
+ /**
+ * Flags to pass to Shell_GetArgumentForWindows or
+ * Shell_GetArgumentForUnix. These modify the generated
+ * quoting and escape sequences to work under alternative
+ * environments.
+ */
+ enum Shell_Flag_e
+ {
+ /** The target shell is in a makefile. */
+ Shell_Flag_Make = (1 << 0),
+
+ /** The target shell is in a VS project file. Do not use with
+ Shell_Flag_Make. */
+ Shell_Flag_VSIDE = (1 << 1),
+
+ /** In a windows shell the argument is being passed to "echo". */
+ Shell_Flag_EchoWindows = (1 << 2),
+
+ /** The target shell is in a Watcom WMake makefile. */
+ Shell_Flag_WatcomWMake = (1 << 3),
+
+ /** The target shell is in a MinGW Make makefile. */
+ Shell_Flag_MinGWMake = (1 << 4),
+
+ /** The target shell is in a NMake makefile. */
+ Shell_Flag_NMake = (1 << 5),
+
+ /** Make variable reference syntax $(MAKEVAR) should not be escaped
+ to allow a build tool to replace it. Replacement values
+ containing spaces, quotes, backslashes, or other
+ non-alphanumeric characters that have significance to some makes
+ or shells produce undefined behavior. */
+ Shell_Flag_AllowMakeVariables = (1 << 6),
+
+ /** The target shell quoting uses extra single Quotes for Watcom tools. */
+ Shell_Flag_WatcomQuote = (1 << 7)
+ };
+
+ /**
+ * Transform the given command line argument for use in a Windows or
+ * Unix shell. Returns a pointer to the end of the command line
+ * argument in the provided output buffer. Flags may be passed to
+ * modify the generated quoting and escape sequences to work under
+ * alternative environments.
+ */
+ static std::string Shell_GetArgumentForWindows(const char* in, int flags);
+ static std::string Shell_GetArgumentForUnix(const char* in, int flags);
+
+ std::string EscapeForShell(const std::string& str, bool makeVars = false,
+ bool forEcho = false,
+ bool useWatcomQuote = false) const;
+
+ static std::string EscapeForCMake(const std::string& str);
+
+ /** Compute an escaped version of the given argument for use in a
+ windows shell. */
+ static std::string EscapeWindowsShellArgument(const char* arg,
+ int shell_flags);
+
+ enum FortranFormat
+ {
+ FortranFormatNone,
+ FortranFormatFixed,
+ FortranFormatFree
+ };
+ static FortranFormat GetFortranFormat(const char* value);
+
+ /**
+ * Convert the given remote path to a relative path with respect to
+ * the given local path. The local path must be given in component
+ * form (see SystemTools::SplitPath) without a trailing slash. The
+ * remote path must use forward slashes and not already be escaped
+ * or quoted.
+ */
+ std::string ConvertToRelativePath(const std::vector<std::string>& local,
+ const std::string& in_remote,
+ bool force = false) const;
+
+private:
+ cmState* GetState() const;
+
+ static int Shell__CharIsWhitespace(char c);
+ static int Shell__CharNeedsQuotesOnUnix(char c);
+ static int Shell__CharNeedsQuotesOnWindows(char c);
+ static int Shell__CharNeedsQuotes(char c, int isUnix, int flags);
+ static int Shell__CharIsMakeVariableName(char c);
+ static const char* Shell__SkipMakeVariables(const char* c);
+ static int Shell__ArgumentNeedsQuotes(const char* in, int isUnix, int flags);
+ static std::string Shell__GetArgument(const char* in, int isUnix, int flags);
+
+private:
+ cmState::Snapshot StateSnapshot;
+
+ bool LinkScriptShell;
+};
+
+#endif
diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx
new file mode 100644
index 0000000..ef636e7
--- /dev/null
+++ b/Source/cmOutputRequiredFilesCommand.cxx
@@ -0,0 +1,557 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmOutputRequiredFilesCommand.h"
+
+#include "cmAlgorithms.h"
+#include <cmsys/FStream.hxx>
+
+/** \class cmDependInformation
+ * \brief Store dependency information for a single source file.
+ *
+ * This structure stores the depend information for a single source file.
+ */
+class cmDependInformation
+{
+public:
+ /**
+ * Construct with dependency generation marked not done; instance
+ * not placed in cmMakefile's list.
+ */
+ cmDependInformation()
+ : DependDone(false)
+ , SourceFile(CM_NULLPTR)
+ {
+ }
+
+ /**
+ * The set of files on which this one depends.
+ */
+ typedef std::set<cmDependInformation*> DependencySetType;
+ DependencySetType DependencySet;
+
+ /**
+ * This flag indicates whether dependency checking has been
+ * performed for this file.
+ */
+ bool DependDone;
+
+ /**
+ * If this object corresponds to a cmSourceFile instance, this points
+ * to it.
+ */
+ const cmSourceFile* SourceFile;
+
+ /**
+ * Full path to this file.
+ */
+ std::string FullPath;
+
+ /**
+ * Full path not including file name.
+ */
+ std::string PathOnly;
+
+ /**
+ * Name used to #include this file.
+ */
+ std::string IncludeName;
+
+ /**
+ * This method adds the dependencies of another file to this one.
+ */
+ void AddDependencies(cmDependInformation* info)
+ {
+ if (this != info) {
+ this->DependencySet.insert(info);
+ }
+ }
+};
+
+class cmLBDepend
+{
+public:
+ /**
+ * Construct the object with verbose turned off.
+ */
+ cmLBDepend()
+ {
+ this->Verbose = false;
+ this->IncludeFileRegularExpression.compile("^.*$");
+ this->ComplainFileRegularExpression.compile("^$");
+ }
+
+ /**
+ * Destructor.
+ */
+ ~cmLBDepend() { cmDeleteAll(this->DependInformationMap); }
+
+ /**
+ * Set the makefile that is used as a source of classes.
+ */
+ void SetMakefile(cmMakefile* makefile)
+ {
+ this->Makefile = makefile;
+
+ // Now extract the include file regular expression from the makefile.
+ this->IncludeFileRegularExpression.compile(
+ this->Makefile->GetIncludeRegularExpression());
+ this->ComplainFileRegularExpression.compile(
+ this->Makefile->GetComplainRegularExpression());
+
+ // Now extract any include paths from the targets
+ std::set<std::string> uniqueIncludes;
+ std::vector<std::string> orderedAndUniqueIncludes;
+ cmTargets& targets = this->Makefile->GetTargets();
+ for (cmTargets::iterator l = targets.begin(); l != targets.end(); ++l) {
+ const char* incDirProp = l->second.GetProperty("INCLUDE_DIRECTORIES");
+ if (!incDirProp) {
+ continue;
+ }
+
+ std::string incDirs = cmGeneratorExpression::Preprocess(
+ incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions);
+
+ std::vector<std::string> includes;
+ cmSystemTools::ExpandListArgument(incDirs, includes);
+
+ for (std::vector<std::string>::const_iterator j = includes.begin();
+ j != includes.end(); ++j) {
+ std::string path = *j;
+ this->Makefile->ExpandVariablesInString(path);
+ if (uniqueIncludes.insert(path).second) {
+ orderedAndUniqueIncludes.push_back(path);
+ }
+ }
+ }
+
+ for (std::vector<std::string>::const_iterator it =
+ orderedAndUniqueIncludes.begin();
+ it != orderedAndUniqueIncludes.end(); ++it) {
+ this->AddSearchPath(*it);
+ }
+ }
+
+ /**
+ * Add a directory to the search path for include files.
+ */
+ void AddSearchPath(const std::string& path)
+ {
+ this->IncludeDirectories.push_back(path);
+ }
+
+ /**
+ * Generate dependencies for the file given. Returns a pointer to
+ * the cmDependInformation object for the file.
+ */
+ const cmDependInformation* FindDependencies(const char* file)
+ {
+ cmDependInformation* info = this->GetDependInformation(file, CM_NULLPTR);
+ this->GenerateDependInformation(info);
+ return info;
+ }
+
+protected:
+ /**
+ * Compute the depend information for this class.
+ */
+
+ void DependWalk(cmDependInformation* info)
+ {
+ cmsys::ifstream fin(info->FullPath.c_str());
+ if (!fin) {
+ cmSystemTools::Error("error can not open ", info->FullPath.c_str());
+ return;
+ }
+
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (cmHasLiteralPrefix(line.c_str(), "#include")) {
+ // if it is an include line then create a string class
+ std::string currentline = line;
+ size_t qstart = currentline.find('\"', 8);
+ size_t qend;
+ // if a quote is not found look for a <
+ if (qstart == std::string::npos) {
+ qstart = currentline.find('<', 8);
+ // if a < is not found then move on
+ if (qstart == std::string::npos) {
+ cmSystemTools::Error("unknown include directive ",
+ currentline.c_str());
+ continue;
+ } else {
+ qend = currentline.find('>', qstart + 1);
+ }
+ } else {
+ qend = currentline.find('\"', qstart + 1);
+ }
+ // extract the file being included
+ std::string includeFile =
+ currentline.substr(qstart + 1, qend - qstart - 1);
+ // see if the include matches the regular expression
+ if (!this->IncludeFileRegularExpression.find(includeFile)) {
+ if (this->Verbose) {
+ std::string message = "Skipping ";
+ message += includeFile;
+ message += " for file ";
+ message += info->FullPath.c_str();
+ cmSystemTools::Error(message.c_str(), CM_NULLPTR);
+ }
+ continue;
+ }
+
+ // Add this file and all its dependencies.
+ this->AddDependency(info, includeFile.c_str());
+ /// add the cxx file if it exists
+ std::string cxxFile = includeFile;
+ std::string::size_type pos = cxxFile.rfind('.');
+ if (pos != std::string::npos) {
+ std::string root = cxxFile.substr(0, pos);
+ cxxFile = root + ".cxx";
+ bool found = false;
+ // try jumping to .cxx .cpp and .c in order
+ if (cmSystemTools::FileExists(cxxFile.c_str())) {
+ found = true;
+ }
+ for (std::vector<std::string>::iterator i =
+ this->IncludeDirectories.begin();
+ i != this->IncludeDirectories.end(); ++i) {
+ std::string path = *i;
+ path = path + "/";
+ path = path + cxxFile;
+ if (cmSystemTools::FileExists(path.c_str())) {
+ found = true;
+ }
+ }
+ if (!found) {
+ cxxFile = root + ".cpp";
+ if (cmSystemTools::FileExists(cxxFile.c_str())) {
+ found = true;
+ }
+ for (std::vector<std::string>::iterator i =
+ this->IncludeDirectories.begin();
+ i != this->IncludeDirectories.end(); ++i) {
+ std::string path = *i;
+ path = path + "/";
+ path = path + cxxFile;
+ if (cmSystemTools::FileExists(path.c_str())) {
+ found = true;
+ }
+ }
+ }
+ if (!found) {
+ cxxFile = root + ".c";
+ if (cmSystemTools::FileExists(cxxFile.c_str())) {
+ found = true;
+ }
+ for (std::vector<std::string>::iterator i =
+ this->IncludeDirectories.begin();
+ i != this->IncludeDirectories.end(); ++i) {
+ std::string path = *i;
+ path = path + "/";
+ path = path + cxxFile;
+ if (cmSystemTools::FileExists(path.c_str())) {
+ found = true;
+ }
+ }
+ }
+ if (!found) {
+ cxxFile = root + ".txx";
+ if (cmSystemTools::FileExists(cxxFile.c_str())) {
+ found = true;
+ }
+ for (std::vector<std::string>::iterator i =
+ this->IncludeDirectories.begin();
+ i != this->IncludeDirectories.end(); ++i) {
+ std::string path = *i;
+ path = path + "/";
+ path = path + cxxFile;
+ if (cmSystemTools::FileExists(path.c_str())) {
+ found = true;
+ }
+ }
+ }
+ if (found) {
+ this->AddDependency(info, cxxFile.c_str());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Add a dependency. Possibly walk it for more dependencies.
+ */
+ void AddDependency(cmDependInformation* info, const char* file)
+ {
+ cmDependInformation* dependInfo =
+ this->GetDependInformation(file, info->PathOnly.c_str());
+ this->GenerateDependInformation(dependInfo);
+ info->AddDependencies(dependInfo);
+ }
+
+ /**
+ * Fill in the given object with dependency information. If the
+ * information is already complete, nothing is done.
+ */
+ void GenerateDependInformation(cmDependInformation* info)
+ {
+ // If dependencies are already done, stop now.
+ if (info->DependDone) {
+ return;
+ } else {
+ // Make sure we don't visit the same file more than once.
+ info->DependDone = true;
+ }
+ const char* path = info->FullPath.c_str();
+ if (!path) {
+ cmSystemTools::Error(
+ "Attempt to find dependencies for file without path!");
+ return;
+ }
+
+ bool found = false;
+
+ // If the file exists, use it to find dependency information.
+ if (cmSystemTools::FileExists(path, true)) {
+ // Use the real file to find its dependencies.
+ this->DependWalk(info);
+ found = true;
+ }
+
+ // See if the cmSourceFile for it has any files specified as
+ // dependency hints.
+ if (info->SourceFile != CM_NULLPTR) {
+
+ // Get the cmSourceFile corresponding to this.
+ const cmSourceFile& cFile = *(info->SourceFile);
+ // See if there are any hints for finding dependencies for the missing
+ // file.
+ if (!cFile.GetDepends().empty()) {
+ // Dependency hints have been given. Use them to begin the
+ // recursion.
+ for (std::vector<std::string>::const_iterator file =
+ cFile.GetDepends().begin();
+ file != cFile.GetDepends().end(); ++file) {
+ this->AddDependency(info, file->c_str());
+ }
+
+ // Found dependency information. We are done.
+ found = true;
+ }
+ }
+
+ if (!found) {
+ // Try to find the file amongst the sources
+ cmSourceFile* srcFile = this->Makefile->GetSource(
+ cmSystemTools::GetFilenameWithoutExtension(path));
+ if (srcFile) {
+ if (srcFile->GetFullPath() == path) {
+ found = true;
+ } else {
+ // try to guess which include path to use
+ for (std::vector<std::string>::iterator t =
+ this->IncludeDirectories.begin();
+ t != this->IncludeDirectories.end(); ++t) {
+ std::string incpath = *t;
+ if (!incpath.empty() && incpath[incpath.size() - 1] != '/') {
+ incpath = incpath + "/";
+ }
+ incpath = incpath + path;
+ if (srcFile->GetFullPath() == incpath) {
+ // set the path to the guessed path
+ info->FullPath = incpath;
+ found = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ // Couldn't find any dependency information.
+ if (this->ComplainFileRegularExpression.find(
+ info->IncludeName.c_str())) {
+ 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.
+ info->FullPath = "";
+ }
+ }
+ }
+
+ /**
+ * Get an instance of cmDependInformation corresponding to the given file
+ * name.
+ */
+ cmDependInformation* GetDependInformation(const char* file,
+ const char* extraPath)
+ {
+ // Get the full path for the file so that lookup is unambiguous.
+ std::string fullPath = this->FullPath(file, extraPath);
+
+ // Try to find the file's instance of cmDependInformation.
+ DependInformationMapType::const_iterator result =
+ this->DependInformationMap.find(fullPath);
+ if (result != this->DependInformationMap.end()) {
+ // Found an instance, return it.
+ return result->second;
+ } else {
+ // Didn't find an instance. Create a new one and save it.
+ cmDependInformation* info = new cmDependInformation;
+ info->FullPath = fullPath;
+ info->PathOnly = cmSystemTools::GetFilenamePath(fullPath);
+ info->IncludeName = file;
+ this->DependInformationMap[fullPath] = info;
+ return info;
+ }
+ }
+
+ /**
+ * Find the full path name for the given file name.
+ * This uses the include directories.
+ * TODO: Cache path conversions to reduce FileExists calls.
+ */
+ std::string FullPath(const char* fname, const char* extraPath)
+ {
+ DirectoryToFileToPathMapType::iterator m;
+ if (extraPath) {
+ m = this->DirectoryToFileToPathMap.find(extraPath);
+ } else {
+ m = this->DirectoryToFileToPathMap.find("");
+ }
+
+ if (m != this->DirectoryToFileToPathMap.end()) {
+ FileToPathMapType& map = m->second;
+ FileToPathMapType::iterator p = map.find(fname);
+ if (p != map.end()) {
+ return p->second;
+ }
+ }
+
+ if (cmSystemTools::FileExists(fname, true)) {
+ std::string fp = cmSystemTools::CollapseFullPath(fname);
+ this->DirectoryToFileToPathMap[extraPath ? extraPath : ""][fname] = fp;
+ return fp;
+ }
+
+ for (std::vector<std::string>::iterator i =
+ this->IncludeDirectories.begin();
+ i != this->IncludeDirectories.end(); ++i) {
+ std::string path = *i;
+ if (!path.empty() && path[path.size() - 1] != '/') {
+ path = path + "/";
+ }
+ path = path + fname;
+ if (cmSystemTools::FileExists(path.c_str(), true) &&
+ !cmSystemTools::FileIsDirectory(path)) {
+ std::string fp = cmSystemTools::CollapseFullPath(path);
+ this->DirectoryToFileToPathMap[extraPath ? extraPath : ""][fname] = fp;
+ return fp;
+ }
+ }
+
+ if (extraPath) {
+ std::string path = extraPath;
+ if (!path.empty() && path[path.size() - 1] != '/') {
+ path = path + "/";
+ }
+ path = path + fname;
+ if (cmSystemTools::FileExists(path.c_str(), true) &&
+ !cmSystemTools::FileIsDirectory(path)) {
+ std::string fp = cmSystemTools::CollapseFullPath(path);
+ this->DirectoryToFileToPathMap[extraPath][fname] = fp;
+ return fp;
+ }
+ }
+
+ // Couldn't find the file.
+ return std::string(fname);
+ }
+
+ cmMakefile* Makefile;
+ bool Verbose;
+ cmsys::RegularExpression IncludeFileRegularExpression;
+ cmsys::RegularExpression ComplainFileRegularExpression;
+ std::vector<std::string> IncludeDirectories;
+ typedef std::map<std::string, std::string> FileToPathMapType;
+ typedef std::map<std::string, FileToPathMapType>
+ DirectoryToFileToPathMapType;
+ typedef std::map<std::string, cmDependInformation*> DependInformationMapType;
+ DependInformationMapType DependInformationMap;
+ DirectoryToFileToPathMapType DirectoryToFileToPathMap;
+};
+
+// cmOutputRequiredFilesCommand
+bool cmOutputRequiredFilesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (this->Disallowed(cmPolicies::CMP0032, "The output_required_files "
+ "command should not be called; "
+ "see CMP0032.")) {
+ return true;
+ }
+ if (args.size() != 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // store the arg for final pass
+ this->File = args[0];
+ this->OutputFile = args[1];
+
+ // compute the list of files
+ cmLBDepend md;
+ md.SetMakefile(this->Makefile);
+ md.AddSearchPath(this->Makefile->GetCurrentSourceDirectory());
+ // find the depends for a file
+ const cmDependInformation* info = md.FindDependencies(this->File.c_str());
+ if (info) {
+ // write them out
+ FILE* fout = cmsys::SystemTools::Fopen(this->OutputFile.c_str(), "w");
+ if (!fout) {
+ std::string err = "Can not open output file: ";
+ err += this->OutputFile;
+ this->SetError(err);
+ return false;
+ }
+ std::set<cmDependInformation const*> visited;
+ this->ListDependencies(info, fout, &visited);
+ fclose(fout);
+ }
+
+ return true;
+}
+
+void cmOutputRequiredFilesCommand::ListDependencies(
+ cmDependInformation const* info, FILE* fout,
+ std::set<cmDependInformation const*>* visited)
+{
+ // add info to the visited set
+ visited->insert(info);
+ // now recurse with info's dependencies
+ for (cmDependInformation::DependencySetType::const_iterator d =
+ info->DependencySet.begin();
+ d != info->DependencySet.end(); ++d) {
+ if (visited->find(*d) == visited->end()) {
+ if (info->FullPath != "") {
+ std::string tmp = (*d)->FullPath;
+ std::string::size_type pos = tmp.rfind('.');
+ if (pos != std::string::npos && (tmp.substr(pos) != ".h")) {
+ tmp = tmp.substr(0, pos);
+ fprintf(fout, "%s\n", (*d)->FullPath.c_str());
+ }
+ }
+ this->ListDependencies(*d, fout, visited);
+ }
+ }
+}
diff --git a/Source/cmOutputRequiredFilesCommand.h b/Source/cmOutputRequiredFilesCommand.h
new file mode 100644
index 0000000..8838d09
--- /dev/null
+++ b/Source/cmOutputRequiredFilesCommand.h
@@ -0,0 +1,36 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmOutputRequiredFilesCommand_h
+#define cmOutputRequiredFilesCommand_h
+
+#include "cmCommand.h"
+
+class cmDependInformation;
+
+class cmOutputRequiredFilesCommand : public cmCommand
+{
+public:
+ cmTypeMacro(cmOutputRequiredFilesCommand, cmCommand);
+ cmCommand* Clone() CM_OVERRIDE { return new cmOutputRequiredFilesCommand; }
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+ std::string GetName() const CM_OVERRIDE { return "output_required_files"; }
+
+ void ListDependencies(cmDependInformation const* info, FILE* fout,
+ std::set<cmDependInformation const*>* visited);
+
+private:
+ std::string File;
+ std::string OutputFile;
+};
+
+#endif
diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx
new file mode 100644
index 0000000..8f524ec
--- /dev/null
+++ b/Source/cmParseArgumentsCommand.cxx
@@ -0,0 +1,174 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Matthias Maennich <matthias@maennich.net>
+ Copyright 2010 Alexander Neundorf <neundorf@kde.org>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmParseArgumentsCommand.h"
+
+#include "cmAlgorithms.h"
+
+bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ // cmake_parse_arguments(prefix options single multi <ARGN>)
+ // 1 2 3 4
+ if (args.size() < 4) {
+ this->SetError("must be called with at least 4 arguments.");
+ return false;
+ }
+
+ std::vector<std::string>::const_iterator argIter = args.begin(),
+ argEnd = args.end();
+ // the first argument is the prefix
+ const std::string prefix = (*argIter++) + "_";
+
+ // 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 single;
+ multi_map multi;
+
+ // 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: ";
+
+ // the second argument is a (cmake) list of options without argument
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(*argIter++, list);
+ for (std::vector<std::string>::const_iterator iter = list.begin(),
+ end = list.end();
+ iter != end; ++iter) {
+ if (!used_keywords.insert(*iter).second) {
+ this->GetMakefile()->IssueMessage(cmake::WARNING, dup_warning + *iter);
+ }
+ options[*iter]; // default initialize
+ }
+
+ // the third argument is a (cmake) list of single argument options
+ list.clear();
+ cmSystemTools::ExpandListArgument(*argIter++, list);
+ for (std::vector<std::string>::const_iterator iter = list.begin(),
+ end = list.end();
+ iter != end; ++iter) {
+ if (!used_keywords.insert(*iter).second) {
+ this->GetMakefile()->IssueMessage(cmake::WARNING, dup_warning + *iter);
+ }
+ single[*iter]; // default initialize
+ }
+
+ // the fourth argument is a (cmake) list of multi argument options
+ list.clear();
+ cmSystemTools::ExpandListArgument(*argIter++, list);
+ for (std::vector<std::string>::const_iterator iter = list.begin(),
+ end = list.end();
+ iter != end; ++iter) {
+ if (!used_keywords.insert(*iter).second) {
+ this->GetMakefile()->IssueMessage(cmake::WARNING, dup_warning + *iter);
+ }
+ multi[*iter]; // default initialize
+ }
+
+ enum insideValues
+ {
+ NONE,
+ SINGLE,
+ MULTI
+ } insideValues = NONE;
+ std::string currentArgName;
+
+ // Flatten ;-lists in the arguments into a single list as was done
+ // by the original function(CMAKE_PARSE_ARGUMENTS).
+ list.clear();
+ for (; argIter != argEnd; ++argIter) {
+ cmSystemTools::ExpandListArgument(*argIter, list);
+ }
+
+ // iterate over the arguments list and fill in the values where applicable
+ for (argIter = list.begin(), argEnd = list.end(); argIter != argEnd;
+ ++argIter) {
+ const options_map::iterator optIter = options.find(*argIter);
+ if (optIter != options.end()) {
+ insideValues = NONE;
+ optIter->second = true;
+ continue;
+ }
+
+ const single_map::iterator singleIter = single.find(*argIter);
+ if (singleIter != single.end()) {
+ insideValues = SINGLE;
+ currentArgName = *argIter;
+ continue;
+ }
+
+ const multi_map::iterator multiIter = multi.find(*argIter);
+ if (multiIter != multi.end()) {
+ insideValues = MULTI;
+ currentArgName = *argIter;
+ continue;
+ }
+
+ switch (insideValues) {
+ case SINGLE:
+ single[currentArgName] = *argIter;
+ insideValues = NONE;
+ break;
+ case MULTI:
+ multi[currentArgName].push_back(*argIter);
+ break;
+ default:
+ unparsed.push_back(*argIter);
+ break;
+ }
+ }
+
+ // now iterate over the collected values and update their definition
+ // within the current scope. undefine if necessary.
+
+ for (options_map::const_iterator iter = options.begin(), end = options.end();
+ iter != end; ++iter) {
+ this->Makefile->AddDefinition(prefix + iter->first,
+ iter->second ? "TRUE" : "FALSE");
+ }
+ for (single_map::const_iterator iter = single.begin(), end = single.end();
+ iter != end; ++iter) {
+ if (!iter->second.empty()) {
+ this->Makefile->AddDefinition(prefix + iter->first,
+ iter->second.c_str());
+ } else {
+ this->Makefile->RemoveDefinition(prefix + iter->first);
+ }
+ }
+
+ for (multi_map::const_iterator iter = multi.begin(), end = multi.end();
+ iter != end; ++iter) {
+ 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");
+ }
+
+ return true;
+}
diff --git a/Source/cmParseArgumentsCommand.h b/Source/cmParseArgumentsCommand.h
new file mode 100644
index 0000000..fcd9992
--- /dev/null
+++ b/Source/cmParseArgumentsCommand.h
@@ -0,0 +1,49 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Matthias Maennich <matthias@maennich.net>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmParseArgumentsCommand_h
+#define cmParseArgumentsCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmParseArgumentsCommand
+ *
+ */
+class cmParseArgumentsCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmParseArgumentsCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "cmake_parse_arguments"; }
+
+ cmTypeMacro(cmParseArgumentsCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmPathLabel.cxx b/Source/cmPathLabel.cxx
new file mode 100644
index 0000000..491d2f0
--- /dev/null
+++ b/Source/cmPathLabel.cxx
@@ -0,0 +1,38 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmPathLabel.h"
+
+cmPathLabel::cmPathLabel(const std::string& label)
+ : Label(label)
+ , Hash(0)
+{
+ // Use a Jenkins one-at-a-time hash with under/over-flow protection
+ for (size_t i = 0; i < this->Label.size(); ++i) {
+ this->Hash += this->Label[i];
+ this->Hash += ((this->Hash & 0x003FFFFF) << 10);
+ this->Hash ^= ((this->Hash & 0xFFFFFFC0) >> 6);
+ }
+ this->Hash += ((this->Hash & 0x1FFFFFFF) << 3);
+ this->Hash ^= ((this->Hash & 0xFFFFF800) >> 11);
+ this->Hash += ((this->Hash & 0x0001FFFF) << 15);
+}
+
+bool cmPathLabel::operator<(const cmPathLabel& l) const
+{
+ return this->Hash < l.Hash;
+}
+
+bool cmPathLabel::operator==(const cmPathLabel& l) const
+{
+ return this->Hash == l.Hash;
+}
diff --git a/Source/cmPathLabel.h b/Source/cmPathLabel.h
new file mode 100644
index 0000000..39fbec3
--- /dev/null
+++ b/Source/cmPathLabel.h
@@ -0,0 +1,44 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmPathLabel_h
+#define cmPathLabel_h
+
+#include "cmStandardIncludes.h"
+
+/** \class cmPathLabel
+ * \brief Helper class for text based labels
+ *
+ * cmPathLabel is extended in different classes to act as an inheritable
+ * enum. Comparisons are done on a precomputed Jenkins hash of the string
+ * label for indexing and searchig.
+ */
+class cmPathLabel
+{
+public:
+ cmPathLabel(const std::string& label);
+
+ // The comparison operators are only for quick sorting and searching and
+ // in no way imply any lexicographical order of the label
+ bool operator<(const cmPathLabel& l) const;
+ bool operator==(const cmPathLabel& l) const;
+
+ const std::string& GetLabel() const { return this->Label; }
+ const unsigned int& GetHash() const { return this->Hash; }
+
+protected:
+ cmPathLabel();
+
+ std::string Label;
+ unsigned int Hash;
+};
+
+#endif
diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx
new file mode 100644
index 0000000..124fb6a
--- /dev/null
+++ b/Source/cmPolicies.cxx
@@ -0,0 +1,349 @@
+#include "cmPolicies.h"
+
+#include "cmAlgorithms.h"
+#include "cmMakefile.h"
+#include "cmVersion.h"
+#include "cmVersionMacros.h"
+#include "cmake.h"
+#include <assert.h>
+#include <ctype.h>
+#include <map>
+#include <queue>
+#include <set>
+
+static bool stringToId(const char* input, cmPolicies::PolicyID& pid)
+{
+ assert(input);
+ if (strlen(input) != 7) {
+ return false;
+ }
+ if (!cmHasLiteralPrefix(input, "CMP")) {
+ return false;
+ }
+ if (cmHasLiteralSuffix(input, "0000")) {
+ pid = cmPolicies::CMP0000;
+ return true;
+ }
+ for (int i = 3; i < 7; ++i) {
+ if (!isdigit(*(input + i))) {
+ return false;
+ }
+ }
+ long id;
+ if (!cmSystemTools::StringToLong(input + 3, &id)) {
+ return false;
+ }
+ if (id >= cmPolicies::CMPCOUNT) {
+ return false;
+ }
+ pid = cmPolicies::PolicyID(id);
+ return true;
+}
+
+#define CM_SELECT_ID_VERSION(F, A1, A2, A3, A4, A5, A6) F(A1, A3, A4, A5)
+#define CM_FOR_EACH_POLICY_ID_VERSION(POLICY) \
+ CM_FOR_EACH_POLICY_TABLE(POLICY, CM_SELECT_ID_VERSION)
+
+#define CM_SELECT_ID_DOC(F, A1, A2, A3, A4, A5, A6) F(A1, A2)
+#define CM_FOR_EACH_POLICY_ID_DOC(POLICY) \
+ CM_FOR_EACH_POLICY_TABLE(POLICY, CM_SELECT_ID_DOC)
+
+static const char* idToString(cmPolicies::PolicyID id)
+{
+ switch (id) {
+#define POLICY_CASE(ID) \
+ case cmPolicies::ID: \
+ return #ID;
+ CM_FOR_EACH_POLICY_ID(POLICY_CASE)
+#undef POLICY_CASE
+ case cmPolicies::CMPCOUNT:
+ return CM_NULLPTR;
+ }
+ return CM_NULLPTR;
+}
+
+static const char* idToVersion(cmPolicies::PolicyID id)
+{
+ switch (id) {
+#define POLICY_CASE(ID, V_MAJOR, V_MINOR, V_PATCH) \
+ case cmPolicies::ID: \
+ return #V_MAJOR "." #V_MINOR "." #V_PATCH;
+ CM_FOR_EACH_POLICY_ID_VERSION(POLICY_CASE)
+#undef POLICY_CASE
+ case cmPolicies::CMPCOUNT:
+ return CM_NULLPTR;
+ }
+ return CM_NULLPTR;
+}
+
+static bool isPolicyNewerThan(cmPolicies::PolicyID id, unsigned int majorV,
+ unsigned int minorV, unsigned int patchV)
+{
+ switch (id) {
+#define POLICY_CASE(ID, V_MAJOR, V_MINOR, V_PATCH) \
+ case cmPolicies::ID: \
+ return ( \
+ majorV < V_MAJOR || (majorV == V_MAJOR && minorV + 1 < V_MINOR + 1) || \
+ (majorV == V_MAJOR && minorV == V_MINOR && patchV + 1 < V_PATCH + 1));
+ CM_FOR_EACH_POLICY_ID_VERSION(POLICY_CASE)
+#undef POLICY_CASE
+ case cmPolicies::CMPCOUNT:
+ return false;
+ }
+ return false;
+}
+
+const char* idToShortDescription(cmPolicies::PolicyID id)
+{
+ switch (id) {
+#define POLICY_CASE(ID, SHORT_DESCRIPTION) \
+ case cmPolicies::ID: \
+ return SHORT_DESCRIPTION;
+ CM_FOR_EACH_POLICY_ID_DOC(POLICY_CASE)
+#undef POLICY_CASE
+ case cmPolicies::CMPCOUNT:
+ return CM_NULLPTR;
+ }
+ return CM_NULLPTR;
+}
+
+static void DiagnoseAncientPolicies(
+ std::vector<cmPolicies::PolicyID> const& ancient, unsigned int majorVer,
+ unsigned int minorVer, unsigned int patchVer, cmMakefile* mf)
+{
+ std::ostringstream e;
+ e << "The project requests behavior compatible with CMake version \""
+ << majorVer << "." << minorVer << "." << patchVer
+ << "\", which requires the OLD behavior for some policies:\n";
+ for (std::vector<cmPolicies::PolicyID>::const_iterator i = ancient.begin();
+ i != ancient.end(); ++i) {
+ e << " " << idToString(*i) << ": " << idToShortDescription(*i) << "\n";
+ }
+ e << "However, this version of CMake no longer supports the OLD "
+ << "behavior for these policies. "
+ << "Please either update your CMakeLists.txt files to conform to "
+ << "the new behavior or use an older version of CMake that still "
+ << "supports the old behavior.";
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+static bool GetPolicyDefault(cmMakefile* mf, std::string const& policy,
+ cmPolicies::PolicyStatus* defaultSetting)
+{
+ std::string defaultVar = "CMAKE_POLICY_DEFAULT_" + policy;
+ std::string defaultValue = mf->GetSafeDefinition(defaultVar);
+ if (defaultValue == "NEW") {
+ *defaultSetting = cmPolicies::NEW;
+ } else if (defaultValue == "OLD") {
+ *defaultSetting = cmPolicies::OLD;
+ } else if (defaultValue == "") {
+ *defaultSetting = cmPolicies::WARN;
+ } else {
+ std::ostringstream e;
+ e << defaultVar << " has value \"" << defaultValue
+ << "\" but must be \"OLD\", \"NEW\", or \"\" (empty).";
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ return true;
+}
+
+bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, const char* version)
+{
+ std::string ver = "2.4.0";
+
+ if (version && strlen(version) > 0) {
+ ver = version;
+ }
+
+ unsigned int majorVer = 2;
+ unsigned int minorVer = 0;
+ unsigned int patchVer = 0;
+ unsigned int tweakVer = 0;
+
+ // parse the string
+ if (sscanf(ver.c_str(), "%u.%u.%u.%u", &majorVer, &minorVer, &patchVer,
+ &tweakVer) < 2) {
+ std::ostringstream e;
+ e << "Invalid policy version value \"" << ver << "\". "
+ << "A numeric major.minor[.patch[.tweak]] must be given.";
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ // it is an error if the policy version is less than 2.4
+ if (majorVer < 2 || (majorVer == 2 && minorVer < 4)) {
+ mf->IssueMessage(
+ cmake::FATAL_ERROR,
+ "Compatibility with CMake < 2.4 is not supported by CMake >= 3.0. "
+ "For compatibility with older versions please use any CMake 2.8.x "
+ "release or lower.");
+ return false;
+ }
+
+ // It is an error if the policy version is greater than the running
+ // CMake.
+ if (majorVer > cmVersion::GetMajorVersion() ||
+ (majorVer == cmVersion::GetMajorVersion() &&
+ minorVer > cmVersion::GetMinorVersion()) ||
+ (majorVer == cmVersion::GetMajorVersion() &&
+ minorVer == cmVersion::GetMinorVersion() &&
+ patchVer > cmVersion::GetPatchVersion()) ||
+ (majorVer == cmVersion::GetMajorVersion() &&
+ minorVer == cmVersion::GetMinorVersion() &&
+ patchVer == cmVersion::GetPatchVersion() &&
+ tweakVer > cmVersion::GetTweakVersion())) {
+ std::ostringstream e;
+ e << "An attempt was made to set the policy version of CMake to \""
+ << version << "\" which is greater than this version of CMake. "
+ << "This is not allowed because the greater version may have new "
+ << "policies not known to this CMake. "
+ << "You may need a newer CMake version to build this project.";
+ mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ // now loop over all the policies and set them as appropriate
+ std::vector<cmPolicies::PolicyID> ancientPolicies;
+ for (PolicyID pid = cmPolicies::CMP0000; pid != cmPolicies::CMPCOUNT;
+ pid = PolicyID(pid + 1)) {
+ if (isPolicyNewerThan(pid, majorVer, minorVer, patchVer)) {
+ if (cmPolicies::GetPolicyStatus(pid) == cmPolicies::REQUIRED_ALWAYS) {
+ ancientPolicies.push_back(pid);
+ } else {
+ cmPolicies::PolicyStatus status = cmPolicies::WARN;
+ if (!GetPolicyDefault(mf, idToString(pid), &status) ||
+ !mf->SetPolicy(pid, status)) {
+ return false;
+ }
+ if (pid == cmPolicies::CMP0001 &&
+ (status == cmPolicies::WARN || status == cmPolicies::OLD)) {
+ if (!(mf->GetState()->GetInitializedCacheValue(
+ "CMAKE_BACKWARDS_COMPATIBILITY"))) {
+ // Set it to 2.4 because that is the last version where the
+ // variable had meaning.
+ mf->AddCacheDefinition(
+ "CMAKE_BACKWARDS_COMPATIBILITY", "2.4",
+ "For backwards compatibility, what version of CMake "
+ "commands and "
+ "syntax should this version of CMake try to support.",
+ cmState::STRING);
+ }
+ }
+ }
+ } else {
+ if (!mf->SetPolicy(pid, cmPolicies::NEW)) {
+ return false;
+ }
+ }
+ }
+
+ // Make sure the project does not use any ancient policies.
+ if (!ancientPolicies.empty()) {
+ DiagnoseAncientPolicies(ancientPolicies, majorVer, minorVer, patchVer, mf);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ return true;
+}
+
+bool cmPolicies::GetPolicyID(const char* id, cmPolicies::PolicyID& pid)
+{
+ return stringToId(id, pid);
+}
+
+///! return a warning string for a given policy
+std::string cmPolicies::GetPolicyWarning(cmPolicies::PolicyID id)
+{
+ std::ostringstream msg;
+ msg << "Policy " << idToString(id) << " is not set: "
+ ""
+ << idToShortDescription(id) << " "
+ "Run \"cmake --help-policy "
+ << idToString(id) << "\" for "
+ "policy details. "
+ "Use the cmake_policy command to set the policy "
+ "and suppress this warning.";
+ return msg.str();
+}
+
+///! return an error string for when a required policy is unspecified
+std::string cmPolicies::GetRequiredPolicyError(cmPolicies::PolicyID id)
+{
+ std::ostringstream error;
+ error << "Policy " << idToString(id) << " is not set to NEW: "
+ ""
+ << idToShortDescription(id) << " "
+ "Run \"cmake --help-policy "
+ << idToString(id)
+ << "\" for "
+ "policy details. "
+ "CMake now requires this policy to be set to NEW by the project. "
+ "The policy may be set explicitly using the code\n"
+ " cmake_policy(SET "
+ << idToString(id) << " NEW)\n"
+ "or by upgrading all policies with the code\n"
+ " cmake_policy(VERSION "
+ << idToVersion(id)
+ << ") # or later\n"
+ "Run \"cmake --help-command cmake_policy\" for more information.";
+ return error.str();
+}
+
+///! Get the default status for a policy
+cmPolicies::PolicyStatus cmPolicies::GetPolicyStatus(cmPolicies::PolicyID)
+{
+ return cmPolicies::WARN;
+}
+
+std::string cmPolicies::GetRequiredAlwaysPolicyError(cmPolicies::PolicyID id)
+{
+ std::string pid = idToString(id);
+ std::ostringstream e;
+ e << "Policy " << pid << " may not be set to OLD behavior because this "
+ << "version of CMake no longer supports it. "
+ << "The policy was introduced in "
+ << "CMake version " << idToVersion(id)
+ << ", and use of NEW behavior is now required."
+ << "\n"
+ << "Please either update your CMakeLists.txt files to conform to "
+ << "the new behavior or use an older version of CMake that still "
+ << "supports the old behavior. "
+ << "Run cmake --help-policy " << pid << " for more information.";
+ return e.str();
+}
+
+cmPolicies::PolicyStatus cmPolicies::PolicyMap::Get(
+ cmPolicies::PolicyID id) const
+{
+ PolicyStatus status = cmPolicies::WARN;
+
+ if (this->Status[(POLICY_STATUS_COUNT * id) + OLD]) {
+ status = cmPolicies::OLD;
+ } else if (this->Status[(POLICY_STATUS_COUNT * id) + NEW]) {
+ status = cmPolicies::NEW;
+ }
+ return status;
+}
+
+void cmPolicies::PolicyMap::Set(cmPolicies::PolicyID id,
+ cmPolicies::PolicyStatus status)
+{
+ this->Status[(POLICY_STATUS_COUNT * id) + OLD] = (status == OLD);
+ this->Status[(POLICY_STATUS_COUNT * id) + WARN] = (status == WARN);
+ this->Status[(POLICY_STATUS_COUNT * id) + NEW] = (status == NEW);
+}
+
+bool cmPolicies::PolicyMap::IsDefined(cmPolicies::PolicyID id) const
+{
+ return this->Status[(POLICY_STATUS_COUNT * id) + OLD] ||
+ this->Status[(POLICY_STATUS_COUNT * id) + WARN] ||
+ this->Status[(POLICY_STATUS_COUNT * id) + NEW];
+}
+
+bool cmPolicies::PolicyMap::IsEmpty() const
+{
+ return this->Status.none();
+}
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
new file mode 100644
index 0000000..0c8ff60
--- /dev/null
+++ b/Source/cmPolicies.h
@@ -0,0 +1,301 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmPolicies_h
+#define cmPolicies_h
+
+#include "cmStandardIncludes.h"
+
+#include <bitset>
+
+class cmMakefile;
+class cmPolicy;
+
+#define CM_FOR_EACH_POLICY_TABLE(POLICY, SELECT) \
+ SELECT(POLICY, CMP0000, \
+ "A minimum required CMake version must be specified.", 2, 6, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0001, \
+ "CMAKE_BACKWARDS_COMPATIBILITY should no longer be used.", 2, 6, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0002, "Logical target names must be globally unique.", 2, \
+ 6, 0, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0003, \
+ "Libraries linked via full path no longer produce linker search paths.", \
+ 2, 6, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0004, \
+ "Libraries linked may not have leading or trailing whitespace.", 2, \
+ 6, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0005, \
+ "Preprocessor definition values are now escaped automatically.", 2, \
+ 6, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0006, \
+ "Installing MACOSX_BUNDLE targets requires a BUNDLE DESTINATION.", \
+ 2, 6, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0007, "list command no longer ignores empty elements.", \
+ 2, 6, 0, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0008, \
+ "Libraries linked by full-path must have a valid library file name.", 2, \
+ 6, 1, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0009, \
+ "FILE GLOB_RECURSE calls should not follow symlinks by default.", 2, \
+ 6, 2, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0010, "Bad variable reference syntax is an error.", 2, 6, \
+ 3, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0011, \
+ "Included scripts do automatic cmake_policy PUSH and POP.", 2, 6, 3, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0012, "if() recognizes numbers and boolean constants.", \
+ 2, 8, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0013, "Duplicate binary directories are not allowed.", 2, \
+ 8, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0014, "Input directories must have CMakeLists.txt.", 2, \
+ 8, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0015, \
+ "link_directories() treats paths relative to the source dir.", 2, 8, \
+ 1, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0016, \
+ "target_link_libraries() reports error if its only argument " \
+ "is not a target.", \
+ 2, 8, 3, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0017, \
+ "Prefer files from the CMake module directory when including from " \
+ "there.", \
+ 2, 8, 4, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0018, \
+ "Ignore CMAKE_SHARED_LIBRARY_<Lang>_FLAGS variable.", 2, 8, 9, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0019, \
+ "Do not re-expand variables in include and link information.", 2, 8, \
+ 11, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0020, \
+ "Automatically link Qt executables to qtmain target on Windows.", 2, \
+ 8, 11, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0021, \
+ "Fatal error on relative paths in INCLUDE_DIRECTORIES target property.", \
+ 2, 8, 12, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0022, \
+ "INTERFACE_LINK_LIBRARIES defines the link interface.", 2, 8, 12, \
+ cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0023, \
+ "Plain and keyword target_link_libraries signatures cannot be mixed.", 2, \
+ 8, 12, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0024, "Disallow include export result.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0025, "Compiler id for Apple Clang is now AppleClang.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0026, "Disallow use of the LOCATION target property.", 3, \
+ 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0027, \
+ "Conditionally linked imported targets with missing include " \
+ "directories.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0028, \
+ "Double colon in target name means ALIAS or IMPORTED target.", 3, 0, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0029, "The subdir_depends command should not be called.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0030, \
+ "The use_mangled_mesa command should not be called.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0031, "The load_command command should not be called.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0032, \
+ "The output_required_files command should not be called.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0033, \
+ "The export_library_dependencies command should not be called.", 3, \
+ 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0034, "The utility_source command should not be called.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0035, \
+ "The variable_requires command should not be called.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0036, "The build_name command should not be called.", 3, \
+ 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0037, \
+ "Target names should not be reserved and should match a validity " \
+ "pattern.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0038, "Targets may not link directly to themselves.", 3, \
+ 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0039, "Utility targets may not have link dependencies.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0040, \
+ "The target in the TARGET signature of add_custom_command() must " \
+ "exist.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0041, \
+ "Error on relative include with generator expression.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0042, "MACOSX_RPATH is enabled by default.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0043, "Ignore COMPILE_DEFINITIONS_<Config> properties.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0044, \
+ "Case sensitive <LANG>_COMPILER_ID generator expressions.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0045, \
+ "Error on non-existent target in get_target_property.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0046, \
+ "Error on non-existent dependency in add_dependencies.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0047, "Use QCC compiler id for the qcc drivers on QNX.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0048, "project() command manages VERSION variables.", 3, \
+ 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0049, \
+ "Do not expand variables in target source entries.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0050, "Disallow add_custom_command SOURCE signatures.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0051, "List TARGET_OBJECTS in SOURCES target property.", \
+ 3, 1, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0052, "Reject source and build dirs in installed " \
+ "INTERFACE_INCLUDE_DIRECTORIES.", \
+ 3, 1, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0053, \
+ "Simplify variable reference and escape sequence evaluation.", 3, 1, \
+ 0, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0054, \
+ "Only interpret if() arguments as variables or keywords when unquoted.", \
+ 3, 1, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0055, "Strict checking for break() command.", 3, 2, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0056, \
+ "Honor link flags in try_compile() source-file signature.", 3, 2, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0057, "Support new IN_LIST if() operator.", 3, 3, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0058, \
+ "Ninja requires custom command byproducts to be explicit.", 3, 3, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0059, \
+ "Do not treat DEFINITIONS as a built-in directory property.", 3, 3, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0060, \
+ "Link libraries by full path even in implicit directories.", 3, 3, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0061, \
+ "CTest does not by default tell make to ignore errors (-i).", 3, 3, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0062, "Disallow install() of export() result.", 3, 3, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0063, \
+ "Honor visibility properties for all target types.", 3, 3, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0064, "Support new TEST if() operator.", 3, 4, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0065, \
+ "Do not add flags to export symbols from executables without " \
+ "the ENABLE_EXPORTS target property.", \
+ 3, 4, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0066, \
+ "Honor per-config flags in try_compile() source-file signature.", 3, \
+ 7, 0, cmPolicies::WARN)
+
+#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
+#define CM_FOR_EACH_POLICY_ID(POLICY) \
+ CM_FOR_EACH_POLICY_TABLE(POLICY, CM_SELECT_ID)
+
+#define CM_FOR_EACH_TARGET_POLICY(F) \
+ F(CMP0003) \
+ F(CMP0004) \
+ F(CMP0008) \
+ F(CMP0020) \
+ F(CMP0021) \
+ F(CMP0022) \
+ F(CMP0027) \
+ F(CMP0038) \
+ F(CMP0041) \
+ F(CMP0042) \
+ F(CMP0046) \
+ F(CMP0052) \
+ F(CMP0060) \
+ F(CMP0063) \
+ F(CMP0065)
+
+/** \class cmPolicies
+ * \brief Handles changes in CMake behavior and policies
+ *
+ * See the cmake wiki section on
+ * <a href="https://cmake.org/Wiki/CMake/Policies">policies</a>
+ * for an overview of this class's purpose
+ */
+class cmPolicies
+{
+public:
+ /// Status of a policy
+ enum PolicyStatus
+ {
+ OLD, ///< Use old behavior
+ WARN, ///< Use old behavior but issue a warning
+ NEW, ///< Use new behavior
+ /// Issue an error if user doesn't set policy status to NEW and hits the
+ /// check
+ REQUIRED_IF_USED,
+ REQUIRED_ALWAYS ///< Issue an error unless user sets policy status to NEW.
+ };
+
+ /// Policy identifiers
+ enum PolicyID
+ {
+#define POLICY_ENUM(POLICY_ID) POLICY_ID,
+ CM_FOR_EACH_POLICY_ID(POLICY_ENUM)
+#undef POLICY_ENUM
+
+ /** \brief Always the last entry.
+ *
+ * Useful mostly to avoid adding a comma the last policy when adding a new
+ * one.
+ */
+ CMPCOUNT
+ };
+
+ ///! 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
+ static cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id);
+
+ ///! Set a policy level for this listfile
+ static bool ApplyPolicyVersion(cmMakefile* mf, const char* version);
+
+ ///! return a warning string for a given policy
+ static std::string GetPolicyWarning(cmPolicies::PolicyID id);
+
+ ///! 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
+ static std::string GetRequiredAlwaysPolicyError(cmPolicies::PolicyID id);
+
+ /** Represent a set of policy values. */
+ struct PolicyMap
+ {
+ PolicyStatus Get(PolicyID id) const;
+ void Set(PolicyID id, PolicyStatus status);
+ bool IsDefined(PolicyID id) const;
+ bool IsEmpty() const;
+
+ private:
+#define POLICY_STATUS_COUNT 3
+ std::bitset<cmPolicies::CMPCOUNT * POLICY_STATUS_COUNT> Status;
+ };
+};
+
+#endif
diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx
new file mode 100644
index 0000000..34b8df2
--- /dev/null
+++ b/Source/cmProcessTools.cxx
@@ -0,0 +1,78 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmProcessTools.h"
+
+#include <cmsys/Process.h>
+
+void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
+ OutputParser* err)
+{
+ cmsysProcess_Execute(cp);
+ char* data = CM_NULLPTR;
+ int length = 0;
+ int p;
+ while ((out || err) &&
+ (p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) {
+ if (out && p == cmsysProcess_Pipe_STDOUT) {
+ if (!out->Process(data, length)) {
+ out = CM_NULLPTR;
+ }
+ } else if (err && p == cmsysProcess_Pipe_STDERR) {
+ if (!err->Process(data, length)) {
+ err = CM_NULLPTR;
+ }
+ }
+ }
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+}
+
+cmProcessTools::LineParser::LineParser(char sep, bool ignoreCR)
+ : Log(CM_NULLPTR)
+ , Prefix(CM_NULLPTR)
+ , Separator(sep)
+ , LineEnd('\0')
+ , IgnoreCR(ignoreCR)
+{
+}
+
+void cmProcessTools::LineParser::SetLog(std::ostream* log, const char* prefix)
+{
+ this->Log = log;
+ this->Prefix = prefix ? prefix : "";
+}
+
+bool cmProcessTools::LineParser::ProcessChunk(const char* first, int length)
+{
+ const char* last = first + length;
+ for (const char* c = first; c != last; ++c) {
+ if (*c == this->Separator || *c == '\0') {
+ this->LineEnd = *c;
+
+ // Log this line.
+ if (this->Log && this->Prefix) {
+ *this->Log << this->Prefix << this->Line << "\n";
+ }
+
+ // Hand this line to the subclass implementation.
+ if (!this->ProcessLine()) {
+ this->Line = "";
+ return false;
+ }
+
+ this->Line = "";
+ } else if (*c != '\r' || !this->IgnoreCR) {
+ // Append this character to the line under construction.
+ this->Line.append(1, *c);
+ }
+ }
+ return true;
+}
diff --git a/Source/cmProcessTools.h b/Source/cmProcessTools.h
new file mode 100644
index 0000000..61bfc64
--- /dev/null
+++ b/Source/cmProcessTools.h
@@ -0,0 +1,90 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmProcessTools_h
+#define cmProcessTools_h
+
+#include "cmStandardIncludes.h"
+
+/** \class cmProcessTools
+ * \brief Helper classes for process output parsing
+ *
+ */
+class cmProcessTools
+{
+public:
+ /** Abstract interface for process output parsers. */
+ class OutputParser
+ {
+ public:
+ /** Process the given output data from a tool. Processing may be
+ done incrementally. Returns true if the parser is interested
+ in any more data and false if it is done. */
+ bool Process(const char* data, int length)
+ {
+ return this->ProcessChunk(data, length);
+ }
+ bool Process(const char* data)
+ {
+ return this->Process(data, static_cast<int>(strlen(data)));
+ }
+
+ virtual ~OutputParser() {}
+ protected:
+ /** Implement in a subclass to process a chunk of data. It should
+ return true only if it is interested in more data. */
+ virtual bool ProcessChunk(const char* data, int length) = 0;
+ };
+
+ /** Process output parser that extracts one line at a time. */
+ class LineParser : public OutputParser
+ {
+ public:
+ /** Construct with line separation character and choose whether to
+ ignore carriage returns. */
+ LineParser(char sep = '\n', bool ignoreCR = true);
+
+ /** Configure logging of lines as they are extracted. */
+ void SetLog(std::ostream* log, const char* prefix);
+
+ protected:
+ std::ostream* Log;
+ const char* Prefix;
+ std::string Line;
+ char Separator;
+ char LineEnd;
+ bool IgnoreCR;
+ bool ProcessChunk(const char* data, int length) CM_OVERRIDE;
+
+ /** Implement in a subclass to process one line of input. It
+ should return true only if it is interested in more data. */
+ virtual bool ProcessLine() = 0;
+ };
+
+ /** Trivial line handler for simple logging. */
+ class OutputLogger : public LineParser
+ {
+ public:
+ OutputLogger(std::ostream& log, const char* prefix = CM_NULLPTR)
+ {
+ this->SetLog(&log, prefix);
+ }
+
+ private:
+ bool ProcessLine() CM_OVERRIDE { return true; }
+ };
+
+ /** Run a process and send output to given parsers. */
+ static void RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
+ OutputParser* err = CM_NULLPTR);
+};
+
+#endif
diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx
new file mode 100644
index 0000000..139303b
--- /dev/null
+++ b/Source/cmProjectCommand.cxx
@@ -0,0 +1,216 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmProjectCommand.h"
+
+// cmProjectCommand
+bool cmProjectCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("PROJECT called with incorrect number of arguments");
+ return false;
+ }
+ this->Makefile->SetProjectName(args[0]);
+
+ std::string bindir = args[0];
+ bindir += "_BINARY_DIR";
+ std::string srcdir = args[0];
+ srcdir += "_SOURCE_DIR";
+
+ this->Makefile->AddCacheDefinition(
+ bindir, this->Makefile->GetCurrentBinaryDirectory(),
+ "Value Computed by CMake", cmState::STATIC);
+ this->Makefile->AddCacheDefinition(
+ srcdir, this->Makefile->GetCurrentSourceDirectory(),
+ "Value Computed by CMake", cmState::STATIC);
+
+ bindir = "PROJECT_BINARY_DIR";
+ srcdir = "PROJECT_SOURCE_DIR";
+
+ this->Makefile->AddDefinition(bindir,
+ this->Makefile->GetCurrentBinaryDirectory());
+ this->Makefile->AddDefinition(srcdir,
+ this->Makefile->GetCurrentSourceDirectory());
+
+ this->Makefile->AddDefinition("PROJECT_NAME", args[0].c_str());
+
+ // Set the CMAKE_PROJECT_NAME variable to be the highest-level
+ // project name in the tree. If there are two project commands
+ // in the same CMakeLists.txt file, and it is the top level
+ // CMakeLists.txt file, then go with the last one, so that
+ // CMAKE_PROJECT_NAME will match PROJECT_NAME, and cmake --build
+ // will work.
+ if (!this->Makefile->GetDefinition("CMAKE_PROJECT_NAME") ||
+ (this->Makefile->IsRootMakefile())) {
+ this->Makefile->AddDefinition("CMAKE_PROJECT_NAME", args[0].c_str());
+ this->Makefile->AddCacheDefinition("CMAKE_PROJECT_NAME", args[0].c_str(),
+ "Value Computed by CMake",
+ cmState::STATIC);
+ }
+
+ bool haveVersion = false;
+ bool haveLanguages = false;
+ std::string version;
+ std::vector<std::string> languages;
+ enum Doing
+ {
+ DoingLanguages,
+ DoingVersion
+ };
+ Doing doing = DoingLanguages;
+ for (size_t i = 1; i < args.size(); ++i) {
+ if (args[i] == "LANGUAGES") {
+ if (haveLanguages) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR, "LANGUAGES may be specified at most once.");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ haveLanguages = true;
+ doing = DoingLanguages;
+ } else if (args[i] == "VERSION") {
+ if (haveVersion) {
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR,
+ "VERSION may be specified at most once.");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ haveVersion = true;
+ doing = DoingVersion;
+ } else if (doing == DoingVersion) {
+ doing = DoingLanguages;
+ version = args[i];
+ } else // doing == DoingLanguages
+ {
+ languages.push_back(args[i]);
+ }
+ }
+
+ if (haveVersion && !haveLanguages && !languages.empty()) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "project with VERSION must use LANGUAGES before language names.");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ if (haveLanguages && languages.empty()) {
+ languages.push_back("NONE");
+ }
+
+ cmPolicies::PolicyStatus cmp0048 =
+ this->Makefile->GetPolicyStatus(cmPolicies::CMP0048);
+ if (haveVersion) {
+ // Set project VERSION variables to given values
+ if (cmp0048 == cmPolicies::OLD || cmp0048 == cmPolicies::WARN) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "VERSION not allowed unless CMP0048 is set to NEW");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+
+ cmsys::RegularExpression vx(
+ "^([0-9]+(\\.[0-9]+(\\.[0-9]+(\\.[0-9]+)?)?)?)?$");
+ if (!vx.find(version)) {
+ std::string e = "VERSION \"" + version + "\" format invalid.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e);
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+
+ std::string vs;
+ const char* sep = "";
+ char vb[4][64];
+ unsigned int v[4] = { 0, 0, 0, 0 };
+ int vc =
+ sscanf(version.c_str(), "%u.%u.%u.%u", &v[0], &v[1], &v[2], &v[3]);
+ for (int i = 0; i < 4; ++i) {
+ if (i < vc) {
+ sprintf(vb[i], "%u", v[i]);
+ vs += sep;
+ vs += vb[i];
+ sep = ".";
+ } else {
+ vb[i][0] = 0;
+ }
+ }
+
+ std::string vv;
+ vv = args[0] + "_VERSION";
+ this->Makefile->AddDefinition("PROJECT_VERSION", vs.c_str());
+ this->Makefile->AddDefinition(vv, vs.c_str());
+ vv = args[0] + "_VERSION_MAJOR";
+ this->Makefile->AddDefinition("PROJECT_VERSION_MAJOR", vb[0]);
+ this->Makefile->AddDefinition(vv, vb[0]);
+ vv = args[0] + "_VERSION_MINOR";
+ this->Makefile->AddDefinition("PROJECT_VERSION_MINOR", vb[1]);
+ this->Makefile->AddDefinition(vv, vb[1]);
+ vv = args[0] + "_VERSION_PATCH";
+ this->Makefile->AddDefinition("PROJECT_VERSION_PATCH", vb[2]);
+ this->Makefile->AddDefinition(vv, vb[2]);
+ vv = args[0] + "_VERSION_TWEAK";
+ this->Makefile->AddDefinition("PROJECT_VERSION_TWEAK", vb[3]);
+ this->Makefile->AddDefinition(vv, vb[3]);
+ } else if (cmp0048 != cmPolicies::OLD) {
+ // Set project VERSION variables to empty
+ std::vector<std::string> vv;
+ vv.push_back("PROJECT_VERSION");
+ vv.push_back("PROJECT_VERSION_MAJOR");
+ vv.push_back("PROJECT_VERSION_MINOR");
+ vv.push_back("PROJECT_VERSION_PATCH");
+ vv.push_back("PROJECT_VERSION_TWEAK");
+ vv.push_back(args[0] + "_VERSION");
+ vv.push_back(args[0] + "_VERSION_MAJOR");
+ vv.push_back(args[0] + "_VERSION_MINOR");
+ vv.push_back(args[0] + "_VERSION_PATCH");
+ vv.push_back(args[0] + "_VERSION_TWEAK");
+ std::string vw;
+ for (std::vector<std::string>::iterator i = vv.begin(); i != vv.end();
+ ++i) {
+ const char* v = this->Makefile->GetDefinition(*i);
+ if (v && *v) {
+ if (cmp0048 == cmPolicies::WARN) {
+ vw += "\n ";
+ vw += *i;
+ } else {
+ this->Makefile->AddDefinition(*i, "");
+ }
+ }
+ }
+ if (!vw.empty()) {
+ std::ostringstream w;
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0048)
+ << "\nThe following variable(s) would be set to empty:" << vw;
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+ }
+ }
+
+ if (languages.empty()) {
+ // if no language is specified do c and c++
+ languages.push_back("C");
+ languages.push_back("CXX");
+ }
+ this->Makefile->EnableLanguage(languages, false);
+ std::string extraInclude = "CMAKE_PROJECT_" + args[0] + "_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;
+ }
+ }
+ return true;
+}
diff --git a/Source/cmProjectCommand.h b/Source/cmProjectCommand.h
new file mode 100644
index 0000000..3318df1
--- /dev/null
+++ b/Source/cmProjectCommand.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmProjectCommand_h
+#define cmProjectCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmProjectCommand
+ * \brief Specify the name for this build project.
+ *
+ * cmProjectCommand is used to specify a name for this build project.
+ * It is defined once per set of CMakeList.txt files (including
+ * all subdirectories). Currently it just sets the name of the workspace
+ * file for Microsoft Visual C++
+ */
+class cmProjectCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmProjectCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "project"; }
+
+ cmTypeMacro(cmProjectCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmProperty.cxx b/Source/cmProperty.cxx
new file mode 100644
index 0000000..133258f
--- /dev/null
+++ b/Source/cmProperty.cxx
@@ -0,0 +1,37 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmProperty.h"
+
+#include "cmSystemTools.h"
+
+void cmProperty::Set(const char* value)
+{
+ this->Value = value;
+ this->ValueHasBeenSet = true;
+}
+
+void cmProperty::Append(const char* value, bool asString)
+{
+ if (!this->Value.empty() && *value && !asString) {
+ this->Value += ";";
+ }
+ this->Value += value;
+ this->ValueHasBeenSet = true;
+}
+
+const char* cmProperty::GetValue() const
+{
+ if (this->ValueHasBeenSet) {
+ return this->Value.c_str();
+ }
+ return CM_NULLPTR;
+}
diff --git a/Source/cmProperty.h b/Source/cmProperty.h
new file mode 100644
index 0000000..1736136
--- /dev/null
+++ b/Source/cmProperty.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmProperty_h
+#define cmProperty_h
+
+#include "cmStandardIncludes.h"
+
+class cmProperty
+{
+public:
+ enum ScopeType
+ {
+ TARGET,
+ SOURCE_FILE,
+ DIRECTORY,
+ GLOBAL,
+ CACHE,
+ TEST,
+ VARIABLE,
+ CACHED_VARIABLE,
+ INSTALL
+ };
+
+ // set this property
+ void Set(const char* value);
+
+ // append to this property
+ void Append(const char* value, bool asString = false);
+
+ // get the value
+ const char* GetValue() const;
+
+ // construct with the value not set
+ cmProperty() { this->ValueHasBeenSet = false; }
+
+protected:
+ std::string Value;
+ bool ValueHasBeenSet;
+};
+
+#endif
diff --git a/Source/cmPropertyDefinition.cxx b/Source/cmPropertyDefinition.cxx
new file mode 100644
index 0000000..546146b
--- /dev/null
+++ b/Source/cmPropertyDefinition.cxx
@@ -0,0 +1,31 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmPropertyDefinition.h"
+
+#include "cmSystemTools.h"
+
+void cmPropertyDefinition::DefineProperty(const std::string& name,
+ cmProperty::ScopeType scope,
+ const char* shortDescription,
+ const char* fullDescription,
+ bool chain)
+{
+ this->Name = name;
+ this->Scope = scope;
+ this->Chained = chain;
+ if (shortDescription) {
+ this->ShortDescription = shortDescription;
+ }
+ if (fullDescription) {
+ this->FullDescription = fullDescription;
+ }
+}
diff --git a/Source/cmPropertyDefinition.h b/Source/cmPropertyDefinition.h
new file mode 100644
index 0000000..5733917
--- /dev/null
+++ b/Source/cmPropertyDefinition.h
@@ -0,0 +1,63 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmPropertyDefinition_h
+#define cmPropertyDefinition_h
+
+#include "cmProperty.h"
+
+/** \class cmPropertyDefinition
+ * \brief Property meta-information
+ *
+ * This class contains the following meta-information about property:
+ * - Name;
+ * - Various documentation strings;
+ * - The scope of the property;
+ * - If the property is chained.
+ */
+class cmPropertyDefinition
+{
+public:
+ /// Define this property
+ void DefineProperty(const std::string& name, cmProperty::ScopeType scope,
+ const char* ShortDescription,
+ const char* FullDescription, bool chained);
+
+ /// Default constructor
+ cmPropertyDefinition() { this->Chained = false; }
+
+ /// Is the property chained?
+ bool IsChained() const { return this->Chained; }
+
+ /// Get the scope
+ cmProperty::ScopeType GetScope() const { return this->Scope; }
+
+ /// Get the documentation (short version)
+ const std::string& GetShortDescription() const
+ {
+ return this->ShortDescription;
+ }
+
+ /// Get the documentation (full version)
+ const std::string& GetFullDescription() const
+ {
+ return this->FullDescription;
+ }
+
+protected:
+ std::string Name;
+ std::string ShortDescription;
+ std::string FullDescription;
+ cmProperty::ScopeType Scope;
+ bool Chained;
+};
+
+#endif
diff --git a/Source/cmPropertyDefinitionMap.cxx b/Source/cmPropertyDefinitionMap.cxx
new file mode 100644
index 0000000..0ba35e7
--- /dev/null
+++ b/Source/cmPropertyDefinitionMap.cxx
@@ -0,0 +1,45 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmPropertyDefinitionMap.h"
+
+#include "cmDocumentationSection.h"
+#include "cmSystemTools.h"
+
+void cmPropertyDefinitionMap::DefineProperty(const std::string& name,
+ cmProperty::ScopeType scope,
+ const char* ShortDescription,
+ const char* FullDescription,
+ bool chain)
+{
+ cmPropertyDefinitionMap::iterator it = this->find(name);
+ cmPropertyDefinition* prop;
+ if (it == this->end()) {
+ prop = &(*this)[name];
+ prop->DefineProperty(name, scope, ShortDescription, FullDescription,
+ chain);
+ }
+}
+
+bool cmPropertyDefinitionMap::IsPropertyDefined(const std::string& name) const
+{
+ return this->find(name) != this->end();
+}
+
+bool cmPropertyDefinitionMap::IsPropertyChained(const std::string& name) const
+{
+ cmPropertyDefinitionMap::const_iterator it = this->find(name);
+ if (it == this->end()) {
+ return false;
+ }
+
+ return it->second.IsChained();
+}
diff --git a/Source/cmPropertyDefinitionMap.h b/Source/cmPropertyDefinitionMap.h
new file mode 100644
index 0000000..fbc9a18
--- /dev/null
+++ b/Source/cmPropertyDefinitionMap.h
@@ -0,0 +1,35 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmPropertyDefinitionMap_h
+#define cmPropertyDefinitionMap_h
+
+#include "cmPropertyDefinition.h"
+
+class cmDocumentationSection;
+
+class cmPropertyDefinitionMap
+ : public std::map<std::string, cmPropertyDefinition>
+{
+public:
+ // define the property
+ void DefineProperty(const std::string& name, cmProperty::ScopeType scope,
+ const char* ShortDescription,
+ const char* FullDescription, bool chain);
+
+ // has a named property been defined
+ bool IsPropertyDefined(const std::string& name) const;
+
+ // is a named property set to chain
+ bool IsPropertyChained(const std::string& name) const;
+};
+
+#endif
diff --git a/Source/cmPropertyMap.cxx b/Source/cmPropertyMap.cxx
new file mode 100644
index 0000000..1e1ff91
--- /dev/null
+++ b/Source/cmPropertyMap.cxx
@@ -0,0 +1,76 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmPropertyMap.h"
+
+#include "cmState.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <algorithm>
+#include <assert.h>
+
+cmProperty* cmPropertyMap::GetOrCreateProperty(const std::string& name)
+{
+ cmPropertyMap::iterator it = this->find(name);
+ cmProperty* prop;
+ if (it == this->end()) {
+ prop = &(*this)[name];
+ } else {
+ prop = &(it->second);
+ }
+ return prop;
+}
+
+std::vector<std::string> cmPropertyMap::GetPropertyList() const
+{
+ std::vector<std::string> keyList;
+ for (cmPropertyMap::const_iterator i = this->begin(), e = this->end();
+ i != e; ++i) {
+ keyList.push_back(i->first);
+ }
+ std::sort(keyList.begin(), keyList.end());
+ return keyList;
+}
+
+void cmPropertyMap::SetProperty(const std::string& name, const char* value)
+{
+ if (!value) {
+ this->erase(name);
+ return;
+ }
+
+ cmProperty* prop = this->GetOrCreateProperty(name);
+ prop->Set(value);
+}
+
+void cmPropertyMap::AppendProperty(const std::string& name, const char* value,
+ bool asString)
+{
+ // Skip if nothing to append.
+ if (!value || !*value) {
+ return;
+ }
+
+ cmProperty* prop = this->GetOrCreateProperty(name);
+ prop->Append(value, asString);
+}
+
+const char* cmPropertyMap::GetPropertyValue(const std::string& name) const
+{
+ assert(!name.empty());
+
+ cmPropertyMap::const_iterator it = this->find(name);
+ if (it == this->end()) {
+ return CM_NULLPTR;
+ }
+ return it->second.GetValue();
+}
diff --git a/Source/cmPropertyMap.h b/Source/cmPropertyMap.h
new file mode 100644
index 0000000..6dc7bfb
--- /dev/null
+++ b/Source/cmPropertyMap.h
@@ -0,0 +1,32 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmPropertyMap_h
+#define cmPropertyMap_h
+
+#include "cmProperty.h"
+
+class cmPropertyMap : public std::map<std::string, cmProperty>
+{
+public:
+ cmProperty* GetOrCreateProperty(const std::string& name);
+
+ std::vector<std::string> GetPropertyList() const;
+
+ void SetProperty(const std::string& name, const char* value);
+
+ void AppendProperty(const std::string& name, const char* value,
+ bool asString = false);
+
+ const char* GetPropertyValue(const std::string& name) const;
+};
+
+#endif
diff --git a/Source/cmQTWrapCPPCommand.cxx b/Source/cmQTWrapCPPCommand.cxx
new file mode 100644
index 0000000..ef8255a
--- /dev/null
+++ b/Source/cmQTWrapCPPCommand.cxx
@@ -0,0 +1,93 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmQTWrapCPPCommand.h"
+
+// cmQTWrapCPPCommand
+bool cmQTWrapCPPCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Get the moc executable to run in the custom command.
+ const char* moc_exe =
+ this->Makefile->GetRequiredDefinition("QT_MOC_EXECUTABLE");
+
+ // Get the variable holding the list of sources.
+ std::string const& sourceList = args[1];
+ 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);
+ // 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 newName = this->Makefile->GetCurrentBinaryDirectory();
+ newName += "/moc_";
+ newName += srcName;
+ newName += ".cxx";
+ cmSourceFile* sf = this->Makefile->GetOrCreateSource(newName, true);
+ if (curr) {
+ sf->SetProperty("ABSTRACT", curr->GetProperty("ABSTRACT"));
+ }
+
+ // Compute the name of the header from which to generate the file.
+ std::string hname;
+ if (cmSystemTools::FileIsFullPath(j->c_str())) {
+ hname = *j;
+ } else {
+ if (curr && curr->GetPropertyAsBool("GENERATED")) {
+ hname = this->Makefile->GetCurrentBinaryDirectory();
+ } else {
+ hname = this->Makefile->GetCurrentSourceDirectory();
+ }
+ hname += "/";
+ hname += *j;
+ }
+
+ // Append the generated source file to the list.
+ if (!sourceListValue.empty()) {
+ sourceListValue += ";";
+ }
+ sourceListValue += newName;
+
+ // Create the custom command to generate the file.
+ cmCustomCommandLine commandLine;
+ commandLine.push_back(moc_exe);
+ commandLine.push_back("-o");
+ commandLine.push_back(newName);
+ commandLine.push_back(hname);
+
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(commandLine);
+
+ std::vector<std::string> depends;
+ depends.push_back(moc_exe);
+ depends.push_back(hname);
+
+ std::string no_main_dependency = "";
+ const char* no_working_dir = CM_NULLPTR;
+ this->Makefile->AddCustomCommandToOutput(
+ newName, depends, no_main_dependency, commandLines, "Qt Wrapped File",
+ no_working_dir);
+ }
+ }
+
+ // Store the final list of source files.
+ this->Makefile->AddDefinition(sourceList, sourceListValue.c_str());
+ return true;
+}
diff --git a/Source/cmQTWrapCPPCommand.h b/Source/cmQTWrapCPPCommand.h
new file mode 100644
index 0000000..78d5510
--- /dev/null
+++ b/Source/cmQTWrapCPPCommand.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmQTWrapCPPCommand_h
+#define cmQTWrapCPPCommand_h
+
+#include "cmCommand.h"
+
+#include "cmSourceFile.h"
+
+/** \class cmQTWrapCPPCommand
+ * \brief Create moc file rules for Qt classes
+ *
+ * cmQTWrapCPPCommand is used to create wrappers for Qt classes into
+ * normal C++
+ */
+class cmQTWrapCPPCommand : public cmCommand
+{
+public:
+ cmTypeMacro(cmQTWrapCPPCommand, cmCommand);
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmQTWrapCPPCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "qt_wrap_cpp"; }
+};
+
+#endif
diff --git a/Source/cmQTWrapUICommand.cxx b/Source/cmQTWrapUICommand.cxx
new file mode 100644
index 0000000..a948dd6
--- /dev/null
+++ b/Source/cmQTWrapUICommand.cxx
@@ -0,0 +1,137 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmQTWrapUICommand.h"
+
+// cmQTWrapUICommand
+bool cmQTWrapUICommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 4) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Get the uic and moc executables to run in the custom commands.
+ const char* uic_exe =
+ this->Makefile->GetRequiredDefinition("QT_UIC_EXECUTABLE");
+ const char* moc_exe =
+ this->Makefile->GetRequiredDefinition("QT_MOC_EXECUTABLE");
+
+ // Get the variable holding the list of sources.
+ std::string const& headerList = args[1];
+ std::string const& sourceList = args[2];
+ std::string headerListValue = this->Makefile->GetSafeDefinition(headerList);
+ 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);
+ // 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 hName = this->Makefile->GetCurrentBinaryDirectory();
+ hName += "/";
+ hName += srcName;
+ hName += ".h";
+ std::string cxxName = this->Makefile->GetCurrentBinaryDirectory();
+ cxxName += "/";
+ cxxName += srcName;
+ cxxName += ".cxx";
+ std::string mocName = this->Makefile->GetCurrentBinaryDirectory();
+ mocName += "/moc_";
+ mocName += srcName;
+ mocName += ".cxx";
+
+ // Compute the name of the ui file from which to generate others.
+ std::string uiName;
+ if (cmSystemTools::FileIsFullPath(j->c_str())) {
+ uiName = *j;
+ } else {
+ if (curr && curr->GetPropertyAsBool("GENERATED")) {
+ uiName = this->Makefile->GetCurrentBinaryDirectory();
+ } else {
+ uiName = this->Makefile->GetCurrentSourceDirectory();
+ }
+ uiName += "/";
+ uiName += *j;
+ }
+
+ // create the list of headers
+ if (!headerListValue.empty()) {
+ headerListValue += ";";
+ }
+ headerListValue += hName;
+
+ // create the list of sources
+ if (!sourceListValue.empty()) {
+ sourceListValue += ";";
+ }
+ sourceListValue += cxxName;
+ sourceListValue += ";";
+ sourceListValue += mocName;
+
+ // set up .ui to .h and .cxx command
+ cmCustomCommandLine hCommand;
+ hCommand.push_back(uic_exe);
+ hCommand.push_back("-o");
+ hCommand.push_back(hName);
+ hCommand.push_back(uiName);
+ cmCustomCommandLines hCommandLines;
+ hCommandLines.push_back(hCommand);
+
+ cmCustomCommandLine cxxCommand;
+ cxxCommand.push_back(uic_exe);
+ cxxCommand.push_back("-impl");
+ cxxCommand.push_back(hName);
+ cxxCommand.push_back("-o");
+ cxxCommand.push_back(cxxName);
+ cxxCommand.push_back(uiName);
+ cmCustomCommandLines cxxCommandLines;
+ cxxCommandLines.push_back(cxxCommand);
+
+ cmCustomCommandLine mocCommand;
+ mocCommand.push_back(moc_exe);
+ mocCommand.push_back("-o");
+ mocCommand.push_back(mocName);
+ mocCommand.push_back(hName);
+ cmCustomCommandLines mocCommandLines;
+ mocCommandLines.push_back(mocCommand);
+
+ std::vector<std::string> depends;
+ depends.push_back(uiName);
+ std::string no_main_dependency = "";
+ const char* no_comment = CM_NULLPTR;
+ const char* no_working_dir = CM_NULLPTR;
+ this->Makefile->AddCustomCommandToOutput(
+ hName, depends, no_main_dependency, hCommandLines, no_comment,
+ no_working_dir);
+
+ depends.push_back(hName);
+ this->Makefile->AddCustomCommandToOutput(
+ cxxName, depends, no_main_dependency, cxxCommandLines, no_comment,
+ no_working_dir);
+
+ depends.clear();
+ depends.push_back(hName);
+ this->Makefile->AddCustomCommandToOutput(
+ mocName, depends, no_main_dependency, mocCommandLines, no_comment,
+ no_working_dir);
+ }
+ }
+
+ // Store the final list of source files and headers.
+ this->Makefile->AddDefinition(sourceList, sourceListValue.c_str());
+ this->Makefile->AddDefinition(headerList, headerListValue.c_str());
+ return true;
+}
diff --git a/Source/cmQTWrapUICommand.h b/Source/cmQTWrapUICommand.h
new file mode 100644
index 0000000..a34a7bf
--- /dev/null
+++ b/Source/cmQTWrapUICommand.h
@@ -0,0 +1,46 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmQTWrapUICommand_h
+#define cmQTWrapUICommand_h
+
+#include "cmCommand.h"
+
+#include "cmSourceFile.h"
+
+/** \class cmQTWrapUICommand
+ * \brief Create .h and .cxx files rules for Qt user interfaces files
+ *
+ * cmQTWrapUICommand is used to create wrappers for Qt classes into normal C++
+ */
+class cmQTWrapUICommand : public cmCommand
+{
+public:
+ cmTypeMacro(cmQTWrapUICommand, cmCommand);
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmQTWrapUICommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "qt_wrap_ui"; }
+};
+
+#endif
diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx
new file mode 100644
index 0000000..4a63aad
--- /dev/null
+++ b/Source/cmQtAutoGeneratorInitializer.cxx
@@ -0,0 +1,1001 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2011 Kitware, Inc.
+ Copyright 2011 Alexander Neundorf (neundorf@kde.org)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmQtAutoGeneratorInitializer.h"
+
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+
+#include <sys/stat.h>
+
+#include <cmsys/FStream.hxx>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include "cmGlobalVisualStudioGenerator.h"
+#endif
+
+static std::string GetAutogenTargetName(cmGeneratorTarget const* target)
+{
+ std::string autogenTargetName = target->GetName();
+ autogenTargetName += "_automoc";
+ return autogenTargetName;
+}
+
+static std::string GetAutogenTargetDir(cmGeneratorTarget const* target)
+{
+ cmMakefile* makefile = target->Target->GetMakefile();
+ std::string targetDir = makefile->GetCurrentBinaryDirectory();
+ targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory();
+ targetDir += "/";
+ targetDir += GetAutogenTargetName(target);
+ targetDir += ".dir/";
+ return targetDir;
+}
+
+static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target)
+{
+ cmMakefile* makefile = target->Target->GetMakefile();
+ std::string targetDir = makefile->GetCurrentBinaryDirectory();
+ targetDir += "/";
+ targetDir += GetAutogenTargetName(target);
+ targetDir += ".dir/";
+ return targetDir;
+}
+
+static std::string GetSourceRelativePath(cmGeneratorTarget const* target,
+ const std::string& fileName)
+{
+ std::string pathRel;
+ // Test if the file is child to any of the known directories
+ {
+ const std::string fileNameReal = cmsys::SystemTools::GetRealPath(fileName);
+ std::string parentDirectory;
+ bool match(false);
+ {
+ std::string testDirs[4];
+ {
+ cmMakefile* makefile = target->Target->GetMakefile();
+ testDirs[0] = makefile->GetCurrentSourceDirectory();
+ testDirs[1] = makefile->GetCurrentBinaryDirectory();
+ testDirs[2] = makefile->GetHomeDirectory();
+ testDirs[3] = makefile->GetHomeOutputDirectory();
+ }
+ for (int ii = 0; ii != sizeof(testDirs) / sizeof(std::string); ++ii) {
+ const ::std::string testDir =
+ cmsys::SystemTools::GetRealPath(testDirs[ii]);
+ if (!testDir.empty() &&
+ cmsys::SystemTools::IsSubDirectory(fileNameReal, testDir)) {
+ parentDirectory = testDir;
+ match = true;
+ break;
+ }
+ }
+ }
+ // Use root as fallback parent directory
+ if (!match) {
+ cmsys::SystemTools::SplitPathRootComponent(fileNameReal,
+ &parentDirectory);
+ }
+ pathRel = cmsys::SystemTools::RelativePath(
+ parentDirectory, cmsys::SystemTools::GetParentDirectory(fileNameReal));
+ }
+ // Sanitize relative path
+ if (!pathRel.empty()) {
+ pathRel += '/';
+ cmSystemTools::ReplaceString(pathRel, "..", "__");
+ }
+ return pathRel;
+}
+
+static void SetupSourceFiles(cmGeneratorTarget const* target,
+ std::vector<std::string>& skipMoc,
+ std::vector<std::string>& mocSources,
+ std::vector<std::string>& mocHeaders,
+ std::vector<std::string>& skipUic)
+{
+ cmMakefile* makefile = target->Target->GetMakefile();
+
+ std::vector<cmSourceFile*> srcFiles;
+ target->GetConfigCommonSourceFiles(srcFiles);
+
+ std::vector<std::string> newRccFiles;
+
+ for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
+ fileIt != srcFiles.end(); ++fileIt) {
+ cmSourceFile* sf = *fileIt;
+ std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath());
+ bool skipFileForMoc =
+ cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC"));
+ bool generated = cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"));
+
+ if (cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOUIC"))) {
+ skipUic.push_back(absFile);
+ }
+
+ std::string ext = sf->GetExtension();
+
+ if (target->GetPropertyAsBool("AUTORCC")) {
+ if (ext == "qrc" &&
+ !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) {
+
+ std::string rcc_output_dir = GetAutogenTargetBuildDir(target);
+ rcc_output_dir += GetSourceRelativePath(target, absFile);
+ cmSystemTools::MakeDirectory(rcc_output_dir.c_str());
+
+ std::string basename =
+ cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile);
+
+ std::string rcc_output_file = rcc_output_dir;
+ rcc_output_file += "qrc_" + basename + ".cpp";
+ makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
+ rcc_output_file.c_str(), false);
+ makefile->GetOrCreateSource(rcc_output_file, true);
+ newRccFiles.push_back(rcc_output_file);
+ }
+ }
+
+ if (!generated) {
+ if (skipFileForMoc) {
+ skipMoc.push_back(absFile);
+ } else {
+ cmSystemTools::FileFormat fileType =
+ cmSystemTools::GetFileFormat(ext.c_str());
+ if (fileType == cmSystemTools::CXX_FILE_FORMAT) {
+ mocSources.push_back(absFile);
+ } else if (fileType == cmSystemTools::HEADER_FILE_FORMAT) {
+ mocHeaders.push_back(absFile);
+ }
+ }
+ }
+ }
+
+ for (std::vector<std::string>::const_iterator fileIt = newRccFiles.begin();
+ fileIt != newRccFiles.end(); ++fileIt) {
+ const_cast<cmGeneratorTarget*>(target)->AddSource(*fileIt);
+ }
+}
+
+static void GetCompileDefinitionsAndDirectories(
+ cmGeneratorTarget const* target, const std::string& config,
+ std::string& incs, std::string& defs)
+{
+ std::vector<std::string> includeDirs;
+ cmLocalGenerator* localGen = target->GetLocalGenerator();
+ // Get the include dirs for this target, without stripping the implicit
+ // include dirs off, see http://public.kitware.com/Bug/view.php?id=13667
+ localGen->GetIncludeDirectories(includeDirs, target, "CXX", config, false);
+
+ incs = cmJoin(includeDirs, ";");
+
+ std::set<std::string> defines;
+ localGen->AddCompileDefinitions(defines, target, config, "CXX");
+
+ defs += cmJoin(defines, ";");
+}
+
+static void SetupAutoMocTarget(
+ cmGeneratorTarget const* target, const std::string& autogenTargetName,
+ std::vector<std::string> const& skipMoc,
+ std::vector<std::string> const& mocHeaders,
+ std::map<std::string, std::string>& configIncludes,
+ std::map<std::string, std::string>& configDefines)
+{
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ cmMakefile* makefile = target->Target->GetMakefile();
+
+ const char* tmp = target->GetProperty("AUTOMOC_MOC_OPTIONS");
+ std::string _moc_options = (tmp != CM_NULLPTR ? tmp : "");
+ makefile->AddDefinition(
+ "_moc_options", cmOutputConverter::EscapeForCMake(_moc_options).c_str());
+ makefile->AddDefinition(
+ "_skip_moc",
+ cmOutputConverter::EscapeForCMake(cmJoin(skipMoc, ";")).c_str());
+ makefile->AddDefinition(
+ "_moc_headers",
+ cmOutputConverter::EscapeForCMake(cmJoin(mocHeaders, ";")).c_str());
+ bool relaxedMode = makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE");
+ makefile->AddDefinition("_moc_relaxed_mode", relaxedMode ? "TRUE" : "FALSE");
+
+ std::string _moc_incs;
+ std::string _moc_compile_defs;
+ std::vector<std::string> configs;
+ const std::string& config = makefile->GetConfigurations(configs);
+ GetCompileDefinitionsAndDirectories(target, config, _moc_incs,
+ _moc_compile_defs);
+
+ makefile->AddDefinition(
+ "_moc_incs", cmOutputConverter::EscapeForCMake(_moc_incs).c_str());
+ makefile->AddDefinition(
+ "_moc_compile_defs",
+ cmOutputConverter::EscapeForCMake(_moc_compile_defs).c_str());
+
+ for (std::vector<std::string>::const_iterator li = configs.begin();
+ li != configs.end(); ++li) {
+ std::string config_moc_incs;
+ std::string config_moc_compile_defs;
+ GetCompileDefinitionsAndDirectories(target, *li, config_moc_incs,
+ config_moc_compile_defs);
+ if (config_moc_incs != _moc_incs) {
+ configIncludes[*li] = cmOutputConverter::EscapeForCMake(config_moc_incs);
+ if (_moc_incs.empty()) {
+ _moc_incs = config_moc_incs;
+ }
+ }
+ if (config_moc_compile_defs != _moc_compile_defs) {
+ configDefines[*li] =
+ cmOutputConverter::EscapeForCMake(config_moc_compile_defs);
+ if (_moc_compile_defs.empty()) {
+ _moc_compile_defs = config_moc_compile_defs;
+ }
+ }
+ }
+
+ const char* qtVersion = makefile->GetDefinition("_target_qt_version");
+ if (strcmp(qtVersion, "5") == 0) {
+ cmGeneratorTarget* qt5Moc = lg->FindGeneratorTargetToUse("Qt5::moc");
+ if (!qt5Moc) {
+ cmSystemTools::Error("Qt5::moc target not found ",
+ autogenTargetName.c_str());
+ return;
+ }
+ makefile->AddDefinition("_qt_moc_executable",
+ qt5Moc->ImportedGetLocation(""));
+ } else if (strcmp(qtVersion, "4") == 0) {
+ cmGeneratorTarget* qt4Moc = lg->FindGeneratorTargetToUse("Qt4::moc");
+ if (!qt4Moc) {
+ cmSystemTools::Error("Qt4::moc target not found ",
+ autogenTargetName.c_str());
+ return;
+ }
+ makefile->AddDefinition("_qt_moc_executable",
+ qt4Moc->ImportedGetLocation(""));
+ } else {
+ cmSystemTools::Error("The CMAKE_AUTOMOC feature supports only Qt 4 and "
+ "Qt 5 ",
+ autogenTargetName.c_str());
+ }
+}
+
+static void GetUicOpts(cmGeneratorTarget const* target,
+ const std::string& config, std::string& optString)
+{
+ std::vector<std::string> opts;
+ target->GetAutoUicOptions(opts, config);
+ optString = cmJoin(opts, ";");
+}
+
+static void SetupAutoUicTarget(
+ cmGeneratorTarget const* target, std::vector<std::string> const& skipUic,
+ std::map<std::string, std::string>& configUicOptions)
+{
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ cmMakefile* makefile = target->Target->GetMakefile();
+
+ std::set<std::string> skipped;
+ skipped.insert(skipUic.begin(), skipUic.end());
+
+ makefile->AddDefinition(
+ "_skip_uic",
+ cmOutputConverter::EscapeForCMake(cmJoin(skipUic, ";")).c_str());
+
+ std::vector<cmSourceFile*> uiFilesWithOptions =
+ makefile->GetQtUiFilesWithOptions();
+
+ const char* qtVersion = makefile->GetDefinition("_target_qt_version");
+
+ std::string _uic_opts;
+ std::vector<std::string> configs;
+ const std::string& config = makefile->GetConfigurations(configs);
+ GetUicOpts(target, config, _uic_opts);
+
+ if (!_uic_opts.empty()) {
+ _uic_opts = cmOutputConverter::EscapeForCMake(_uic_opts);
+ makefile->AddDefinition("_uic_target_options", _uic_opts.c_str());
+ }
+ for (std::vector<std::string>::const_iterator li = configs.begin();
+ li != configs.end(); ++li) {
+ std::string config_uic_opts;
+ GetUicOpts(target, *li, config_uic_opts);
+ if (config_uic_opts != _uic_opts) {
+ configUicOptions[*li] =
+ cmOutputConverter::EscapeForCMake(config_uic_opts);
+ if (_uic_opts.empty()) {
+ _uic_opts = config_uic_opts;
+ }
+ }
+ }
+
+ std::string uiFileFiles;
+ std::string uiFileOptions;
+ const char* sep = "";
+
+ for (std::vector<cmSourceFile*>::const_iterator fileIt =
+ uiFilesWithOptions.begin();
+ fileIt != uiFilesWithOptions.end(); ++fileIt) {
+ cmSourceFile* sf = *fileIt;
+ std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath());
+
+ if (!skipped.insert(absFile).second) {
+ continue;
+ }
+ uiFileFiles += sep;
+ uiFileFiles += absFile;
+ uiFileOptions += sep;
+ std::string opts = sf->GetProperty("AUTOUIC_OPTIONS");
+ cmSystemTools::ReplaceString(opts, ";", "@list_sep@");
+ uiFileOptions += opts;
+ sep = ";";
+ }
+
+ makefile->AddDefinition(
+ "_qt_uic_options_files",
+ cmOutputConverter::EscapeForCMake(uiFileFiles).c_str());
+ makefile->AddDefinition(
+ "_qt_uic_options_options",
+ cmOutputConverter::EscapeForCMake(uiFileOptions).c_str());
+
+ std::string targetName = target->GetName();
+ if (strcmp(qtVersion, "5") == 0) {
+ cmGeneratorTarget* qt5Uic = lg->FindGeneratorTargetToUse("Qt5::uic");
+ if (!qt5Uic) {
+ // Project does not use Qt5Widgets, but has AUTOUIC ON anyway
+ } else {
+ makefile->AddDefinition("_qt_uic_executable",
+ qt5Uic->ImportedGetLocation(""));
+ }
+ } else if (strcmp(qtVersion, "4") == 0) {
+ cmGeneratorTarget* qt4Uic = lg->FindGeneratorTargetToUse("Qt4::uic");
+ if (!qt4Uic) {
+ cmSystemTools::Error("Qt4::uic target not found ", targetName.c_str());
+ return;
+ }
+ makefile->AddDefinition("_qt_uic_executable",
+ qt4Uic->ImportedGetLocation(""));
+ } else {
+ cmSystemTools::Error("The CMAKE_AUTOUIC feature supports only Qt 4 and "
+ "Qt 5 ",
+ targetName.c_str());
+ }
+}
+
+static std::string GetRccExecutable(cmGeneratorTarget const* target)
+{
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ cmMakefile* makefile = target->Target->GetMakefile();
+ const char* qtVersion = makefile->GetDefinition("_target_qt_version");
+ if (!qtVersion) {
+ qtVersion = makefile->GetDefinition("Qt5Core_VERSION_MAJOR");
+ if (!qtVersion) {
+ qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR");
+ }
+ if (const char* targetQtVersion =
+ target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION",
+ "")) {
+ qtVersion = targetQtVersion;
+ }
+ }
+
+ std::string targetName = target->GetName();
+ if (strcmp(qtVersion, "5") == 0) {
+ cmGeneratorTarget* qt5Rcc = lg->FindGeneratorTargetToUse("Qt5::rcc");
+ if (!qt5Rcc) {
+ cmSystemTools::Error("Qt5::rcc target not found ", targetName.c_str());
+ return std::string();
+ }
+ return qt5Rcc->ImportedGetLocation("");
+ } else if (strcmp(qtVersion, "4") == 0) {
+ cmGeneratorTarget* qt4Rcc = lg->FindGeneratorTargetToUse("Qt4::rcc");
+ if (!qt4Rcc) {
+ cmSystemTools::Error("Qt4::rcc target not found ", targetName.c_str());
+ return std::string();
+ }
+ return qt4Rcc->ImportedGetLocation("");
+ }
+
+ cmSystemTools::Error("The CMAKE_AUTORCC feature supports only Qt 4 and "
+ "Qt 5 ",
+ targetName.c_str());
+ return std::string();
+}
+
+static void MergeRccOptions(std::vector<std::string>& opts,
+ const std::vector<std::string>& fileOpts,
+ bool isQt5)
+{
+ static const char* valueOptions[] = { "name", "root", "compress",
+ "threshold" };
+ std::vector<std::string> extraOpts;
+ for (std::vector<std::string>::const_iterator it = fileOpts.begin();
+ it != fileOpts.end(); ++it) {
+ std::vector<std::string>::iterator existingIt =
+ std::find(opts.begin(), opts.end(), *it);
+ if (existingIt != opts.end()) {
+ const char* o = it->c_str();
+ if (*o == '-') {
+ ++o;
+ }
+ if (isQt5 && *o == '-') {
+ ++o;
+ }
+ if (std::find_if(cmArrayBegin(valueOptions), cmArrayEnd(valueOptions),
+ cmStrCmp(*it)) != cmArrayEnd(valueOptions)) {
+ assert(existingIt + 1 != opts.end());
+ *(existingIt + 1) = *(it + 1);
+ ++it;
+ }
+ } else {
+ extraOpts.push_back(*it);
+ }
+ }
+ opts.insert(opts.end(), extraOpts.begin(), extraOpts.end());
+}
+
+static void copyTargetProperty(cmTarget* destinationTarget,
+ cmTarget* sourceTarget,
+ const std::string& propertyName)
+{
+ const char* propertyValue = sourceTarget->GetProperty(propertyName);
+ if (propertyValue) {
+ destinationTarget->SetProperty(propertyName, propertyValue);
+ }
+}
+
+static std::string cmQtAutoGeneratorsStripCR(std::string const& line)
+{
+ // Strip CR characters rcc may have printed (possibly more than one!).
+ std::string::size_type cr = line.find('\r');
+ if (cr != line.npos) {
+ return line.substr(0, cr);
+ }
+ return line;
+}
+
+static std::string ReadAll(const std::string& filename)
+{
+ cmsys::ifstream file(filename.c_str());
+ std::ostringstream stream;
+ stream << file.rdbuf();
+ file.close();
+ return stream.str();
+}
+
+static std::string ListQt5RccInputs(cmSourceFile* sf,
+ cmGeneratorTarget const* target,
+ std::vector<std::string>& depends)
+{
+ std::string rccCommand = GetRccExecutable(target);
+
+ bool hasDashDashList = false;
+ {
+ std::vector<std::string> command;
+ command.push_back(rccCommand);
+ command.push_back("--help");
+ std::string rccStdOut;
+ std::string rccStdErr;
+ int retVal = 0;
+ bool result =
+ cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal,
+ CM_NULLPTR, cmSystemTools::OUTPUT_NONE);
+ if (result && retVal == 0 &&
+ rccStdOut.find("--list") != std::string::npos) {
+ hasDashDashList = true;
+ }
+ }
+
+ std::vector<std::string> qrcEntries;
+
+ std::vector<std::string> command;
+ command.push_back(rccCommand);
+ command.push_back(hasDashDashList ? "--list" : "-list");
+
+ std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath());
+
+ command.push_back(absFile);
+
+ std::string rccStdOut;
+ std::string rccStdErr;
+ int retVal = 0;
+ bool result =
+ cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal,
+ CM_NULLPTR, cmSystemTools::OUTPUT_NONE);
+ if (!result || retVal) {
+ std::ostringstream err;
+ err << "AUTOGEN: error: Rcc list process for " << sf->GetFullPath()
+ << " failed:\n"
+ << rccStdOut << "\n"
+ << rccStdErr << std::endl;
+ std::cerr << err.str();
+ return std::string();
+ }
+
+ {
+ std::istringstream ostr(rccStdOut);
+ std::string oline;
+ while (std::getline(ostr, oline)) {
+ oline = cmQtAutoGeneratorsStripCR(oline);
+ if (!oline.empty()) {
+ qrcEntries.push_back(oline);
+ }
+ }
+ }
+
+ {
+ std::istringstream estr(rccStdErr);
+ std::string eline;
+ while (std::getline(estr, eline)) {
+ eline = cmQtAutoGeneratorsStripCR(eline);
+ if (cmHasLiteralPrefix(eline, "RCC: Error in")) {
+ static std::string searchString = "Cannot find file '";
+
+ std::string::size_type pos = eline.find(searchString);
+ if (pos == std::string::npos) {
+ std::ostringstream err;
+ err << "AUTOGEN: error: Rcc lists unparsable output " << eline
+ << std::endl;
+ std::cerr << err.str();
+ return std::string();
+ }
+ pos += searchString.length();
+ std::string::size_type sz = eline.size() - pos - 1;
+ qrcEntries.push_back(eline.substr(pos, sz));
+ }
+ }
+ }
+
+ depends.insert(depends.end(), qrcEntries.begin(), qrcEntries.end());
+ return cmJoin(qrcEntries, "@list_sep@");
+}
+
+static std::string ListQt4RccInputs(cmSourceFile* sf,
+ std::vector<std::string>& depends)
+{
+ const std::string qrcContents = ReadAll(sf->GetFullPath());
+
+ cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
+
+ std::string entriesList;
+ const char* sep = "";
+
+ size_t offset = 0;
+ while (fileMatchRegex.find(qrcContents.c_str() + offset)) {
+ std::string qrcEntry = fileMatchRegex.match(1);
+
+ offset += qrcEntry.size();
+
+ cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
+ fileReplaceRegex.find(qrcEntry);
+ std::string tag = fileReplaceRegex.match(1);
+
+ qrcEntry = qrcEntry.substr(tag.size());
+
+ if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) {
+ qrcEntry = sf->GetLocation().GetDirectory() + "/" + qrcEntry;
+ }
+
+ entriesList += sep;
+ entriesList += qrcEntry;
+ sep = "@list_sep@";
+ depends.push_back(qrcEntry);
+ }
+ return entriesList;
+}
+
+static void SetupAutoRccTarget(cmGeneratorTarget const* target)
+{
+ std::string _rcc_files;
+ const char* sepRccFiles = "";
+ cmMakefile* makefile = target->Target->GetMakefile();
+
+ std::vector<cmSourceFile*> srcFiles;
+ target->GetConfigCommonSourceFiles(srcFiles);
+
+ std::string qrcInputs;
+ const char* qrcInputsSep = "";
+
+ std::string rccFileFiles;
+ std::string rccFileOptions;
+ const char* optionSep = "";
+
+ const char* qtVersion = makefile->GetDefinition("_target_qt_version");
+
+ std::vector<std::string> rccOptions;
+ if (const char* opts = target->GetProperty("AUTORCC_OPTIONS")) {
+ cmSystemTools::ExpandListArgument(opts, rccOptions);
+ }
+ std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
+ if (qtMajorVersion == "") {
+ qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
+ }
+
+ for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
+ fileIt != srcFiles.end(); ++fileIt) {
+ cmSourceFile* sf = *fileIt;
+ std::string ext = sf->GetExtension();
+ if (ext == "qrc") {
+ std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath());
+ bool skip = cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"));
+
+ if (!skip) {
+ _rcc_files += sepRccFiles;
+ _rcc_files += absFile;
+ sepRccFiles = ";";
+
+ if (const char* prop = sf->GetProperty("AUTORCC_OPTIONS")) {
+ std::vector<std::string> optsVec;
+ cmSystemTools::ExpandListArgument(prop, optsVec);
+ MergeRccOptions(rccOptions, optsVec, strcmp(qtVersion, "5") == 0);
+ }
+
+ if (!rccOptions.empty()) {
+ rccFileFiles += optionSep;
+ rccFileFiles += absFile;
+ rccFileOptions += optionSep;
+ }
+ const char* listSep = "";
+ for (std::vector<std::string>::const_iterator it = rccOptions.begin();
+ it != rccOptions.end(); ++it) {
+ rccFileOptions += listSep;
+ rccFileOptions += *it;
+ listSep = "@list_sep@";
+ }
+ optionSep = ";";
+
+ std::vector<std::string> depends;
+
+ std::string entriesList;
+ if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) {
+ if (qtMajorVersion == "5") {
+ entriesList = ListQt5RccInputs(sf, target, depends);
+ } else {
+ entriesList = ListQt4RccInputs(sf, depends);
+ }
+ if (entriesList.empty()) {
+ return;
+ }
+ }
+ qrcInputs += qrcInputsSep;
+ qrcInputs += entriesList;
+ qrcInputsSep = ";";
+ }
+ }
+ }
+ makefile->AddDefinition(
+ "_qt_rcc_inputs_" + target->GetName(),
+ cmOutputConverter::EscapeForCMake(qrcInputs).c_str());
+
+ makefile->AddDefinition(
+ "_rcc_files", cmOutputConverter::EscapeForCMake(_rcc_files).c_str());
+
+ makefile->AddDefinition(
+ "_qt_rcc_options_files",
+ cmOutputConverter::EscapeForCMake(rccFileFiles).c_str());
+ makefile->AddDefinition(
+ "_qt_rcc_options_options",
+ cmOutputConverter::EscapeForCMake(rccFileOptions).c_str());
+
+ makefile->AddDefinition("_qt_rcc_executable",
+ GetRccExecutable(target).c_str());
+}
+
+void cmQtAutoGeneratorInitializer::InitializeAutogenSources(
+ cmGeneratorTarget* target)
+{
+ cmMakefile* makefile = target->Target->GetMakefile();
+
+ if (target->GetPropertyAsBool("AUTOMOC")) {
+ std::string automocTargetName = GetAutogenTargetName(target);
+ std::string mocCppFile = makefile->GetCurrentBinaryDirectory();
+ mocCppFile += "/";
+ mocCppFile += automocTargetName;
+ mocCppFile += ".cpp";
+ makefile->GetOrCreateSource(mocCppFile, true);
+ makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", mocCppFile.c_str(),
+ false);
+
+ target->AddSource(mocCppFile);
+ }
+}
+
+void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
+ cmLocalGenerator* lg, cmGeneratorTarget* target)
+{
+ cmMakefile* makefile = target->Target->GetMakefile();
+
+ std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
+ if (qtMajorVersion == "") {
+ qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
+ }
+
+ // create a custom target for running generators at buildtime:
+ std::string autogenTargetName = GetAutogenTargetName(target);
+
+ std::string targetDir = GetAutogenTargetDir(target);
+
+ cmCustomCommandLine currentLine;
+ currentLine.push_back(cmSystemTools::GetCMakeCommand());
+ currentLine.push_back("-E");
+ currentLine.push_back("cmake_autogen");
+ currentLine.push_back(targetDir);
+ currentLine.push_back("$<CONFIGURATION>");
+
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(currentLine);
+
+ std::string workingDirectory =
+ cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory());
+
+ std::vector<std::string> depends;
+ if (const char* autogenDepends =
+ target->GetProperty("AUTOGEN_TARGET_DEPENDS")) {
+ cmSystemTools::ExpandListArgument(autogenDepends, depends);
+ }
+ std::vector<std::string> toolNames;
+ if (target->GetPropertyAsBool("AUTOMOC")) {
+ toolNames.push_back("moc");
+ }
+ if (target->GetPropertyAsBool("AUTOUIC")) {
+ toolNames.push_back("uic");
+ }
+ if (target->GetPropertyAsBool("AUTORCC")) {
+ toolNames.push_back("rcc");
+ }
+
+ std::string tools = toolNames[0];
+ toolNames.erase(toolNames.begin());
+ while (toolNames.size() > 1) {
+ tools += ", " + toolNames[0];
+ toolNames.erase(toolNames.begin());
+ }
+ if (toolNames.size() == 1) {
+ tools += " and " + toolNames[0];
+ }
+ std::string autogenComment = "Automatic " + tools + " for target ";
+ autogenComment += target->GetName();
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ bool usePRE_BUILD = false;
+ cmGlobalGenerator* gg = lg->GetGlobalGenerator();
+ if (gg->GetName().find("Visual Studio") != std::string::npos) {
+ cmGlobalVisualStudioGenerator* vsgg =
+ static_cast<cmGlobalVisualStudioGenerator*>(gg);
+ // Under VS >= 7 use a PRE_BUILD event instead of a separate target to
+ // reduce the number of targets loaded into the IDE.
+ // This also works around a VS 11 bug that may skip updating the target:
+ // https://connect.microsoft.com/VisualStudio/feedback/details/769495
+ usePRE_BUILD = vsgg->GetVersion() >= cmGlobalVisualStudioGenerator::VS7;
+ if (usePRE_BUILD) {
+ for (std::vector<std::string>::iterator it = depends.begin();
+ it != depends.end(); ++it) {
+ if (!makefile->FindTargetToUse(it->c_str())) {
+ usePRE_BUILD = false;
+ break;
+ }
+ }
+ }
+ }
+#endif
+
+ std::vector<std::string> rcc_output;
+ bool const isNinja = lg->GetGlobalGenerator()->GetName() == "Ninja";
+ if (isNinja
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ || usePRE_BUILD
+#endif
+ ) {
+ std::vector<cmSourceFile*> srcFiles;
+ target->GetConfigCommonSourceFiles(srcFiles);
+ for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
+ fileIt != srcFiles.end(); ++fileIt) {
+ cmSourceFile* sf = *fileIt;
+ std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath());
+
+ std::string ext = sf->GetExtension();
+
+ if (target->GetPropertyAsBool("AUTORCC")) {
+ if (ext == "qrc" &&
+ !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) {
+
+ {
+ std::string rcc_output_dir = GetAutogenTargetBuildDir(target);
+ rcc_output_dir += GetSourceRelativePath(target, absFile);
+ cmSystemTools::MakeDirectory(rcc_output_dir.c_str());
+
+ std::string basename =
+ cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile);
+ std::string rcc_output_file = rcc_output_dir;
+ rcc_output_file += "qrc_" + basename + ".cpp";
+ rcc_output.push_back(rcc_output_file);
+ }
+
+ if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) {
+ if (qtMajorVersion == "5") {
+ ListQt5RccInputs(sf, target, depends);
+ } else {
+ ListQt4RccInputs(sf, depends);
+ }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // Cannot use PRE_BUILD because the resource files themselves
+ // may not be sources within the target so VS may not know the
+ // target needs to re-build at all.
+ usePRE_BUILD = false;
+#endif
+ }
+ }
+ }
+ }
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (usePRE_BUILD) {
+ // Add the pre-build command directly to bypass the OBJECT_LIBRARY
+ // rejection in cmMakefile::AddCustomCommandToTarget because we know
+ // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case.
+ std::vector<std::string> no_output;
+ std::vector<std::string> no_byproducts;
+ cmCustomCommand cc(makefile, no_output, no_byproducts, depends,
+ commandLines, autogenComment.c_str(),
+ workingDirectory.c_str());
+ cc.SetEscapeOldStyle(false);
+ cc.SetEscapeAllowMakeVars(true);
+ target->Target->AddPreBuildCommand(cc);
+ } else
+#endif
+ {
+ cmTarget* autogenTarget = makefile->AddUtilityCommand(
+ autogenTargetName, true, workingDirectory.c_str(),
+ /*byproducts=*/rcc_output, depends, commandLines, false,
+ autogenComment.c_str());
+
+ cmGeneratorTarget* gt = new cmGeneratorTarget(autogenTarget, lg);
+ lg->AddGeneratorTarget(gt);
+
+ // Set target folder
+ const char* autogenFolder =
+ makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER");
+ if (!autogenFolder) {
+ autogenFolder =
+ makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER");
+ }
+ if (autogenFolder && *autogenFolder) {
+ autogenTarget->SetProperty("FOLDER", autogenFolder);
+ } else {
+ // inherit FOLDER property from target (#13688)
+ copyTargetProperty(gt->Target, target->Target, "FOLDER");
+ }
+
+ target->Target->AddUtility(autogenTargetName);
+ }
+}
+
+void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(
+ cmGeneratorTarget const* target)
+{
+ cmMakefile* makefile = target->Target->GetMakefile();
+
+ // forget the variables added here afterwards again:
+ cmMakefile::ScopePushPop varScope(makefile);
+ static_cast<void>(varScope);
+
+ // create a custom target for running generators at buildtime:
+ std::string autogenTargetName = GetAutogenTargetName(target);
+
+ makefile->AddDefinition(
+ "_moc_target_name",
+ cmOutputConverter::EscapeForCMake(autogenTargetName).c_str());
+ makefile->AddDefinition(
+ "_origin_target_name",
+ cmOutputConverter::EscapeForCMake(target->GetName()).c_str());
+
+ std::string targetDir = GetAutogenTargetDir(target);
+
+ const char* qtVersion = makefile->GetDefinition("Qt5Core_VERSION_MAJOR");
+ if (!qtVersion) {
+ qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR");
+ }
+ if (const char* targetQtVersion =
+ target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION",
+ "")) {
+ qtVersion = targetQtVersion;
+ }
+ if (qtVersion) {
+ makefile->AddDefinition("_target_qt_version", qtVersion);
+ }
+
+ std::vector<std::string> skipUic;
+ std::vector<std::string> skipMoc;
+ std::vector<std::string> mocSources;
+ std::vector<std::string> mocHeaders;
+ std::map<std::string, std::string> configIncludes;
+ std::map<std::string, std::string> configDefines;
+ std::map<std::string, std::string> configUicOptions;
+
+ if (target->GetPropertyAsBool("AUTOMOC") ||
+ target->GetPropertyAsBool("AUTOUIC") ||
+ target->GetPropertyAsBool("AUTORCC")) {
+ SetupSourceFiles(target, skipMoc, mocSources, mocHeaders, skipUic);
+ }
+ makefile->AddDefinition(
+ "_cpp_files",
+ cmOutputConverter::EscapeForCMake(cmJoin(mocSources, ";")).c_str());
+ if (target->GetPropertyAsBool("AUTOMOC")) {
+ SetupAutoMocTarget(target, autogenTargetName, skipMoc, mocHeaders,
+ configIncludes, configDefines);
+ }
+ if (target->GetPropertyAsBool("AUTOUIC")) {
+ SetupAutoUicTarget(target, skipUic, configUicOptions);
+ }
+ if (target->GetPropertyAsBool("AUTORCC")) {
+ SetupAutoRccTarget(target);
+ }
+
+ std::string inputFile = cmSystemTools::GetCMakeRoot();
+ inputFile += "/Modules/AutogenInfo.cmake.in";
+ std::string outputFile = targetDir;
+ outputFile += "/AutogenInfo.cmake";
+ makefile->AddDefinition(
+ "_qt_rcc_inputs",
+ makefile->GetDefinition("_qt_rcc_inputs_" + target->GetName()));
+ makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(), false, true,
+ false);
+
+ // Ensure we have write permission in case .in was read-only.
+ mode_t perm = 0;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ mode_t mode_write = S_IWRITE;
+#else
+ mode_t mode_write = S_IWUSR;
+#endif
+ cmSystemTools::GetPermissions(outputFile, perm);
+ if (!(perm & mode_write)) {
+ cmSystemTools::SetPermissions(outputFile, perm | mode_write);
+ }
+ if (!configDefines.empty() || !configIncludes.empty() ||
+ !configUicOptions.empty()) {
+ cmsys::ofstream infoFile(outputFile.c_str(), std::ios::app);
+ if (!infoFile) {
+ std::string error = "Internal CMake error when trying to open file: ";
+ error += outputFile;
+ error += " for writing.";
+ cmSystemTools::Error(error.c_str());
+ return;
+ }
+ if (!configDefines.empty()) {
+ for (std::map<std::string, std::string>::iterator
+ it = configDefines.begin(),
+ end = configDefines.end();
+ it != end; ++it) {
+ infoFile << "set(AM_MOC_COMPILE_DEFINITIONS_" << it->first << " "
+ << it->second << ")\n";
+ }
+ }
+ if (!configIncludes.empty()) {
+ for (std::map<std::string, std::string>::iterator
+ it = configIncludes.begin(),
+ end = configIncludes.end();
+ it != end; ++it) {
+ infoFile << "set(AM_MOC_INCLUDES_" << it->first << " " << it->second
+ << ")\n";
+ }
+ }
+ if (!configUicOptions.empty()) {
+ for (std::map<std::string, std::string>::iterator
+ it = configUicOptions.begin(),
+ end = configUicOptions.end();
+ it != end; ++it) {
+ infoFile << "set(AM_UIC_TARGET_OPTIONS_" << it->first << " "
+ << it->second << ")\n";
+ }
+ }
+ }
+}
diff --git a/Source/cmQtAutoGeneratorInitializer.h b/Source/cmQtAutoGeneratorInitializer.h
new file mode 100644
index 0000000..b411597
--- /dev/null
+++ b/Source/cmQtAutoGeneratorInitializer.h
@@ -0,0 +1,36 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2011 Kitware, Inc.
+ Copyright 2011 Alexander Neundorf (neundorf@kde.org)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmQtAutoGeneratorInitializer_h
+#define cmQtAutoGeneratorInitializer_h
+
+#include "cmStandardIncludes.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+class cmSourceFile;
+class cmGeneratorTarget;
+class cmLocalGenerator;
+
+class cmQtAutoGeneratorInitializer
+{
+public:
+ static void InitializeAutogenSources(cmGeneratorTarget* target);
+ static void InitializeAutogenTarget(cmLocalGenerator* lg,
+ cmGeneratorTarget* target);
+ static void SetupAutoGenerateTarget(cmGeneratorTarget const* target);
+};
+
+#endif
diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx
new file mode 100644
index 0000000..4b40c08
--- /dev/null
+++ b/Source/cmQtAutoGenerators.cxx
@@ -0,0 +1,1491 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2011 Kitware, Inc.
+ Copyright 2011 Alexander Neundorf (neundorf@kde.org)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmQtAutoGenerators.h"
+
+#include "cmAlgorithms.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmState.h"
+#include "cmSystemTools.h"
+
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Terminal.h>
+
+#include <string.h>
+#if defined(__APPLE__)
+#include <unistd.h>
+#endif
+
+static bool requiresMocing(const std::string& text, std::string& macroName)
+{
+ // this simple check is much much faster than the regexp
+ if (strstr(text.c_str(), "Q_OBJECT") == CM_NULLPTR &&
+ strstr(text.c_str(), "Q_GADGET") == CM_NULLPTR) {
+ return false;
+ }
+
+ cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]");
+ if (qObjectRegExp.find(text)) {
+ macroName = "Q_OBJECT";
+ return true;
+ }
+ cmsys::RegularExpression qGadgetRegExp("[\n][ \t]*Q_GADGET[^a-zA-Z0-9_]");
+ if (qGadgetRegExp.find(text)) {
+ macroName = "Q_GADGET";
+ return true;
+ }
+ return false;
+}
+
+static std::string findMatchingHeader(
+ const std::string& absPath, const std::string& mocSubDir,
+ const std::string& basename,
+ const std::vector<std::string>& headerExtensions)
+{
+ std::string header;
+ for (std::vector<std::string>::const_iterator ext = headerExtensions.begin();
+ ext != headerExtensions.end(); ++ext) {
+ std::string sourceFilePath = absPath + basename + "." + (*ext);
+ if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) {
+ header = sourceFilePath;
+ break;
+ }
+ if (!mocSubDir.empty()) {
+ sourceFilePath = mocSubDir + basename + "." + (*ext);
+ if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) {
+ header = sourceFilePath;
+ break;
+ }
+ }
+ }
+
+ return header;
+}
+
+static std::string extractSubDir(const std::string& absPath,
+ const std::string& currentMoc)
+{
+ std::string subDir;
+ if (currentMoc.find_first_of('/') != std::string::npos) {
+ subDir = absPath + cmsys::SystemTools::GetFilenamePath(currentMoc) + '/';
+ }
+ return subDir;
+}
+
+cmQtAutoGenerators::cmQtAutoGenerators()
+ : Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != CM_NULLPTR)
+ , ColorOutput(true)
+ , RunMocFailed(false)
+ , RunUicFailed(false)
+ , RunRccFailed(false)
+ , GenerateAll(false)
+{
+
+ std::string colorEnv = "";
+ cmsys::SystemTools::GetEnv("COLOR", colorEnv);
+ if (!colorEnv.empty()) {
+ if (cmSystemTools::IsOn(colorEnv.c_str())) {
+ this->ColorOutput = true;
+ } else {
+ this->ColorOutput = false;
+ }
+ }
+}
+
+void cmQtAutoGenerators::MergeUicOptions(
+ std::vector<std::string>& opts, const std::vector<std::string>& fileOpts,
+ bool isQt5)
+{
+ static const char* valueOptions[] = { "tr", "translate",
+ "postfix", "generator",
+ "include", // Since Qt 5.3
+ "g" };
+ std::vector<std::string> extraOpts;
+ for (std::vector<std::string>::const_iterator it = fileOpts.begin();
+ it != fileOpts.end(); ++it) {
+ std::vector<std::string>::iterator existingIt =
+ std::find(opts.begin(), opts.end(), *it);
+ if (existingIt != opts.end()) {
+ const char* o = it->c_str();
+ if (*o == '-') {
+ ++o;
+ }
+ if (isQt5 && *o == '-') {
+ ++o;
+ }
+ if (std::find_if(cmArrayBegin(valueOptions), cmArrayEnd(valueOptions),
+ cmStrCmp(*it)) != cmArrayEnd(valueOptions)) {
+ assert(existingIt + 1 != opts.end());
+ *(existingIt + 1) = *(it + 1);
+ ++it;
+ }
+ } else {
+ extraOpts.push_back(*it);
+ }
+ }
+ opts.insert(opts.end(), extraOpts.begin(), extraOpts.end());
+}
+
+bool cmQtAutoGenerators::Run(const std::string& targetDirectory,
+ const std::string& config)
+{
+ bool success = true;
+ cmake cm;
+ cm.SetHomeOutputDirectory(targetDirectory);
+ cm.SetHomeDirectory(targetDirectory);
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator gg(&cm);
+
+ cmState::Snapshot snapshot = cm.GetCurrentSnapshot();
+ snapshot.GetDirectory().SetCurrentBinary(targetDirectory);
+ snapshot.GetDirectory().SetCurrentSource(targetDirectory);
+
+ CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(&gg, snapshot));
+ gg.SetCurrentMakefile(mf.get());
+
+ this->ReadAutogenInfoFile(mf.get(), targetDirectory, config);
+ this->ReadOldMocDefinitionsFile(mf.get(), targetDirectory);
+
+ this->Init();
+
+ if (this->QtMajorVersion == "4" || this->QtMajorVersion == "5") {
+ success = this->RunAutogen(mf.get());
+ }
+
+ this->WriteOldMocDefinitionsFile(targetDirectory);
+
+ return success;
+}
+
+bool cmQtAutoGenerators::ReadAutogenInfoFile(
+ cmMakefile* makefile, const std::string& targetDirectory,
+ const std::string& config)
+{
+ std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
+ cmSystemTools::ConvertToUnixSlashes(filename);
+ filename += "/AutogenInfo.cmake";
+
+ if (!makefile->ReadListFile(filename.c_str())) {
+ cmSystemTools::Error("Error processing file: ", filename.c_str());
+ return false;
+ }
+
+ this->QtMajorVersion = makefile->GetSafeDefinition("AM_QT_VERSION_MAJOR");
+ if (this->QtMajorVersion == "") {
+ this->QtMajorVersion =
+ makefile->GetSafeDefinition("AM_Qt5Core_VERSION_MAJOR");
+ }
+ this->Sources = makefile->GetSafeDefinition("AM_SOURCES");
+ {
+ std::string rccSources = makefile->GetSafeDefinition("AM_RCC_SOURCES");
+ cmSystemTools::ExpandListArgument(rccSources, this->RccSources);
+ }
+ this->SkipMoc = makefile->GetSafeDefinition("AM_SKIP_MOC");
+ this->SkipUic = makefile->GetSafeDefinition("AM_SKIP_UIC");
+ this->Headers = makefile->GetSafeDefinition("AM_HEADERS");
+ this->IncludeProjectDirsBefore =
+ makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
+ this->Srcdir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_SOURCE_DIR");
+ this->Builddir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_BINARY_DIR");
+ this->MocExecutable = makefile->GetSafeDefinition("AM_QT_MOC_EXECUTABLE");
+ this->UicExecutable = makefile->GetSafeDefinition("AM_QT_UIC_EXECUTABLE");
+ this->RccExecutable = makefile->GetSafeDefinition("AM_QT_RCC_EXECUTABLE");
+ {
+ std::string compileDefsPropOrig = "AM_MOC_COMPILE_DEFINITIONS";
+ std::string compileDefsProp = compileDefsPropOrig;
+ if (!config.empty()) {
+ compileDefsProp += "_";
+ compileDefsProp += config;
+ }
+ const char* compileDefs = makefile->GetDefinition(compileDefsProp);
+ this->MocCompileDefinitionsStr = compileDefs
+ ? compileDefs
+ : makefile->GetSafeDefinition(compileDefsPropOrig);
+ }
+ {
+ std::string includesPropOrig = "AM_MOC_INCLUDES";
+ std::string includesProp = includesPropOrig;
+ if (!config.empty()) {
+ includesProp += "_";
+ includesProp += config;
+ }
+ const char* includes = makefile->GetDefinition(includesProp);
+ this->MocIncludesStr =
+ includes ? includes : makefile->GetSafeDefinition(includesPropOrig);
+ }
+ this->MocOptionsStr = makefile->GetSafeDefinition("AM_MOC_OPTIONS");
+ this->ProjectBinaryDir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR");
+ this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR");
+ this->TargetName = makefile->GetSafeDefinition("AM_TARGET_NAME");
+ this->OriginTargetName =
+ makefile->GetSafeDefinition("AM_ORIGIN_TARGET_NAME");
+
+ {
+ const char* uicOptionsFiles =
+ makefile->GetSafeDefinition("AM_UIC_OPTIONS_FILES");
+ std::string uicOptionsPropOrig = "AM_UIC_TARGET_OPTIONS";
+ std::string uicOptionsProp = uicOptionsPropOrig;
+ if (!config.empty()) {
+ uicOptionsProp += "_";
+ uicOptionsProp += config;
+ }
+ const char* uicTargetOptions = makefile->GetSafeDefinition(uicOptionsProp);
+ cmSystemTools::ExpandListArgument(
+ uicTargetOptions ? uicTargetOptions
+ : makefile->GetSafeDefinition(uicOptionsPropOrig),
+ this->UicTargetOptions);
+ const char* uicOptionsOptions =
+ makefile->GetSafeDefinition("AM_UIC_OPTIONS_OPTIONS");
+ std::vector<std::string> uicFilesVec;
+ cmSystemTools::ExpandListArgument(uicOptionsFiles, uicFilesVec);
+ std::vector<std::string> uicOptionsVec;
+ cmSystemTools::ExpandListArgument(uicOptionsOptions, uicOptionsVec);
+ if (uicFilesVec.size() != uicOptionsVec.size()) {
+ return false;
+ }
+ for (std::vector<std::string>::iterator fileIt = uicFilesVec.begin(),
+ optionIt = uicOptionsVec.begin();
+ fileIt != uicFilesVec.end(); ++fileIt, ++optionIt) {
+ cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";");
+ this->UicOptions[*fileIt] = *optionIt;
+ }
+ }
+ {
+ const char* rccOptionsFiles =
+ makefile->GetSafeDefinition("AM_RCC_OPTIONS_FILES");
+ const char* rccOptionsOptions =
+ makefile->GetSafeDefinition("AM_RCC_OPTIONS_OPTIONS");
+ std::vector<std::string> rccFilesVec;
+ cmSystemTools::ExpandListArgument(rccOptionsFiles, rccFilesVec);
+ std::vector<std::string> rccOptionsVec;
+ cmSystemTools::ExpandListArgument(rccOptionsOptions, rccOptionsVec);
+ if (rccFilesVec.size() != rccOptionsVec.size()) {
+ return false;
+ }
+ for (std::vector<std::string>::iterator fileIt = rccFilesVec.begin(),
+ optionIt = rccOptionsVec.begin();
+ fileIt != rccFilesVec.end(); ++fileIt, ++optionIt) {
+ cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";");
+ this->RccOptions[*fileIt] = *optionIt;
+ }
+
+ const char* rccInputs = makefile->GetSafeDefinition("AM_RCC_INPUTS");
+ std::vector<std::string> rccInputLists;
+ cmSystemTools::ExpandListArgument(rccInputs, rccInputLists);
+
+ if (this->RccSources.size() != rccInputLists.size()) {
+ cmSystemTools::Error("Error processing file: ", filename.c_str());
+ return false;
+ }
+
+ for (std::vector<std::string>::iterator fileIt = this->RccSources.begin(),
+ inputIt = rccInputLists.begin();
+ fileIt != this->RccSources.end(); ++fileIt, ++inputIt) {
+ cmSystemTools::ReplaceString(*inputIt, "@list_sep@", ";");
+ std::vector<std::string> rccInputFiles;
+ cmSystemTools::ExpandListArgument(*inputIt, rccInputFiles);
+
+ this->RccInputs[*fileIt] = rccInputFiles;
+ }
+ }
+ this->CurrentCompileSettingsStr = this->MakeCompileSettingsString(makefile);
+
+ this->RelaxedMode = makefile->IsOn("AM_RELAXED_MODE");
+
+ return true;
+}
+
+std::string cmQtAutoGenerators::MakeCompileSettingsString(cmMakefile* makefile)
+{
+ std::string s;
+ s += makefile->GetSafeDefinition("AM_MOC_COMPILE_DEFINITIONS");
+ s += " ~~~ ";
+ s += makefile->GetSafeDefinition("AM_MOC_INCLUDES");
+ s += " ~~~ ";
+ s += makefile->GetSafeDefinition("AM_MOC_OPTIONS");
+ s += " ~~~ ";
+ s += makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE") ? "TRUE"
+ : "FALSE";
+ s += " ~~~ ";
+
+ return s;
+}
+
+bool cmQtAutoGenerators::ReadOldMocDefinitionsFile(
+ cmMakefile* makefile, const std::string& targetDirectory)
+{
+ std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
+ cmSystemTools::ConvertToUnixSlashes(filename);
+ filename += "/AutomocOldMocDefinitions.cmake";
+
+ if (makefile->ReadListFile(filename.c_str())) {
+ this->OldCompileSettingsStr =
+ makefile->GetSafeDefinition("AM_OLD_COMPILE_SETTINGS");
+ }
+ return true;
+}
+
+void cmQtAutoGenerators::WriteOldMocDefinitionsFile(
+ const std::string& targetDirectory)
+{
+ std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
+ cmSystemTools::ConvertToUnixSlashes(filename);
+ filename += "/AutomocOldMocDefinitions.cmake";
+
+ cmsys::ofstream outfile;
+ outfile.open(filename.c_str(), std::ios::trunc);
+ outfile << "set(AM_OLD_COMPILE_SETTINGS "
+ << cmOutputConverter::EscapeForCMake(this->CurrentCompileSettingsStr)
+ << ")\n";
+
+ outfile.close();
+}
+
+void cmQtAutoGenerators::Init()
+{
+ this->TargetBuildSubDir = this->TargetName;
+ this->TargetBuildSubDir += ".dir/";
+
+ this->OutMocCppFilenameRel = this->TargetName;
+ this->OutMocCppFilenameRel += ".cpp";
+ this->OutMocCppFilenameAbs = this->Builddir + this->OutMocCppFilenameRel;
+
+ std::vector<std::string> cdefList;
+ cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList);
+ for (std::vector<std::string>::const_iterator it = cdefList.begin();
+ it != cdefList.end(); ++it) {
+ this->MocDefinitions.push_back("-D" + (*it));
+ }
+
+ cmSystemTools::ExpandListArgument(this->MocOptionsStr, this->MocOptions);
+
+ std::vector<std::string> incPaths;
+ cmSystemTools::ExpandListArgument(this->MocIncludesStr, incPaths);
+
+ std::set<std::string> frameworkPaths;
+ for (std::vector<std::string>::const_iterator it = incPaths.begin();
+ it != incPaths.end(); ++it) {
+ const std::string& path = *it;
+ this->MocIncludes.push_back("-I" + path);
+ if (cmHasLiteralSuffix(path, ".framework/Headers")) {
+ // Go up twice to get to the framework root
+ std::vector<std::string> pathComponents;
+ cmsys::SystemTools::SplitPath(path, pathComponents);
+ std::string frameworkPath = cmsys::SystemTools::JoinPath(
+ pathComponents.begin(), pathComponents.end() - 2);
+ frameworkPaths.insert(frameworkPath);
+ }
+ }
+
+ for (std::set<std::string>::const_iterator it = frameworkPaths.begin();
+ it != frameworkPaths.end(); ++it) {
+ this->MocIncludes.push_back("-F");
+ this->MocIncludes.push_back(*it);
+ }
+
+ if (this->IncludeProjectDirsBefore) {
+ const std::string binDir = "-I" + this->ProjectBinaryDir;
+
+ const std::string srcDir = "-I" + this->ProjectSourceDir;
+
+ std::list<std::string> sortedMocIncludes;
+ std::list<std::string>::iterator it = this->MocIncludes.begin();
+ while (it != this->MocIncludes.end()) {
+ if (cmsys::SystemTools::StringStartsWith(*it, binDir.c_str())) {
+ sortedMocIncludes.push_back(*it);
+ it = this->MocIncludes.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ it = this->MocIncludes.begin();
+ while (it != this->MocIncludes.end()) {
+ if (cmsys::SystemTools::StringStartsWith(*it, srcDir.c_str())) {
+ sortedMocIncludes.push_back(*it);
+ it = this->MocIncludes.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ sortedMocIncludes.insert(sortedMocIncludes.end(),
+ this->MocIncludes.begin(),
+ this->MocIncludes.end());
+ this->MocIncludes = sortedMocIncludes;
+ }
+}
+
+static std::string ReadAll(const std::string& filename)
+{
+ cmsys::ifstream file(filename.c_str());
+ std::ostringstream stream;
+ stream << file.rdbuf();
+ file.close();
+ return stream.str();
+}
+
+bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
+{
+ if (!cmsys::SystemTools::FileExists(this->OutMocCppFilenameAbs.c_str()) ||
+ (this->OldCompileSettingsStr != this->CurrentCompileSettingsStr)) {
+ this->GenerateAll = true;
+ }
+
+ // the program goes through all .cpp files to see which moc files are
+ // included. It is not really interesting how the moc file is named, but
+ // what file the moc is created from. Once a moc is included the same moc
+ // may not be included in the _automoc.cpp file anymore. OTOH if there's a
+ // header containing Q_OBJECT where no corresponding moc file is included
+ // anywhere a moc_<filename>.cpp file is created and included in
+ // the _automoc.cpp file.
+
+ // key = moc source filepath, value = moc output filepath
+ std::map<std::string, std::string> includedMocs;
+ // collect all headers which may need to be mocced
+ std::set<std::string> headerFiles;
+
+ std::vector<std::string> sourceFiles;
+ cmSystemTools::ExpandListArgument(this->Sources, sourceFiles);
+
+ const std::vector<std::string>& headerExtensions =
+ makefile->GetCMakeInstance()->GetHeaderExtensions();
+
+ std::map<std::string, std::vector<std::string> > includedUis;
+ std::map<std::string, std::vector<std::string> > skippedUis;
+ std::vector<std::string> uicSkipped;
+ cmSystemTools::ExpandListArgument(this->SkipUic, uicSkipped);
+
+ for (std::vector<std::string>::const_iterator it = sourceFiles.begin();
+ it != sourceFiles.end(); ++it) {
+ const bool skipUic =
+ std::find(uicSkipped.begin(), uicSkipped.end(), *it) != uicSkipped.end();
+ std::map<std::string, std::vector<std::string> >& uiFiles =
+ skipUic ? skippedUis : includedUis;
+ const std::string& absFilename = *it;
+ if (this->Verbose) {
+ std::ostringstream err;
+ err << "AUTOGEN: Checking " << absFilename << std::endl;
+ this->LogInfo(err.str());
+ }
+ if (this->RelaxedMode) {
+ this->ParseCppFile(absFilename, headerExtensions, includedMocs, uiFiles);
+ } else {
+ this->StrictParseCppFile(absFilename, headerExtensions, includedMocs,
+ uiFiles);
+ }
+ this->SearchHeadersForCppFile(absFilename, headerExtensions, headerFiles);
+ }
+
+ {
+ std::vector<std::string> mocSkipped;
+ cmSystemTools::ExpandListArgument(this->SkipMoc, mocSkipped);
+ for (std::vector<std::string>::const_iterator it = mocSkipped.begin();
+ it != mocSkipped.end(); ++it) {
+ if (std::find(uicSkipped.begin(), uicSkipped.end(), *it) !=
+ uicSkipped.end()) {
+ const std::string& absFilename = *it;
+ if (this->Verbose) {
+ std::ostringstream err;
+ err << "AUTOGEN: Checking " << absFilename << std::endl;
+ this->LogInfo(err.str());
+ }
+ this->ParseForUic(absFilename, includedUis);
+ }
+ }
+ }
+
+ std::vector<std::string> headerFilesVec;
+ cmSystemTools::ExpandListArgument(this->Headers, headerFilesVec);
+ headerFiles.insert(headerFilesVec.begin(), headerFilesVec.end());
+
+ // key = moc source filepath, value = moc output filename
+ std::map<std::string, std::string> notIncludedMocs;
+ this->ParseHeaders(headerFiles, includedMocs, notIncludedMocs, includedUis);
+
+ if (!this->MocExecutable.empty()) {
+ this->GenerateMocFiles(includedMocs, notIncludedMocs);
+ }
+ if (!this->UicExecutable.empty()) {
+ this->GenerateUiFiles(includedUis);
+ }
+ if (!this->RccExecutable.empty()) {
+ this->GenerateQrcFiles();
+ }
+
+ if (this->RunMocFailed) {
+ std::ostringstream err;
+ err << "moc failed..." << std::endl;
+ this->LogError(err.str());
+ return false;
+ }
+ if (this->RunUicFailed) {
+ std::ostringstream err;
+ err << "uic failed..." << std::endl;
+ this->LogError(err.str());
+ return false;
+ }
+ if (this->RunRccFailed) {
+ std::ostringstream err;
+ err << "rcc failed..." << std::endl;
+ this->LogError(err.str());
+ return false;
+ }
+
+ return true;
+}
+
+void cmQtAutoGenerators::ParseCppFile(
+ const std::string& absFilename,
+ const std::vector<std::string>& headerExtensions,
+ std::map<std::string, std::string>& includedMocs,
+ std::map<std::string, std::vector<std::string> >& includedUis)
+{
+ cmsys::RegularExpression mocIncludeRegExp(
+ "[\n][ \t]*#[ \t]*include[ \t]+"
+ "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
+
+ const std::string contentsString = ReadAll(absFilename);
+ if (contentsString.empty()) {
+ std::ostringstream err;
+ err << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
+ << std::endl;
+ this->LogError(err.str());
+ return;
+ }
+ this->ParseForUic(absFilename, contentsString, includedUis);
+ if (this->MocExecutable.empty()) {
+ return;
+ }
+
+ const std::string absPath = cmsys::SystemTools::GetFilenamePath(
+ cmsys::SystemTools::GetRealPath(absFilename)) +
+ '/';
+ const std::string scannedFileBasename =
+ cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
+ std::string macroName;
+ const bool requiresMoc = requiresMocing(contentsString, macroName);
+ bool dotMocIncluded = false;
+ bool mocUnderscoreIncluded = false;
+ std::string ownMocUnderscoreFile;
+ std::string ownDotMocFile;
+ std::string ownMocHeaderFile;
+
+ std::string::size_type matchOffset = 0;
+ // first a simple string check for "moc" is *much* faster than the regexp,
+ // and if the string search already fails, we don't have to try the
+ // expensive regexp
+ if ((strstr(contentsString.c_str(), "moc") != CM_NULLPTR) &&
+ (mocIncludeRegExp.find(contentsString))) {
+ // for every moc include in the file
+ do {
+ const std::string currentMoc = mocIncludeRegExp.match(1);
+
+ std::string basename =
+ cmsys::SystemTools::GetFilenameWithoutLastExtension(currentMoc);
+ const bool moc_style = cmHasLiteralPrefix(basename, "moc_");
+
+ // If the moc include is of the moc_foo.cpp style we expect
+ // the Q_OBJECT class declaration in a header file.
+ // If the moc include is of the foo.moc style we need to look for
+ // a Q_OBJECT macro in the current source file, if it contains the
+ // macro we generate the moc file from the source file.
+ // Q_OBJECT
+ if (moc_style) {
+ // basename should be the part of the moc filename used for
+ // finding the correct header, so we need to remove the moc_ part
+ basename = basename.substr(4);
+ std::string mocSubDir = extractSubDir(absPath, currentMoc);
+ std::string headerToMoc =
+ findMatchingHeader(absPath, mocSubDir, basename, headerExtensions);
+
+ if (!headerToMoc.empty()) {
+ includedMocs[headerToMoc] = currentMoc;
+ if (basename == scannedFileBasename) {
+ mocUnderscoreIncluded = true;
+ ownMocUnderscoreFile = currentMoc;
+ ownMocHeaderFile = headerToMoc;
+ }
+ } else {
+ std::ostringstream err;
+ err << "AUTOGEN: error: " << absFilename << ": The file "
+ << "includes the moc file \"" << currentMoc << "\", "
+ << "but could not find header \"" << basename << '{'
+ << this->JoinExts(headerExtensions) << "}\" ";
+ if (mocSubDir.empty()) {
+ err << "in " << absPath << "\n" << std::endl;
+ } else {
+ err << "neither in " << absPath << " nor in " << mocSubDir << "\n"
+ << std::endl;
+ }
+ this->LogError(err.str());
+ ::exit(EXIT_FAILURE);
+ }
+ } else {
+ std::string fileToMoc = absFilename;
+ if (!requiresMoc || basename != scannedFileBasename) {
+ std::string mocSubDir = extractSubDir(absPath, currentMoc);
+ std::string headerToMoc =
+ findMatchingHeader(absPath, mocSubDir, basename, headerExtensions);
+ if (!headerToMoc.empty()) {
+ // this is for KDE4 compatibility:
+ fileToMoc = headerToMoc;
+ if (!requiresMoc && basename == scannedFileBasename) {
+ std::ostringstream err;
+ err << "AUTOGEN: warning: " << absFilename
+ << ": The file "
+ "includes the moc file \""
+ << currentMoc << "\", but does not contain a " << macroName
+ << " macro. Running moc on "
+ << "\"" << headerToMoc << "\" ! Include \"moc_" << basename
+ << ".cpp\" for a compatibility with "
+ "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
+ << std::endl;
+ this->LogError(err.str());
+ } else {
+ std::ostringstream err;
+ err << "AUTOGEN: warning: " << absFilename
+ << ": The file "
+ "includes the moc file \""
+ << currentMoc << "\" instead of \"moc_" << basename
+ << ".cpp\". "
+ "Running moc on "
+ << "\"" << headerToMoc << "\" ! Include \"moc_" << basename
+ << ".cpp\" for compatibility with "
+ "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
+ << std::endl;
+ this->LogError(err.str());
+ }
+ } else {
+ std::ostringstream err;
+ err << "AUTOGEN: error: " << absFilename
+ << ": The file "
+ "includes the moc file \""
+ << currentMoc
+ << "\", which seems to be the moc file from a different "
+ "source file. CMake also could not find a matching "
+ "header.\n"
+ << std::endl;
+ this->LogError(err.str());
+ ::exit(EXIT_FAILURE);
+ }
+ } else {
+ dotMocIncluded = true;
+ ownDotMocFile = currentMoc;
+ }
+ includedMocs[fileToMoc] = currentMoc;
+ }
+ matchOffset += mocIncludeRegExp.end();
+ } while (mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
+ }
+
+ // 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.
+ if (!dotMocIncluded && requiresMoc) {
+ if (mocUnderscoreIncluded) {
+ // this is for KDE4 compatibility:
+ std::ostringstream err;
+ err << "AUTOGEN: warning: " << absFilename << ": The file "
+ << "contains a " << macroName << " macro, but does not "
+ "include "
+ << "\"" << scannedFileBasename << ".moc\", but instead "
+ "includes "
+ << "\"" << ownMocUnderscoreFile << "\". Running moc on "
+ << "\"" << absFilename << "\" ! Better include \""
+ << scannedFileBasename
+ << ".moc\" for compatibility with "
+ "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
+ << std::endl;
+ this->LogError(err.str());
+
+ includedMocs[absFilename] = ownMocUnderscoreFile;
+ includedMocs.erase(ownMocHeaderFile);
+ } else {
+ // otherwise always error out since it will not compile:
+ std::ostringstream err;
+ err << "AUTOGEN: error: " << absFilename << ": The file "
+ << "contains a " << macroName << " macro, but does not "
+ "include "
+ << "\"" << scannedFileBasename << ".moc\" !\n"
+ << std::endl;
+ this->LogError(err.str());
+
+ ::exit(EXIT_FAILURE);
+ }
+ }
+}
+
+void cmQtAutoGenerators::StrictParseCppFile(
+ const std::string& absFilename,
+ const std::vector<std::string>& headerExtensions,
+ std::map<std::string, std::string>& includedMocs,
+ std::map<std::string, std::vector<std::string> >& includedUis)
+{
+ cmsys::RegularExpression mocIncludeRegExp(
+ "[\n][ \t]*#[ \t]*include[ \t]+"
+ "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
+
+ const std::string contentsString = ReadAll(absFilename);
+ if (contentsString.empty()) {
+ std::ostringstream err;
+ err << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
+ << std::endl;
+ this->LogError(err.str());
+ return;
+ }
+ this->ParseForUic(absFilename, contentsString, includedUis);
+ if (this->MocExecutable.empty()) {
+ return;
+ }
+
+ const std::string absPath = cmsys::SystemTools::GetFilenamePath(
+ cmsys::SystemTools::GetRealPath(absFilename)) +
+ '/';
+ const std::string scannedFileBasename =
+ cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
+
+ bool dotMocIncluded = false;
+
+ std::string::size_type matchOffset = 0;
+ // first a simple string check for "moc" is *much* faster than the regexp,
+ // and if the string search already fails, we don't have to try the
+ // expensive regexp
+ if ((strstr(contentsString.c_str(), "moc") != CM_NULLPTR) &&
+ (mocIncludeRegExp.find(contentsString))) {
+ // for every moc include in the file
+ do {
+ const std::string currentMoc = mocIncludeRegExp.match(1);
+
+ std::string basename =
+ cmsys::SystemTools::GetFilenameWithoutLastExtension(currentMoc);
+ const bool mocUnderscoreStyle = cmHasLiteralPrefix(basename, "moc_");
+
+ // If the moc include is of the moc_foo.cpp style we expect
+ // the Q_OBJECT class declaration in a header file.
+ // If the moc include is of the foo.moc style we need to look for
+ // a Q_OBJECT macro in the current source file, if it contains the
+ // macro we generate the moc file from the source file.
+ if (mocUnderscoreStyle) {
+ // basename should be the part of the moc filename used for
+ // finding the correct header, so we need to remove the moc_ part
+ basename = basename.substr(4);
+ std::string mocSubDir = extractSubDir(absPath, currentMoc);
+ std::string headerToMoc =
+ findMatchingHeader(absPath, mocSubDir, basename, headerExtensions);
+
+ if (!headerToMoc.empty()) {
+ includedMocs[headerToMoc] = currentMoc;
+ } else {
+ std::ostringstream err;
+ err << "AUTOGEN: error: " << absFilename << " The file "
+ << "includes the moc file \"" << currentMoc << "\", "
+ << "but could not find header \"" << basename << '{'
+ << this->JoinExts(headerExtensions) << "}\" ";
+ if (mocSubDir.empty()) {
+ err << "in " << absPath << "\n" << std::endl;
+ } else {
+ err << "neither in " << absPath << " nor in " << mocSubDir << "\n"
+ << std::endl;
+ }
+ this->LogError(err.str());
+ ::exit(EXIT_FAILURE);
+ }
+ } else {
+ if (basename != scannedFileBasename) {
+ std::ostringstream err;
+ err << "AUTOGEN: error: " << absFilename
+ << ": The file "
+ "includes the moc file \""
+ << currentMoc
+ << "\", which seems to be the moc file from a different "
+ "source file. This is not supported. "
+ "Include \""
+ << scannedFileBasename << ".moc\" to run "
+ "moc on this source file.\n"
+ << std::endl;
+ this->LogError(err.str());
+ ::exit(EXIT_FAILURE);
+ }
+ dotMocIncluded = true;
+ includedMocs[absFilename] = currentMoc;
+ }
+ matchOffset += mocIncludeRegExp.end();
+ } while (mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
+ }
+
+ // 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.
+ std::string macroName;
+ if (!dotMocIncluded && requiresMocing(contentsString, macroName)) {
+ // otherwise always error out since it will not compile:
+ std::ostringstream err;
+ err << "AUTOGEN: error: " << absFilename << ": The file "
+ << "contains a " << macroName << " macro, but does not include "
+ << "\"" << scannedFileBasename << ".moc\" !\n"
+ << std::endl;
+ this->LogError(err.str());
+ ::exit(EXIT_FAILURE);
+ }
+}
+
+void cmQtAutoGenerators::ParseForUic(
+ const std::string& absFilename,
+ std::map<std::string, std::vector<std::string> >& includedUis)
+{
+ if (this->UicExecutable.empty()) {
+ return;
+ }
+ const std::string contentsString = ReadAll(absFilename);
+ if (contentsString.empty()) {
+ std::ostringstream err;
+ err << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
+ << std::endl;
+ this->LogError(err.str());
+ return;
+ }
+ this->ParseForUic(absFilename, contentsString, includedUis);
+}
+
+void cmQtAutoGenerators::ParseForUic(
+ const std::string& absFilename, const std::string& contentsString,
+ std::map<std::string, std::vector<std::string> >& includedUis)
+{
+ if (this->UicExecutable.empty()) {
+ return;
+ }
+ cmsys::RegularExpression uiIncludeRegExp(
+ "[\n][ \t]*#[ \t]*include[ \t]+"
+ "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
+
+ std::string::size_type matchOffset = 0;
+
+ const std::string realName = cmsys::SystemTools::GetRealPath(absFilename);
+
+ matchOffset = 0;
+ if ((strstr(contentsString.c_str(), "ui_") != CM_NULLPTR) &&
+ (uiIncludeRegExp.find(contentsString))) {
+ do {
+ const std::string currentUi = uiIncludeRegExp.match(1);
+
+ std::string basename =
+ cmsys::SystemTools::GetFilenameWithoutLastExtension(currentUi);
+
+ // basename should be the part of the ui filename used for
+ // finding the correct header, so we need to remove the ui_ part
+ basename = basename.substr(3);
+
+ includedUis[realName].push_back(basename);
+
+ matchOffset += uiIncludeRegExp.end();
+ } while (uiIncludeRegExp.find(contentsString.c_str() + matchOffset));
+ }
+}
+
+void cmQtAutoGenerators::SearchHeadersForCppFile(
+ const std::string& absFilename,
+ const std::vector<std::string>& headerExtensions,
+ std::set<std::string>& absHeaders)
+{
+ // search for header files and private header files we may need to moc:
+ const std::string basename =
+ cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
+ const std::string absPath = cmsys::SystemTools::GetFilenamePath(
+ cmsys::SystemTools::GetRealPath(absFilename)) +
+ '/';
+
+ for (std::vector<std::string>::const_iterator ext = headerExtensions.begin();
+ ext != headerExtensions.end(); ++ext) {
+ const std::string headerName = absPath + basename + "." + (*ext);
+ if (cmsys::SystemTools::FileExists(headerName.c_str())) {
+ absHeaders.insert(headerName);
+ break;
+ }
+ }
+ for (std::vector<std::string>::const_iterator ext = headerExtensions.begin();
+ ext != headerExtensions.end(); ++ext) {
+ const std::string privateHeaderName = absPath + basename + "_p." + (*ext);
+ if (cmsys::SystemTools::FileExists(privateHeaderName.c_str())) {
+ absHeaders.insert(privateHeaderName);
+ break;
+ }
+ }
+}
+
+void cmQtAutoGenerators::ParseHeaders(
+ const std::set<std::string>& absHeaders,
+ const std::map<std::string, std::string>& includedMocs,
+ std::map<std::string, std::string>& notIncludedMocs,
+ std::map<std::string, std::vector<std::string> >& includedUis)
+{
+ for (std::set<std::string>::const_iterator hIt = absHeaders.begin();
+ hIt != absHeaders.end(); ++hIt) {
+ const std::string& headerName = *hIt;
+ const std::string contents = ReadAll(headerName);
+
+ if (!this->MocExecutable.empty() &&
+ includedMocs.find(headerName) == includedMocs.end()) {
+ if (this->Verbose) {
+ std::ostringstream err;
+ err << "AUTOGEN: Checking " << headerName << std::endl;
+ this->LogInfo(err.str());
+ }
+
+ std::string macroName;
+ if (requiresMocing(contents, macroName)) {
+ const std::string parentDir =
+ this->TargetBuildSubDir + this->SourceRelativePath(headerName);
+ const std::string basename =
+ cmsys::SystemTools::GetFilenameWithoutLastExtension(headerName);
+ const std::string currentMoc = parentDir + "moc_" + basename + ".cpp";
+ notIncludedMocs[headerName] = currentMoc;
+ }
+ }
+ this->ParseForUic(headerName, contents, includedUis);
+ }
+}
+
+bool cmQtAutoGenerators::GenerateMocFiles(
+ const std::map<std::string, std::string>& includedMocs,
+ const std::map<std::string, std::string>& notIncludedMocs)
+{
+ // look for name collisions
+ {
+ std::multimap<std::string, std::string> collisions;
+ // Test merged map of included and notIncluded
+ std::map<std::string, std::string> mergedMocs(includedMocs);
+ mergedMocs.insert(notIncludedMocs.begin(), notIncludedMocs.end());
+ if (this->NameCollisionTest(mergedMocs, collisions)) {
+ std::ostringstream err;
+ err << "AUTOGEN: error: "
+ "The same moc file will be generated "
+ "from different sources."
+ << std::endl
+ << "To avoid this error either" << std::endl
+ << "- rename the source files or" << std::endl
+ << "- do not include the (moc_NAME.cpp|NAME.moc) file" << std::endl;
+ this->NameCollisionLog(err.str(), collisions);
+ ::exit(EXIT_FAILURE);
+ }
+ }
+
+ // generate moc files that are included by source files.
+ for (std::map<std::string, std::string>::const_iterator it =
+ includedMocs.begin();
+ it != includedMocs.end(); ++it) {
+ if (!this->GenerateMoc(it->first, it->second)) {
+ if (this->RunMocFailed) {
+ return false;
+ }
+ }
+ }
+
+ // generate moc files that are _not_ included by source files.
+ bool automocCppChanged = false;
+ for (std::map<std::string, std::string>::const_iterator it =
+ notIncludedMocs.begin();
+ it != notIncludedMocs.end(); ++it) {
+ if (this->GenerateMoc(it->first, it->second)) {
+ automocCppChanged = true;
+ } else {
+ if (this->RunMocFailed) {
+ return false;
+ }
+ }
+ }
+
+ // compose _automoc.cpp content
+ std::string automocSource;
+ {
+ std::ostringstream outStream;
+ outStream << "/* This file is autogenerated, do not edit*/\n";
+ if (notIncludedMocs.empty()) {
+ outStream << "enum some_compilers { need_more_than_nothing };\n";
+ } else {
+ for (std::map<std::string, std::string>::const_iterator it =
+ notIncludedMocs.begin();
+ it != notIncludedMocs.end(); ++it) {
+ outStream << "#include \"" << it->second << "\"\n";
+ }
+ }
+ outStream.flush();
+ automocSource = outStream.str();
+ }
+
+ // check if we even need to update _automoc.cpp
+ if (!automocCppChanged) {
+ // compare contents of the _automoc.cpp file
+ const std::string oldContents = ReadAll(this->OutMocCppFilenameAbs);
+ if (oldContents == automocSource) {
+ // nothing changed: don't touch the _automoc.cpp file
+ if (this->Verbose) {
+ std::ostringstream err;
+ err << "AUTOGEN: " << this->OutMocCppFilenameRel << " still up to date"
+ << std::endl;
+ this->LogInfo(err.str());
+ }
+ return true;
+ }
+ }
+
+ // actually write _automoc.cpp
+ {
+ std::string msg = "Generating moc compilation ";
+ msg += this->OutMocCppFilenameRel;
+ cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
+ cmsysTerminal_Color_ForegroundBold,
+ msg.c_str(), true, this->ColorOutput);
+ }
+ {
+ cmsys::ofstream outfile;
+ outfile.open(this->OutMocCppFilenameAbs.c_str(), std::ios::trunc);
+ outfile << automocSource;
+ outfile.close();
+ }
+
+ return true;
+}
+
+bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile,
+ const std::string& mocFileName)
+{
+ const std::string mocFilePath = this->Builddir + mocFileName;
+ int sourceNewerThanMoc = 0;
+ bool success = cmsys::SystemTools::FileTimeCompare(sourceFile, mocFilePath,
+ &sourceNewerThanMoc);
+ if (this->GenerateAll || !success || sourceNewerThanMoc >= 0) {
+ // make sure the directory for the resulting moc file exists
+ std::string mocDir = mocFilePath.substr(0, mocFilePath.rfind('/'));
+ if (!cmsys::SystemTools::FileExists(mocDir.c_str(), false)) {
+ cmsys::SystemTools::MakeDirectory(mocDir.c_str());
+ }
+
+ std::string msg = "Generating moc source ";
+ msg += mocFileName;
+ cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
+ cmsysTerminal_Color_ForegroundBold,
+ msg.c_str(), true, this->ColorOutput);
+
+ std::vector<std::string> command;
+ command.push_back(this->MocExecutable);
+ command.insert(command.end(), this->MocIncludes.begin(),
+ this->MocIncludes.end());
+ command.insert(command.end(), this->MocDefinitions.begin(),
+ this->MocDefinitions.end());
+ command.insert(command.end(), this->MocOptions.begin(),
+ this->MocOptions.end());
+#ifdef _WIN32
+ command.push_back("-DWIN32");
+#endif
+ command.push_back("-o");
+ command.push_back(mocFilePath);
+ command.push_back(sourceFile);
+
+ if (this->Verbose) {
+ this->LogCommand(command);
+ }
+
+ std::string output;
+ int retVal = 0;
+ bool result =
+ cmSystemTools::RunSingleCommand(command, &output, &output, &retVal);
+ if (!result || retVal) {
+ std::ostringstream err;
+ err << "AUTOGEN: error: process for " << mocFilePath << " failed:\n"
+ << output << std::endl;
+ this->LogError(err.str());
+ this->RunMocFailed = true;
+ cmSystemTools::RemoveFile(mocFilePath);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool cmQtAutoGenerators::GenerateUiFiles(
+ const std::map<std::string, std::vector<std::string> >& includedUis)
+{
+ // single map with input / output names
+ std::map<std::string, std::map<std::string, std::string> > uiGenMap;
+ std::map<std::string, std::string> testMap;
+ for (std::map<std::string, std::vector<std::string> >::const_iterator it =
+ includedUis.begin();
+ it != includedUis.end(); ++it) {
+ // source file path
+ std::string sourcePath = cmsys::SystemTools::GetFilenamePath(it->first);
+ sourcePath += '/';
+ // insert new map for source file an use new reference
+ uiGenMap[it->first] = std::map<std::string, std::string>();
+ std::map<std::string, std::string>& sourceMap = uiGenMap[it->first];
+ for (std::vector<std::string>::const_iterator sit = it->second.begin();
+ sit != it->second.end(); ++sit) {
+ const std::string& uiFileName = *sit;
+ const std::string uiInputFile = sourcePath + uiFileName + ".ui";
+ const std::string uiOutputFile = "ui_" + uiFileName + ".h";
+ sourceMap[uiInputFile] = uiOutputFile;
+ testMap[uiInputFile] = uiOutputFile;
+ }
+ }
+
+ // look for name collisions
+ {
+ std::multimap<std::string, std::string> collisions;
+ if (this->NameCollisionTest(testMap, collisions)) {
+ std::ostringstream err;
+ err << "AUTOGEN: error: The same ui_NAME.h file will be generated "
+ "from different sources."
+ << std::endl
+ << "To avoid this error rename the source files." << std::endl;
+ this->NameCollisionLog(err.str(), collisions);
+ ::exit(EXIT_FAILURE);
+ }
+ }
+ testMap.clear();
+
+ // generate ui files
+ for (std::map<std::string,
+ std::map<std::string, std::string> >::const_iterator it =
+ uiGenMap.begin();
+ it != uiGenMap.end(); ++it) {
+ for (std::map<std::string, std::string>::const_iterator sit =
+ it->second.begin();
+ sit != it->second.end(); ++sit) {
+ if (!this->GenerateUi(it->first, sit->first, sit->second)) {
+ if (this->RunUicFailed) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmQtAutoGenerators::GenerateUi(const std::string& realName,
+ const std::string& uiInputFile,
+ const std::string& uiOutputFile)
+{
+ if (!cmsys::SystemTools::FileExists(this->Builddir.c_str(), false)) {
+ cmsys::SystemTools::MakeDirectory(this->Builddir.c_str());
+ }
+
+ const ::std::string uiBuildFile = this->Builddir + uiOutputFile;
+
+ int sourceNewerThanUi = 0;
+ bool success = cmsys::SystemTools::FileTimeCompare(uiInputFile, uiBuildFile,
+ &sourceNewerThanUi);
+ if (this->GenerateAll || !success || sourceNewerThanUi >= 0) {
+ std::string msg = "Generating ui header ";
+ msg += uiOutputFile;
+ cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
+ cmsysTerminal_Color_ForegroundBold,
+ msg.c_str(), true, this->ColorOutput);
+
+ std::vector<std::string> command;
+ command.push_back(this->UicExecutable);
+
+ std::vector<std::string> opts = this->UicTargetOptions;
+ std::map<std::string, std::string>::const_iterator optionIt =
+ this->UicOptions.find(uiInputFile);
+ if (optionIt != this->UicOptions.end()) {
+ std::vector<std::string> fileOpts;
+ cmSystemTools::ExpandListArgument(optionIt->second, fileOpts);
+ cmQtAutoGenerators::MergeUicOptions(opts, fileOpts,
+ this->QtMajorVersion == "5");
+ }
+ command.insert(command.end(), opts.begin(), opts.end());
+
+ command.push_back("-o");
+ command.push_back(uiBuildFile);
+ command.push_back(uiInputFile);
+
+ if (this->Verbose) {
+ this->LogCommand(command);
+ }
+ std::string output;
+ int retVal = 0;
+ bool result =
+ cmSystemTools::RunSingleCommand(command, &output, &output, &retVal);
+ if (!result || retVal) {
+ std::ostringstream err;
+ err << "AUTOUIC: error: process for " << uiOutputFile
+ << " needed by\n \"" << realName << "\"\nfailed:\n"
+ << output << std::endl;
+ this->LogError(err.str());
+ this->RunUicFailed = true;
+ cmSystemTools::RemoveFile(uiOutputFile);
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool cmQtAutoGenerators::InputFilesNewerThanQrc(const std::string& qrcFile,
+ const std::string& rccOutput)
+{
+ std::vector<std::string> const& files = this->RccInputs[qrcFile];
+ for (std::vector<std::string>::const_iterator it = files.begin();
+ it != files.end(); ++it) {
+ int inputNewerThanQrc = 0;
+ bool success =
+ cmsys::SystemTools::FileTimeCompare(*it, rccOutput, &inputNewerThanQrc);
+ if (!success || inputNewerThanQrc >= 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmQtAutoGenerators::GenerateQrcFiles()
+{
+ // generate single map with input / output names
+ std::map<std::string, std::string> qrcGenMap;
+ for (std::vector<std::string>::const_iterator si = this->RccSources.begin();
+ si != this->RccSources.end(); ++si) {
+ const std::string ext = cmsys::SystemTools::GetFilenameLastExtension(*si);
+ if (ext == ".qrc") {
+ std::string basename =
+ cmsys::SystemTools::GetFilenameWithoutLastExtension(*si);
+ std::string qrcOutputFile = this->TargetBuildSubDir +
+ this->SourceRelativePath(*si) + "qrc_" + basename + ".cpp";
+ // std::string qrcOutputFile = "CMakeFiles/" + this->OriginTargetName
+ // + ".dir/qrc_" + basename + ".cpp";
+ qrcGenMap[*si] = qrcOutputFile;
+ }
+ }
+
+ // look for name collisions
+ {
+ std::multimap<std::string, std::string> collisions;
+ if (this->NameCollisionTest(qrcGenMap, collisions)) {
+ std::ostringstream err;
+ err << "AUTOGEN: error: The same qrc_NAME.cpp file"
+ " will be generated from different sources."
+ << std::endl
+ << "To avoid this error rename the source .qrc files." << std::endl;
+ this->NameCollisionLog(err.str(), collisions);
+ ::exit(EXIT_FAILURE);
+ }
+ }
+
+ // generate qrc files
+ for (std::map<std::string, std::string>::const_iterator si =
+ qrcGenMap.begin();
+ si != qrcGenMap.end(); ++si) {
+ if (!this->GenerateQrc(si->first, si->second)) {
+ if (this->RunRccFailed) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile,
+ const std::string& qrcOutputFile)
+{
+ std::string relName = this->SourceRelativePath(qrcInputFile);
+ std::replace(relName.begin(), relName.end(), '/', '_');
+ relName += cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile);
+
+ const ::std::string qrcBuildFile = this->Builddir + qrcOutputFile;
+
+ int sourceNewerThanQrc = 0;
+ bool generateQrc = !cmsys::SystemTools::FileTimeCompare(
+ qrcInputFile, qrcBuildFile, &sourceNewerThanQrc);
+ generateQrc = generateQrc || (sourceNewerThanQrc >= 0);
+ generateQrc =
+ generateQrc || this->InputFilesNewerThanQrc(qrcInputFile, qrcBuildFile);
+
+ if (this->GenerateAll || generateQrc) {
+ std::string msg = "Generating qrc source ";
+ msg += qrcOutputFile;
+ cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
+ cmsysTerminal_Color_ForegroundBold,
+ msg.c_str(), true, this->ColorOutput);
+
+ std::vector<std::string> command;
+ command.push_back(this->RccExecutable);
+
+ std::map<std::string, std::string>::const_iterator optionIt =
+ this->RccOptions.find(qrcInputFile);
+ if (optionIt != this->RccOptions.end()) {
+ cmSystemTools::ExpandListArgument(optionIt->second, command);
+ }
+
+ command.push_back("-name");
+ command.push_back(relName);
+ command.push_back("-o");
+ command.push_back(qrcBuildFile);
+ command.push_back(qrcInputFile);
+
+ if (this->Verbose) {
+ this->LogCommand(command);
+ }
+ std::string output;
+ int retVal = 0;
+ bool result =
+ cmSystemTools::RunSingleCommand(command, &output, &output, &retVal);
+ if (!result || retVal) {
+ std::ostringstream err;
+ err << "AUTORCC: error: process for " << qrcOutputFile << " failed:\n"
+ << output << std::endl;
+ this->LogError(err.str());
+ this->RunRccFailed = true;
+ cmSystemTools::RemoveFile(qrcBuildFile);
+ return false;
+ }
+ }
+ return true;
+}
+
+std::string cmQtAutoGenerators::SourceRelativePath(const std::string& filename)
+{
+ std::string pathRel;
+
+ // Test if the file is child to any of the known directories
+ {
+ std::string fileNameReal = cmsys::SystemTools::GetRealPath(filename);
+ std::string parentDirectory;
+ bool match(false);
+ {
+ const ::std::string* testDirs[4];
+ testDirs[0] = &(this->Srcdir);
+ testDirs[1] = &(this->Builddir);
+ testDirs[2] = &(this->ProjectSourceDir);
+ testDirs[3] = &(this->ProjectBinaryDir);
+ for (int ii = 0; ii != sizeof(testDirs) / sizeof(const ::std::string*);
+ ++ii) {
+ const ::std::string testDir =
+ cmsys::SystemTools::GetRealPath(*(testDirs[ii]));
+ if (cmsys::SystemTools::IsSubDirectory(fileNameReal, testDir)) {
+ parentDirectory = testDir;
+ match = true;
+ break;
+ }
+ }
+ }
+ // Use root as fallback parent directory
+ if (!match) {
+ cmsys::SystemTools::SplitPathRootComponent(fileNameReal,
+ &parentDirectory);
+ }
+ pathRel = cmsys::SystemTools::RelativePath(
+ parentDirectory, cmsys::SystemTools::GetParentDirectory(fileNameReal));
+ }
+
+ // Sanitize relative path
+ if (!pathRel.empty()) {
+ pathRel += '/';
+ cmSystemTools::ReplaceString(pathRel, "..", "__");
+ }
+ return pathRel;
+}
+
+/**
+ * @brief Collects name collisions as output/input pairs
+ * @return True if there were collisions
+ */
+bool cmQtAutoGenerators::NameCollisionTest(
+ const std::map<std::string, std::string>& genFiles,
+ std::multimap<std::string, std::string>& collisions)
+{
+ typedef std::map<std::string, std::string>::const_iterator Iter;
+ typedef std::map<std::string, std::string>::value_type VType;
+ for (Iter ait = genFiles.begin(); ait != genFiles.end(); ++ait) {
+ bool first_match(true);
+ for (Iter bit = (++Iter(ait)); bit != genFiles.end(); ++bit) {
+ if (ait->second == bit->second) {
+ if (first_match) {
+ if (collisions.find(ait->second) != collisions.end()) {
+ // We already know of this collision from before
+ break;
+ }
+ collisions.insert(VType(ait->second, ait->first));
+ first_match = false;
+ }
+ collisions.insert(VType(bit->second, bit->first));
+ }
+ }
+ }
+
+ return !collisions.empty();
+}
+
+void cmQtAutoGenerators::NameCollisionLog(
+ const std::string& message,
+ const std::multimap<std::string, std::string>& collisions)
+{
+ typedef std::multimap<std::string, std::string>::const_iterator Iter;
+
+ std::ostringstream err;
+ // Add message
+ err << message;
+ // Append collision list
+ for (Iter it = collisions.begin(); it != collisions.end(); ++it) {
+ err << it->first << " : " << it->second << std::endl;
+ }
+ this->LogError(err.str());
+}
+
+void cmQtAutoGenerators::LogInfo(const std::string& message)
+{
+ std::cout << message;
+}
+
+void cmQtAutoGenerators::LogError(const std::string& message)
+{
+ std::cerr << message;
+}
+
+void cmQtAutoGenerators::LogCommand(const std::vector<std::string>& command)
+{
+ std::ostringstream sbuf;
+ for (std::vector<std::string>::const_iterator cmdIt = command.begin();
+ cmdIt != command.end(); ++cmdIt) {
+ if (cmdIt != command.begin()) {
+ sbuf << " ";
+ }
+ sbuf << *cmdIt;
+ }
+ if (!sbuf.str().empty()) {
+ sbuf << std::endl;
+ this->LogInfo(sbuf.str());
+ }
+}
+
+std::string cmQtAutoGenerators::JoinExts(const std::vector<std::string>& lst)
+{
+ if (lst.empty()) {
+ return "";
+ }
+
+ std::string result;
+ std::string separator = ",";
+ for (std::vector<std::string>::const_iterator it = lst.begin();
+ it != lst.end(); ++it) {
+ if (it != lst.begin()) {
+ result += separator;
+ }
+ result += '.' + (*it);
+ }
+ result.erase(result.end() - 1);
+ return result;
+}
diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h
new file mode 100644
index 0000000..5e7fab5
--- /dev/null
+++ b/Source/cmQtAutoGenerators.h
@@ -0,0 +1,149 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2011 Kitware, Inc.
+ Copyright 2011 Alexander Neundorf (neundorf@kde.org)
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmQtAutoGenerators_h
+#define cmQtAutoGenerators_h
+
+#include "cmStandardIncludes.h"
+
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+class cmMakefile;
+
+class cmQtAutoGenerators
+{
+public:
+ cmQtAutoGenerators();
+ bool Run(const std::string& targetDirectory, const std::string& config);
+
+private:
+ bool ReadAutogenInfoFile(cmMakefile* makefile,
+ const std::string& targetDirectory,
+ const std::string& config);
+ bool ReadOldMocDefinitionsFile(cmMakefile* makefile,
+ const std::string& targetDirectory);
+ void WriteOldMocDefinitionsFile(const std::string& targetDirectory);
+
+ std::string MakeCompileSettingsString(cmMakefile* makefile);
+
+ bool RunAutogen(cmMakefile* makefile);
+ bool GenerateMocFiles(
+ const std::map<std::string, std::string>& includedMocs,
+ const std::map<std::string, std::string>& notIncludedMocs);
+ bool GenerateMoc(const std::string& sourceFile,
+ const std::string& mocFileName);
+ bool GenerateUiFiles(
+ const std::map<std::string, std::vector<std::string> >& includedUis);
+ bool GenerateUi(const std::string& realName, const std::string& uiInputFile,
+ const std::string& uiOutputFile);
+ bool GenerateQrcFiles();
+ bool GenerateQrc(const std::string& qrcInputFile,
+ const std::string& qrcOutputFile);
+ void ParseCppFile(
+ const std::string& absFilename,
+ const std::vector<std::string>& headerExtensions,
+ std::map<std::string, std::string>& includedMocs,
+ std::map<std::string, std::vector<std::string> >& includedUis);
+ void StrictParseCppFile(
+ const std::string& absFilename,
+ const std::vector<std::string>& headerExtensions,
+ std::map<std::string, std::string>& includedMocs,
+ std::map<std::string, std::vector<std::string> >& includedUis);
+ void SearchHeadersForCppFile(
+ const std::string& absFilename,
+ const std::vector<std::string>& headerExtensions,
+ std::set<std::string>& absHeaders);
+
+ void ParseHeaders(
+ const std::set<std::string>& absHeaders,
+ const std::map<std::string, std::string>& includedMocs,
+ std::map<std::string, std::string>& notIncludedMocs,
+ std::map<std::string, std::vector<std::string> >& includedUis);
+
+ void ParseForUic(
+ const std::string& fileName, const std::string& contentsString,
+ std::map<std::string, std::vector<std::string> >& includedUis);
+
+ void ParseForUic(
+ const std::string& fileName,
+ std::map<std::string, std::vector<std::string> >& includedUis);
+
+ void Init();
+
+ std::string SourceRelativePath(const std::string& filename);
+
+ bool NameCollisionTest(const std::map<std::string, std::string>& genFiles,
+ std::multimap<std::string, std::string>& collisions);
+ void NameCollisionLog(
+ const std::string& message,
+ const std::multimap<std::string, std::string>& collisions);
+
+ void LogInfo(const std::string& message);
+ void LogError(const std::string& message);
+ void LogCommand(const std::vector<std::string>& command);
+ std::string JoinExts(const std::vector<std::string>& lst);
+
+ static void MergeUicOptions(std::vector<std::string>& opts,
+ const std::vector<std::string>& fileOpts,
+ bool isQt5);
+
+ bool InputFilesNewerThanQrc(const std::string& qrcFile,
+ const std::string& rccOutput);
+
+ std::string QtMajorVersion;
+ std::string Sources;
+ std::vector<std::string> RccSources;
+ std::string SkipMoc;
+ std::string SkipUic;
+ std::string Headers;
+ std::string Srcdir;
+ std::string Builddir;
+ std::string MocExecutable;
+ std::string UicExecutable;
+ std::string RccExecutable;
+ std::string MocCompileDefinitionsStr;
+ std::string MocIncludesStr;
+ std::string MocOptionsStr;
+ std::string ProjectBinaryDir;
+ std::string ProjectSourceDir;
+ std::string TargetName;
+ std::string OriginTargetName;
+
+ std::string CurrentCompileSettingsStr;
+ std::string OldCompileSettingsStr;
+
+ std::string TargetBuildSubDir;
+ std::string OutMocCppFilenameRel;
+ std::string OutMocCppFilenameAbs;
+ std::list<std::string> MocIncludes;
+ std::list<std::string> MocDefinitions;
+ std::vector<std::string> MocOptions;
+ std::vector<std::string> UicTargetOptions;
+ std::map<std::string, std::string> UicOptions;
+ std::map<std::string, std::string> RccOptions;
+ std::map<std::string, std::vector<std::string> > RccInputs;
+
+ bool IncludeProjectDirsBefore;
+ bool Verbose;
+ bool ColorOutput;
+ bool RunMocFailed;
+ bool RunUicFailed;
+ bool RunRccFailed;
+ bool GenerateAll;
+ bool RelaxedMode;
+};
+
+#endif
diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx
new file mode 100644
index 0000000..10d1cda
--- /dev/null
+++ b/Source/cmRST.cxx
@@ -0,0 +1,424 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2013 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmRST.h"
+
+#include "cmAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+#include <cmsys/FStream.hxx>
+#include <ctype.h>
+
+cmRST::cmRST(std::ostream& os, std::string const& docroot)
+ : OS(os)
+ , DocRoot(docroot)
+ , IncludeDepth(0)
+ , OutputLinePending(false)
+ , LastLineEndedInColonColon(false)
+ , Markup(MarkupNone)
+ , Directive(DirectiveNone)
+ , CMakeDirective("^.. (cmake:)?("
+ "command|variable"
+ ")::[ \t]+([^ \t\n]+)$")
+ , CMakeModuleDirective("^.. cmake-module::[ \t]+([^ \t\n]+)$")
+ , ParsedLiteralDirective("^.. parsed-literal::[ \t]*(.*)$")
+ , CodeBlockDirective("^.. code-block::[ \t]*(.*)$")
+ , ReplaceDirective("^.. (\\|[^|]+\\|) replace::[ \t]*(.*)$")
+ , IncludeDirective("^.. include::[ \t]+([^ \t\n]+)$")
+ , TocTreeDirective("^.. toctree::[ \t]*(.*)$")
+ , ProductionListDirective("^.. productionlist::[ \t]*(.*)$")
+ , NoteDirective("^.. note::[ \t]*(.*)$")
+ , ModuleRST("^#\\[(=*)\\[\\.rst:$")
+ , CMakeRole("(:cmake)?:("
+ "command|generator|variable|module|policy|"
+ "prop_cache|prop_dir|prop_gbl|prop_inst|prop_sf|"
+ "prop_test|prop_tgt|"
+ "manual"
+ "):`(<*([^`<]|[^` \t]<)*)([ \t]+<[^`]*>)?`")
+ , Substitution("(^|[^A-Za-z0-9_])"
+ "((\\|[^| \t\r\n]([^|\r\n]*[^| \t\r\n])?\\|)(__|_|))"
+ "([^A-Za-z0-9_]|$)")
+ , TocTreeLink("^.*[ \t]+<([^>]+)>$")
+{
+ this->Replace["|release|"] = cmVersion::GetCMakeVersion();
+}
+
+bool cmRST::ProcessFile(std::string const& fname, bool isModule)
+{
+ cmsys::ifstream fin(fname.c_str());
+ if (fin) {
+ this->DocDir = cmSystemTools::GetFilenamePath(fname);
+ if (isModule) {
+ this->ProcessModule(fin);
+ } else {
+ this->ProcessRST(fin);
+ }
+ this->OutputLinePending = true;
+ return true;
+ }
+ return false;
+}
+
+void cmRST::ProcessRST(std::istream& is)
+{
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(is, line)) {
+ this->ProcessLine(line);
+ }
+ this->Reset();
+}
+
+void cmRST::ProcessModule(std::istream& is)
+{
+ std::string line;
+ std::string rst;
+ while (cmSystemTools::GetLineFromStream(is, line)) {
+ if (!rst.empty() && rst != "#") {
+ // Bracket mode: check for end bracket
+ std::string::size_type pos = line.find(rst);
+ if (pos == line.npos) {
+ this->ProcessLine(line);
+ } else {
+ if (line[0] != '#') {
+ this->ProcessLine(line.substr(0, pos));
+ }
+ rst = "";
+ this->Reset();
+ this->OutputLinePending = true;
+ }
+ } else {
+ // Line mode: check for .rst start (bracket or line)
+ if (rst == "#") {
+ if (line == "#") {
+ this->ProcessLine("");
+ continue;
+ } else if (line.substr(0, 2) == "# ") {
+ this->ProcessLine(line.substr(2, line.npos));
+ continue;
+ } else {
+ rst = "";
+ this->Reset();
+ this->OutputLinePending = true;
+ }
+ }
+ if (line == "#.rst:") {
+ rst = "#";
+ } else if (this->ModuleRST.find(line)) {
+ rst = "]" + this->ModuleRST.match(1) + "]";
+ }
+ }
+ }
+ if (rst == "#") {
+ this->Reset();
+ }
+}
+
+void cmRST::Reset()
+{
+ if (!this->MarkupLines.empty()) {
+ this->UnindentLines(this->MarkupLines);
+ }
+ switch (this->Directive) {
+ case DirectiveNone:
+ break;
+ case DirectiveParsedLiteral:
+ this->ProcessDirectiveParsedLiteral();
+ break;
+ case DirectiveLiteralBlock:
+ this->ProcessDirectiveLiteralBlock();
+ break;
+ case DirectiveCodeBlock:
+ this->ProcessDirectiveCodeBlock();
+ break;
+ case DirectiveReplace:
+ this->ProcessDirectiveReplace();
+ break;
+ case DirectiveTocTree:
+ this->ProcessDirectiveTocTree();
+ break;
+ }
+ this->Markup = MarkupNone;
+ this->Directive = DirectiveNone;
+ this->MarkupLines.clear();
+}
+
+void cmRST::ProcessLine(std::string const& line)
+{
+ bool lastLineEndedInColonColon = this->LastLineEndedInColonColon;
+ this->LastLineEndedInColonColon = false;
+
+ // A line starting in .. is an explicit markup start.
+ if (line == ".." || (line.size() >= 3 && line[0] == '.' && line[1] == '.' &&
+ isspace(line[2]))) {
+ this->Reset();
+ this->Markup =
+ (line.find_first_not_of(" \t", 2) == line.npos ? MarkupEmpty
+ : MarkupNormal);
+ if (this->CMakeDirective.find(line)) {
+ // Output cmake domain directives and their content normally.
+ this->NormalLine(line);
+ } else if (this->CMakeModuleDirective.find(line)) {
+ // Process cmake-module directive: scan .cmake file comments.
+ std::string file = this->CMakeModuleDirective.match(1);
+ if (file.empty() || !this->ProcessInclude(file, IncludeModule)) {
+ this->NormalLine(line);
+ }
+ } else if (this->ParsedLiteralDirective.find(line)) {
+ // Record the literal lines to output after whole block.
+ this->Directive = DirectiveParsedLiteral;
+ this->MarkupLines.push_back(this->ParsedLiteralDirective.match(1));
+ } else if (this->CodeBlockDirective.find(line)) {
+ // Record the literal lines to output after whole block.
+ // Ignore the language spec and record the opening line as blank.
+ this->Directive = DirectiveCodeBlock;
+ this->MarkupLines.push_back("");
+ } else if (this->ReplaceDirective.find(line)) {
+ // Record the replace directive content.
+ this->Directive = DirectiveReplace;
+ this->ReplaceName = this->ReplaceDirective.match(1);
+ this->MarkupLines.push_back(this->ReplaceDirective.match(2));
+ } else if (this->IncludeDirective.find(line)) {
+ // Process the include directive or output the directive and its
+ // content normally if it fails.
+ std::string file = this->IncludeDirective.match(1);
+ if (file.empty() || !this->ProcessInclude(file, IncludeNormal)) {
+ this->NormalLine(line);
+ }
+ } else if (this->TocTreeDirective.find(line)) {
+ // Record the toctree entries to process after whole block.
+ this->Directive = DirectiveTocTree;
+ this->MarkupLines.push_back(this->TocTreeDirective.match(1));
+ } else if (this->ProductionListDirective.find(line)) {
+ // Output productionlist directives and their content normally.
+ this->NormalLine(line);
+ } else if (this->NoteDirective.find(line)) {
+ // Output note directives and their content normally.
+ this->NormalLine(line);
+ }
+ }
+ // An explicit markup start followed nothing but whitespace and a
+ // blank line does not consume any indented text following.
+ else if (this->Markup == MarkupEmpty && line.empty()) {
+ this->NormalLine(line);
+ }
+ // Indented lines following an explicit markup start are explicit markup.
+ else if (this->Markup && (line.empty() || isspace(line[0]))) {
+ this->Markup = MarkupNormal;
+ // Record markup lines if the start line was recorded.
+ if (!this->MarkupLines.empty()) {
+ this->MarkupLines.push_back(line);
+ }
+ }
+ // A blank line following a paragraph ending in "::" starts a literal block.
+ else if (lastLineEndedInColonColon && line.empty()) {
+ // Record the literal lines to output after whole block.
+ this->Markup = MarkupNormal;
+ this->Directive = DirectiveLiteralBlock;
+ this->MarkupLines.push_back("");
+ this->OutputLine("", false);
+ }
+ // Print non-markup lines.
+ else {
+ this->NormalLine(line);
+ this->LastLineEndedInColonColon =
+ (line.size() >= 2 && line[line.size() - 2] == ':' &&
+ line[line.size() - 1] == ':');
+ }
+}
+
+void cmRST::NormalLine(std::string const& line)
+{
+ this->Reset();
+ this->OutputLine(line, true);
+}
+
+void cmRST::OutputLine(std::string const& line_in, bool inlineMarkup)
+{
+ if (this->OutputLinePending) {
+ this->OS << "\n";
+ this->OutputLinePending = false;
+ }
+ if (inlineMarkup) {
+ std::string line = this->ReplaceSubstitutions(line_in);
+ std::string::size_type pos = 0;
+ while (this->CMakeRole.find(line.c_str() + pos)) {
+ this->OS << line.substr(pos, this->CMakeRole.start());
+ std::string text = this->CMakeRole.match(3);
+ // If a command reference has no explicit target and
+ // no explicit "(...)" then add "()" to the text.
+ if (this->CMakeRole.match(2) == "command" &&
+ this->CMakeRole.match(5).empty() &&
+ text.find_first_of("()") == text.npos) {
+ text += "()";
+ }
+ this->OS << "``" << text << "``";
+ pos += this->CMakeRole.end();
+ }
+ this->OS << line.substr(pos) << "\n";
+ } else {
+ this->OS << line_in << "\n";
+ }
+}
+
+std::string cmRST::ReplaceSubstitutions(std::string const& line)
+{
+ std::string out;
+ std::string::size_type pos = 0;
+ while (this->Substitution.find(line.c_str() + pos)) {
+ std::string::size_type start = this->Substitution.start(2);
+ std::string::size_type end = this->Substitution.end(2);
+ std::string substitute = this->Substitution.match(3);
+ std::map<std::string, std::string>::iterator replace =
+ this->Replace.find(substitute);
+ if (replace != this->Replace.end()) {
+ std::pair<std::set<std::string>::iterator, bool> replaced =
+ this->Replaced.insert(substitute);
+ if (replaced.second) {
+ substitute = this->ReplaceSubstitutions(replace->second);
+ this->Replaced.erase(replaced.first);
+ }
+ }
+ out += line.substr(pos, start);
+ out += substitute;
+ pos += end;
+ }
+ out += line.substr(pos);
+ return out;
+}
+
+void cmRST::OutputMarkupLines(bool inlineMarkup)
+{
+ for (std::vector<std::string>::iterator i = this->MarkupLines.begin();
+ i != this->MarkupLines.end(); ++i) {
+ std::string line = *i;
+ if (!line.empty()) {
+ line = " " + line;
+ }
+ this->OutputLine(line, inlineMarkup);
+ }
+ this->OutputLinePending = true;
+}
+
+bool cmRST::ProcessInclude(std::string file, IncludeType type)
+{
+ bool found = false;
+ if (this->IncludeDepth < 10) {
+ cmRST r(this->OS, this->DocRoot);
+ r.IncludeDepth = this->IncludeDepth + 1;
+ r.OutputLinePending = this->OutputLinePending;
+ if (type != IncludeTocTree) {
+ r.Replace = this->Replace;
+ }
+ if (file[0] == '/') {
+ file = this->DocRoot + file;
+ } else {
+ file = this->DocDir + "/" + file;
+ }
+ found = r.ProcessFile(file, type == IncludeModule);
+ if (type != IncludeTocTree) {
+ this->Replace = r.Replace;
+ }
+ this->OutputLinePending = r.OutputLinePending;
+ }
+ return found;
+}
+
+void cmRST::ProcessDirectiveParsedLiteral()
+{
+ this->OutputMarkupLines(true);
+}
+
+void cmRST::ProcessDirectiveLiteralBlock()
+{
+ this->OutputMarkupLines(false);
+}
+
+void cmRST::ProcessDirectiveCodeBlock()
+{
+ this->OutputMarkupLines(false);
+}
+
+void cmRST::ProcessDirectiveReplace()
+{
+ // Record markup lines as replacement text.
+ std::string& replacement = this->Replace[this->ReplaceName];
+ replacement += cmJoin(this->MarkupLines, " ");
+ this->ReplaceName = "";
+}
+
+void cmRST::ProcessDirectiveTocTree()
+{
+ // Process documents referenced by toctree directive.
+ for (std::vector<std::string>::iterator i = this->MarkupLines.begin();
+ i != this->MarkupLines.end(); ++i) {
+ std::string const& line = *i;
+ if (!line.empty() && line[0] != ':') {
+ if (this->TocTreeLink.find(line)) {
+ std::string const& link = this->TocTreeLink.match(1);
+ this->ProcessInclude(link + ".rst", IncludeTocTree);
+ } else {
+ this->ProcessInclude(line + ".rst", IncludeTocTree);
+ }
+ }
+ }
+}
+
+void cmRST::UnindentLines(std::vector<std::string>& lines)
+{
+ // Remove the common indentation from the second and later lines.
+ std::string indentText;
+ std::string::size_type indentEnd = 0;
+ bool first = true;
+ for (size_t i = 1; i < lines.size(); ++i) {
+ std::string const& line = lines[i];
+
+ // Do not consider empty lines.
+ if (line.empty()) {
+ continue;
+ }
+
+ // Record indentation on first non-empty line.
+ if (first) {
+ first = false;
+ indentEnd = line.find_first_not_of(" \t");
+ indentText = line.substr(0, indentEnd);
+ continue;
+ }
+
+ // Truncate indentation to match that on this line.
+ indentEnd = std::min(indentEnd, line.size());
+ for (std::string::size_type j = 0; j != indentEnd; ++j) {
+ if (line[j] != indentText[j]) {
+ indentEnd = j;
+ break;
+ }
+ }
+ }
+
+ // Update second and later lines.
+ for (size_t i = 1; i < lines.size(); ++i) {
+ std::string& line = lines[i];
+ if (!line.empty()) {
+ line = line.substr(indentEnd);
+ }
+ }
+
+ std::vector<std::string>::const_iterator it = lines.begin();
+ size_t leadingEmpty = std::distance(it, cmFindNot(lines, std::string()));
+
+ std::vector<std::string>::const_reverse_iterator rit = lines.rbegin();
+ size_t trailingEmpty =
+ std::distance(rit, cmFindNot(cmReverseRange(lines), std::string()));
+
+ std::vector<std::string>::iterator contentEnd = cmRotate(
+ lines.begin(), lines.begin() + leadingEmpty, lines.end() - trailingEmpty);
+ lines.erase(contentEnd, lines.end());
+}
diff --git a/Source/cmRST.h b/Source/cmRST.h
new file mode 100644
index 0000000..0e379b6
--- /dev/null
+++ b/Source/cmRST.h
@@ -0,0 +1,102 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2013 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef _cmRST_h
+#define _cmRST_h
+
+#include "cmStandardIncludes.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+/** \class cmRST
+ * \brief Perform basic .rst processing for command-line help
+ *
+ * This class implements a subset of reStructuredText and Sphinx
+ * document processing. It is used to print command-line help.
+ *
+ * If you modify the capabilities of this class, be sure to update
+ * the Help/manual/cmake-developer.7.rst documentation and to update
+ * the Tests/CMakeLib/testRST.(rst|expect) test input and output.
+ */
+class cmRST
+{
+public:
+ cmRST(std::ostream& os, std::string const& docroot);
+ bool ProcessFile(std::string const& fname, bool isModule = false);
+
+private:
+ enum IncludeType
+ {
+ IncludeNormal,
+ IncludeModule,
+ IncludeTocTree
+ };
+ enum MarkupType
+ {
+ MarkupNone,
+ MarkupNormal,
+ MarkupEmpty
+ };
+ enum DirectiveType
+ {
+ DirectiveNone,
+ DirectiveParsedLiteral,
+ DirectiveLiteralBlock,
+ DirectiveCodeBlock,
+ DirectiveReplace,
+ DirectiveTocTree
+ };
+
+ void ProcessRST(std::istream& is);
+ void ProcessModule(std::istream& is);
+ void Reset();
+ void ProcessLine(std::string const& line);
+ void NormalLine(std::string const& line);
+ void OutputLine(std::string const& line, bool inlineMarkup);
+ std::string ReplaceSubstitutions(std::string const& line);
+ void OutputMarkupLines(bool inlineMarkup);
+ bool ProcessInclude(std::string file, IncludeType type);
+ void ProcessDirectiveParsedLiteral();
+ void ProcessDirectiveLiteralBlock();
+ void ProcessDirectiveCodeBlock();
+ void ProcessDirectiveReplace();
+ void ProcessDirectiveTocTree();
+ static void UnindentLines(std::vector<std::string>& lines);
+
+ std::ostream& OS;
+ std::string DocRoot;
+ int IncludeDepth;
+ bool OutputLinePending;
+ bool LastLineEndedInColonColon;
+ MarkupType Markup;
+ DirectiveType Directive;
+ cmsys::RegularExpression CMakeDirective;
+ cmsys::RegularExpression CMakeModuleDirective;
+ cmsys::RegularExpression ParsedLiteralDirective;
+ cmsys::RegularExpression CodeBlockDirective;
+ cmsys::RegularExpression ReplaceDirective;
+ cmsys::RegularExpression IncludeDirective;
+ cmsys::RegularExpression TocTreeDirective;
+ cmsys::RegularExpression ProductionListDirective;
+ cmsys::RegularExpression NoteDirective;
+ cmsys::RegularExpression ModuleRST;
+ cmsys::RegularExpression CMakeRole;
+ cmsys::RegularExpression Substitution;
+ cmsys::RegularExpression TocTreeLink;
+
+ std::vector<std::string> MarkupLines;
+ std::string DocDir;
+ std::map<std::string, std::string> Replace;
+ std::set<std::string> Replaced;
+ std::string ReplaceName;
+};
+
+#endif
diff --git a/Source/cmRemoveCommand.cxx b/Source/cmRemoveCommand.cxx
new file mode 100644
index 0000000..955f712
--- /dev/null
+++ b/Source/cmRemoveCommand.cxx
@@ -0,0 +1,64 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmRemoveCommand.h"
+
+// cmRemoveCommand
+bool cmRemoveCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ return true;
+ }
+
+ const char* variable = args[0].c_str(); // VAR is always first
+ // get the old value
+ const char* cacheValue = this->Makefile->GetDefinition(variable);
+
+ // if there is no old value then return
+ if (!cacheValue) {
+ return true;
+ }
+
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ cmSystemTools::ExpandListArgument(cacheValue, varArgsExpanded);
+
+ // 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);
+
+ // now create the new value
+ std::string value;
+ for (unsigned int j = 0; j < varArgsExpanded.size(); ++j) {
+ int found = 0;
+ for (unsigned int k = 0; k < argsExpanded.size(); ++k) {
+ if (varArgsExpanded[j] == argsExpanded[k]) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ if (!value.empty()) {
+ value += ";";
+ }
+ value += varArgsExpanded[j];
+ }
+ }
+
+ // add the definition
+ this->Makefile->AddDefinition(variable, value.c_str());
+
+ return true;
+}
diff --git a/Source/cmRemoveCommand.h b/Source/cmRemoveCommand.h
new file mode 100644
index 0000000..1deff36
--- /dev/null
+++ b/Source/cmRemoveCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmRemoveCommand_h
+#define cmRemoveCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmRemoveCommand
+ * \brief remove command
+ *
+ * cmRemoveCommand implements the remove CMake command
+ */
+class cmRemoveCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmRemoveCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "remove"; }
+
+ cmTypeMacro(cmRemoveCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmRemoveDefinitionsCommand.cxx b/Source/cmRemoveDefinitionsCommand.cxx
new file mode 100644
index 0000000..638eda6
--- /dev/null
+++ b/Source/cmRemoveDefinitionsCommand.cxx
@@ -0,0 +1,28 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmRemoveDefinitionsCommand.h"
+
+// cmRemoveDefinitionsCommand
+bool cmRemoveDefinitionsCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ // it is OK to have no arguments
+ if (args.size() < 1) {
+ return true;
+ }
+
+ for (std::vector<std::string>::const_iterator i = args.begin();
+ i != args.end(); ++i) {
+ this->Makefile->RemoveDefineFlag(i->c_str());
+ }
+ return true;
+}
diff --git a/Source/cmRemoveDefinitionsCommand.h b/Source/cmRemoveDefinitionsCommand.h
new file mode 100644
index 0000000..7fb2e5f
--- /dev/null
+++ b/Source/cmRemoveDefinitionsCommand.h
@@ -0,0 +1,47 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmRemoveDefinitionsCommand_h
+#define cmRemoveDefinitionsCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmRemoveDefinitionsCommand
+ * \brief Specify a list of compiler defines
+ *
+ * cmRemoveDefinitionsCommand specifies a list of compiler defines.
+ * These defines will
+ * be removed from the compile command.
+ */
+class cmRemoveDefinitionsCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmRemoveDefinitionsCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "remove_definitions"; }
+
+ cmTypeMacro(cmRemoveDefinitionsCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmReturnCommand.cxx b/Source/cmReturnCommand.cxx
new file mode 100644
index 0000000..1de649f
--- /dev/null
+++ b/Source/cmReturnCommand.cxx
@@ -0,0 +1,20 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmReturnCommand.h"
+
+// cmReturnCommand
+bool cmReturnCommand::InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus& status)
+{
+ status.SetReturnInvoked(true);
+ return true;
+}
diff --git a/Source/cmReturnCommand.h b/Source/cmReturnCommand.h
new file mode 100644
index 0000000..ddf3613
--- /dev/null
+++ b/Source/cmReturnCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmReturnCommand_h
+#define cmReturnCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmReturnCommand
+ * \brief Return from a directory or function
+ *
+ * cmReturnCommand returns from a directory or function
+ */
+class cmReturnCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmReturnCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "return"; }
+
+ cmTypeMacro(cmReturnCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmScriptGenerator.cxx b/Source/cmScriptGenerator.cxx
new file mode 100644
index 0000000..b8aae5d
--- /dev/null
+++ b/Source/cmScriptGenerator.cxx
@@ -0,0 +1,197 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmScriptGenerator.h"
+
+#include "cmSystemTools.h"
+
+cmScriptGenerator::cmScriptGenerator(
+ const std::string& config_var,
+ std::vector<std::string> const& configurations)
+ : RuntimeConfigVariable(config_var)
+ , Configurations(configurations)
+ , ConfigurationName("")
+ , ConfigurationTypes(CM_NULLPTR)
+ , ActionsPerConfig(false)
+{
+}
+
+cmScriptGenerator::~cmScriptGenerator()
+{
+}
+
+void cmScriptGenerator::Generate(
+ std::ostream& os, const std::string& config,
+ std::vector<std::string> const& configurationTypes)
+{
+ this->ConfigurationName = config;
+ this->ConfigurationTypes = &configurationTypes;
+ this->GenerateScript(os);
+ this->ConfigurationName = "";
+ this->ConfigurationTypes = CM_NULLPTR;
+}
+
+static void cmScriptGeneratorEncodeConfig(const std::string& config,
+ std::string& result)
+{
+ for (const char* c = config.c_str(); *c; ++c) {
+ if (*c >= 'a' && *c <= 'z') {
+ result += "[";
+ result += static_cast<char>(*c + 'A' - 'a');
+ result += *c;
+ result += "]";
+ } else if (*c >= 'A' && *c <= 'Z') {
+ result += "[";
+ result += *c;
+ result += static_cast<char>(*c + 'a' - 'A');
+ result += "]";
+ } else {
+ result += *c;
+ }
+ }
+}
+
+std::string cmScriptGenerator::CreateConfigTest(const std::string& config)
+{
+ std::string result = "\"${";
+ result += this->RuntimeConfigVariable;
+ result += "}\" MATCHES \"^(";
+ if (!config.empty()) {
+ cmScriptGeneratorEncodeConfig(config, result);
+ }
+ result += ")$\"";
+ return result;
+}
+
+std::string cmScriptGenerator::CreateConfigTest(
+ std::vector<std::string> const& configs)
+{
+ std::string result = "\"${";
+ result += this->RuntimeConfigVariable;
+ result += "}\" MATCHES \"^(";
+ const char* sep = "";
+ for (std::vector<std::string>::const_iterator ci = configs.begin();
+ ci != configs.end(); ++ci) {
+ result += sep;
+ sep = "|";
+ cmScriptGeneratorEncodeConfig(*ci, result);
+ }
+ result += ")$\"";
+ return result;
+}
+
+void cmScriptGenerator::GenerateScript(std::ostream& os)
+{
+ // Track indentation.
+ Indent indent;
+
+ // Generate the script possibly with per-configuration code.
+ this->GenerateScriptConfigs(os, indent);
+}
+
+void cmScriptGenerator::GenerateScriptConfigs(std::ostream& os,
+ Indent const& indent)
+{
+ if (this->ActionsPerConfig) {
+ this->GenerateScriptActionsPerConfig(os, indent);
+ } else {
+ this->GenerateScriptActionsOnce(os, indent);
+ }
+}
+
+void cmScriptGenerator::GenerateScriptActions(std::ostream& os,
+ Indent const& indent)
+{
+ if (this->ActionsPerConfig) {
+ // This is reached for single-configuration build generators in a
+ // per-config script generator.
+ this->GenerateScriptForConfig(os, this->ConfigurationName, indent);
+ }
+}
+
+void cmScriptGenerator::GenerateScriptForConfig(std::ostream&,
+ const std::string&,
+ Indent const&)
+{
+ // No actions for this generator.
+}
+
+bool cmScriptGenerator::GeneratesForConfig(const std::string& config)
+{
+ // If this is not a configuration-specific rule then we install.
+ if (this->Configurations.empty()) {
+ return true;
+ }
+
+ // This is a configuration-specific rule. Check if the config
+ // matches this rule.
+ std::string config_upper = cmSystemTools::UpperCase(config);
+ for (std::vector<std::string>::const_iterator i =
+ this->Configurations.begin();
+ i != this->Configurations.end(); ++i) {
+ if (cmSystemTools::UpperCase(*i) == config_upper) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmScriptGenerator::GenerateScriptActionsOnce(std::ostream& os,
+ Indent const& indent)
+{
+ if (this->Configurations.empty()) {
+ // This rule is for all configurations.
+ this->GenerateScriptActions(os, indent);
+ } else {
+ // Generate a per-configuration block.
+ std::string config_test = this->CreateConfigTest(this->Configurations);
+ os << indent << "if(" << config_test << ")\n";
+ this->GenerateScriptActions(os, indent.Next());
+ os << indent << "endif(" << config_test << ")\n";
+ }
+}
+
+void cmScriptGenerator::GenerateScriptActionsPerConfig(std::ostream& os,
+ Indent const& indent)
+{
+ if (this->ConfigurationTypes->empty()) {
+ // In a single-configuration generator there is only one action
+ // and it applies if the runtime-requested configuration is among
+ // the rule's allowed configurations. The configuration built in
+ // the tree does not matter for this decision but will be used to
+ // generate proper target file names into the code.
+ this->GenerateScriptActionsOnce(os, indent);
+ } else {
+ // In a multi-configuration generator we produce a separate rule
+ // in a block for each configuration that is built. We restrict
+ // the list of configurations to those to which this rule applies.
+ bool first = true;
+ for (std::vector<std::string>::const_iterator i =
+ this->ConfigurationTypes->begin();
+ i != this->ConfigurationTypes->end(); ++i) {
+ const char* config = i->c_str();
+ if (this->GeneratesForConfig(config)) {
+ // Generate a per-configuration block.
+ std::string config_test = this->CreateConfigTest(config);
+ os << indent << (first ? "if(" : "elseif(") << config_test << ")\n";
+ this->GenerateScriptForConfig(os, config, indent.Next());
+ first = false;
+ }
+ }
+ if (!first) {
+ if (this->NeedsScriptNoConfig()) {
+ os << indent << "else()\n";
+ this->GenerateScriptNoConfig(os, indent.Next());
+ }
+ os << indent << "endif()\n";
+ }
+ }
+}
diff --git a/Source/cmScriptGenerator.h b/Source/cmScriptGenerator.h
new file mode 100644
index 0000000..ef0766f
--- /dev/null
+++ b/Source/cmScriptGenerator.h
@@ -0,0 +1,99 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmScriptGenerator_h
+#define cmScriptGenerator_h
+
+#include "cmStandardIncludes.h"
+
+class cmScriptGeneratorIndent
+{
+public:
+ cmScriptGeneratorIndent()
+ : Level(0)
+ {
+ }
+ cmScriptGeneratorIndent(int level)
+ : Level(level)
+ {
+ }
+ void Write(std::ostream& os) const
+ {
+ for (int i = 0; i < this->Level; ++i) {
+ os << " ";
+ }
+ }
+ cmScriptGeneratorIndent Next(int step = 2) const
+ {
+ return cmScriptGeneratorIndent(this->Level + step);
+ }
+
+private:
+ int Level;
+};
+inline std::ostream& operator<<(std::ostream& os,
+ cmScriptGeneratorIndent const& indent)
+{
+ indent.Write(os);
+ return os;
+}
+
+/** \class cmScriptGenerator
+ * \brief Support class for generating install and test scripts.
+ *
+ */
+class cmScriptGenerator
+{
+public:
+ cmScriptGenerator(const std::string& config_var,
+ std::vector<std::string> const& configurations);
+ virtual ~cmScriptGenerator();
+
+ void Generate(std::ostream& os, const std::string& config,
+ std::vector<std::string> const& configurationTypes);
+
+protected:
+ typedef cmScriptGeneratorIndent Indent;
+ virtual void GenerateScript(std::ostream& os);
+ virtual void GenerateScriptConfigs(std::ostream& os, Indent const& indent);
+ virtual void GenerateScriptActions(std::ostream& os, Indent const& indent);
+ virtual void GenerateScriptForConfig(std::ostream& os,
+ const std::string& config,
+ Indent const& indent);
+ virtual void GenerateScriptNoConfig(std::ostream&, Indent const&) {}
+ virtual bool NeedsScriptNoConfig() const { return false; }
+
+ // Test if this generator does something for a given configuration.
+ bool GeneratesForConfig(const std::string&);
+
+ std::string CreateConfigTest(const std::string& config);
+ std::string CreateConfigTest(std::vector<std::string> const& configs);
+ std::string CreateComponentTest(const char* component);
+
+ // Information shared by most generator types.
+ std::string RuntimeConfigVariable;
+ std::vector<std::string> const Configurations;
+
+ // Information used during generation.
+ std::string ConfigurationName;
+ std::vector<std::string> const* ConfigurationTypes;
+
+ // True if the subclass needs to generate an explicit rule for each
+ // configuration. False if the subclass only generates one rule for
+ // all enabled configurations.
+ bool ActionsPerConfig;
+
+private:
+ void GenerateScriptActionsOnce(std::ostream& os, Indent const& indent);
+ void GenerateScriptActionsPerConfig(std::ostream& os, Indent const& indent);
+};
+
+#endif
diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx
new file mode 100644
index 0000000..ca3a57f
--- /dev/null
+++ b/Source/cmSearchPath.cxx
@@ -0,0 +1,228 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSearchPath.h"
+
+#include "cmAlgorithms.h"
+#include "cmFindCommon.h"
+
+cmSearchPath::cmSearchPath(cmFindCommon* findCmd)
+ : FC(findCmd)
+{
+}
+
+cmSearchPath::~cmSearchPath()
+{
+}
+
+void cmSearchPath::ExtractWithout(const std::set<std::string>& ignore,
+ std::vector<std::string>& outPaths,
+ bool clear) const
+{
+ if (clear) {
+ outPaths.clear();
+ }
+ for (std::vector<std::string>::const_iterator p = this->Paths.begin();
+ p != this->Paths.end(); ++p) {
+ if (ignore.count(*p) == 0) {
+ outPaths.push_back(*p);
+ }
+ }
+}
+
+void cmSearchPath::AddPath(const std::string& path)
+{
+ this->AddPathInternal(path);
+}
+
+void cmSearchPath::AddUserPath(const std::string& path)
+{
+ assert(this->FC != CM_NULLPTR);
+
+ std::vector<std::string> outPaths;
+
+ // We should view the registry as the target application would view
+ // it.
+ cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32;
+ cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64;
+ if (this->FC->Makefile->PlatformIs64Bit()) {
+ view = cmSystemTools::KeyWOW64_64;
+ other_view = cmSystemTools::KeyWOW64_32;
+ }
+
+ // Expand using the view of the target application.
+ std::string expanded = path;
+ cmSystemTools::ExpandRegistryValues(expanded, view);
+ cmSystemTools::GlobDirs(expanded, outPaths);
+
+ // Executables can be either 32-bit or 64-bit, so expand using the
+ // alternative view.
+ if (expanded != path && this->FC->CMakePathName == "PROGRAM") {
+ expanded = path;
+ cmSystemTools::ExpandRegistryValues(expanded, other_view);
+ cmSystemTools::GlobDirs(expanded, outPaths);
+ }
+
+ // Process them all from the current directory
+ for (std::vector<std::string>::const_iterator p = outPaths.begin();
+ p != outPaths.end(); ++p) {
+ this->AddPathInternal(*p, this->FC->Makefile->GetCurrentSourceDirectory());
+ }
+}
+
+void cmSearchPath::AddCMakePath(const std::string& variable)
+{
+ assert(this->FC != CM_NULLPTR);
+
+ // Get a path from a CMake variable.
+ if (const char* value = this->FC->Makefile->GetDefinition(variable)) {
+ std::vector<std::string> expanded;
+ cmSystemTools::ExpandListArgument(value, expanded);
+
+ for (std::vector<std::string>::const_iterator p = expanded.begin();
+ p != expanded.end(); ++p) {
+ this->AddPathInternal(*p,
+ this->FC->Makefile->GetCurrentSourceDirectory());
+ }
+ }
+}
+
+void cmSearchPath::AddEnvPath(const std::string& variable)
+{
+ std::vector<std::string> expanded;
+ cmSystemTools::GetPath(expanded, variable.c_str());
+ for (std::vector<std::string>::const_iterator p = expanded.begin();
+ p != expanded.end(); ++p) {
+ this->AddPathInternal(*p);
+ }
+}
+
+void cmSearchPath::AddCMakePrefixPath(const std::string& variable)
+{
+ assert(this->FC != CM_NULLPTR);
+
+ // Get a path from a CMake variable.
+ if (const char* value = this->FC->Makefile->GetDefinition(variable)) {
+ std::vector<std::string> expanded;
+ cmSystemTools::ExpandListArgument(value, expanded);
+
+ this->AddPrefixPaths(expanded,
+ this->FC->Makefile->GetCurrentSourceDirectory());
+ }
+}
+
+static std::string cmSearchPathStripBin(std::string const& s)
+{
+ // If the path is a PREFIX/bin case then add its parent instead.
+ if ((cmHasLiteralSuffix(s, "/bin")) || (cmHasLiteralSuffix(s, "/sbin"))) {
+ return cmSystemTools::GetFilenamePath(s);
+ } else {
+ return s;
+ }
+}
+
+void cmSearchPath::AddEnvPrefixPath(const std::string& variable, bool stripBin)
+{
+ std::vector<std::string> expanded;
+ cmSystemTools::GetPath(expanded, variable.c_str());
+ if (stripBin) {
+ std::transform(expanded.begin(), expanded.end(), expanded.begin(),
+ cmSearchPathStripBin);
+ }
+ this->AddPrefixPaths(expanded);
+}
+
+void cmSearchPath::AddSuffixes(const std::vector<std::string>& suffixes)
+{
+ std::vector<std::string> inPaths;
+ inPaths.swap(this->Paths);
+ this->Paths.reserve(inPaths.size() * (suffixes.size() + 1));
+
+ for (std::vector<std::string>::iterator ip = inPaths.begin();
+ ip != inPaths.end(); ++ip) {
+ cmSystemTools::ConvertToUnixSlashes(*ip);
+
+ // if *i is only / then do not add a //
+ // this will get incorrectly considered a network
+ // path on windows and cause huge delays.
+ std::string p = *ip;
+ if (!p.empty() && *p.rbegin() != '/') {
+ p += "/";
+ }
+
+ // Combine with all the suffixes
+ for (std::vector<std::string>::const_iterator s = suffixes.begin();
+ s != suffixes.end(); ++s) {
+ this->Paths.push_back(p + *s);
+ }
+
+ // And now the original w/o any suffix
+ this->Paths.push_back(*ip);
+ }
+}
+
+void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths,
+ const char* base)
+{
+ assert(this->FC != CM_NULLPTR);
+
+ // default for programs
+ std::string subdir = "bin";
+
+ if (this->FC->CMakePathName == "INCLUDE") {
+ subdir = "include";
+ } else if (this->FC->CMakePathName == "LIBRARY") {
+ subdir = "lib";
+ } else if (this->FC->CMakePathName == "FRAMEWORK") {
+ subdir = ""; // ? what to do for frameworks ?
+ }
+
+ for (std::vector<std::string>::const_iterator p = paths.begin();
+ p != paths.end(); ++p) {
+ std::string dir = *p;
+ if (!subdir.empty() && !dir.empty() && *dir.rbegin() != '/') {
+ dir += "/";
+ }
+ if (subdir == "include" || subdir == "lib") {
+ const char* arch =
+ this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE");
+ if (arch && *arch) {
+ this->AddPathInternal(dir + subdir + "/" + arch, base);
+ }
+ }
+ std::string add = dir + subdir;
+ if (add != "/") {
+ this->AddPathInternal(add, base);
+ }
+ if (subdir == "bin") {
+ this->AddPathInternal(dir + "sbin", base);
+ }
+ if (!subdir.empty() && *p != "/") {
+ this->AddPathInternal(*p, base);
+ }
+ }
+}
+
+void cmSearchPath::AddPathInternal(const std::string& path, const char* base)
+{
+ assert(this->FC != CM_NULLPTR);
+
+ std::string collapsed = cmSystemTools::CollapseFullPath(path, base);
+
+ if (collapsed.empty()) {
+ return;
+ }
+
+ // Insert the path if has not already been emitted.
+ if (this->FC->SearchPathsEmitted.insert(collapsed).second) {
+ this->Paths.push_back(collapsed);
+ }
+}
diff --git a/Source/cmSearchPath.h b/Source/cmSearchPath.h
new file mode 100644
index 0000000..65f703f
--- /dev/null
+++ b/Source/cmSearchPath.h
@@ -0,0 +1,57 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSearchPath_h
+#define cmSearchPath_h
+
+#include "cmStandardIncludes.h"
+
+class cmFindCommon;
+
+/** \class cmSearchPath
+ * \brief Container for encapsulating a set of search paths
+ *
+ * cmSearchPath is a container that encapsulates search path construction and
+ * management
+ */
+class cmSearchPath
+{
+public:
+ // cmSearchPath must be initialized from a valid pointer. The only reason
+ // for the default is to allow it to be easily used in stl containers.
+ // Attempting to initialize with a NULL value will fail an assertion
+ cmSearchPath(cmFindCommon* findCmd = CM_NULLPTR);
+ ~cmSearchPath();
+
+ const std::vector<std::string>& GetPaths() const { return this->Paths; }
+
+ void ExtractWithout(const std::set<std::string>& ignore,
+ std::vector<std::string>& outPaths,
+ bool clear = false) const;
+
+ void AddPath(const std::string& path);
+ void AddUserPath(const std::string& path);
+ void AddCMakePath(const std::string& variable);
+ void AddEnvPath(const std::string& variable);
+ void AddCMakePrefixPath(const std::string& variable);
+ void AddEnvPrefixPath(const std::string& variable, bool stripBin = false);
+ void AddSuffixes(const std::vector<std::string>& suffixes);
+
+protected:
+ void AddPrefixPaths(const std::vector<std::string>& paths,
+ const char* base = CM_NULLPTR);
+ void AddPathInternal(const std::string& path, const char* base = CM_NULLPTR);
+
+ cmFindCommon* FC;
+ std::vector<std::string> Paths;
+};
+
+#endif
diff --git a/Source/cmSeparateArgumentsCommand.cxx b/Source/cmSeparateArgumentsCommand.cxx
new file mode 100644
index 0000000..440b635
--- /dev/null
+++ b/Source/cmSeparateArgumentsCommand.cxx
@@ -0,0 +1,100 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSeparateArgumentsCommand.h"
+
+// cmSeparateArgumentsCommand
+bool cmSeparateArgumentsCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.empty()) {
+ this->SetError("must be given at least one argument.");
+ return false;
+ }
+
+ std::string var;
+ std::string command;
+ enum Mode
+ {
+ ModeOld,
+ ModeUnix,
+ ModeWindows
+ };
+ Mode mode = ModeOld;
+ enum Doing
+ {
+ DoingNone,
+ DoingVariable,
+ DoingMode,
+ DoingCommand
+ };
+ Doing doing = DoingVariable;
+ for (unsigned int i = 0; i < args.size(); ++i) {
+ if (doing == DoingVariable) {
+ var = args[i];
+ doing = DoingMode;
+ } else if (doing == DoingMode && args[i] == "UNIX_COMMAND") {
+ mode = ModeUnix;
+ doing = DoingCommand;
+ } else if (doing == DoingMode && args[i] == "WINDOWS_COMMAND") {
+ mode = ModeWindows;
+ doing = DoingCommand;
+ } else if (doing == DoingCommand) {
+ command = args[i];
+ doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << "given unknown argument " << args[i];
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ if (mode == ModeOld) {
+ // Original space-replacement version of command.
+ if (const char* def = this->Makefile->GetDefinition(var)) {
+ std::string value = def;
+ std::replace(value.begin(), value.end(), ' ', ';');
+ this->Makefile->AddDefinition(var, value.c_str());
+ }
+ } else {
+ // Parse the command line.
+ std::vector<std::string> vec;
+ if (mode == ModeUnix) {
+ cmSystemTools::ParseUnixCommandLine(command.c_str(), vec);
+ } else // if(mode == ModeWindows)
+ {
+ cmSystemTools::ParseWindowsCommandLine(command.c_str(), vec);
+ }
+
+ // Construct the result list value.
+ std::string value;
+ const char* sep = "";
+ for (std::vector<std::string>::const_iterator vi = vec.begin();
+ vi != vec.end(); ++vi) {
+ // Separate from the previous argument.
+ value += sep;
+ sep = ";";
+
+ // Preserve semicolons.
+ for (std::string::const_iterator si = vi->begin(); si != vi->end();
+ ++si) {
+ if (*si == ';') {
+ value += '\\';
+ }
+ value += *si;
+ }
+ }
+ this->Makefile->AddDefinition(var, value.c_str());
+ }
+
+ return true;
+}
diff --git a/Source/cmSeparateArgumentsCommand.h b/Source/cmSeparateArgumentsCommand.h
new file mode 100644
index 0000000..3c9e7d7
--- /dev/null
+++ b/Source/cmSeparateArgumentsCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSeparateArgumentsCommand_h
+#define cmSeparateArgumentsCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmSeparateArgumentsCommand
+ * \brief separate_arguments command
+ *
+ * cmSeparateArgumentsCommand implements the separate_arguments CMake command
+ */
+class cmSeparateArgumentsCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmSeparateArgumentsCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "separate_arguments"; }
+
+ cmTypeMacro(cmSeparateArgumentsCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx
new file mode 100644
index 0000000..1484368
--- /dev/null
+++ b/Source/cmSetCommand.cxx
@@ -0,0 +1,145 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSetCommand.h"
+
+// cmSetCommand
+bool cmSetCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // watch for ENV signatures
+ const char* variable = args[0].c_str(); // VAR is always first
+ if (cmHasLiteralPrefix(variable, "ENV{") && strlen(variable) > 5) {
+ // what is the variable name
+ char* varName = new char[strlen(variable)];
+ strncpy(varName, variable + 4, strlen(variable) - 5);
+ varName[strlen(variable) - 5] = '\0';
+ std::string putEnvArg = varName;
+ putEnvArg += "=";
+
+ // what is the current value if any
+ const char* currValue = getenv(varName);
+ delete[] varName;
+
+ // will it be set to something, then set it
+ if (args.size() > 1 && !args[1].empty()) {
+ // but only if it is different from current value
+ if (!currValue || strcmp(currValue, args[1].c_str())) {
+ putEnvArg += args[1];
+ cmSystemTools::PutEnv(putEnvArg);
+ }
+ return true;
+ }
+
+ // if it will be cleared, then clear it if it isn't already clear
+ if (currValue) {
+ cmSystemTools::PutEnv(putEnvArg);
+ }
+ return true;
+ }
+
+ // SET (VAR) // Removes the definition of VAR.
+ if (args.size() == 1) {
+ this->Makefile->RemoveDefinition(variable);
+ return true;
+ }
+ // SET (VAR PARENT_SCOPE) // Removes the definition of VAR
+ // in the parent scope.
+ else if (args.size() == 2 && args[args.size() - 1] == "PARENT_SCOPE") {
+ this->Makefile->RaiseScope(variable, CM_NULLPTR);
+ return true;
+ }
+
+ // here are the remaining options
+ // SET (VAR value )
+ // SET (VAR value PARENT_SCOPE)
+ // SET (VAR CACHE TYPE "doc String" [FORCE])
+ // SET (VAR value CACHE TYPE "doc string" [FORCE])
+ std::string value; // optional
+ bool cache = false; // optional
+ bool force = false; // optional
+ bool parentScope = false;
+ cmState::CacheEntryType type = cmState::STRING; // required if cache
+ const char* docstring = CM_NULLPTR; // required if cache
+
+ unsigned int ignoreLastArgs = 0;
+ // look for PARENT_SCOPE argument
+ if (args.size() > 1 && args[args.size() - 1] == "PARENT_SCOPE") {
+ parentScope = true;
+ ignoreLastArgs++;
+ } else {
+ // look for FORCE argument
+ if (args.size() > 4 && args[args.size() - 1] == "FORCE") {
+ force = true;
+ ignoreLastArgs++;
+ }
+
+ // check for cache signature
+ if (args.size() > 3 &&
+ args[args.size() - 3 - (force ? 1 : 0)] == "CACHE") {
+ cache = true;
+ ignoreLastArgs += 3;
+ }
+ }
+
+ // collect any values into a single semi-colon separated value list
+ value = cmJoin(cmMakeRange(args).advance(1).retreat(ignoreLastArgs), ";");
+
+ if (parentScope) {
+ this->Makefile->RaiseScope(variable, value.c_str());
+ return true;
+ }
+
+ // we should be nice and try to catch some simple screwups if the last or
+ // next to last args are CACHE then they screwed up. If they used FORCE
+ // without CACHE they screwed up
+ if ((args[args.size() - 1] == "CACHE") ||
+ (args.size() > 1 && args[args.size() - 2] == "CACHE") ||
+ (force && !cache)) {
+ this->SetError("given invalid arguments for CACHE mode.");
+ return false;
+ }
+
+ if (cache) {
+ std::string::size_type cacheStart = args.size() - 3 - (force ? 1 : 0);
+ type = cmState::StringToCacheEntryType(args[cacheStart + 1].c_str());
+ docstring = args[cacheStart + 2].c_str();
+ }
+
+ // see if this is already in the cache
+ cmState* state = this->Makefile->GetState();
+ const char* existingValue = state->GetCacheEntryValue(variable);
+ if (existingValue &&
+ (state->GetCacheEntryType(variable) != cmState::UNINITIALIZED)) {
+ // if the set is trying to CACHE the value but the value
+ // is already in the cache and the type is not internal
+ // then leave now without setting any definitions in the cache
+ // or the makefile
+ if (cache && type != cmState::INTERNAL && !force) {
+ return true;
+ }
+ }
+
+ // if it is meant to be in the cache then define it in the cache
+ if (cache) {
+ this->Makefile->AddCacheDefinition(variable, value.c_str(), docstring,
+ type, force);
+ } else {
+ // add the definition
+ this->Makefile->AddDefinition(variable, value.c_str());
+ }
+ return true;
+}
diff --git a/Source/cmSetCommand.h b/Source/cmSetCommand.h
new file mode 100644
index 0000000..b51eed0
--- /dev/null
+++ b/Source/cmSetCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSetCommand_h
+#define cmSetCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmSetCommand
+ * \brief Set a CMAKE variable
+ *
+ * cmSetCommand sets a variable to a value with expansion.
+ */
+class cmSetCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmSetCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "set"; }
+
+ cmTypeMacro(cmSetCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmSetDirectoryPropertiesCommand.cxx b/Source/cmSetDirectoryPropertiesCommand.cxx
new file mode 100644
index 0000000..ca758da
--- /dev/null
+++ b/Source/cmSetDirectoryPropertiesCommand.cxx
@@ -0,0 +1,56 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSetDirectoryPropertiesCommand.h"
+
+#include "cmake.h"
+
+// cmSetDirectoryPropertiesCommand
+bool cmSetDirectoryPropertiesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string errors;
+ bool ret = cmSetDirectoryPropertiesCommand::RunCommand(
+ this->Makefile, args.begin() + 1, args.end(), errors);
+ if (!ret) {
+ this->SetError(errors);
+ }
+ return ret;
+}
+
+bool cmSetDirectoryPropertiesCommand::RunCommand(
+ cmMakefile* mf, std::vector<std::string>::const_iterator ait,
+ std::vector<std::string>::const_iterator aitend, std::string& errors)
+{
+ for (; ait != aitend; ait += 2) {
+ if (ait + 1 == aitend) {
+ errors = "Wrong number of arguments";
+ return false;
+ }
+ const std::string& prop = *ait;
+ const std::string& value = *(ait + 1);
+ if (prop == "VARIABLES") {
+ errors = "Variables and cache variables should be set using SET command";
+ return false;
+ } else if (prop == "MACROS") {
+ errors = "Commands and macros cannot be set using SET_CMAKE_PROPERTIES";
+ return false;
+ }
+ mf->SetProperty(prop, value.c_str());
+ }
+
+ return true;
+}
diff --git a/Source/cmSetDirectoryPropertiesCommand.h b/Source/cmSetDirectoryPropertiesCommand.h
new file mode 100644
index 0000000..ef476ec
--- /dev/null
+++ b/Source/cmSetDirectoryPropertiesCommand.h
@@ -0,0 +1,56 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSetDirectoryPropertiesCommand_h
+#define cmSetDirectoryPropertiesCommand_h
+
+#include "cmCommand.h"
+
+class cmSetDirectoryPropertiesCommand : public cmCommand
+{
+public:
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ return new cmSetDirectoryPropertiesCommand;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE
+ {
+ return "set_directory_properties";
+ }
+
+ /**
+ * Static entry point for use by other commands
+ */
+ static bool RunCommand(cmMakefile* mf,
+ std::vector<std::string>::const_iterator ait,
+ std::vector<std::string>::const_iterator aitend,
+ std::string& errors);
+
+ cmTypeMacro(cmSetDirectoryPropertiesCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
new file mode 100644
index 0000000..8fe8ade
--- /dev/null
+++ b/Source/cmSetPropertyCommand.cxx
@@ -0,0 +1,437 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSetPropertyCommand.h"
+
+#include "cmSetSourceFilesPropertiesCommand.h"
+#include "cmSetTargetPropertiesCommand.h"
+#include "cmSetTestsPropertiesCommand.h"
+
+cmSetPropertyCommand::cmSetPropertyCommand()
+{
+ this->AppendMode = false;
+ this->AppendAsString = false;
+ this->Remove = true;
+}
+
+bool cmSetPropertyCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Get the scope on which to set the property.
+ std::vector<std::string>::const_iterator arg = args.begin();
+ cmProperty::ScopeType scope;
+ if (*arg == "GLOBAL") {
+ scope = cmProperty::GLOBAL;
+ } else if (*arg == "DIRECTORY") {
+ scope = cmProperty::DIRECTORY;
+ } else if (*arg == "TARGET") {
+ scope = cmProperty::TARGET;
+ } else if (*arg == "SOURCE") {
+ scope = cmProperty::SOURCE_FILE;
+ } else if (*arg == "TEST") {
+ scope = cmProperty::TEST;
+ } else if (*arg == "CACHE") {
+ scope = cmProperty::CACHE;
+ } else if (*arg == "INSTALL") {
+ scope = cmProperty::INSTALL;
+ } else {
+ std::ostringstream e;
+ e << "given invalid scope " << *arg << ". "
+ << "Valid scopes are GLOBAL, DIRECTORY, "
+ "TARGET, SOURCE, TEST, CACHE, INSTALL.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Parse the rest of the arguments up to the values.
+ enum Doing
+ {
+ DoingNone,
+ DoingNames,
+ DoingProperty,
+ DoingValues
+ };
+ Doing doing = DoingNames;
+ const char* sep = "";
+ for (++arg; arg != args.end(); ++arg) {
+ if (*arg == "PROPERTY") {
+ doing = DoingProperty;
+ } else if (*arg == "APPEND") {
+ doing = DoingNone;
+ this->AppendMode = true;
+ this->Remove = false;
+ this->AppendAsString = false;
+ } else if (*arg == "APPEND_STRING") {
+ doing = DoingNone;
+ this->AppendMode = true;
+ this->Remove = false;
+ this->AppendAsString = true;
+ } else if (doing == DoingNames) {
+ this->Names.insert(*arg);
+ } else if (doing == DoingProperty) {
+ this->PropertyName = *arg;
+ doing = DoingValues;
+ } else if (doing == DoingValues) {
+ this->PropertyValue += sep;
+ sep = ";";
+ this->PropertyValue += *arg;
+ this->Remove = false;
+ } else {
+ std::ostringstream e;
+ e << "given invalid argument \"" << *arg << "\".";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+
+ // Make sure a property name was found.
+ if (this->PropertyName.empty()) {
+ this->SetError("not given a PROPERTY <name> argument.");
+ return false;
+ }
+
+ // Dispatch property setting.
+ switch (scope) {
+ case cmProperty::GLOBAL:
+ return this->HandleGlobalMode();
+ case cmProperty::DIRECTORY:
+ return this->HandleDirectoryMode();
+ case cmProperty::TARGET:
+ return this->HandleTargetMode();
+ case cmProperty::SOURCE_FILE:
+ return this->HandleSourceMode();
+ case cmProperty::TEST:
+ return this->HandleTestMode();
+ case cmProperty::CACHE:
+ return this->HandleCacheMode();
+ case cmProperty::INSTALL:
+ return this->HandleInstallMode();
+
+ case cmProperty::VARIABLE:
+ case cmProperty::CACHED_VARIABLE:
+ break; // should never happen
+ }
+ return true;
+}
+
+bool cmSetPropertyCommand::HandleGlobalMode()
+{
+ if (!this->Names.empty()) {
+ this->SetError("given names for GLOBAL scope.");
+ return false;
+ }
+
+ // Set or append the property.
+ cmake* cm = this->Makefile->GetCMakeInstance();
+ const char* name = this->PropertyName.c_str();
+ const char* value = this->PropertyValue.c_str();
+ if (this->Remove) {
+ value = CM_NULLPTR;
+ }
+ if (this->AppendMode) {
+ cm->AppendProperty(name, value ? value : "", this->AppendAsString);
+ } else {
+ cm->SetProperty(name, value);
+ }
+
+ return true;
+}
+
+bool cmSetPropertyCommand::HandleDirectoryMode()
+{
+ if (this->Names.size() > 1) {
+ this->SetError("allows at most one name for DIRECTORY scope.");
+ return false;
+ }
+
+ // Default to the current directory.
+ cmMakefile* mf = this->Makefile;
+
+ // Lookup the directory if given.
+ if (!this->Names.empty()) {
+ // Construct the directory name. Interpret relative paths with
+ // respect to the current directory.
+ std::string dir = *this->Names.begin();
+ if (!cmSystemTools::FileIsFullPath(dir.c_str())) {
+ dir = this->Makefile->GetCurrentSourceDirectory();
+ dir += "/";
+ dir += *this->Names.begin();
+ }
+
+ // The local generators are associated with collapsed paths.
+ dir = cmSystemTools::CollapseFullPath(dir);
+
+ mf = this->Makefile->GetGlobalGenerator()->FindMakefile(dir);
+ if (!mf) {
+ // Could not find the directory.
+ this->SetError(
+ "DIRECTORY scope provided but requested directory was not found. "
+ "This could be because the directory argument was invalid or, "
+ "it is valid but has not been processed yet.");
+ return false;
+ }
+ }
+
+ // Set or append the property.
+ const char* name = this->PropertyName.c_str();
+ const char* value = this->PropertyValue.c_str();
+ if (this->Remove) {
+ value = CM_NULLPTR;
+ }
+ if (this->AppendMode) {
+ mf->AppendProperty(name, value ? value : "", this->AppendAsString);
+ } else {
+ mf->SetProperty(name, value);
+ }
+
+ return true;
+}
+
+bool cmSetPropertyCommand::HandleTargetMode()
+{
+ for (std::set<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ if (this->Makefile->IsAlias(*ni)) {
+ this->SetError("can not be used on an ALIAS target.");
+ return false;
+ }
+ if (cmTarget* target = this->Makefile->FindTargetToUse(*ni)) {
+ // Handle the current target.
+ if (!this->HandleTarget(target)) {
+ return false;
+ }
+ } else {
+ std::ostringstream e;
+ e << "could not find TARGET " << *ni
+ << ". Perhaps it has not yet been created.";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmSetPropertyCommand::HandleTarget(cmTarget* target)
+{
+ // Set or append the property.
+ const char* name = this->PropertyName.c_str();
+ const char* value = this->PropertyValue.c_str();
+ if (this->Remove) {
+ value = CM_NULLPTR;
+ }
+ if (this->AppendMode) {
+ target->AppendProperty(name, value, this->AppendAsString);
+ } else {
+ target->SetProperty(name, value);
+ }
+
+ // Check the resulting value.
+ target->CheckProperty(name, this->Makefile);
+
+ return true;
+}
+
+bool cmSetPropertyCommand::HandleSourceMode()
+{
+ for (std::set<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ // Get the source file.
+ if (cmSourceFile* sf = this->Makefile->GetOrCreateSource(*ni)) {
+ if (!this->HandleSource(sf)) {
+ return false;
+ }
+ } else {
+ std::ostringstream e;
+ e << "given SOURCE name that could not be found or created: " << *ni;
+ this->SetError(e.str());
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmSetPropertyCommand::HandleSource(cmSourceFile* sf)
+{
+ // Set or append the property.
+ const char* name = this->PropertyName.c_str();
+ const char* value = this->PropertyValue.c_str();
+ if (this->Remove) {
+ value = CM_NULLPTR;
+ }
+
+ if (this->AppendMode) {
+ sf->AppendProperty(name, value, this->AppendAsString);
+ } else {
+ sf->SetProperty(name, value);
+ }
+ return true;
+}
+
+bool cmSetPropertyCommand::HandleTestMode()
+{
+ // Look for tests with all names given.
+ std::set<std::string>::iterator next;
+ for (std::set<std::string>::iterator ni = this->Names.begin();
+ ni != this->Names.end(); ni = next) {
+ next = ni;
+ ++next;
+ if (cmTest* test = this->Makefile->GetTest(*ni)) {
+ if (this->HandleTest(test)) {
+ this->Names.erase(ni);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ // Names that are still left were not found.
+ if (!this->Names.empty()) {
+ std::ostringstream e;
+ e << "given TEST names that do not exist:\n";
+ for (std::set<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ e << " " << *ni << "\n";
+ }
+ this->SetError(e.str());
+ return false;
+ }
+ return true;
+}
+
+bool cmSetPropertyCommand::HandleTest(cmTest* test)
+{
+ // Set or append the property.
+ const char* name = this->PropertyName.c_str();
+ const char* value = this->PropertyValue.c_str();
+ if (this->Remove) {
+ value = CM_NULLPTR;
+ }
+ if (this->AppendMode) {
+ test->AppendProperty(name, value, this->AppendAsString);
+ } else {
+ test->SetProperty(name, value);
+ }
+
+ return true;
+}
+
+bool cmSetPropertyCommand::HandleCacheMode()
+{
+ if (this->PropertyName == "ADVANCED") {
+ if (!this->Remove && !cmSystemTools::IsOn(this->PropertyValue.c_str()) &&
+ !cmSystemTools::IsOff(this->PropertyValue.c_str())) {
+ std::ostringstream e;
+ e << "given non-boolean value \"" << this->PropertyValue
+ << "\" for CACHE property \"ADVANCED\". ";
+ this->SetError(e.str());
+ return false;
+ }
+ } else if (this->PropertyName == "TYPE") {
+ if (!cmState::IsCacheEntryType(this->PropertyValue.c_str())) {
+ std::ostringstream e;
+ e << "given invalid CACHE entry TYPE \"" << this->PropertyValue << "\"";
+ this->SetError(e.str());
+ return false;
+ }
+ } else if (this->PropertyName != "HELPSTRING" &&
+ this->PropertyName != "STRINGS" &&
+ this->PropertyName != "VALUE") {
+ std::ostringstream e;
+ e << "given invalid CACHE property " << this->PropertyName << ". "
+ << "Settable CACHE properties are: "
+ << "ADVANCED, HELPSTRING, STRINGS, TYPE, and VALUE.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ for (std::set<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni) {
+ // Get the source file.
+ cmMakefile* mf = this->GetMakefile();
+ cmake* cm = mf->GetCMakeInstance();
+ const char* existingValue = cm->GetState()->GetCacheEntryValue(*ni);
+ if (existingValue) {
+ if (!this->HandleCacheEntry(*ni)) {
+ return false;
+ }
+ } else {
+ std::ostringstream e;
+ e << "could not find CACHE variable " << *ni
+ << ". Perhaps it has not yet been created.";
+ this->SetError(e.str());
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmSetPropertyCommand::HandleCacheEntry(std::string const& cacheKey)
+{
+ // Set or append the property.
+ const char* name = this->PropertyName.c_str();
+ const char* value = this->PropertyValue.c_str();
+ cmState* state = this->Makefile->GetState();
+ if (this->Remove) {
+ state->RemoveCacheEntryProperty(cacheKey, name);
+ }
+ if (this->AppendMode) {
+ state->AppendCacheEntryProperty(cacheKey, name, value,
+ this->AppendAsString);
+ } else {
+ state->SetCacheEntryProperty(cacheKey, name, value);
+ }
+
+ return true;
+}
+
+bool cmSetPropertyCommand::HandleInstallMode()
+{
+ cmake* cm = this->Makefile->GetCMakeInstance();
+
+ for (std::set<std::string>::const_iterator i = this->Names.begin();
+ i != this->Names.end(); ++i) {
+ if (cmInstalledFile* file =
+ cm->GetOrCreateInstalledFile(this->Makefile, *i)) {
+ if (!this->HandleInstall(file)) {
+ return false;
+ }
+ } else {
+ std::ostringstream e;
+ e << "given INSTALL name that could not be found or created: " << *i;
+ this->SetError(e.str());
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmSetPropertyCommand::HandleInstall(cmInstalledFile* file)
+{
+ // Set or append the property.
+ std::string const& name = this->PropertyName;
+
+ cmMakefile* mf = this->Makefile;
+
+ const char* value = this->PropertyValue.c_str();
+ if (this->Remove) {
+ file->RemoveProperty(name);
+ } else if (this->AppendMode) {
+ file->AppendProperty(mf, name, value, this->AppendAsString);
+ } else {
+ file->SetProperty(mf, name, value);
+ }
+ return true;
+}
diff --git a/Source/cmSetPropertyCommand.h b/Source/cmSetPropertyCommand.h
new file mode 100644
index 0000000..e78b04c
--- /dev/null
+++ b/Source/cmSetPropertyCommand.h
@@ -0,0 +1,66 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSetsPropertiesCommand_h
+#define cmSetsPropertiesCommand_h
+
+#include "cmCommand.h"
+
+class cmSetPropertyCommand : public cmCommand
+{
+public:
+ cmSetPropertyCommand();
+
+ cmCommand* Clone() CM_OVERRIDE { return new cmSetPropertyCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "set_property"; }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ cmTypeMacro(cmSetPropertyCommand, cmCommand);
+
+private:
+ std::set<std::string> Names;
+ std::string PropertyName;
+ std::string PropertyValue;
+ bool Remove;
+ bool AppendMode;
+ bool AppendAsString;
+
+ // Implementation of each property type.
+ bool HandleGlobalMode();
+ bool HandleDirectoryMode();
+ bool HandleTargetMode();
+ bool HandleTarget(cmTarget* target);
+ bool HandleSourceMode();
+ bool HandleSource(cmSourceFile* sf);
+ bool HandleTestMode();
+ bool HandleTest(cmTest* test);
+ bool HandleCacheMode();
+ bool HandleCacheEntry(std::string const&);
+ bool HandleInstallMode();
+ bool HandleInstall(cmInstalledFile* file);
+};
+
+#endif
diff --git a/Source/cmSetSourceFilesPropertiesCommand.cxx b/Source/cmSetSourceFilesPropertiesCommand.cxx
new file mode 100644
index 0000000..976f3c8
--- /dev/null
+++ b/Source/cmSetSourceFilesPropertiesCommand.cxx
@@ -0,0 +1,130 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSetSourceFilesPropertiesCommand.h"
+
+#include "cmSourceFile.h"
+
+// cmSetSourceFilesPropertiesCommand
+bool cmSetSourceFilesPropertiesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // break the arguments into source file names and properties
+ int numFiles = 0;
+ std::vector<std::string>::const_iterator j;
+ j = args.begin();
+ // old style allows for specifier before PROPERTIES keyword
+ while (j != args.end() && *j != "ABSTRACT" && *j != "WRAP_EXCLUDE" &&
+ *j != "GENERATED" && *j != "COMPILE_FLAGS" &&
+ *j != "OBJECT_DEPENDS" && *j != "PROPERTIES") {
+ numFiles++;
+ ++j;
+ }
+
+ // now call the worker function
+ std::string errors;
+ bool ret = cmSetSourceFilesPropertiesCommand::RunCommand(
+ this->Makefile, args.begin(), args.begin() + numFiles,
+ args.begin() + numFiles, args.end(), errors);
+ if (!ret) {
+ this->SetError(errors);
+ }
+ return ret;
+}
+
+bool cmSetSourceFilesPropertiesCommand::RunCommand(
+ cmMakefile* mf, std::vector<std::string>::const_iterator filebeg,
+ std::vector<std::string>::const_iterator fileend,
+ std::vector<std::string>::const_iterator propbeg,
+ std::vector<std::string>::const_iterator propend, std::string& errors)
+{
+ std::vector<std::string> propertyPairs;
+ bool generated = false;
+ std::vector<std::string>::const_iterator j;
+ // build the property pairs
+ for (j = propbeg; j != propend; ++j) {
+ // old style allows for specifier before PROPERTIES keyword
+ if (*j == "ABSTRACT") {
+ propertyPairs.push_back("ABSTRACT");
+ propertyPairs.push_back("1");
+ } else if (*j == "WRAP_EXCLUDE") {
+ propertyPairs.push_back("WRAP_EXCLUDE");
+ propertyPairs.push_back("1");
+ } else if (*j == "GENERATED") {
+ generated = true;
+ propertyPairs.push_back("GENERATED");
+ propertyPairs.push_back("1");
+ } else if (*j == "COMPILE_FLAGS") {
+ propertyPairs.push_back("COMPILE_FLAGS");
+ ++j;
+ if (j == propend) {
+ errors = "called with incorrect number of arguments "
+ "COMPILE_FLAGS with no flags";
+ return false;
+ }
+ propertyPairs.push_back(*j);
+ } else if (*j == "OBJECT_DEPENDS") {
+ propertyPairs.push_back("OBJECT_DEPENDS");
+ ++j;
+ if (j == propend) {
+ errors = "called with incorrect number of arguments "
+ "OBJECT_DEPENDS with no dependencies";
+ return false;
+ }
+ propertyPairs.push_back(*j);
+ } else if (*j == "PROPERTIES") {
+ // now loop through the rest of the arguments, new style
+ ++j;
+ while (j != propend) {
+ propertyPairs.push_back(*j);
+ if (*j == "GENERATED") {
+ ++j;
+ if (j != propend && cmSystemTools::IsOn(j->c_str())) {
+ generated = true;
+ }
+ } else {
+ ++j;
+ }
+ if (j == propend) {
+ errors = "called with incorrect number of arguments.";
+ return false;
+ }
+ propertyPairs.push_back(*j);
+ ++j;
+ }
+ // break out of the loop because j is already == end
+ break;
+ } else {
+ errors = "called with illegal arguments, maybe missing a "
+ "PROPERTIES specifier?";
+ return false;
+ }
+ }
+
+ // now loop over all the files
+ for (j = filebeg; j != fileend; ++j) {
+ // get the source file
+ cmSourceFile* sf = mf->GetOrCreateSource(*j, generated);
+ if (sf) {
+ // now loop through all the props and set them
+ unsigned int k;
+ for (k = 0; k < propertyPairs.size(); k = k + 2) {
+ sf->SetProperty(propertyPairs[k], propertyPairs[k + 1].c_str());
+ }
+ }
+ }
+ return true;
+}
diff --git a/Source/cmSetSourceFilesPropertiesCommand.h b/Source/cmSetSourceFilesPropertiesCommand.h
new file mode 100644
index 0000000..f6b4de0
--- /dev/null
+++ b/Source/cmSetSourceFilesPropertiesCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSetSourceFilesPropertiesCommand_h
+#define cmSetSourceFilesPropertiesCommand_h
+
+#include "cmCommand.h"
+
+class cmSetSourceFilesPropertiesCommand : public cmCommand
+{
+public:
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ return new cmSetSourceFilesPropertiesCommand;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE
+ {
+ return "set_source_files_properties";
+ }
+
+ cmTypeMacro(cmSetSourceFilesPropertiesCommand, cmCommand);
+
+ static bool RunCommand(cmMakefile* mf,
+ std::vector<std::string>::const_iterator filebeg,
+ std::vector<std::string>::const_iterator fileend,
+ std::vector<std::string>::const_iterator propbeg,
+ std::vector<std::string>::const_iterator propend,
+ std::string& errors);
+};
+
+#endif
diff --git a/Source/cmSetTargetPropertiesCommand.cxx b/Source/cmSetTargetPropertiesCommand.cxx
new file mode 100644
index 0000000..86c8016
--- /dev/null
+++ b/Source/cmSetTargetPropertiesCommand.cxx
@@ -0,0 +1,85 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSetTargetPropertiesCommand.h"
+
+#include "cmGlobalGenerator.h"
+
+// cmSetTargetPropertiesCommand
+bool cmSetTargetPropertiesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // first collect up the list of files
+ std::vector<std::string> propertyPairs;
+ int numFiles = 0;
+ std::vector<std::string>::const_iterator j;
+ for (j = args.begin(); j != args.end(); ++j) {
+ if (*j == "PROPERTIES") {
+ // now loop through the rest of the arguments, new style
+ ++j;
+ if (std::distance(j, args.end()) % 2 != 0) {
+ this->SetError("called with incorrect number of arguments.");
+ return false;
+ }
+ propertyPairs.insert(propertyPairs.end(), j, args.end());
+ break;
+ } else {
+ numFiles++;
+ }
+ }
+ if (propertyPairs.empty()) {
+ this->SetError("called with illegal arguments, maybe missing "
+ "a PROPERTIES specifier?");
+ return false;
+ }
+
+ // now loop over all the targets
+ int i;
+ for (i = 0; i < numFiles; ++i) {
+ if (this->Makefile->IsAlias(args[i])) {
+ this->SetError("can not be used on an ALIAS target.");
+ return false;
+ }
+ bool ret = cmSetTargetPropertiesCommand::SetOneTarget(
+ args[i], propertyPairs, this->Makefile);
+ if (!ret) {
+ std::string message = "Can not find target to add properties to: ";
+ message += args[i];
+ this->SetError(message);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmSetTargetPropertiesCommand::SetOneTarget(
+ const std::string& tname, std::vector<std::string>& propertyPairs,
+ cmMakefile* mf)
+{
+ if (cmTarget* target = mf->FindTargetToUse(tname)) {
+ // now loop through all the props and set them
+ unsigned int k;
+ for (k = 0; k < propertyPairs.size(); k = k + 2) {
+ target->SetProperty(propertyPairs[k], propertyPairs[k + 1].c_str());
+ target->CheckProperty(propertyPairs[k], mf);
+ }
+ }
+ // if file is not already in the makefile, then add it
+ else {
+ return false;
+ }
+ return true;
+}
diff --git a/Source/cmSetTargetPropertiesCommand.h b/Source/cmSetTargetPropertiesCommand.h
new file mode 100644
index 0000000..1ed8d90
--- /dev/null
+++ b/Source/cmSetTargetPropertiesCommand.h
@@ -0,0 +1,44 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSetTargetsPropertiesCommand_h
+#define cmSetTargetsPropertiesCommand_h
+
+#include "cmCommand.h"
+
+class cmSetTargetPropertiesCommand : public cmCommand
+{
+public:
+ cmCommand* Clone() CM_OVERRIDE { return new cmSetTargetPropertiesCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "set_target_properties"; }
+
+ /**
+ * Used by this command and cmSetPropertiesCommand
+ */
+ static bool SetOneTarget(const std::string& tname,
+ std::vector<std::string>& propertyPairs,
+ cmMakefile* mf);
+
+ cmTypeMacro(cmSetTargetPropertiesCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmSetTestsPropertiesCommand.cxx b/Source/cmSetTestsPropertiesCommand.cxx
new file mode 100644
index 0000000..2fb137f
--- /dev/null
+++ b/Source/cmSetTestsPropertiesCommand.cxx
@@ -0,0 +1,84 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSetTestsPropertiesCommand.h"
+
+#include "cmTest.h"
+#include "cmake.h"
+
+// cmSetTestsPropertiesCommand
+bool cmSetTestsPropertiesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // first collect up the list of files
+ std::vector<std::string> propertyPairs;
+ int numFiles = 0;
+ std::vector<std::string>::const_iterator j;
+ for (j = args.begin(); j != args.end(); ++j) {
+ if (*j == "PROPERTIES") {
+ // now loop through the rest of the arguments, new style
+ ++j;
+ if (std::distance(j, args.end()) % 2 != 0) {
+ this->SetError("called with incorrect number of arguments.");
+ return false;
+ }
+ propertyPairs.insert(propertyPairs.end(), j, args.end());
+ break;
+ } else {
+ numFiles++;
+ }
+ }
+ if (propertyPairs.empty()) {
+ this->SetError("called with illegal arguments, maybe "
+ "missing a PROPERTIES specifier?");
+ return false;
+ }
+
+ // now loop over all the targets
+ int i;
+ for (i = 0; i < numFiles; ++i) {
+ std::string errors;
+ bool ret = cmSetTestsPropertiesCommand::SetOneTest(args[i], propertyPairs,
+ this->Makefile, errors);
+ if (!ret) {
+ this->SetError(errors);
+ return ret;
+ }
+ }
+
+ return true;
+}
+
+bool cmSetTestsPropertiesCommand::SetOneTest(
+ const std::string& tname, std::vector<std::string>& propertyPairs,
+ cmMakefile* mf, std::string& errors)
+{
+ if (cmTest* test = mf->GetTest(tname)) {
+ // now loop through all the props and set them
+ unsigned int k;
+ for (k = 0; k < propertyPairs.size(); k = k + 2) {
+ if (!propertyPairs[k].empty()) {
+ test->SetProperty(propertyPairs[k], propertyPairs[k + 1].c_str());
+ }
+ }
+ } else {
+ errors = "Can not find test to add properties to: ";
+ errors += tname;
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmSetTestsPropertiesCommand.h b/Source/cmSetTestsPropertiesCommand.h
new file mode 100644
index 0000000..712ab36
--- /dev/null
+++ b/Source/cmSetTestsPropertiesCommand.h
@@ -0,0 +1,41 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSetTestsPropertiesCommand_h
+#define cmSetTestsPropertiesCommand_h
+
+#include "cmCommand.h"
+
+class cmSetTestsPropertiesCommand : public cmCommand
+{
+public:
+ cmCommand* Clone() CM_OVERRIDE { return new cmSetTestsPropertiesCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "set_tests_properties"; }
+
+ cmTypeMacro(cmSetTestsPropertiesCommand, cmCommand);
+
+ static bool SetOneTest(const std::string& tname,
+ std::vector<std::string>& propertyPairs,
+ cmMakefile* mf, std::string& errors);
+};
+
+#endif
diff --git a/Source/cmSiteNameCommand.cxx b/Source/cmSiteNameCommand.cxx
new file mode 100644
index 0000000..5c14991
--- /dev/null
+++ b/Source/cmSiteNameCommand.cxx
@@ -0,0 +1,83 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSiteNameCommand.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+// cmSiteNameCommand
+bool cmSiteNameCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() != 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ std::vector<std::string> paths;
+ paths.push_back("/usr/bsd");
+ paths.push_back("/usr/sbin");
+ paths.push_back("/usr/bin");
+ paths.push_back("/bin");
+ paths.push_back("/sbin");
+ paths.push_back("/usr/local/bin");
+
+ const char* cacheValue = this->Makefile->GetDefinition(args[0]);
+ if (cacheValue) {
+ return true;
+ }
+
+ const char* temp = this->Makefile->GetDefinition("HOSTNAME");
+ std::string hostname_cmd;
+ if (temp) {
+ hostname_cmd = temp;
+ } else {
+ hostname_cmd = cmSystemTools::FindProgram("hostname", paths);
+ }
+
+ std::string siteName = "unknown";
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ std::string host;
+ if (cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\"
+ "Control\\ComputerName\\ComputerName;ComputerName",
+ host)) {
+ siteName = host;
+ }
+#else
+ // try to find the hostname for this computer
+ if (!cmSystemTools::IsOff(hostname_cmd.c_str())) {
+ std::string host;
+ cmSystemTools::RunSingleCommand(hostname_cmd.c_str(), &host, CM_NULLPTR,
+ CM_NULLPTR, CM_NULLPTR,
+ cmSystemTools::OUTPUT_NONE);
+
+ // got the hostname
+ if (!host.empty()) {
+ // remove any white space from the host name
+ std::string hostRegExp = "[ \t\n\r]*([^\t\n\r ]*)[ \t\n\r]*";
+ cmsys::RegularExpression hostReg(hostRegExp.c_str());
+ if (hostReg.find(host.c_str())) {
+ // strip whitespace
+ host = hostReg.match(1);
+ }
+
+ if (!host.empty()) {
+ siteName = host;
+ }
+ }
+ }
+#endif
+ this->Makefile->AddCacheDefinition(
+ args[0], siteName.c_str(),
+ "Name of the computer/site where compile is being run", cmState::STRING);
+
+ return true;
+}
diff --git a/Source/cmSiteNameCommand.h b/Source/cmSiteNameCommand.h
new file mode 100644
index 0000000..7a9ca9d
--- /dev/null
+++ b/Source/cmSiteNameCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSiteNameCommand_h
+#define cmSiteNameCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmSiteNameCommand
+ * \brief site_name command
+ *
+ * cmSiteNameCommand implements the site_name CMake command
+ */
+class cmSiteNameCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmSiteNameCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "site_name"; }
+
+ cmTypeMacro(cmSiteNameCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx
new file mode 100644
index 0000000..04727b2
--- /dev/null
+++ b/Source/cmSourceFile.cxx
@@ -0,0 +1,336 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSourceFile.h"
+
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+cmSourceFile::cmSourceFile(cmMakefile* mf, const std::string& name)
+ : Location(mf, name)
+{
+ this->CustomCommand = CM_NULLPTR;
+ this->FindFullPathFailed = false;
+ this->IsUiFile = (".ui" == cmSystemTools::GetFilenameLastExtension(
+ this->Location.GetName()));
+}
+
+cmSourceFile::~cmSourceFile()
+{
+ this->SetCustomCommand(CM_NULLPTR);
+}
+
+std::string const& cmSourceFile::GetExtension() const
+{
+ return this->Extension;
+}
+
+const std::string cmSourceFile::propLANGUAGE = "LANGUAGE";
+
+void cmSourceFile::SetObjectLibrary(std::string const& objlib)
+{
+ this->ObjectLibrary = objlib;
+}
+
+std::string cmSourceFile::GetObjectLibrary() const
+{
+ return this->ObjectLibrary;
+}
+
+std::string cmSourceFile::GetLanguage()
+{
+ // If the language was set explicitly by the user then use it.
+ if (const char* lang = this->GetProperty(propLANGUAGE)) {
+ return lang;
+ }
+
+ // Perform computation needed to get the language if necessary.
+ if (this->FullPath.empty() && this->Language.empty()) {
+ // If a known extension is given or a known full path is given
+ // then trust that the current extension is sufficient to
+ // determine the language. This will fail only if the user
+ // specifies a full path to the source but leaves off the
+ // extension, which is kind of weird.
+ if (this->Location.ExtensionIsAmbiguous() &&
+ this->Location.DirectoryIsAmbiguous()) {
+ // Finalize the file location to get the extension and set the
+ // language.
+ this->GetFullPath();
+ } else {
+ // Use the known extension to get the language if possible.
+ std::string ext =
+ cmSystemTools::GetFilenameLastExtension(this->Location.GetName());
+ this->CheckLanguage(ext);
+ }
+ }
+
+ // Now try to determine the language.
+ return static_cast<cmSourceFile const*>(this)->GetLanguage();
+}
+
+std::string cmSourceFile::GetLanguage() const
+{
+ // If the language was set explicitly by the user then use it.
+ if (const char* lang = this->GetProperty(propLANGUAGE)) {
+ return lang;
+ }
+
+ // If the language was determined from the source file extension use it.
+ if (!this->Language.empty()) {
+ return this->Language;
+ }
+
+ // The language is not known.
+ return "";
+}
+
+cmSourceFileLocation const& cmSourceFile::GetLocation() const
+{
+ return this->Location;
+}
+
+std::string const& cmSourceFile::GetFullPath(std::string* error)
+{
+ if (this->FullPath.empty()) {
+ if (this->FindFullPath(error)) {
+ this->CheckExtension();
+ }
+ }
+ return this->FullPath;
+}
+
+std::string const& cmSourceFile::GetFullPath() const
+{
+ return this->FullPath;
+}
+
+bool cmSourceFile::FindFullPath(std::string* error)
+{
+ // If thie method has already failed once do not try again.
+ if (this->FindFullPathFailed) {
+ return false;
+ }
+
+ // If the file is generated compute the location without checking on
+ // disk.
+ if (this->GetPropertyAsBool("GENERATED")) {
+ // The file is either already a full path or is relative to the
+ // build directory for the target.
+ this->Location.DirectoryUseBinary();
+ this->FullPath = this->Location.GetDirectory();
+ this->FullPath += "/";
+ this->FullPath += this->Location.GetName();
+ return true;
+ }
+
+ // The file is not generated. It must exist on disk.
+ cmMakefile const* mf = this->Location.GetMakefile();
+ const char* tryDirs[3] = { CM_NULLPTR, CM_NULLPTR, CM_NULLPTR };
+ if (this->Location.DirectoryIsAmbiguous()) {
+ tryDirs[0] = mf->GetCurrentSourceDirectory();
+ tryDirs[1] = mf->GetCurrentBinaryDirectory();
+ } else {
+ tryDirs[0] = "";
+ }
+ const std::vector<std::string>& srcExts =
+ mf->GetCMakeInstance()->GetSourceExtensions();
+ std::vector<std::string> hdrExts =
+ mf->GetCMakeInstance()->GetHeaderExtensions();
+ for (const char* const* di = tryDirs; *di; ++di) {
+ std::string tryPath = this->Location.GetDirectory();
+ if (!tryPath.empty()) {
+ tryPath += "/";
+ }
+ tryPath += this->Location.GetName();
+ tryPath = cmSystemTools::CollapseFullPath(tryPath, *di);
+ if (this->TryFullPath(tryPath, "")) {
+ return true;
+ }
+ for (std::vector<std::string>::const_iterator ei = srcExts.begin();
+ ei != srcExts.end(); ++ei) {
+ if (this->TryFullPath(tryPath, *ei)) {
+ return true;
+ }
+ }
+ for (std::vector<std::string>::const_iterator ei = hdrExts.begin();
+ ei != hdrExts.end(); ++ei) {
+ if (this->TryFullPath(tryPath, *ei)) {
+ return true;
+ }
+ }
+ }
+
+ std::ostringstream e;
+ std::string missing = this->Location.GetDirectory();
+ if (!missing.empty()) {
+ missing += "/";
+ }
+ missing += this->Location.GetName();
+ e << "Cannot find source file:\n " << missing << "\nTried extensions";
+ for (std::vector<std::string>::const_iterator ext = srcExts.begin();
+ ext != srcExts.end(); ++ext) {
+ e << " ." << *ext;
+ }
+ for (std::vector<std::string>::const_iterator ext = hdrExts.begin();
+ ext != hdrExts.end(); ++ext) {
+ e << " ." << *ext;
+ }
+ if (error) {
+ *error = e.str();
+ } else {
+ this->Location.GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str());
+ }
+ this->FindFullPathFailed = true;
+ return false;
+}
+
+bool cmSourceFile::TryFullPath(const std::string& path, const std::string& ext)
+{
+ std::string tryPath = path;
+ if (!ext.empty()) {
+ tryPath += ".";
+ tryPath += ext;
+ }
+ if (cmSystemTools::FileExists(tryPath.c_str())) {
+ this->FullPath = tryPath;
+ return true;
+ }
+ return false;
+}
+
+void cmSourceFile::CheckExtension()
+{
+ // Compute the extension.
+ std::string realExt =
+ cmSystemTools::GetFilenameLastExtension(this->FullPath);
+ if (!realExt.empty()) {
+ // Store the extension without the leading '.'.
+ this->Extension = realExt.substr(1);
+ }
+
+ // Look for object files.
+ if (this->Extension == "obj" || this->Extension == "o" ||
+ this->Extension == "lo") {
+ this->SetProperty("EXTERNAL_OBJECT", "1");
+ }
+
+ // Try to identify the source file language from the extension.
+ if (this->Language.empty()) {
+ this->CheckLanguage(this->Extension);
+ }
+}
+
+void cmSourceFile::CheckLanguage(std::string const& ext)
+{
+ // Try to identify the source file language from the extension.
+ cmMakefile const* mf = this->Location.GetMakefile();
+ cmGlobalGenerator* gg = mf->GetGlobalGenerator();
+ std::string l = gg->GetLanguageFromExtension(ext.c_str());
+ if (!l.empty()) {
+ this->Language = l;
+ }
+}
+
+bool cmSourceFile::Matches(cmSourceFileLocation const& loc)
+{
+ return this->Location.Matches(loc);
+}
+
+void cmSourceFile::SetProperty(const std::string& prop, const char* value)
+{
+ this->Properties.SetProperty(prop, value);
+
+ if (this->IsUiFile) {
+ cmMakefile const* mf = this->Location.GetMakefile();
+ if (prop == "AUTOUIC_OPTIONS") {
+ const_cast<cmMakefile*>(mf)->AddQtUiFileWithOptions(this);
+ }
+ }
+}
+
+void cmSourceFile::AppendProperty(const std::string& prop, const char* value,
+ bool asString)
+{
+ this->Properties.AppendProperty(prop, value, asString);
+}
+
+const char* cmSourceFile::GetPropertyForUser(const std::string& prop)
+{
+ // This method is a consequence of design history and backwards
+ // compatibility. GetProperty is (and should be) a const method.
+ // Computed properties should not be stored back in the property map
+ // but instead reference information already known. If they need to
+ // cache information in a mutable ivar to provide the return string
+ // safely then so be it.
+ //
+ // The LOCATION property is particularly problematic. The CMake
+ // language has very loose restrictions on the names that will match
+ // a given source file (for historical reasons). Implementing
+ // lookups correctly with such loose naming requires the
+ // cmSourceFileLocation class to commit to a particular full path to
+ // the source file as late as possible. If the users requests the
+ // LOCATION property we must commit now.
+ if (prop == "LOCATION") {
+ // Commit to a location.
+ this->GetFullPath();
+ }
+
+ // Perform the normal property lookup.
+ return this->GetProperty(prop);
+}
+
+const char* cmSourceFile::GetProperty(const std::string& prop) const
+{
+ // Check for computed properties.
+ if (prop == "LOCATION") {
+ if (this->FullPath.empty()) {
+ return CM_NULLPTR;
+ } else {
+ return this->FullPath.c_str();
+ }
+ }
+
+ const char* retVal = this->Properties.GetPropertyValue(prop);
+ if (!retVal) {
+ cmMakefile const* mf = this->Location.GetMakefile();
+ const bool chain =
+ mf->GetState()->IsPropertyChained(prop, cmProperty::SOURCE_FILE);
+ if (chain) {
+ return mf->GetProperty(prop, chain);
+ }
+ }
+
+ return retVal;
+}
+
+bool cmSourceFile::GetPropertyAsBool(const std::string& prop) const
+{
+ return cmSystemTools::IsOn(this->GetProperty(prop));
+}
+
+cmCustomCommand* cmSourceFile::GetCustomCommand()
+{
+ return this->CustomCommand;
+}
+
+cmCustomCommand const* cmSourceFile::GetCustomCommand() const
+{
+ return this->CustomCommand;
+}
+
+void cmSourceFile::SetCustomCommand(cmCustomCommand* cc)
+{
+ cmCustomCommand* old = this->CustomCommand;
+ this->CustomCommand = cc;
+ delete old;
+}
diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h
new file mode 100644
index 0000000..a3808f7
--- /dev/null
+++ b/Source/cmSourceFile.h
@@ -0,0 +1,127 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSourceFile_h
+#define cmSourceFile_h
+
+#include "cmSourceFileLocation.h"
+
+#include "cmCustomCommand.h"
+#include "cmPropertyMap.h"
+
+class cmake;
+
+/** \class cmSourceFile
+ * \brief Represent a class loaded from a makefile.
+ *
+ * cmSourceFile is represents a class loaded from
+ * a makefile.
+ */
+class cmSourceFile
+{
+public:
+ /**
+ * Construct with the makefile storing the source and the initial
+ * name referencing it.
+ */
+ cmSourceFile(cmMakefile* mf, const std::string& name);
+
+ ~cmSourceFile();
+
+ /**
+ * Get the list of the custom commands for this source file
+ */
+ cmCustomCommand* GetCustomCommand();
+ cmCustomCommand const* GetCustomCommand() const;
+ void SetCustomCommand(cmCustomCommand* cc);
+
+ ///! 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);
+ const char* GetProperty(const std::string& prop) const;
+ bool GetPropertyAsBool(const std::string& prop) const;
+
+ /** Implement getting a property when called from a CMake language
+ command like get_property or get_source_file_property. */
+ const char* GetPropertyForUser(const std::string& prop);
+
+ /**
+ * The full path to the file. The non-const version of this method
+ * may attempt to locate the file on disk and finalize its location.
+ * The const version of this method may return an empty string if
+ * the non-const version has not yet been called (yes this is a
+ * horrible interface, but is necessary for backwards
+ * compatibility).
+ */
+ std::string const& GetFullPath(std::string* error = CM_NULLPTR);
+ std::string const& GetFullPath() const;
+
+ /**
+ * Get the information currently known about the source file
+ * location without attempting to locate the file as GetFullPath
+ * would. See cmSourceFileLocation documentation.
+ */
+ cmSourceFileLocation const& GetLocation() const;
+
+ /**
+ * Get the file extension of this source file.
+ */
+ std::string const& GetExtension() const;
+
+ /**
+ * Get the language of the compiler to use for this source file.
+ */
+ std::string GetLanguage();
+ std::string GetLanguage() const;
+
+ /**
+ * Return the vector that holds the list of dependencies
+ */
+ const std::vector<std::string>& GetDepends() const { return this->Depends; }
+ void AddDepend(const std::string& d) { this->Depends.push_back(d); }
+
+ // Get the properties
+ cmPropertyMap& GetProperties() { return this->Properties; }
+
+ /**
+ * Check whether the given source file location could refer to this
+ * source.
+ */
+ bool Matches(cmSourceFileLocation const&);
+
+ void SetObjectLibrary(std::string const& objlib);
+ std::string GetObjectLibrary() const;
+
+private:
+ cmSourceFileLocation Location;
+ cmPropertyMap Properties;
+ cmCustomCommand* CustomCommand;
+ std::string Extension;
+ std::string Language;
+ std::string FullPath;
+ std::string ObjectLibrary;
+ std::vector<std::string> Depends;
+ bool FindFullPathFailed;
+ bool IsUiFile;
+
+ bool FindFullPath(std::string* error);
+ bool TryFullPath(const std::string& path, const std::string& ext);
+ void CheckExtension();
+ void CheckLanguage(std::string const& ext);
+
+ static const std::string propLANGUAGE;
+};
+
+// TODO: Factor out into platform information modules.
+#define CM_HEADER_REGEX "\\.(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$"
+
+#endif
diff --git a/Source/cmSourceFileLocation.cxx b/Source/cmSourceFileLocation.cxx
new file mode 100644
index 0000000..099a6f0
--- /dev/null
+++ b/Source/cmSourceFileLocation.cxx
@@ -0,0 +1,256 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSourceFileLocation.h"
+
+#include "cmAlgorithms.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include "assert.h"
+
+cmSourceFileLocation::cmSourceFileLocation()
+ : Makefile(CM_NULLPTR)
+ , AmbiguousDirectory(true)
+ , AmbiguousExtension(true)
+{
+}
+
+cmSourceFileLocation::cmSourceFileLocation(const cmSourceFileLocation& loc)
+ : Makefile(loc.Makefile)
+{
+ this->AmbiguousDirectory = loc.AmbiguousDirectory;
+ this->AmbiguousExtension = loc.AmbiguousExtension;
+ this->Directory = loc.Directory;
+ this->Name = loc.Name;
+}
+
+cmSourceFileLocation& cmSourceFileLocation::operator=(
+ const cmSourceFileLocation& loc)
+{
+ if (this == &loc) {
+ return *this;
+ }
+ this->Makefile = loc.Makefile;
+ this->AmbiguousDirectory = loc.AmbiguousDirectory;
+ this->AmbiguousExtension = loc.AmbiguousExtension;
+ this->Directory = loc.Directory;
+ this->Name = loc.Name;
+ this->UpdateExtension(this->Name);
+ return *this;
+}
+
+cmSourceFileLocation::cmSourceFileLocation(cmMakefile const* mf,
+ const std::string& name)
+ : Makefile(mf)
+{
+ this->AmbiguousDirectory = !cmSystemTools::FileIsFullPath(name.c_str());
+ this->AmbiguousExtension = true;
+ this->Directory = cmSystemTools::GetFilenamePath(name);
+ if (cmSystemTools::FileIsFullPath(this->Directory.c_str())) {
+ this->Directory = cmSystemTools::CollapseFullPath(this->Directory);
+ }
+ this->Name = cmSystemTools::GetFilenameName(name);
+ this->UpdateExtension(name);
+}
+
+void cmSourceFileLocation::Update(cmSourceFileLocation const& loc)
+{
+ if (this->AmbiguousDirectory && !loc.AmbiguousDirectory) {
+ this->Directory = loc.Directory;
+ this->AmbiguousDirectory = false;
+ }
+ if (this->AmbiguousExtension && !loc.AmbiguousExtension) {
+ this->Name = loc.Name;
+ this->AmbiguousExtension = false;
+ }
+}
+
+void cmSourceFileLocation::DirectoryUseSource()
+{
+ assert(this->Makefile);
+ if (this->AmbiguousDirectory) {
+ this->Directory = cmSystemTools::CollapseFullPath(
+ this->Directory, this->Makefile->GetCurrentSourceDirectory());
+ this->AmbiguousDirectory = false;
+ }
+}
+
+void cmSourceFileLocation::DirectoryUseBinary()
+{
+ assert(this->Makefile);
+ if (this->AmbiguousDirectory) {
+ this->Directory = cmSystemTools::CollapseFullPath(
+ this->Directory, this->Makefile->GetCurrentBinaryDirectory());
+ this->AmbiguousDirectory = false;
+ }
+}
+
+void cmSourceFileLocation::UpdateExtension(const std::string& name)
+{
+ assert(this->Makefile);
+ // Check the extension.
+ std::string ext = cmSystemTools::GetFilenameLastExtension(name);
+ if (!ext.empty()) {
+ ext = ext.substr(1);
+ }
+
+ // The global generator checks extensions of enabled languages.
+ cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ cmMakefile const* mf = this->Makefile;
+ const std::vector<std::string>& srcExts =
+ mf->GetCMakeInstance()->GetSourceExtensions();
+ const std::vector<std::string>& hdrExts =
+ mf->GetCMakeInstance()->GetHeaderExtensions();
+ if (!gg->GetLanguageFromExtension(ext.c_str()).empty() ||
+ std::find(srcExts.begin(), srcExts.end(), ext) != srcExts.end() ||
+ std::find(hdrExts.begin(), hdrExts.end(), ext) != hdrExts.end()) {
+ // This is a known extension. Use the given filename with extension.
+ this->Name = cmSystemTools::GetFilenameName(name);
+ this->AmbiguousExtension = false;
+ } else {
+ // This is not a known extension. See if the file exists on disk as
+ // named.
+ std::string tryPath;
+ if (this->AmbiguousDirectory) {
+ // Check the source tree only because a file in the build tree should
+ // be specified by full path at least once. We do not want this
+ // detection to depend on whether the project has already been built.
+ tryPath = this->Makefile->GetCurrentSourceDirectory();
+ tryPath += "/";
+ }
+ if (!this->Directory.empty()) {
+ tryPath += this->Directory;
+ tryPath += "/";
+ }
+ tryPath += this->Name;
+ if (cmSystemTools::FileExists(tryPath.c_str(), true)) {
+ // We found a source file named by the user on disk. Trust it's
+ // extension.
+ this->Name = cmSystemTools::GetFilenameName(name);
+ this->AmbiguousExtension = false;
+
+ // If the directory was ambiguous, it isn't anymore.
+ if (this->AmbiguousDirectory) {
+ this->DirectoryUseSource();
+ }
+ }
+ }
+}
+
+bool cmSourceFileLocation::MatchesAmbiguousExtension(
+ cmSourceFileLocation const& loc) const
+{
+ assert(this->Makefile);
+ // This location's extension is not ambiguous but loc's extension
+ // is. See if the names match as-is.
+ if (this->Name == loc.Name) {
+ return true;
+ }
+
+ // Check if loc's name could possibly be extended to our name by
+ // adding an extension.
+ if (!(this->Name.size() > loc.Name.size() &&
+ this->Name[loc.Name.size()] == '.' &&
+ cmHasLiteralPrefixImpl(this->Name.c_str(), loc.Name.c_str(),
+ loc.Name.size()))) {
+ return false;
+ }
+
+ // Only a fixed set of extensions will be tried to match a file on
+ // disk. One of these must match if loc refers to this source file.
+ std::string const& ext = this->Name.substr(loc.Name.size() + 1);
+ cmMakefile const* mf = this->Makefile;
+ const std::vector<std::string>& srcExts =
+ mf->GetCMakeInstance()->GetSourceExtensions();
+ if (std::find(srcExts.begin(), srcExts.end(), ext) != srcExts.end()) {
+ return true;
+ }
+ std::vector<std::string> hdrExts =
+ mf->GetCMakeInstance()->GetHeaderExtensions();
+ return std::find(hdrExts.begin(), hdrExts.end(), ext) != hdrExts.end();
+}
+
+bool cmSourceFileLocation::Matches(cmSourceFileLocation const& loc)
+{
+ assert(this->Makefile);
+ if (this->AmbiguousExtension == loc.AmbiguousExtension) {
+ // Both extensions are similarly ambiguous. Since only the old fixed set
+ // of extensions will be tried, the names must match at this point to be
+ // the same file.
+ if (this->Name.size() != loc.Name.size() ||
+ !cmSystemTools::ComparePath(this->Name, loc.Name)) {
+ return false;
+ }
+ } else {
+ const cmSourceFileLocation* loc1;
+ const cmSourceFileLocation* loc2;
+ if (this->AmbiguousExtension) {
+ // Only "this" extension is ambiguous.
+ loc1 = &loc;
+ loc2 = this;
+ } else {
+ // Only "loc" extension is ambiguous.
+ loc1 = this;
+ loc2 = &loc;
+ }
+ if (!loc1->MatchesAmbiguousExtension(*loc2)) {
+ return false;
+ }
+ }
+
+ if (!this->AmbiguousDirectory && !loc.AmbiguousDirectory) {
+ // Both sides have absolute directories.
+ if (this->Directory != loc.Directory) {
+ return false;
+ }
+ } else if (this->AmbiguousDirectory && loc.AmbiguousDirectory) {
+ if (this->Makefile == loc.Makefile) {
+ // Both sides have directories relative to the same location.
+ if (this->Directory != loc.Directory) {
+ return false;
+ }
+ } else {
+ // Each side has a directory relative to a different location.
+ // This can occur when referencing a source file from a different
+ // directory. This is not yet allowed.
+ this->Makefile->IssueMessage(
+ cmake::INTERNAL_ERROR,
+ "Matches error: Each side has a directory relative to a different "
+ "location. This can occur when referencing a source file from a "
+ "different directory. This is not yet allowed.");
+ return false;
+ }
+ } else if (this->AmbiguousDirectory) {
+ // Compare possible directory combinations.
+ std::string const& srcDir = cmSystemTools::CollapseFullPath(
+ this->Directory, this->Makefile->GetCurrentSourceDirectory());
+ std::string const& binDir = cmSystemTools::CollapseFullPath(
+ this->Directory, this->Makefile->GetCurrentBinaryDirectory());
+ if (srcDir != loc.Directory && binDir != loc.Directory) {
+ return false;
+ }
+ } else if (loc.AmbiguousDirectory) {
+ // Compare possible directory combinations.
+ std::string const& srcDir = cmSystemTools::CollapseFullPath(
+ loc.Directory, loc.Makefile->GetCurrentSourceDirectory());
+ std::string const& binDir = cmSystemTools::CollapseFullPath(
+ loc.Directory, loc.Makefile->GetCurrentBinaryDirectory());
+ if (srcDir != this->Directory && binDir != this->Directory) {
+ return false;
+ }
+ }
+
+ // File locations match.
+ this->Update(loc);
+ return true;
+}
diff --git a/Source/cmSourceFileLocation.h b/Source/cmSourceFileLocation.h
new file mode 100644
index 0000000..7989173
--- /dev/null
+++ b/Source/cmSourceFileLocation.h
@@ -0,0 +1,102 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSourceFileLocation_h
+#define cmSourceFileLocation_h
+
+#include "cmStandardIncludes.h"
+
+class cmMakefile;
+
+/** \class cmSourceFileLocation
+ * \brief cmSourceFileLocation tracks knowledge about a source file location
+ *
+ * Source files can be referenced by a variety of names. The
+ * directory and/or extension may be omitted leading to a certain
+ * level of ambiguity about the source file location. This class is
+ * used by cmSourceFile to keep track of what is known about the
+ * source file location. Each reference may add some information
+ * about the directory or extension of the file.
+ */
+class cmSourceFileLocation
+{
+public:
+ /**
+ * Construct for a source file created in a given cmMakefile
+ * instance with an initial name.
+ */
+ cmSourceFileLocation(cmMakefile const* mf, const std::string& name);
+ cmSourceFileLocation();
+ cmSourceFileLocation(const cmSourceFileLocation& loc);
+ cmSourceFileLocation& operator=(const cmSourceFileLocation& loc);
+
+ /**
+ * Return whether the given source file location could refers to the
+ * same source file as this location given the level of ambiguity in
+ * each location.
+ */
+ bool Matches(cmSourceFileLocation const& loc);
+
+ /**
+ * Explicity state that the source file is located in the source tree.
+ */
+ void DirectoryUseSource();
+
+ /**
+ * Explicity state that the source file is located in the build tree.
+ */
+ void DirectoryUseBinary();
+
+ /**
+ * Return whether the directory containing the source is ambiguous.
+ */
+ bool DirectoryIsAmbiguous() const { return this->AmbiguousDirectory; }
+
+ /**
+ * Return whether the extension of the source name is ambiguous.
+ */
+ bool ExtensionIsAmbiguous() const { return this->AmbiguousExtension; }
+
+ /**
+ * Get the directory containing the file as best is currently known.
+ * If DirectoryIsAmbiguous() returns false this will be a full path.
+ * Otherwise it will be a relative path (possibly empty) that is
+ * either with respect to the source or build tree.
+ */
+ const std::string& GetDirectory() const { return this->Directory; }
+
+ /**
+ * Get the file name as best is currently known. If
+ * ExtensionIsAmbiguous() returns true this name may not be the
+ * final name (but could be). Otherwise the returned name is the
+ * final name.
+ */
+ const std::string& GetName() const { return this->Name; }
+
+ /**
+ * Get the cmMakefile instance for which the source file was created.
+ */
+ cmMakefile const* GetMakefile() const { return this->Makefile; }
+private:
+ cmMakefile const* Makefile;
+ bool AmbiguousDirectory;
+ bool AmbiguousExtension;
+ std::string Directory;
+ std::string Name;
+
+ bool MatchesAmbiguousExtension(cmSourceFileLocation const& loc) const;
+
+ // Update the location with additional knowledge.
+ void Update(cmSourceFileLocation const& loc);
+ void UpdateExtension(const std::string& name);
+};
+
+#endif
diff --git a/Source/cmSourceGroup.cxx b/Source/cmSourceGroup.cxx
new file mode 100644
index 0000000..d9529a2
--- /dev/null
+++ b/Source/cmSourceGroup.cxx
@@ -0,0 +1,173 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSourceGroup.h"
+
+class cmSourceGroupInternals
+{
+public:
+ std::vector<cmSourceGroup> GroupChildren;
+};
+
+cmSourceGroup::cmSourceGroup(const char* name, const char* regex,
+ const char* parentName)
+ : Name(name)
+{
+ this->Internal = new cmSourceGroupInternals;
+ this->SetGroupRegex(regex);
+ if (parentName) {
+ this->FullName = parentName;
+ this->FullName += "\\";
+ }
+ this->FullName += this->Name;
+}
+
+cmSourceGroup::~cmSourceGroup()
+{
+ delete this->Internal;
+}
+
+cmSourceGroup::cmSourceGroup(cmSourceGroup const& r)
+{
+ this->Name = r.Name;
+ this->FullName = r.FullName;
+ this->GroupRegex = r.GroupRegex;
+ this->GroupFiles = r.GroupFiles;
+ this->SourceFiles = r.SourceFiles;
+ this->Internal = new cmSourceGroupInternals(*r.Internal);
+}
+
+cmSourceGroup& cmSourceGroup::operator=(cmSourceGroup const& r)
+{
+ this->Name = r.Name;
+ this->GroupRegex = r.GroupRegex;
+ this->GroupFiles = r.GroupFiles;
+ this->SourceFiles = r.SourceFiles;
+ *(this->Internal) = *(r.Internal);
+ return *this;
+}
+
+void cmSourceGroup::SetGroupRegex(const char* regex)
+{
+ if (regex) {
+ this->GroupRegex.compile(regex);
+ } else {
+ this->GroupRegex.compile("^$");
+ }
+}
+
+void cmSourceGroup::AddGroupFile(const std::string& name)
+{
+ this->GroupFiles.insert(name);
+}
+
+const char* cmSourceGroup::GetName() const
+{
+ return this->Name.c_str();
+}
+
+const char* cmSourceGroup::GetFullName() const
+{
+ return this->FullName.c_str();
+}
+
+bool cmSourceGroup::MatchesRegex(const char* name)
+{
+ return this->GroupRegex.find(name);
+}
+
+bool cmSourceGroup::MatchesFiles(const char* name)
+{
+ return this->GroupFiles.find(name) != this->GroupFiles.end();
+}
+
+void cmSourceGroup::AssignSource(const cmSourceFile* sf)
+{
+ this->SourceFiles.push_back(sf);
+}
+
+const std::vector<const cmSourceFile*>& cmSourceGroup::GetSourceFiles() const
+{
+ return this->SourceFiles;
+}
+
+void cmSourceGroup::AddChild(cmSourceGroup const& child)
+{
+ this->Internal->GroupChildren.push_back(child);
+}
+
+cmSourceGroup* cmSourceGroup::LookupChild(const char* name) const
+{
+ // initializing iterators
+ std::vector<cmSourceGroup>::const_iterator iter =
+ this->Internal->GroupChildren.begin();
+ const std::vector<cmSourceGroup>::const_iterator end =
+ this->Internal->GroupChildren.end();
+
+ // st
+ for (; iter != end; ++iter) {
+ std::string sgName = iter->GetName();
+
+ // look if descenened is the one were looking for
+ if (sgName == name) {
+ return const_cast<cmSourceGroup*>(&(*iter)); // if it so return it
+ }
+ }
+
+ // if no child with this name was found return NULL
+ return CM_NULLPTR;
+}
+
+cmSourceGroup* cmSourceGroup::MatchChildrenFiles(const char* name)
+{
+ // initializing iterators
+ std::vector<cmSourceGroup>::iterator iter =
+ this->Internal->GroupChildren.begin();
+ std::vector<cmSourceGroup>::iterator end =
+ this->Internal->GroupChildren.end();
+
+ if (this->MatchesFiles(name)) {
+ return this;
+ }
+ for (; iter != end; ++iter) {
+ cmSourceGroup* result = iter->MatchChildrenFiles(name);
+ if (result) {
+ return result;
+ }
+ }
+ return CM_NULLPTR;
+}
+
+cmSourceGroup* cmSourceGroup::MatchChildrenRegex(const char* name)
+{
+ // initializing iterators
+ std::vector<cmSourceGroup>::iterator iter =
+ this->Internal->GroupChildren.begin();
+ std::vector<cmSourceGroup>::iterator end =
+ this->Internal->GroupChildren.end();
+
+ for (; iter != end; ++iter) {
+ cmSourceGroup* result = iter->MatchChildrenRegex(name);
+ if (result) {
+ return result;
+ }
+ }
+ if (this->MatchesRegex(name)) {
+ return this;
+ }
+
+ return CM_NULLPTR;
+}
+
+std::vector<cmSourceGroup> const& cmSourceGroup::GetGroupChildren() const
+{
+ return this->Internal->GroupChildren;
+}
diff --git a/Source/cmSourceGroup.h b/Source/cmSourceGroup.h
new file mode 100644
index 0000000..1f5232e
--- /dev/null
+++ b/Source/cmSourceGroup.h
@@ -0,0 +1,134 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSourceGroup_h
+#define cmSourceGroup_h
+
+#include "cmStandardIncludes.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+class cmSourceFile;
+
+class cmSourceGroupInternals;
+
+/** \class cmSourceGroup
+ * \brief Hold a group of sources as specified by a SOURCE_GROUP command.
+ *
+ * cmSourceGroup holds a regular expression and a list of files. When
+ * local generators are about to generate the rules for a target's
+ * files, the set of source groups is consulted to group files
+ * together. A file is placed into the last source group that lists
+ * the file by name. If no group lists the file, it is placed into
+ * the last group whose regex matches it.
+ */
+class cmSourceGroup
+{
+public:
+ cmSourceGroup(const char* name, const char* regex,
+ const char* parentName = CM_NULLPTR);
+ cmSourceGroup(cmSourceGroup const& r);
+ ~cmSourceGroup();
+ cmSourceGroup& operator=(cmSourceGroup const&);
+
+ /**
+ * Set the regular expression for this group.
+ */
+ void SetGroupRegex(const char* regex);
+
+ /**
+ * Add a file name to the explicit list of files for this group.
+ */
+ void AddGroupFile(const std::string& name);
+
+ /**
+ * Add child to this sourcegroup
+ */
+ void AddChild(cmSourceGroup const& child);
+
+ /**
+ * Looks up child and returns it
+ */
+ cmSourceGroup* LookupChild(const char* name) const;
+
+ /**
+ * Get the name of this group.
+ */
+ const char* GetName() const;
+
+ /**
+ * Get the full path name for group.
+ */
+ const char* GetFullName() const;
+
+ /**
+ * Check if the given name matches this group's regex.
+ */
+ bool MatchesRegex(const char* name);
+
+ /**
+ * Check if the given name matches this group's explicit file list.
+ */
+ bool MatchesFiles(const char* name);
+
+ /**
+ * Check if the given name matches this group's explicit file list
+ * in children.
+ */
+ cmSourceGroup* MatchChildrenFiles(const char* name);
+
+ /**
+ * Check if the given name matches this group's regex in children.
+ */
+ cmSourceGroup* MatchChildrenRegex(const char* name);
+
+ /**
+ * Assign the given source file to this group. Used only by
+ * generators.
+ */
+ void AssignSource(const cmSourceFile* sf);
+
+ /**
+ * Get the list of the source files that have been assigned to this
+ * source group.
+ */
+ const std::vector<const cmSourceFile*>& GetSourceFiles() const;
+
+ std::vector<cmSourceGroup> const& GetGroupChildren() const;
+
+private:
+ /**
+ * The name of the source group.
+ */
+ std::string Name;
+ // Full path to group
+ std::string FullName;
+
+ /**
+ * The regular expression matching the files in the group.
+ */
+ cmsys::RegularExpression GroupRegex;
+
+ /**
+ * Set of file names explicitly added to this group.
+ */
+ std::set<std::string> GroupFiles;
+
+ /**
+ * Vector of all source files that have been assigned to
+ * this group.
+ */
+ std::vector<const cmSourceFile*> SourceFiles;
+
+ cmSourceGroupInternals* Internal;
+};
+
+#endif
diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx
new file mode 100644
index 0000000..6db14c0
--- /dev/null
+++ b/Source/cmSourceGroupCommand.cxx
@@ -0,0 +1,85 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSourceGroupCommand.h"
+
+// cmSourceGroupCommand
+bool cmSourceGroupCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string delimiter = "\\";
+ if (this->Makefile->GetDefinition("SOURCE_GROUP_DELIMITER")) {
+ delimiter = this->Makefile->GetDefinition("SOURCE_GROUP_DELIMITER");
+ }
+
+ std::vector<std::string> folders =
+ cmSystemTools::tokenize(args[0], delimiter);
+
+ cmSourceGroup* sg = CM_NULLPTR;
+ sg = this->Makefile->GetSourceGroup(folders);
+ if (!sg) {
+ this->Makefile->AddSourceGroup(folders);
+ sg = this->Makefile->GetSourceGroup(folders);
+ }
+
+ if (!sg) {
+ this->SetError("Could not create or find source group");
+ return false;
+ }
+ // If only two arguments are given, the pre-1.8 version of the
+ // command is being invoked.
+ if (args.size() == 2 && args[1] != "FILES") {
+ sg->SetGroupRegex(args[1].c_str());
+ return true;
+ }
+
+ // Process arguments.
+ bool doingFiles = false;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "REGULAR_EXPRESSION") {
+ // Next argument must specify the regex.
+ if (i + 1 < args.size()) {
+ ++i;
+ sg->SetGroupRegex(args[i].c_str());
+ } else {
+ this->SetError("REGULAR_EXPRESSION argument given without a regex.");
+ return false;
+ }
+ doingFiles = false;
+ } else if (args[i] == "FILES") {
+ // Next arguments will specify files.
+ doingFiles = true;
+ } else if (doingFiles) {
+ // Convert name to full path and add to the group's list.
+ std::string src = args[i];
+ if (!cmSystemTools::FileIsFullPath(src.c_str())) {
+ src = this->Makefile->GetCurrentSourceDirectory();
+ src += "/";
+ src += args[i];
+ }
+ src = cmSystemTools::CollapseFullPath(src.c_str());
+ sg->AddGroupFile(src);
+ } else {
+ std::ostringstream err;
+ err << "Unknown argument \"" << args[i] << "\". "
+ << "Perhaps the FILES keyword is missing.\n";
+ this->SetError(err.str());
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/Source/cmSourceGroupCommand.h b/Source/cmSourceGroupCommand.h
new file mode 100644
index 0000000..81dfad6
--- /dev/null
+++ b/Source/cmSourceGroupCommand.h
@@ -0,0 +1,46 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSourceGroupCommand_h
+#define cmSourceGroupCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmSourceGroupCommand
+ * \brief Adds a cmSourceGroup to the cmMakefile.
+ *
+ * cmSourceGroupCommand is used to define cmSourceGroups which split up
+ * source files in to named, organized groups in the generated makefiles.
+ */
+class cmSourceGroupCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmSourceGroupCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "source_group"; }
+
+ cmTypeMacro(cmSourceGroupCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmStandardIncludes.h b/Source/cmStandardIncludes.h
new file mode 100644
index 0000000..606978e
--- /dev/null
+++ b/Source/cmStandardIncludes.h
@@ -0,0 +1,63 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/**
+ * Include header files as a function of the build process, compiler,
+ * and operating system.
+ */
+#ifndef cmStandardIncludes_h
+#define cmStandardIncludes_h
+
+#include <cmConfigure.h>
+
+// Provide fixed-size integer types.
+#include <cm_kwiml.h>
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+// we must have stl with the standard include style
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+// include the "c" string header
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(_MSC_VER)
+typedef unsigned short mode_t;
+#else
+#include <sys/types.h>
+#endif
+
+// use this class to shrink the size of symbols in .o files
+// std::string is really basic_string<....lots of stuff....>
+// when combined with a map or set, the symbols can be > 2000 chars!
+#include <cmsys/String.hxx>
+// typedef cmsys::String std::string;
+
+/* Poison this operator to avoid common mistakes. */
+extern void operator<<(std::ostream&, const std::ostringstream&);
+
+#include "cmCustomCommandLines.h"
+#include "cmDocumentationEntry.h"
+#include "cmTargetLinkLibraryType.h"
+#include "cmTypeMacro.h"
+
+#endif
diff --git a/Source/cmStandardLexer.h b/Source/cmStandardLexer.h
new file mode 100644
index 0000000..94ed276
--- /dev/null
+++ b/Source/cmStandardLexer.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmStandardLexer_h
+#define cmStandardLexer_h
+
+/* Disable some warnings. */
+#if defined(_MSC_VER)
+#pragma warning(disable : 4127)
+#pragma warning(disable : 4131)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4251)
+#pragma warning(disable : 4267)
+#pragma warning(disable : 4305)
+#pragma warning(disable : 4309)
+#pragma warning(disable : 4706)
+#pragma warning(disable : 4786)
+#endif
+
+/* Define isatty on windows. */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <io.h>
+#if defined(_MSC_VER)
+#define isatty _isatty
+#endif
+#define YY_NO_UNISTD_H 1
+#endif
+
+/* Make sure malloc and free are available on QNX. */
+#ifdef __QNX__
+#include <malloc.h>
+#endif
+
+/* Disable features we do not need. */
+#define YY_NEVER_INTERACTIVE 1
+#define YY_NO_INPUT 1
+#define YY_NO_UNPUT 1
+#define ECHO
+
+#endif
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
new file mode 100644
index 0000000..f2fe134
--- /dev/null
+++ b/Source/cmState.cxx
@@ -0,0 +1,1830 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmState.h"
+
+#include "cmAlgorithms.h"
+#include "cmCacheManager.h"
+#include "cmCommand.h"
+#include "cmDefinitions.h"
+#include "cmVersion.h"
+#include "cmake.h"
+
+#include <assert.h>
+
+struct cmState::SnapshotDataType
+{
+ cmState::PositionType ScopeParent;
+ cmState::PositionType DirectoryParent;
+ cmLinkedTree<cmState::PolicyStackEntry>::iterator Policies;
+ cmLinkedTree<cmState::PolicyStackEntry>::iterator PolicyRoot;
+ cmLinkedTree<cmState::PolicyStackEntry>::iterator PolicyScope;
+ cmState::SnapshotType SnapshotType;
+ bool Keep;
+ cmLinkedTree<std::string>::iterator ExecutionListFile;
+ cmLinkedTree<cmState::BuildsystemDirectoryStateType>::iterator
+ BuildSystemDirectory;
+ cmLinkedTree<cmDefinitions>::iterator Vars;
+ cmLinkedTree<cmDefinitions>::iterator Root;
+ cmLinkedTree<cmDefinitions>::iterator Parent;
+ std::vector<std::string>::size_type IncludeDirectoryPosition;
+ std::vector<std::string>::size_type CompileDefinitionsPosition;
+ std::vector<std::string>::size_type CompileOptionsPosition;
+};
+
+struct cmState::PolicyStackEntry : public cmPolicies::PolicyMap
+{
+ typedef cmPolicies::PolicyMap derived;
+ PolicyStackEntry(bool w = false)
+ : derived()
+ , Weak(w)
+ {
+ }
+ PolicyStackEntry(derived const& d, bool w)
+ : derived(d)
+ , Weak(w)
+ {
+ }
+ PolicyStackEntry(PolicyStackEntry const& r)
+ : derived(r)
+ , Weak(r.Weak)
+ {
+ }
+ bool Weak;
+};
+
+struct cmState::BuildsystemDirectoryStateType
+{
+ cmState::PositionType DirectoryEnd;
+
+ std::string Location;
+ std::string OutputLocation;
+
+ std::vector<std::string> CurrentSourceDirectoryComponents;
+ std::vector<std::string> CurrentBinaryDirectoryComponents;
+ // The top-most directories for relative path conversion. Both the
+ // source and destination location of a relative path conversion
+ // must be underneath one of these directories (both under source or
+ // both under binary) in order for the relative path to be evaluated
+ // safely by the build tools.
+ std::string RelativePathTopSource;
+ std::string RelativePathTopBinary;
+
+ std::vector<std::string> IncludeDirectories;
+ std::vector<cmListFileBacktrace> IncludeDirectoryBacktraces;
+
+ std::vector<std::string> CompileDefinitions;
+ std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces;
+
+ std::vector<std::string> CompileOptions;
+ std::vector<cmListFileBacktrace> CompileOptionsBacktraces;
+
+ std::string ProjectName;
+
+ cmPropertyMap Properties;
+
+ std::vector<cmState::Snapshot> Children;
+};
+
+cmState::cmState()
+ : IsInTryCompile(false)
+ , WindowsShell(false)
+ , WindowsVSIDE(false)
+ , WatcomWMake(false)
+ , MinGWMake(false)
+ , NMake(false)
+ , MSYSShell(false)
+{
+ this->CacheManager = new cmCacheManager;
+}
+
+cmState::~cmState()
+{
+ delete this->CacheManager;
+ cmDeleteAll(this->Commands);
+}
+
+const char* cmState::GetTargetTypeName(cmState::TargetType targetType)
+{
+ switch (targetType) {
+ case cmState::STATIC_LIBRARY:
+ return "STATIC_LIBRARY";
+ case cmState::MODULE_LIBRARY:
+ return "MODULE_LIBRARY";
+ case cmState::SHARED_LIBRARY:
+ return "SHARED_LIBRARY";
+ case cmState::OBJECT_LIBRARY:
+ return "OBJECT_LIBRARY";
+ case cmState::EXECUTABLE:
+ return "EXECUTABLE";
+ case cmState::UTILITY:
+ return "UTILITY";
+ case cmState::GLOBAL_TARGET:
+ return "GLOBAL_TARGET";
+ case cmState::INTERFACE_LIBRARY:
+ return "INTERFACE_LIBRARY";
+ case cmState::UNKNOWN_LIBRARY:
+ return "UNKNOWN_LIBRARY";
+ }
+ assert(0 && "Unexpected target type");
+ return CM_NULLPTR;
+}
+
+const char* cmCacheEntryTypes[] = { "BOOL", "PATH", "FILEPATH",
+ "STRING", "INTERNAL", "STATIC",
+ "UNINITIALIZED", CM_NULLPTR };
+
+const char* cmState::CacheEntryTypeToString(cmState::CacheEntryType type)
+{
+ if (type > 6) {
+ return cmCacheEntryTypes[6];
+ }
+ return cmCacheEntryTypes[type];
+}
+
+cmState::CacheEntryType cmState::StringToCacheEntryType(const char* s)
+{
+ int i = 0;
+ while (cmCacheEntryTypes[i]) {
+ if (strcmp(s, cmCacheEntryTypes[i]) == 0) {
+ return static_cast<cmState::CacheEntryType>(i);
+ }
+ ++i;
+ }
+ return STRING;
+}
+
+bool cmState::IsCacheEntryType(std::string const& key)
+{
+ for (int i = 0; cmCacheEntryTypes[i]; ++i) {
+ if (strcmp(key.c_str(), cmCacheEntryTypes[i]) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmState::LoadCache(const std::string& path, bool internal,
+ std::set<std::string>& excludes,
+ std::set<std::string>& includes)
+{
+ return this->CacheManager->LoadCache(path, internal, excludes, includes);
+}
+
+bool cmState::SaveCache(const std::string& path)
+{
+ return this->CacheManager->SaveCache(path);
+}
+
+bool cmState::DeleteCache(const std::string& path)
+{
+ return this->CacheManager->DeleteCache(path);
+}
+
+std::vector<std::string> cmState::GetCacheEntryKeys() const
+{
+ std::vector<std::string> definitions;
+ definitions.reserve(this->CacheManager->GetSize());
+ cmCacheManager::CacheIterator cit = this->CacheManager->GetCacheIterator();
+ for (cit.Begin(); !cit.IsAtEnd(); cit.Next()) {
+ definitions.push_back(cit.GetName());
+ }
+ return definitions;
+}
+
+const char* cmState::GetCacheEntryValue(std::string const& key) const
+{
+ cmCacheManager::CacheEntry* e = this->CacheManager->GetCacheEntry(key);
+ if (!e) {
+ return CM_NULLPTR;
+ }
+ return e->Value.c_str();
+}
+
+const char* cmState::GetInitializedCacheValue(std::string const& key) const
+{
+ return this->CacheManager->GetInitializedCacheValue(key);
+}
+
+cmState::CacheEntryType cmState::GetCacheEntryType(
+ std::string const& key) const
+{
+ cmCacheManager::CacheIterator it =
+ this->CacheManager->GetCacheIterator(key.c_str());
+ return it.GetType();
+}
+
+void cmState::SetCacheEntryValue(std::string const& key,
+ std::string const& value)
+{
+ this->CacheManager->SetCacheEntryValue(key, value);
+}
+
+void cmState::SetCacheEntryProperty(std::string const& key,
+ std::string const& propertyName,
+ std::string const& value)
+{
+ cmCacheManager::CacheIterator it =
+ this->CacheManager->GetCacheIterator(key.c_str());
+ it.SetProperty(propertyName, value.c_str());
+}
+
+void cmState::SetCacheEntryBoolProperty(std::string const& key,
+ std::string const& propertyName,
+ bool value)
+{
+ cmCacheManager::CacheIterator it =
+ this->CacheManager->GetCacheIterator(key.c_str());
+ it.SetProperty(propertyName, value);
+}
+
+std::vector<std::string> cmState::GetCacheEntryPropertyList(
+ const std::string& key)
+{
+ cmCacheManager::CacheIterator it =
+ this->CacheManager->GetCacheIterator(key.c_str());
+ return it.GetPropertyList();
+}
+
+const char* cmState::GetCacheEntryProperty(std::string const& key,
+ std::string const& propertyName)
+{
+ cmCacheManager::CacheIterator it =
+ this->CacheManager->GetCacheIterator(key.c_str());
+ if (!it.PropertyExists(propertyName)) {
+ return CM_NULLPTR;
+ }
+ return it.GetProperty(propertyName);
+}
+
+bool cmState::GetCacheEntryPropertyAsBool(std::string const& key,
+ std::string const& propertyName)
+{
+ return this->CacheManager->GetCacheIterator(key.c_str())
+ .GetPropertyAsBool(propertyName);
+}
+
+void cmState::AddCacheEntry(const std::string& key, const char* value,
+ const char* helpString,
+ cmState::CacheEntryType type)
+{
+ this->CacheManager->AddCacheEntry(key, value, helpString, type);
+}
+
+void cmState::RemoveCacheEntry(std::string const& key)
+{
+ this->CacheManager->RemoveCacheEntry(key);
+}
+
+void cmState::AppendCacheEntryProperty(const std::string& key,
+ const std::string& property,
+ const std::string& value, bool asString)
+{
+ this->CacheManager->GetCacheIterator(key.c_str())
+ .AppendProperty(property, value.c_str(), asString);
+}
+
+void cmState::RemoveCacheEntryProperty(std::string const& key,
+ std::string const& propertyName)
+{
+ this->CacheManager->GetCacheIterator(key.c_str())
+ .SetProperty(propertyName, (void*)CM_NULLPTR);
+}
+
+cmState::Snapshot cmState::Reset()
+{
+ this->GlobalProperties.clear();
+ this->PropertyDefinitions.clear();
+
+ PositionType pos = this->SnapshotData.Truncate();
+ this->ExecutionListFiles.Truncate();
+
+ {
+ cmLinkedTree<BuildsystemDirectoryStateType>::iterator it =
+ this->BuildsystemDirectory.Truncate();
+ it->IncludeDirectories.clear();
+ it->IncludeDirectoryBacktraces.clear();
+ it->CompileDefinitions.clear();
+ it->CompileDefinitionsBacktraces.clear();
+ it->CompileOptions.clear();
+ it->CompileOptionsBacktraces.clear();
+ it->DirectoryEnd = pos;
+ it->Properties.clear();
+ it->Children.clear();
+ }
+
+ this->PolicyStack.Clear();
+ pos->Policies = this->PolicyStack.Root();
+ pos->PolicyRoot = this->PolicyStack.Root();
+ pos->PolicyScope = this->PolicyStack.Root();
+ assert(pos->Policies.IsValid());
+ assert(pos->PolicyRoot.IsValid());
+
+ {
+ std::string srcDir =
+ cmDefinitions::Get("CMAKE_SOURCE_DIR", pos->Vars, pos->Root);
+ std::string binDir =
+ cmDefinitions::Get("CMAKE_BINARY_DIR", pos->Vars, pos->Root);
+ this->VarTree.Clear();
+ pos->Vars = this->VarTree.Push(this->VarTree.Root());
+ pos->Parent = this->VarTree.Root();
+ pos->Root = this->VarTree.Root();
+
+ pos->Vars->Set("CMAKE_SOURCE_DIR", srcDir.c_str());
+ pos->Vars->Set("CMAKE_BINARY_DIR", binDir.c_str());
+ }
+
+ this->DefineProperty("RULE_LAUNCH_COMPILE", cmProperty::DIRECTORY, "", "",
+ true);
+ this->DefineProperty("RULE_LAUNCH_LINK", cmProperty::DIRECTORY, "", "",
+ true);
+ this->DefineProperty("RULE_LAUNCH_CUSTOM", cmProperty::DIRECTORY, "", "",
+ true);
+
+ this->DefineProperty("RULE_LAUNCH_COMPILE", cmProperty::TARGET, "", "",
+ true);
+ this->DefineProperty("RULE_LAUNCH_LINK", cmProperty::TARGET, "", "", true);
+ this->DefineProperty("RULE_LAUNCH_CUSTOM", cmProperty::TARGET, "", "", true);
+
+ return Snapshot(this, pos);
+}
+
+void cmState::DefineProperty(const std::string& name,
+ cmProperty::ScopeType scope,
+ const char* ShortDescription,
+ const char* FullDescription, bool chained)
+{
+ this->PropertyDefinitions[scope].DefineProperty(
+ name, scope, ShortDescription, FullDescription, chained);
+}
+
+cmPropertyDefinition const* cmState::GetPropertyDefinition(
+ const std::string& name, cmProperty::ScopeType scope) const
+{
+ if (this->IsPropertyDefined(name, scope)) {
+ cmPropertyDefinitionMap const& defs =
+ this->PropertyDefinitions.find(scope)->second;
+ return &defs.find(name)->second;
+ }
+ return CM_NULLPTR;
+}
+
+bool cmState::IsPropertyDefined(const std::string& name,
+ cmProperty::ScopeType scope) const
+{
+ std::map<cmProperty::ScopeType, cmPropertyDefinitionMap>::const_iterator it =
+ this->PropertyDefinitions.find(scope);
+ if (it == this->PropertyDefinitions.end()) {
+ return false;
+ }
+ return it->second.IsPropertyDefined(name);
+}
+
+bool cmState::IsPropertyChained(const std::string& name,
+ cmProperty::ScopeType scope) const
+{
+ std::map<cmProperty::ScopeType, cmPropertyDefinitionMap>::const_iterator it =
+ this->PropertyDefinitions.find(scope);
+ if (it == this->PropertyDefinitions.end()) {
+ return false;
+ }
+ return it->second.IsPropertyChained(name);
+}
+
+void cmState::SetLanguageEnabled(std::string const& l)
+{
+ std::vector<std::string>::iterator it = std::lower_bound(
+ this->EnabledLanguages.begin(), this->EnabledLanguages.end(), l);
+ if (it == this->EnabledLanguages.end() || *it != l) {
+ this->EnabledLanguages.insert(it, l);
+ }
+}
+
+bool cmState::GetLanguageEnabled(std::string const& l) const
+{
+ return std::binary_search(this->EnabledLanguages.begin(),
+ this->EnabledLanguages.end(), l);
+}
+
+std::vector<std::string> cmState::GetEnabledLanguages() const
+{
+ return this->EnabledLanguages;
+}
+
+void cmState::SetEnabledLanguages(std::vector<std::string> const& langs)
+{
+ this->EnabledLanguages = langs;
+}
+
+void cmState::ClearEnabledLanguages()
+{
+ this->EnabledLanguages.clear();
+}
+
+bool cmState::GetIsInTryCompile() const
+{
+ return this->IsInTryCompile;
+}
+
+void cmState::SetIsInTryCompile(bool b)
+{
+ this->IsInTryCompile = b;
+}
+
+void cmState::RenameCommand(std::string const& oldName,
+ std::string const& newName)
+{
+ // if the command already exists, free the old one
+ std::string sOldName = cmSystemTools::LowerCase(oldName);
+ std::string sNewName = cmSystemTools::LowerCase(newName);
+ std::map<std::string, cmCommand*>::iterator pos =
+ this->Commands.find(sOldName);
+ if (pos == this->Commands.end()) {
+ return;
+ }
+ cmCommand* cmd = pos->second;
+
+ pos = this->Commands.find(sNewName);
+ if (pos != this->Commands.end()) {
+ delete pos->second;
+ this->Commands.erase(pos);
+ }
+ this->Commands.insert(std::make_pair(sNewName, cmd));
+ pos = this->Commands.find(sOldName);
+ this->Commands.erase(pos);
+}
+
+void cmState::AddCommand(cmCommand* command)
+{
+ std::string name = cmSystemTools::LowerCase(command->GetName());
+ // if the command already exists, free the old one
+ std::map<std::string, cmCommand*>::iterator pos = this->Commands.find(name);
+ if (pos != this->Commands.end()) {
+ delete pos->second;
+ this->Commands.erase(pos);
+ }
+ this->Commands.insert(std::make_pair(name, command));
+}
+
+void cmState::RemoveUnscriptableCommands()
+{
+ std::vector<std::string> unscriptableCommands;
+ for (std::map<std::string, cmCommand*>::iterator pos =
+ this->Commands.begin();
+ pos != this->Commands.end();) {
+ if (!pos->second->IsScriptable()) {
+ delete pos->second;
+ this->Commands.erase(pos++);
+ } else {
+ ++pos;
+ }
+ }
+}
+
+cmCommand* cmState::GetCommand(std::string const& name) const
+{
+ cmCommand* command = CM_NULLPTR;
+ std::string sName = cmSystemTools::LowerCase(name);
+ std::map<std::string, cmCommand*>::const_iterator pos =
+ this->Commands.find(sName);
+ if (pos != this->Commands.end()) {
+ command = (*pos).second;
+ }
+ return command;
+}
+
+std::vector<std::string> cmState::GetCommandNames() const
+{
+ std::vector<std::string> commandNames;
+ commandNames.reserve(this->Commands.size());
+ std::map<std::string, cmCommand*>::const_iterator cmds =
+ this->Commands.begin();
+ for (; cmds != this->Commands.end(); ++cmds) {
+ commandNames.push_back(cmds->first);
+ }
+ return commandNames;
+}
+
+void cmState::RemoveUserDefinedCommands()
+{
+ std::vector<cmCommand*> renamedCommands;
+ for (std::map<std::string, cmCommand*>::iterator j = this->Commands.begin();
+ j != this->Commands.end();) {
+ if (j->second->IsA("cmMacroHelperCommand") ||
+ j->second->IsA("cmFunctionHelperCommand")) {
+ delete j->second;
+ this->Commands.erase(j++);
+ } else if (j->first != j->second->GetName()) {
+ renamedCommands.push_back(j->second);
+ this->Commands.erase(j++);
+ } else {
+ ++j;
+ }
+ }
+ for (std::vector<cmCommand*>::const_iterator it = renamedCommands.begin();
+ it != renamedCommands.end(); ++it) {
+ this->Commands[cmSystemTools::LowerCase((*it)->GetName())] = *it;
+ }
+}
+
+void cmState::SetGlobalProperty(const std::string& prop, const char* value)
+{
+ this->GlobalProperties.SetProperty(prop, value);
+}
+
+void cmState::AppendGlobalProperty(const std::string& prop, const char* value,
+ bool asString)
+{
+ this->GlobalProperties.AppendProperty(prop, value, asString);
+}
+
+const char* cmState::GetGlobalProperty(const std::string& prop)
+{
+ if (prop == "CACHE_VARIABLES") {
+ std::vector<std::string> cacheKeys = this->GetCacheEntryKeys();
+ this->SetGlobalProperty("CACHE_VARIABLES", cmJoin(cacheKeys, ";").c_str());
+ } else if (prop == "COMMANDS") {
+ std::vector<std::string> commands = this->GetCommandNames();
+ this->SetGlobalProperty("COMMANDS", cmJoin(commands, ";").c_str());
+ } else if (prop == "IN_TRY_COMPILE") {
+ this->SetGlobalProperty("IN_TRY_COMPILE",
+ this->IsInTryCompile ? "1" : "0");
+ } else if (prop == "ENABLED_LANGUAGES") {
+ std::string langs;
+ langs = cmJoin(this->EnabledLanguages, ";");
+ this->SetGlobalProperty("ENABLED_LANGUAGES", langs.c_str());
+ }
+#define STRING_LIST_ELEMENT(F) ";" #F
+ if (prop == "CMAKE_C_KNOWN_FEATURES") {
+ return FOR_EACH_C_FEATURE(STRING_LIST_ELEMENT) + 1;
+ }
+ if (prop == "CMAKE_CXX_KNOWN_FEATURES") {
+ return FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT) + 1;
+ }
+#undef STRING_LIST_ELEMENT
+ return this->GlobalProperties.GetPropertyValue(prop);
+}
+
+bool cmState::GetGlobalPropertyAsBool(const std::string& prop)
+{
+ return cmSystemTools::IsOn(this->GetGlobalProperty(prop));
+}
+
+void cmState::SetSourceDirectory(std::string const& sourceDirectory)
+{
+ this->SourceDirectory = sourceDirectory;
+ cmSystemTools::ConvertToUnixSlashes(this->SourceDirectory);
+
+ cmSystemTools::SplitPath(
+ cmSystemTools::CollapseFullPath(this->SourceDirectory),
+ this->SourceDirectoryComponents);
+}
+
+const char* cmState::GetSourceDirectory() const
+{
+ return this->SourceDirectory.c_str();
+}
+
+std::vector<std::string> const& cmState::GetSourceDirectoryComponents() const
+{
+ return this->SourceDirectoryComponents;
+}
+
+void cmState::SetBinaryDirectory(std::string const& binaryDirectory)
+{
+ this->BinaryDirectory = binaryDirectory;
+ cmSystemTools::ConvertToUnixSlashes(this->BinaryDirectory);
+
+ cmSystemTools::SplitPath(
+ cmSystemTools::CollapseFullPath(this->BinaryDirectory),
+ this->BinaryDirectoryComponents);
+}
+
+void cmState::SetWindowsShell(bool windowsShell)
+{
+ this->WindowsShell = windowsShell;
+}
+
+bool cmState::UseWindowsShell() const
+{
+ return this->WindowsShell;
+}
+
+void cmState::SetWindowsVSIDE(bool windowsVSIDE)
+{
+ this->WindowsVSIDE = windowsVSIDE;
+}
+
+bool cmState::UseWindowsVSIDE() const
+{
+ return this->WindowsVSIDE;
+}
+
+void cmState::SetWatcomWMake(bool watcomWMake)
+{
+ this->WatcomWMake = watcomWMake;
+}
+
+bool cmState::UseWatcomWMake() const
+{
+ return this->WatcomWMake;
+}
+
+void cmState::SetMinGWMake(bool minGWMake)
+{
+ this->MinGWMake = minGWMake;
+}
+
+bool cmState::UseMinGWMake() const
+{
+ return this->MinGWMake;
+}
+
+void cmState::SetNMake(bool nMake)
+{
+ this->NMake = nMake;
+}
+
+bool cmState::UseNMake() const
+{
+ return this->NMake;
+}
+
+void cmState::SetMSYSShell(bool mSYSShell)
+{
+ this->MSYSShell = mSYSShell;
+}
+
+bool cmState::UseMSYSShell() const
+{
+ return this->MSYSShell;
+}
+
+unsigned int cmState::GetCacheMajorVersion() const
+{
+ return this->CacheManager->GetCacheMajorVersion();
+}
+
+unsigned int cmState::GetCacheMinorVersion() const
+{
+ return this->CacheManager->GetCacheMinorVersion();
+}
+
+const char* cmState::GetBinaryDirectory() const
+{
+ return this->BinaryDirectory.c_str();
+}
+
+std::vector<std::string> const& cmState::GetBinaryDirectoryComponents() const
+{
+ return this->BinaryDirectoryComponents;
+}
+
+void cmState::Directory::ComputeRelativePathTopSource()
+{
+ // Relative path conversion inside the source tree is not used to
+ // construct relative paths passed to build tools so it is safe to use
+ // even when the source is a network path.
+
+ cmState::Snapshot snapshot = this->Snapshot_;
+ std::vector<cmState::Snapshot> snapshots;
+ snapshots.push_back(snapshot);
+ while (true) {
+ snapshot = snapshot.GetBuildsystemDirectoryParent();
+ if (snapshot.IsValid()) {
+ snapshots.push_back(snapshot);
+ } else {
+ break;
+ }
+ }
+
+ std::string result = snapshots.front().GetDirectory().GetCurrentSource();
+
+ for (std::vector<cmState::Snapshot>::const_iterator it =
+ snapshots.begin() + 1;
+ it != snapshots.end(); ++it) {
+ std::string currentSource = it->GetDirectory().GetCurrentSource();
+ if (cmSystemTools::IsSubDirectory(result, currentSource)) {
+ result = currentSource;
+ }
+ }
+ this->DirectoryState->RelativePathTopSource = result;
+}
+
+void cmState::Directory::ComputeRelativePathTopBinary()
+{
+ cmState::Snapshot snapshot = this->Snapshot_;
+ std::vector<cmState::Snapshot> snapshots;
+ snapshots.push_back(snapshot);
+ while (true) {
+ snapshot = snapshot.GetBuildsystemDirectoryParent();
+ if (snapshot.IsValid()) {
+ snapshots.push_back(snapshot);
+ } else {
+ break;
+ }
+ }
+
+ std::string result = snapshots.front().GetDirectory().GetCurrentBinary();
+
+ for (std::vector<cmState::Snapshot>::const_iterator it =
+ snapshots.begin() + 1;
+ it != snapshots.end(); ++it) {
+ std::string currentBinary = it->GetDirectory().GetCurrentBinary();
+ if (cmSystemTools::IsSubDirectory(result, currentBinary)) {
+ result = currentBinary;
+ }
+ }
+
+ // The current working directory on Windows cannot be a network
+ // path. Therefore relative paths cannot work when the binary tree
+ // is a network path.
+ if (result.size() < 2 || result.substr(0, 2) != "//") {
+ this->DirectoryState->RelativePathTopBinary = result;
+ } else {
+ this->DirectoryState->RelativePathTopBinary = "";
+ }
+}
+
+cmState::Snapshot cmState::CreateBaseSnapshot()
+{
+ PositionType pos = this->SnapshotData.Push(this->SnapshotData.Root());
+ pos->DirectoryParent = this->SnapshotData.Root();
+ pos->ScopeParent = this->SnapshotData.Root();
+ pos->SnapshotType = BaseType;
+ pos->Keep = true;
+ pos->BuildSystemDirectory =
+ this->BuildsystemDirectory.Push(this->BuildsystemDirectory.Root());
+ pos->ExecutionListFile =
+ this->ExecutionListFiles.Push(this->ExecutionListFiles.Root());
+ pos->IncludeDirectoryPosition = 0;
+ pos->CompileDefinitionsPosition = 0;
+ pos->CompileOptionsPosition = 0;
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->Policies = this->PolicyStack.Root();
+ pos->PolicyRoot = this->PolicyStack.Root();
+ pos->PolicyScope = this->PolicyStack.Root();
+ assert(pos->Policies.IsValid());
+ assert(pos->PolicyRoot.IsValid());
+ pos->Vars = this->VarTree.Push(this->VarTree.Root());
+ assert(pos->Vars.IsValid());
+ pos->Parent = this->VarTree.Root();
+ pos->Root = this->VarTree.Root();
+ return cmState::Snapshot(this, pos);
+}
+
+cmState::Snapshot cmState::CreateBuildsystemDirectorySnapshot(
+ Snapshot originSnapshot)
+{
+ assert(originSnapshot.IsValid());
+ PositionType pos = this->SnapshotData.Push(originSnapshot.Position);
+ pos->DirectoryParent = originSnapshot.Position;
+ pos->ScopeParent = originSnapshot.Position;
+ pos->SnapshotType = BuildsystemDirectoryType;
+ pos->Keep = true;
+ pos->BuildSystemDirectory = this->BuildsystemDirectory.Push(
+ originSnapshot.Position->BuildSystemDirectory);
+ pos->ExecutionListFile =
+ this->ExecutionListFiles.Push(originSnapshot.Position->ExecutionListFile);
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->Policies = originSnapshot.Position->Policies;
+ pos->PolicyRoot = originSnapshot.Position->Policies;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ assert(pos->Policies.IsValid());
+ assert(pos->PolicyRoot.IsValid());
+
+ cmLinkedTree<cmDefinitions>::iterator origin = originSnapshot.Position->Vars;
+ pos->Parent = origin;
+ pos->Root = origin;
+ pos->Vars = this->VarTree.Push(origin);
+
+ cmState::Snapshot snapshot = cmState::Snapshot(this, pos);
+ originSnapshot.Position->BuildSystemDirectory->Children.push_back(snapshot);
+ snapshot.SetDefaultDefinitions();
+ snapshot.InitializeFromParent();
+ snapshot.SetDirectoryDefinitions();
+ return snapshot;
+}
+
+cmState::Snapshot cmState::CreateFunctionCallSnapshot(
+ cmState::Snapshot originSnapshot, std::string const& fileName)
+{
+ PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position);
+ pos->ScopeParent = originSnapshot.Position;
+ pos->SnapshotType = FunctionCallType;
+ pos->Keep = false;
+ pos->ExecutionListFile = this->ExecutionListFiles.Push(
+ originSnapshot.Position->ExecutionListFile, fileName);
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ assert(originSnapshot.Position->Vars.IsValid());
+ cmLinkedTree<cmDefinitions>::iterator origin = originSnapshot.Position->Vars;
+ pos->Parent = origin;
+ pos->Vars = this->VarTree.Push(origin);
+ return cmState::Snapshot(this, pos);
+}
+
+cmState::Snapshot cmState::CreateMacroCallSnapshot(
+ cmState::Snapshot originSnapshot, std::string const& fileName)
+{
+ PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position);
+ pos->SnapshotType = MacroCallType;
+ pos->Keep = false;
+ pos->ExecutionListFile = this->ExecutionListFiles.Push(
+ originSnapshot.Position->ExecutionListFile, fileName);
+ assert(originSnapshot.Position->Vars.IsValid());
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ return cmState::Snapshot(this, pos);
+}
+
+cmState::Snapshot cmState::CreateIncludeFileSnapshot(
+ cmState::Snapshot originSnapshot, const std::string& fileName)
+{
+ PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position);
+ pos->SnapshotType = IncludeFileType;
+ pos->Keep = true;
+ pos->ExecutionListFile = this->ExecutionListFiles.Push(
+ originSnapshot.Position->ExecutionListFile, fileName);
+ assert(originSnapshot.Position->Vars.IsValid());
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ return cmState::Snapshot(this, pos);
+}
+
+cmState::Snapshot cmState::CreateVariableScopeSnapshot(
+ cmState::Snapshot originSnapshot)
+{
+ PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position);
+ pos->ScopeParent = originSnapshot.Position;
+ pos->SnapshotType = VariableScopeType;
+ pos->Keep = false;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ assert(originSnapshot.Position->Vars.IsValid());
+
+ cmLinkedTree<cmDefinitions>::iterator origin = originSnapshot.Position->Vars;
+ pos->Parent = origin;
+ pos->Vars = this->VarTree.Push(origin);
+ assert(pos->Vars.IsValid());
+ return cmState::Snapshot(this, pos);
+}
+
+cmState::Snapshot cmState::CreateInlineListFileSnapshot(
+ cmState::Snapshot originSnapshot, const std::string& fileName)
+{
+ PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position);
+ pos->SnapshotType = InlineListFileType;
+ pos->Keep = true;
+ pos->ExecutionListFile = this->ExecutionListFiles.Push(
+ originSnapshot.Position->ExecutionListFile, fileName);
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ return cmState::Snapshot(this, pos);
+}
+
+cmState::Snapshot cmState::CreatePolicyScopeSnapshot(
+ cmState::Snapshot originSnapshot)
+{
+ PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position);
+ pos->SnapshotType = PolicyScopeType;
+ pos->Keep = false;
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ return cmState::Snapshot(this, pos);
+}
+
+cmState::Snapshot cmState::Pop(cmState::Snapshot originSnapshot)
+{
+ PositionType pos = originSnapshot.Position;
+ PositionType prevPos = pos;
+ ++prevPos;
+ prevPos->IncludeDirectoryPosition =
+ prevPos->BuildSystemDirectory->IncludeDirectories.size();
+ prevPos->CompileDefinitionsPosition =
+ prevPos->BuildSystemDirectory->CompileDefinitions.size();
+ prevPos->CompileOptionsPosition =
+ prevPos->BuildSystemDirectory->CompileOptions.size();
+ prevPos->BuildSystemDirectory->DirectoryEnd = prevPos;
+
+ if (!pos->Keep && this->SnapshotData.IsLast(pos)) {
+ if (pos->Vars != prevPos->Vars) {
+ assert(this->VarTree.IsLast(pos->Vars));
+ this->VarTree.Pop(pos->Vars);
+ }
+ if (pos->ExecutionListFile != prevPos->ExecutionListFile) {
+ assert(this->ExecutionListFiles.IsLast(pos->ExecutionListFile));
+ this->ExecutionListFiles.Pop(pos->ExecutionListFile);
+ }
+ this->SnapshotData.Pop(pos);
+ }
+
+ return Snapshot(this, prevPos);
+}
+
+cmState::Snapshot::Snapshot(cmState* state)
+ : State(state)
+ , Position()
+{
+}
+
+std::vector<cmState::Snapshot> cmState::Snapshot::GetChildren()
+{
+ return this->Position->BuildSystemDirectory->Children;
+}
+
+cmState::Snapshot::Snapshot(cmState* state, PositionType position)
+ : State(state)
+ , Position(position)
+{
+}
+
+cmState::SnapshotType cmState::Snapshot::GetType() const
+{
+ return this->Position->SnapshotType;
+}
+
+const char* cmState::Directory::GetCurrentSource() const
+{
+ return this->DirectoryState->Location.c_str();
+}
+
+void cmState::Directory::SetCurrentSource(std::string const& dir)
+{
+ std::string& loc = this->DirectoryState->Location;
+ loc = dir;
+ cmSystemTools::ConvertToUnixSlashes(loc);
+ loc = cmSystemTools::CollapseFullPath(loc);
+
+ cmSystemTools::SplitPath(
+ loc, this->DirectoryState->CurrentSourceDirectoryComponents);
+ this->ComputeRelativePathTopSource();
+
+ this->Snapshot_.SetDefinition("CMAKE_CURRENT_SOURCE_DIR", loc);
+}
+
+const char* cmState::Directory::GetCurrentBinary() const
+{
+ return this->DirectoryState->OutputLocation.c_str();
+}
+
+void cmState::Directory::SetCurrentBinary(std::string const& dir)
+{
+ std::string& loc = this->DirectoryState->OutputLocation;
+ loc = dir;
+ cmSystemTools::ConvertToUnixSlashes(loc);
+ loc = cmSystemTools::CollapseFullPath(loc);
+
+ cmSystemTools::SplitPath(
+ loc, this->DirectoryState->CurrentBinaryDirectoryComponents);
+ this->ComputeRelativePathTopBinary();
+
+ this->Snapshot_.SetDefinition("CMAKE_CURRENT_BINARY_DIR", loc);
+}
+
+void cmState::Snapshot::SetListFile(const std::string& listfile)
+{
+ *this->Position->ExecutionListFile = listfile;
+}
+
+std::vector<std::string> const&
+cmState::Directory::GetCurrentSourceComponents() const
+{
+ return this->DirectoryState->CurrentSourceDirectoryComponents;
+}
+
+std::vector<std::string> const&
+cmState::Directory::GetCurrentBinaryComponents() const
+{
+ return this->DirectoryState->CurrentBinaryDirectoryComponents;
+}
+
+const char* cmState::Directory::GetRelativePathTopSource() const
+{
+ return this->DirectoryState->RelativePathTopSource.c_str();
+}
+
+const char* cmState::Directory::GetRelativePathTopBinary() const
+{
+ return this->DirectoryState->RelativePathTopBinary.c_str();
+}
+
+void cmState::Directory::SetRelativePathTopSource(const char* dir)
+{
+ this->DirectoryState->RelativePathTopSource = dir;
+}
+
+void cmState::Directory::SetRelativePathTopBinary(const char* dir)
+{
+ this->DirectoryState->RelativePathTopBinary = dir;
+}
+
+std::string cmState::Snapshot::GetExecutionListFile() const
+{
+ return *this->Position->ExecutionListFile;
+}
+
+bool cmState::Snapshot::IsValid() const
+{
+ return this->State && this->Position.IsValid()
+ ? this->Position != this->State->SnapshotData.Root()
+ : false;
+}
+
+cmState::Snapshot cmState::Snapshot::GetBuildsystemDirectoryParent() const
+{
+ Snapshot snapshot;
+ if (!this->State || this->Position == this->State->SnapshotData.Root()) {
+ return snapshot;
+ }
+ PositionType parentPos = this->Position->DirectoryParent;
+ if (parentPos != this->State->SnapshotData.Root()) {
+ snapshot =
+ Snapshot(this->State, parentPos->BuildSystemDirectory->DirectoryEnd);
+ }
+
+ return snapshot;
+}
+
+cmState::Snapshot cmState::Snapshot::GetCallStackParent() const
+{
+ assert(this->State);
+ assert(this->Position != this->State->SnapshotData.Root());
+
+ Snapshot snapshot;
+ PositionType parentPos = this->Position;
+ while (parentPos->SnapshotType == cmState::PolicyScopeType ||
+ parentPos->SnapshotType == cmState::VariableScopeType) {
+ ++parentPos;
+ }
+ if (parentPos->SnapshotType == cmState::BuildsystemDirectoryType ||
+ parentPos->SnapshotType == cmState::BaseType) {
+ return snapshot;
+ }
+
+ ++parentPos;
+ while (parentPos->SnapshotType == cmState::PolicyScopeType ||
+ parentPos->SnapshotType == cmState::VariableScopeType) {
+ ++parentPos;
+ }
+
+ if (parentPos == this->State->SnapshotData.Root()) {
+ return snapshot;
+ }
+
+ snapshot = Snapshot(this->State, parentPos);
+ return snapshot;
+}
+
+cmState::Snapshot cmState::Snapshot::GetCallStackBottom() const
+{
+ assert(this->State);
+ assert(this->Position != this->State->SnapshotData.Root());
+
+ PositionType pos = this->Position;
+ while (pos->SnapshotType != cmState::BaseType &&
+ pos->SnapshotType != cmState::BuildsystemDirectoryType &&
+ pos != this->State->SnapshotData.Root()) {
+ ++pos;
+ }
+ return Snapshot(this->State, pos);
+}
+
+void cmState::Snapshot::PushPolicy(cmPolicies::PolicyMap entry, bool weak)
+{
+ PositionType pos = this->Position;
+ pos->Policies = this->State->PolicyStack.Push(pos->Policies,
+ PolicyStackEntry(entry, weak));
+}
+
+bool cmState::Snapshot::PopPolicy()
+{
+ PositionType pos = this->Position;
+ if (pos->Policies == pos->PolicyScope) {
+ return false;
+ }
+ pos->Policies = this->State->PolicyStack.Pop(pos->Policies);
+ return true;
+}
+
+bool cmState::Snapshot::CanPopPolicyScope()
+{
+ return this->Position->Policies == this->Position->PolicyScope;
+}
+
+void cmState::Snapshot::SetPolicy(cmPolicies::PolicyID id,
+ cmPolicies::PolicyStatus status)
+{
+ // Update the policy stack from the top to the top-most strong entry.
+ bool previous_was_weak = true;
+ for (cmLinkedTree<PolicyStackEntry>::iterator psi = this->Position->Policies;
+ previous_was_weak && psi != this->Position->PolicyRoot; ++psi) {
+ psi->Set(id, status);
+ previous_was_weak = psi->Weak;
+ }
+}
+
+cmPolicies::PolicyStatus cmState::Snapshot::GetPolicy(
+ cmPolicies::PolicyID id) const
+{
+ cmPolicies::PolicyStatus status = cmPolicies::GetPolicyStatus(id);
+
+ if (status == cmPolicies::REQUIRED_ALWAYS ||
+ status == cmPolicies::REQUIRED_IF_USED) {
+ return status;
+ }
+
+ cmLinkedTree<BuildsystemDirectoryStateType>::iterator dir =
+ this->Position->BuildSystemDirectory;
+
+ while (true) {
+ assert(dir.IsValid());
+ cmLinkedTree<PolicyStackEntry>::iterator leaf =
+ dir->DirectoryEnd->Policies;
+ cmLinkedTree<PolicyStackEntry>::iterator root =
+ dir->DirectoryEnd->PolicyRoot;
+ for (; leaf != root; ++leaf) {
+ if (leaf->IsDefined(id)) {
+ status = leaf->Get(id);
+ return status;
+ }
+ }
+ cmState::PositionType e = dir->DirectoryEnd;
+ cmState::PositionType p = e->DirectoryParent;
+ if (p == this->State->SnapshotData.Root()) {
+ break;
+ }
+ dir = p->BuildSystemDirectory;
+ }
+ return status;
+}
+
+bool cmState::Snapshot::HasDefinedPolicyCMP0011()
+{
+ return !this->Position->Policies->IsEmpty();
+}
+
+const char* cmState::Snapshot::GetDefinition(std::string const& name) const
+{
+ assert(this->Position->Vars.IsValid());
+ return cmDefinitions::Get(name, this->Position->Vars, this->Position->Root);
+}
+
+bool cmState::Snapshot::IsInitialized(std::string const& name) const
+{
+ return cmDefinitions::HasKey(name, this->Position->Vars,
+ this->Position->Root);
+}
+
+void cmState::Snapshot::SetDefinition(std::string const& name,
+ std::string const& value)
+{
+ this->Position->Vars->Set(name, value.c_str());
+}
+
+void cmState::Snapshot::RemoveDefinition(std::string const& name)
+{
+ this->Position->Vars->Set(name, CM_NULLPTR);
+}
+
+std::vector<std::string> cmState::Snapshot::UnusedKeys() const
+{
+ return this->Position->Vars->UnusedKeys();
+}
+
+std::vector<std::string> cmState::Snapshot::ClosureKeys() const
+{
+ return cmDefinitions::ClosureKeys(this->Position->Vars,
+ this->Position->Root);
+}
+
+bool cmState::Snapshot::RaiseScope(std::string const& var, const char* varDef)
+{
+ if (this->Position->ScopeParent == this->Position->DirectoryParent) {
+ Snapshot parentDir = this->GetBuildsystemDirectoryParent();
+ if (!parentDir.IsValid()) {
+ return false;
+ }
+ // Update the definition in the parent directory top scope. This
+ // directory's scope was initialized by the closure of the parent
+ // scope, so we do not need to localize the definition first.
+ if (varDef) {
+ parentDir.SetDefinition(var, varDef);
+ } else {
+ parentDir.RemoveDefinition(var);
+ }
+ return true;
+ }
+ // First localize the definition in the current scope.
+ cmDefinitions::Raise(var, this->Position->Vars, this->Position->Root);
+
+ // Now update the definition in the parent scope.
+ this->Position->Parent->Set(var, varDef);
+ return true;
+}
+
+static const std::string cmPropertySentinal = std::string();
+
+template <typename T, typename U, typename V>
+void InitializeContentFromParent(T& parentContent, T& thisContent,
+ U& parentBacktraces, U& thisBacktraces,
+ V& contentEndPosition)
+{
+ std::vector<std::string>::const_iterator parentBegin = parentContent.begin();
+ std::vector<std::string>::const_iterator parentEnd = parentContent.end();
+
+ std::vector<std::string>::const_reverse_iterator parentRbegin =
+ cmMakeReverseIterator(parentEnd);
+ std::vector<std::string>::const_reverse_iterator parentRend =
+ parentContent.rend();
+ parentRbegin = std::find(parentRbegin, parentRend, cmPropertySentinal);
+ std::vector<std::string>::const_iterator parentIt = parentRbegin.base();
+
+ thisContent = std::vector<std::string>(parentIt, parentEnd);
+
+ std::vector<cmListFileBacktrace>::const_iterator btIt =
+ parentBacktraces.begin() + std::distance(parentBegin, parentIt);
+ std::vector<cmListFileBacktrace>::const_iterator btEnd =
+ parentBacktraces.end();
+
+ thisBacktraces = std::vector<cmListFileBacktrace>(btIt, btEnd);
+
+ contentEndPosition = thisContent.size();
+}
+
+void cmState::Snapshot::SetDefaultDefinitions()
+{
+/* Up to CMake 2.4 here only WIN32, UNIX and APPLE were set.
+ With CMake must separate between target and host platform. In most cases
+ the tests for WIN32, UNIX and APPLE will be for the target system, so an
+ additional set of variables for the host system is required ->
+ CMAKE_HOST_WIN32, CMAKE_HOST_UNIX, CMAKE_HOST_APPLE.
+ WIN32, UNIX and APPLE are now set in the platform files in
+ Modules/Platforms/.
+ To keep cmake scripts (-P) and custom language and compiler modules
+ working, these variables are still also set here in this place, but they
+ will be reset in CMakeSystemSpecificInformation.cmake before the platform
+ files are executed. */
+#if defined(_WIN32)
+ this->SetDefinition("WIN32", "1");
+ this->SetDefinition("CMAKE_HOST_WIN32", "1");
+#else
+ this->SetDefinition("UNIX", "1");
+ this->SetDefinition("CMAKE_HOST_UNIX", "1");
+#endif
+#if defined(__CYGWIN__)
+ if (cmSystemTools::IsOn(
+ cmSystemTools::GetEnv("CMAKE_LEGACY_CYGWIN_WIN32"))) {
+ this->SetDefinition("WIN32", "1");
+ this->SetDefinition("CMAKE_HOST_WIN32", "1");
+ }
+#endif
+#if defined(__APPLE__)
+ this->SetDefinition("APPLE", "1");
+ this->SetDefinition("CMAKE_HOST_APPLE", "1");
+#endif
+#if defined(__sun__)
+ this->SetDefinition("CMAKE_HOST_SOLARIS", "1");
+#endif
+
+ char temp[1024];
+ sprintf(temp, "%d", cmVersion::GetMinorVersion());
+ this->SetDefinition("CMAKE_MINOR_VERSION", temp);
+ sprintf(temp, "%d", cmVersion::GetMajorVersion());
+ this->SetDefinition("CMAKE_MAJOR_VERSION", temp);
+ sprintf(temp, "%d", cmVersion::GetPatchVersion());
+ this->SetDefinition("CMAKE_PATCH_VERSION", temp);
+ sprintf(temp, "%d", cmVersion::GetTweakVersion());
+ this->SetDefinition("CMAKE_TWEAK_VERSION", temp);
+ this->SetDefinition("CMAKE_VERSION", cmVersion::GetCMakeVersion());
+
+ this->SetDefinition("CMAKE_FILES_DIRECTORY",
+ cmake::GetCMakeFilesDirectory());
+
+ // Setup the default include file regular expression (match everything).
+ this->Position->BuildSystemDirectory->Properties.SetProperty(
+ "INCLUDE_REGULAR_EXPRESSION", "^.*$");
+}
+
+void cmState::Snapshot::SetDirectoryDefinitions()
+{
+ this->SetDefinition("CMAKE_SOURCE_DIR", this->State->GetSourceDirectory());
+ this->SetDefinition("CMAKE_CURRENT_SOURCE_DIR",
+ this->State->GetSourceDirectory());
+ this->SetDefinition("CMAKE_BINARY_DIR", this->State->GetBinaryDirectory());
+ this->SetDefinition("CMAKE_CURRENT_BINARY_DIR",
+ this->State->GetBinaryDirectory());
+}
+
+void cmState::Snapshot::InitializeFromParent()
+{
+ PositionType parent = this->Position->DirectoryParent;
+ assert(this->Position->Vars.IsValid());
+ assert(parent->Vars.IsValid());
+
+ *this->Position->Vars =
+ cmDefinitions::MakeClosure(parent->Vars, parent->Root);
+
+ InitializeContentFromParent(
+ parent->BuildSystemDirectory->IncludeDirectories,
+ this->Position->BuildSystemDirectory->IncludeDirectories,
+ parent->BuildSystemDirectory->IncludeDirectoryBacktraces,
+ this->Position->BuildSystemDirectory->IncludeDirectoryBacktraces,
+ this->Position->IncludeDirectoryPosition);
+
+ InitializeContentFromParent(
+ parent->BuildSystemDirectory->CompileDefinitions,
+ this->Position->BuildSystemDirectory->CompileDefinitions,
+ parent->BuildSystemDirectory->CompileDefinitionsBacktraces,
+ this->Position->BuildSystemDirectory->CompileDefinitionsBacktraces,
+ this->Position->CompileDefinitionsPosition);
+
+ InitializeContentFromParent(
+ parent->BuildSystemDirectory->CompileOptions,
+ this->Position->BuildSystemDirectory->CompileOptions,
+ parent->BuildSystemDirectory->CompileOptionsBacktraces,
+ this->Position->BuildSystemDirectory->CompileOptionsBacktraces,
+ this->Position->CompileOptionsPosition);
+}
+
+cmState* cmState::Snapshot::GetState() const
+{
+ return this->State;
+}
+
+cmState::Directory cmState::Snapshot::GetDirectory() const
+{
+ return Directory(this->Position->BuildSystemDirectory, *this);
+}
+
+void cmState::Snapshot::SetProjectName(const std::string& name)
+{
+ this->Position->BuildSystemDirectory->ProjectName = name;
+}
+
+std::string cmState::Snapshot::GetProjectName() const
+{
+ return this->Position->BuildSystemDirectory->ProjectName;
+}
+
+void cmState::Snapshot::InitializeFromParent_ForSubdirsCommand()
+{
+ std::string currentSrcDir = this->GetDefinition("CMAKE_CURRENT_SOURCE_DIR");
+ std::string currentBinDir = this->GetDefinition("CMAKE_CURRENT_BINARY_DIR");
+ this->InitializeFromParent();
+ this->SetDefinition("CMAKE_SOURCE_DIR", this->State->GetSourceDirectory());
+ this->SetDefinition("CMAKE_BINARY_DIR", this->State->GetBinaryDirectory());
+
+ this->SetDefinition("CMAKE_CURRENT_SOURCE_DIR", currentSrcDir);
+ this->SetDefinition("CMAKE_CURRENT_BINARY_DIR", currentBinDir);
+}
+
+cmState::Directory::Directory(
+ cmLinkedTree<BuildsystemDirectoryStateType>::iterator iter,
+ const cmState::Snapshot& snapshot)
+ : DirectoryState(iter)
+ , Snapshot_(snapshot)
+{
+}
+
+template <typename T, typename U>
+cmStringRange GetPropertyContent(T const& content, U contentEndPosition)
+{
+ std::vector<std::string>::const_iterator end =
+ content.begin() + contentEndPosition;
+
+ std::vector<std::string>::const_reverse_iterator rbegin =
+ cmMakeReverseIterator(end);
+ rbegin = std::find(rbegin, content.rend(), cmPropertySentinal);
+
+ return cmMakeRange(rbegin.base(), end);
+}
+
+template <typename T, typename U, typename V>
+cmBacktraceRange GetPropertyBacktraces(T const& content, U const& backtraces,
+ V contentEndPosition)
+{
+ std::vector<std::string>::const_iterator entryEnd =
+ content.begin() + contentEndPosition;
+
+ std::vector<std::string>::const_reverse_iterator rbegin =
+ cmMakeReverseIterator(entryEnd);
+ rbegin = std::find(rbegin, content.rend(), cmPropertySentinal);
+
+ std::vector<cmListFileBacktrace>::const_iterator it =
+ backtraces.begin() + std::distance(content.begin(), rbegin.base());
+
+ std::vector<cmListFileBacktrace>::const_iterator end = backtraces.end();
+ return cmMakeRange(it, end);
+}
+
+template <typename T, typename U, typename V>
+void AppendEntry(T& content, U& backtraces, V& endContentPosition,
+ const std::string& value, const cmListFileBacktrace& lfbt)
+{
+ if (value.empty()) {
+ return;
+ }
+
+ assert(endContentPosition == content.size());
+
+ content.push_back(value);
+ backtraces.push_back(lfbt);
+
+ endContentPosition = content.size();
+}
+
+template <typename T, typename U, typename V>
+void SetContent(T& content, U& backtraces, V& endContentPosition,
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ assert(endContentPosition == content.size());
+
+ content.resize(content.size() + 2);
+ backtraces.resize(backtraces.size() + 2);
+
+ content.back() = vec;
+ backtraces.back() = lfbt;
+
+ endContentPosition = content.size();
+}
+
+template <typename T, typename U, typename V>
+void ClearContent(T& content, U& backtraces, V& endContentPosition)
+{
+ assert(endContentPosition == content.size());
+
+ content.resize(content.size() + 1);
+ backtraces.resize(backtraces.size() + 1);
+
+ endContentPosition = content.size();
+}
+
+cmStringRange cmState::Directory::GetIncludeDirectoriesEntries() const
+{
+ return GetPropertyContent(
+ this->DirectoryState->IncludeDirectories,
+ this->Snapshot_.Position->IncludeDirectoryPosition);
+}
+
+cmBacktraceRange cmState::Directory::GetIncludeDirectoriesEntryBacktraces()
+ const
+{
+ return GetPropertyBacktraces(
+ this->DirectoryState->IncludeDirectories,
+ this->DirectoryState->IncludeDirectoryBacktraces,
+ this->Snapshot_.Position->IncludeDirectoryPosition);
+}
+
+void cmState::Directory::AppendIncludeDirectoriesEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ AppendEntry(this->DirectoryState->IncludeDirectories,
+ this->DirectoryState->IncludeDirectoryBacktraces,
+ this->Snapshot_.Position->IncludeDirectoryPosition, vec, lfbt);
+}
+
+void cmState::Directory::PrependIncludeDirectoriesEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ std::vector<std::string>::iterator entryEnd =
+ this->DirectoryState->IncludeDirectories.begin() +
+ this->Snapshot_.Position->IncludeDirectoryPosition;
+
+ std::vector<std::string>::reverse_iterator rend =
+ this->DirectoryState->IncludeDirectories.rend();
+ std::vector<std::string>::reverse_iterator rbegin =
+ cmMakeReverseIterator(entryEnd);
+ rbegin = std::find(rbegin, rend, cmPropertySentinal);
+
+ std::vector<std::string>::iterator entryIt = rbegin.base();
+ std::vector<std::string>::iterator entryBegin =
+ this->DirectoryState->IncludeDirectories.begin();
+
+ std::vector<cmListFileBacktrace>::iterator btIt =
+ this->DirectoryState->IncludeDirectoryBacktraces.begin() +
+ std::distance(entryBegin, entryIt);
+
+ this->DirectoryState->IncludeDirectories.insert(entryIt, vec);
+ this->DirectoryState->IncludeDirectoryBacktraces.insert(btIt, lfbt);
+
+ this->Snapshot_.Position->IncludeDirectoryPosition =
+ this->DirectoryState->IncludeDirectories.size();
+}
+
+void cmState::Directory::SetIncludeDirectories(const std::string& vec,
+ const cmListFileBacktrace& lfbt)
+{
+ SetContent(this->DirectoryState->IncludeDirectories,
+ this->DirectoryState->IncludeDirectoryBacktraces,
+ this->Snapshot_.Position->IncludeDirectoryPosition, vec, lfbt);
+}
+
+void cmState::Directory::ClearIncludeDirectories()
+{
+ ClearContent(this->DirectoryState->IncludeDirectories,
+ this->DirectoryState->IncludeDirectoryBacktraces,
+ this->Snapshot_.Position->IncludeDirectoryPosition);
+}
+
+cmStringRange cmState::Directory::GetCompileDefinitionsEntries() const
+{
+ return GetPropertyContent(
+ this->DirectoryState->CompileDefinitions,
+ this->Snapshot_.Position->CompileDefinitionsPosition);
+}
+
+cmBacktraceRange cmState::Directory::GetCompileDefinitionsEntryBacktraces()
+ const
+{
+ return GetPropertyBacktraces(
+ this->DirectoryState->CompileDefinitions,
+ this->DirectoryState->CompileDefinitionsBacktraces,
+ this->Snapshot_.Position->CompileDefinitionsPosition);
+}
+
+void cmState::Directory::AppendCompileDefinitionsEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ AppendEntry(this->DirectoryState->CompileDefinitions,
+ this->DirectoryState->CompileDefinitionsBacktraces,
+ this->Snapshot_.Position->CompileDefinitionsPosition, vec, lfbt);
+}
+
+void cmState::Directory::SetCompileDefinitions(const std::string& vec,
+ const cmListFileBacktrace& lfbt)
+{
+ SetContent(this->DirectoryState->CompileDefinitions,
+ this->DirectoryState->CompileDefinitionsBacktraces,
+ this->Snapshot_.Position->CompileDefinitionsPosition, vec, lfbt);
+}
+
+void cmState::Directory::ClearCompileDefinitions()
+{
+ ClearContent(this->DirectoryState->CompileDefinitions,
+ this->DirectoryState->CompileDefinitionsBacktraces,
+ this->Snapshot_.Position->CompileDefinitionsPosition);
+}
+
+cmStringRange cmState::Directory::GetCompileOptionsEntries() const
+{
+ return GetPropertyContent(this->DirectoryState->CompileOptions,
+ this->Snapshot_.Position->CompileOptionsPosition);
+}
+
+cmBacktraceRange cmState::Directory::GetCompileOptionsEntryBacktraces() const
+{
+ return GetPropertyBacktraces(
+ this->DirectoryState->CompileOptions,
+ this->DirectoryState->CompileOptionsBacktraces,
+ this->Snapshot_.Position->CompileOptionsPosition);
+}
+
+void cmState::Directory::AppendCompileOptionsEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ AppendEntry(this->DirectoryState->CompileOptions,
+ this->DirectoryState->CompileOptionsBacktraces,
+ this->Snapshot_.Position->CompileOptionsPosition, vec, lfbt);
+}
+
+void cmState::Directory::SetCompileOptions(const std::string& vec,
+ const cmListFileBacktrace& lfbt)
+{
+ SetContent(this->DirectoryState->CompileOptions,
+ this->DirectoryState->CompileOptionsBacktraces,
+ this->Snapshot_.Position->CompileOptionsPosition, vec, lfbt);
+}
+
+void cmState::Directory::ClearCompileOptions()
+{
+ ClearContent(this->DirectoryState->CompileOptions,
+ this->DirectoryState->CompileOptionsBacktraces,
+ this->Snapshot_.Position->CompileOptionsPosition);
+}
+
+bool cmState::Snapshot::StrictWeakOrder::operator()(
+ const cmState::Snapshot& lhs, const cmState::Snapshot& rhs) const
+{
+ return lhs.Position.StrictWeakOrdered(rhs.Position);
+}
+
+void cmState::Directory::SetProperty(const std::string& prop,
+ const char* value,
+ cmListFileBacktrace const& lfbt)
+{
+ if (prop == "INCLUDE_DIRECTORIES") {
+ if (!value) {
+ this->ClearIncludeDirectories();
+ return;
+ }
+ this->SetIncludeDirectories(value, lfbt);
+ return;
+ }
+ if (prop == "COMPILE_OPTIONS") {
+ if (!value) {
+ this->ClearCompileOptions();
+ return;
+ }
+ this->SetCompileOptions(value, lfbt);
+ return;
+ }
+ if (prop == "COMPILE_DEFINITIONS") {
+ if (!value) {
+ this->ClearCompileDefinitions();
+ return;
+ }
+ this->SetCompileDefinitions(value, lfbt);
+ return;
+ }
+
+ this->DirectoryState->Properties.SetProperty(prop, value);
+}
+
+void cmState::Directory::AppendProperty(const std::string& prop,
+ const char* value, bool asString,
+ cmListFileBacktrace const& lfbt)
+{
+ if (prop == "INCLUDE_DIRECTORIES") {
+ this->AppendIncludeDirectoriesEntry(value, lfbt);
+ return;
+ }
+ if (prop == "COMPILE_OPTIONS") {
+ this->AppendCompileOptionsEntry(value, lfbt);
+ return;
+ }
+ if (prop == "COMPILE_DEFINITIONS") {
+ this->AppendCompileDefinitionsEntry(value, lfbt);
+ return;
+ }
+
+ this->DirectoryState->Properties.AppendProperty(prop, value, asString);
+}
+
+const char* cmState::Directory::GetProperty(const std::string& prop) const
+{
+ const bool chain =
+ this->Snapshot_.State->IsPropertyChained(prop, cmProperty::DIRECTORY);
+ return this->GetProperty(prop, chain);
+}
+
+const char* cmState::Directory::GetProperty(const std::string& prop,
+ bool chain) const
+{
+ static std::string output;
+ output = "";
+ if (prop == "PARENT_DIRECTORY") {
+ cmState::Snapshot parent = this->Snapshot_.GetBuildsystemDirectoryParent();
+ if (parent.IsValid()) {
+ return parent.GetDirectory().GetCurrentSource();
+ }
+ return "";
+ } else if (prop == "LISTFILE_STACK") {
+ std::vector<std::string> listFiles;
+ cmState::Snapshot snp = this->Snapshot_;
+ while (snp.IsValid()) {
+ listFiles.push_back(snp.GetExecutionListFile());
+ snp = snp.GetCallStackParent();
+ }
+ std::reverse(listFiles.begin(), listFiles.end());
+ output = cmJoin(listFiles, ";");
+ return output.c_str();
+ } else if (prop == "CACHE_VARIABLES") {
+ output = cmJoin(this->Snapshot_.State->GetCacheEntryKeys(), ";");
+ return output.c_str();
+ } else 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());
+ std::sort(res.begin(), res.end());
+ output = cmJoin(res, ";");
+ return output.c_str();
+ } else if (prop == "INCLUDE_DIRECTORIES") {
+ output = cmJoin(this->GetIncludeDirectoriesEntries(), ";");
+ return output.c_str();
+ } else if (prop == "COMPILE_OPTIONS") {
+ output = cmJoin(this->GetCompileOptionsEntries(), ";");
+ return output.c_str();
+ } else if (prop == "COMPILE_DEFINITIONS") {
+ output = cmJoin(this->GetCompileDefinitionsEntries(), ";");
+ return output.c_str();
+ }
+
+ const char* retVal = this->DirectoryState->Properties.GetPropertyValue(prop);
+ if (!retVal && chain) {
+ Snapshot parentSnapshot = this->Snapshot_.GetBuildsystemDirectoryParent();
+ if (parentSnapshot.IsValid()) {
+ return parentSnapshot.GetDirectory().GetProperty(prop, chain);
+ }
+ return this->Snapshot_.State->GetGlobalProperty(prop);
+ }
+
+ return retVal;
+}
+
+bool cmState::Directory::GetPropertyAsBool(const std::string& prop) const
+{
+ return cmSystemTools::IsOn(this->GetProperty(prop));
+}
+
+std::vector<std::string> cmState::Directory::GetPropertyKeys() const
+{
+ std::vector<std::string> keys;
+ keys.reserve(this->DirectoryState->Properties.size());
+ for (cmPropertyMap::const_iterator it =
+ this->DirectoryState->Properties.begin();
+ it != this->DirectoryState->Properties.end(); ++it) {
+ keys.push_back(it->first);
+ }
+ return keys;
+}
+
+bool operator==(const cmState::Snapshot& lhs, const cmState::Snapshot& rhs)
+{
+ return lhs.Position == rhs.Position;
+}
+
+bool operator!=(const cmState::Snapshot& lhs, const cmState::Snapshot& rhs)
+{
+ return lhs.Position != rhs.Position;
+}
+
+static bool ParseEntryWithoutType(const std::string& entry, std::string& var,
+ std::string& value)
+{
+ // input line is: key=value
+ static cmsys::RegularExpression reg(
+ "^([^=]*)=(.*[^\r\t ]|[\r\t ]*)[\r\t ]*$");
+ // input line is: "key"=value
+ static cmsys::RegularExpression regQuoted(
+ "^\"([^\"]*)\"=(.*[^\r\t ]|[\r\t ]*)[\r\t ]*$");
+ bool flag = false;
+ if (regQuoted.find(entry)) {
+ var = regQuoted.match(1);
+ value = regQuoted.match(2);
+ flag = true;
+ } else if (reg.find(entry)) {
+ var = reg.match(1);
+ value = reg.match(2);
+ flag = true;
+ }
+
+ // if value is enclosed in single quotes ('foo') then remove them
+ // it is used to enclose trailing space or tab
+ if (flag && value.size() >= 2 && value[0] == '\'' &&
+ value[value.size() - 1] == '\'') {
+ value = value.substr(1, value.size() - 2);
+ }
+
+ return flag;
+}
+
+bool cmState::ParseCacheEntry(const std::string& entry, std::string& var,
+ std::string& value, CacheEntryType& type)
+{
+ // input line is: key:type=value
+ static cmsys::RegularExpression reg(
+ "^([^=:]*):([^=]*)=(.*[^\r\t ]|[\r\t ]*)[\r\t ]*$");
+ // input line is: "key":type=value
+ static cmsys::RegularExpression regQuoted(
+ "^\"([^\"]*)\":([^=]*)=(.*[^\r\t ]|[\r\t ]*)[\r\t ]*$");
+ bool flag = false;
+ if (regQuoted.find(entry)) {
+ var = regQuoted.match(1);
+ type = cmState::StringToCacheEntryType(regQuoted.match(2).c_str());
+ value = regQuoted.match(3);
+ flag = true;
+ } else if (reg.find(entry)) {
+ var = reg.match(1);
+ type = cmState::StringToCacheEntryType(reg.match(2).c_str());
+ value = reg.match(3);
+ flag = true;
+ }
+
+ // if value is enclosed in single quotes ('foo') then remove them
+ // it is used to enclose trailing space or tab
+ if (flag && value.size() >= 2 && value[0] == '\'' &&
+ value[value.size() - 1] == '\'') {
+ value = value.substr(1, value.size() - 2);
+ }
+
+ if (!flag) {
+ return ParseEntryWithoutType(entry, var, value);
+ }
+
+ return flag;
+}
diff --git a/Source/cmState.h b/Source/cmState.h
new file mode 100644
index 0000000..e5f9917
--- /dev/null
+++ b/Source/cmState.h
@@ -0,0 +1,363 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmState_h
+#define cmState_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmAlgorithms.h"
+#include "cmLinkedTree.h"
+#include "cmPolicies.h"
+#include "cmPropertyDefinitionMap.h"
+#include "cmPropertyMap.h"
+
+class cmake;
+class cmCommand;
+class cmDefinitions;
+class cmListFileBacktrace;
+class cmCacheManager;
+
+class cmState
+{
+ struct SnapshotDataType;
+ struct PolicyStackEntry;
+ struct BuildsystemDirectoryStateType;
+ typedef cmLinkedTree<SnapshotDataType>::iterator PositionType;
+ friend class Snapshot;
+
+public:
+ cmState();
+ ~cmState();
+
+ enum SnapshotType
+ {
+ BaseType,
+ BuildsystemDirectoryType,
+ FunctionCallType,
+ MacroCallType,
+ IncludeFileType,
+ InlineListFileType,
+ PolicyScopeType,
+ VariableScopeType
+ };
+
+ class Directory;
+
+ class Snapshot
+ {
+ public:
+ Snapshot(cmState* state = CM_NULLPTR);
+ Snapshot(cmState* state, PositionType position);
+
+ const char* GetDefinition(std::string const& name) const;
+ bool IsInitialized(std::string const& name) const;
+ void SetDefinition(std::string const& name, std::string const& value);
+ void RemoveDefinition(std::string const& name);
+ std::vector<std::string> UnusedKeys() const;
+ std::vector<std::string> ClosureKeys() const;
+ bool RaiseScope(std::string const& var, const char* varDef);
+
+ void SetListFile(std::string const& listfile);
+
+ std::string GetExecutionListFile() const;
+
+ std::vector<Snapshot> GetChildren();
+
+ bool IsValid() const;
+ Snapshot GetBuildsystemDirectoryParent() const;
+ Snapshot GetCallStackParent() const;
+ Snapshot GetCallStackBottom() const;
+ SnapshotType GetType() const;
+
+ void SetPolicy(cmPolicies::PolicyID id, cmPolicies::PolicyStatus status);
+ cmPolicies::PolicyStatus GetPolicy(cmPolicies::PolicyID id) const;
+ bool HasDefinedPolicyCMP0011();
+ void PushPolicy(cmPolicies::PolicyMap entry, bool weak);
+ bool PopPolicy();
+ bool CanPopPolicyScope();
+
+ cmState* GetState() const;
+
+ Directory GetDirectory() const;
+
+ void SetProjectName(std::string const& name);
+ std::string GetProjectName() const;
+
+ void InitializeFromParent_ForSubdirsCommand();
+
+ struct StrictWeakOrder
+ {
+ bool operator()(const cmState::Snapshot& lhs,
+ const cmState::Snapshot& rhs) const;
+ };
+
+ void SetDirectoryDefinitions();
+ void SetDefaultDefinitions();
+
+ private:
+ friend bool operator==(const cmState::Snapshot& lhs,
+ const cmState::Snapshot& rhs);
+ friend bool operator!=(const cmState::Snapshot& lhs,
+ const cmState::Snapshot& rhs);
+ friend class cmState;
+ friend class Directory;
+ friend struct StrictWeakOrder;
+
+ void InitializeFromParent();
+
+ cmState* State;
+ cmState::PositionType Position;
+ };
+
+ class Directory
+ {
+ Directory(cmLinkedTree<BuildsystemDirectoryStateType>::iterator iter,
+ Snapshot const& snapshot);
+
+ public:
+ const char* GetCurrentSource() const;
+ void SetCurrentSource(std::string const& dir);
+ const char* GetCurrentBinary() const;
+ void SetCurrentBinary(std::string const& dir);
+
+ std::vector<std::string> const& GetCurrentSourceComponents() const;
+ std::vector<std::string> const& GetCurrentBinaryComponents() const;
+
+ const char* GetRelativePathTopSource() const;
+ const char* GetRelativePathTopBinary() const;
+ void SetRelativePathTopSource(const char* dir);
+ void SetRelativePathTopBinary(const char* dir);
+
+ cmStringRange GetIncludeDirectoriesEntries() const;
+ cmBacktraceRange GetIncludeDirectoriesEntryBacktraces() const;
+ void AppendIncludeDirectoriesEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void PrependIncludeDirectoriesEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void SetIncludeDirectories(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void ClearIncludeDirectories();
+
+ cmStringRange GetCompileDefinitionsEntries() const;
+ cmBacktraceRange GetCompileDefinitionsEntryBacktraces() const;
+ void AppendCompileDefinitionsEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void SetCompileDefinitions(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void ClearCompileDefinitions();
+
+ cmStringRange GetCompileOptionsEntries() const;
+ cmBacktraceRange GetCompileOptionsEntryBacktraces() const;
+ void AppendCompileOptionsEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void SetCompileOptions(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void ClearCompileOptions();
+
+ void SetProperty(const std::string& prop, const char* value,
+ cmListFileBacktrace const& lfbt);
+ void AppendProperty(const std::string& prop, const char* value,
+ bool asString, cmListFileBacktrace const& lfbt);
+ const char* GetProperty(const std::string& prop) const;
+ const char* GetProperty(const std::string& prop, bool chain) const;
+ bool GetPropertyAsBool(const std::string& prop) const;
+ std::vector<std::string> GetPropertyKeys() const;
+
+ private:
+ void ComputeRelativePathTopSource();
+ void ComputeRelativePathTopBinary();
+
+ private:
+ cmLinkedTree<BuildsystemDirectoryStateType>::iterator DirectoryState;
+ Snapshot Snapshot_;
+ friend class Snapshot;
+ };
+
+ enum TargetType
+ {
+ EXECUTABLE,
+ STATIC_LIBRARY,
+ SHARED_LIBRARY,
+ MODULE_LIBRARY,
+ OBJECT_LIBRARY,
+ UTILITY,
+ GLOBAL_TARGET,
+ INTERFACE_LIBRARY,
+ UNKNOWN_LIBRARY
+ };
+
+ static const char* GetTargetTypeName(cmState::TargetType targetType);
+
+ Snapshot CreateBaseSnapshot();
+ Snapshot CreateBuildsystemDirectorySnapshot(Snapshot originSnapshot);
+ Snapshot CreateFunctionCallSnapshot(Snapshot originSnapshot,
+ std::string const& fileName);
+ Snapshot CreateMacroCallSnapshot(Snapshot originSnapshot,
+ std::string const& fileName);
+ Snapshot CreateIncludeFileSnapshot(Snapshot originSnapshot,
+ std::string const& fileName);
+ Snapshot CreateVariableScopeSnapshot(Snapshot originSnapshot);
+ Snapshot CreateInlineListFileSnapshot(Snapshot originSnapshot,
+ std::string const& fileName);
+ Snapshot CreatePolicyScopeSnapshot(Snapshot originSnapshot);
+ Snapshot Pop(Snapshot originSnapshot);
+
+ enum CacheEntryType
+ {
+ BOOL = 0,
+ PATH,
+ FILEPATH,
+ STRING,
+ INTERNAL,
+ STATIC,
+ UNINITIALIZED
+ };
+ static CacheEntryType StringToCacheEntryType(const char*);
+ static const char* CacheEntryTypeToString(CacheEntryType);
+ static bool IsCacheEntryType(std::string const& key);
+
+ bool LoadCache(const std::string& path, bool internal,
+ std::set<std::string>& excludes,
+ std::set<std::string>& includes);
+
+ bool SaveCache(const std::string& path);
+
+ bool DeleteCache(const std::string& path);
+
+ std::vector<std::string> GetCacheEntryKeys() const;
+ const char* GetCacheEntryValue(std::string const& key) const;
+ const char* GetInitializedCacheValue(std::string const& key) const;
+ CacheEntryType GetCacheEntryType(std::string const& key) const;
+ void SetCacheEntryValue(std::string const& key, std::string const& value);
+ void SetCacheValue(std::string const& key, std::string const& value);
+
+ void RemoveCacheEntry(std::string const& key);
+
+ void SetCacheEntryProperty(std::string const& key,
+ std::string const& propertyName,
+ std::string const& value);
+ void SetCacheEntryBoolProperty(std::string const& key,
+ std::string const& propertyName, bool value);
+ std::vector<std::string> GetCacheEntryPropertyList(std::string const& key);
+ const char* GetCacheEntryProperty(std::string const& key,
+ std::string const& propertyName);
+ bool GetCacheEntryPropertyAsBool(std::string const& key,
+ std::string const& propertyName);
+ void AppendCacheEntryProperty(std::string const& key,
+ const std::string& property,
+ const std::string& value,
+ bool asString = false);
+ void RemoveCacheEntryProperty(std::string const& key,
+ std::string const& propertyName);
+
+ ///! 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, CacheEntryType& type);
+
+ Snapshot Reset();
+ // Define a property
+ void DefineProperty(const std::string& name, cmProperty::ScopeType scope,
+ const char* ShortDescription,
+ const char* FullDescription, bool chain = false);
+
+ // get property definition
+ cmPropertyDefinition const* GetPropertyDefinition(
+ const std::string& name, cmProperty::ScopeType scope) const;
+
+ // Is a property defined?
+ bool IsPropertyDefined(const std::string& name,
+ cmProperty::ScopeType scope) const;
+ bool IsPropertyChained(const std::string& name,
+ cmProperty::ScopeType scope) const;
+
+ void SetLanguageEnabled(std::string const& l);
+ bool GetLanguageEnabled(std::string const& l) const;
+ std::vector<std::string> GetEnabledLanguages() const;
+ void SetEnabledLanguages(std::vector<std::string> const& langs);
+ void ClearEnabledLanguages();
+
+ bool GetIsInTryCompile() const;
+ void SetIsInTryCompile(bool b);
+
+ cmCommand* GetCommand(std::string const& name) const;
+ void AddCommand(cmCommand* command);
+ void RemoveUnscriptableCommands();
+ void RenameCommand(std::string const& oldName, std::string const& newName);
+ void RemoveUserDefinedCommands();
+ std::vector<std::string> GetCommandNames() const;
+
+ void SetGlobalProperty(const std::string& prop, const char* value);
+ void AppendGlobalProperty(const std::string& prop, const char* value,
+ bool asString = false);
+ const char* GetGlobalProperty(const std::string& prop);
+ bool GetGlobalPropertyAsBool(const std::string& prop);
+
+ const char* GetSourceDirectory() const;
+ void SetSourceDirectory(std::string const& sourceDirectory);
+ const char* GetBinaryDirectory() const;
+ void SetBinaryDirectory(std::string const& binaryDirectory);
+
+ std::vector<std::string> const& GetSourceDirectoryComponents() const;
+ std::vector<std::string> const& GetBinaryDirectoryComponents() const;
+
+ void SetWindowsShell(bool windowsShell);
+ bool UseWindowsShell() const;
+ void SetWindowsVSIDE(bool windowsVSIDE);
+ bool UseWindowsVSIDE() const;
+ void SetWatcomWMake(bool watcomWMake);
+ bool UseWatcomWMake() const;
+ void SetMinGWMake(bool minGWMake);
+ bool UseMinGWMake() const;
+ void SetNMake(bool nMake);
+ bool UseNMake() const;
+ void SetMSYSShell(bool mSYSShell);
+ bool UseMSYSShell() const;
+
+ unsigned int GetCacheMajorVersion() const;
+ unsigned int GetCacheMinorVersion() const;
+
+private:
+ friend class cmake;
+ void AddCacheEntry(const std::string& key, const char* value,
+ const char* helpString, CacheEntryType type);
+
+ std::map<cmProperty::ScopeType, cmPropertyDefinitionMap> PropertyDefinitions;
+ std::vector<std::string> EnabledLanguages;
+ std::map<std::string, cmCommand*> Commands;
+ cmPropertyMap GlobalProperties;
+ cmCacheManager* CacheManager;
+
+ cmLinkedTree<BuildsystemDirectoryStateType> BuildsystemDirectory;
+
+ cmLinkedTree<std::string> ExecutionListFiles;
+
+ cmLinkedTree<PolicyStackEntry> PolicyStack;
+ cmLinkedTree<SnapshotDataType> SnapshotData;
+ cmLinkedTree<cmDefinitions> VarTree;
+
+ std::vector<std::string> SourceDirectoryComponents;
+ std::vector<std::string> BinaryDirectoryComponents;
+ std::string SourceDirectory;
+ std::string BinaryDirectory;
+ bool IsInTryCompile;
+ bool WindowsShell;
+ bool WindowsVSIDE;
+ bool WatcomWMake;
+ bool MinGWMake;
+ bool NMake;
+ bool MSYSShell;
+};
+
+bool operator==(const cmState::Snapshot& lhs, const cmState::Snapshot& rhs);
+bool operator!=(const cmState::Snapshot& lhs, const cmState::Snapshot& rhs);
+
+#endif
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
new file mode 100644
index 0000000..dce4687
--- /dev/null
+++ b/Source/cmStringCommand.cxx
@@ -0,0 +1,902 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmStringCommand.h"
+
+#include "cmCryptoHash.h"
+
+#include <cmsys/RegularExpression.hxx>
+#include <cmsys/SystemTools.hxx>
+
+#include <ctype.h>
+#include <stdlib.h> // required for atoi
+#include <time.h>
+
+#include <cmTimestamp.h>
+#include <cmUuid.h>
+
+bool cmStringCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("must be called with at least one argument.");
+ return false;
+ }
+
+ const std::string& subCommand = args[0];
+ if (subCommand == "REGEX") {
+ return this->HandleRegexCommand(args);
+ } else if (subCommand == "REPLACE") {
+ return this->HandleReplaceCommand(args);
+ } else if (subCommand == "MD5" || subCommand == "SHA1" ||
+ subCommand == "SHA224" || subCommand == "SHA256" ||
+ subCommand == "SHA384" || subCommand == "SHA512") {
+ return this->HandleHashCommand(args);
+ } else if (subCommand == "TOLOWER") {
+ return this->HandleToUpperLowerCommand(args, false);
+ } else if (subCommand == "TOUPPER") {
+ return this->HandleToUpperLowerCommand(args, true);
+ } else if (subCommand == "COMPARE") {
+ return this->HandleCompareCommand(args);
+ } else if (subCommand == "ASCII") {
+ return this->HandleAsciiCommand(args);
+ } else if (subCommand == "CONFIGURE") {
+ return this->HandleConfigureCommand(args);
+ } else if (subCommand == "LENGTH") {
+ return this->HandleLengthCommand(args);
+ } else if (subCommand == "APPEND") {
+ return this->HandleAppendCommand(args);
+ } else if (subCommand == "CONCAT") {
+ return this->HandleConcatCommand(args);
+ } else if (subCommand == "SUBSTRING") {
+ return this->HandleSubstringCommand(args);
+ } else if (subCommand == "STRIP") {
+ return this->HandleStripCommand(args);
+ } else if (subCommand == "RANDOM") {
+ return this->HandleRandomCommand(args);
+ } else if (subCommand == "FIND") {
+ return this->HandleFindCommand(args);
+ } else if (subCommand == "TIMESTAMP") {
+ return this->HandleTimestampCommand(args);
+ } else if (subCommand == "MAKE_C_IDENTIFIER") {
+ return this->HandleMakeCIdentifierCommand(args);
+ } else if (subCommand == "GENEX_STRIP") {
+ return this->HandleGenexStripCommand(args);
+ } else if (subCommand == "UUID") {
+ return this->HandleUuidCommand(args);
+ }
+
+ std::string e = "does not recognize sub-command " + subCommand;
+ this->SetError(e);
+ return false;
+}
+
+bool cmStringCommand::HandleHashCommand(std::vector<std::string> const& args)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ if (args.size() != 3) {
+ std::ostringstream e;
+ e << args[0] << " requires an output variable and an input string";
+ this->SetError(e.str());
+ return false;
+ }
+
+ CM_AUTO_PTR<cmCryptoHash> hash(cmCryptoHash::New(args[0].c_str()));
+ if (hash.get()) {
+ std::string out = hash->HashString(args[2]);
+ this->Makefile->AddDefinition(args[1], out.c_str());
+ return true;
+ }
+ return false;
+#else
+ std::ostringstream e;
+ e << args[0] << " not available during bootstrap";
+ this->SetError(e.str().c_str());
+ return false;
+#endif
+}
+
+bool cmStringCommand::HandleToUpperLowerCommand(
+ std::vector<std::string> const& args, bool toUpper)
+{
+ if (args.size() < 3) {
+ this->SetError("no output variable specified");
+ return false;
+ }
+
+ std::string outvar = args[2];
+ std::string output;
+
+ if (toUpper) {
+ output = cmSystemTools::UpperCase(args[1]);
+ } else {
+ output = cmSystemTools::LowerCase(args[1]);
+ }
+
+ // Store the output in the provided variable.
+ this->Makefile->AddDefinition(outvar, output.c_str());
+ return true;
+}
+
+bool cmStringCommand::HandleAsciiCommand(std::vector<std::string> const& args)
+{
+ if (args.size() < 3) {
+ this->SetError("No output variable specified");
+ return false;
+ }
+ std::string::size_type cc;
+ std::string outvar = args[args.size() - 1];
+ std::string output = "";
+ for (cc = 1; cc < args.size() - 1; cc++) {
+ int ch = atoi(args[cc].c_str());
+ if (ch > 0 && ch < 256) {
+ output += static_cast<char>(ch);
+ } else {
+ std::string error = "Character with code ";
+ error += args[cc];
+ error += " does not exist.";
+ this->SetError(error);
+ return false;
+ }
+ }
+ // Store the output in the provided variable.
+ this->Makefile->AddDefinition(outvar, output.c_str());
+ return true;
+}
+
+bool cmStringCommand::HandleConfigureCommand(
+ std::vector<std::string> const& args)
+{
+ if (args.size() < 2) {
+ this->SetError("No input string specified.");
+ return false;
+ } else if (args.size() < 3) {
+ this->SetError("No output variable specified.");
+ return false;
+ }
+
+ // Parse options.
+ bool escapeQuotes = false;
+ bool atOnly = false;
+ for (unsigned int i = 3; i < args.size(); ++i) {
+ if (args[i] == "@ONLY") {
+ atOnly = true;
+ } else if (args[i] == "ESCAPE_QUOTES") {
+ escapeQuotes = true;
+ } else {
+ std::ostringstream err;
+ err << "Unrecognized argument \"" << args[i] << "\"";
+ this->SetError(err.str());
+ return false;
+ }
+ }
+
+ // Configure the string.
+ std::string output;
+ this->Makefile->ConfigureString(args[1], output, atOnly, escapeQuotes);
+
+ // Store the output in the provided variable.
+ this->Makefile->AddDefinition(args[2], output.c_str());
+
+ return true;
+}
+
+bool cmStringCommand::HandleRegexCommand(std::vector<std::string> const& args)
+{
+ if (args.size() < 2) {
+ this->SetError("sub-command REGEX requires a mode to be specified.");
+ return false;
+ }
+ std::string mode = args[1];
+ if (mode == "MATCH") {
+ if (args.size() < 5) {
+ this->SetError("sub-command REGEX, mode MATCH needs "
+ "at least 5 arguments total to command.");
+ return false;
+ }
+ return this->RegexMatch(args);
+ } else if (mode == "MATCHALL") {
+ if (args.size() < 5) {
+ this->SetError("sub-command REGEX, mode MATCHALL needs "
+ "at least 5 arguments total to command.");
+ return false;
+ }
+ return this->RegexMatchAll(args);
+ } else if (mode == "REPLACE") {
+ if (args.size() < 6) {
+ this->SetError("sub-command REGEX, mode REPLACE needs "
+ "at least 6 arguments total to command.");
+ return false;
+ }
+ return this->RegexReplace(args);
+ }
+
+ std::string e = "sub-command REGEX does not recognize mode " + mode;
+ this->SetError(e);
+ return false;
+}
+
+bool cmStringCommand::RegexMatch(std::vector<std::string> const& args)
+{
+ //"STRING(REGEX MATCH <regular_expression> <output variable>
+ // <input> [<input>...])\n";
+ std::string regex = args[2];
+ std::string outvar = args[3];
+
+ this->Makefile->ClearMatches();
+ // Compile the regular expression.
+ cmsys::RegularExpression re;
+ if (!re.compile(regex.c_str())) {
+ std::string e =
+ "sub-command REGEX, mode MATCH failed to compile regex \"" + regex +
+ "\".";
+ this->SetError(e);
+ return false;
+ }
+
+ // Concatenate all the last arguments together.
+ std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
+
+ // Scan through the input for all matches.
+ std::string output;
+ if (re.find(input.c_str())) {
+ this->Makefile->StoreMatches(re);
+ std::string::size_type l = re.start();
+ std::string::size_type r = re.end();
+ if (r - l == 0) {
+ std::string e = "sub-command REGEX, mode MATCH regex \"" + regex +
+ "\" matched an empty string.";
+ this->SetError(e);
+ return false;
+ }
+ output = input.substr(l, r - l);
+ }
+
+ // Store the output in the provided variable.
+ this->Makefile->AddDefinition(outvar, output.c_str());
+ return true;
+}
+
+bool cmStringCommand::RegexMatchAll(std::vector<std::string> const& args)
+{
+ //"STRING(REGEX MATCHALL <regular_expression> <output variable> <input>
+ // [<input>...])\n";
+ std::string regex = args[2];
+ std::string outvar = args[3];
+
+ this->Makefile->ClearMatches();
+ // Compile the regular expression.
+ cmsys::RegularExpression re;
+ if (!re.compile(regex.c_str())) {
+ std::string e =
+ "sub-command REGEX, mode MATCHALL failed to compile regex \"" + regex +
+ "\".";
+ this->SetError(e);
+ return false;
+ }
+
+ // Concatenate all the last arguments together.
+ std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
+
+ // Scan through the input for all matches.
+ std::string output;
+ const char* p = input.c_str();
+ while (re.find(p)) {
+ this->Makefile->StoreMatches(re);
+ std::string::size_type l = re.start();
+ std::string::size_type r = re.end();
+ if (r - l == 0) {
+ std::string e = "sub-command REGEX, mode MATCHALL regex \"" + regex +
+ "\" matched an empty string.";
+ this->SetError(e);
+ return false;
+ }
+ if (!output.empty()) {
+ output += ";";
+ }
+ output += std::string(p + l, r - l);
+ p += r;
+ }
+
+ // Store the output in the provided variable.
+ this->Makefile->AddDefinition(outvar, output.c_str());
+ return true;
+}
+
+bool cmStringCommand::RegexReplace(std::vector<std::string> const& args)
+{
+ //"STRING(REGEX REPLACE <regular_expression> <replace_expression>
+ // <output variable> <input> [<input>...])\n"
+ std::string regex = args[2];
+ std::string replace = args[3];
+ std::string outvar = args[4];
+
+ // Pull apart the replace expression to find the escaped [0-9] values.
+ std::vector<RegexReplacement> replacement;
+ std::string::size_type l = 0;
+ while (l < replace.length()) {
+ std::string::size_type r = replace.find("\\", l);
+ if (r == std::string::npos) {
+ r = replace.length();
+ replacement.push_back(replace.substr(l, r - l));
+ } else {
+ if (r - l > 0) {
+ replacement.push_back(replace.substr(l, r - l));
+ }
+ if (r == (replace.length() - 1)) {
+ this->SetError("sub-command REGEX, mode REPLACE: "
+ "replace-expression ends in a backslash.");
+ return false;
+ }
+ if ((replace[r + 1] >= '0') && (replace[r + 1] <= '9')) {
+ replacement.push_back(replace[r + 1] - '0');
+ } else if (replace[r + 1] == 'n') {
+ replacement.push_back("\n");
+ } else if (replace[r + 1] == '\\') {
+ replacement.push_back("\\");
+ } else {
+ std::string e = "sub-command REGEX, mode REPLACE: Unknown escape \"";
+ e += replace.substr(r, 2);
+ e += "\" in replace-expression.";
+ this->SetError(e);
+ return false;
+ }
+ r += 2;
+ }
+ l = r;
+ }
+
+ this->Makefile->ClearMatches();
+ // Compile the regular expression.
+ cmsys::RegularExpression re;
+ if (!re.compile(regex.c_str())) {
+ std::string e =
+ "sub-command REGEX, mode REPLACE failed to compile regex \"" + regex +
+ "\".";
+ this->SetError(e);
+ return false;
+ }
+
+ // Concatenate all the last arguments together.
+ std::string input = cmJoin(cmMakeRange(args).advance(5), std::string());
+
+ // Scan through the input for all matches.
+ std::string output;
+ std::string::size_type base = 0;
+ while (re.find(input.c_str() + base)) {
+ this->Makefile->StoreMatches(re);
+ std::string::size_type l2 = re.start();
+ std::string::size_type r = re.end();
+
+ // Concatenate the part of the input that was not matched.
+ output += input.substr(base, l2);
+
+ // Make sure the match had some text.
+ if (r - l2 == 0) {
+ std::string e = "sub-command REGEX, mode REPLACE regex \"" + regex +
+ "\" matched an empty string.";
+ this->SetError(e);
+ return false;
+ }
+
+ // Concatenate the replacement for the match.
+ for (unsigned int i = 0; i < replacement.size(); ++i) {
+ if (replacement[i].number < 0) {
+ // This is just a plain-text part of the replacement.
+ output += replacement[i].value;
+ } else {
+ // Replace with part of the match.
+ int n = replacement[i].number;
+ std::string::size_type start = re.start(n);
+ std::string::size_type end = re.end(n);
+ std::string::size_type len = input.length() - base;
+ if ((start != std::string::npos) && (end != std::string::npos) &&
+ (start <= len) && (end <= len)) {
+ output += input.substr(base + start, end - start);
+ } else {
+ std::string e =
+ "sub-command REGEX, mode REPLACE: replace expression \"" +
+ replace + "\" contains an out-of-range escape for regex \"" +
+ regex + "\".";
+ this->SetError(e);
+ return false;
+ }
+ }
+ }
+
+ // Move past the match.
+ base += r;
+ }
+
+ // Concatenate the text after the last match.
+ output += input.substr(base, input.length() - base);
+
+ // Store the output in the provided variable.
+ this->Makefile->AddDefinition(outvar, output.c_str());
+ return true;
+}
+
+bool cmStringCommand::HandleFindCommand(std::vector<std::string> const& args)
+{
+ // check if all required parameters were passed
+ if (args.size() < 4 || args.size() > 5) {
+ this->SetError("sub-command FIND requires 3 or 4 parameters.");
+ return false;
+ }
+
+ // check if the reverse flag was set or not
+ bool reverseMode = false;
+ if (args.size() == 5 && args[4] == "REVERSE") {
+ reverseMode = true;
+ }
+
+ // if we have 5 arguments the last one must be REVERSE
+ if (args.size() == 5 && args[4] != "REVERSE") {
+ this->SetError("sub-command FIND: unknown last parameter");
+ return false;
+ }
+
+ // local parameter names.
+ const std::string& sstring = args[1];
+ const std::string& schar = args[2];
+ const std::string& outvar = args[3];
+
+ // ensure that the user cannot accidentally specify REVERSE as a variable
+ if (outvar == "REVERSE") {
+ this->SetError("sub-command FIND does not allow one to select REVERSE as "
+ "the output variable. "
+ "Maybe you missed the actual output variable?");
+ return false;
+ }
+
+ // try to find the character and return its position
+ size_t pos;
+ if (!reverseMode) {
+ pos = sstring.find(schar);
+ } else {
+ pos = sstring.rfind(schar);
+ }
+ if (std::string::npos != pos) {
+ std::ostringstream s;
+ s << pos;
+ this->Makefile->AddDefinition(outvar, s.str().c_str());
+ return true;
+ }
+
+ // the character was not found, but this is not really an error
+ this->Makefile->AddDefinition(outvar, "-1");
+ return true;
+}
+
+bool cmStringCommand::HandleCompareCommand(
+ std::vector<std::string> const& args)
+{
+ if (args.size() < 2) {
+ this->SetError("sub-command COMPARE requires a mode to be specified.");
+ return false;
+ }
+ std::string mode = args[1];
+ if ((mode == "EQUAL") || (mode == "NOTEQUAL") || (mode == "LESS") ||
+ (mode == "GREATER")) {
+ if (args.size() < 5) {
+ std::string e = "sub-command COMPARE, mode ";
+ e += mode;
+ e += " needs at least 5 arguments total to command.";
+ this->SetError(e);
+ return false;
+ }
+
+ const std::string& left = args[2];
+ const std::string& right = args[3];
+ const std::string& outvar = args[4];
+ bool result;
+ if (mode == "LESS") {
+ result = (left < right);
+ } else if (mode == "GREATER") {
+ result = (left > right);
+ } else if (mode == "EQUAL") {
+ result = (left == right);
+ } else // if(mode == "NOTEQUAL")
+ {
+ result = !(left == right);
+ }
+ if (result) {
+ this->Makefile->AddDefinition(outvar, "1");
+ } else {
+ this->Makefile->AddDefinition(outvar, "0");
+ }
+ return true;
+ }
+ std::string e = "sub-command COMPARE does not recognize mode " + mode;
+ this->SetError(e);
+ return false;
+}
+
+bool cmStringCommand::HandleReplaceCommand(
+ std::vector<std::string> const& args)
+{
+ if (args.size() < 5) {
+ this->SetError("sub-command REPLACE requires at least four arguments.");
+ return false;
+ }
+
+ const std::string& matchExpression = args[1];
+ const std::string& replaceExpression = args[2];
+ const std::string& variableName = args[3];
+
+ std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
+
+ cmsys::SystemTools::ReplaceString(input, matchExpression.c_str(),
+ replaceExpression.c_str());
+
+ this->Makefile->AddDefinition(variableName, input.c_str());
+ return true;
+}
+
+bool cmStringCommand::HandleSubstringCommand(
+ std::vector<std::string> const& args)
+{
+ if (args.size() != 5) {
+ this->SetError("sub-command SUBSTRING requires four arguments.");
+ return false;
+ }
+
+ const std::string& stringValue = args[1];
+ int begin = atoi(args[2].c_str());
+ int end = atoi(args[3].c_str());
+ const std::string& variableName = args[4];
+
+ size_t stringLength = stringValue.size();
+ int intStringLength = static_cast<int>(stringLength);
+ if (begin < 0 || begin > intStringLength) {
+ std::ostringstream ostr;
+ ostr << "begin index: " << begin << " is out of range 0 - "
+ << stringLength;
+ this->SetError(ostr.str());
+ return false;
+ }
+ if (end < -1) {
+ std::ostringstream ostr;
+ ostr << "end index: " << end << " should be -1 or greater";
+ this->SetError(ostr.str());
+ return false;
+ }
+
+ this->Makefile->AddDefinition(variableName,
+ stringValue.substr(begin, end).c_str());
+ return true;
+}
+
+bool cmStringCommand::HandleLengthCommand(std::vector<std::string> const& args)
+{
+ if (args.size() != 3) {
+ this->SetError("sub-command LENGTH requires two arguments.");
+ return false;
+ }
+
+ const std::string& stringValue = args[1];
+ const std::string& variableName = args[2];
+
+ size_t length = stringValue.size();
+ char buffer[1024];
+ sprintf(buffer, "%d", static_cast<int>(length));
+
+ this->Makefile->AddDefinition(variableName, buffer);
+ return true;
+}
+
+bool cmStringCommand::HandleAppendCommand(std::vector<std::string> const& args)
+{
+ if (args.size() < 2) {
+ this->SetError("sub-command APPEND requires at least one argument.");
+ return false;
+ }
+
+ // Skip if nothing to append.
+ if (args.size() < 3) {
+ return true;
+ }
+
+ const std::string& variable = args[1];
+
+ std::string value;
+ const char* oldValue = this->Makefile->GetDefinition(variable);
+ if (oldValue) {
+ value = oldValue;
+ }
+ value += cmJoin(cmMakeRange(args).advance(2), std::string());
+ this->Makefile->AddDefinition(variable, value.c_str());
+ return true;
+}
+
+bool cmStringCommand::HandleConcatCommand(std::vector<std::string> const& args)
+{
+ if (args.size() < 2) {
+ this->SetError("sub-command CONCAT requires at least one argument.");
+ return false;
+ }
+
+ std::string const& variableName = args[1];
+ std::string value = cmJoin(cmMakeRange(args).advance(2), std::string());
+
+ this->Makefile->AddDefinition(variableName, value.c_str());
+ return true;
+}
+
+bool cmStringCommand::HandleMakeCIdentifierCommand(
+ std::vector<std::string> const& args)
+{
+ if (args.size() != 3) {
+ this->SetError("sub-command MAKE_C_IDENTIFIER requires two arguments.");
+ return false;
+ }
+
+ const std::string& input = args[1];
+ const std::string& variableName = args[2];
+
+ this->Makefile->AddDefinition(variableName,
+ cmSystemTools::MakeCidentifier(input).c_str());
+ return true;
+}
+
+bool cmStringCommand::HandleGenexStripCommand(
+ std::vector<std::string> const& args)
+{
+ if (args.size() != 3) {
+ this->SetError("sub-command GENEX_STRIP requires two arguments.");
+ return false;
+ }
+
+ const std::string& input = args[1];
+
+ std::string result = cmGeneratorExpression::Preprocess(
+ input, cmGeneratorExpression::StripAllGeneratorExpressions);
+
+ const std::string& variableName = args[2];
+
+ this->Makefile->AddDefinition(variableName, result.c_str());
+ return true;
+}
+
+bool cmStringCommand::HandleStripCommand(std::vector<std::string> const& args)
+{
+ if (args.size() != 3) {
+ this->SetError("sub-command STRIP requires two arguments.");
+ return false;
+ }
+
+ const std::string& stringValue = args[1];
+ const std::string& variableName = args[2];
+ size_t inStringLength = stringValue.size();
+ size_t startPos = inStringLength + 1;
+ size_t endPos = 0;
+ const char* ptr = stringValue.c_str();
+ size_t cc;
+ for (cc = 0; cc < inStringLength; ++cc) {
+ if (!isspace(*ptr)) {
+ if (startPos > inStringLength) {
+ startPos = cc;
+ }
+ endPos = cc;
+ }
+ ++ptr;
+ }
+
+ size_t outLength = 0;
+
+ // if the input string didn't contain any non-space characters, return
+ // an empty string
+ if (startPos > inStringLength) {
+ outLength = 0;
+ startPos = 0;
+ } else {
+ outLength = endPos - startPos + 1;
+ }
+
+ this->Makefile->AddDefinition(
+ variableName, stringValue.substr(startPos, outLength).c_str());
+ return true;
+}
+
+bool cmStringCommand::HandleRandomCommand(std::vector<std::string> const& args)
+{
+ if (args.size() < 2 || args.size() == 3 || args.size() == 5) {
+ this->SetError("sub-command RANDOM requires at least one argument.");
+ return false;
+ }
+
+ static bool seeded = false;
+ bool force_seed = false;
+ unsigned int seed = 0;
+ int length = 5;
+ const char cmStringCommandDefaultAlphabet[] = "qwertyuiopasdfghjklzxcvbnm"
+ "QWERTYUIOPASDFGHJKLZXCVBNM"
+ "0123456789";
+ std::string alphabet;
+
+ if (args.size() > 3) {
+ size_t i = 1;
+ size_t stopAt = args.size() - 2;
+
+ for (; i < stopAt; ++i) {
+ if (args[i] == "LENGTH") {
+ ++i;
+ length = atoi(args[i].c_str());
+ } else if (args[i] == "ALPHABET") {
+ ++i;
+ alphabet = args[i];
+ } else if (args[i] == "RANDOM_SEED") {
+ ++i;
+ seed = static_cast<unsigned int>(atoi(args[i].c_str()));
+ force_seed = true;
+ }
+ }
+ }
+ if (alphabet.empty()) {
+ alphabet = cmStringCommandDefaultAlphabet;
+ }
+
+ double sizeofAlphabet = static_cast<double>(alphabet.size());
+ if (sizeofAlphabet < 1) {
+ this->SetError("sub-command RANDOM invoked with bad alphabet.");
+ return false;
+ }
+ if (length < 1) {
+ this->SetError("sub-command RANDOM invoked with bad length.");
+ return false;
+ }
+ const std::string& variableName = args[args.size() - 1];
+
+ std::vector<char> result;
+
+ if (!seeded || force_seed) {
+ seeded = true;
+ srand(force_seed ? seed : cmSystemTools::RandomSeed());
+ }
+
+ const char* alphaPtr = alphabet.c_str();
+ int cc;
+ for (cc = 0; cc < length; cc++) {
+ int idx = (int)(sizeofAlphabet * rand() / (RAND_MAX + 1.0));
+ result.push_back(*(alphaPtr + idx));
+ }
+ result.push_back(0);
+
+ this->Makefile->AddDefinition(variableName, &*result.begin());
+ return true;
+}
+
+bool cmStringCommand::HandleTimestampCommand(
+ std::vector<std::string> const& args)
+{
+ if (args.size() < 2) {
+ this->SetError("sub-command TIMESTAMP requires at least one argument.");
+ return false;
+ } else if (args.size() > 4) {
+ this->SetError("sub-command TIMESTAMP takes at most three arguments.");
+ return false;
+ }
+
+ unsigned int argsIndex = 1;
+
+ const std::string& outputVariable = args[argsIndex++];
+
+ std::string formatString;
+ if (args.size() > argsIndex && args[argsIndex] != "UTC") {
+ formatString = args[argsIndex++];
+ }
+
+ bool utcFlag = false;
+ if (args.size() > argsIndex) {
+ if (args[argsIndex] == "UTC") {
+ utcFlag = true;
+ } else {
+ std::string e = " TIMESTAMP sub-command does not recognize option " +
+ args[argsIndex] + ".";
+ this->SetError(e);
+ return false;
+ }
+ }
+
+ cmTimestamp timestamp;
+ std::string result = timestamp.CurrentTime(formatString, utcFlag);
+ this->Makefile->AddDefinition(outputVariable, result.c_str());
+
+ return true;
+}
+
+bool cmStringCommand::HandleUuidCommand(std::vector<std::string> const& args)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ unsigned int argsIndex = 1;
+
+ if (args.size() < 2) {
+ this->SetError("UUID sub-command requires an output variable.");
+ return false;
+ }
+
+ const std::string& outputVariable = args[argsIndex++];
+
+ std::string uuidNamespaceString;
+ std::string uuidName;
+ std::string uuidType;
+ bool uuidUpperCase = false;
+
+ while (args.size() > argsIndex) {
+ if (args[argsIndex] == "NAMESPACE") {
+ ++argsIndex;
+ if (argsIndex >= args.size()) {
+ this->SetError("UUID sub-command, NAMESPACE requires a value.");
+ return false;
+ }
+ uuidNamespaceString = args[argsIndex++];
+ } else if (args[argsIndex] == "NAME") {
+ ++argsIndex;
+ if (argsIndex >= args.size()) {
+ this->SetError("UUID sub-command, NAME requires a value.");
+ return false;
+ }
+ uuidName = args[argsIndex++];
+ } else if (args[argsIndex] == "TYPE") {
+ ++argsIndex;
+ if (argsIndex >= args.size()) {
+ this->SetError("UUID sub-command, TYPE requires a value.");
+ return false;
+ }
+ uuidType = args[argsIndex++];
+ } else if (args[argsIndex] == "UPPER") {
+ ++argsIndex;
+ uuidUpperCase = true;
+ } else {
+ std::string e =
+ "UUID sub-command does not recognize option " + args[argsIndex] + ".";
+ this->SetError(e);
+ return false;
+ }
+ }
+
+ std::string uuid;
+ cmUuid uuidGenerator;
+
+ std::vector<unsigned char> uuidNamespace;
+ if (!uuidGenerator.StringToBinary(uuidNamespaceString, uuidNamespace)) {
+ this->SetError("UUID sub-command, malformed NAMESPACE UUID.");
+ return false;
+ }
+
+ if (uuidType == "MD5") {
+ uuid = uuidGenerator.FromMd5(uuidNamespace, uuidName);
+ } else if (uuidType == "SHA1") {
+ uuid = uuidGenerator.FromSha1(uuidNamespace, uuidName);
+ } else {
+ std::string e = "UUID sub-command, unknown TYPE '" + uuidType + "'.";
+ this->SetError(e);
+ return false;
+ }
+
+ if (uuid.empty()) {
+ this->SetError("UUID sub-command, generation failed.");
+ return false;
+ }
+
+ if (uuidUpperCase) {
+ uuid = cmSystemTools::UpperCase(uuid);
+ }
+
+ this->Makefile->AddDefinition(outputVariable, uuid.c_str());
+ return true;
+#else
+ std::ostringstream e;
+ e << args[0] << " not available during bootstrap";
+ this->SetError(e.str().c_str());
+ return false;
+#endif
+}
diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h
new file mode 100644
index 0000000..23dc9db
--- /dev/null
+++ b/Source/cmStringCommand.h
@@ -0,0 +1,101 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmStringCommand_h
+#define cmStringCommand_h
+
+#include "cmCommand.h"
+
+class cmMakefile;
+namespace cmsys {
+class RegularExpression;
+}
+
+/** \class cmStringCommand
+ * \brief Common string operations
+ *
+ */
+class cmStringCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmStringCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "string"; }
+
+ cmTypeMacro(cmStringCommand, cmCommand);
+
+protected:
+ bool HandleConfigureCommand(std::vector<std::string> const& args);
+ bool HandleAsciiCommand(std::vector<std::string> const& args);
+ bool HandleRegexCommand(std::vector<std::string> const& args);
+ bool RegexMatch(std::vector<std::string> const& args);
+ bool RegexMatchAll(std::vector<std::string> const& args);
+ bool RegexReplace(std::vector<std::string> const& args);
+ bool HandleHashCommand(std::vector<std::string> const& args);
+ bool HandleToUpperLowerCommand(std::vector<std::string> const& args,
+ bool toUpper);
+ bool HandleCompareCommand(std::vector<std::string> const& args);
+ bool HandleReplaceCommand(std::vector<std::string> const& args);
+ bool HandleLengthCommand(std::vector<std::string> const& args);
+ bool HandleSubstringCommand(std::vector<std::string> const& args);
+ bool HandleAppendCommand(std::vector<std::string> const& args);
+ bool HandleConcatCommand(std::vector<std::string> const& args);
+ bool HandleStripCommand(std::vector<std::string> const& args);
+ bool HandleRandomCommand(std::vector<std::string> const& args);
+ bool HandleFindCommand(std::vector<std::string> const& args);
+ bool HandleTimestampCommand(std::vector<std::string> const& args);
+ bool HandleMakeCIdentifierCommand(std::vector<std::string> const& args);
+ bool HandleGenexStripCommand(std::vector<std::string> const& args);
+ bool HandleUuidCommand(std::vector<std::string> const& args);
+
+ class RegexReplacement
+ {
+ public:
+ RegexReplacement(const char* s)
+ : number(-1)
+ , value(s)
+ {
+ }
+ RegexReplacement(const std::string& s)
+ : number(-1)
+ , value(s)
+ {
+ }
+ RegexReplacement(int n)
+ : number(n)
+ , value()
+ {
+ }
+ RegexReplacement() {}
+ int number;
+ std::string value;
+ };
+};
+
+#endif
diff --git a/Source/cmSubdirCommand.cxx b/Source/cmSubdirCommand.cxx
new file mode 100644
index 0000000..401f588
--- /dev/null
+++ b/Source/cmSubdirCommand.cxx
@@ -0,0 +1,62 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSubdirCommand.h"
+
+// cmSubdirCommand
+bool cmSubdirCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ bool res = true;
+ bool excludeFromAll = false;
+
+ for (std::vector<std::string>::const_iterator i = args.begin();
+ i != args.end(); ++i) {
+ if (*i == "EXCLUDE_FROM_ALL") {
+ excludeFromAll = true;
+ continue;
+ }
+ if (*i == "PREORDER") {
+ // Ignored
+ continue;
+ }
+
+ // if they specified a relative path then compute the full
+ std::string srcPath =
+ std::string(this->Makefile->GetCurrentSourceDirectory()) + "/" +
+ i->c_str();
+ if (cmSystemTools::FileIsDirectory(srcPath)) {
+ std::string binPath =
+ std::string(this->Makefile->GetCurrentBinaryDirectory()) + "/" +
+ i->c_str();
+ this->Makefile->AddSubDirectory(srcPath, binPath, excludeFromAll, false);
+ }
+ // otherwise it is a full path
+ else if (cmSystemTools::FileIsDirectory(*i)) {
+ // we must compute the binPath from the srcPath, we just take the last
+ // element from the source path and use that
+ std::string binPath =
+ std::string(this->Makefile->GetCurrentBinaryDirectory()) + "/" +
+ cmSystemTools::GetFilenameName(*i);
+ this->Makefile->AddSubDirectory(*i, binPath, excludeFromAll, false);
+ } else {
+ std::string error = "Incorrect SUBDIRS command. Directory: ";
+ error += *i + " does not exist.";
+ this->SetError(error);
+ res = false;
+ }
+ }
+ return res;
+}
diff --git a/Source/cmSubdirCommand.h b/Source/cmSubdirCommand.h
new file mode 100644
index 0000000..08eb9a0
--- /dev/null
+++ b/Source/cmSubdirCommand.h
@@ -0,0 +1,47 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSubdirCommand_h
+#define cmSubdirCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmSubdirCommand
+ * \brief Specify a list of subdirectories to build.
+ *
+ * cmSubdirCommand specifies a list of subdirectories to process
+ * by CMake. For each subdirectory listed, CMake will descend
+ * into that subdirectory and process any CMakeLists.txt found.
+ */
+class cmSubdirCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmSubdirCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "subdirs"; }
+
+ cmTypeMacro(cmSubdirCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmSubdirDependsCommand.cxx b/Source/cmSubdirDependsCommand.cxx
new file mode 100644
index 0000000..c80fb94
--- /dev/null
+++ b/Source/cmSubdirDependsCommand.cxx
@@ -0,0 +1,21 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSubdirDependsCommand.h"
+
+bool cmSubdirDependsCommand::InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&)
+{
+ this->Disallowed(
+ cmPolicies::CMP0029,
+ "The subdir_depends command should not be called; see CMP0029.");
+ return true;
+}
diff --git a/Source/cmSubdirDependsCommand.h b/Source/cmSubdirDependsCommand.h
new file mode 100644
index 0000000..41b27c8
--- /dev/null
+++ b/Source/cmSubdirDependsCommand.h
@@ -0,0 +1,27 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSubdirDependsCommand_h
+#define cmSubdirDependsCommand_h
+
+#include "cmCommand.h"
+
+class cmSubdirDependsCommand : public cmCommand
+{
+public:
+ cmCommand* Clone() CM_OVERRIDE { return new cmSubdirDependsCommand; }
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+ std::string GetName() const CM_OVERRIDE { return "subdir_depends"; }
+ cmTypeMacro(cmSubdirDependsCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
new file mode 100644
index 0000000..2d463f3
--- /dev/null
+++ b/Source/cmSystemTools.cxx
@@ -0,0 +1,2642 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSystemTools.h"
+
+#include "cmAlgorithms.h"
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#ifdef __QNX__
+#include <malloc.h> /* for malloc/free on QNX */
+#endif
+#include <cmsys/Directory.hxx>
+#include <cmsys/Encoding.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/RegularExpression.hxx>
+#include <cmsys/System.h>
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmArchiveWrite.h"
+#include "cmLocale.h"
+#include <cm_libarchive.h>
+#ifndef __LA_INT64_T
+#define __LA_INT64_T la_int64_t
+#endif
+#endif
+#include <cmsys/FStream.hxx>
+#include <cmsys/Terminal.h>
+
+#if defined(_WIN32)
+#include <windows.h>
+// include wincrypt.h after windows.h
+#include <wincrypt.h>
+#else
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <utime.h>
+#endif
+
+#if defined(__APPLE__)
+#include <mach-o/dyld.h>
+#endif
+
+#include <sys/stat.h>
+
+#if defined(_WIN32) && \
+ (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__MINGW32__))
+#include <io.h>
+#endif
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmCryptoHash.h"
+#endif
+
+#if defined(CMAKE_USE_ELF_PARSER)
+#include "cmELF.h"
+#endif
+
+#if defined(CMAKE_USE_MACH_PARSER)
+#include "cmMachO.h"
+#endif
+
+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)
+extern __declspec(dllimport) char** environ;
+#else
+extern char** environ;
+#endif
+#endif
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+static std::string cm_archive_entry_pathname(struct archive_entry* entry)
+{
+#if cmsys_STL_HAS_WSTRING
+ return cmsys::Encoding::ToNarrow(archive_entry_pathname_w(entry));
+#else
+ return archive_entry_pathname(entry);
+#endif
+}
+
+static int cm_archive_read_open_file(struct archive* a, const char* file,
+ int block_size)
+{
+#if cmsys_STL_HAS_WSTRING
+ std::wstring wfile = cmsys::Encoding::ToWide(file);
+ return archive_read_open_filename_w(a, wfile.c_str(), block_size);
+#else
+ return archive_read_open_filename(a, file, block_size);
+#endif
+}
+#endif
+
+#ifdef _WIN32
+class cmSystemToolsWindowsHandle
+{
+public:
+ cmSystemToolsWindowsHandle(HANDLE h)
+ : handle_(h)
+ {
+ }
+ ~cmSystemToolsWindowsHandle()
+ {
+ if (this->handle_ != INVALID_HANDLE_VALUE) {
+ CloseHandle(this->handle_);
+ }
+ }
+ 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>
+#define environ (*_NSGetEnviron())
+#endif
+
+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;
+
+cmSystemTools::MessageCallback cmSystemTools::s_MessageCallback;
+cmSystemTools::OutputCallback cmSystemTools::s_StdoutCallback;
+cmSystemTools::OutputCallback cmSystemTools::s_StderrCallback;
+cmSystemTools::InterruptCallback cmSystemTools::s_InterruptCallback;
+void* cmSystemTools::s_MessageCallbackClientData;
+void* cmSystemTools::s_StdoutCallbackClientData;
+void* cmSystemTools::s_StderrCallbackClientData;
+void* cmSystemTools::s_InterruptCallbackClientData;
+
+// replace replace with with as many times as it shows up in source.
+// write the result into source.
+#if defined(_WIN32) && !defined(__CYGWIN__)
+void cmSystemTools::ExpandRegistryValues(std::string& source, KeyWOW64 view)
+{
+ // Regular expression to match anything inside [...] that begins in HKEY.
+ // Note that there is a special rule for regular expressions to match a
+ // close square-bracket inside a list delimited by square brackets.
+ // The "[^]]" part of this expression will match any character except
+ // a close square-bracket. The ']' character must be the first in the
+ // list of characters inside the [^...] block of the expression.
+ cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]");
+
+ // check for black line or comment
+ while (regEntry.find(source)) {
+ // the arguments are the second match
+ std::string key = regEntry.match(1);
+ std::string val;
+ if (ReadRegistryValue(key.c_str(), val, view)) {
+ std::string reg = "[";
+ reg += key + "]";
+ cmSystemTools::ReplaceString(source, reg.c_str(), val.c_str());
+ } else {
+ std::string reg = "[";
+ reg += key + "]";
+ cmSystemTools::ReplaceString(source, reg.c_str(), "/registry");
+ }
+ }
+}
+#else
+void cmSystemTools::ExpandRegistryValues(std::string& source, KeyWOW64)
+{
+ cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]");
+ while (regEntry.find(source)) {
+ // the arguments are the second match
+ std::string key = regEntry.match(1);
+ std::string val;
+ std::string reg = "[";
+ reg += key + "]";
+ cmSystemTools::ReplaceString(source, reg.c_str(), "/registry");
+ }
+}
+#endif
+
+std::string cmSystemTools::EscapeQuotes(const std::string& str)
+{
+ std::string result;
+ result.reserve(str.size());
+ for (const char* ch = str.c_str(); *ch != '\0'; ++ch) {
+ if (*ch == '"') {
+ result += '\\';
+ }
+ result += *ch;
+ }
+ return result;
+}
+
+std::string cmSystemTools::HelpFileName(std::string name)
+{
+ cmSystemTools::ReplaceString(name, "<", "");
+ cmSystemTools::ReplaceString(name, ">", "");
+ return name;
+}
+
+std::string cmSystemTools::TrimWhitespace(const std::string& s)
+{
+ std::string::const_iterator start = s.begin();
+ while (start != s.end() && cm_isspace(*start)) {
+ ++start;
+ }
+ if (start == s.end()) {
+ return "";
+ }
+ std::string::const_iterator stop = s.end() - 1;
+ while (cm_isspace(*stop)) {
+ --stop;
+ }
+ 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.c_str(), "Error");
+}
+
+void cmSystemTools::SetInterruptCallback(InterruptCallback f, void* clientData)
+{
+ s_InterruptCallback = f;
+ s_InterruptCallbackClientData = clientData;
+}
+
+bool cmSystemTools::GetInterruptFlag()
+{
+ if (s_InterruptCallback) {
+ return (*s_InterruptCallback)(s_InterruptCallbackClientData);
+ }
+ return false;
+}
+
+void cmSystemTools::SetMessageCallback(MessageCallback f, void* clientData)
+{
+ s_MessageCallback = f;
+ s_MessageCallbackClientData = clientData;
+}
+
+void cmSystemTools::SetStdoutCallback(OutputCallback f, void* clientData)
+{
+ s_StdoutCallback = f;
+ s_StdoutCallbackClientData = clientData;
+}
+
+void cmSystemTools::SetStderrCallback(OutputCallback f, void* clientData)
+{
+ s_StderrCallback = f;
+ s_StderrCallbackClientData = clientData;
+}
+
+void cmSystemTools::Stdout(const char* s)
+{
+ cmSystemTools::Stdout(s, strlen(s));
+}
+
+void cmSystemTools::Stderr(const char* s)
+{
+ cmSystemTools::Stderr(s, strlen(s));
+}
+
+void cmSystemTools::Stderr(const char* s, size_t length)
+{
+ if (s_StderrCallback) {
+ (*s_StderrCallback)(s, length, s_StderrCallbackClientData);
+ } else {
+ std::cerr.write(s, length);
+ std::cerr.flush();
+ }
+}
+
+void cmSystemTools::Stdout(const char* s, size_t length)
+{
+ if (s_StdoutCallback) {
+ (*s_StdoutCallback)(s, length, s_StdoutCallbackClientData);
+ } else {
+ std::cout.write(s, length);
+ std::cout.flush();
+ }
+}
+
+void cmSystemTools::Message(const char* m1, const char* title)
+{
+ if (s_DisableMessages) {
+ return;
+ }
+ if (s_MessageCallback) {
+ (*s_MessageCallback)(m1, title, s_DisableMessages,
+ s_MessageCallbackClientData);
+ return;
+ } else {
+ std::cerr << m1 << std::endl << std::flush;
+ }
+}
+
+void cmSystemTools::ReportLastSystemError(const char* msg)
+{
+ std::string m = msg;
+ m += ": System Error: ";
+ m += Superclass::GetLastSystemError();
+ cmSystemTools::Error(m.c_str());
+}
+
+bool cmSystemTools::IsInternallyOn(const char* val)
+{
+ if (!val) {
+ return false;
+ }
+ std::basic_string<char> v = val;
+ if (v.size() > 4) {
+ return false;
+ }
+
+ for (std::basic_string<char>::iterator c = v.begin(); c != v.end(); c++) {
+ *c = static_cast<char>(toupper(*c));
+ }
+ return v == "I_ON";
+}
+
+bool cmSystemTools::IsOn(const char* val)
+{
+ if (!val) {
+ return false;
+ }
+ size_t len = strlen(val);
+ if (len > 4) {
+ return false;
+ }
+ std::basic_string<char> v(val, len);
+
+ static std::set<std::string> onValues;
+ if (onValues.empty()) {
+ onValues.insert("ON");
+ onValues.insert("1");
+ onValues.insert("YES");
+ onValues.insert("TRUE");
+ onValues.insert("Y");
+ }
+ for (std::basic_string<char>::iterator c = v.begin(); c != v.end(); c++) {
+ *c = static_cast<char>(toupper(*c));
+ }
+ return (onValues.count(v) > 0);
+}
+
+bool cmSystemTools::IsNOTFOUND(const char* val)
+{
+ if (strcmp(val, "NOTFOUND") == 0) {
+ return true;
+ }
+ return cmHasLiteralSuffix(val, "-NOTFOUND");
+}
+
+bool cmSystemTools::IsOff(const char* val)
+{
+ if (!val || !*val) {
+ return true;
+ }
+ size_t len = strlen(val);
+ // Try and avoid toupper() for large strings.
+ if (len > 6) {
+ return cmSystemTools::IsNOTFOUND(val);
+ }
+
+ static std::set<std::string> offValues;
+ if (offValues.empty()) {
+ offValues.insert("OFF");
+ offValues.insert("0");
+ offValues.insert("NO");
+ offValues.insert("FALSE");
+ offValues.insert("N");
+ offValues.insert("IGNORE");
+ }
+ // Try and avoid toupper().
+ std::basic_string<char> v(val, len);
+ for (std::basic_string<char>::iterator c = v.begin(); c != v.end(); c++) {
+ *c = static_cast<char>(toupper(*c));
+ }
+ return (offValues.count(v) > 0);
+}
+
+void cmSystemTools::ParseWindowsCommandLine(const char* command,
+ std::vector<std::string>& args)
+{
+ // See the MSDN document "Parsing C Command-Line Arguments" at
+ // http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx for rules
+ // of parsing the windows command line.
+
+ bool in_argument = false;
+ bool in_quotes = false;
+ int backslashes = 0;
+ std::string arg;
+ for (const char* c = command; *c; ++c) {
+ if (*c == '\\') {
+ ++backslashes;
+ in_argument = true;
+ } else if (*c == '"') {
+ int backslash_pairs = backslashes >> 1;
+ int backslash_escaped = backslashes & 1;
+ arg.append(backslash_pairs, '\\');
+ backslashes = 0;
+ if (backslash_escaped) {
+ /* An odd number of backslashes precede this quote.
+ It is escaped. */
+ arg.append(1, '"');
+ } else {
+ /* An even number of backslashes precede this quote.
+ It is not escaped. */
+ in_quotes = !in_quotes;
+ }
+ in_argument = true;
+ } else {
+ arg.append(backslashes, '\\');
+ backslashes = 0;
+ if (cm_isspace(*c)) {
+ if (in_quotes) {
+ arg.append(1, *c);
+ } else if (in_argument) {
+ args.push_back(arg);
+ arg = "";
+ in_argument = false;
+ }
+ } else {
+ in_argument = true;
+ arg.append(1, *c);
+ }
+ }
+ }
+ arg.append(backslashes, '\\');
+ if (in_argument) {
+ args.push_back(arg);
+ }
+}
+
+class cmSystemToolsArgV
+{
+ char** ArgV;
+
+public:
+ cmSystemToolsArgV(char** argv)
+ : ArgV(argv)
+ {
+ }
+ ~cmSystemToolsArgV()
+ {
+ for (char** arg = this->ArgV; arg && *arg; ++arg) {
+ free(*arg);
+ }
+ free(this->ArgV);
+ }
+ void Store(std::vector<std::string>& args) const
+ {
+ for (char** arg = this->ArgV; arg && *arg; ++arg) {
+ args.push_back(*arg);
+ }
+ }
+};
+
+void cmSystemTools::ParseUnixCommandLine(const char* command,
+ std::vector<std::string>& args)
+{
+ // Invoke the underlying parser.
+ cmSystemToolsArgV argv = cmsysSystem_Parse_CommandForUnix(command, 0);
+ argv.Store(args);
+}
+
+std::vector<std::string> cmSystemTools::ParseArguments(const char* command)
+{
+ std::vector<std::string> args;
+ std::string arg;
+
+ bool win_path = false;
+
+ if ((command[0] != '/' && command[1] == ':' && command[2] == '\\') ||
+ (command[0] == '\"' && command[1] != '/' && command[2] == ':' &&
+ command[3] == '\\') ||
+ (command[0] == '\'' && command[1] != '/' && command[2] == ':' &&
+ command[3] == '\\') ||
+ (command[0] == '\\' && command[1] == '\\')) {
+ win_path = true;
+ }
+ // Split the command into an argv array.
+ for (const char* c = command; *c;) {
+ // Skip over whitespace.
+ while (*c == ' ' || *c == '\t') {
+ ++c;
+ }
+ arg = "";
+ if (*c == '"') {
+ // Parse a quoted argument.
+ ++c;
+ while (*c && *c != '"') {
+ arg.append(1, *c);
+ ++c;
+ }
+ if (*c) {
+ ++c;
+ }
+ args.push_back(arg);
+ } else if (*c == '\'') {
+ // Parse a quoted argument.
+ ++c;
+ while (*c && *c != '\'') {
+ arg.append(1, *c);
+ ++c;
+ }
+ if (*c) {
+ ++c;
+ }
+ args.push_back(arg);
+ } else if (*c) {
+ // Parse an unquoted argument.
+ while (*c && *c != ' ' && *c != '\t') {
+ if (*c == '\\' && !win_path) {
+ ++c;
+ if (*c) {
+ arg.append(1, *c);
+ ++c;
+ }
+ } else {
+ arg.append(1, *c);
+ ++c;
+ }
+ }
+ args.push_back(arg);
+ }
+ }
+
+ return args;
+}
+
+bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
+ std::string* captureStdOut,
+ std::string* captureStdErr, int* retVal,
+ const char* dir, OutputOption outputflag,
+ double timeout)
+{
+ std::vector<const char*> argv;
+ for (std::vector<std::string>::const_iterator a = command.begin();
+ a != command.end(); ++a) {
+ argv.push_back(a->c_str());
+ }
+ argv.push_back(CM_NULLPTR);
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ if (cmSystemTools::GetRunCommandHideConsole()) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ }
+
+ if (outputflag == OUTPUT_PASSTHROUGH) {
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
+ captureStdOut = CM_NULLPTR;
+ captureStdErr = CM_NULLPTR;
+ } else if (outputflag == OUTPUT_MERGE ||
+ (captureStdErr && captureStdErr == captureStdOut)) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1);
+ captureStdErr = CM_NULLPTR;
+ }
+ assert(!captureStdErr || captureStdErr != captureStdOut);
+
+ cmsysProcess_SetTimeout(cp, timeout);
+ cmsysProcess_Execute(cp);
+
+ std::vector<char> tempStdOut;
+ std::vector<char> tempStdErr;
+ char* data;
+ int length;
+ int pipe;
+ if (outputflag != OUTPUT_PASSTHROUGH &&
+ (captureStdOut || captureStdErr || outputflag != OUTPUT_NONE)) {
+ while ((pipe = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR)) >
+ 0) {
+ // Translate NULL characters in the output into valid text.
+ // Visual Studio 7 puts these characters in the output of its
+ // build process.
+ for (int i = 0; i < length; ++i) {
+ if (data[i] == '\0') {
+ data[i] = ' ';
+ }
+ }
+
+ if (pipe == cmsysProcess_Pipe_STDOUT) {
+ if (outputflag != OUTPUT_NONE) {
+ cmSystemTools::Stdout(data, length);
+ }
+ if (captureStdOut) {
+ tempStdOut.insert(tempStdOut.end(), data, data + length);
+ }
+ } else if (pipe == cmsysProcess_Pipe_STDERR) {
+ if (outputflag != OUTPUT_NONE) {
+ cmSystemTools::Stderr(data, length);
+ }
+ if (captureStdErr) {
+ tempStdErr.insert(tempStdErr.end(), data, data + length);
+ }
+ }
+ }
+ }
+
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+ if (captureStdOut) {
+ captureStdOut->assign(tempStdOut.begin(), tempStdOut.end());
+ }
+ if (captureStdErr) {
+ captureStdErr->assign(tempStdErr.begin(), tempStdErr.end());
+ }
+
+ bool result = true;
+ if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
+ if (retVal) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ } else {
+ if (cmsysProcess_GetExitValue(cp) != 0) {
+ result = false;
+ }
+ }
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) {
+ const char* exception_str = cmsysProcess_GetExceptionString(cp);
+ if (outputflag != OUTPUT_NONE) {
+ std::cerr << exception_str << std::endl;
+ }
+ if (captureStdErr) {
+ captureStdErr->append(exception_str, strlen(exception_str));
+ }
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
+ const char* error_str = cmsysProcess_GetErrorString(cp);
+ if (outputflag != OUTPUT_NONE) {
+ std::cerr << error_str << std::endl;
+ }
+ if (captureStdErr) {
+ captureStdErr->append(error_str, strlen(error_str));
+ }
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) {
+ const char* error_str = "Process terminated due to timeout\n";
+ if (outputflag != OUTPUT_NONE) {
+ std::cerr << error_str << std::endl;
+ }
+ if (captureStdErr) {
+ captureStdErr->append(error_str, strlen(error_str));
+ }
+ result = false;
+ }
+
+ cmsysProcess_Delete(cp);
+ return result;
+}
+
+bool cmSystemTools::RunSingleCommand(const char* command,
+ std::string* captureStdOut,
+ std::string* captureStdErr, int* retVal,
+ const char* dir, OutputOption outputflag,
+ double timeout)
+{
+ if (s_DisableRunCommandOutput) {
+ outputflag = OUTPUT_NONE;
+ }
+
+ std::vector<std::string> args = cmSystemTools::ParseArguments(command);
+
+ if (args.empty()) {
+ return false;
+ }
+ return cmSystemTools::RunSingleCommand(args, captureStdOut, captureStdErr,
+ retVal, dir, outputflag, timeout);
+}
+
+std::string cmSystemTools::PrintSingleCommand(
+ std::vector<std::string> const& command)
+{
+ if (command.empty()) {
+ return std::string();
+ }
+
+ return cmWrap('"', command, '"', " ");
+}
+
+bool cmSystemTools::DoesFileExistWithExtensions(
+ const char* name, const std::vector<std::string>& headerExts)
+{
+ std::string hname;
+
+ for (std::vector<std::string>::const_iterator ext = headerExts.begin();
+ ext != headerExts.end(); ++ext) {
+ hname = name;
+ hname += ".";
+ hname += *ext;
+ if (cmSystemTools::FileExists(hname.c_str())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::string cmSystemTools::FileExistsInParentDirectories(const char* fname,
+ const char* directory,
+ const char* toplevel)
+{
+ std::string file = fname;
+ cmSystemTools::ConvertToUnixSlashes(file);
+ std::string dir = directory;
+ cmSystemTools::ConvertToUnixSlashes(dir);
+ std::string prevDir;
+ while (dir != prevDir) {
+ std::string path = dir + "/" + file;
+ if (cmSystemTools::FileExists(path.c_str())) {
+ return path;
+ }
+ if (dir.size() < strlen(toplevel)) {
+ break;
+ }
+ prevDir = dir;
+ dir = cmSystemTools::GetParentDirectory(dir);
+ }
+ return "";
+}
+
+bool cmSystemTools::cmCopyFile(const char* source, const char* destination)
+{
+ return Superclass::CopyFileAlways(source, destination);
+}
+
+bool cmSystemTools::CopyFileIfDifferent(const char* source,
+ const char* destination)
+{
+ return Superclass::CopyFileIfDifferent(source, destination);
+}
+
+#ifdef _WIN32
+cmSystemTools::WindowsFileRetry cmSystemTools::GetWindowsFileRetry()
+{
+ static WindowsFileRetry retry = { 0, 0 };
+ if (!retry.Count) {
+ unsigned int data[2] = { 0, 0 };
+ HKEY const keys[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE };
+ wchar_t const* const values[2] = { L"FilesystemRetryCount",
+ L"FilesystemRetryDelay" };
+ for (int k = 0; k < 2; ++k) {
+ HKEY hKey;
+ if (RegOpenKeyExW(keys[k], L"Software\\Kitware\\CMake\\Config", 0,
+ KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
+ for (int v = 0; v < 2; ++v) {
+ DWORD dwData, dwType, dwSize = 4;
+ if (!data[v] &&
+ RegQueryValueExW(hKey, values[v], 0, &dwType, (BYTE*)&dwData,
+ &dwSize) == ERROR_SUCCESS &&
+ dwType == REG_DWORD && dwSize == 4) {
+ data[v] = static_cast<unsigned int>(dwData);
+ }
+ }
+ RegCloseKey(hKey);
+ }
+ }
+ retry.Count = data[0] ? data[0] : 5;
+ retry.Delay = data[1] ? data[1] : 500;
+ }
+ return retry;
+}
+#endif
+
+bool cmSystemTools::RenameFile(const char* oldname, const char* newname)
+{
+#ifdef _WIN32
+#ifndef INVALID_FILE_ATTRIBUTES
+#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+#endif
+ /* Windows MoveFileEx may not replace read-only or in-use files. If it
+ fails then remove the read-only attribute from any existing destination.
+ Try multiple times since we may be racing against another process
+ creating/opening the destination file just before our MoveFileEx. */
+ WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry();
+ while (
+ !MoveFileExW(SystemTools::ConvertToWindowsExtendedPath(oldname).c_str(),
+ SystemTools::ConvertToWindowsExtendedPath(newname).c_str(),
+ MOVEFILE_REPLACE_EXISTING) &&
+ --retry.Count) {
+ DWORD last_error = GetLastError();
+ // Try again only if failure was due to access/sharing permissions.
+ if (last_error != ERROR_ACCESS_DENIED &&
+ last_error != ERROR_SHARING_VIOLATION) {
+ return false;
+ }
+ DWORD attrs = GetFileAttributesW(
+ SystemTools::ConvertToWindowsExtendedPath(newname).c_str());
+ if ((attrs != INVALID_FILE_ATTRIBUTES) &&
+ (attrs & FILE_ATTRIBUTE_READONLY)) {
+ // Remove the read-only attribute from the destination file.
+ SetFileAttributesW(
+ SystemTools::ConvertToWindowsExtendedPath(newname).c_str(),
+ attrs & ~FILE_ATTRIBUTE_READONLY);
+ } else {
+ // The file may be temporarily in use so wait a bit.
+ cmSystemTools::Delay(retry.Delay);
+ }
+ }
+ return retry.Count > 0;
+#else
+ /* On UNIX we have an OS-provided call to do this atomically. */
+ return rename(oldname, newname) == 0;
+#endif
+}
+
+bool cmSystemTools::ComputeFileMD5(const std::string& source, char* md5out)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ cmCryptoHashMD5 md5;
+ std::string str = md5.HashFile(source);
+ strncpy(md5out, str.c_str(), 32);
+ return !str.empty();
+#else
+ (void)source;
+ (void)md5out;
+ cmSystemTools::Message("md5sum not supported in bootstrapping mode",
+ "Error");
+ return false;
+#endif
+}
+
+std::string cmSystemTools::ComputeStringMD5(const std::string& input)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ cmCryptoHashMD5 md5;
+ return md5.HashString(input);
+#else
+ (void)input;
+ cmSystemTools::Message("md5sum not supported in bootstrapping mode",
+ "Error");
+ return "";
+#endif
+}
+
+std::string cmSystemTools::ComputeCertificateThumbprint(
+ const std::string& source)
+{
+ std::string thumbprint;
+
+#if defined(CMAKE_BUILD_WITH_CMAKE) && defined(_WIN32)
+ BYTE* certData = NULL;
+ CRYPT_INTEGER_BLOB cryptBlob;
+ HCERTSTORE certStore = NULL;
+ PCCERT_CONTEXT certContext = NULL;
+
+ HANDLE certFile = CreateFileW(
+ cmsys::Encoding::ToWide(source.c_str()).c_str(), GENERIC_READ,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (certFile != INVALID_HANDLE_VALUE && certFile != NULL) {
+ DWORD fileSize = GetFileSize(certFile, NULL);
+ if (fileSize != INVALID_FILE_SIZE) {
+ certData = new BYTE[fileSize];
+ if (certData != NULL) {
+ DWORD dwRead = 0;
+ if (ReadFile(certFile, certData, fileSize, &dwRead, NULL)) {
+ cryptBlob.cbData = fileSize;
+ cryptBlob.pbData = certData;
+
+ // Verify that this is a valid cert
+ if (PFXIsPFXBlob(&cryptBlob)) {
+ // Open the certificate as a store
+ certStore = PFXImportCertStore(&cryptBlob, NULL, CRYPT_EXPORTABLE);
+ if (certStore != NULL) {
+ // There should only be 1 cert.
+ certContext =
+ CertEnumCertificatesInStore(certStore, certContext);
+ if (certContext != NULL) {
+ // The hash is 20 bytes
+ BYTE hashData[20];
+ DWORD hashLength = 20;
+
+ // Buffer to print the hash. Each byte takes 2 chars +
+ // terminating character
+ char hashPrint[41];
+ char* pHashPrint = hashPrint;
+ // Get the hash property from the certificate
+ if (CertGetCertificateContextProperty(
+ certContext, CERT_HASH_PROP_ID, hashData, &hashLength)) {
+ for (DWORD i = 0; i < hashLength; i++) {
+ // Convert each byte to hexadecimal
+ sprintf(pHashPrint, "%02X", hashData[i]);
+ pHashPrint += 2;
+ }
+ *pHashPrint = '\0';
+ thumbprint = hashPrint;
+ }
+ CertFreeCertificateContext(certContext);
+ }
+ CertCloseStore(certStore, 0);
+ }
+ }
+ }
+ delete[] certData;
+ }
+ }
+ CloseHandle(certFile);
+ }
+#else
+ (void)source;
+ cmSystemTools::Message("ComputeCertificateThumbprint is not implemented",
+ "Error");
+#endif
+
+ return thumbprint;
+}
+
+void cmSystemTools::Glob(const std::string& directory,
+ const std::string& regexp,
+ std::vector<std::string>& files)
+{
+ cmsys::Directory d;
+ cmsys::RegularExpression reg(regexp.c_str());
+
+ if (d.Load(directory)) {
+ size_t numf;
+ unsigned int i;
+ numf = d.GetNumberOfFiles();
+ for (i = 0; i < numf; i++) {
+ std::string fname = d.GetFile(i);
+ if (reg.find(fname)) {
+ files.push_back(fname);
+ }
+ }
+ }
+}
+
+void cmSystemTools::GlobDirs(const std::string& path,
+ std::vector<std::string>& files)
+{
+ std::string::size_type pos = path.find("/*");
+ if (pos == std::string::npos) {
+ files.push_back(path);
+ return;
+ }
+ std::string startPath = path.substr(0, pos);
+ std::string finishPath = path.substr(pos + 2);
+
+ cmsys::Directory d;
+ if (d.Load(startPath)) {
+ for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i) {
+ if ((std::string(d.GetFile(i)) != ".") &&
+ (std::string(d.GetFile(i)) != "..")) {
+ std::string fname = startPath;
+ fname += "/";
+ fname += d.GetFile(i);
+ if (cmSystemTools::FileIsDirectory(fname)) {
+ fname += finishPath;
+ cmSystemTools::GlobDirs(fname, files);
+ }
+ }
+ }
+ }
+}
+
+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,
+ bool emptyArgs)
+{
+ // If argument is empty, it is an empty list.
+ if (!emptyArgs && arg.empty()) {
+ return;
+ }
+ // if there are no ; in the name then just copy the current string
+ if (arg.find(';') == std::string::npos) {
+ newargs.push_back(arg);
+ return;
+ }
+ std::string newArg;
+ const char* last = arg.c_str();
+ // Break the string at non-escaped semicolons not nested in [].
+ int squareNesting = 0;
+ for (const char* c = last; *c; ++c) {
+ switch (*c) {
+ case '\\': {
+ // We only want to allow escaping of semicolons. Other
+ // escapes should not be processed here.
+ const char* next = c + 1;
+ if (*next == ';') {
+ newArg.append(last, c - last);
+ // Skip over the escape character
+ last = c = next;
+ }
+ } break;
+ case '[': {
+ ++squareNesting;
+ } break;
+ case ']': {
+ --squareNesting;
+ } break;
+ case ';': {
+ // Break the string here if we are not nested inside square
+ // brackets.
+ if (squareNesting == 0) {
+ newArg.append(last, c - last);
+ // Skip over the semicolon
+ last = c + 1;
+ if (!newArg.empty() || emptyArgs) {
+ // Add the last argument if the string is not empty.
+ newargs.push_back(newArg);
+ newArg = "";
+ }
+ }
+ } break;
+ default: {
+ // Just append this character.
+ } break;
+ }
+ }
+ newArg.append(last);
+ if (!newArg.empty() || emptyArgs) {
+ // Add the last argument if the string is not empty.
+ newargs.push_back(newArg);
+ }
+}
+
+bool cmSystemTools::SimpleGlob(const std::string& glob,
+ std::vector<std::string>& files,
+ int type /* = 0 */)
+{
+ files.clear();
+ if (glob[glob.size() - 1] != '*') {
+ return false;
+ }
+ std::string path = cmSystemTools::GetFilenamePath(glob);
+ std::string ppath = cmSystemTools::GetFilenameName(glob);
+ ppath = ppath.substr(0, ppath.size() - 1);
+ if (path.empty()) {
+ path = "/";
+ }
+
+ bool res = false;
+ cmsys::Directory d;
+ if (d.Load(path)) {
+ for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i) {
+ if ((std::string(d.GetFile(i)) != ".") &&
+ (std::string(d.GetFile(i)) != "..")) {
+ std::string fname = path;
+ if (path[path.size() - 1] != '/') {
+ fname += "/";
+ }
+ fname += d.GetFile(i);
+ std::string sfname = d.GetFile(i);
+ if (type > 0 && cmSystemTools::FileIsDirectory(fname)) {
+ continue;
+ }
+ if (type < 0 && !cmSystemTools::FileIsDirectory(fname)) {
+ continue;
+ }
+ if (sfname.size() >= ppath.size() &&
+ sfname.substr(0, ppath.size()) == ppath) {
+ files.push_back(fname);
+ res = true;
+ }
+ }
+ }
+ }
+ return res;
+}
+
+cmSystemTools::FileFormat cmSystemTools::GetFileFormat(const char* cext)
+{
+ if (!cext || *cext == 0) {
+ return cmSystemTools::NO_FILE_FORMAT;
+ }
+ // std::string ext = cmSystemTools::LowerCase(cext);
+ std::string ext = cext;
+ if (ext == "c" || ext == ".c" || ext == "m" || ext == ".m") {
+ return cmSystemTools::C_FILE_FORMAT;
+ }
+ if (ext == "C" || ext == ".C" || ext == "M" || ext == ".M" || ext == "c++" ||
+ ext == ".c++" || ext == "cc" || ext == ".cc" || ext == "cpp" ||
+ ext == ".cpp" || ext == "cxx" || ext == ".cxx" || ext == "mm" ||
+ ext == ".mm") {
+ return cmSystemTools::CXX_FILE_FORMAT;
+ }
+ if (ext == "f" || ext == ".f" || ext == "F" || ext == ".F" || ext == "f77" ||
+ ext == ".f77" || ext == "f90" || ext == ".f90" || ext == "for" ||
+ ext == ".for" || ext == "f95" || ext == ".f95") {
+ return cmSystemTools::FORTRAN_FILE_FORMAT;
+ }
+ if (ext == "java" || ext == ".java") {
+ return cmSystemTools::JAVA_FILE_FORMAT;
+ }
+ if (ext == "H" || ext == ".H" || ext == "h" || ext == ".h" || ext == "h++" ||
+ ext == ".h++" || ext == "hm" || ext == ".hm" || ext == "hpp" ||
+ ext == ".hpp" || ext == "hxx" || ext == ".hxx" || ext == "in" ||
+ ext == ".in" || ext == "txx" || ext == ".txx") {
+ return cmSystemTools::HEADER_FILE_FORMAT;
+ }
+ if (ext == "rc" || ext == ".rc") {
+ return cmSystemTools::RESOURCE_FILE_FORMAT;
+ }
+ if (ext == "def" || ext == ".def") {
+ return cmSystemTools::DEFINITION_FILE_FORMAT;
+ }
+ if (ext == "lib" || ext == ".lib" || ext == "a" || ext == ".a") {
+ return cmSystemTools::STATIC_LIBRARY_FILE_FORMAT;
+ }
+ if (ext == "o" || ext == ".o" || ext == "obj" || ext == ".obj") {
+ return cmSystemTools::OBJECT_FILE_FORMAT;
+ }
+#ifdef __APPLE__
+ if (ext == "dylib" || ext == ".dylib") {
+ return cmSystemTools::SHARED_LIBRARY_FILE_FORMAT;
+ }
+ if (ext == "so" || ext == ".so" || ext == "bundle" || ext == ".bundle") {
+ return cmSystemTools::MODULE_FILE_FORMAT;
+ }
+#else // __APPLE__
+ if (ext == "so" || ext == ".so" || ext == "sl" || ext == ".sl" ||
+ ext == "dll" || ext == ".dll") {
+ return cmSystemTools::SHARED_LIBRARY_FILE_FORMAT;
+ }
+#endif // __APPLE__
+ 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(const char* path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (s_ForceUnixPaths) {
+ return cmSystemTools::ConvertToUnixOutputPath(path);
+ }
+ return cmSystemTools::ConvertToWindowsOutputPath(path);
+#else
+ return cmSystemTools::ConvertToUnixOutputPath(path);
+#endif
+}
+
+void cmSystemTools::ConvertToOutputSlashes(std::string& path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (!s_ForceUnixPaths) {
+ // Convert to windows slashes.
+ std::string::size_type pos = 0;
+ while ((pos = path.find('/', pos)) != std::string::npos) {
+ path[pos++] = '\\';
+ }
+ }
+#else
+ static_cast<void>(path);
+#endif
+}
+
+std::string cmSystemTools::ConvertToRunCommandPath(const char* path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ return cmSystemTools::ConvertToWindowsOutputPath(path);
+#else
+ return cmSystemTools::ConvertToUnixOutputPath(path);
+#endif
+}
+
+// compute the relative path from here to there
+std::string cmSystemTools::RelativePath(const char* local, const char* remote)
+{
+ if (!cmSystemTools::FileIsFullPath(local)) {
+ 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);
+ }
+ return cmsys::SystemTools::RelativePath(local, remote);
+}
+
+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] != "") {
+ // 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)
+{
+#if !defined(HAVE_UNSETENV)
+ std::string var = value;
+ var += "=";
+ return cmSystemTools::PutEnv(var.c_str());
+#else
+ unsetenv(value);
+ return true;
+#endif
+}
+
+std::vector<std::string> cmSystemTools::GetEnvironmentVariables()
+{
+ std::vector<std::string> env;
+ int cc;
+ for (cc = 0; environ[cc]; ++cc) {
+ env.push_back(environ[cc]);
+ }
+ return env;
+}
+
+void cmSystemTools::AppendEnv(std::vector<std::string> const& env)
+{
+ for (std::vector<std::string>::const_iterator eit = env.begin();
+ eit != env.end(); ++eit) {
+ cmSystemTools::PutEnv(*eit);
+ }
+}
+
+cmSystemTools::SaveRestoreEnvironment::SaveRestoreEnvironment()
+{
+ this->Env = cmSystemTools::GetEnvironmentVariables();
+}
+
+cmSystemTools::SaveRestoreEnvironment::~SaveRestoreEnvironment()
+{
+ // First clear everything in the current environment:
+ std::vector<std::string> currentEnv = GetEnvironmentVariables();
+ for (std::vector<std::string>::const_iterator eit = currentEnv.begin();
+ eit != currentEnv.end(); ++eit) {
+ std::string var(*eit);
+
+ std::string::size_type pos = var.find('=');
+ if (pos != std::string::npos) {
+ var = var.substr(0, pos);
+ }
+
+ cmSystemTools::UnsetEnv(var.c_str());
+ }
+
+ // Then put back each entry from the original environment:
+ cmSystemTools::AppendEnv(this->Env);
+}
+#endif
+
+void cmSystemTools::EnableVSConsoleOutput()
+{
+#ifdef _WIN32
+ // Visual Studio 8 2005 (devenv.exe or VCExpress.exe) will not
+ // display output to the console unless this environment variable is
+ // set. We need it to capture the output of these build tools.
+ // Note for future work that one could pass "/out \\.\pipe\NAME" to
+ // either of these executables where NAME is created with
+ // CreateNamedPipe. This would bypass the internal buffering of the
+ // output and allow it to be captured on the fly.
+ cmSystemTools::PutEnv("vsconsoleoutput=1");
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ // VS sets an environment variable to tell MS tools like "cl" to report
+ // output through a backdoor pipe instead of stdout/stderr. Unset the
+ // environment variable to close this backdoor for any path of process
+ // invocations that passes through CMake so we can capture the output.
+ cmSystemTools::UnsetEnv("VS_UNICODE_OUTPUT");
+#endif
+#endif
+}
+
+bool cmSystemTools::IsPathToFramework(const char* path)
+{
+ return (cmSystemTools::FileIsFullPath(path) &&
+ cmHasLiteralSuffix(path, ".framework"));
+}
+
+bool cmSystemTools::CreateTar(const char* outFileName,
+ const std::vector<std::string>& files,
+ cmTarCompression compressType, bool verbose,
+ std::string const& mtime,
+ std::string const& format)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ cmsys::ofstream fout(outFileName, std::ios::out | std::ios::binary);
+ if (!fout) {
+ std::string e = "Cannot open output file \"";
+ e += outFileName;
+ e += "\": ";
+ e += cmSystemTools::GetLastSystemError();
+ cmSystemTools::Error(e.c_str());
+ return false;
+ }
+ cmArchiveWrite::Compress compress = cmArchiveWrite::CompressNone;
+ switch (compressType) {
+ case TarCompressGZip:
+ compress = cmArchiveWrite::CompressGZip;
+ break;
+ case TarCompressBZip2:
+ compress = cmArchiveWrite::CompressBZip2;
+ break;
+ case TarCompressXZ:
+ compress = cmArchiveWrite::CompressXZ;
+ break;
+ case TarCompressNone:
+ compress = cmArchiveWrite::CompressNone;
+ break;
+ }
+
+ cmArchiveWrite a(fout, compress, format.empty() ? "paxr" : format);
+
+ a.SetMTime(mtime);
+ a.SetVerbose(verbose);
+ for (std::vector<std::string>::const_iterator i = files.begin();
+ i != files.end(); ++i) {
+ std::string path = *i;
+ if (cmSystemTools::FileIsFullPath(path.c_str())) {
+ // Get the relative path to the file.
+ path = cmSystemTools::RelativePath(cwd.c_str(), path.c_str());
+ }
+ if (!a.Add(path)) {
+ break;
+ }
+ }
+ if (!a) {
+ cmSystemTools::Error(a.GetError().c_str());
+ return false;
+ }
+ return true;
+#else
+ (void)outFileName;
+ (void)files;
+ (void)verbose;
+ return false;
+#endif
+}
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+namespace {
+#define BSDTAR_FILESIZE_PRINTF "%lu"
+#define BSDTAR_FILESIZE_TYPE unsigned long
+void list_item_verbose(FILE* out, struct archive_entry* entry)
+{
+ char tmp[100];
+ size_t w;
+ const char* p;
+ const char* fmt;
+ time_t tim;
+ static time_t now;
+ size_t u_width = 6;
+ size_t gs_width = 13;
+
+ /*
+ * We avoid collecting the entire list in memory at once by
+ * listing things as we see them. However, that also means we can't
+ * just pre-compute the field widths. Instead, we start with guesses
+ * and just widen them as necessary. These numbers are completely
+ * arbitrary.
+ */
+ if (!now) {
+ time(&now);
+ }
+ fprintf(out, "%s %d ", archive_entry_strmode(entry),
+ archive_entry_nlink(entry));
+
+ /* Use uname if it's present, else uid. */
+ p = archive_entry_uname(entry);
+ if ((p == CM_NULLPTR) || (*p == '\0')) {
+ sprintf(tmp, "%lu ", (unsigned long)archive_entry_uid(entry));
+ p = tmp;
+ }
+ w = strlen(p);
+ if (w > u_width) {
+ u_width = w;
+ }
+ fprintf(out, "%-*s ", (int)u_width, p);
+ /* Use gname if it's present, else gid. */
+ p = archive_entry_gname(entry);
+ if (p != CM_NULLPTR && p[0] != '\0') {
+ fprintf(out, "%s", p);
+ w = strlen(p);
+ } else {
+ sprintf(tmp, "%lu", (unsigned long)archive_entry_gid(entry));
+ w = strlen(tmp);
+ fprintf(out, "%s", tmp);
+ }
+
+ /*
+ * Print device number or file size, right-aligned so as to make
+ * total width of group and devnum/filesize fields be gs_width.
+ * If gs_width is too small, grow it.
+ */
+ if (archive_entry_filetype(entry) == AE_IFCHR ||
+ archive_entry_filetype(entry) == AE_IFBLK) {
+ sprintf(tmp, "%lu,%lu", (unsigned long)archive_entry_rdevmajor(entry),
+ (unsigned long)archive_entry_rdevminor(entry));
+ } else {
+ /*
+ * Note the use of platform-dependent macros to format
+ * the filesize here. We need the format string and the
+ * corresponding type for the cast.
+ */
+ sprintf(tmp, BSDTAR_FILESIZE_PRINTF,
+ (BSDTAR_FILESIZE_TYPE)archive_entry_size(entry));
+ }
+ if (w + strlen(tmp) >= gs_width) {
+ gs_width = w + strlen(tmp) + 1;
+ }
+ fprintf(out, "%*s", (int)(gs_width - w), tmp);
+
+ /* Format the time using 'ls -l' conventions. */
+ tim = archive_entry_mtime(entry);
+#define HALF_YEAR (time_t)365 * 86400 / 2
+#if defined(_WIN32) && !defined(__CYGWIN__)
+/* Windows' strftime function does not support %e format. */
+#define DAY_FMT "%d"
+#else
+#define DAY_FMT "%e" /* Day number without leading zeros */
+#endif
+ if (tim < now - HALF_YEAR || tim > now + HALF_YEAR) {
+ fmt = DAY_FMT " %b %Y";
+ } else {
+ fmt = DAY_FMT " %b %H:%M";
+ }
+ strftime(tmp, sizeof(tmp), fmt, localtime(&tim));
+ fprintf(out, " %s ", tmp);
+ fprintf(out, "%s", cm_archive_entry_pathname(entry).c_str());
+
+ /* Extra information for links. */
+ if (archive_entry_hardlink(entry)) /* Hard link */
+ {
+ fprintf(out, " link to %s", archive_entry_hardlink(entry));
+ } else if (archive_entry_symlink(entry)) /* Symbolic link */
+ {
+ fprintf(out, " -> %s", archive_entry_symlink(entry));
+ }
+}
+
+long copy_data(struct archive* ar, struct archive* aw)
+{
+ long r;
+ const void* buff;
+ size_t size;
+#if defined(ARCHIVE_VERSION_NUMBER) && ARCHIVE_VERSION_NUMBER >= 3000000
+ __LA_INT64_T offset;
+#else
+ off_t offset;
+#endif
+
+ for (;;) {
+ r = archive_read_data_block(ar, &buff, &size, &offset);
+ if (r == ARCHIVE_EOF) {
+ return (ARCHIVE_OK);
+ }
+ if (r != ARCHIVE_OK) {
+ return (r);
+ }
+ r = archive_write_data_block(aw, buff, size, offset);
+ if (r != ARCHIVE_OK) {
+ cmSystemTools::Message("archive_write_data_block()",
+ archive_error_string(aw));
+ return (r);
+ }
+ }
+#if !defined(__clang__) && !defined(__HP_aCC)
+ return r; /* this should not happen but it quiets some compilers */
+#endif
+}
+
+bool extract_tar(const char* outFileName, bool verbose, bool extract)
+{
+ cmLocaleRAII localeRAII;
+ static_cast<void>(localeRAII);
+ struct archive* a = archive_read_new();
+ struct archive* ext = archive_write_disk_new();
+ 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);
+ if (r) {
+ cmSystemTools::Error("Problem with archive_read_open_file(): ",
+ archive_error_string(a));
+ archive_write_free(ext);
+ archive_read_close(a);
+ return false;
+ }
+ for (;;) {
+ r = archive_read_next_header(a, &entry);
+ if (r == ARCHIVE_EOF) {
+ break;
+ }
+ if (r != ARCHIVE_OK) {
+ cmSystemTools::Error("Problem with archive_read_next_header(): ",
+ archive_error_string(a));
+ break;
+ }
+ if (verbose) {
+ if (extract) {
+ cmSystemTools::Stdout("x ");
+ cmSystemTools::Stdout(cm_archive_entry_pathname(entry).c_str());
+ } else {
+ list_item_verbose(stdout, entry);
+ }
+ cmSystemTools::Stdout("\n");
+ } else if (!extract) {
+ cmSystemTools::Stdout(cm_archive_entry_pathname(entry).c_str());
+ cmSystemTools::Stdout("\n");
+ }
+ 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));
+ break;
+ }
+
+ r = archive_write_header(ext, entry);
+ if (r == ARCHIVE_OK) {
+ copy_data(a, ext);
+ r = archive_write_finish_entry(ext);
+ if (r != ARCHIVE_OK) {
+ cmSystemTools::Error("Problem with archive_write_finish_entry(): ",
+ archive_error_string(ext));
+ break;
+ }
+ }
+#ifdef _WIN32
+ else if (const char* linktext = archive_entry_symlink(entry)) {
+ std::cerr << "cmake -E tar: warning: skipping symbolic link \""
+ << cm_archive_entry_pathname(entry) << "\" -> \"" << linktext
+ << "\"." << std::endl;
+ }
+#endif
+ else {
+ cmSystemTools::Error("Problem with archive_write_header(): ",
+ archive_error_string(ext));
+ cmSystemTools::Error("Current file: ",
+ cm_archive_entry_pathname(entry).c_str());
+ break;
+ }
+ }
+ }
+ archive_write_free(ext);
+ archive_read_close(a);
+ archive_read_free(a);
+ return r == ARCHIVE_EOF || r == ARCHIVE_OK;
+}
+}
+#endif
+
+bool cmSystemTools::ExtractTar(const char* outFileName, bool verbose)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ return extract_tar(outFileName, verbose, true);
+#else
+ (void)outFileName;
+ (void)verbose;
+ return false;
+#endif
+}
+
+bool cmSystemTools::ListTar(const char* outFileName, bool verbose)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ return extract_tar(outFileName, verbose, false);
+#else
+ (void)outFileName;
+ (void)verbose;
+ return false;
+#endif
+}
+
+int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
+ double timeout, std::vector<char>& out,
+ std::vector<char>& err)
+{
+ line = "";
+ std::vector<char>::iterator outiter = out.begin();
+ std::vector<char>::iterator erriter = err.begin();
+ while (1) {
+ // Check for a newline in stdout.
+ for (; outiter != out.end(); ++outiter) {
+ if ((*outiter == '\r') && ((outiter + 1) == out.end())) {
+ break;
+ } else if (*outiter == '\n' || *outiter == '\0') {
+ std::vector<char>::size_type length = outiter - out.begin();
+ if (length > 1 && *(outiter - 1) == '\r') {
+ --length;
+ }
+ if (length > 0) {
+ line.append(&out[0], length);
+ }
+ out.erase(out.begin(), outiter + 1);
+ return cmsysProcess_Pipe_STDOUT;
+ }
+ }
+
+ // Check for a newline in stderr.
+ for (; erriter != err.end(); ++erriter) {
+ if ((*erriter == '\r') && ((erriter + 1) == err.end())) {
+ break;
+ } else if (*erriter == '\n' || *erriter == '\0') {
+ std::vector<char>::size_type length = erriter - err.begin();
+ if (length > 1 && *(erriter - 1) == '\r') {
+ --length;
+ }
+ if (length > 0) {
+ line.append(&err[0], length);
+ }
+ err.erase(err.begin(), erriter + 1);
+ return cmsysProcess_Pipe_STDERR;
+ }
+ }
+
+ // No newlines found. Wait for more data from the process.
+ int length;
+ char* data;
+ int pipe = cmsysProcess_WaitForData(process, &data, &length, &timeout);
+ if (pipe == cmsysProcess_Pipe_Timeout) {
+ // Timeout has been exceeded.
+ return pipe;
+ } else if (pipe == cmsysProcess_Pipe_STDOUT) {
+ // Append to the stdout buffer.
+ std::vector<char>::size_type size = out.size();
+ out.insert(out.end(), data, data + length);
+ outiter = out.begin() + size;
+ } else if (pipe == cmsysProcess_Pipe_STDERR) {
+ // Append to the stderr buffer.
+ std::vector<char>::size_type size = err.size();
+ err.insert(err.end(), data, data + length);
+ erriter = err.begin() + size;
+ } else if (pipe == cmsysProcess_Pipe_None) {
+ // Both stdout and stderr pipes have broken. Return leftover data.
+ if (!out.empty()) {
+ line.append(&out[0], outiter - out.begin());
+ out.erase(out.begin(), out.end());
+ return cmsysProcess_Pipe_STDOUT;
+ } else if (!err.empty()) {
+ line.append(&err[0], erriter - err.begin());
+ err.erase(err.begin(), err.end());
+ return cmsysProcess_Pipe_STDERR;
+ } else {
+ return cmsysProcess_Pipe_None;
+ }
+ }
+ }
+}
+
+void cmSystemTools::DoNotInheritStdPipes()
+{
+#ifdef _WIN32
+ // Check to see if we are attached to a console
+ // if so, then do not stop the inherited pipes
+ // or stdout and stderr will not show up in dos
+ // shell windows
+ CONSOLE_SCREEN_BUFFER_INFO hOutInfo;
+ HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (GetConsoleScreenBufferInfo(hOut, &hOutInfo)) {
+ return;
+ }
+ {
+ HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
+ DuplicateHandle(GetCurrentProcess(), out, GetCurrentProcess(), &out, 0,
+ FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
+ SetStdHandle(STD_OUTPUT_HANDLE, out);
+ }
+ {
+ HANDLE out = GetStdHandle(STD_ERROR_HANDLE);
+ DuplicateHandle(GetCurrentProcess(), out, GetCurrentProcess(), &out, 0,
+ FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
+ SetStdHandle(STD_ERROR_HANDLE, out);
+ }
+#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;
+ }
+ if (!SetFileTime(hTo, &timeCreation, &timeLastAccess, &timeLastWrite)) {
+ return false;
+ }
+#else
+ struct stat fromStat;
+ if (stat(fromFile, &fromStat) < 0) {
+ return false;
+ }
+
+ struct utimbuf buf;
+ buf.actime = fromStat.st_atime;
+ buf.modtime = fromStat.st_mtime;
+ if (utime(toFile, &buf) < 0) {
+ return false;
+ }
+#endif
+ return true;
+}
+
+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;
+ }
+ if (!SetFileTime(h, &t->timeCreation, &t->timeLastAccess,
+ &t->timeLastWrite)) {
+ return false;
+ }
+#else
+ if (utime(fname, &t->timeBuf) < 0) {
+ return false;
+ }
+#endif
+ return true;
+}
+
+#ifdef _WIN32
+#ifndef CRYPT_SILENT
+#define CRYPT_SILENT 0x40 /* Not defined by VS 6 version of header. */
+#endif
+static int WinCryptRandom(void* data, size_t size)
+{
+ int result = 0;
+ HCRYPTPROV hProvider = 0;
+ if (CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
+ result = CryptGenRandom(hProvider, (DWORD)size, (BYTE*)data) ? 1 : 0;
+ CryptReleaseContext(hProvider, 0);
+ }
+ return result;
+}
+#endif
+
+unsigned int cmSystemTools::RandomSeed()
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ unsigned int seed = 0;
+
+ // Try using a real random source.
+ if (WinCryptRandom(&seed, sizeof(seed))) {
+ return seed;
+ }
+
+ // Fall back to the time and pid.
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+ unsigned int t1 = static_cast<unsigned int>(ft.dwHighDateTime);
+ unsigned int t2 = static_cast<unsigned int>(ft.dwLowDateTime);
+ unsigned int pid = static_cast<unsigned int>(GetCurrentProcessId());
+ return t1 ^ t2 ^ pid;
+#else
+ union
+ {
+ unsigned int integer;
+ char bytes[sizeof(unsigned int)];
+ } seed;
+
+ // Try using a real random source.
+ cmsys::ifstream fin;
+ fin.rdbuf()->pubsetbuf(CM_NULLPTR, 0); // Unbuffered read.
+ fin.open("/dev/urandom");
+ if (fin.good() && fin.read(seed.bytes, sizeof(seed)) &&
+ fin.gcount() == sizeof(seed)) {
+ return seed.integer;
+ }
+
+ // Fall back to the time and pid.
+ struct timeval t;
+ gettimeofday(&t, CM_NULLPTR);
+ unsigned int pid = static_cast<unsigned int>(getpid());
+ unsigned int tv_sec = static_cast<unsigned int>(t.tv_sec);
+ unsigned int tv_usec = static_cast<unsigned int>(t.tv_usec);
+ // Since tv_usec never fills more than 11 bits we shift it to fill
+ // in the slow-changing high-order bits of tv_sec.
+ return tv_sec ^ (tv_usec << 21) ^ pid;
+#endif
+}
+
+static std::string cmSystemToolsCMakeCommand;
+static std::string cmSystemToolsCTestCommand;
+static std::string cmSystemToolsCPackCommand;
+static std::string cmSystemToolsCMakeCursesCommand;
+static std::string cmSystemToolsCMakeGUICommand;
+static std::string cmSystemToolsCMClDepsCommand;
+static std::string cmSystemToolsCMakeRoot;
+void cmSystemTools::FindCMakeResources(const char* argv0)
+{
+ std::string exe_dir;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ (void)argv0; // ignore this on windows
+ wchar_t modulepath[_MAX_PATH];
+ ::GetModuleFileNameW(NULL, modulepath, sizeof(modulepath));
+ exe_dir =
+ cmSystemTools::GetFilenamePath(cmsys::Encoding::ToNarrow(modulepath));
+#elif defined(__APPLE__)
+ (void)argv0; // ignore this on OS X
+#define CM_EXE_PATH_LOCAL_SIZE 16384
+ char exe_path_local[CM_EXE_PATH_LOCAL_SIZE];
+#if defined(MAC_OS_X_VERSION_10_3) && !defined(MAC_OS_X_VERSION_10_4)
+ unsigned long exe_path_size = CM_EXE_PATH_LOCAL_SIZE;
+#else
+ uint32_t exe_path_size = CM_EXE_PATH_LOCAL_SIZE;
+#endif
+#undef CM_EXE_PATH_LOCAL_SIZE
+ char* exe_path = exe_path_local;
+ if (_NSGetExecutablePath(exe_path, &exe_path_size) < 0) {
+ exe_path = (char*)malloc(exe_path_size);
+ _NSGetExecutablePath(exe_path, &exe_path_size);
+ }
+ exe_dir =
+ cmSystemTools::GetFilenamePath(cmSystemTools::GetRealPath(exe_path));
+ if (exe_path != exe_path_local) {
+ free(exe_path);
+ }
+ if (cmSystemTools::GetFilenameName(exe_dir) == "MacOS") {
+ // The executable is inside an application bundle.
+ // Look for ..<CMAKE_BIN_DIR> (install tree) and then fall back to
+ // ../../../bin (build tree).
+ exe_dir = cmSystemTools::GetFilenamePath(exe_dir);
+ if (cmSystemTools::FileExists(exe_dir + CMAKE_BIN_DIR "/cmake")) {
+ exe_dir += CMAKE_BIN_DIR;
+ } else {
+ exe_dir = cmSystemTools::GetFilenamePath(exe_dir);
+ exe_dir = cmSystemTools::GetFilenamePath(exe_dir);
+ }
+ }
+#else
+ std::string errorMsg;
+ std::string exe;
+ if (cmSystemTools::FindProgramPath(argv0, exe, errorMsg)) {
+ // remove symlinks
+ exe = cmSystemTools::GetRealPath(exe);
+ exe_dir = cmSystemTools::GetFilenamePath(exe);
+ } else {
+ // ???
+ }
+#endif
+ cmSystemToolsCMakeCommand = exe_dir;
+ cmSystemToolsCMakeCommand += "/cmake";
+ cmSystemToolsCMakeCommand += cmSystemTools::GetExecutableExtension();
+#ifndef CMAKE_BUILD_WITH_CMAKE
+ // The bootstrap cmake does not provide the other tools,
+ // so use the directory where they are about to be built.
+ exe_dir = CMAKE_BOOTSTRAP_BINARY_DIR "/bin";
+#endif
+ cmSystemToolsCTestCommand = exe_dir;
+ cmSystemToolsCTestCommand += "/ctest";
+ cmSystemToolsCTestCommand += cmSystemTools::GetExecutableExtension();
+ cmSystemToolsCPackCommand = exe_dir;
+ cmSystemToolsCPackCommand += "/cpack";
+ cmSystemToolsCPackCommand += cmSystemTools::GetExecutableExtension();
+ cmSystemToolsCMakeGUICommand = exe_dir;
+ cmSystemToolsCMakeGUICommand += "/cmake-gui";
+ cmSystemToolsCMakeGUICommand += cmSystemTools::GetExecutableExtension();
+ if (!cmSystemTools::FileExists(cmSystemToolsCMakeGUICommand.c_str())) {
+ cmSystemToolsCMakeGUICommand = "";
+ }
+ cmSystemToolsCMakeCursesCommand = exe_dir;
+ cmSystemToolsCMakeCursesCommand += "/ccmake";
+ cmSystemToolsCMakeCursesCommand += cmSystemTools::GetExecutableExtension();
+ if (!cmSystemTools::FileExists(cmSystemToolsCMakeCursesCommand.c_str())) {
+ cmSystemToolsCMakeCursesCommand = "";
+ }
+ cmSystemToolsCMClDepsCommand = exe_dir;
+ cmSystemToolsCMClDepsCommand += "/cmcldeps";
+ cmSystemToolsCMClDepsCommand += cmSystemTools::GetExecutableExtension();
+ if (!cmSystemTools::FileExists(cmSystemToolsCMClDepsCommand.c_str())) {
+ cmSystemToolsCMClDepsCommand = "";
+ }
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ // Install tree has
+ // - "<prefix><CMAKE_BIN_DIR>/cmake"
+ // - "<prefix><CMAKE_DATA_DIR>"
+ if (cmHasSuffix(exe_dir, CMAKE_BIN_DIR)) {
+ std::string const prefix =
+ exe_dir.substr(0, exe_dir.size() - strlen(CMAKE_BIN_DIR));
+ cmSystemToolsCMakeRoot = prefix + CMAKE_DATA_DIR;
+ }
+ if (cmSystemToolsCMakeRoot.empty() ||
+ !cmSystemTools::FileExists(
+ (cmSystemToolsCMakeRoot + "/Modules/CMake.cmake").c_str())) {
+ // Build tree has "<build>/bin[/<config>]/cmake" and
+ // "<build>/CMakeFiles/CMakeSourceDir.txt".
+ std::string dir = cmSystemTools::GetFilenamePath(exe_dir);
+ std::string src_dir_txt = dir + "/CMakeFiles/CMakeSourceDir.txt";
+ cmsys::ifstream fin(src_dir_txt.c_str());
+ std::string src_dir;
+ if (fin && cmSystemTools::GetLineFromStream(fin, src_dir) &&
+ cmSystemTools::FileIsDirectory(src_dir)) {
+ cmSystemToolsCMakeRoot = src_dir;
+ } else {
+ dir = cmSystemTools::GetFilenamePath(dir);
+ src_dir_txt = dir + "/CMakeFiles/CMakeSourceDir.txt";
+ cmsys::ifstream fin2(src_dir_txt.c_str());
+ if (fin2 && cmSystemTools::GetLineFromStream(fin2, src_dir) &&
+ cmSystemTools::FileIsDirectory(src_dir)) {
+ cmSystemToolsCMakeRoot = src_dir;
+ }
+ }
+ }
+#else
+ // Bootstrap build knows its source.
+ cmSystemToolsCMakeRoot = CMAKE_BOOTSTRAP_SOURCE_DIR;
+#endif
+}
+
+std::string const& cmSystemTools::GetCMakeCommand()
+{
+ return cmSystemToolsCMakeCommand;
+}
+
+std::string const& cmSystemTools::GetCTestCommand()
+{
+ return cmSystemToolsCTestCommand;
+}
+
+std::string const& cmSystemTools::GetCPackCommand()
+{
+ return cmSystemToolsCPackCommand;
+}
+
+std::string const& cmSystemTools::GetCMakeCursesCommand()
+{
+ return cmSystemToolsCMakeCursesCommand;
+}
+
+std::string const& cmSystemTools::GetCMakeGUICommand()
+{
+ return cmSystemToolsCMakeGUICommand;
+}
+
+std::string const& cmSystemTools::GetCMClDepsCommand()
+{
+ return cmSystemToolsCMClDepsCommand;
+}
+
+std::string const& cmSystemTools::GetCMakeRoot()
+{
+ return cmSystemToolsCMakeRoot;
+}
+
+void cmSystemTools::MakefileColorEcho(int color, const char* message,
+ bool newline, bool enabled)
+{
+ // On some platforms (an MSYS prompt) cmsysTerminal may not be able
+ // to determine whether the stream is displayed on a tty. In this
+ // case it assumes no unless we tell it otherwise. Since we want
+ // color messages to be displayed for users we will assume yes.
+ // However, we can test for some situations when the answer is most
+ // likely no.
+ int assumeTTY = cmsysTerminal_Color_AssumeTTY;
+ if (cmSystemTools::GetEnv("DART_TEST_FROM_DART") ||
+ cmSystemTools::GetEnv("DASHBOARD_TEST_FROM_CTEST") ||
+ cmSystemTools::GetEnv("CTEST_INTERACTIVE_DEBUG_MODE")) {
+ // Avoid printing color escapes during dashboard builds.
+ assumeTTY = 0;
+ }
+
+ if (enabled && color != cmsysTerminal_Color_Normal) {
+ // Print with color. Delay the newline until later so that
+ // all color restore sequences appear before it.
+ cmsysTerminal_cfprintf(color | assumeTTY, stdout, "%s", message);
+ } else {
+ // Color is disabled. Print without color.
+ fprintf(stdout, "%s", message);
+ }
+
+ if (newline) {
+ fprintf(stdout, "\n");
+ }
+}
+
+bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath,
+ std::string& soname)
+{
+// For ELF shared libraries use a real parser to get the correct
+// soname.
+#if defined(CMAKE_USE_ELF_PARSER)
+ cmELF elf(fullPath.c_str());
+ if (elf) {
+ return elf.GetSOName(soname);
+ }
+#endif
+
+ // If the file is not a symlink we have no guess for its soname.
+ if (!cmSystemTools::FileIsSymlink(fullPath)) {
+ return false;
+ }
+ if (!cmSystemTools::ReadSymlink(fullPath, soname)) {
+ return false;
+ }
+
+ // If the symlink has a path component we have no guess for the soname.
+ if (!cmSystemTools::GetFilenamePath(soname).empty()) {
+ return false;
+ }
+
+ // If the symlink points at an extended version of the same name
+ // assume it is the soname.
+ std::string name = cmSystemTools::GetFilenameName(fullPath);
+ return soname.length() > name.length() &&
+ soname.compare(0, name.length(), name) == 0;
+}
+
+bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath,
+ std::string& soname)
+{
+#if defined(CMAKE_USE_MACH_PARSER)
+ cmMachO macho(fullPath.c_str());
+ if (macho) {
+ return macho.GetInstallName(soname);
+ }
+#else
+ (void)fullPath;
+ (void)soname;
+#endif
+
+ return false;
+}
+
+#if defined(CMAKE_USE_ELF_PARSER)
+std::string::size_type cmSystemToolsFindRPath(std::string const& have,
+ std::string const& want)
+{
+ std::string::size_type pos = 0;
+ while (pos < have.size()) {
+ // Look for an occurrence of the string.
+ std::string::size_type const beg = have.find(want, pos);
+ if (beg == std::string::npos) {
+ return std::string::npos;
+ }
+
+ // Make sure it is separated from preceding entries.
+ if (beg > 0 && have[beg - 1] != ':') {
+ pos = beg + 1;
+ continue;
+ }
+
+ // Make sure it is separated from following entries.
+ std::string::size_type const end = beg + want.size();
+ if (end < have.size() && have[end] != ':') {
+ pos = beg + 1;
+ continue;
+ }
+
+ // Return the position of the path portion.
+ return beg;
+ }
+
+ // The desired rpath was not found.
+ return std::string::npos;
+}
+#endif
+
+#if defined(CMAKE_USE_ELF_PARSER)
+struct cmSystemToolsRPathInfo
+{
+ unsigned long Position;
+ unsigned long Size;
+ std::string Name;
+ std::string Value;
+};
+#endif
+
+bool cmSystemTools::ChangeRPath(std::string const& file,
+ std::string const& oldRPath,
+ std::string const& newRPath, std::string* emsg,
+ bool* changed)
+{
+#if defined(CMAKE_USE_ELF_PARSER)
+ if (changed) {
+ *changed = false;
+ }
+ int rp_count = 0;
+ bool remove_rpath = true;
+ cmSystemToolsRPathInfo rp[2];
+ {
+ // Parse the ELF binary.
+ cmELF elf(file.c_str());
+
+ // Get the RPATH and RUNPATH entries from it.
+ int se_count = 0;
+ cmELF::StringEntry const* se[2] = { CM_NULLPTR, CM_NULLPTR };
+ const char* se_name[2] = { CM_NULLPTR, CM_NULLPTR };
+ if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) {
+ se[se_count] = se_rpath;
+ se_name[se_count] = "RPATH";
+ ++se_count;
+ }
+ if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) {
+ se[se_count] = se_runpath;
+ se_name[se_count] = "RUNPATH";
+ ++se_count;
+ }
+ if (se_count == 0) {
+ if (newRPath.empty()) {
+ // The new rpath is empty and there is no rpath anyway so it is
+ // okay.
+ return true;
+ } else {
+ if (emsg) {
+ *emsg = "No valid ELF RPATH or RUNPATH entry exists in the file; ";
+ *emsg += elf.GetErrorMessage();
+ }
+ return false;
+ }
+ }
+
+ for (int i = 0; i < se_count; ++i) {
+ // If both RPATH and RUNPATH refer to the same string literal it
+ // needs to be changed only once.
+ if (rp_count && rp[0].Position == se[i]->Position) {
+ continue;
+ }
+
+ // Make sure the current rpath contains the old rpath.
+ std::string::size_type pos =
+ cmSystemToolsFindRPath(se[i]->Value, oldRPath);
+ if (pos == std::string::npos) {
+ // If it contains the new rpath instead then it is okay.
+ if (cmSystemToolsFindRPath(se[i]->Value, newRPath) !=
+ std::string::npos) {
+ remove_rpath = false;
+ continue;
+ }
+ if (emsg) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "The current " << se_name[i] << " is:\n"
+ << " " << se[i]->Value << "\n"
+ << "which does not contain:\n"
+ << " " << oldRPath << "\n"
+ << "as was expected.";
+ /* clang-format on */
+ *emsg = e.str();
+ }
+ return false;
+ }
+
+ // Store information about the entry in the file.
+ rp[rp_count].Position = se[i]->Position;
+ rp[rp_count].Size = se[i]->Size;
+ rp[rp_count].Name = se_name[i];
+
+ std::string::size_type prefix_len = pos;
+
+ // If oldRPath was at the end of the file's RPath, and newRPath is empty,
+ // we should remove the unnecessary ':' at the end.
+ if (newRPath.empty() && pos > 0 && se[i]->Value[pos - 1] == ':' &&
+ pos + oldRPath.length() == se[i]->Value.length()) {
+ prefix_len--;
+ }
+
+ // Construct the new value which preserves the part of the path
+ // not being changed.
+ rp[rp_count].Value = se[i]->Value.substr(0, prefix_len);
+ rp[rp_count].Value += newRPath;
+ rp[rp_count].Value +=
+ se[i]->Value.substr(pos + oldRPath.length(), oldRPath.npos);
+
+ if (!rp[rp_count].Value.empty()) {
+ remove_rpath = false;
+ }
+
+ // Make sure there is enough room to store the new rpath and at
+ // least one null terminator.
+ if (rp[rp_count].Size < rp[rp_count].Value.length() + 1) {
+ if (emsg) {
+ *emsg = "The replacement path is too long for the ";
+ *emsg += se_name[i];
+ *emsg += " entry.";
+ }
+ return false;
+ }
+
+ // This entry is ready for update.
+ ++rp_count;
+ }
+ }
+
+ // If no runtime path needs to be changed, we are done.
+ if (rp_count == 0) {
+ return true;
+ }
+
+ // If the resulting rpath is empty, just remove the entire entry instead.
+ if (remove_rpath) {
+ return cmSystemTools::RemoveRPath(file, emsg, changed);
+ }
+
+ {
+ // Open the file for update.
+ cmsys::ofstream f(file.c_str(),
+ std::ios::in | std::ios::out | std::ios::binary);
+ if (!f) {
+ if (emsg) {
+ *emsg = "Error opening file for update.";
+ }
+ return false;
+ }
+
+ // Store the new RPATH and RUNPATH strings.
+ for (int i = 0; i < rp_count; ++i) {
+ // Seek to the RPATH position.
+ if (!f.seekp(rp[i].Position)) {
+ if (emsg) {
+ *emsg = "Error seeking to ";
+ *emsg += rp[i].Name;
+ *emsg += " position.";
+ }
+ return false;
+ }
+
+ // Write the new rpath. Follow it with enough null terminators to
+ // fill the string table entry.
+ f << rp[i].Value;
+ for (unsigned long j = rp[i].Value.length(); j < rp[i].Size; ++j) {
+ f << '\0';
+ }
+
+ // Make sure it wrote correctly.
+ if (!f) {
+ if (emsg) {
+ *emsg = "Error writing the new ";
+ *emsg += rp[i].Name;
+ *emsg += " string to the file.";
+ }
+ return false;
+ }
+ }
+ }
+
+ // Everything was updated successfully.
+ if (changed) {
+ *changed = true;
+ }
+ return true;
+#else
+ (void)file;
+ (void)oldRPath;
+ (void)newRPath;
+ (void)emsg;
+ (void)changed;
+ return false;
+#endif
+}
+
+bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op,
+ const char* lhss, const char* rhss)
+{
+ const char* endl = lhss;
+ const char* endr = rhss;
+ unsigned long lhs, rhs;
+
+ while (((*endl >= '0') && (*endl <= '9')) ||
+ ((*endr >= '0') && (*endr <= '9'))) {
+ // Do component-wise comparison.
+ lhs = strtoul(endl, const_cast<char**>(&endl), 10);
+ rhs = strtoul(endr, const_cast<char**>(&endr), 10);
+
+ if (lhs < rhs) {
+ // lhs < rhs, so true if operation is LESS
+ return op == cmSystemTools::OP_LESS;
+ } else if (lhs > rhs) {
+ // lhs > rhs, so true if operation is GREATER
+ return op == cmSystemTools::OP_GREATER;
+ }
+
+ if (*endr == '.') {
+ endr++;
+ }
+
+ if (*endl == '.') {
+ endl++;
+ }
+ }
+ // lhs == rhs, so true if operation is EQUAL
+ return op == cmSystemTools::OP_EQUAL;
+}
+
+bool cmSystemTools::VersionCompareEqual(std::string const& lhs,
+ std::string const& rhs)
+{
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, lhs.c_str(),
+ rhs.c_str());
+}
+
+bool cmSystemTools::VersionCompareGreater(std::string const& lhs,
+ std::string const& rhs)
+{
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, lhs.c_str(),
+ rhs.c_str());
+}
+
+bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
+ bool* removed)
+{
+#if defined(CMAKE_USE_ELF_PARSER)
+ if (removed) {
+ *removed = false;
+ }
+ int zeroCount = 0;
+ unsigned long zeroPosition[2] = { 0, 0 };
+ unsigned long zeroSize[2] = { 0, 0 };
+ unsigned long bytesBegin = 0;
+ std::vector<char> bytes;
+ {
+ // Parse the ELF binary.
+ cmELF elf(file.c_str());
+
+ // Get the RPATH and RUNPATH entries from it and sort them by index
+ // in the dynamic section header.
+ int se_count = 0;
+ cmELF::StringEntry const* se[2] = { CM_NULLPTR, CM_NULLPTR };
+ if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) {
+ se[se_count++] = se_rpath;
+ }
+ if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) {
+ se[se_count++] = se_runpath;
+ }
+ if (se_count == 0) {
+ // There is no RPATH or RUNPATH anyway.
+ return true;
+ }
+ if (se_count == 2 && se[1]->IndexInSection < se[0]->IndexInSection) {
+ std::swap(se[0], se[1]);
+ }
+
+ // Get the size of the dynamic section header.
+ unsigned int count = elf.GetDynamicEntryCount();
+ if (count == 0) {
+ // This should happen only for invalid ELF files where a DT_NULL
+ // appears before the end of the table.
+ if (emsg) {
+ *emsg = "DYNAMIC section contains a DT_NULL before the end.";
+ }
+ return false;
+ }
+
+ // Save information about the string entries to be zeroed.
+ zeroCount = se_count;
+ for (int i = 0; i < se_count; ++i) {
+ zeroPosition[i] = se[i]->Position;
+ zeroSize[i] = se[i]->Size;
+ }
+
+ // Get the range of file positions corresponding to each entry and
+ // the rest of the table after them.
+ unsigned long entryBegin[3] = { 0, 0, 0 };
+ unsigned long entryEnd[2] = { 0, 0 };
+ for (int i = 0; i < se_count; ++i) {
+ entryBegin[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection);
+ entryEnd[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection + 1);
+ }
+ entryBegin[se_count] = elf.GetDynamicEntryPosition(count);
+
+ // The data are to be written over the old table entries starting at
+ // the first one being removed.
+ bytesBegin = entryBegin[0];
+ unsigned long bytesEnd = entryBegin[se_count];
+
+ // Allocate a buffer to hold the part of the file to be written.
+ // Initialize it with zeros.
+ bytes.resize(bytesEnd - bytesBegin, 0);
+
+ // Read the part of the DYNAMIC section header that will move.
+ // The remainder of the buffer will be left with zeros which
+ // represent a DT_NULL entry.
+ char* data = &bytes[0];
+ for (int i = 0; i < se_count; ++i) {
+ // Read data between the entries being removed.
+ unsigned long sz = entryBegin[i + 1] - entryEnd[i];
+ if (sz > 0 && !elf.ReadBytes(entryEnd[i], sz, data)) {
+ if (emsg) {
+ *emsg = "Failed to read DYNAMIC section header.";
+ }
+ return false;
+ }
+ data += sz;
+ }
+ }
+
+ // Open the file for update.
+ cmsys::ofstream f(file.c_str(),
+ std::ios::in | std::ios::out | std::ios::binary);
+ if (!f) {
+ if (emsg) {
+ *emsg = "Error opening file for update.";
+ }
+ return false;
+ }
+
+ // Write the new DYNAMIC table header.
+ if (!f.seekp(bytesBegin)) {
+ if (emsg) {
+ *emsg = "Error seeking to DYNAMIC table header for RPATH.";
+ }
+ return false;
+ }
+ if (!f.write(&bytes[0], bytes.size())) {
+ if (emsg) {
+ *emsg = "Error replacing DYNAMIC table header.";
+ }
+ return false;
+ }
+
+ // Fill the RPATH and RUNPATH strings with zero bytes.
+ for (int i = 0; i < zeroCount; ++i) {
+ if (!f.seekp(zeroPosition[i])) {
+ if (emsg) {
+ *emsg = "Error seeking to RPATH position.";
+ }
+ return false;
+ }
+ for (unsigned long j = 0; j < zeroSize[i]; ++j) {
+ f << '\0';
+ }
+ if (!f) {
+ if (emsg) {
+ *emsg = "Error writing the empty rpath string to the file.";
+ }
+ return false;
+ }
+ }
+
+ // Everything was updated successfully.
+ if (removed) {
+ *removed = true;
+ }
+ return true;
+#else
+ (void)file;
+ (void)emsg;
+ (void)removed;
+ return false;
+#endif
+}
+
+bool cmSystemTools::CheckRPath(std::string const& file,
+ std::string const& newRPath)
+{
+#if defined(CMAKE_USE_ELF_PARSER)
+ // Parse the ELF binary.
+ cmELF elf(file.c_str());
+
+ // Get the RPATH or RUNPATH entry from it.
+ cmELF::StringEntry const* se = elf.GetRPath();
+ if (!se) {
+ se = elf.GetRunPath();
+ }
+
+ // Make sure the current rpath contains the new rpath.
+ if (newRPath.empty()) {
+ if (!se) {
+ return true;
+ }
+ } else {
+ if (se &&
+ cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+#else
+ (void)file;
+ (void)newRPath;
+ return false;
+#endif
+}
+
+bool cmSystemTools::RepeatedRemoveDirectory(const char* dir)
+{
+ // Windows sometimes locks files temporarily so try a few times.
+ for (int i = 0; i < 10; ++i) {
+ if (cmSystemTools::RemoveADirectory(dir)) {
+ return true;
+ }
+ cmSystemTools::Delay(100);
+ }
+ return false;
+}
+
+std::vector<std::string> cmSystemTools::tokenize(const std::string& str,
+ const std::string& sep)
+{
+ std::vector<std::string> tokens;
+ std::string::size_type tokend = 0;
+
+ do {
+ std::string::size_type tokstart = str.find_first_not_of(sep, tokend);
+ if (tokstart == std::string::npos) {
+ break; // no more tokens
+ }
+ tokend = str.find_first_of(sep, tokstart);
+ if (tokend == std::string::npos) {
+ tokens.push_back(str.substr(tokstart));
+ } else {
+ tokens.push_back(str.substr(tokstart, tokend - tokstart));
+ }
+ } while (tokend != std::string::npos);
+
+ if (tokens.empty()) {
+ tokens.push_back("");
+ }
+ return tokens;
+}
+
+bool cmSystemTools::StringToLong(const char* str, long* value)
+{
+ errno = 0;
+ char* endp;
+ *value = strtol(str, &endp, 10);
+ return (*endp == '\0') && (endp != str) && (errno == 0);
+}
+
+bool cmSystemTools::StringToULong(const char* str, unsigned long* value)
+{
+ errno = 0;
+ char* endp;
+ *value = strtoul(str, &endp, 10);
+ return (*endp == '\0') && (endp != str) && (errno == 0);
+}
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
new file mode 100644
index 0000000..39e7994
--- /dev/null
+++ b/Source/cmSystemTools.h
@@ -0,0 +1,491 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmSystemTools_h
+#define cmSystemTools_h
+
+#include "cmStandardIncludes.h"
+
+#include <cmsys/Process.h>
+#include <cmsys/SystemTools.hxx>
+
+class cmSystemToolsFileTime;
+
+/** \class cmSystemTools
+ * \brief A collection of useful functions for CMake.
+ *
+ * cmSystemTools is a class that provides helper functions
+ * for the CMake build system.
+ */
+class cmSystemTools : public cmsys::SystemTools
+{
+public:
+ typedef cmsys::SystemTools Superclass;
+
+ /** 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.
+ */
+ 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);
+
+ /**
+ * Look for and replace registry values in a string
+ */
+ static void ExpandRegistryValues(std::string& source,
+ KeyWOW64 view = KeyWOW64_Default);
+
+ ///! Escape quotes in a string.
+ static std::string EscapeQuotes(const std::string& str);
+
+ /** Map help document name to file name. */
+ static std::string HelpFileName(std::string);
+
+ /**
+ * Returns a string that has whitespace removed from the start and the end.
+ */
+ static std::string TrimWhitespace(const std::string& s);
+
+ typedef void (*MessageCallback)(const char*, const char*, bool&, void*);
+ /**
+ * Set the function used by GUIs to display error messages
+ * Function gets passed: message as a const char*,
+ * title as a const char*, and a reference to bool that when
+ * set to false, will disable furthur messages (cancel).
+ */
+ static void SetMessageCallback(MessageCallback f,
+ void* clientData = CM_NULLPTR);
+
+ /**
+ * Display an error message.
+ */
+ static void Error(const char* m, const char* m2 = CM_NULLPTR,
+ const char* m3 = CM_NULLPTR, const char* m4 = CM_NULLPTR);
+
+ /**
+ * Display a message.
+ */
+ static void Message(const char* m, const char* title = CM_NULLPTR);
+
+ typedef void (*OutputCallback)(const char*, size_t length, void*);
+
+ ///! Send a string to stdout
+ static void Stdout(const char* s);
+ static void Stdout(const char* s, size_t length);
+ static void SetStdoutCallback(OutputCallback, void* clientData = CM_NULLPTR);
+
+ ///! Send a string to stderr
+ static void Stderr(const char* s);
+ static void Stderr(const char* s, size_t length);
+ static void SetStderrCallback(OutputCallback, void* clientData = CM_NULLPTR);
+
+ typedef bool (*InterruptCallback)(void*);
+ static void SetInterruptCallback(InterruptCallback f,
+ void* clientData = CM_NULLPTR);
+ static bool GetInterruptFlag();
+
+ ///! 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.
+ static void SetFatalErrorOccured()
+ {
+ cmSystemTools::s_FatalErrorOccured = true;
+ }
+ static void SetErrorOccured() { cmSystemTools::s_ErrorOccured = true; }
+ ///! 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
+ static void ResetErrorOccuredFlag()
+ {
+ cmSystemTools::s_FatalErrorOccured = false;
+ cmSystemTools::s_ErrorOccured = false;
+ }
+
+ /**
+ * Does a string indicates that CMake/CPack/CTest internally
+ * forced this value. This is not the same as On, but this
+ * may be considered as "internally switched on".
+ */
+ static bool IsInternallyOn(const char* val);
+ /**
+ * does a string indicate a true or on value ? This is not the same
+ * as ifdef.
+ */
+ static bool IsOn(const char* val);
+
+ /**
+ * does a string indicate a false or off value ? Note that this is
+ * not the same as !IsOn(...) because there are a number of
+ * ambiguous values such as "/usr/local/bin" a path will result in
+ * IsON and IsOff both returning false. Note that the special path
+ * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true.
+ */
+ static bool IsOff(const char* val);
+
+ ///! 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);
+
+ static bool DoesFileExistWithExtensions(
+ const char* 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 void Glob(const std::string& directory, const std::string& regexp,
+ std::vector<std::string>& files);
+ static void GlobDirs(const std::string& fullPath,
+ std::vector<std::string>& files);
+
+ /**
+ * Try to find a list of files that match the "simple" globbing
+ * expression. At this point in time the globbing expressions have
+ * to be in form: /directory/partial_file_name*. The * character has
+ * to be at the end of the string and it does not support ?
+ * []... The optional argument type specifies what kind of files you
+ * want to find. 0 means all files, -1 means directories, 1 means
+ * files only. This method returns true if search was succesfull.
+ */
+ static bool SimpleGlob(const std::string& glob,
+ std::vector<std::string>& files, int type = 0);
+
+ ///! Copy a file.
+ static bool cmCopyFile(const char* source, const char* destination);
+ static bool CopyFileIfDifferent(const char* source, const char* destination);
+
+ /** Rename a file or directory within a single disk volume (atomic
+ if possible). */
+ static bool RenameFile(const char* oldname, const char* newname);
+
+ ///! Compute the md5sum of a file
+ static bool ComputeFileMD5(const std::string& source, char* md5out);
+
+ /** Compute the md5sum of a string. */
+ static std::string ComputeStringMD5(const std::string& input);
+
+ ///! Get the SHA thumbprint for a certificate file
+ static std::string ComputeCertificateThumbprint(const std::string& source);
+
+ /**
+ * Run a single executable command
+ *
+ * Output is controlled with outputflag. If outputflag is OUTPUT_NONE, no
+ * user-viewable output from the program being run will be generated.
+ * OUTPUT_MERGE is the legacy behaviour where stdout and stderr are merged
+ * into stdout. OUTPUT_FORWARD copies the output to stdout/stderr as
+ * it was received. OUTPUT_PASSTHROUGH passes through the original handles.
+ *
+ * If timeout is specified, the command will be terminated after
+ * timeout expires. Timeout is specified in seconds.
+ *
+ * Argument retVal should be a pointer to the location where the
+ * exit code will be stored. If the retVal is not specified and
+ * the program exits with a code other than 0, then the this
+ * function will return false.
+ *
+ * If the command has spaces in the path the caller MUST call
+ * cmSystemTools::ConvertToRunCommandPath on the command before passing
+ * it into this function or it will not work. The command must be correctly
+ * escaped for this to with spaces.
+ */
+ enum OutputOption
+ {
+ OUTPUT_NONE = 0,
+ OUTPUT_MERGE,
+ OUTPUT_FORWARD,
+ OUTPUT_PASSTHROUGH
+ };
+ static bool RunSingleCommand(const char* command,
+ std::string* captureStdOut = CM_NULLPTR,
+ std::string* captureStdErr = CM_NULLPTR,
+ int* retVal = CM_NULLPTR,
+ const char* dir = CM_NULLPTR,
+ OutputOption outputflag = OUTPUT_MERGE,
+ double timeout = 0.0);
+ /**
+ * In this version of RunSingleCommand, command[0] should be
+ * the command to run, and each argument to the command should
+ * be in comand[1]...command[command.size()]
+ */
+ static bool RunSingleCommand(std::vector<std::string> const& command,
+ std::string* captureStdOut = CM_NULLPTR,
+ std::string* captureStdErr = CM_NULLPTR,
+ int* retVal = CM_NULLPTR,
+ const char* dir = CM_NULLPTR,
+ OutputOption outputflag = OUTPUT_MERGE,
+ double timeout = 0.0);
+
+ static std::string PrintSingleCommand(std::vector<std::string> const&);
+
+ /**
+ * Parse arguments out of a single string command
+ */
+ static std::vector<std::string> ParseArguments(const char* command);
+
+ /** Parse arguments out of a windows command line string. */
+ static void ParseWindowsCommandLine(const char* command,
+ std::vector<std::string>& args);
+
+ /** Parse arguments out of a unix command line string. */
+ static void ParseUnixCommandLine(const char* command,
+ std::vector<std::string>& args);
+
+ 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; }
+
+ /**
+ * Some constants for different file formats.
+ */
+ enum FileFormat
+ {
+ NO_FILE_FORMAT = 0,
+ C_FILE_FORMAT,
+ CXX_FILE_FORMAT,
+ FORTRAN_FILE_FORMAT,
+ JAVA_FILE_FORMAT,
+ HEADER_FILE_FORMAT,
+ RESOURCE_FILE_FORMAT,
+ DEFINITION_FILE_FORMAT,
+ STATIC_LIBRARY_FILE_FORMAT,
+ SHARED_LIBRARY_FILE_FORMAT,
+ MODULE_FILE_FORMAT,
+ OBJECT_FILE_FORMAT,
+ UNKNOWN_FILE_FORMAT
+ };
+
+ enum CompareOp
+ {
+ OP_LESS,
+ OP_GREATER,
+ OP_EQUAL
+ };
+
+ /**
+ * Compare versions
+ */
+ static bool VersionCompare(CompareOp op, const char* lhs, const char* rhs);
+ static bool VersionCompareEqual(std::string const& lhs,
+ std::string const& rhs);
+ static bool VersionCompareGreater(std::string const& lhs,
+ std::string const& rhs);
+
+ /**
+ * Determine the file type based on the extension
+ */
+ static FileFormat GetFileFormat(const char* ext);
+
+ /** Windows if this is true, the CreateProcess in RunCommand will
+ * not show new consol windows when running programs.
+ */
+ static void SetRunCommandHideConsole(bool v) { s_RunCommandHideConsole = v; }
+ static bool GetRunCommandHideConsole() { return s_RunCommandHideConsole; }
+ /** Call cmSystemTools::Error with the message m, plus the
+ * result of strerror(errno)
+ */
+ static void ReportLastSystemError(const char* m);
+
+ /** a general output handler for cmsysProcess */
+ static int WaitForLine(cmsysProcess* process, std::string& line,
+ double 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; }
+
+ // ConvertToOutputPath use s_ForceUnixPaths
+ static std::string ConvertToOutputPath(const char* path);
+ static void ConvertToOutputSlashes(std::string& path);
+
+ // 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);
+
+ /** compute the relative path from local to remote. local must
+ be a directory. remote can be a file or a directory.
+ Both remote and local must be full paths. Basically, if
+ you are in directory local and you want to access the file in remote
+ what is the relative path to do that. For example:
+ /a/b/c/d to /a/b/c1/d1 -> ../../c1/d1
+ from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp
+ */
+ static std::string RelativePath(const char* local, const char* remote);
+
+ /** 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);
+
+ /** Get the list of all environment variables */
+ static std::vector<std::string> GetEnvironmentVariables();
+
+ /** Append multiple variables to the current environment. */
+ static void AppendEnv(std::vector<std::string> const& env);
+
+ /** Helper class to save and restore the environment.
+ Instantiate this class as an automatic variable on
+ the stack. Its constructor saves a copy of the current
+ environment and then its destructor restores the
+ original environment. */
+ class SaveRestoreEnvironment
+ {
+ public:
+ SaveRestoreEnvironment();
+ virtual ~SaveRestoreEnvironment();
+
+ private:
+ std::vector<std::string> Env;
+ };
+#endif
+
+ /** Setup the environment to enable VS 8 IDE output. */
+ static void EnableVSConsoleOutput();
+
+ /** Create tar */
+ enum cmTarCompression
+ {
+ TarCompressGZip,
+ TarCompressBZip2,
+ TarCompressXZ,
+ TarCompressNone
+ };
+ static bool ListTar(const char* outFileName, bool verbose);
+ static bool CreateTar(const char* 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);
+ // 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
+ // if you want to be able to kill child processes and
+ // 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);
+
+ /** Random seed generation. */
+ static unsigned int RandomSeed();
+
+ /** Find the directory containing CMake executables. */
+ static void FindCMakeResources(const char* argv0);
+
+ /** Get the CMake resource paths, after FindCMakeResources. */
+ static std::string const& GetCTestCommand();
+ static std::string const& GetCPackCommand();
+ static std::string const& GetCMakeCommand();
+ static std::string const& GetCMakeGUICommand();
+ static std::string const& GetCMakeCursesCommand();
+ static std::string const& GetCMClDepsCommand();
+ static std::string const& GetCMakeRoot();
+
+ /** Echo a message in color using KWSys's Terminal cprintf. */
+ static void MakefileColorEcho(int color, const char* message, bool newLine,
+ bool enabled);
+
+ /** Try to guess the soname of a shared library. */
+ static bool GuessLibrarySOName(std::string const& fullPath,
+ std::string& soname);
+
+ /** Try to guess the install name of a shared library. */
+ static bool GuessLibraryInstallName(std::string const& fullPath,
+ std::string& soname);
+
+ /** Try to set the RPATH in an ELF binary. */
+ static bool ChangeRPath(std::string const& file, std::string const& oldRPath,
+ std::string const& newRPath,
+ std::string* emsg = CM_NULLPTR,
+ bool* changed = CM_NULLPTR);
+
+ /** Try to remove the RPATH from an ELF binary. */
+ static bool RemoveRPath(std::string const& file,
+ std::string* emsg = CM_NULLPTR,
+ bool* removed = CM_NULLPTR);
+
+ /** Check whether the RPATH in an ELF binary contains the path
+ given. */
+ 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);
+
+ /** Tokenize a string */
+ static std::vector<std::string> tokenize(const std::string& str,
+ const std::string& sep);
+
+ /** Convert string to long. Expected that the whole string is an integer */
+ static bool StringToLong(const char* str, long* value);
+ static bool StringToULong(const char* str, unsigned long* value);
+
+#ifdef _WIN32
+ struct WindowsFileRetry
+ {
+ unsigned int Count;
+ unsigned int Delay;
+ };
+ static WindowsFileRetry GetWindowsFileRetry();
+#endif
+private:
+ static bool s_ForceUnixPaths;
+ static bool s_RunCommandHideConsole;
+ static bool s_ErrorOccured;
+ static bool s_FatalErrorOccured;
+ static bool s_DisableMessages;
+ static bool s_DisableRunCommandOutput;
+ static MessageCallback s_MessageCallback;
+ static OutputCallback s_StdoutCallback;
+ static OutputCallback s_StderrCallback;
+ static InterruptCallback s_InterruptCallback;
+ static void* s_MessageCallbackClientData;
+ static void* s_StdoutCallbackClientData;
+ static void* s_StderrCallbackClientData;
+ static void* s_InterruptCallbackClientData;
+};
+
+#endif
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
new file mode 100644
index 0000000..ceebf93
--- /dev/null
+++ b/Source/cmTarget.cxx
@@ -0,0 +1,1640 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTarget.h"
+
+#include "cmAlgorithms.h"
+#include "cmComputeLinkInformation.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmSourceFile.h"
+#include "cmake.h"
+#include <assert.h>
+#include <cmsys/RegularExpression.hxx>
+#include <errno.h>
+#include <map>
+#include <set>
+#include <stdlib.h> // required for atof
+
+#if defined(CMake_HAVE_CXX_UNORDERED_SET)
+#include <unordered_set>
+#define UNORDERED_SET std::unordered_set
+#elif defined(CMAKE_BUILD_WITH_CMAKE)
+#include <cmsys/hash_set.hxx>
+#define UNORDERED_SET cmsys::hash_set
+#else
+#define UNORDERED_SET std::set
+#endif
+
+class cmTargetInternals
+{
+public:
+ std::vector<std::string> IncludeDirectoriesEntries;
+ std::vector<cmListFileBacktrace> IncludeDirectoriesBacktraces;
+ std::vector<std::string> CompileOptionsEntries;
+ std::vector<cmListFileBacktrace> CompileOptionsBacktraces;
+ std::vector<std::string> CompileFeaturesEntries;
+ std::vector<cmListFileBacktrace> CompileFeaturesBacktraces;
+ std::vector<std::string> CompileDefinitionsEntries;
+ std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces;
+ std::vector<std::string> SourceEntries;
+ std::vector<cmListFileBacktrace> SourceBacktraces;
+ std::vector<std::string> LinkImplementationPropertyEntries;
+ std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces;
+};
+
+cmTarget::cmTarget()
+{
+ this->Makefile = CM_NULLPTR;
+ this->HaveInstallRule = false;
+ this->DLLPlatform = false;
+ this->IsAndroid = false;
+ this->IsImportedTarget = false;
+ this->ImportedGloballyVisible = false;
+ this->BuildInterfaceIncludesAppended = false;
+}
+
+void cmTarget::SetType(cmState::TargetType type, const std::string& name)
+{
+ this->Name = name;
+ // only add dependency information for library targets
+ this->TargetTypeValue = type;
+ if (this->TargetTypeValue >= cmState::STATIC_LIBRARY &&
+ this->TargetTypeValue <= cmState::MODULE_LIBRARY) {
+ this->RecordDependencies = true;
+ } else {
+ this->RecordDependencies = false;
+ }
+}
+
+void cmTarget::SetMakefile(cmMakefile* mf)
+{
+ // Set our makefile.
+ this->Makefile = mf;
+
+ // Check whether this is a DLL platform.
+ this->DLLPlatform =
+ (this->Makefile->IsOn("WIN32") || this->Makefile->IsOn("CYGWIN") ||
+ this->Makefile->IsOn("MINGW"));
+
+ // Check whether we are targeting an Android platform.
+ this->IsAndroid =
+ strcmp(this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME"),
+ "Android") == 0;
+
+ // Setup default property values.
+ if (this->GetType() != cmState::INTERFACE_LIBRARY &&
+ this->GetType() != cmState::UTILITY) {
+ this->SetPropertyDefault("ANDROID_API", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_API_MIN", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_ARCH", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_STL_TYPE", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_SKIP_ANT_STEP", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_PROCESS_MAX", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_PROGUARD", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_PROGUARD_CONFIG_PATH", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_SECURE_PROPS_PATH", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_NATIVE_LIB_DIRECTORIES", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_NATIVE_LIB_DEPENDENCIES", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_JAVA_SOURCE_DIR", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_JAR_DIRECTORIES", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_JAR_DEPENDENCIES", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_ASSETS_DIRECTORIES", CM_NULLPTR);
+ this->SetPropertyDefault("ANDROID_ANT_ADDITIONAL_OPTIONS", CM_NULLPTR);
+ this->SetPropertyDefault("INSTALL_NAME_DIR", CM_NULLPTR);
+ this->SetPropertyDefault("INSTALL_RPATH", "");
+ this->SetPropertyDefault("INSTALL_RPATH_USE_LINK_PATH", "OFF");
+ this->SetPropertyDefault("SKIP_BUILD_RPATH", "OFF");
+ this->SetPropertyDefault("BUILD_WITH_INSTALL_RPATH", "OFF");
+ this->SetPropertyDefault("ARCHIVE_OUTPUT_DIRECTORY", CM_NULLPTR);
+ this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", CM_NULLPTR);
+ this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", CM_NULLPTR);
+ this->SetPropertyDefault("PDB_OUTPUT_DIRECTORY", CM_NULLPTR);
+ this->SetPropertyDefault("COMPILE_PDB_OUTPUT_DIRECTORY", CM_NULLPTR);
+ this->SetPropertyDefault("Fortran_FORMAT", CM_NULLPTR);
+ this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", CM_NULLPTR);
+ this->SetPropertyDefault("GNUtoMS", CM_NULLPTR);
+ this->SetPropertyDefault("OSX_ARCHITECTURES", CM_NULLPTR);
+ this->SetPropertyDefault("IOS_INSTALL_COMBINED", CM_NULLPTR);
+ this->SetPropertyDefault("AUTOMOC", CM_NULLPTR);
+ this->SetPropertyDefault("AUTOUIC", CM_NULLPTR);
+ this->SetPropertyDefault("AUTORCC", CM_NULLPTR);
+ this->SetPropertyDefault("AUTOMOC_MOC_OPTIONS", CM_NULLPTR);
+ this->SetPropertyDefault("AUTOUIC_OPTIONS", CM_NULLPTR);
+ this->SetPropertyDefault("AUTORCC_OPTIONS", CM_NULLPTR);
+ this->SetPropertyDefault("LINK_DEPENDS_NO_SHARED", CM_NULLPTR);
+ this->SetPropertyDefault("LINK_INTERFACE_LIBRARIES", CM_NULLPTR);
+ this->SetPropertyDefault("WIN32_EXECUTABLE", CM_NULLPTR);
+ this->SetPropertyDefault("MACOSX_BUNDLE", CM_NULLPTR);
+ this->SetPropertyDefault("MACOSX_RPATH", CM_NULLPTR);
+ this->SetPropertyDefault("NO_SYSTEM_FROM_IMPORTED", CM_NULLPTR);
+ this->SetPropertyDefault("C_CLANG_TIDY", CM_NULLPTR);
+ this->SetPropertyDefault("C_COMPILER_LAUNCHER", CM_NULLPTR);
+ this->SetPropertyDefault("C_INCLUDE_WHAT_YOU_USE", CM_NULLPTR);
+ this->SetPropertyDefault("LINK_WHAT_YOU_USE", CM_NULLPTR);
+ this->SetPropertyDefault("C_STANDARD", CM_NULLPTR);
+ this->SetPropertyDefault("C_STANDARD_REQUIRED", CM_NULLPTR);
+ this->SetPropertyDefault("C_EXTENSIONS", CM_NULLPTR);
+ this->SetPropertyDefault("CXX_CLANG_TIDY", CM_NULLPTR);
+ this->SetPropertyDefault("CXX_COMPILER_LAUNCHER", CM_NULLPTR);
+ this->SetPropertyDefault("CXX_INCLUDE_WHAT_YOU_USE", CM_NULLPTR);
+ this->SetPropertyDefault("CXX_STANDARD", CM_NULLPTR);
+ this->SetPropertyDefault("CXX_STANDARD_REQUIRED", CM_NULLPTR);
+ this->SetPropertyDefault("CXX_EXTENSIONS", CM_NULLPTR);
+ this->SetPropertyDefault("LINK_SEARCH_START_STATIC", CM_NULLPTR);
+ this->SetPropertyDefault("LINK_SEARCH_END_STATIC", CM_NULLPTR);
+ }
+
+ // Collect the set of configuration types.
+ std::vector<std::string> configNames;
+ mf->GetConfigurations(configNames);
+
+ // Setup per-configuration property default values.
+ if (this->GetType() != cmState::UTILITY) {
+ const char* 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_",
+ CM_NULLPTR
+ };
+ for (std::vector<std::string>::iterator ci = configNames.begin();
+ ci != configNames.end(); ++ci) {
+ std::string configUpper = cmSystemTools::UpperCase(*ci);
+ for (const char** p = configProps; *p; ++p) {
+ if (this->TargetTypeValue == cmState::INTERFACE_LIBRARY &&
+ strcmp(*p, "MAP_IMPORTED_CONFIG_") != 0) {
+ continue;
+ }
+ std::string property = *p;
+ property += configUpper;
+ this->SetPropertyDefault(property, CM_NULLPTR);
+ }
+
+ // Initialize per-configuration name postfix property from the
+ // variable only for non-executable targets. This preserves
+ // compatibility with previous CMake versions in which executables
+ // did not support this variable. Projects may still specify the
+ // property directly.
+ if (this->TargetTypeValue != cmState::EXECUTABLE &&
+ this->TargetTypeValue != cmState::INTERFACE_LIBRARY) {
+ std::string property = cmSystemTools::UpperCase(*ci);
+ property += "_POSTFIX";
+ this->SetPropertyDefault(property, CM_NULLPTR);
+ }
+ }
+ }
+
+ // Save the backtrace of target construction.
+ this->Backtrace = this->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 parentOptions =
+ this->Makefile->GetCompileOptionsEntries();
+ const cmBacktraceRange parentOptionsBts =
+ this->Makefile->GetCompileOptionsBacktraces();
+
+ this->Internal->CompileOptionsEntries.insert(
+ this->Internal->CompileOptionsEntries.end(), parentOptions.begin(),
+ parentOptions.end());
+ this->Internal->CompileOptionsBacktraces.insert(
+ this->Internal->CompileOptionsBacktraces.end(), parentOptionsBts.begin(),
+ parentOptionsBts.end());
+ }
+
+ if (this->GetType() != cmState::INTERFACE_LIBRARY &&
+ this->GetType() != cmState::UTILITY) {
+ this->SetPropertyDefault("C_VISIBILITY_PRESET", CM_NULLPTR);
+ this->SetPropertyDefault("CXX_VISIBILITY_PRESET", CM_NULLPTR);
+ this->SetPropertyDefault("VISIBILITY_INLINES_HIDDEN", CM_NULLPTR);
+ }
+
+ if (this->TargetTypeValue == cmState::EXECUTABLE) {
+ this->SetPropertyDefault("ANDROID_GUI", CM_NULLPTR);
+ this->SetPropertyDefault("CROSSCOMPILING_EMULATOR", CM_NULLPTR);
+ this->SetPropertyDefault("ENABLE_EXPORTS", CM_NULLPTR);
+ }
+ if (this->TargetTypeValue == cmState::SHARED_LIBRARY ||
+ this->TargetTypeValue == cmState::MODULE_LIBRARY) {
+ this->SetProperty("POSITION_INDEPENDENT_CODE", "True");
+ }
+ if (this->TargetTypeValue == cmState::SHARED_LIBRARY) {
+ this->SetPropertyDefault("WINDOWS_EXPORT_ALL_SYMBOLS", CM_NULLPTR);
+ }
+
+ if (this->GetType() != cmState::INTERFACE_LIBRARY &&
+ this->GetType() != cmState::UTILITY) {
+ this->SetPropertyDefault("POSITION_INDEPENDENT_CODE", CM_NULLPTR);
+ }
+
+ // Record current policies for later use.
+ this->Makefile->RecordPolicies(this->PolicyMap);
+
+ if (this->TargetTypeValue == cmState::INTERFACE_LIBRARY) {
+ // This policy is checked in a few conditions. The properties relevant
+ // to the policy are always ignored for cmState::INTERFACE_LIBRARY targets,
+ // so ensure that the conditions don't lead to nonsense.
+ this->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
+ }
+
+ if (this->GetType() != cmState::INTERFACE_LIBRARY &&
+ this->GetType() != cmState::UTILITY) {
+ this->SetPropertyDefault("JOB_POOL_COMPILE", CM_NULLPTR);
+ this->SetPropertyDefault("JOB_POOL_LINK", CM_NULLPTR);
+ }
+}
+
+void cmTarget::AddUtility(const std::string& u, cmMakefile* makefile)
+{
+ if (this->Utilities.insert(u).second && makefile) {
+ this->UtilityBacktraces.insert(
+ std::make_pair(u, makefile->GetBacktrace()));
+ }
+}
+
+cmListFileBacktrace const* cmTarget::GetUtilityBacktrace(
+ const std::string& u) const
+{
+ std::map<std::string, cmListFileBacktrace>::const_iterator i =
+ this->UtilityBacktraces.find(u);
+ if (i == this->UtilityBacktraces.end()) {
+ return CM_NULLPTR;
+ }
+
+ return &i->second;
+}
+
+cmListFileBacktrace const& cmTarget::GetBacktrace() const
+{
+ return this->Backtrace;
+}
+
+bool cmTarget::IsExecutableWithExports() const
+{
+ return (this->GetType() == cmState::EXECUTABLE &&
+ this->GetPropertyAsBool("ENABLE_EXPORTS"));
+}
+
+bool cmTarget::HasImportLibrary() const
+{
+ return (this->DLLPlatform && (this->GetType() == cmState::SHARED_LIBRARY ||
+ this->IsExecutableWithExports()));
+}
+
+bool cmTarget::IsFrameworkOnApple() const
+{
+ return (this->GetType() == cmState::SHARED_LIBRARY &&
+ this->Makefile->IsOn("APPLE") &&
+ this->GetPropertyAsBool("FRAMEWORK"));
+}
+
+bool cmTarget::IsAppBundleOnApple() const
+{
+ return (this->GetType() == cmState::EXECUTABLE &&
+ this->Makefile->IsOn("APPLE") &&
+ this->GetPropertyAsBool("MACOSX_BUNDLE"));
+}
+
+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);
+ }
+}
+
+void cmTarget::AddSources(std::vector<std::string> const& srcs)
+{
+ std::string srcFiles;
+ const char* sep = "";
+ for (std::vector<std::string>::const_iterator i = srcs.begin();
+ i != srcs.end(); ++i) {
+ std::string filename = *i;
+ const char* src = filename.c_str();
+
+ if (!(src[0] == '$' && src[1] == '<')) {
+ if (!filename.empty()) {
+ filename = this->ProcessSourceItemCMP0049(filename);
+ if (filename.empty()) {
+ return;
+ }
+ }
+ this->Makefile->GetOrCreateSource(filename);
+ }
+ srcFiles += sep;
+ srcFiles += filename;
+ sep = ";";
+ }
+ if (!srcFiles.empty()) {
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->SourceEntries.push_back(srcFiles);
+ this->Internal->SourceBacktraces.push_back(lfbt);
+ }
+}
+
+std::string cmTarget::ProcessSourceItemCMP0049(const std::string& s)
+{
+ std::string src = s;
+
+ // For backwards compatibility replace varibles in source names.
+ // This should eventually be removed.
+ this->Makefile->ExpandVariablesInString(src);
+ if (src != s) {
+ std::ostringstream e;
+ bool noMessage = false;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0049)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0049) << "\n";
+ break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ messageType = cmake::FATAL_ERROR;
+ }
+ if (!noMessage) {
+ e << "Legacy variable expansion in source file \"" << s
+ << "\" expanded to \"" << src << "\" in target \"" << this->GetName()
+ << "\". This behavior will be removed in a "
+ "future version of CMake.";
+ this->Makefile->IssueMessage(messageType, e.str());
+ if (messageType == cmake::FATAL_ERROR) {
+ return "";
+ }
+ }
+ }
+ return src;
+}
+
+cmSourceFile* cmTarget::AddSourceCMP0049(const std::string& s)
+{
+ std::string src = this->ProcessSourceItemCMP0049(s);
+ if (!s.empty() && src.empty()) {
+ return CM_NULLPTR;
+ }
+ return this->AddSource(src);
+}
+
+struct CreateLocation
+{
+ cmMakefile const* Makefile;
+
+ CreateLocation(cmMakefile const* mf)
+ : Makefile(mf)
+ {
+ }
+
+ cmSourceFileLocation operator()(const std::string& filename)
+ {
+ return cmSourceFileLocation(this->Makefile, filename);
+ }
+};
+
+struct LocationMatcher
+{
+ const cmSourceFileLocation& Needle;
+
+ LocationMatcher(const cmSourceFileLocation& needle)
+ : Needle(needle)
+ {
+ }
+
+ bool operator()(cmSourceFileLocation& loc)
+ {
+ return loc.Matches(this->Needle);
+ }
+};
+
+struct TargetPropertyEntryFinder
+{
+private:
+ const cmSourceFileLocation& Needle;
+
+public:
+ TargetPropertyEntryFinder(const cmSourceFileLocation& needle)
+ : Needle(needle)
+ {
+ }
+
+ bool operator()(std::string const& entry)
+ {
+ std::vector<std::string> files;
+ cmSystemTools::ExpandListArgument(entry, files);
+ std::vector<cmSourceFileLocation> locations(files.size());
+ std::transform(files.begin(), files.end(), locations.begin(),
+ CreateLocation(this->Needle.GetMakefile()));
+
+ return std::find_if(locations.begin(), locations.end(),
+ LocationMatcher(this->Needle)) != locations.end();
+ }
+};
+
+cmSourceFile* cmTarget::AddSource(const std::string& src)
+{
+ cmSourceFileLocation sfl(this->Makefile, src);
+ if (std::find_if(this->Internal->SourceEntries.begin(),
+ this->Internal->SourceEntries.end(),
+ TargetPropertyEntryFinder(sfl)) ==
+ this->Internal->SourceEntries.end()) {
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->SourceEntries.push_back(src);
+ this->Internal->SourceBacktraces.push_back(lfbt);
+ }
+ if (cmGeneratorExpression::Find(src) != std::string::npos) {
+ return CM_NULLPTR;
+ }
+ return this->Makefile->GetOrCreateSource(src);
+}
+
+void cmTarget::MergeLinkLibraries(cmMakefile& mf, const std::string& selfname,
+ const LinkLibraryVectorType& libs)
+{
+ // Only add on libraries we haven't added on before.
+ // Assumption: the global link libraries could only grow, never shrink
+ LinkLibraryVectorType::const_iterator i = libs.begin();
+ i += this->PrevLinkedLibraries.size();
+ for (; i != libs.end(); ++i) {
+ // This is equivalent to the target_link_libraries plain signature.
+ this->AddLinkLibrary(mf, selfname, i->first, i->second);
+ this->AppendProperty(
+ "INTERFACE_LINK_LIBRARIES",
+ this->GetDebugGeneratorExpressions(i->first, i->second).c_str());
+ }
+ this->PrevLinkedLibraries = libs;
+}
+
+void cmTarget::AddLinkDirectory(const std::string& d)
+{
+ // Make sure we don't add unnecessary search directories.
+ if (this->LinkDirectoriesEmmitted.insert(d).second) {
+ this->LinkDirectories.push_back(d);
+ }
+}
+
+const std::vector<std::string>& cmTarget::GetLinkDirectories() const
+{
+ return this->LinkDirectories;
+}
+
+void cmTarget::ClearDependencyInformation(cmMakefile& mf,
+ const std::string& target)
+{
+ // Clear the dependencies. The cache variable must exist iff we are
+ // recording dependency information for this target.
+ std::string depname = target;
+ depname += "_LIB_DEPENDS";
+ if (this->RecordDependencies) {
+ mf.AddCacheDefinition(depname, "", "Dependencies for target",
+ cmState::STATIC);
+ } else {
+ if (mf.GetDefinition(depname)) {
+ std::string message = "Target ";
+ message += target;
+ message += " has dependency information when it shouldn't.\n";
+ message += "Your cache is probably stale. Please remove the entry\n ";
+ message += depname;
+ message += "\nfrom the cache.";
+ cmSystemTools::Error(message.c_str());
+ }
+ }
+}
+
+std::string cmTarget::GetDebugGeneratorExpressions(
+ const std::string& value, cmTargetLinkLibraryType llt) const
+{
+ if (llt == GENERAL_LibraryType) {
+ return value;
+ }
+
+ // Get the list of configurations considered to be DEBUG.
+ std::vector<std::string> debugConfigs =
+ this->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 + ">";
+ }
+ configString = "$<OR:" + configString + ">";
+ }
+
+ if (llt == OPTIMIZED_LibraryType) {
+ configString = "$<NOT:" + configString + ">";
+ }
+ return "$<" + configString + ":" + value + ">";
+}
+
+static std::string targetNameGenex(const std::string& lib)
+{
+ return "$<TARGET_NAME:" + lib + ">";
+}
+
+bool cmTarget::PushTLLCommandTrace(TLLSignature signature,
+ cmListFileContext const& lfc)
+{
+ bool ret = true;
+ if (!this->TLLCommands.empty()) {
+ if (this->TLLCommands.back().first != signature) {
+ ret = false;
+ }
+ }
+ if (this->TLLCommands.empty() || this->TLLCommands.back().second != lfc) {
+ this->TLLCommands.push_back(std::make_pair(signature, lfc));
+ }
+ return ret;
+}
+
+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";
+ typedef std::vector<std::pair<TLLSignature, cmListFileContext> > Container;
+ cmOutputConverter converter(this->GetMakefile()->GetStateSnapshot());
+ for (Container::const_iterator it = this->TLLCommands.begin();
+ it != this->TLLCommands.end(); ++it) {
+ if (it->first == sig) {
+ cmListFileContext lfc = it->second;
+ lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME);
+ s << " * " << lfc << std::endl;
+ }
+ }
+}
+
+void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& target,
+ const std::string& lib,
+ cmTargetLinkLibraryType llt)
+{
+ cmTarget* tgt = this->Makefile->FindTargetToUse(lib);
+ {
+ const bool isNonImportedTarget = tgt && !tgt->IsImported();
+
+ const std::string libName =
+ (isNonImportedTarget && llt != GENERAL_LibraryType)
+ ? targetNameGenex(lib)
+ : lib;
+ this->AppendProperty(
+ "LINK_LIBRARIES",
+ this->GetDebugGeneratorExpressions(libName, llt).c_str());
+ }
+
+ if (cmGeneratorExpression::Find(lib) != std::string::npos ||
+ (tgt && tgt->GetType() == cmState::INTERFACE_LIBRARY) ||
+ (target == lib)) {
+ return;
+ }
+
+ cmTarget::LibraryID tmp;
+ tmp.first = lib;
+ tmp.second = llt;
+ this->OriginalLinkLibraries.push_back(tmp);
+
+ // Add the explicit dependency information for this target. This is
+ // simply a set of libraries separated by ";". There should always
+ // be a trailing ";". These library names are not canonical, in that
+ // they may be "-framework x", "-ly", "/path/libz.a", etc.
+ // We shouldn't remove duplicates here because external libraries
+ // may be purposefully duplicated to handle recursive dependencies,
+ // and we removing one instance will break the link line. Duplicates
+ // will be appropriately eliminated at emit time.
+ if (this->RecordDependencies) {
+ std::string targetEntry = target;
+ targetEntry += "_LIB_DEPENDS";
+ std::string dependencies;
+ const char* old_val = mf.GetDefinition(targetEntry);
+ if (old_val) {
+ dependencies += old_val;
+ }
+ switch (llt) {
+ case GENERAL_LibraryType:
+ dependencies += "general";
+ break;
+ case DEBUG_LibraryType:
+ dependencies += "debug";
+ break;
+ case OPTIMIZED_LibraryType:
+ dependencies += "optimized";
+ break;
+ }
+ dependencies += ";";
+ dependencies += lib;
+ dependencies += ";";
+ mf.AddCacheDefinition(targetEntry, dependencies.c_str(),
+ "Dependencies for the target", cmState::STATIC);
+ }
+}
+
+void cmTarget::AddSystemIncludeDirectories(const std::set<std::string>& incs)
+{
+ this->SystemIncludeDirectories.insert(incs.begin(), incs.end());
+}
+
+cmStringRange cmTarget::GetIncludeDirectoriesEntries() const
+{
+ return cmMakeRange(this->Internal->IncludeDirectoriesEntries);
+}
+
+cmBacktraceRange cmTarget::GetIncludeDirectoriesBacktraces() const
+{
+ return cmMakeRange(this->Internal->IncludeDirectoriesBacktraces);
+}
+
+cmStringRange cmTarget::GetCompileOptionsEntries() const
+{
+ return cmMakeRange(this->Internal->CompileOptionsEntries);
+}
+
+cmBacktraceRange cmTarget::GetCompileOptionsBacktraces() const
+{
+ return cmMakeRange(this->Internal->CompileOptionsBacktraces);
+}
+
+cmStringRange cmTarget::GetCompileFeaturesEntries() const
+{
+ return cmMakeRange(this->Internal->CompileFeaturesEntries);
+}
+
+cmBacktraceRange cmTarget::GetCompileFeaturesBacktraces() const
+{
+ return cmMakeRange(this->Internal->CompileFeaturesBacktraces);
+}
+
+cmStringRange cmTarget::GetCompileDefinitionsEntries() const
+{
+ return cmMakeRange(this->Internal->CompileDefinitionsEntries);
+}
+
+cmBacktraceRange cmTarget::GetCompileDefinitionsBacktraces() const
+{
+ return cmMakeRange(this->Internal->CompileDefinitionsBacktraces);
+}
+
+cmStringRange cmTarget::GetSourceEntries() const
+{
+ return cmMakeRange(this->Internal->SourceEntries);
+}
+
+cmBacktraceRange cmTarget::GetSourceBacktraces() const
+{
+ return cmMakeRange(this->Internal->SourceBacktraces);
+}
+
+cmStringRange cmTarget::GetLinkImplementationEntries() const
+{
+ return cmMakeRange(this->Internal->LinkImplementationPropertyEntries);
+}
+
+cmBacktraceRange cmTarget::GetLinkImplementationBacktraces() const
+{
+ return cmMakeRange(this->Internal->LinkImplementationPropertyBacktraces);
+}
+
+static bool whiteListedInterfaceProperty(const std::string& prop)
+{
+ if (cmHasLiteralPrefix(prop, "INTERFACE_")) {
+ return true;
+ }
+ static UNORDERED_SET<std::string> builtIns;
+ if (builtIns.empty()) {
+ builtIns.insert("COMPATIBLE_INTERFACE_BOOL");
+ builtIns.insert("COMPATIBLE_INTERFACE_NUMBER_MAX");
+ builtIns.insert("COMPATIBLE_INTERFACE_NUMBER_MIN");
+ builtIns.insert("COMPATIBLE_INTERFACE_STRING");
+ builtIns.insert("EXPORT_NAME");
+ builtIns.insert("IMPORTED");
+ builtIns.insert("NAME");
+ builtIns.insert("TYPE");
+ }
+
+ if (builtIns.count(prop)) {
+ return true;
+ }
+
+ if (cmHasLiteralPrefix(prop, "MAP_IMPORTED_CONFIG_")) {
+ return true;
+ }
+
+ return false;
+}
+
+void cmTarget::SetProperty(const std::string& prop, const char* value)
+{
+ if (this->GetType() == cmState::INTERFACE_LIBRARY &&
+ !whiteListedInterfaceProperty(prop)) {
+ std::ostringstream e;
+ e << "INTERFACE_LIBRARY targets may only have whitelisted properties. "
+ "The property \""
+ << prop << "\" is not allowed.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ } else if (prop == "NAME") {
+ std::ostringstream e;
+ e << "NAME property is read-only\n";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ } else if (prop == "INCLUDE_DIRECTORIES") {
+ this->Internal->IncludeDirectoriesEntries.clear();
+ this->Internal->IncludeDirectoriesBacktraces.clear();
+ if (value) {
+ this->Internal->IncludeDirectoriesEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "COMPILE_OPTIONS") {
+ this->Internal->CompileOptionsEntries.clear();
+ this->Internal->CompileOptionsBacktraces.clear();
+ if (value) {
+ this->Internal->CompileOptionsEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->CompileOptionsBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "COMPILE_FEATURES") {
+ this->Internal->CompileFeaturesEntries.clear();
+ this->Internal->CompileFeaturesBacktraces.clear();
+ if (value) {
+ this->Internal->CompileFeaturesEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->CompileFeaturesBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "COMPILE_DEFINITIONS") {
+ this->Internal->CompileDefinitionsEntries.clear();
+ this->Internal->CompileDefinitionsBacktraces.clear();
+ if (value) {
+ this->Internal->CompileDefinitionsEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
+ }
+ } else 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(cmake::FATAL_ERROR, e.str());
+ } else if (prop == "LINK_LIBRARIES") {
+ this->Internal->LinkImplementationPropertyEntries.clear();
+ this->Internal->LinkImplementationPropertyBacktraces.clear();
+ if (value) {
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->LinkImplementationPropertyEntries.push_back(value);
+ this->Internal->LinkImplementationPropertyBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "SOURCES") {
+ if (this->IsImported()) {
+ std::ostringstream e;
+ e << "SOURCES property can't be set on imported targets (\""
+ << this->Name << "\")\n";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+
+ this->Internal->SourceEntries.clear();
+ this->Internal->SourceBacktraces.clear();
+ if (value) {
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->SourceEntries.push_back(value);
+ this->Internal->SourceBacktraces.push_back(lfbt);
+ }
+ } else {
+ this->Properties.SetProperty(prop, value);
+ }
+}
+
+void cmTarget::AppendProperty(const std::string& prop, const char* value,
+ bool asString)
+{
+ if (this->GetType() == cmState::INTERFACE_LIBRARY &&
+ !whiteListedInterfaceProperty(prop)) {
+ std::ostringstream e;
+ e << "INTERFACE_LIBRARY targets may only have whitelisted properties. "
+ "The property \""
+ << prop << "\" is not allowed.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ } else if (prop == "NAME") {
+ std::ostringstream e;
+ e << "NAME property is read-only\n";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ } else if (prop == "INCLUDE_DIRECTORIES") {
+ if (value && *value) {
+ this->Internal->IncludeDirectoriesEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "COMPILE_OPTIONS") {
+ if (value && *value) {
+ this->Internal->CompileOptionsEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->CompileOptionsBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "COMPILE_FEATURES") {
+ if (value && *value) {
+ this->Internal->CompileFeaturesEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->CompileFeaturesBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "COMPILE_DEFINITIONS") {
+ if (value && *value) {
+ this->Internal->CompileDefinitionsEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
+ }
+ } else 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(cmake::FATAL_ERROR, e.str());
+ } else if (prop == "LINK_LIBRARIES") {
+ if (value && *value) {
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->LinkImplementationPropertyEntries.push_back(value);
+ this->Internal->LinkImplementationPropertyBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "SOURCES") {
+ if (this->IsImported()) {
+ std::ostringstream e;
+ e << "SOURCES property can't be set on imported targets (\""
+ << this->Name << "\")\n";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->SourceEntries.push_back(value);
+ this->Internal->SourceBacktraces.push_back(lfbt);
+ } else {
+ this->Properties.AppendProperty(prop, value, asString);
+ }
+}
+
+void cmTarget::AppendBuildInterfaceIncludes()
+{
+ if (this->GetType() != cmState::SHARED_LIBRARY &&
+ this->GetType() != cmState::STATIC_LIBRARY &&
+ this->GetType() != cmState::MODULE_LIBRARY &&
+ this->GetType() != cmState::INTERFACE_LIBRARY &&
+ !this->IsExecutableWithExports()) {
+ return;
+ }
+ if (this->BuildInterfaceIncludesAppended) {
+ return;
+ }
+ this->BuildInterfaceIncludesAppended = true;
+
+ if (this->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) {
+ const char* binDir = this->Makefile->GetCurrentBinaryDirectory();
+ const char* srcDir = this->Makefile->GetCurrentSourceDirectory();
+ const std::string dirs = std::string(binDir ? binDir : "") +
+ std::string(binDir ? ";" : "") + std::string(srcDir ? srcDir : "");
+ if (!dirs.empty()) {
+ this->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
+ ("$<BUILD_INTERFACE:" + dirs + ">").c_str());
+ }
+ }
+}
+
+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();
+
+ std::vector<cmListFileBacktrace>::iterator btPosition = before
+ ? this->Internal->IncludeDirectoriesBacktraces.begin()
+ : this->Internal->IncludeDirectoriesBacktraces.end();
+
+ this->Internal->IncludeDirectoriesEntries.insert(position, entry);
+ this->Internal->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();
+
+ std::vector<cmListFileBacktrace>::iterator btPosition = before
+ ? this->Internal->CompileOptionsBacktraces.begin()
+ : this->Internal->CompileOptionsBacktraces.end();
+
+ this->Internal->CompileOptionsEntries.insert(position, entry);
+ this->Internal->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);
+}
+
+static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
+ const char* value,
+ cmMakefile* context,
+ bool imported)
+{
+ // Look for link-type keywords in the value.
+ static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)");
+ if (!keys.find(value)) {
+ return;
+ }
+
+ // Support imported and non-imported versions of the property.
+ const char* base = (imported ? "IMPORTED_LINK_INTERFACE_LIBRARIES"
+ : "LINK_INTERFACE_LIBRARIES");
+
+ // Report an error.
+ std::ostringstream e;
+ e << "Property " << prop << " may not contain link-type keyword \""
+ << keys.match(2) << "\". "
+ << "The " << base << " property has a per-configuration "
+ << "version called " << base << "_<CONFIG> which may be "
+ << "used to specify per-configuration rules.";
+ if (!imported) {
+ e << " "
+ << "Alternatively, an IMPORTED library may be created, configured "
+ << "with a per-configuration location, and then named in the "
+ << "property value. "
+ << "See the add_library command's IMPORTED mode for details."
+ << "\n"
+ << "If you have a list of libraries that already contains the "
+ << "keyword, use the target_link_libraries command with its "
+ << "LINK_INTERFACE_LIBRARIES mode to set the property. "
+ << "The command automatically recognizes link-type keywords and sets "
+ << "the LINK_INTERFACE_LIBRARIES and LINK_INTERFACE_LIBRARIES_DEBUG "
+ << "properties accordingly.";
+ }
+ context->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+static void cmTargetCheckINTERFACE_LINK_LIBRARIES(const char* value,
+ cmMakefile* context)
+{
+ // Look for link-type keywords in the value.
+ static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)");
+ if (!keys.find(value)) {
+ return;
+ }
+
+ // Report an error.
+ std::ostringstream e;
+
+ e << "Property INTERFACE_LINK_LIBRARIES may not contain link-type "
+ "keyword \""
+ << keys.match(2)
+ << "\". The INTERFACE_LINK_LIBRARIES "
+ "property may contain configuration-sensitive generator-expressions "
+ "which may be used to specify per-configuration rules.";
+
+ context->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+void cmTarget::CheckProperty(const std::string& prop,
+ cmMakefile* context) const
+{
+ // Certain properties need checking.
+ if (cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES")) {
+ if (const char* value = this->GetProperty(prop)) {
+ cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, value, context, false);
+ }
+ }
+ if (cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES")) {
+ if (const char* value = this->GetProperty(prop)) {
+ cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, value, context, true);
+ }
+ }
+ if (cmHasLiteralPrefix(prop, "INTERFACE_LINK_LIBRARIES")) {
+ if (const char* value = this->GetProperty(prop)) {
+ cmTargetCheckINTERFACE_LINK_LIBRARIES(value, context);
+ }
+ }
+}
+
+void cmTarget::MarkAsImported(bool global)
+{
+ this->IsImportedTarget = true;
+ this->ImportedGloballyVisible = global;
+}
+
+bool cmTarget::HandleLocationPropertyPolicy(cmMakefile* context) const
+{
+ if (this->IsImported()) {
+ return true;
+ }
+ std::ostringstream e;
+ const char* modal = CM_NULLPTR;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ switch (context->GetPolicyStatus(cmPolicies::CMP0026)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0026) << "\n";
+ modal = "should";
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ modal = "may";
+ messageType = cmake::FATAL_ERROR;
+ }
+
+ if (modal) {
+ e << "The LOCATION property " << modal << " not be read from target \""
+ << this->GetName()
+ << "\". Use the target name directly with "
+ "add_custom_command, or use the generator expression $<TARGET_FILE>, "
+ "as appropriate.\n";
+ context->IssueMessage(messageType, e.str());
+ }
+
+ return messageType != cmake::FATAL_ERROR;
+}
+
+const char* cmTarget::GetProperty(const std::string& prop) const
+{
+ return this->GetProperty(prop, this->Makefile);
+}
+
+const char* cmTarget::GetProperty(const std::string& prop,
+ cmMakefile* context) const
+{
+ if (this->GetType() == cmState::INTERFACE_LIBRARY &&
+ !whiteListedInterfaceProperty(prop)) {
+ std::ostringstream e;
+ e << "INTERFACE_LIBRARY targets may only have whitelisted properties. "
+ "The property \""
+ << prop << "\" is not allowed.";
+ context->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return CM_NULLPTR;
+ }
+
+ // Watch for special "computed" properties that are dependent on
+ // other properties or variables. Always recompute them.
+ if (this->GetType() == cmState::EXECUTABLE ||
+ this->GetType() == cmState::STATIC_LIBRARY ||
+ this->GetType() == cmState::SHARED_LIBRARY ||
+ this->GetType() == cmState::MODULE_LIBRARY ||
+ this->GetType() == cmState::UNKNOWN_LIBRARY) {
+ static const std::string propLOCATION = "LOCATION";
+ if (prop == propLOCATION) {
+ if (!this->HandleLocationPropertyPolicy(context)) {
+ return CM_NULLPTR;
+ }
+
+ // Set the LOCATION property of the target.
+ //
+ // For an imported target this is the location of an arbitrary
+ // available configuration.
+ //
+ if (this->IsImported()) {
+ this->Properties.SetProperty(
+ propLOCATION, this->ImportedGetFullPath("", false).c_str());
+ } else {
+ // For a non-imported target this is deprecated because it
+ // cannot take into account the per-configuration name of the
+ // target because the configuration type may not be known at
+ // CMake time.
+ cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ if (!gg->GetConfigureDoneCMP0026()) {
+ gg->CreateGenerationObjects();
+ }
+ cmGeneratorTarget* gt = gg->FindGeneratorTarget(this->GetName());
+ this->Properties.SetProperty(propLOCATION, gt->GetLocationForBuild());
+ }
+
+ }
+
+ // Support "LOCATION_<CONFIG>".
+ else if (cmHasLiteralPrefix(prop, "LOCATION_")) {
+ if (!this->HandleLocationPropertyPolicy(context)) {
+ return CM_NULLPTR;
+ }
+ const char* configName = prop.c_str() + 9;
+
+ if (this->IsImported()) {
+ this->Properties.SetProperty(
+ prop, this->ImportedGetFullPath(configName, false).c_str());
+ } else {
+ cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ if (!gg->GetConfigureDoneCMP0026()) {
+ gg->CreateGenerationObjects();
+ }
+ cmGeneratorTarget* gt = gg->FindGeneratorTarget(this->GetName());
+ this->Properties.SetProperty(
+ prop, gt->GetFullPath(configName, false).c_str());
+ }
+ }
+ // Support "<CONFIG>_LOCATION".
+ else if (cmHasLiteralSuffix(prop, "_LOCATION")) {
+ std::string configName(prop.c_str(), prop.size() - 9);
+ if (configName != "IMPORTED") {
+ if (!this->HandleLocationPropertyPolicy(context)) {
+ return CM_NULLPTR;
+ }
+ if (this->IsImported()) {
+ this->Properties.SetProperty(
+ prop, this->ImportedGetFullPath(configName, false).c_str());
+ } else {
+ cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ if (!gg->GetConfigureDoneCMP0026()) {
+ gg->CreateGenerationObjects();
+ }
+ cmGeneratorTarget* gt = gg->FindGeneratorTarget(this->GetName());
+ this->Properties.SetProperty(
+ prop, gt->GetFullPath(configName, false).c_str());
+ }
+ }
+ }
+ }
+ static UNORDERED_SET<std::string> specialProps;
+#define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP
+ MAKE_STATIC_PROP(LINK_LIBRARIES);
+ MAKE_STATIC_PROP(TYPE);
+ MAKE_STATIC_PROP(INCLUDE_DIRECTORIES);
+ MAKE_STATIC_PROP(COMPILE_FEATURES);
+ MAKE_STATIC_PROP(COMPILE_OPTIONS);
+ MAKE_STATIC_PROP(COMPILE_DEFINITIONS);
+ MAKE_STATIC_PROP(IMPORTED);
+ MAKE_STATIC_PROP(NAME);
+ MAKE_STATIC_PROP(BINARY_DIR);
+ MAKE_STATIC_PROP(SOURCE_DIR);
+ MAKE_STATIC_PROP(SOURCES);
+#undef MAKE_STATIC_PROP
+ if (specialProps.empty()) {
+ specialProps.insert(propLINK_LIBRARIES);
+ specialProps.insert(propTYPE);
+ specialProps.insert(propINCLUDE_DIRECTORIES);
+ specialProps.insert(propCOMPILE_FEATURES);
+ specialProps.insert(propCOMPILE_OPTIONS);
+ specialProps.insert(propCOMPILE_DEFINITIONS);
+ specialProps.insert(propIMPORTED);
+ specialProps.insert(propNAME);
+ specialProps.insert(propBINARY_DIR);
+ specialProps.insert(propSOURCE_DIR);
+ specialProps.insert(propSOURCES);
+ }
+ if (specialProps.count(prop)) {
+ if (prop == propLINK_LIBRARIES) {
+ if (this->Internal->LinkImplementationPropertyEntries.empty()) {
+ return CM_NULLPTR;
+ }
+
+ static std::string output;
+ output = cmJoin(this->Internal->LinkImplementationPropertyEntries, ";");
+ return output.c_str();
+ }
+ // the type property returns what type the target is
+ else if (prop == propTYPE) {
+ return cmState::GetTargetTypeName(this->GetType());
+ } else if (prop == propINCLUDE_DIRECTORIES) {
+ if (this->Internal->IncludeDirectoriesEntries.empty()) {
+ return CM_NULLPTR;
+ }
+
+ static std::string output;
+ output = cmJoin(this->Internal->IncludeDirectoriesEntries, ";");
+ return output.c_str();
+ } else if (prop == propCOMPILE_FEATURES) {
+ if (this->Internal->CompileFeaturesEntries.empty()) {
+ return CM_NULLPTR;
+ }
+
+ static std::string output;
+ output = cmJoin(this->Internal->CompileFeaturesEntries, ";");
+ return output.c_str();
+ } else if (prop == propCOMPILE_OPTIONS) {
+ if (this->Internal->CompileOptionsEntries.empty()) {
+ return CM_NULLPTR;
+ }
+
+ static std::string output;
+ output = cmJoin(this->Internal->CompileOptionsEntries, ";");
+ return output.c_str();
+ } else if (prop == propCOMPILE_DEFINITIONS) {
+ if (this->Internal->CompileDefinitionsEntries.empty()) {
+ return CM_NULLPTR;
+ }
+
+ static std::string output;
+ output = cmJoin(this->Internal->CompileDefinitionsEntries, ";");
+ return output.c_str();
+ } else if (prop == propIMPORTED) {
+ return this->IsImported() ? "TRUE" : "FALSE";
+ } else if (prop == propNAME) {
+ return this->GetName().c_str();
+ } else if (prop == propBINARY_DIR) {
+ return this->GetMakefile()->GetCurrentBinaryDirectory();
+ } else if (prop == propSOURCE_DIR) {
+ return this->GetMakefile()->GetCurrentSourceDirectory();
+ } else if (prop == propSOURCES) {
+ if (this->Internal->SourceEntries.empty()) {
+ return CM_NULLPTR;
+ }
+
+ std::ostringstream ss;
+ const char* sep = "";
+ for (std::vector<std::string>::const_iterator i =
+ this->Internal->SourceEntries.begin();
+ i != this->Internal->SourceEntries.end(); ++i) {
+ std::string const& entry = *i;
+
+ std::vector<std::string> files;
+ cmSystemTools::ExpandListArgument(entry, files);
+ for (std::vector<std::string>::const_iterator li = files.begin();
+ li != files.end(); ++li) {
+ if (cmHasLiteralPrefix(*li, "$<TARGET_OBJECTS:") &&
+ (*li)[li->size() - 1] == '>') {
+ std::string objLibName = li->substr(17, li->size() - 18);
+
+ if (cmGeneratorExpression::Find(objLibName) != std::string::npos) {
+ ss << sep;
+ sep = ";";
+ ss << *li;
+ continue;
+ }
+
+ bool addContent = false;
+ bool noMessage = true;
+ std::ostringstream e;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ switch (context->GetPolicyStatus(cmPolicies::CMP0051)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0051) << "\n";
+ noMessage = false;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ addContent = true;
+ }
+ if (!noMessage) {
+ e << "Target \"" << this->Name
+ << "\" contains "
+ "$<TARGET_OBJECTS> generator expression in its sources "
+ "list. "
+ "This content was not previously part of the SOURCES "
+ "property "
+ "when that property was read at configure time. Code "
+ "reading "
+ "that property needs to be adapted to ignore the generator "
+ "expression using the string(GENEX_STRIP) command.";
+ context->IssueMessage(messageType, e.str());
+ }
+ if (addContent) {
+ ss << sep;
+ sep = ";";
+ ss << *li;
+ }
+ } else if (cmGeneratorExpression::Find(*li) == std::string::npos) {
+ ss << sep;
+ sep = ";";
+ ss << *li;
+ } else {
+ cmSourceFile* sf = this->Makefile->GetOrCreateSource(*li);
+ // Construct what is known about this source file location.
+ cmSourceFileLocation const& location = sf->GetLocation();
+ std::string sname = location.GetDirectory();
+ if (!sname.empty()) {
+ sname += "/";
+ }
+ sname += location.GetName();
+
+ ss << sep;
+ sep = ";";
+ // Append this list entry.
+ ss << sname;
+ }
+ }
+ }
+ this->Properties.SetProperty("SOURCES", ss.str().c_str());
+ }
+ }
+
+ const char* retVal = this->Properties.GetPropertyValue(prop);
+ if (!retVal) {
+ const bool chain = this->GetMakefile()->GetState()->IsPropertyChained(
+ prop, cmProperty::TARGET);
+ if (chain) {
+ return this->Makefile->GetProperty(prop, chain);
+ }
+ }
+ return retVal;
+}
+
+bool cmTarget::GetPropertyAsBool(const std::string& prop) const
+{
+ return cmSystemTools::IsOn(this->GetProperty(prop));
+}
+
+const char* cmTarget::GetSuffixVariableInternal(bool implib) const
+{
+ switch (this->GetType()) {
+ case cmState::STATIC_LIBRARY:
+ return "CMAKE_STATIC_LIBRARY_SUFFIX";
+ case cmState::SHARED_LIBRARY:
+ return (implib ? "CMAKE_IMPORT_LIBRARY_SUFFIX"
+ : "CMAKE_SHARED_LIBRARY_SUFFIX");
+ case cmState::MODULE_LIBRARY:
+ return (implib ? "CMAKE_IMPORT_LIBRARY_SUFFIX"
+ : "CMAKE_SHARED_MODULE_SUFFIX");
+ case cmState::EXECUTABLE:
+ return (implib
+ ? "CMAKE_IMPORT_LIBRARY_SUFFIX"
+ // Android GUI application packages store the native
+ // binary as a shared library.
+ : (this->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
+ ? "CMAKE_SHARED_LIBRARY_SUFFIX"
+ : "CMAKE_EXECUTABLE_SUFFIX"));
+ default:
+ break;
+ }
+ return "";
+}
+
+const char* cmTarget::GetPrefixVariableInternal(bool implib) const
+{
+ switch (this->GetType()) {
+ case cmState::STATIC_LIBRARY:
+ return "CMAKE_STATIC_LIBRARY_PREFIX";
+ case cmState::SHARED_LIBRARY:
+ return (implib ? "CMAKE_IMPORT_LIBRARY_PREFIX"
+ : "CMAKE_SHARED_LIBRARY_PREFIX");
+ case cmState::MODULE_LIBRARY:
+ return (implib ? "CMAKE_IMPORT_LIBRARY_PREFIX"
+ : "CMAKE_SHARED_MODULE_PREFIX");
+ case cmState::EXECUTABLE:
+ return (implib
+ ? "CMAKE_IMPORT_LIBRARY_PREFIX"
+ // Android GUI application packages store the native
+ // binary as a shared library.
+ : (this->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
+ ? "CMAKE_SHARED_LIBRARY_PREFIX"
+ : ""));
+ default:
+ break;
+ }
+ return "";
+}
+
+std::string cmTarget::ImportedGetFullPath(const std::string& config,
+ bool pimplib) const
+{
+ assert(this->IsImported());
+
+ // Lookup/compute/cache the import information for this
+ // configuration.
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ } else {
+ config_upper = "NOCONFIG";
+ }
+
+ std::string result;
+
+ const char* loc = CM_NULLPTR;
+ const char* imp = CM_NULLPTR;
+ std::string suffix;
+
+ if (this->GetType() != cmState::INTERFACE_LIBRARY &&
+ this->GetMappedConfig(config_upper, &loc, &imp, suffix)) {
+ if (!pimplib) {
+ if (loc) {
+ result = loc;
+ } else {
+ std::string impProp = "IMPORTED_LOCATION";
+ impProp += suffix;
+ if (const char* config_location = this->GetProperty(impProp)) {
+ result = config_location;
+ } else if (const char* location =
+ this->GetProperty("IMPORTED_LOCATION")) {
+ result = location;
+ }
+ }
+ } else {
+ if (imp) {
+ result = imp;
+ } else if (this->GetType() == cmState::SHARED_LIBRARY ||
+ this->IsExecutableWithExports()) {
+ std::string impProp = "IMPORTED_IMPLIB";
+ impProp += suffix;
+ if (const char* config_implib = this->GetProperty(impProp)) {
+ result = config_implib;
+ } else if (const char* implib = this->GetProperty("IMPORTED_IMPLIB")) {
+ result = implib;
+ }
+ }
+ }
+ }
+
+ if (result.empty()) {
+ result = this->GetName();
+ result += "-NOTFOUND";
+ }
+ 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::GetMappedConfig(std::string const& desired_config,
+ const char** loc, const char** imp,
+ std::string& suffix) const
+{
+ if (this->GetType() == cmState::INTERFACE_LIBRARY) {
+ // This method attempts to find a config-specific LOCATION for the
+ // IMPORTED library. In the case of cmState::INTERFACE_LIBRARY, there is no
+ // LOCATION at all, so leaving *loc and *imp unchanged is the appropriate
+ // and valid response.
+ return true;
+ }
+
+ // Track the configuration-specific property suffix.
+ suffix = "_";
+ suffix += desired_config;
+
+ std::vector<std::string> mappedConfigs;
+ {
+ std::string mapProp = "MAP_IMPORTED_CONFIG_";
+ mapProp += desired_config;
+ if (const char* mapValue = this->GetProperty(mapProp)) {
+ cmSystemTools::ExpandListArgument(mapValue, mappedConfigs);
+ }
+ }
+
+ // 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();
+
+ // If a mapping was found, check its configurations.
+ for (std::vector<std::string>::const_iterator mci = mappedConfigs.begin();
+ !*loc && !*imp && mci != mappedConfigs.end(); ++mci) {
+ // Look for this configuration.
+ std::string mcUpper = cmSystemTools::UpperCase(*mci);
+ std::string locProp = "IMPORTED_LOCATION_";
+ locProp += mcUpper;
+ *loc = this->GetProperty(locProp);
+ if (allowImp) {
+ std::string impProp = "IMPORTED_IMPLIB_";
+ impProp += mcUpper;
+ *imp = this->GetProperty(impProp);
+ }
+
+ // If it was found, use it for all properties below.
+ if (*loc || *imp) {
+ suffix = "_";
+ suffix += mcUpper;
+ }
+ }
+
+ // If we needed to find one of the mapped configurations but did not
+ // then the target is not found. The project does not want any
+ // other configuration.
+ if (!mappedConfigs.empty() && !*loc && !*imp) {
+ return false;
+ }
+
+ // If we have not yet found it then there are no mapped
+ // configurations. Look for an exact-match.
+ if (!*loc && !*imp) {
+ std::string locProp = "IMPORTED_LOCATION";
+ locProp += suffix;
+ *loc = this->GetProperty(locProp);
+ if (allowImp) {
+ std::string impProp = "IMPORTED_IMPLIB";
+ impProp += suffix;
+ *imp = this->GetProperty(impProp);
+ }
+ }
+
+ // If we have not yet found it then there are no mapped
+ // configurations and no exact match.
+ if (!*loc && !*imp) {
+ // The suffix computed above is not useful.
+ suffix = "";
+
+ // Look for a configuration-less location. This may be set by
+ // manually-written code.
+ *loc = this->GetProperty("IMPORTED_LOCATION");
+ if (allowImp) {
+ *imp = this->GetProperty("IMPORTED_IMPLIB");
+ }
+ }
+
+ // If we have not yet found it then the project is willing to try
+ // any available configuration.
+ if (!*loc && !*imp) {
+ std::vector<std::string> availableConfigs;
+ if (const char* iconfigs = this->GetProperty("IMPORTED_CONFIGURATIONS")) {
+ cmSystemTools::ExpandListArgument(iconfigs, availableConfigs);
+ }
+ for (std::vector<std::string>::const_iterator aci =
+ availableConfigs.begin();
+ !*loc && !*imp && aci != availableConfigs.end(); ++aci) {
+ suffix = "_";
+ suffix += cmSystemTools::UpperCase(*aci);
+ std::string locProp = "IMPORTED_LOCATION";
+ locProp += suffix;
+ *loc = this->GetProperty(locProp);
+ if (allowImp) {
+ std::string impProp = "IMPORTED_IMPLIB";
+ impProp += suffix;
+ *imp = this->GetProperty(impProp);
+ }
+ }
+ }
+ // If we have not yet found it then the target is not available.
+ if (!*loc && !*imp) {
+ return false;
+ }
+
+ 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
new file mode 100644
index 0000000..209a729
--- /dev/null
+++ b/Source/cmTarget.h
@@ -0,0 +1,350 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmTarget_h
+#define cmTarget_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmCustomCommand.h"
+#include "cmListFileCache.h"
+#include "cmPolicies.h"
+#include "cmPropertyMap.h"
+
+#include <cm_auto_ptr.hxx>
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+#include <unordered_map>
+#else
+#include <cmsys/hash_map.hxx>
+#endif
+#endif
+
+class cmake;
+class cmMakefile;
+class cmSourceFile;
+class cmGlobalGenerator;
+class cmListFileBacktrace;
+class cmTarget;
+class cmGeneratorTarget;
+class cmTargetTraceDependencies;
+
+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.
+ */
+class cmTarget
+{
+public:
+ cmTarget();
+ enum CustomCommandType
+ {
+ PRE_BUILD,
+ PRE_LINK,
+ POST_BUILD
+ };
+
+ /**
+ * Return the type of target.
+ */
+ cmState::TargetType GetType() const { return this->TargetTypeValue; }
+
+ /**
+ * Set the target type
+ */
+ void SetType(cmState::TargetType f, const std::string& name);
+
+ void MarkAsImported(bool global = false);
+
+ ///! Set/Get the name of the target
+ const std::string& GetName() const { return this->Name; }
+
+ ///! Set the cmMakefile that owns this target
+ void SetMakefile(cmMakefile* mf);
+ cmMakefile* GetMakefile() const { return this->Makefile; }
+
+#define DECLARE_TARGET_POLICY(POLICY) \
+ cmPolicies::PolicyStatus GetPolicyStatus##POLICY() const \
+ { \
+ return this->PolicyMap.Get(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);
+ }
+
+ /**
+ * 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);
+
+ //* 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;
+ }
+
+ /**
+ * Clear the dependency information recorded for this target, if any.
+ */
+ void ClearDependencyInformation(cmMakefile& mf, const std::string& target);
+
+ void AddLinkLibrary(cmMakefile& mf, const std::string& target,
+ const std::string& lib, cmTargetLinkLibraryType llt);
+ enum TLLSignature
+ {
+ KeywordTLLSignature,
+ PlainTLLSignature
+ };
+ bool PushTLLCommandTrace(TLLSignature signature,
+ cmListFileContext const& lfc);
+ void GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const;
+
+ void MergeLinkLibraries(cmMakefile& mf, const std::string& selfname,
+ const LinkLibraryVectorType& libs);
+
+ const std::vector<std::string>& GetLinkDirectories() const;
+
+ void AddLinkDirectory(const std::string& d);
+
+ /**
+ * 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; }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Get/Set whether there is an install rule for this target.
+ */
+ bool GetHaveInstallRule() const { return this->HaveInstallRule; }
+ void SetHaveInstallRule(bool h) { this->HaveInstallRule = h; }
+
+ /** 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(const std::string& u, cmMakefile* makefile = CM_NULLPTR);
+ ///! Get the utilities used by this target
+ std::set<std::string> const& GetUtilities() const { return this->Utilities; }
+ cmListFileBacktrace const* GetUtilityBacktrace(const std::string& u) const;
+
+ ///! 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) const;
+ const char* GetProperty(const std::string& prop, cmMakefile* context) const;
+ bool GetPropertyAsBool(const std::string& prop) const;
+ void CheckProperty(const std::string& prop, cmMakefile* context) const;
+
+ bool IsImported() const { return this->IsImportedTarget; }
+ bool IsImportedGloballyVisible() const
+ {
+ return this->ImportedGloballyVisible;
+ }
+
+ // Get the properties
+ cmPropertyMap& GetProperties() const { return this->Properties; }
+
+ 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. */
+ bool IsExecutableWithExports() const;
+
+ /** Return whether this target is a shared library Framework on
+ Apple. */
+ bool IsFrameworkOnApple() const;
+
+ /** Return whether this target is an executable Bundle on Apple. */
+ bool IsAppBundleOnApple() const;
+
+ /** Get a backtrace from the creation of the target. */
+ cmListFileBacktrace const& GetBacktrace() const;
+
+ void InsertInclude(std::string const& entry, cmListFileBacktrace const& bt,
+ bool before = false);
+ void InsertCompileOption(std::string const& entry,
+ cmListFileBacktrace const& bt, bool before = false);
+ void InsertCompileDefinition(std::string const& entry,
+ cmListFileBacktrace const& bt);
+
+ void AppendBuildInterfaceIncludes();
+
+ 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;
+ }
+
+ cmStringRange GetIncludeDirectoriesEntries() const;
+ cmBacktraceRange GetIncludeDirectoriesBacktraces() const;
+
+ cmStringRange GetCompileOptionsEntries() const;
+ cmBacktraceRange GetCompileOptionsBacktraces() const;
+
+ cmStringRange GetCompileFeaturesEntries() const;
+ cmBacktraceRange GetCompileFeaturesBacktraces() const;
+
+ cmStringRange GetCompileDefinitionsEntries() const;
+ cmBacktraceRange GetCompileDefinitionsBacktraces() const;
+
+ cmStringRange GetSourceEntries() const;
+ cmBacktraceRange GetSourceBacktraces() const;
+ cmStringRange GetLinkImplementationEntries() const;
+ cmBacktraceRange GetLinkImplementationBacktraces() const;
+
+ struct StrictTargetComparison
+ {
+ bool operator()(cmTarget const* t1, cmTarget const* t2) const;
+ };
+
+private:
+ bool HandleLocationPropertyPolicy(cmMakefile* context) const;
+
+ const char* GetSuffixVariableInternal(bool implib) const;
+ const char* GetPrefixVariableInternal(bool implib) 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);
+
+ std::string ImportedGetFullPath(const std::string& config,
+ bool implib) const;
+
+private:
+ mutable cmPropertyMap Properties;
+ std::set<std::string> SystemIncludeDirectories;
+ std::set<std::string> LinkDirectoriesEmmitted;
+ std::set<std::string> Utilities;
+ std::map<std::string, cmListFileBacktrace> UtilityBacktraces;
+ cmPolicies::PolicyMap PolicyMap;
+ std::string Name;
+ std::string InstallPath;
+ std::string RuntimeInstallPath;
+ std::vector<std::string> LinkDirectories;
+ std::vector<cmCustomCommand> PreBuildCommands;
+ std::vector<cmCustomCommand> PreLinkCommands;
+ std::vector<cmCustomCommand> PostBuildCommands;
+ std::vector<std::pair<TLLSignature, cmListFileContext> > TLLCommands;
+ LinkLibraryVectorType PrevLinkedLibraries;
+ LinkLibraryVectorType OriginalLinkLibraries;
+ cmMakefile* Makefile;
+ cmTargetInternalPointer Internal;
+ cmState::TargetType TargetTypeValue;
+ bool HaveInstallRule;
+ bool RecordDependencies;
+ 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;
+};
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+typedef std::unordered_map<std::string, cmTarget> cmTargets;
+#else
+typedef cmsys::hash_map<std::string, cmTarget> cmTargets;
+#endif
+#else
+typedef std::map<std::string, cmTarget> cmTargets;
+#endif
+
+class cmTargetSet : public std::set<std::string>
+{
+};
+class cmTargetManifest : public std::map<std::string, cmTargetSet>
+{
+};
+
+#endif
diff --git a/Source/cmTargetCompileDefinitionsCommand.cxx b/Source/cmTargetCompileDefinitionsCommand.cxx
new file mode 100644
index 0000000..0711a5c
--- /dev/null
+++ b/Source/cmTargetCompileDefinitionsCommand.cxx
@@ -0,0 +1,63 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTargetCompileDefinitionsCommand.h"
+
+#include "cmAlgorithms.h"
+
+bool cmTargetCompileDefinitionsCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ return this->HandleArguments(args, "COMPILE_DEFINITIONS");
+}
+
+void cmTargetCompileDefinitionsCommand::HandleImportedTarget(
+ const std::string& tgt)
+{
+ std::ostringstream e;
+ e << "Cannot specify compile definitions for imported target \"" << tgt
+ << "\".";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+void cmTargetCompileDefinitionsCommand::HandleMissingTarget(
+ const std::string& name)
+{
+ std::ostringstream e;
+ e << "Cannot specify compile definitions for target \"" << name
+ << "\" "
+ "which is not built by this project.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+std::string cmTargetCompileDefinitionsCommand::Join(
+ const std::vector<std::string>& content)
+{
+ std::string defs;
+ std::string sep;
+ for (std::vector<std::string>::const_iterator it = content.begin();
+ it != content.end(); ++it) {
+ if (cmHasLiteralPrefix(it->c_str(), "-D")) {
+ defs += sep + it->substr(2);
+ } else {
+ defs += sep + *it;
+ }
+ sep = ";";
+ }
+ return defs;
+}
+
+bool cmTargetCompileDefinitionsCommand::HandleDirectContent(
+ cmTarget* tgt, const std::vector<std::string>& content, bool, bool)
+{
+ tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content).c_str());
+ return true;
+}
diff --git a/Source/cmTargetCompileDefinitionsCommand.h b/Source/cmTargetCompileDefinitionsCommand.h
new file mode 100644
index 0000000..1689a75
--- /dev/null
+++ b/Source/cmTargetCompileDefinitionsCommand.h
@@ -0,0 +1,56 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmTargetCompileDefinitionsCommand_h
+#define cmTargetCompileDefinitionsCommand_h
+
+#include "cmTargetPropCommandBase.h"
+
+class cmTargetCompileDefinitionsCommand : public cmTargetPropCommandBase
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ return new cmTargetCompileDefinitionsCommand;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE
+ {
+ return "target_compile_definitions";
+ }
+
+ cmTypeMacro(cmTargetCompileDefinitionsCommand, cmTargetPropCommandBase);
+
+private:
+ void HandleImportedTarget(const std::string& tgt) CM_OVERRIDE;
+ void HandleMissingTarget(const std::string& name) CM_OVERRIDE;
+
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) CM_OVERRIDE;
+ std::string Join(const std::vector<std::string>& content) CM_OVERRIDE;
+};
+
+#endif
diff --git a/Source/cmTargetCompileFeaturesCommand.cxx b/Source/cmTargetCompileFeaturesCommand.cxx
new file mode 100644
index 0000000..3ac791a
--- /dev/null
+++ b/Source/cmTargetCompileFeaturesCommand.cxx
@@ -0,0 +1,59 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTargetCompileFeaturesCommand.h"
+
+#include "cmAlgorithms.h"
+
+bool cmTargetCompileFeaturesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ return this->HandleArguments(args, "COMPILE_FEATURES", NO_FLAGS);
+}
+
+void cmTargetCompileFeaturesCommand::HandleImportedTarget(
+ const std::string& tgt)
+{
+ std::ostringstream e;
+ e << "Cannot specify compile features for imported target \"" << tgt
+ << "\".";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+void cmTargetCompileFeaturesCommand::HandleMissingTarget(
+ const std::string& name)
+{
+ std::ostringstream e;
+ e << "Cannot specify compile features for target \"" << name
+ << "\" "
+ "which is not built by this project.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+std::string cmTargetCompileFeaturesCommand::Join(
+ const std::vector<std::string>& content)
+{
+ return cmJoin(content, ";");
+}
+
+bool cmTargetCompileFeaturesCommand::HandleDirectContent(
+ cmTarget* tgt, const std::vector<std::string>& content, bool, bool)
+{
+ for (std::vector<std::string>::const_iterator it = content.begin();
+ it != content.end(); ++it) {
+ std::string error;
+ if (!this->Makefile->AddRequiredTargetFeature(tgt, *it, &error)) {
+ this->SetError(error);
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/Source/cmTargetCompileFeaturesCommand.h b/Source/cmTargetCompileFeaturesCommand.h
new file mode 100644
index 0000000..4fae84a
--- /dev/null
+++ b/Source/cmTargetCompileFeaturesCommand.h
@@ -0,0 +1,38 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmTargetCompileFeaturesCommand_h
+#define cmTargetCompileFeaturesCommand_h
+
+#include "cmTargetPropCommandBase.h"
+
+class cmTargetCompileFeaturesCommand : public cmTargetPropCommandBase
+{
+ cmCommand* Clone() CM_OVERRIDE { return new cmTargetCompileFeaturesCommand; }
+
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ std::string GetName() const CM_OVERRIDE { return "target_compile_features"; }
+
+ cmTypeMacro(cmTargetCompileFeaturesCommand, cmTargetPropCommandBase);
+
+private:
+ void HandleImportedTarget(const std::string& tgt) CM_OVERRIDE;
+ void HandleMissingTarget(const std::string& name) CM_OVERRIDE;
+
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) CM_OVERRIDE;
+ std::string Join(const std::vector<std::string>& content) CM_OVERRIDE;
+};
+
+#endif
diff --git a/Source/cmTargetCompileOptionsCommand.cxx b/Source/cmTargetCompileOptionsCommand.cxx
new file mode 100644
index 0000000..065f618
--- /dev/null
+++ b/Source/cmTargetCompileOptionsCommand.cxx
@@ -0,0 +1,52 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTargetCompileOptionsCommand.h"
+
+#include "cmAlgorithms.h"
+
+bool cmTargetCompileOptionsCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ return this->HandleArguments(args, "COMPILE_OPTIONS", PROCESS_BEFORE);
+}
+
+void cmTargetCompileOptionsCommand::HandleImportedTarget(
+ const std::string& tgt)
+{
+ std::ostringstream e;
+ e << "Cannot specify compile options for imported target \"" << tgt << "\".";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+void cmTargetCompileOptionsCommand::HandleMissingTarget(
+ const std::string& name)
+{
+ std::ostringstream e;
+ e << "Cannot specify compile options for target \"" << name
+ << "\" "
+ "which is not built by this project.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+std::string cmTargetCompileOptionsCommand::Join(
+ const std::vector<std::string>& content)
+{
+ return cmJoin(content, ";");
+}
+
+bool cmTargetCompileOptionsCommand::HandleDirectContent(
+ cmTarget* tgt, const std::vector<std::string>& content, bool, bool)
+{
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ tgt->InsertCompileOption(this->Join(content), lfbt);
+ return true;
+}
diff --git a/Source/cmTargetCompileOptionsCommand.h b/Source/cmTargetCompileOptionsCommand.h
new file mode 100644
index 0000000..7239629
--- /dev/null
+++ b/Source/cmTargetCompileOptionsCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmTargetCompileOptionsCommand_h
+#define cmTargetCompileOptionsCommand_h
+
+#include "cmTargetPropCommandBase.h"
+
+class cmTargetCompileOptionsCommand : public cmTargetPropCommandBase
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmTargetCompileOptionsCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "target_compile_options"; }
+
+ cmTypeMacro(cmTargetCompileOptionsCommand, cmTargetPropCommandBase);
+
+private:
+ void HandleImportedTarget(const std::string& tgt) CM_OVERRIDE;
+ void HandleMissingTarget(const std::string& name) CM_OVERRIDE;
+
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) CM_OVERRIDE;
+ std::string Join(const std::vector<std::string>& content) CM_OVERRIDE;
+};
+
+#endif
diff --git a/Source/cmTargetDepend.h b/Source/cmTargetDepend.h
new file mode 100644
index 0000000..954d8f6
--- /dev/null
+++ b/Source/cmTargetDepend.h
@@ -0,0 +1,61 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2010 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmTargetDepend_h
+#define cmTargetDepend_h
+
+#include "cmStandardIncludes.h"
+
+class cmGeneratorTarget;
+
+/** One edge in the global target dependency graph.
+ It may be marked as a 'link' or 'util' edge or both. */
+class cmTargetDepend
+{
+ cmGeneratorTarget const* Target;
+
+ // The set order depends only on the Target, so we use
+ // mutable members to acheive a map with set syntax.
+ mutable bool Link;
+ mutable bool Util;
+
+public:
+ cmTargetDepend(cmGeneratorTarget const* t)
+ : Target(t)
+ , Link(false)
+ , Util(false)
+ {
+ }
+ operator cmGeneratorTarget const*() const { return this->Target; }
+ cmGeneratorTarget const* operator->() const { return this->Target; }
+ cmGeneratorTarget const& operator*() const { return *this->Target; }
+ friend bool operator<(cmTargetDepend const& l, cmTargetDepend const& r)
+ {
+ return l.Target < r.Target;
+ }
+ void SetType(bool strong) const
+ {
+ if (strong) {
+ this->Util = true;
+ } else {
+ this->Link = true;
+ }
+ }
+ bool IsLink() const { return this->Link; }
+ bool IsUtil() const { return this->Util; }
+};
+
+/** Unordered set of (direct) dependencies of a target. */
+class cmTargetDependSet : public std::set<cmTargetDepend>
+{
+};
+
+#endif
diff --git a/Source/cmTargetExport.h b/Source/cmTargetExport.h
new file mode 100644
index 0000000..2781337
--- /dev/null
+++ b/Source/cmTargetExport.h
@@ -0,0 +1,43 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmTargetExport_h
+#define cmTargetExport_h
+
+#include "cmStandardIncludes.h"
+
+class cmGeneratorTarget;
+class cmInstallTargetGenerator;
+class cmInstallFilesGenerator;
+
+/** \brief A member of an ExportSet
+ *
+ * This struct holds pointers to target and all relevant generators.
+ */
+class cmTargetExport
+{
+public:
+ std::string TargetName;
+ cmGeneratorTarget* Target;
+
+ ///@name Generators
+ ///@{
+ cmInstallTargetGenerator* ArchiveGenerator;
+ cmInstallTargetGenerator* RuntimeGenerator;
+ cmInstallTargetGenerator* LibraryGenerator;
+ cmInstallTargetGenerator* FrameworkGenerator;
+ cmInstallTargetGenerator* BundleGenerator;
+ cmInstallFilesGenerator* HeaderGenerator;
+ std::string InterfaceIncludeDirectories;
+ ///@}
+};
+
+#endif
diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx
new file mode 100644
index 0000000..4486b0e
--- /dev/null
+++ b/Source/cmTargetIncludeDirectoriesCommand.cxx
@@ -0,0 +1,98 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTargetIncludeDirectoriesCommand.h"
+
+#include "cmGeneratorExpression.h"
+
+bool cmTargetIncludeDirectoriesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ return this->HandleArguments(args, "INCLUDE_DIRECTORIES",
+ ArgumentFlags(PROCESS_BEFORE | PROCESS_SYSTEM));
+}
+
+void cmTargetIncludeDirectoriesCommand::HandleImportedTarget(
+ const std::string& tgt)
+{
+ std::ostringstream e;
+ e << "Cannot specify include directories for imported target \"" << tgt
+ << "\".";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+void cmTargetIncludeDirectoriesCommand::HandleMissingTarget(
+ const std::string& name)
+{
+ std::ostringstream e;
+ e << "Cannot specify include directories for target \"" << name
+ << "\" "
+ "which is not built by this project.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+std::string cmTargetIncludeDirectoriesCommand::Join(
+ const std::vector<std::string>& content)
+{
+ std::string dirs;
+ std::string sep;
+ std::string prefix =
+ this->Makefile->GetCurrentSourceDirectory() + std::string("/");
+ for (std::vector<std::string>::const_iterator it = content.begin();
+ it != content.end(); ++it) {
+ if (cmSystemTools::FileIsFullPath(it->c_str()) ||
+ cmGeneratorExpression::Find(*it) == 0) {
+ dirs += sep + *it;
+ } else {
+ dirs += sep + prefix + *it;
+ }
+ sep = ";";
+ }
+ return dirs;
+}
+
+bool cmTargetIncludeDirectoriesCommand::HandleDirectContent(
+ cmTarget* tgt, const std::vector<std::string>& content, bool prepend,
+ bool system)
+{
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ tgt->InsertInclude(this->Join(content), lfbt, prepend);
+ if (system) {
+ std::string prefix =
+ this->Makefile->GetCurrentSourceDirectory() + std::string("/");
+ std::set<std::string> sdirs;
+ for (std::vector<std::string>::const_iterator it = content.begin();
+ it != content.end(); ++it) {
+ if (cmSystemTools::FileIsFullPath(it->c_str()) ||
+ cmGeneratorExpression::Find(*it) == 0) {
+ sdirs.insert(*it);
+ } else {
+ sdirs.insert(prefix + *it);
+ }
+ }
+ tgt->AddSystemIncludeDirectories(sdirs);
+ }
+ return true;
+}
+
+void cmTargetIncludeDirectoriesCommand::HandleInterfaceContent(
+ cmTarget* tgt, const std::vector<std::string>& content, bool prepend,
+ bool system)
+{
+ cmTargetPropCommandBase::HandleInterfaceContent(tgt, content, prepend,
+ system);
+
+ if (system) {
+ std::string joined = this->Join(content);
+ tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES",
+ joined.c_str());
+ }
+}
diff --git a/Source/cmTargetIncludeDirectoriesCommand.h b/Source/cmTargetIncludeDirectoriesCommand.h
new file mode 100644
index 0000000..ba5d980
--- /dev/null
+++ b/Source/cmTargetIncludeDirectoriesCommand.h
@@ -0,0 +1,60 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmTargetIncludeDirectoriesCommand_h
+#define cmTargetIncludeDirectoriesCommand_h
+
+#include "cmTargetPropCommandBase.h"
+
+class cmTargetIncludeDirectoriesCommand : public cmTargetPropCommandBase
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ return new cmTargetIncludeDirectoriesCommand;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE
+ {
+ return "target_include_directories";
+ }
+
+ cmTypeMacro(cmTargetIncludeDirectoriesCommand, cmTargetPropCommandBase);
+
+private:
+ void HandleImportedTarget(const std::string& tgt) CM_OVERRIDE;
+ void HandleMissingTarget(const std::string& name) CM_OVERRIDE;
+
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) CM_OVERRIDE;
+ void HandleInterfaceContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) CM_OVERRIDE;
+
+ std::string Join(const std::vector<std::string>& content) CM_OVERRIDE;
+};
+
+#endif
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
new file mode 100644
index 0000000..1c4a9ce
--- /dev/null
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -0,0 +1,423 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTargetLinkLibrariesCommand.h"
+
+#include "cmGeneratorExpression.h"
+
+const char* cmTargetLinkLibrariesCommand::LinkLibraryTypeNames[3] = {
+ "general", "debug", "optimized"
+};
+
+// cmTargetLinkLibrariesCommand
+bool cmTargetLinkLibrariesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ // must have one argument
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ if (this->Makefile->IsAlias(args[0])) {
+ this->SetError("can not be used on an ALIAS target.");
+ return false;
+ }
+ // Lookup the target for which libraries are specified.
+ this->Target =
+ this->Makefile->GetCMakeInstance()->GetGlobalGenerator()->FindTarget(
+ args[0]);
+ if (!this->Target) {
+ cmake::MessageType t = cmake::FATAL_ERROR; // fail by default
+ std::ostringstream e;
+ e << "Cannot specify link libraries for target \"" << args[0] << "\" "
+ << "which is not built by this project.";
+ // The bad target is the only argument. Check how policy CMP0016 is set,
+ // and accept, warn or fail respectively:
+ if (args.size() < 2) {
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0016)) {
+ case cmPolicies::WARN:
+ t = cmake::AUTHOR_WARNING;
+ // Print the warning.
+ e << "\n"
+ << "CMake does not support this but it used to work accidentally "
+ << "and is being allowed for compatibility."
+ << "\n"
+ << cmPolicies::GetPolicyWarning(cmPolicies::CMP0016);
+ break;
+ case cmPolicies::OLD: // OLD behavior does not warn.
+ t = cmake::MESSAGE;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ e << "\n" << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0016);
+ break;
+ case cmPolicies::NEW: // NEW behavior prints the error.
+ break;
+ }
+ }
+
+ // now actually print the message
+ switch (t) {
+ case cmake::AUTHOR_WARNING:
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, e.str());
+ break;
+ case cmake::FATAL_ERROR:
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ if (this->Target->GetType() == cmState::OBJECT_LIBRARY) {
+ std::ostringstream e;
+ e << "Object library target \"" << args[0] << "\" "
+ << "may not link to anything.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+
+ if (this->Target->GetType() == cmState::UTILITY) {
+ std::ostringstream e;
+ const char* modal = CM_NULLPTR;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0039)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0039) << "\n";
+ modal = "should";
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ modal = "must";
+ messageType = cmake::FATAL_ERROR;
+ }
+ if (modal) {
+ e << "Utility target \"" << this->Target->GetName() << "\" " << modal
+ << " not be used as the target of a target_link_libraries call.";
+ this->Makefile->IssueMessage(messageType, e.str());
+ if (messageType == cmake::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+
+ // but we might not have any libs after variable expansion
+ if (args.size() < 2) {
+ return true;
+ }
+
+ // Keep track of link configuration specifiers.
+ cmTargetLinkLibraryType llt = GENERAL_LibraryType;
+ bool haveLLT = false;
+
+ // Start with primary linking and switch to link interface
+ // specification if the keyword is encountered as the first argument.
+ this->CurrentProcessingState = ProcessingLinkLibraries;
+
+ // add libraries, note that there is an optional prefix
+ // of debug and optimized that can be used
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "LINK_INTERFACE_LIBRARIES") {
+ this->CurrentProcessingState = ProcessingPlainLinkInterface;
+ if (i != 1) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "The LINK_INTERFACE_LIBRARIES option must appear as the second "
+ "argument, just after the target name.");
+ return true;
+ }
+ } else if (args[i] == "INTERFACE") {
+ if (i != 1 &&
+ this->CurrentProcessingState != ProcessingKeywordPrivateInterface &&
+ this->CurrentProcessingState != ProcessingKeywordPublicInterface &&
+ this->CurrentProcessingState != ProcessingKeywordLinkInterface) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR, "The INTERFACE option must appear as the second "
+ "argument, just after the target name.");
+ return true;
+ }
+ this->CurrentProcessingState = ProcessingKeywordLinkInterface;
+ } else if (args[i] == "LINK_PUBLIC") {
+ if (i != 1 &&
+ this->CurrentProcessingState != ProcessingPlainPrivateInterface &&
+ this->CurrentProcessingState != ProcessingPlainPublicInterface) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "The LINK_PUBLIC or LINK_PRIVATE option must appear as the second "
+ "argument, just after the target name.");
+ return true;
+ }
+ this->CurrentProcessingState = ProcessingPlainPublicInterface;
+ } else if (args[i] == "PUBLIC") {
+ if (i != 1 &&
+ this->CurrentProcessingState != ProcessingKeywordPrivateInterface &&
+ this->CurrentProcessingState != ProcessingKeywordPublicInterface &&
+ this->CurrentProcessingState != ProcessingKeywordLinkInterface) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "The PUBLIC or PRIVATE option must appear as the second "
+ "argument, just after the target name.");
+ return true;
+ }
+ this->CurrentProcessingState = ProcessingKeywordPublicInterface;
+ } else if (args[i] == "LINK_PRIVATE") {
+ if (i != 1 &&
+ this->CurrentProcessingState != ProcessingPlainPublicInterface &&
+ this->CurrentProcessingState != ProcessingPlainPrivateInterface) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "The LINK_PUBLIC or LINK_PRIVATE option must appear as the second "
+ "argument, just after the target name.");
+ return true;
+ }
+ this->CurrentProcessingState = ProcessingPlainPrivateInterface;
+ } else if (args[i] == "PRIVATE") {
+ if (i != 1 &&
+ this->CurrentProcessingState != ProcessingKeywordPrivateInterface &&
+ this->CurrentProcessingState != ProcessingKeywordPublicInterface &&
+ this->CurrentProcessingState != ProcessingKeywordLinkInterface) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "The PUBLIC or PRIVATE option must appear as the second "
+ "argument, just after the target name.");
+ return true;
+ }
+ this->CurrentProcessingState = ProcessingKeywordPrivateInterface;
+ } else if (args[i] == "debug") {
+ if (haveLLT) {
+ this->LinkLibraryTypeSpecifierWarning(llt, DEBUG_LibraryType);
+ }
+ llt = DEBUG_LibraryType;
+ haveLLT = true;
+ } else if (args[i] == "optimized") {
+ if (haveLLT) {
+ this->LinkLibraryTypeSpecifierWarning(llt, OPTIMIZED_LibraryType);
+ }
+ llt = OPTIMIZED_LibraryType;
+ haveLLT = true;
+ } else if (args[i] == "general") {
+ if (haveLLT) {
+ this->LinkLibraryTypeSpecifierWarning(llt, GENERAL_LibraryType);
+ }
+ llt = GENERAL_LibraryType;
+ haveLLT = true;
+ } else if (haveLLT) {
+ // The link type was specified by the previous argument.
+ haveLLT = false;
+ if (!this->HandleLibrary(args[i], llt)) {
+ return false;
+ }
+ } else {
+ // Lookup old-style cache entry if type is unspecified. So if you
+ // do a target_link_libraries(foo optimized bar) it will stay optimized
+ // and not use the lookup. As there maybe the case where someone has
+ // specifed that a library is both debug and optimized. (this check is
+ // only there for backwards compatibility when mixing projects built
+ // with old versions of CMake and new)
+ llt = GENERAL_LibraryType;
+ std::string linkType = args[0];
+ linkType += "_LINK_TYPE";
+ const char* linkTypeString = this->Makefile->GetDefinition(linkType);
+ if (linkTypeString) {
+ if (strcmp(linkTypeString, "debug") == 0) {
+ llt = DEBUG_LibraryType;
+ }
+ if (strcmp(linkTypeString, "optimized") == 0) {
+ llt = OPTIMIZED_LibraryType;
+ }
+ }
+ if (!this->HandleLibrary(args[i], llt)) {
+ return false;
+ }
+ }
+ }
+
+ // Make sure the last argument was not a library type specifier.
+ if (haveLLT) {
+ std::ostringstream e;
+ e << "The \"" << this->LinkLibraryTypeNames[llt]
+ << "\" argument must be followed by a library.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ }
+
+ const cmPolicies::PolicyStatus policy22Status =
+ this->Target->GetPolicyStatusCMP0022();
+
+ // If any of the LINK_ options were given, make sure the
+ // LINK_INTERFACE_LIBRARIES target property exists.
+ // Use of any of the new keywords implies awareness of
+ // this property. And if no libraries are named, it should
+ // result in an empty link interface.
+ if ((policy22Status == cmPolicies::OLD ||
+ policy22Status == cmPolicies::WARN) &&
+ this->CurrentProcessingState != ProcessingLinkLibraries &&
+ !this->Target->GetProperty("LINK_INTERFACE_LIBRARIES")) {
+ this->Target->SetProperty("LINK_INTERFACE_LIBRARIES", "");
+ }
+
+ return true;
+}
+
+void cmTargetLinkLibrariesCommand::LinkLibraryTypeSpecifierWarning(int left,
+ int right)
+{
+ std::ostringstream w;
+ w << "Link library type specifier \"" << this->LinkLibraryTypeNames[left]
+ << "\" is followed by specifier \"" << this->LinkLibraryTypeNames[right]
+ << "\" instead of a library name. "
+ << "The first specifier will be ignored.";
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+}
+
+bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib,
+ cmTargetLinkLibraryType llt)
+{
+ if (this->Target->GetType() == cmState::INTERFACE_LIBRARY &&
+ this->CurrentProcessingState != ProcessingKeywordLinkInterface) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "INTERFACE library can only be used with the INTERFACE keyword of "
+ "target_link_libraries");
+ return false;
+ }
+
+ cmTarget::TLLSignature sig =
+ (this->CurrentProcessingState == ProcessingPlainPrivateInterface ||
+ this->CurrentProcessingState == ProcessingPlainPublicInterface ||
+ this->CurrentProcessingState == ProcessingKeywordPrivateInterface ||
+ this->CurrentProcessingState == ProcessingKeywordPublicInterface ||
+ this->CurrentProcessingState == ProcessingKeywordLinkInterface)
+ ? cmTarget::KeywordTLLSignature
+ : cmTarget::PlainTLLSignature;
+ if (!this->Target->PushTLLCommandTrace(
+ sig, this->Makefile->GetExecutionContext())) {
+ std::ostringstream e;
+ const char* modal = CM_NULLPTR;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0023)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0023) << "\n";
+ modal = "should";
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ modal = "must";
+ messageType = cmake::FATAL_ERROR;
+ }
+
+ if (modal) {
+ // If the sig is a keyword form and there is a conflict, the existing
+ // form must be the plain form.
+ const char* existingSig =
+ (sig == cmTarget::KeywordTLLSignature ? "plain" : "keyword");
+ e << "The " << existingSig << " signature for target_link_libraries "
+ "has already been used with the target \""
+ << this->Target->GetName() << "\". All uses of "
+ "target_link_libraries with a target "
+ << modal << " be either "
+ "all-keyword or all-plain.\n";
+ this->Target->GetTllSignatureTraces(e,
+ sig == cmTarget::KeywordTLLSignature
+ ? cmTarget::PlainTLLSignature
+ : cmTarget::KeywordTLLSignature);
+ this->Makefile->IssueMessage(messageType, e.str());
+ if (messageType == cmake::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+
+ // Handle normal case first.
+ if (this->CurrentProcessingState != ProcessingKeywordLinkInterface &&
+ this->CurrentProcessingState != ProcessingPlainLinkInterface) {
+ this->Makefile->AddLinkLibraryForTarget(this->Target->GetName(), lib, llt);
+ if (this->CurrentProcessingState == ProcessingLinkLibraries) {
+ this->Target->AppendProperty(
+ "INTERFACE_LINK_LIBRARIES",
+ this->Target->GetDebugGeneratorExpressions(lib, llt).c_str());
+ return true;
+ } else if (this->CurrentProcessingState !=
+ ProcessingKeywordPublicInterface &&
+ this->CurrentProcessingState !=
+ ProcessingPlainPublicInterface) {
+ if (this->Target->GetType() == cmState::STATIC_LIBRARY) {
+ std::string configLib =
+ this->Target->GetDebugGeneratorExpressions(lib, llt);
+ if (cmGeneratorExpression::IsValidTargetName(lib) ||
+ cmGeneratorExpression::Find(lib) != std::string::npos) {
+ configLib = "$<LINK_ONLY:" + configLib + ">";
+ }
+ this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES",
+ configLib.c_str());
+ }
+ // Not a 'public' or 'interface' library. Do not add to interface
+ // property.
+ return true;
+ }
+ }
+
+ this->Target->AppendProperty(
+ "INTERFACE_LINK_LIBRARIES",
+ this->Target->GetDebugGeneratorExpressions(lib, llt).c_str());
+
+ const cmPolicies::PolicyStatus policy22Status =
+ this->Target->GetPolicyStatusCMP0022();
+
+ if (policy22Status != cmPolicies::OLD &&
+ policy22Status != cmPolicies::WARN) {
+ return true;
+ }
+
+ if (this->Target->GetType() == cmState::INTERFACE_LIBRARY) {
+ return true;
+ }
+
+ // Get the list of configurations considered to be DEBUG.
+ std::vector<std::string> debugConfigs =
+ this->Makefile->GetCMakeInstance()->GetDebugConfigs();
+ std::string prop;
+
+ // Include this library in the link interface for the target.
+ if (llt == DEBUG_LibraryType || llt == GENERAL_LibraryType) {
+ // Put in the DEBUG configuration interfaces.
+ for (std::vector<std::string>::const_iterator i = debugConfigs.begin();
+ i != debugConfigs.end(); ++i) {
+ prop = "LINK_INTERFACE_LIBRARIES_";
+ prop += *i;
+ this->Target->AppendProperty(prop, lib.c_str());
+ }
+ }
+ if (llt == OPTIMIZED_LibraryType || llt == GENERAL_LibraryType) {
+ // Put in the non-DEBUG configuration interfaces.
+ this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES", lib.c_str());
+
+ // Make sure the DEBUG configuration interfaces exist so that the
+ // general one will not be used as a fall-back.
+ for (std::vector<std::string>::const_iterator i = debugConfigs.begin();
+ i != debugConfigs.end(); ++i) {
+ prop = "LINK_INTERFACE_LIBRARIES_";
+ prop += *i;
+ if (!this->Target->GetProperty(prop)) {
+ this->Target->SetProperty(prop, "");
+ }
+ }
+ }
+ return true;
+}
diff --git a/Source/cmTargetLinkLibrariesCommand.h b/Source/cmTargetLinkLibrariesCommand.h
new file mode 100644
index 0000000..4f58639
--- /dev/null
+++ b/Source/cmTargetLinkLibrariesCommand.h
@@ -0,0 +1,67 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmTargetLinkLibrariesCommand_h
+#define cmTargetLinkLibrariesCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmTargetLinkLibrariesCommand
+ * \brief Specify a list of libraries to link into executables.
+ *
+ * cmTargetLinkLibrariesCommand is used to specify a list of libraries to link
+ * into executable(s) or shared objects. The names of the libraries
+ * should be those defined by the LIBRARY(library) command(s).
+ */
+class cmTargetLinkLibrariesCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmTargetLinkLibrariesCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "target_link_libraries"; }
+
+ cmTypeMacro(cmTargetLinkLibrariesCommand, cmCommand);
+
+private:
+ void LinkLibraryTypeSpecifierWarning(int left, int right);
+ static const char* LinkLibraryTypeNames[3];
+
+ cmTarget* Target;
+ enum ProcessingState
+ {
+ ProcessingLinkLibraries,
+ ProcessingPlainLinkInterface,
+ ProcessingKeywordLinkInterface,
+ ProcessingPlainPublicInterface,
+ ProcessingKeywordPublicInterface,
+ ProcessingPlainPrivateInterface,
+ ProcessingKeywordPrivateInterface
+ };
+
+ ProcessingState CurrentProcessingState;
+
+ bool HandleLibrary(const std::string& lib, cmTargetLinkLibraryType llt);
+};
+
+#endif
diff --git a/Source/cmTargetLinkLibraryType.h b/Source/cmTargetLinkLibraryType.h
new file mode 100644
index 0000000..71ac9e7
--- /dev/null
+++ b/Source/cmTargetLinkLibraryType.h
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmTargetLinkLibraryType_h
+#define cmTargetLinkLibraryType_h
+
+enum cmTargetLinkLibraryType
+{
+ GENERAL_LibraryType,
+ DEBUG_LibraryType,
+ OPTIMIZED_LibraryType
+};
+
+#endif
diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx
new file mode 100644
index 0000000..487074f
--- /dev/null
+++ b/Source/cmTargetPropCommandBase.cxx
@@ -0,0 +1,148 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmTargetPropCommandBase.h"
+
+#include "cmGlobalGenerator.h"
+
+bool cmTargetPropCommandBase::HandleArguments(
+ std::vector<std::string> const& args, const std::string& prop,
+ ArgumentFlags flags)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Lookup the target for which libraries are specified.
+ if (this->Makefile->IsAlias(args[0])) {
+ this->SetError("can not be used on an ALIAS target.");
+ return false;
+ }
+ this->Target =
+ this->Makefile->GetCMakeInstance()->GetGlobalGenerator()->FindTarget(
+ args[0]);
+ if (!this->Target) {
+ this->Target = this->Makefile->FindTargetToUse(args[0]);
+ }
+ if (!this->Target) {
+ this->HandleMissingTarget(args[0]);
+ return false;
+ }
+ if ((this->Target->GetType() != cmState::SHARED_LIBRARY) &&
+ (this->Target->GetType() != cmState::STATIC_LIBRARY) &&
+ (this->Target->GetType() != cmState::OBJECT_LIBRARY) &&
+ (this->Target->GetType() != cmState::MODULE_LIBRARY) &&
+ (this->Target->GetType() != cmState::INTERFACE_LIBRARY) &&
+ (this->Target->GetType() != cmState::EXECUTABLE)) {
+ this->SetError("called with non-compilable target type");
+ return false;
+ }
+
+ bool system = false;
+ unsigned int argIndex = 1;
+
+ if ((flags & PROCESS_SYSTEM) && args[argIndex] == "SYSTEM") {
+ if (args.size() < 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ system = true;
+ ++argIndex;
+ }
+
+ bool prepend = false;
+ if ((flags & PROCESS_BEFORE) && args[argIndex] == "BEFORE") {
+ if (args.size() < 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ prepend = true;
+ ++argIndex;
+ }
+
+ this->Property = prop;
+
+ while (argIndex < args.size()) {
+ if (!this->ProcessContentArgs(args, argIndex, prepend, system)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmTargetPropCommandBase::ProcessContentArgs(
+ std::vector<std::string> const& args, unsigned int& argIndex, bool prepend,
+ bool system)
+{
+ const std::string scope = args[argIndex];
+
+ if (scope != "PUBLIC" && scope != "PRIVATE" && scope != "INTERFACE") {
+ this->SetError("called with invalid arguments");
+ return false;
+ }
+
+ if (this->Target->IsImported()) {
+ this->HandleImportedTarget(args[0]);
+ return false;
+ }
+
+ if (this->Target->GetType() == cmState::INTERFACE_LIBRARY &&
+ scope != "INTERFACE") {
+ this->SetError("may only be set INTERFACE properties on INTERFACE "
+ "targets");
+ return false;
+ }
+
+ ++argIndex;
+
+ std::vector<std::string> content;
+
+ for (unsigned int i = argIndex; i < args.size(); ++i, ++argIndex) {
+ if (args[i] == "PUBLIC" || args[i] == "PRIVATE" ||
+ args[i] == "INTERFACE") {
+ return this->PopulateTargetProperies(scope, content, prepend, system);
+ }
+ content.push_back(args[i]);
+ }
+ return this->PopulateTargetProperies(scope, content, prepend, system);
+}
+
+bool cmTargetPropCommandBase::PopulateTargetProperies(
+ const std::string& scope, const std::vector<std::string>& content,
+ bool prepend, bool system)
+{
+ if (scope == "PRIVATE" || scope == "PUBLIC") {
+ if (!this->HandleDirectContent(this->Target, content, prepend, system)) {
+ return false;
+ }
+ }
+ if (scope == "INTERFACE" || scope == "PUBLIC") {
+ this->HandleInterfaceContent(this->Target, content, prepend, system);
+ }
+ return true;
+}
+
+void cmTargetPropCommandBase::HandleInterfaceContent(
+ cmTarget* tgt, const std::vector<std::string>& content, bool prepend, bool)
+{
+ if (prepend) {
+ const std::string propName = std::string("INTERFACE_") + this->Property;
+ const char* propValue = tgt->GetProperty(propName);
+ const std::string totalContent = this->Join(content) +
+ (propValue ? std::string(";") + propValue : std::string());
+ tgt->SetProperty(propName, totalContent.c_str());
+ } else {
+ tgt->AppendProperty("INTERFACE_" + this->Property,
+ this->Join(content).c_str());
+ }
+}
diff --git a/Source/cmTargetPropCommandBase.h b/Source/cmTargetPropCommandBase.h
new file mode 100644
index 0000000..88591dc
--- /dev/null
+++ b/Source/cmTargetPropCommandBase.h
@@ -0,0 +1,61 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmTargetPropCommandBase_h
+#define cmTargetPropCommandBase_h
+
+#include "cmCommand.h"
+
+class cmTarget;
+
+class cmTargetPropCommandBase : public cmCommand
+{
+public:
+ enum ArgumentFlags
+ {
+ NO_FLAGS = 0,
+ PROCESS_BEFORE = 1,
+ PROCESS_SYSTEM = 2
+ };
+
+ bool HandleArguments(std::vector<std::string> const& args,
+ const std::string& prop,
+ ArgumentFlags flags = NO_FLAGS);
+
+ cmTypeMacro(cmTargetPropCommandBase, cmCommand);
+
+protected:
+ std::string Property;
+ cmTarget* Target;
+
+ virtual void HandleInterfaceContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system);
+
+private:
+ virtual void HandleImportedTarget(const std::string& tgt) = 0;
+ virtual void HandleMissingTarget(const std::string& name) = 0;
+
+ virtual bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) = 0;
+
+ virtual std::string Join(const std::vector<std::string>& content) = 0;
+
+ bool ProcessContentArgs(std::vector<std::string> const& args,
+ unsigned int& argIndex, bool prepend, bool system);
+ bool PopulateTargetProperies(const std::string& scope,
+ const std::vector<std::string>& content,
+ bool prepend, bool system);
+};
+
+#endif
diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx
new file mode 100644
index 0000000..64372dc
--- /dev/null
+++ b/Source/cmTargetSourcesCommand.cxx
@@ -0,0 +1,49 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTargetSourcesCommand.h"
+
+#include "cmGeneratorExpression.h"
+
+bool cmTargetSourcesCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ return this->HandleArguments(args, "SOURCES");
+}
+
+void cmTargetSourcesCommand::HandleImportedTarget(const std::string& tgt)
+{
+ std::ostringstream e;
+ e << "Cannot specify sources for imported target \"" << tgt << "\".";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+void cmTargetSourcesCommand::HandleMissingTarget(const std::string& name)
+{
+ std::ostringstream e;
+ e << "Cannot specify sources for target \"" << name
+ << "\" "
+ "which is not built by this project.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+std::string cmTargetSourcesCommand::Join(
+ const std::vector<std::string>& content)
+{
+ return cmJoin(content, ";");
+}
+
+bool cmTargetSourcesCommand::HandleDirectContent(
+ cmTarget* tgt, const std::vector<std::string>& content, bool, bool)
+{
+ tgt->AppendProperty("SOURCES", this->Join(content).c_str());
+ return true;
+}
diff --git a/Source/cmTargetSourcesCommand.h b/Source/cmTargetSourcesCommand.h
new file mode 100644
index 0000000..9073204
--- /dev/null
+++ b/Source/cmTargetSourcesCommand.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmTargetSourcesCommand_h
+#define cmTargetSourcesCommand_h
+
+#include "cmTargetPropCommandBase.h"
+
+class cmTargetSourcesCommand : public cmTargetPropCommandBase
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmTargetSourcesCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "target_sources"; }
+
+ cmTypeMacro(cmTargetSourcesCommand, cmTargetPropCommandBase);
+
+private:
+ void HandleImportedTarget(const std::string& tgt) CM_OVERRIDE;
+ void HandleMissingTarget(const std::string& name) CM_OVERRIDE;
+
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) CM_OVERRIDE;
+
+ std::string Join(const std::vector<std::string>& content) CM_OVERRIDE;
+};
+
+#endif
diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx
new file mode 100644
index 0000000..0658e95
--- /dev/null
+++ b/Source/cmTest.cxx
@@ -0,0 +1,72 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTest.h"
+
+#include "cmSystemTools.h"
+
+#include "cmMakefile.h"
+#include "cmake.h"
+
+cmTest::cmTest(cmMakefile* mf)
+ : Backtrace(mf->GetBacktrace())
+{
+ this->Makefile = mf;
+ this->OldStyle = true;
+}
+
+cmTest::~cmTest()
+{
+}
+
+cmListFileBacktrace const& cmTest::GetBacktrace() const
+{
+ return this->Backtrace;
+}
+
+void cmTest::SetName(const std::string& name)
+{
+ this->Name = name;
+}
+
+void cmTest::SetCommand(std::vector<std::string> const& command)
+{
+ this->Command = command;
+}
+
+const char* cmTest::GetProperty(const std::string& prop) const
+{
+ const char* retVal = this->Properties.GetPropertyValue(prop);
+ if (!retVal) {
+ const bool chain =
+ this->Makefile->GetState()->IsPropertyChained(prop, cmProperty::TEST);
+ if (chain) {
+ return this->Makefile->GetProperty(prop, chain);
+ }
+ }
+ return retVal;
+}
+
+bool cmTest::GetPropertyAsBool(const std::string& prop) const
+{
+ return cmSystemTools::IsOn(this->GetProperty(prop));
+}
+
+void cmTest::SetProperty(const std::string& prop, const char* value)
+{
+ this->Properties.SetProperty(prop, value);
+}
+
+void cmTest::AppendProperty(const std::string& prop, const char* value,
+ bool asString)
+{
+ this->Properties.AppendProperty(prop, value, asString);
+}
diff --git a/Source/cmTest.h b/Source/cmTest.h
new file mode 100644
index 0000000..db68008
--- /dev/null
+++ b/Source/cmTest.h
@@ -0,0 +1,71 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmTest_h
+#define cmTest_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmCustomCommand.h"
+#include "cmListFileCache.h"
+#include "cmPropertyMap.h"
+class cmMakefile;
+
+/** \class cmTest
+ * \brief Represent a test
+ *
+ * cmTest is representation of a test.
+ */
+class cmTest
+{
+public:
+ /**
+ */
+ cmTest(cmMakefile* mf);
+ ~cmTest();
+
+ ///! 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
+ 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) const;
+ bool GetPropertyAsBool(const std::string& prop) const;
+ cmPropertyMap& GetProperties() { return this->Properties; }
+
+ /** Get the cmMakefile instance that owns this test. */
+ cmMakefile* GetMakefile() { return this->Makefile; }
+
+ /** Get the backtrace of the command that created this test. */
+ cmListFileBacktrace const& GetBacktrace() const;
+
+ /** Get/Set whether this is an old-style test. */
+ bool GetOldStyle() const { return this->OldStyle; }
+ void SetOldStyle(bool b) { this->OldStyle = b; }
+
+private:
+ cmPropertyMap Properties;
+ std::string Name;
+ std::vector<std::string> Command;
+
+ bool OldStyle;
+
+ cmMakefile* Makefile;
+ cmListFileBacktrace Backtrace;
+};
+
+#endif
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
new file mode 100644
index 0000000..462edf9
--- /dev/null
+++ b/Source/cmTestGenerator.cxx
@@ -0,0 +1,187 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTestGenerator.h"
+
+#include "cmGeneratorExpression.h"
+#include "cmLocalGenerator.h"
+#include "cmOutputConverter.h"
+#include "cmSystemTools.h"
+#include "cmTest.h"
+
+cmTestGenerator::cmTestGenerator(
+ cmTest* test, std::vector<std::string> const& configurations)
+ : cmScriptGenerator("CTEST_CONFIGURATION_TYPE", configurations)
+ , Test(test)
+{
+ this->ActionsPerConfig = !test->GetOldStyle();
+ this->TestGenerated = false;
+ this->LG = CM_NULLPTR;
+}
+
+cmTestGenerator::~cmTestGenerator()
+{
+}
+
+void cmTestGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LG = lg;
+}
+
+void cmTestGenerator::GenerateScriptConfigs(std::ostream& os,
+ Indent const& indent)
+{
+ // Create the tests.
+ this->cmScriptGenerator::GenerateScriptConfigs(os, indent);
+}
+
+void cmTestGenerator::GenerateScriptActions(std::ostream& os,
+ Indent const& indent)
+{
+ if (this->ActionsPerConfig) {
+ // This is the per-config generation in a single-configuration
+ // build generator case. The superclass will call our per-config
+ // method.
+ this->cmScriptGenerator::GenerateScriptActions(os, indent);
+ } else {
+ // This is an old-style test, so there is only one config.
+ // assert(this->Test->GetOldStyle());
+ this->GenerateOldStyle(os, indent);
+ }
+}
+
+void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
+ const std::string& config,
+ Indent const& indent)
+{
+ this->TestGenerated = true;
+
+ // Set up generator expression evaluation context.
+ cmGeneratorExpression ge(this->Test->GetBacktrace());
+
+ // Start the test command.
+ os << indent << "add_test(" << this->Test->GetName() << " ";
+
+ // Get the test command line to be executed.
+ std::vector<std::string> const& command = this->Test->GetCommand();
+
+ // Check whether the command executable is a target whose name is to
+ // be translated.
+ std::string exe = command[0];
+ cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(exe);
+ if (target && target->GetType() == cmState::EXECUTABLE) {
+ // Use the target file on disk.
+ exe = target->GetFullPath(config);
+
+ // Prepend with the emulator when cross compiling if required.
+ const char* emulator = target->GetProperty("CROSSCOMPILING_EMULATOR");
+ if (emulator != CM_NULLPTR) {
+ std::vector<std::string> emulatorWithArgs;
+ cmSystemTools::ExpandListArgument(emulator, emulatorWithArgs);
+ 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) << " ";
+ }
+ }
+ } else {
+ // Use the command name given.
+ exe = ge.Parse(exe.c_str())->Evaluate(this->LG, config);
+ cmSystemTools::ConvertToUnixSlashes(exe);
+ }
+
+ // 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) {
+ os << " " << cmOutputConverter::EscapeForCMake(
+ ge.Parse(*ci)->Evaluate(this->LG, config));
+ }
+
+ // Finish the test command.
+ os << ")\n";
+
+ // Output properties for the test.
+ cmPropertyMap& pm = this->Test->GetProperties();
+ if (!pm.empty()) {
+ os << indent << "set_tests_properties(" << this->Test->GetName()
+ << " PROPERTIES ";
+ for (cmPropertyMap::const_iterator i = pm.begin(); i != pm.end(); ++i) {
+ os << " " << i->first << " "
+ << cmOutputConverter::EscapeForCMake(
+ ge.Parse(i->second.GetValue())->Evaluate(this->LG, config));
+ }
+ os << ")" << std::endl;
+ }
+}
+
+void cmTestGenerator::GenerateScriptNoConfig(std::ostream& os,
+ Indent const& indent)
+{
+ os << indent << "add_test(" << this->Test->GetName() << " NOT_AVAILABLE)\n";
+}
+
+bool cmTestGenerator::NeedsScriptNoConfig() const
+{
+ return (this->TestGenerated && // test generated for at least one config
+ this->ActionsPerConfig && // test is config-aware
+ this->Configurations.empty() && // test runs in all configs
+ !this->ConfigurationTypes->empty()); // config-dependent command
+}
+
+void cmTestGenerator::GenerateOldStyle(std::ostream& fout,
+ Indent const& indent)
+{
+ this->TestGenerated = true;
+
+ // Get the test command line to be executed.
+ std::vector<std::string> const& command = this->Test->GetCommand();
+
+ std::string exe = command[0];
+ cmSystemTools::ConvertToUnixSlashes(exe);
+ fout << indent;
+ fout << "add_test(";
+ fout << this->Test->GetName() << " \"" << exe << "\"";
+
+ for (std::vector<std::string>::const_iterator argit = command.begin() + 1;
+ argit != command.end(); ++argit) {
+ // Just double-quote all arguments so they are re-parsed
+ // correctly by the test system.
+ fout << " \"";
+ for (std::string::const_iterator c = argit->begin(); c != argit->end();
+ ++c) {
+ // Escape quotes within arguments. We should escape
+ // backslashes too but we cannot because it makes the result
+ // inconsistent with previous behavior of this command.
+ if ((*c == '"')) {
+ fout << '\\';
+ }
+ fout << *c;
+ }
+ fout << "\"";
+ }
+ fout << ")" << std::endl;
+
+ // Output properties for the test.
+ cmPropertyMap& pm = this->Test->GetProperties();
+ if (!pm.empty()) {
+ fout << indent << "set_tests_properties(" << this->Test->GetName()
+ << " PROPERTIES ";
+ for (cmPropertyMap::const_iterator i = pm.begin(); i != pm.end(); ++i) {
+ fout << " " << i->first << " "
+ << cmOutputConverter::EscapeForCMake(i->second.GetValue());
+ }
+ fout << ")" << std::endl;
+ }
+}
diff --git a/Source/cmTestGenerator.h b/Source/cmTestGenerator.h
new file mode 100644
index 0000000..66d590e
--- /dev/null
+++ b/Source/cmTestGenerator.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmTestGenerator_h
+#define cmTestGenerator_h
+
+#include "cmScriptGenerator.h"
+
+class cmTest;
+class cmLocalGenerator;
+
+/** \class cmTestGenerator
+ * \brief Support class for generating install scripts.
+ *
+ */
+class cmTestGenerator : public cmScriptGenerator
+{
+public:
+ cmTestGenerator(cmTest* test,
+ std::vector<std::string> const& configurations =
+ std::vector<std::string>());
+ ~cmTestGenerator() CM_OVERRIDE;
+
+ void Compute(cmLocalGenerator* lg);
+
+protected:
+ void GenerateScriptConfigs(std::ostream& os,
+ Indent const& indent) CM_OVERRIDE;
+ void GenerateScriptActions(std::ostream& os,
+ Indent const& indent) CM_OVERRIDE;
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent const& indent) CM_OVERRIDE;
+ void GenerateScriptNoConfig(std::ostream& os,
+ Indent const& indent) CM_OVERRIDE;
+ bool NeedsScriptNoConfig() const CM_OVERRIDE;
+ void GenerateOldStyle(std::ostream& os, Indent const& indent);
+
+ cmLocalGenerator* LG;
+ cmTest* Test;
+ bool TestGenerated;
+};
+
+#endif
diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx
new file mode 100644
index 0000000..c3c1d17
--- /dev/null
+++ b/Source/cmTimestamp.cxx
@@ -0,0 +1,170 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTimestamp.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <sstream>
+
+#include <sys/types.h>
+// include sys/stat.h after sys/types.h
+#include <sys/stat.h>
+
+std::string cmTimestamp::CurrentTime(const std::string& formatString,
+ bool utcFlag)
+{
+ time_t currentTimeT = time(CM_NULLPTR);
+ if (currentTimeT == time_t(-1)) {
+ return std::string();
+ }
+
+ return CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag);
+}
+
+std::string cmTimestamp::FileModificationTime(const char* path,
+ const std::string& formatString,
+ bool utcFlag)
+{
+ if (!cmsys::SystemTools::FileExists(path)) {
+ return std::string();
+ }
+
+ time_t mtime = cmsys::SystemTools::ModifiedTime(path);
+ return CreateTimestampFromTimeT(mtime, formatString, utcFlag);
+}
+
+std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
+ std::string formatString,
+ bool utcFlag) const
+{
+ if (formatString.empty()) {
+ formatString = "%Y-%m-%dT%H:%M:%S";
+ if (utcFlag) {
+ formatString += "Z";
+ }
+ }
+
+ struct tm timeStruct;
+ memset(&timeStruct, 0, sizeof(timeStruct));
+
+ struct tm* ptr = (struct tm*)CM_NULLPTR;
+ if (utcFlag) {
+ ptr = gmtime(&timeT);
+ } else {
+ ptr = localtime(&timeT);
+ }
+
+ if (ptr == CM_NULLPTR) {
+ return std::string();
+ }
+
+ timeStruct = *ptr;
+
+ std::string result;
+ for (std::string::size_type i = 0; i < formatString.size(); ++i) {
+ char c1 = formatString[i];
+ char c2 = (i + 1 < formatString.size()) ? formatString[i + 1]
+ : static_cast<char>(0);
+
+ if (c1 == '%' && c2 != 0) {
+ result += AddTimestampComponent(c2, timeStruct, timeT);
+ ++i;
+ } else {
+ result += c1;
+ }
+ }
+
+ return result;
+}
+
+time_t cmTimestamp::CreateUtcTimeTFromTm(struct tm& tm) const
+{
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ return _mkgmtime(&tm);
+#else
+ // From Linux timegm() manpage.
+
+ std::string tz_old = "TZ=";
+ if (const char* tz = cmSystemTools::GetEnv("TZ")) {
+ tz_old += tz;
+ }
+
+ // The standard says that "TZ=" or "TZ=[UNRECOGNIZED_TZ]" means UTC.
+ // It seems that "TZ=" does NOT work, at least under Windows
+ // with neither MSVC nor MinGW, so let's use explicit "TZ=UTC"
+
+ cmSystemTools::PutEnv("TZ=UTC");
+
+ tzset();
+
+ time_t result = mktime(&tm);
+
+ cmSystemTools::PutEnv(tz_old);
+
+ tzset();
+
+ return result;
+#endif
+}
+
+std::string cmTimestamp::AddTimestampComponent(char flag,
+ struct tm& timeStruct,
+ const time_t timeT) const
+{
+ std::string formatString = "%";
+ formatString += flag;
+
+ switch (flag) {
+ case 'd':
+ case 'H':
+ case 'I':
+ case 'j':
+ case 'm':
+ case 'M':
+ case 'S':
+ case 'U':
+ case 'w':
+ case 'y':
+ case 'Y':
+ break;
+ case 's': // Seconds since UNIX epoch (midnight 1-jan-1970)
+ {
+ // Build a time_t for UNIX epoch and substract from the input "timeT":
+ struct tm tmUnixEpoch;
+ memset(&tmUnixEpoch, 0, sizeof(tmUnixEpoch));
+ tmUnixEpoch.tm_mday = 1;
+ tmUnixEpoch.tm_year = 1970 - 1900;
+
+ const time_t unixEpoch = this->CreateUtcTimeTFromTm(tmUnixEpoch);
+ if (unixEpoch == -1) {
+ cmSystemTools::Error(
+ "Error generating UNIX epoch in "
+ "STRING(TIMESTAMP ...). Please, file a bug report aginst CMake");
+ return std::string();
+ }
+
+ std::ostringstream ss;
+ ss << static_cast<long int>(difftime(timeT, unixEpoch));
+ return ss.str();
+ }
+ default: {
+ return formatString;
+ }
+ }
+
+ char buffer[16];
+
+ size_t size =
+ strftime(buffer, sizeof(buffer), formatString.c_str(), &timeStruct);
+
+ return std::string(buffer, size);
+}
diff --git a/Source/cmTimestamp.h b/Source/cmTimestamp.h
new file mode 100644
index 0000000..77e1f7a
--- /dev/null
+++ b/Source/cmTimestamp.h
@@ -0,0 +1,45 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmTimestamp_h
+#define cmTimestamp_h
+
+#include "cmStandardIncludes.h"
+
+#include <string>
+#include <time.h>
+
+/** \class cmTimestamp
+ * \brief Utility class to generate string representation of a timestamp
+ *
+ */
+class cmTimestamp
+{
+public:
+ cmTimestamp() {}
+
+ std::string CurrentTime(const std::string& formatString, bool utcFlag);
+
+ std::string FileModificationTime(const char* path,
+ const std::string& formatString,
+ bool utcFlag);
+
+private:
+ time_t CreateUtcTimeTFromTm(struct tm& timeStruct) const;
+
+ std::string CreateTimestampFromTimeT(time_t timeT, std::string formatString,
+ bool utcFlag) const;
+
+ std::string AddTimestampComponent(char flag, struct tm& timeStruct,
+ time_t timeT) const;
+};
+
+#endif
diff --git a/Source/cmTryCompileCommand.cxx b/Source/cmTryCompileCommand.cxx
new file mode 100644
index 0000000..7930d23
--- /dev/null
+++ b/Source/cmTryCompileCommand.cxx
@@ -0,0 +1,39 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTryCompileCommand.h"
+
+// cmTryCompileCommand
+bool cmTryCompileCommand::InitialPass(std::vector<std::string> const& argv,
+ cmExecutionStatus&)
+{
+ if (argv.size() < 3) {
+ return false;
+ }
+
+ if (this->Makefile->GetCMakeInstance()->GetWorkingMode() ==
+ cmake::FIND_PACKAGE_MODE) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "The TRY_COMPILE() command is not supported in --find-package mode.");
+ return false;
+ }
+
+ this->TryCompileCode(argv, false);
+
+ // if They specified clean then we clean up what we can
+ if (this->SrcFileSignature) {
+ if (!this->Makefile->GetCMakeInstance()->GetDebugTryCompile()) {
+ this->CleanupFiles(this->BinaryDirectory.c_str());
+ }
+ }
+ return true;
+}
diff --git a/Source/cmTryCompileCommand.h b/Source/cmTryCompileCommand.h
new file mode 100644
index 0000000..abfe335
--- /dev/null
+++ b/Source/cmTryCompileCommand.h
@@ -0,0 +1,45 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmTryCompileCommand_h
+#define cmTryCompileCommand_h
+
+#include "cmCoreTryCompile.h"
+
+/** \class cmTryCompileCommand
+ * \brief Specifies where to install some files
+ *
+ * cmTryCompileCommand is used to test if soucre code can be compiled
+ */
+class cmTryCompileCommand : public cmCoreTryCompile
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmTryCompileCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "try_compile"; }
+
+ cmTypeMacro(cmTryCompileCommand, cmCoreTryCompile);
+};
+
+#endif
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
new file mode 100644
index 0000000..7b19048
--- /dev/null
+++ b/Source/cmTryRunCommand.cxx
@@ -0,0 +1,360 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTryRunCommand.h"
+
+#include "cmTryCompileCommand.h"
+#include <cmsys/FStream.hxx>
+
+// cmTryRunCommand
+bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv,
+ cmExecutionStatus&)
+{
+ if (argv.size() < 4) {
+ return false;
+ }
+
+ if (this->Makefile->GetCMakeInstance()->GetWorkingMode() ==
+ cmake::FIND_PACKAGE_MODE) {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "The TRY_RUN() command is not supported in --find-package mode.");
+ return false;
+ }
+
+ // build an arg list for TryCompile and extract the runArgs,
+ std::vector<std::string> tryCompile;
+
+ this->CompileResultVariable = "";
+ this->RunResultVariable = "";
+ this->OutputVariable = "";
+ this->RunOutputVariable = "";
+ this->CompileOutputVariable = "";
+
+ std::string runArgs;
+ unsigned int i;
+ for (i = 1; i < argv.size(); ++i) {
+ if (argv[i] == "ARGS") {
+ ++i;
+ while (i < argv.size() && argv[i] != "COMPILE_DEFINITIONS" &&
+ argv[i] != "CMAKE_FLAGS" && argv[i] != "LINK_LIBRARIES") {
+ runArgs += " ";
+ runArgs += argv[i];
+ ++i;
+ }
+ if (i < argv.size()) {
+ tryCompile.push_back(argv[i]);
+ }
+ } else {
+ if (argv[i] == "OUTPUT_VARIABLE") {
+ if (argv.size() <= (i + 1)) {
+ cmSystemTools::Error(
+ "OUTPUT_VARIABLE specified but there is no variable");
+ return false;
+ }
+ i++;
+ this->OutputVariable = argv[i];
+ } else if (argv[i] == "RUN_OUTPUT_VARIABLE") {
+ if (argv.size() <= (i + 1)) {
+ cmSystemTools::Error(
+ "RUN_OUTPUT_VARIABLE specified but there is no variable");
+ return false;
+ }
+ i++;
+ this->RunOutputVariable = argv[i];
+ } else if (argv[i] == "COMPILE_OUTPUT_VARIABLE") {
+ if (argv.size() <= (i + 1)) {
+ cmSystemTools::Error(
+ "COMPILE_OUTPUT_VARIABLE specified but there is no variable");
+ return false;
+ }
+ i++;
+ this->CompileOutputVariable = argv[i];
+ } else {
+ tryCompile.push_back(argv[i]);
+ }
+ }
+ }
+
+ // although they could be used together, don't allow it, because
+ // using OUTPUT_VARIABLE makes crosscompiling harder
+ if (this->OutputVariable.size() && (!this->RunOutputVariable.empty() ||
+ !this->CompileOutputVariable.empty())) {
+ cmSystemTools::Error(
+ "You cannot use OUTPUT_VARIABLE together with COMPILE_OUTPUT_VARIABLE "
+ "or RUN_OUTPUT_VARIABLE. Please use only COMPILE_OUTPUT_VARIABLE and/or "
+ "RUN_OUTPUT_VARIABLE.");
+ return false;
+ }
+
+ bool captureRunOutput = false;
+ if (!this->OutputVariable.empty()) {
+ captureRunOutput = true;
+ tryCompile.push_back("OUTPUT_VARIABLE");
+ tryCompile.push_back(this->OutputVariable);
+ }
+ if (!this->CompileOutputVariable.empty()) {
+ tryCompile.push_back("OUTPUT_VARIABLE");
+ tryCompile.push_back(this->CompileOutputVariable);
+ }
+ if (!this->RunOutputVariable.empty()) {
+ captureRunOutput = true;
+ }
+
+ this->RunResultVariable = argv[0];
+ this->CompileResultVariable = argv[1];
+
+ // do the try compile
+ int res = this->TryCompileCode(tryCompile, true);
+
+ // now try running the command if it compiled
+ if (!res) {
+ if (this->OutputFile.empty()) {
+ cmSystemTools::Error(this->FindErrorMessage.c_str());
+ } else {
+ // "run" it and capture the output
+ std::string runOutputContents;
+ if (this->Makefile->IsOn("CMAKE_CROSSCOMPILING") &&
+ !this->Makefile->IsDefinitionSet("CMAKE_CROSSCOMPILING_EMULATOR")) {
+ this->DoNotRunExecutable(runArgs, argv[3], captureRunOutput
+ ? &runOutputContents
+ : CM_NULLPTR);
+ } else {
+ this->RunExecutable(runArgs, &runOutputContents);
+ }
+
+ // now put the output into the variables
+ if (!this->RunOutputVariable.empty()) {
+ this->Makefile->AddDefinition(this->RunOutputVariable,
+ runOutputContents.c_str());
+ }
+
+ if (!this->OutputVariable.empty()) {
+ // if the TryCompileCore saved output in this outputVariable then
+ // prepend that output to this output
+ const char* compileOutput =
+ this->Makefile->GetDefinition(this->OutputVariable);
+ if (compileOutput) {
+ runOutputContents = std::string(compileOutput) + runOutputContents;
+ }
+ this->Makefile->AddDefinition(this->OutputVariable,
+ runOutputContents.c_str());
+ }
+ }
+ }
+
+ // if we created a directory etc, then cleanup after ourselves
+ if (!this->Makefile->GetCMakeInstance()->GetDebugTryCompile()) {
+ this->CleanupFiles(this->BinaryDirectory.c_str());
+ }
+ return true;
+}
+
+void cmTryRunCommand::RunExecutable(const std::string& runArgs,
+ std::string* out)
+{
+ int retVal = -1;
+
+ std::string finalCommand;
+ 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());
+ finalCommand += " ";
+ for (std::vector<std::string>::const_iterator ei =
+ emulatorWithArgs.begin() + 1;
+ ei != emulatorWithArgs.end(); ++ei) {
+ finalCommand += "\"";
+ finalCommand += *ei;
+ finalCommand += "\"";
+ finalCommand += " ";
+ }
+ }
+ finalCommand +=
+ cmSystemTools::ConvertToRunCommandPath(this->OutputFile.c_str());
+ if (!runArgs.empty()) {
+ finalCommand += runArgs;
+ }
+ int timeout = 0;
+ bool worked = cmSystemTools::RunSingleCommand(
+ finalCommand.c_str(), out, out, &retVal, CM_NULLPTR,
+ cmSystemTools::OUTPUT_NONE, timeout);
+ // set the run var
+ char retChar[1000];
+ if (worked) {
+ sprintf(retChar, "%i", retVal);
+ } else {
+ strcpy(retChar, "FAILED_TO_RUN");
+ }
+ this->Makefile->AddCacheDefinition(this->RunResultVariable, retChar,
+ "Result of TRY_RUN", cmState::INTERNAL);
+}
+
+/* This is only used when cross compiling. Instead of running the
+ executable, two cache variables are created which will hold the results
+ the executable would have produced.
+*/
+void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
+ const std::string& srcFile,
+ std::string* out)
+{
+ // copy the executable out of the CMakeFiles/ directory, so it is not
+ // removed at the end of TRY_RUN and the user can run it manually
+ // on the target platform.
+ std::string copyDest = this->Makefile->GetHomeOutputDirectory();
+ copyDest += cmake::GetCMakeFilesDirectory();
+ copyDest += "/";
+ copyDest += cmSystemTools::GetFilenameWithoutExtension(this->OutputFile);
+ copyDest += "-";
+ copyDest += this->RunResultVariable;
+ copyDest += cmSystemTools::GetFilenameExtension(this->OutputFile);
+ cmSystemTools::CopyFileAlways(this->OutputFile, copyDest);
+
+ std::string resultFileName = this->Makefile->GetHomeOutputDirectory();
+ resultFileName += "/TryRunResults.cmake";
+
+ std::string detailsString = "For details see ";
+ detailsString += resultFileName;
+
+ std::string internalRunOutputName =
+ this->RunResultVariable + "__TRYRUN_OUTPUT";
+ bool error = false;
+
+ if (this->Makefile->GetDefinition(this->RunResultVariable) == CM_NULLPTR) {
+ // if the variables doesn't exist, create it with a helpful error text
+ // and mark it as advanced
+ std::string comment;
+ comment += "Run result of TRY_RUN(), indicates whether the executable "
+ "would have been able to run on its target platform.\n";
+ comment += detailsString;
+ this->Makefile->AddCacheDefinition(this->RunResultVariable,
+ "PLEASE_FILL_OUT-FAILED_TO_RUN",
+ comment.c_str(), cmState::STRING);
+
+ cmState* state = this->Makefile->GetState();
+ const char* existingValue =
+ state->GetCacheEntryValue(this->RunResultVariable);
+ if (existingValue) {
+ state->SetCacheEntryProperty(this->RunResultVariable, "ADVANCED", "1");
+ }
+
+ error = true;
+ }
+
+ // is the output from the executable used ?
+ if (out != CM_NULLPTR) {
+ if (this->Makefile->GetDefinition(internalRunOutputName) == CM_NULLPTR) {
+ // if the variables doesn't exist, create it with a helpful error text
+ // and mark it as advanced
+ std::string comment;
+ comment +=
+ "Output of TRY_RUN(), contains the text, which the executable "
+ "would have printed on stdout and stderr on its target platform.\n";
+ comment += detailsString;
+
+ this->Makefile->AddCacheDefinition(internalRunOutputName,
+ "PLEASE_FILL_OUT-NOTFOUND",
+ comment.c_str(), cmState::STRING);
+ cmState* state = this->Makefile->GetState();
+ const char* existing = state->GetCacheEntryValue(internalRunOutputName);
+ if (existing) {
+ state->SetCacheEntryProperty(internalRunOutputName, "ADVANCED", "1");
+ }
+
+ error = true;
+ }
+ }
+
+ if (error) {
+ static bool firstTryRun = true;
+ cmsys::ofstream file(resultFileName.c_str(),
+ firstTryRun ? std::ios::out : std::ios::app);
+ if (file) {
+ if (firstTryRun) {
+ /* clang-format off */
+ file << "# This file was generated by CMake because it detected "
+ "TRY_RUN() commands\n"
+ "# in crosscompiling mode. It will be overwritten by the next "
+ "CMake run.\n"
+ "# Copy it to a safe location, set the variables to "
+ "appropriate values\n"
+ "# and use it then to preset the CMake cache (using -C).\n\n";
+ /* clang-format on */
+ }
+
+ std::string comment = "\n";
+ comment += this->RunResultVariable;
+ comment += "\n indicates whether the executable would have been able "
+ "to run on its\n"
+ " target platform. If so, set ";
+ comment += this->RunResultVariable;
+ comment += " to\n"
+ " the exit code (in many cases 0 for success), otherwise "
+ "enter \"FAILED_TO_RUN\".\n";
+ if (out != CM_NULLPTR) {
+ comment += internalRunOutputName;
+ comment +=
+ "\n contains the text the executable "
+ "would have printed on stdout and stderr.\n"
+ " If the executable would not have been able to run, set ";
+ comment += internalRunOutputName;
+ comment += " empty.\n"
+ " Otherwise check if the output is evaluated by the "
+ "calling CMake code. If so,\n"
+ " check what the source file would have printed when "
+ "called with the given arguments.\n";
+ }
+ comment += "The ";
+ comment += this->CompileResultVariable;
+ comment += " variable holds the build result for this TRY_RUN().\n\n"
+ "Source file : ";
+ comment += srcFile + "\n";
+ comment += "Executable : ";
+ comment += copyDest + "\n";
+ comment += "Run arguments : ";
+ comment += runArgs;
+ comment += "\n";
+ comment += " Called from: " + this->Makefile->FormatListFileStack();
+ cmsys::SystemTools::ReplaceString(comment, "\n", "\n# ");
+ file << comment << "\n\n";
+
+ file << "set( " << this->RunResultVariable << " \n \""
+ << this->Makefile->GetDefinition(this->RunResultVariable)
+ << "\"\n CACHE STRING \"Result from TRY_RUN\" FORCE)\n\n";
+
+ if (out != CM_NULLPTR) {
+ file << "set( " << internalRunOutputName << " \n \""
+ << this->Makefile->GetDefinition(internalRunOutputName)
+ << "\"\n CACHE STRING \"Output from TRY_RUN\" FORCE)\n\n";
+ }
+ file.close();
+ }
+ firstTryRun = false;
+
+ std::string errorMessage = "TRY_RUN() invoked in cross-compiling mode, "
+ "please set the following cache variables "
+ "appropriately:\n";
+ errorMessage += " " + this->RunResultVariable + " (advanced)\n";
+ if (out != CM_NULLPTR) {
+ errorMessage += " " + internalRunOutputName + " (advanced)\n";
+ }
+ errorMessage += detailsString;
+ cmSystemTools::Error(errorMessage.c_str());
+ return;
+ }
+
+ if (out != CM_NULLPTR) {
+ (*out) = this->Makefile->GetDefinition(internalRunOutputName);
+ }
+}
diff --git a/Source/cmTryRunCommand.h b/Source/cmTryRunCommand.h
new file mode 100644
index 0000000..b8eb1de
--- /dev/null
+++ b/Source/cmTryRunCommand.h
@@ -0,0 +1,58 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmTryRunCommand_h
+#define cmTryRunCommand_h
+
+#include "cmCoreTryCompile.h"
+
+/** \class cmTryRunCommand
+ * \brief Specifies where to install some files
+ *
+ * cmTryRunCommand is used to test if soucre code can be compiled
+ */
+class cmTryRunCommand : public cmCoreTryCompile
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmTryRunCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "try_run"; }
+
+ cmTypeMacro(cmTryRunCommand, cmCoreTryCompile);
+
+private:
+ void RunExecutable(const std::string& runArgs,
+ std::string* runOutputContents);
+ void DoNotRunExecutable(const std::string& runArgs,
+ const std::string& srcFile,
+ std::string* runOutputContents);
+
+ std::string CompileResultVariable;
+ std::string RunResultVariable;
+ std::string OutputVariable;
+ std::string RunOutputVariable;
+ std::string CompileOutputVariable;
+};
+
+#endif
diff --git a/Source/cmTypeMacro.h b/Source/cmTypeMacro.h
new file mode 100644
index 0000000..147eba8
--- /dev/null
+++ b/Source/cmTypeMacro.h
@@ -0,0 +1,40 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmTypeMacro_h
+#define cmTypeMacro_h
+
+// All subclasses of cmCommand or cmCTestGenericHandler should
+// invoke this macro.
+#define cmTypeMacro(thisClass, superclass) \
+ const char* GetNameOfClass() CM_OVERRIDE { return #thisClass; } \
+ typedef superclass Superclass; \
+ static bool IsTypeOf(const char* type) \
+ { \
+ if (!strcmp(#thisClass, type)) { \
+ return true; \
+ } \
+ return Superclass::IsTypeOf(type); \
+ } \
+ bool IsA(const char* type) CM_OVERRIDE \
+ { \
+ return thisClass::IsTypeOf(type); \
+ } \
+ static thisClass* SafeDownCast(cmObject* c) \
+ { \
+ if (c && c->IsA(#thisClass)) { \
+ return static_cast<thisClass*>(c); \
+ } \
+ return 0; \
+ } \
+ class cmTypeMacro_UseTrailingSemicolon
+
+#endif
diff --git a/Source/cmUnsetCommand.cxx b/Source/cmUnsetCommand.cxx
new file mode 100644
index 0000000..05ba65a
--- /dev/null
+++ b/Source/cmUnsetCommand.cxx
@@ -0,0 +1,58 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmUnsetCommand.h"
+
+// cmUnsetCommand
+bool cmUnsetCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1 || args.size() > 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ const char* variable = args[0].c_str();
+
+ // unset(ENV{VAR})
+ if (cmHasLiteralPrefix(variable, "ENV{") && strlen(variable) > 5) {
+ // what is the variable name
+ char* envVarName = new char[strlen(variable)];
+ strncpy(envVarName, variable + 4, strlen(variable) - 5);
+ envVarName[strlen(variable) - 5] = '\0';
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ cmSystemTools::UnsetEnv(envVarName);
+#endif
+ delete[] envVarName;
+ return true;
+ }
+ // unset(VAR)
+ else if (args.size() == 1) {
+ this->Makefile->RemoveDefinition(variable);
+ return true;
+ }
+ // unset(VAR CACHE)
+ else if ((args.size() == 2) && (args[1] == "CACHE")) {
+ this->Makefile->RemoveCacheDefinition(variable);
+ return true;
+ }
+ // unset(VAR PARENT_SCOPE)
+ else if ((args.size() == 2) && (args[1] == "PARENT_SCOPE")) {
+ this->Makefile->RaiseScope(variable, CM_NULLPTR);
+ return true;
+ }
+ // ERROR: second argument isn't CACHE or PARENT_SCOPE
+ else {
+ this->SetError("called with an invalid second argument");
+ return false;
+ }
+}
diff --git a/Source/cmUnsetCommand.h b/Source/cmUnsetCommand.h
new file mode 100644
index 0000000..6429c10
--- /dev/null
+++ b/Source/cmUnsetCommand.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmUnsetCommand_h
+#define cmUnsetCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmUnsetCommand
+ * \brief Unset a CMAKE variable
+ *
+ * cmUnsetCommand unsets or removes a variable.
+ */
+class cmUnsetCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmUnsetCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "unset"; }
+
+ cmTypeMacro(cmUnsetCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmUseMangledMesaCommand.cxx b/Source/cmUseMangledMesaCommand.cxx
new file mode 100644
index 0000000..1eb493a
--- /dev/null
+++ b/Source/cmUseMangledMesaCommand.cxx
@@ -0,0 +1,118 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmUseMangledMesaCommand.h"
+
+#include "cmSystemTools.h"
+
+#include <cmsys/FStream.hxx>
+#include <cmsys/RegularExpression.hxx>
+
+bool cmUseMangledMesaCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (this->Disallowed(
+ cmPolicies::CMP0030,
+ "The use_mangled_mesa command should not be called; see CMP0030.")) {
+ return true;
+ }
+ // expected two arguments:
+ // arguement one: the full path to gl_mangle.h
+ // arguement two : directory for output of edited headers
+ if (args.size() != 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ const char* inputDir = args[0].c_str();
+ std::string glh = inputDir;
+ glh += "/";
+ glh += "gl.h";
+ if (!cmSystemTools::FileExists(glh.c_str())) {
+ std::string e = "Bad path to Mesa, could not find: ";
+ e += glh;
+ e += " ";
+ this->SetError(e);
+ return false;
+ }
+ const char* destDir = args[1].c_str();
+ std::vector<std::string> files;
+ cmSystemTools::Glob(inputDir, "\\.h$", files);
+ if (files.empty()) {
+ cmSystemTools::Error("Could not open Mesa Directory ", inputDir);
+ return false;
+ }
+ cmSystemTools::MakeDirectory(destDir);
+ for (std::vector<std::string>::iterator i = files.begin(); i != files.end();
+ ++i) {
+ std::string path = inputDir;
+ path += "/";
+ path += *i;
+ this->CopyAndFullPathMesaHeader(path.c_str(), destDir);
+ }
+
+ return true;
+}
+
+void cmUseMangledMesaCommand::CopyAndFullPathMesaHeader(const char* source,
+ const char* outdir)
+{
+ std::string dir, file;
+ cmSystemTools::SplitProgramPath(source, dir, file);
+ std::string outFile = outdir;
+ outFile += "/";
+ outFile += file;
+ std::string tempOutputFile = outFile;
+ 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::ReportLastSystemError("");
+ return;
+ }
+ cmsys::ifstream fin(source);
+ if (!fin) {
+ cmSystemTools::Error("Could not open file for read in copy operation",
+ source);
+ return;
+ }
+ // now copy input to output and expand variables in the
+ // input file at the same time
+ std::string inLine;
+ // regular expression for any #include line
+ 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)(/|\\\\)([^<\"]+)");
+ // 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)) {
+ if (includeLine.find(inLine.c_str())) {
+ std::string includeFile = includeLine.match(1);
+ if (glDirLine.find(includeFile.c_str())) {
+ std::string gfile = glDirLine.match(3);
+ fout << "#include \"" << outdir << "/" << gfile << "\"\n";
+ } else if (glLine.find(includeFile.c_str())) {
+ fout << "#include \"" << outdir << "/" << includeLine.match(1)
+ << "\"\n";
+ } else {
+ fout << inLine << "\n";
+ }
+ } else {
+ fout << inLine << "\n";
+ }
+ }
+ // close the files before attempting to copy
+ fin.close();
+ fout.close();
+ cmSystemTools::CopyFileIfDifferent(tempOutputFile.c_str(), outFile.c_str());
+ cmSystemTools::RemoveFile(tempOutputFile.c_str());
+}
diff --git a/Source/cmUseMangledMesaCommand.h b/Source/cmUseMangledMesaCommand.h
new file mode 100644
index 0000000..5a44035
--- /dev/null
+++ b/Source/cmUseMangledMesaCommand.h
@@ -0,0 +1,30 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmUseMangledMesaCommand_h
+#define cmUseMangledMesaCommand_h
+
+#include "cmCommand.h"
+
+class cmUseMangledMesaCommand : public cmCommand
+{
+public:
+ cmTypeMacro(cmUseMangledMesaCommand, cmCommand);
+ cmCommand* Clone() CM_OVERRIDE { return new cmUseMangledMesaCommand; }
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+ std::string GetName() const CM_OVERRIDE { return "use_mangled_mesa"; }
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+protected:
+ void CopyAndFullPathMesaHeader(const char* source, const char* outdir);
+};
+
+#endif
diff --git a/Source/cmUtilitySourceCommand.cxx b/Source/cmUtilitySourceCommand.cxx
new file mode 100644
index 0000000..c50cbfb
--- /dev/null
+++ b/Source/cmUtilitySourceCommand.cxx
@@ -0,0 +1,119 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmUtilitySourceCommand.h"
+
+// cmUtilitySourceCommand
+bool cmUtilitySourceCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (this->Disallowed(
+ cmPolicies::CMP0034,
+ "The utility_source command should not be called; see CMP0034.")) {
+ return true;
+ }
+ if (args.size() < 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::vector<std::string>::const_iterator arg = args.begin();
+
+ // The first argument is the cache entry name.
+ std::string cacheEntry = *arg++;
+ const char* cacheValue = this->Makefile->GetDefinition(cacheEntry);
+ // If it exists already and appears up to date then we are done. If
+ // the string contains "(IntDir)" but that is not the
+ // CMAKE_CFG_INTDIR setting then the value is out of date.
+ const char* intDir =
+ this->Makefile->GetRequiredDefinition("CMAKE_CFG_INTDIR");
+
+ bool haveCacheValue = false;
+ if (this->Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
+ haveCacheValue = (cacheValue != CM_NULLPTR);
+ if (!haveCacheValue) {
+ std::string msg = "UTILITY_SOURCE is used in cross compiling mode for ";
+ msg += cacheEntry;
+ msg += ". If your intention is to run this executable, you need to "
+ "preload the cache with the full path to a version of that "
+ "program, which runs on this build machine.";
+ cmSystemTools::Message(msg.c_str(), "Warning");
+ }
+ } else {
+ cmState* state = this->Makefile->GetState();
+ haveCacheValue =
+ (cacheValue && (strstr(cacheValue, "(IntDir)") == CM_NULLPTR ||
+ (intDir && strcmp(intDir, "$(IntDir)") == 0)) &&
+ (state->GetCacheMajorVersion() != 0 &&
+ state->GetCacheMinorVersion() != 0));
+ }
+
+ if (haveCacheValue) {
+ return true;
+ }
+
+ // The second argument is the utility's executable name, which will be
+ // needed later.
+ std::string utilityName = *arg++;
+
+ // The third argument specifies the relative directory of the source
+ // of the utility.
+ std::string relativeSource = *arg++;
+ std::string utilitySource = this->Makefile->GetCurrentSourceDirectory();
+ utilitySource = utilitySource + "/" + relativeSource;
+
+ // If the directory doesn't exist, the source has not been included.
+ if (!cmSystemTools::FileExists(utilitySource.c_str())) {
+ return true;
+ }
+
+ // Make sure all the files exist in the source directory.
+ while (arg != args.end()) {
+ std::string file = utilitySource + "/" + *arg++;
+ if (!cmSystemTools::FileExists(file.c_str())) {
+ return true;
+ }
+ }
+
+ // The source exists.
+ std::string cmakeCFGout =
+ this->Makefile->GetRequiredDefinition("CMAKE_CFG_INTDIR");
+ std::string utilityDirectory = this->Makefile->GetCurrentBinaryDirectory();
+ std::string exePath;
+ if (this->Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH")) {
+ exePath = this->Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
+ }
+ if (!exePath.empty()) {
+ utilityDirectory = exePath;
+ } else {
+ utilityDirectory += "/" + relativeSource;
+ }
+
+ // Construct the cache entry for the executable's location.
+ std::string utilityExecutable = utilityDirectory + "/" + cmakeCFGout + "/" +
+ utilityName + this->Makefile->GetDefinition("CMAKE_EXECUTABLE_SUFFIX");
+
+ // make sure we remove any /./ in the name
+ cmSystemTools::ReplaceString(utilityExecutable, "/./", "/");
+
+ // Enter the value into the cache.
+ this->Makefile->AddCacheDefinition(cacheEntry, utilityExecutable.c_str(),
+ "Path to an internal program.",
+ cmState::FILEPATH);
+ // add a value into the cache that maps from the
+ // full path to the name of the project
+ cmSystemTools::ConvertToUnixSlashes(utilityExecutable);
+ this->Makefile->AddCacheDefinition(utilityExecutable, utilityName.c_str(),
+ "Executable to project name.",
+ cmState::INTERNAL);
+
+ return true;
+}
diff --git a/Source/cmUtilitySourceCommand.h b/Source/cmUtilitySourceCommand.h
new file mode 100644
index 0000000..2eb961f
--- /dev/null
+++ b/Source/cmUtilitySourceCommand.h
@@ -0,0 +1,27 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmUtilitySourceCommand_h
+#define cmUtilitySourceCommand_h
+
+#include "cmCommand.h"
+
+class cmUtilitySourceCommand : public cmCommand
+{
+public:
+ cmTypeMacro(cmUtilitySourceCommand, cmCommand);
+ cmCommand* Clone() CM_OVERRIDE { return new cmUtilitySourceCommand; }
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+ std::string GetName() const CM_OVERRIDE { return "utility_source"; }
+};
+
+#endif
diff --git a/Source/cmUuid.cxx b/Source/cmUuid.cxx
new file mode 100644
index 0000000..6d09bdf
--- /dev/null
+++ b/Source/cmUuid.cxx
@@ -0,0 +1,192 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmUuid.h"
+
+#include <string.h>
+
+#include "cm_sha2.h"
+#include <cmsys/MD5.h>
+
+cmUuid::cmUuid()
+{
+ Groups.push_back(4);
+ Groups.push_back(2);
+ Groups.push_back(2);
+ Groups.push_back(2);
+ Groups.push_back(6);
+}
+
+std::string cmUuid::FromMd5(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name) const
+{
+ std::vector<unsigned char> hashInput;
+ this->CreateHashInput(uuidNamespace, name, hashInput);
+
+ cmsysMD5_s* md5 = cmsysMD5_New();
+ cmsysMD5_Initialize(md5);
+ cmsysMD5_Append(md5, &hashInput[0], int(hashInput.size()));
+
+ unsigned char digest[16] = { 0 };
+ cmsysMD5_Finalize(md5, digest);
+
+ cmsysMD5_Delete(md5);
+
+ return this->FromDigest(digest, 3);
+}
+
+std::string cmUuid::FromSha1(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name) const
+{
+ std::vector<unsigned char> hashInput;
+ this->CreateHashInput(uuidNamespace, name, hashInput);
+
+ SHA_CTX* sha = new SHA_CTX;
+ SHA1_Init(sha);
+ SHA1_Update(sha, &hashInput[0], hashInput.size());
+
+ unsigned char digest[SHA1_DIGEST_LENGTH] = { 0 };
+ SHA1_Final(digest, sha);
+
+ delete sha;
+
+ return this->FromDigest(digest, 5);
+}
+
+void cmUuid::CreateHashInput(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name,
+ std::vector<unsigned char>& output) const
+{
+ output = uuidNamespace;
+
+ if (!name.empty()) {
+ output.resize(output.size() + name.size());
+
+ memcpy(&output[0] + uuidNamespace.size(), name.c_str(), name.size());
+ }
+}
+
+std::string cmUuid::FromDigest(const unsigned char* digest,
+ unsigned char version) const
+{
+ typedef unsigned char byte_t;
+
+ byte_t uuid[16] = { 0 };
+ memcpy(uuid, digest, 16);
+
+ uuid[6] &= 0xF;
+ uuid[6] |= byte_t(version << 4);
+
+ uuid[8] &= 0x3F;
+ uuid[8] |= 0x80;
+
+ return this->BinaryToString(uuid);
+}
+
+bool cmUuid::StringToBinary(std::string const& input,
+ std::vector<unsigned char>& output) const
+{
+ output.clear();
+ output.reserve(16);
+
+ if (input.length() != 36) {
+ return false;
+ }
+ size_t index = 0;
+ for (size_t i = 0; i < this->Groups.size(); ++i) {
+ if (i != 0 && input[index++] != '-') {
+ return false;
+ }
+ size_t digits = this->Groups[i] * 2;
+ if (!StringToBinaryImpl(input.substr(index, digits), output)) {
+ return false;
+ }
+
+ index += digits;
+ }
+
+ return true;
+}
+
+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) {
+ if (i != 0) {
+ output += '-';
+ }
+
+ size_t bytes = this->Groups[i];
+ for (size_t j = 0; j < bytes; ++j) {
+ unsigned char byte = input[inputIndex++];
+ output += this->ByteToHex(byte);
+ }
+ }
+
+ return output;
+}
+
+std::string cmUuid::ByteToHex(unsigned char byte) const
+{
+ std::string result;
+ for (int i = 0; i < 2; ++i) {
+ unsigned char rest = byte % 16;
+ byte /= 16;
+
+ char c = (rest < 0xA) ? char('0' + rest) : char('a' + (rest - 0xA));
+
+ result = c + result;
+ }
+
+ return result;
+}
+
+bool cmUuid::StringToBinaryImpl(std::string const& input,
+ std::vector<unsigned char>& output) const
+{
+ if (input.size() % 2) {
+ return false;
+ }
+
+ for (size_t i = 0; i < input.size(); i += 2) {
+ char c1 = 0;
+ if (!IntFromHexDigit(input[i], c1)) {
+ return false;
+ }
+
+ char c2 = 0;
+ if (!IntFromHexDigit(input[i + 1], c2)) {
+ return false;
+ }
+
+ output.push_back(char(c1 << 4 | c2));
+ }
+
+ return true;
+}
+
+bool cmUuid::IntFromHexDigit(char input, char& output) const
+{
+ if (input >= '0' && input <= '9') {
+ output = char(input - '0');
+ return true;
+ } else if (input >= 'a' && input <= 'f') {
+ output = char(input - 'a' + 0xA);
+ return true;
+ } else if (input >= 'A' && input <= 'F') {
+ output = char(input - 'A' + 0xA);
+ return true;
+ } else {
+ return false;
+ }
+}
diff --git a/Source/cmUuid.h b/Source/cmUuid.h
new file mode 100644
index 0000000..2bd7ec5
--- /dev/null
+++ b/Source/cmUuid.h
@@ -0,0 +1,55 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmUuid_h
+#define cmUuid_h
+
+#include "cmStandardIncludes.h"
+
+/** \class cmUuid
+ * \brief Utility class to generate UUIDs as defined by RFC4122
+ *
+ */
+class cmUuid
+{
+public:
+ cmUuid();
+
+ std::string FromMd5(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name) const;
+
+ std::string FromSha1(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name) const;
+
+ bool StringToBinary(std::string const& input,
+ std::vector<unsigned char>& output) const;
+
+private:
+ std::string ByteToHex(unsigned char byte) const;
+
+ void CreateHashInput(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name,
+ std::vector<unsigned char>& output) const;
+
+ std::string FromDigest(const unsigned char* digest,
+ unsigned char version) const;
+
+ bool StringToBinaryImpl(std::string const& input,
+ std::vector<unsigned char>& output) const;
+
+ std::string BinaryToString(const unsigned char* input) const;
+
+ bool IntFromHexDigit(char input, char& output) const;
+
+ std::vector<int> Groups;
+};
+
+#endif
diff --git a/Source/cmVS10CLFlagTable.h b/Source/cmVS10CLFlagTable.h
new file mode 100644
index 0000000..dbd760e
--- /dev/null
+++ b/Source/cmVS10CLFlagTable.h
@@ -0,0 +1,204 @@
+static cmVS7FlagTable cmVS10CLFlagTable[] = {
+
+ // Enum Properties
+ { "DebugInformationFormat", "Z7", "C7 compatible", "OldStyle", 0 },
+ { "DebugInformationFormat", "Zi", "Program Database", "ProgramDatabase", 0 },
+ { "DebugInformationFormat", "ZI", "Program Database for Edit And Continue",
+ "EditAndContinue", 0 },
+
+ { "WarningLevel", "W0", "Turn Off All Warnings", "TurnOffAllWarnings", 0 },
+ { "WarningLevel", "W1", "Level1", "Level1", 0 },
+ { "WarningLevel", "W2", "Level2", "Level2", 0 },
+ { "WarningLevel", "W3", "Level3", "Level3", 0 },
+ { "WarningLevel", "W4", "Level4", "Level4", 0 },
+ { "WarningLevel", "Wall", "EnableAllWarnings", "EnableAllWarnings", 0 },
+
+ { "Optimization", "Od", "Disabled", "Disabled", 0 },
+ { "Optimization", "O1", "Minimize Size", "MinSpace", 0 },
+ { "Optimization", "O2", "Maximize Speed", "MaxSpeed", 0 },
+ { "Optimization", "Ox", "Full Optimization", "Full", 0 },
+
+ { "InlineFunctionExpansion", "", "Default", "Default", 0 },
+ { "InlineFunctionExpansion", "Ob0", "Disabled", "Disabled", 0 },
+ { "InlineFunctionExpansion", "Ob1", "Only __inline", "OnlyExplicitInline",
+ 0 },
+ { "InlineFunctionExpansion", "Ob2", "Any Suitable", "AnySuitable", 0 },
+
+ { "FavorSizeOrSpeed", "Os", "Favor small code", "Size", 0 },
+ { "FavorSizeOrSpeed", "Ot", "Favor fast code", "Speed", 0 },
+ { "FavorSizeOrSpeed", "", "Neither", "Neither", 0 },
+
+ { "ExceptionHandling", "EHa", "Yes with SEH Exceptions", "Async", 0 },
+ { "ExceptionHandling", "EHsc", "Yes", "Sync", 0 },
+ { "ExceptionHandling", "EHs", "Yes with Extern C functions", "SyncCThrow",
+ 0 },
+ { "ExceptionHandling", "", "No", "false", 0 },
+
+ { "BasicRuntimeChecks", "RTCs", "Stack Frames", "StackFrameRuntimeCheck",
+ 0 },
+ { "BasicRuntimeChecks", "RTCu", "Uninitialized variables",
+ "UninitializedLocalUsageCheck", 0 },
+ { "BasicRuntimeChecks", "RTC1", "Both (/RTC1, equiv. to /RTCsu)",
+ "EnableFastChecks", 0 },
+ { "BasicRuntimeChecks", "", "Default", "Default", 0 },
+
+ { "RuntimeLibrary", "MT", "Multi-threaded", "MultiThreaded", 0 },
+ { "RuntimeLibrary", "MTd", "Multi-threaded Debug", "MultiThreadedDebug", 0 },
+ { "RuntimeLibrary", "MD", "Multi-threaded DLL", "MultiThreadedDLL", 0 },
+ { "RuntimeLibrary", "MDd", "Multi-threaded Debug DLL",
+ "MultiThreadedDebugDLL", 0 },
+
+ { "StructMemberAlignment", "Zp1", "1 Byte", "1Byte", 0 },
+ { "StructMemberAlignment", "Zp2", "2 Bytes", "2Bytes", 0 },
+ { "StructMemberAlignment", "Zp4", "4 Byte", "4Bytes", 0 },
+ { "StructMemberAlignment", "Zp8", "8 Bytes", "8Bytes", 0 },
+ { "StructMemberAlignment", "Zp16", "16 Bytes", "16Bytes", 0 },
+ { "StructMemberAlignment", "", "Default", "Default", 0 },
+
+ { "EnableEnhancedInstructionSet", "arch:SSE",
+ "Streaming SIMD Extensions (/arch:SSE)", "StreamingSIMDExtensions", 0 },
+ { "EnableEnhancedInstructionSet", "arch:SSE2",
+ "Streaming SIMD Extensions 2 (/arch:SSE2)", "StreamingSIMDExtensions2",
+ 0 },
+ { "EnableEnhancedInstructionSet", "", "Not Set", "NotSet", 0 },
+
+ { "FloatingPointModel", "fp:precise", "Precise", "Precise", 0 },
+ { "FloatingPointModel", "fp:strict", "Strict", "Strict", 0 },
+ { "FloatingPointModel", "fp:fast", "Fast", "Fast", 0 },
+
+ { "PrecompiledHeader", "Yc", "Create", "Create",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeader", "Yu", "Use", "Use",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeader", "", "Not Using Precompiled Headers", "NotUsing", 0 },
+
+ { "AssemblerOutput", "", "No Listing", "NoListing", 0 },
+ { "AssemblerOutput", "FA", "Assembly-Only Listing", "AssemblyCode", 0 },
+ { "AssemblerOutput", "FAc", "Assembly With Machine Code",
+ "AssemblyAndMachineCode", 0 },
+ { "AssemblerOutput", "FAs", "Assembly With Source Code",
+ "AssemblyAndSourceCode", 0 },
+ { "AssemblerOutput", "FAcs", "Assembly, Machine Code and Source", "All", 0 },
+
+ { "CallingConvention", "Gd", "__cdecl", "Cdecl", 0 },
+ { "CallingConvention", "Gr", "__fastcall", "FastCall", 0 },
+ { "CallingConvention", "Gz", "__stdcall", "StdCall", 0 },
+
+ { "CompileAs", "", "Default", "Default", 0 },
+ { "CompileAs", "TC", "Compile as C Code", "CompileAsC", 0 },
+ { "CompileAs", "TP", "Compile as C++ Code", "CompileAsCpp", 0 },
+
+ { "ErrorReporting", "errorReport:none", "Do Not Send Report", "None", 0 },
+ { "ErrorReporting", "errorReport:prompt", "Prompt Immediately", "Prompt",
+ 0 },
+ { "ErrorReporting", "errorReport:queue", "Queue For Next Login", "Queue",
+ 0 },
+ { "ErrorReporting", "errorReport:send", "Send Automatically", "Send", 0 },
+
+ { "CompileAsManaged", "", "No Common Language RunTime Support", "false", 0 },
+ { "CompileAsManaged", "clr", "Common Language RunTime Support", "true", 0 },
+ { "CompileAsManaged", "clr:pure",
+ "Pure MSIL Common Language RunTime Support", "Pure", 0 },
+ { "CompileAsManaged", "clr:safe",
+ "Safe MSIL Common Language RunTime Support", "Safe", 0 },
+ { "CompileAsManaged", "clr:oldSyntax",
+ "Common Language RunTime Support, Old Syntax", "OldSyntax", 0 },
+
+ // Bool Properties
+ { "SuppressStartupBanner", "nologo-", "", "false", 0 },
+ { "SuppressStartupBanner", "nologo", "", "true", 0 },
+ { "TreatWarningAsError", "WX-", "", "false", 0 },
+ { "TreatWarningAsError", "WX", "", "true", 0 },
+ { "IntrinsicFunctions", "Oi", "", "true", 0 },
+ { "OmitFramePointers", "Oy-", "", "false", 0 },
+ { "OmitFramePointers", "Oy", "", "true", 0 },
+ { "EnableFiberSafeOptimizations", "GT", "", "true", 0 },
+ { "WholeProgramOptimization", "GL", "", "true", 0 },
+ { "UndefineAllPreprocessorDefinitions", "u", "", "true", 0 },
+ { "IgnoreStandardIncludePath", "X", "", "true", 0 },
+ { "PreprocessToFile", "P", "", "true", 0 },
+ { "PreprocessSuppressLineNumbers", "EP", "", "true", 0 },
+ { "PreprocessKeepComments", "C", "", "true", 0 },
+ { "StringPooling", "GF-", "", "false", 0 },
+ { "StringPooling", "GF", "", "true", 0 },
+ { "MinimalRebuild", "Gm-", "", "false", 0 },
+ { "MinimalRebuild", "Gm", "", "true", 0 },
+ { "SmallerTypeCheck", "RTCc", "", "true", 0 },
+ { "BufferSecurityCheck", "GS-", "", "false", 0 },
+ { "BufferSecurityCheck", "GS", "", "true", 0 },
+ { "FunctionLevelLinking", "Gy-", "", "false", 0 },
+ { "FunctionLevelLinking", "Gy", "", "true", 0 },
+ { "FloatingPointExceptions", "fp:except-", "", "false", 0 },
+ { "FloatingPointExceptions", "fp:except", "", "true", 0 },
+ { "CreateHotpatchableImage", "hotpatch", "", "true", 0 },
+ { "DisableLanguageExtensions", "Za", "", "true", 0 },
+ { "TreatWChar_tAsBuiltInType", "Zc:wchar_t-", "", "false", 0 },
+ { "TreatWChar_tAsBuiltInType", "Zc:wchar_t", "", "true", 0 },
+ { "ForceConformanceInForLoopScope", "Zc:forScope-", "", "false", 0 },
+ { "ForceConformanceInForLoopScope", "Zc:forScope", "", "true", 0 },
+ { "RuntimeTypeInfo", "GR-", "", "false", 0 },
+ { "RuntimeTypeInfo", "GR", "", "true", 0 },
+ { "OpenMPSupport", "openmp-", "", "false", 0 },
+ { "OpenMPSupport", "openmp", "", "true", 0 },
+ { "ExpandAttributedSource", "Fx", "", "true", 0 },
+ { "ShowIncludes", "showIncludes", "", "true", 0 },
+ { "EnablePREfast", "analyze-", "", "false", 0 },
+ { "EnablePREfast", "analyze", "", "true", 0 },
+ { "UseFullPaths", "FC", "", "true", 0 },
+ { "OmitDefaultLibName", "Zl", "", "true", 0 },
+ { "UseUnicodeForAssemblerListing", "FAu", "", "true", 0 },
+
+ // Bool Properties With Argument
+ { "MultiProcessorCompilation", "MP", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "ProcessorNumber", "MP", "Multi-processor Compilation", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "GenerateXMLDocumentationFiles", "doc", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "XMLDocumentationFileName", "doc", "Generate XML Documentation Files", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "BrowseInformation", "FR", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "BrowseInformationFile", "FR", "Enable Browse Information", "",
+ cmVS7FlagTable::UserValueRequired },
+
+ // String List Properties
+ { "AdditionalIncludeDirectories", "I", "Additional Include Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AdditionalUsingDirectories", "AI", "Resolve #using References", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "PreprocessorDefinitions", "D ", "Preprocessor Definitions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "UndefinePreprocessorDefinitions", "U",
+ "Undefine Preprocessor Definitions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "DisableSpecificWarnings", "wd", "Disable Specific Warnings", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ForcedIncludeFiles", "FI", "Forced Include File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ForcedUsingFiles", "FU", "Forced #using File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "TreatSpecificWarningsAsErrors", "we", "Treat Specific Warnings As Errors",
+ "", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // String Properties
+ // Skip [TrackerLogDirectory] - no command line Switch.
+ { "PreprocessOutputPath", "Fi", "Preprocess Output Path", "",
+ cmVS7FlagTable::UserValue },
+ { "PrecompiledHeaderFile", "Yc", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "PrecompiledHeaderFile", "Yu", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "PrecompiledHeaderOutputFile", "Fp", "Precompiled Header Output File", "",
+ cmVS7FlagTable::UserValue },
+ { "AssemblerListingLocation", "Fa", "ASM List Location", "",
+ cmVS7FlagTable::UserValue },
+ { "ObjectFileName", "Fo", "Object File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "ProgramDataBaseFileName", "Fd", "Program Database File Name", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [XMLDocumentationFileName] - no command line Switch.
+ // Skip [BrowseInformationFile] - no command line Switch.
+ // Skip [AdditionalOptions] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS10LibFlagTable.h b/Source/cmVS10LibFlagTable.h
new file mode 100644
index 0000000..65f28ef
--- /dev/null
+++ b/Source/cmVS10LibFlagTable.h
@@ -0,0 +1,76 @@
+static cmVS7FlagTable cmVS10LibFlagTable[] = {
+
+ // Enum Properties
+ { "ErrorReporting", "ERRORREPORT:PROMPT", "PromptImmediately",
+ "PromptImmediately", 0 },
+ { "ErrorReporting", "ERRORREPORT:QUEUE", "Queue For Next Login",
+ "QueueForNextLogin", 0 },
+ { "ErrorReporting", "ERRORREPORT:SEND", "Send Error Report",
+ "SendErrorReport", 0 },
+ { "ErrorReporting", "ERRORREPORT:NONE", "No Error Report", "NoErrorReport",
+ 0 },
+
+ { "TargetMachine", "MACHINE:ARM", "MachineARM", "MachineARM", 0 },
+ { "TargetMachine", "MACHINE:EBC", "MachineEBC", "MachineEBC", 0 },
+ { "TargetMachine", "MACHINE:IA64", "MachineIA64", "MachineIA64", 0 },
+ { "TargetMachine", "MACHINE:MIPS", "MachineMIPS", "MachineMIPS", 0 },
+ { "TargetMachine", "MACHINE:MIPS16", "MachineMIPS16", "MachineMIPS16", 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU", "MachineMIPSFPU", "MachineMIPSFPU",
+ 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU16", "MachineMIPSFPU16",
+ "MachineMIPSFPU16", 0 },
+ { "TargetMachine", "MACHINE:SH4", "MachineSH4", "MachineSH4", 0 },
+ { "TargetMachine", "MACHINE:THUMB", "MachineTHUMB", "MachineTHUMB", 0 },
+ { "TargetMachine", "MACHINE:X64", "MachineX64", "MachineX64", 0 },
+ { "TargetMachine", "MACHINE:X86", "MachineX86", "MachineX86", 0 },
+
+ { "SubSystem", "SUBSYSTEM:CONSOLE", "Console", "Console", 0 },
+ { "SubSystem", "SUBSYSTEM:WINDOWS", "Windows", "Windows", 0 },
+ { "SubSystem", "SUBSYSTEM:NATIVE", "Native", "Native", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_APPLICATION", "EFI Application",
+ "EFI Application", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "EFI Boot Service Driver", "EFI Boot Service Driver", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_ROM", "EFI ROM", "EFI ROM", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_RUNTIME_DRIVER", "EFI Runtime", "EFI Runtime",
+ 0 },
+ { "SubSystem", "SUBSYSTEM:WINDOWSCE", "WindowsCE", "WindowsCE", 0 },
+ { "SubSystem", "SUBSYSTEM:POSIX", "POSIX", "POSIX", 0 },
+
+ // Bool Properties
+ { "SuppressStartupBanner", "NOLOGO", "", "true", 0 },
+ { "IgnoreAllDefaultLibraries", "NODEFAULTLIB", "", "true", 0 },
+ { "TreatLibWarningAsErrors", "WX:NO", "", "false", 0 },
+ { "TreatLibWarningAsErrors", "WX", "", "true", 0 },
+ { "Verbose", "VERBOSE", "", "true", 0 },
+ { "LinkTimeCodeGeneration", "LTCG", "", "true", 0 },
+
+ // Bool Properties With Argument
+
+ // String List Properties
+ // Skip [AdditionalDependencies] - no command line Switch.
+ { "AdditionalLibraryDirectories", "LIBPATH:",
+ "Additional Library Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "IgnoreSpecificDefaultLibraries", "NODEFAULTLIB:",
+ "Ignore Specific Default Libraries", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ExportNamedFunctions", "EXPORT:", "Export Named Functions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "RemoveObjects", "REMOVE:", "Remove Objects", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // String Properties
+ { "OutputFile", "OUT:", "Output File", "", cmVS7FlagTable::UserValue },
+ { "ModuleDefinitionFile", "DEF:", "Module Definition File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "ForceSymbolReferences", "INCLUDE:", "Force Symbol References", "",
+ cmVS7FlagTable::UserValue },
+ { "DisplayLibrary", "LIST:", "Display Library to standard output", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [MinimumRequiredVersion] - no command line Switch.
+ { "Name", "NAME:", "Name", "", cmVS7FlagTable::UserValue },
+ // Skip [TrackerLogDirectory] - no command line Switch.
+ // Skip [AdditionalOptions] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS10LinkFlagTable.h b/Source/cmVS10LinkFlagTable.h
new file mode 100644
index 0000000..c30ea9a
--- /dev/null
+++ b/Source/cmVS10LinkFlagTable.h
@@ -0,0 +1,244 @@
+static cmVS7FlagTable cmVS10LinkFlagTable[] = {
+
+ // Enum Properties
+ { "ShowProgress", "", "Not Set", "NotSet", 0 },
+ { "ShowProgress", "VERBOSE", "Display all progress messages", "LinkVerbose",
+ 0 },
+ { "ShowProgress", "VERBOSE:Lib", "For Libraries Searched", "LinkVerboseLib",
+ 0 },
+ { "ShowProgress", "VERBOSE:ICF",
+ "About COMDAT folding during optimized linking", "LinkVerboseICF", 0 },
+ { "ShowProgress", "VERBOSE:REF",
+ "About data removed during optimized linking", "LinkVerboseREF", 0 },
+ { "ShowProgress", "VERBOSE:SAFESEH", "About Modules incompatible with SEH",
+ "LinkVerboseSAFESEH", 0 },
+ { "ShowProgress", "VERBOSE:CLR",
+ "About linker activity related to managed code", "LinkVerboseCLR", 0 },
+
+ { "ForceFileOutput", "FORCE", "Enabled", "Enabled", 0 },
+ { "ForceFileOutput", "FORCE:MULTIPLE", "Multiply Defined Symbol Only",
+ "MultiplyDefinedSymbolOnly", 0 },
+ { "ForceFileOutput", "FORCE:UNRESOLVED", "Undefined Symbol Only",
+ "UndefinedSymbolOnly", 0 },
+
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN", "Enabled", "Enabled", 0 },
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN:5", "X86 Image Only",
+ "X86Image", 0 },
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN:6", "X64 Image Only",
+ "X64Image", 0 },
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN:16", "Itanium Image Only",
+ "ItaniumImage", 0 },
+
+ { "UACExecutionLevel", "level='asInvoker'", "asInvoker", "AsInvoker", 0 },
+ { "UACExecutionLevel", "level='highestAvailable'", "highestAvailable",
+ "HighestAvailable", 0 },
+ { "UACExecutionLevel", "level='requireAdministrator'",
+ "requireAdministrator", "RequireAdministrator", 0 },
+
+ { "SubSystem", "", "Not Set", "NotSet", 0 },
+ { "SubSystem", "SUBSYSTEM:CONSOLE", "Console", "Console", 0 },
+ { "SubSystem", "SUBSYSTEM:WINDOWS", "Windows", "Windows", 0 },
+ { "SubSystem", "SUBSYSTEM:NATIVE", "Native", "Native", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_APPLICATION", "EFI Application",
+ "EFI Application", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "EFI Boot Service Driver", "EFI Boot Service Driver", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_ROM", "EFI ROM", "EFI ROM", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_RUNTIME_DRIVER", "EFI Runtime", "EFI Runtime",
+ 0 },
+ { "SubSystem", "SUBSYSTEM:WINDOWSCE", "WindowsCE", "WindowsCE", 0 },
+ { "SubSystem", "SUBSYSTEM:POSIX", "POSIX", "POSIX", 0 },
+
+ { "Driver", "", "Not Set", "NotSet", 0 },
+ { "Driver", "Driver", "Driver", "Driver", 0 },
+ { "Driver", "DRIVER:UPONLY", "UP Only", "UpOnly", 0 },
+ { "Driver", "DRIVER:WDM", "WDM", "WDM", 0 },
+
+ { "LinkTimeCodeGeneration", "", "Default", "Default", 0 },
+ { "LinkTimeCodeGeneration", "LTCG", "Use Link Time Code Generation",
+ "UseLinkTimeCodeGeneration", 0 },
+ { "LinkTimeCodeGeneration", "LTCG:PGInstrument",
+ "Profile Guided Optimization - Instrument", "PGInstrument", 0 },
+ { "LinkTimeCodeGeneration", "LTCG:PGOptimize",
+ "Profile Guided Optimization - Optimization", "PGOptimization", 0 },
+ { "LinkTimeCodeGeneration", "LTCG:PGUpdate",
+ "Profile Guided Optimization - Update", "PGUpdate", 0 },
+
+ { "TargetMachine", "", "Not Set", "NotSet", 0 },
+ { "TargetMachine", "MACHINE:ARM", "MachineARM", "MachineARM", 0 },
+ { "TargetMachine", "MACHINE:EBC", "MachineEBC", "MachineEBC", 0 },
+ { "TargetMachine", "MACHINE:IA64", "MachineIA64", "MachineIA64", 0 },
+ { "TargetMachine", "MACHINE:MIPS", "MachineMIPS", "MachineMIPS", 0 },
+ { "TargetMachine", "MACHINE:MIPS16", "MachineMIPS16", "MachineMIPS16", 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU", "MachineMIPSFPU", "MachineMIPSFPU",
+ 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU16", "MachineMIPSFPU16",
+ "MachineMIPSFPU16", 0 },
+ { "TargetMachine", "MACHINE:SH4", "MachineSH4", "MachineSH4", 0 },
+ { "TargetMachine", "MACHINE:THUMB", "MachineTHUMB", "MachineTHUMB", 0 },
+ { "TargetMachine", "MACHINE:X64", "MachineX64", "MachineX64", 0 },
+ { "TargetMachine", "MACHINE:X86", "MachineX86", "MachineX86", 0 },
+
+ { "CLRThreadAttribute", "CLRTHREADATTRIBUTE:MTA", "MTA threading attribute",
+ "MTAThreadingAttribute", 0 },
+ { "CLRThreadAttribute", "CLRTHREADATTRIBUTE:STA", "STA threading attribute",
+ "STAThreadingAttribute", 0 },
+ { "CLRThreadAttribute", "CLRTHREADATTRIBUTE:NONE",
+ "Default threading attribute", "DefaultThreadingAttribute", 0 },
+
+ { "CLRImageType", "CLRIMAGETYPE:IJW", "Force IJW image", "ForceIJWImage",
+ 0 },
+ { "CLRImageType", "CLRIMAGETYPE:PURE", "Force Pure IL Image",
+ "ForcePureILImage", 0 },
+ { "CLRImageType", "CLRIMAGETYPE:SAFE", "Force Safe IL Image",
+ "ForceSafeILImage", 0 },
+ { "CLRImageType", "", "Default image type", "Default", 0 },
+
+ { "LinkErrorReporting", "ERRORREPORT:PROMPT", "PromptImmediately",
+ "PromptImmediately", 0 },
+ { "LinkErrorReporting", "ERRORREPORT:QUEUE", "Queue For Next Login",
+ "QueueForNextLogin", 0 },
+ { "LinkErrorReporting", "ERRORREPORT:SEND", "Send Error Report",
+ "SendErrorReport", 0 },
+ { "LinkErrorReporting", "ERRORREPORT:NONE", "No Error Report",
+ "NoErrorReport", 0 },
+
+ { "CLRSupportLastError", "CLRSupportLastError", "Enabled", "Enabled", 0 },
+ { "CLRSupportLastError", "CLRSupportLastError:NO", "Disabled", "Disabled",
+ 0 },
+ { "CLRSupportLastError", "CLRSupportLastError:SYSTEMDLL", "System Dlls Only",
+ "SystemDlls", 0 },
+
+ // Bool Properties
+ { "LinkIncremental", "INCREMENTAL:NO", "", "false", 0 },
+ { "LinkIncremental", "INCREMENTAL", "", "true", 0 },
+ { "SuppressStartupBanner", "NOLOGO", "", "true", 0 },
+ { "LinkStatus", "LTCG:NOSTATUS", "", "false", 0 },
+ { "LinkStatus", "LTCG:STATUS", "", "true", 0 },
+ { "PreventDllBinding", "ALLOWBIND:NO", "", "false", 0 },
+ { "PreventDllBinding", "ALLOWBIND", "", "true", 0 },
+ { "TreatLinkerWarningAsErrors", "WX:NO", "", "false", 0 },
+ { "TreatLinkerWarningAsErrors", "WX", "", "true", 0 },
+ { "IgnoreAllDefaultLibraries", "NODEFAULTLIB", "", "true", 0 },
+ { "GenerateManifest", "MANIFEST:NO", "", "false", 0 },
+ { "GenerateManifest", "MANIFEST", "", "true", 0 },
+ { "AllowIsolation", "ALLOWISOLATION:NO", "", "false", 0 },
+ { "UACUIAccess", "uiAccess='false'", "", "false", 0 },
+ { "UACUIAccess", "uiAccess='true'", "", "true", 0 },
+ { "GenerateDebugInformation", "DEBUG", "", "true",
+ cmVS7FlagTable::CaseInsensitive },
+ { "MapExports", "MAPINFO:EXPORTS", "", "true", 0 },
+ { "AssemblyDebug", "ASSEMBLYDEBUG:DISABLE", "", "false", 0 },
+ { "AssemblyDebug", "ASSEMBLYDEBUG", "", "true", 0 },
+ { "LargeAddressAware", "LARGEADDRESSAWARE:NO", "", "false", 0 },
+ { "LargeAddressAware", "LARGEADDRESSAWARE", "", "true", 0 },
+ { "TerminalServerAware", "TSAWARE:NO", "", "false", 0 },
+ { "TerminalServerAware", "TSAWARE", "", "true", 0 },
+ { "SwapRunFromCD", "SWAPRUN:CD", "", "true", 0 },
+ { "SwapRunFromNET", "SWAPRUN:NET", "", "true", 0 },
+ { "OptimizeReferences", "OPT:NOREF", "", "false", 0 },
+ { "OptimizeReferences", "OPT:REF", "", "true", 0 },
+ { "EnableCOMDATFolding", "OPT:NOICF", "", "false", 0 },
+ { "EnableCOMDATFolding", "OPT:ICF", "", "true", 0 },
+ { "IgnoreEmbeddedIDL", "IGNOREIDL", "", "true", 0 },
+ { "NoEntryPoint", "NOENTRY", "", "true", 0 },
+ { "SetChecksum", "RELEASE", "", "true", 0 },
+ { "RandomizedBaseAddress", "DYNAMICBASE:NO", "", "false", 0 },
+ { "RandomizedBaseAddress", "DYNAMICBASE", "", "true", 0 },
+ { "FixedBaseAddress", "FIXED:NO", "", "false", 0 },
+ { "FixedBaseAddress", "FIXED", "", "true", 0 },
+ { "DataExecutionPrevention", "NXCOMPAT:NO", "", "false", 0 },
+ { "DataExecutionPrevention", "NXCOMPAT", "", "true", 0 },
+ { "TurnOffAssemblyGeneration", "NOASSEMBLY", "", "true", 0 },
+ { "SupportUnloadOfDelayLoadedDLL", "DELAY:UNLOAD", "", "true", 0 },
+ { "SupportNobindOfDelayLoadedDLL", "DELAY:NOBIND", "", "true", 0 },
+ { "Profile", "PROFILE", "", "true", 0 },
+ { "LinkDelaySign", "DELAYSIGN:NO", "", "false", 0 },
+ { "LinkDelaySign", "DELAYSIGN", "", "true", 0 },
+ { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK:NO", "", "false", 0 },
+ { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK", "", "true", 0 },
+ { "ImageHasSafeExceptionHandlers", "SAFESEH:NO", "", "false", 0 },
+ { "ImageHasSafeExceptionHandlers", "SAFESEH", "", "true", 0 },
+ { "LinkDLL", "DLL", "", "true", 0 },
+
+ // Bool Properties With Argument
+ { "EnableUAC", "MANIFESTUAC:NO", "", "false", 0 },
+ { "EnableUAC", "MANIFESTUAC:", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "UACUIAccess", "MANIFESTUAC:", "Enable User Account Control (UAC)", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "GenerateMapFile", "MAP", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "MapFileName", "MAP:", "Generate Map File", "",
+ cmVS7FlagTable::UserValueRequired },
+
+ // String List Properties
+ { "AdditionalLibraryDirectories", "LIBPATH:",
+ "Additional Library Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ // Skip [AdditionalDependencies] - no command line Switch.
+ { "IgnoreSpecificDefaultLibraries", "NODEFAULTLIB:",
+ "Ignore Specific Default Libraries", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AddModuleNamesToAssembly", "ASSEMBLYMODULE:", "Add Module to Assembly",
+ "", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "EmbedManagedResourceFile", "ASSEMBLYRESOURCE:",
+ "Embed Managed Resource File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ForceSymbolReferences", "INCLUDE:", "Force Symbol References", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "DelayLoadDLLs", "DELAYLOAD:", "Delay Loaded Dlls", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AssemblyLinkResource", "ASSEMBLYLINKRESOURCE:", "Assembly Link Resource",
+ "", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AdditionalManifestDependencies", "MANIFESTDEPENDENCY:",
+ "Additional Manifest Dependencies", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // String Properties
+ { "OutputFile", "OUT:", "Output File", "", cmVS7FlagTable::UserValue },
+ { "Version", "VERSION:", "Version", "", cmVS7FlagTable::UserValue },
+ { "SpecifySectionAttributes", "SECTION:", "Specify Section Attributes", "",
+ cmVS7FlagTable::UserValue },
+ { "MSDOSStubFileName", "STUB:", "MS-DOS Stub File Name", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [TrackerLogDirectory] - no command line Switch.
+ { "ModuleDefinitionFile", "DEF:", "Module Definition File", "",
+ cmVS7FlagTable::UserValue },
+ { "ManifestFile", "ManifestFile:", "Manifest File", "",
+ cmVS7FlagTable::UserValue },
+ { "ProgramDatabaseFile", "PDB:", "Generate Program Database File", "",
+ cmVS7FlagTable::UserValue },
+ { "StripPrivateSymbols", "PDBSTRIPPED:", "Strip Private Symbols", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [MapFileName] - no command line Switch.
+ // Skip [MinimumRequiredVersion] - no command line Switch.
+ { "HeapReserveSize", "HEAP:", "Heap Reserve Size", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [HeapCommitSize] - no command line Switch.
+ { "StackReserveSize", "STACK:", "Stack Reserve Size", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [StackCommitSize] - no command line Switch.
+ { "FunctionOrder", "ORDER:@", "Function Order", "",
+ cmVS7FlagTable::UserValue },
+ { "ProfileGuidedDatabase", "PGD:", "Profile Guided Database", "",
+ cmVS7FlagTable::UserValue },
+ { "MidlCommandFile", "MIDL:@", "MIDL Commands", "",
+ cmVS7FlagTable::UserValue },
+ { "MergedIDLBaseFileName", "IDLOUT:", "Merged IDL Base File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "TypeLibraryFile", "TLBOUT:", "Type Library", "",
+ cmVS7FlagTable::UserValue },
+ { "EntryPointSymbol", "ENTRY:", "Entry Point", "",
+ cmVS7FlagTable::UserValue },
+ { "BaseAddress", "BASE:", "Base Address", "", cmVS7FlagTable::UserValue },
+ { "ImportLibrary", "IMPLIB:", "Import Library", "",
+ cmVS7FlagTable::UserValue },
+ { "MergeSections", "MERGE:", "Merge Sections", "",
+ cmVS7FlagTable::UserValue },
+ { "LinkKeyFile", "KEYFILE:", "Key File", "", cmVS7FlagTable::UserValue },
+ { "KeyContainer", "KEYCONTAINER:", "Key Container", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [AdditionalOptions] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS10MASMFlagTable.h b/Source/cmVS10MASMFlagTable.h
new file mode 100644
index 0000000..82e5270
--- /dev/null
+++ b/Source/cmVS10MASMFlagTable.h
@@ -0,0 +1,78 @@
+static cmVS7FlagTable cmVS10MASMFlagTable[] = {
+
+ // Enum Properties
+ { "PreserveIdentifierCase", "", "Default", "0", 0 },
+ { "PreserveIdentifierCase", "/Cp", "Preserves Identifier Case (/Cp)", "1",
+ 0 },
+ { "PreserveIdentifierCase", "/Cu",
+ "Maps all identifiers to upper case. (/Cu)", "2", 0 },
+ { "PreserveIdentifierCase", "/Cx",
+ "Preserves case in public and extern symbols. (/Cx)", "3", 0 },
+
+ { "WarningLevel", "/W0", "Warning Level 0 (/W0)", "0", 0 },
+ { "WarningLevel", "/W1", "Warning Level 1 (/W1)", "1", 0 },
+ { "WarningLevel", "/W2", "Warning Level 2 (/W2)", "2", 0 },
+ { "WarningLevel", "/W3", "Warning Level 3 (/W3)", "3", 0 },
+
+ { "PackAlignmentBoundary", "", "Default", "0", 0 },
+ { "PackAlignmentBoundary", "/Zp1", "One Byte Boundary (/Zp1)", "1", 0 },
+ { "PackAlignmentBoundary", "/Zp2", "Two Byte Boundary (/Zp2)", "2", 0 },
+ { "PackAlignmentBoundary", "/Zp4", "Four Byte Boundary (/Zp4)", "3", 0 },
+ { "PackAlignmentBoundary", "/Zp8", "Eight Byte Boundary (/Zp8)", "4", 0 },
+ { "PackAlignmentBoundary", "/Zp16", "Sixteen Byte Boundary (/Zp16)", "5",
+ 0 },
+
+ { "CallingConvention", "", "Default", "0", 0 },
+ { "CallingConvention", "/Gd", "Use C-style Calling Convention (/Gd)", "1",
+ 0 },
+ { "CallingConvention", "/Gz", "Use stdcall Calling Convention (/Gz)", "2",
+ 0 },
+ { "CallingConvention", "/Gc", "Use Pascal Calling Convention (/Gc)", "3",
+ 0 },
+
+ { "ErrorReporting", "/errorReport:prompt",
+ "Prompt to send report immediately (/errorReport:prompt)", "0", 0 },
+ { "ErrorReporting", "/errorReport:queue",
+ "Prompt to send report at the next logon (/errorReport:queue)", "1", 0 },
+ { "ErrorReporting", "/errorReport:send",
+ "Automatically send report (/errorReport:send)", "2", 0 },
+ { "ErrorReporting", "/errorReport:none",
+ "Do not send report (/errorReport:none)", "3", 0 },
+
+ // Bool Properties
+ { "NoLogo", "/nologo", "", "true", 0 },
+ { "GeneratePreprocessedSourceListing", "/EP", "", "true", 0 },
+ { "ListAllAvailableInformation", "/Sa", "", "true", 0 },
+ { "UseSafeExceptionHandlers", "/safeseh", "", "true", 0 },
+ { "AddFirstPassListing", "/Sf", "", "true", 0 },
+ { "EnableAssemblyGeneratedCodeListing", "/Sg", "", "true", 0 },
+ { "DisableSymbolTable", "/Sn", "", "true", 0 },
+ { "EnableFalseConditionalsInListing", "/Sx", "", "true", 0 },
+ { "TreatWarningsAsErrors", "/WX", "", "true", 0 },
+ { "MakeAllSymbolsPublic", "/Zf", "", "true", 0 },
+ { "GenerateDebugInformation", "/Zi", "", "true", 0 },
+ { "EnableMASM51Compatibility", "/Zm", "", "true", 0 },
+ { "PerformSyntaxCheckOnly", "/Zs", "", "true", 0 },
+
+ // Bool Properties With Argument
+
+ // String List Properties
+ { "PreprocessorDefinitions", "/D", "Preprocessor Definitions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "IncludePaths", "/I", "Include Paths", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "BrowseFile", "/FR", "Generate Browse Information File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ // Skip [AdditionalDependencies] - no command line Switch.
+
+ // String Properties
+ // Skip [Inputs] - no command line Switch.
+ { "ObjectFileName", "/Fo", "Object File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "AssembledCodeListingFile", "/Fl", "Assembled Code Listing File", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [CommandLineTemplate] - no command line Switch.
+ // Skip [ExecutionDescription] - no command line Switch.
+ // Skip [AdditionalOptions] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS10RCFlagTable.h b/Source/cmVS10RCFlagTable.h
new file mode 100644
index 0000000..32f35e5
--- /dev/null
+++ b/Source/cmVS10RCFlagTable.h
@@ -0,0 +1,6 @@
+static cmVS7FlagTable cmVS10RCFlagTable[] = {
+ // Bool Properties
+ { "NullTerminateStrings", "n", "", "true", 0 },
+
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS11CLFlagTable.h b/Source/cmVS11CLFlagTable.h
new file mode 100644
index 0000000..7531709
--- /dev/null
+++ b/Source/cmVS11CLFlagTable.h
@@ -0,0 +1,219 @@
+static cmVS7FlagTable cmVS11CLFlagTable[] = {
+
+ // Enum Properties
+ { "DebugInformationFormat", "", "None", "None", 0 },
+ { "DebugInformationFormat", "Z7", "C7 compatible", "OldStyle", 0 },
+ { "DebugInformationFormat", "Zi", "Program Database", "ProgramDatabase", 0 },
+ { "DebugInformationFormat", "ZI", "Program Database for Edit And Continue",
+ "EditAndContinue", 0 },
+
+ { "WarningLevel", "W0", "Turn Off All Warnings", "TurnOffAllWarnings", 0 },
+ { "WarningLevel", "W1", "Level1", "Level1", 0 },
+ { "WarningLevel", "W2", "Level2", "Level2", 0 },
+ { "WarningLevel", "W3", "Level3", "Level3", 0 },
+ { "WarningLevel", "W4", "Level4", "Level4", 0 },
+ { "WarningLevel", "Wall", "EnableAllWarnings", "EnableAllWarnings", 0 },
+
+ { "Optimization", "Od", "Disabled", "Disabled", 0 },
+ { "Optimization", "O1", "Minimize Size", "MinSpace", 0 },
+ { "Optimization", "O2", "Maximize Speed", "MaxSpeed", 0 },
+ { "Optimization", "Ox", "Full Optimization", "Full", 0 },
+
+ { "InlineFunctionExpansion", "", "Default", "Default", 0 },
+ { "InlineFunctionExpansion", "Ob0", "Disabled", "Disabled", 0 },
+ { "InlineFunctionExpansion", "Ob1", "Only __inline", "OnlyExplicitInline",
+ 0 },
+ { "InlineFunctionExpansion", "Ob2", "Any Suitable", "AnySuitable", 0 },
+
+ { "FavorSizeOrSpeed", "Os", "Favor small code", "Size", 0 },
+ { "FavorSizeOrSpeed", "Ot", "Favor fast code", "Speed", 0 },
+ { "FavorSizeOrSpeed", "", "Neither", "Neither", 0 },
+
+ { "ExceptionHandling", "EHa", "Yes with SEH Exceptions", "Async", 0 },
+ { "ExceptionHandling", "EHsc", "Yes", "Sync", 0 },
+ { "ExceptionHandling", "EHs", "Yes with Extern C functions", "SyncCThrow",
+ 0 },
+ { "ExceptionHandling", "", "No", "false", 0 },
+
+ { "BasicRuntimeChecks", "RTCs", "Stack Frames", "StackFrameRuntimeCheck",
+ 0 },
+ { "BasicRuntimeChecks", "RTCu", "Uninitialized variables",
+ "UninitializedLocalUsageCheck", 0 },
+ { "BasicRuntimeChecks", "RTC1", "Both (/RTC1, equiv. to /RTCsu)",
+ "EnableFastChecks", 0 },
+ { "BasicRuntimeChecks", "", "Default", "Default", 0 },
+
+ { "RuntimeLibrary", "MT", "Multi-threaded", "MultiThreaded", 0 },
+ { "RuntimeLibrary", "MTd", "Multi-threaded Debug", "MultiThreadedDebug", 0 },
+ { "RuntimeLibrary", "MD", "Multi-threaded DLL", "MultiThreadedDLL", 0 },
+ { "RuntimeLibrary", "MDd", "Multi-threaded Debug DLL",
+ "MultiThreadedDebugDLL", 0 },
+
+ { "StructMemberAlignment", "Zp1", "1 Byte", "1Byte", 0 },
+ { "StructMemberAlignment", "Zp2", "2 Bytes", "2Bytes", 0 },
+ { "StructMemberAlignment", "Zp4", "4 Byte", "4Bytes", 0 },
+ { "StructMemberAlignment", "Zp8", "8 Bytes", "8Bytes", 0 },
+ { "StructMemberAlignment", "Zp16", "16 Bytes", "16Bytes", 0 },
+ { "StructMemberAlignment", "", "Default", "Default", 0 },
+
+ { "EnableEnhancedInstructionSet", "arch:SSE", "Streaming SIMD Extensions",
+ "StreamingSIMDExtensions", 0 },
+ { "EnableEnhancedInstructionSet", "arch:SSE2", "Streaming SIMD Extensions 2",
+ "StreamingSIMDExtensions2", 0 },
+ { "EnableEnhancedInstructionSet", "arch:AVX", "Advanced Vector Extensions",
+ "AdvancedVectorExtensions", 0 },
+ { "EnableEnhancedInstructionSet", "arch:IA32", "No Enhanced Instructions",
+ "NoExtensions", 0 },
+ { "EnableEnhancedInstructionSet", "", "Not Set", "NotSet", 0 },
+
+ { "FloatingPointModel", "fp:precise", "Precise", "Precise", 0 },
+ { "FloatingPointModel", "fp:strict", "Strict", "Strict", 0 },
+ { "FloatingPointModel", "fp:fast", "Fast", "Fast", 0 },
+
+ { "PrecompiledHeader", "Yc", "Create", "Create",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeader", "Yu", "Use", "Use",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeader", "", "Not Using Precompiled Headers", "NotUsing", 0 },
+
+ { "AssemblerOutput", "", "No Listing", "NoListing", 0 },
+ { "AssemblerOutput", "FA", "Assembly-Only Listing", "AssemblyCode", 0 },
+ { "AssemblerOutput", "FAc", "Assembly With Machine Code",
+ "AssemblyAndMachineCode", 0 },
+ { "AssemblerOutput", "FAs", "Assembly With Source Code",
+ "AssemblyAndSourceCode", 0 },
+ { "AssemblerOutput", "FAcs", "Assembly, Machine Code and Source", "All", 0 },
+
+ { "CallingConvention", "Gd", "__cdecl", "Cdecl", 0 },
+ { "CallingConvention", "Gr", "__fastcall", "FastCall", 0 },
+ { "CallingConvention", "Gz", "__stdcall", "StdCall", 0 },
+
+ { "CompileAs", "", "Default", "Default", 0 },
+ { "CompileAs", "TC", "Compile as C Code", "CompileAsC", 0 },
+ { "CompileAs", "TP", "Compile as C++ Code", "CompileAsCpp", 0 },
+
+ { "ErrorReporting", "errorReport:none", "Do Not Send Report", "None", 0 },
+ { "ErrorReporting", "errorReport:prompt", "Prompt Immediately", "Prompt",
+ 0 },
+ { "ErrorReporting", "errorReport:queue", "Queue For Next Login", "Queue",
+ 0 },
+ { "ErrorReporting", "errorReport:send", "Send Automatically", "Send", 0 },
+
+ { "CompileAsManaged", "", "No Common Language RunTime Support", "false", 0 },
+ { "CompileAsManaged", "clr", "Common Language RunTime Support", "true", 0 },
+ { "CompileAsManaged", "clr:pure",
+ "Pure MSIL Common Language RunTime Support", "Pure", 0 },
+ { "CompileAsManaged", "clr:safe",
+ "Safe MSIL Common Language RunTime Support", "Safe", 0 },
+ { "CompileAsManaged", "clr:oldSyntax",
+ "Common Language RunTime Support, Old Syntax", "OldSyntax", 0 },
+
+ // Bool Properties
+ { "CompileAsWinRT", "ZW", "", "true", 0 },
+ { "WinRTNoStdLib", "ZW:nostdlib", "", "true", 0 },
+ { "SuppressStartupBanner", "nologo-", "", "false", 0 },
+ { "SuppressStartupBanner", "nologo", "", "true", 0 },
+ { "TreatWarningAsError", "WX-", "", "false", 0 },
+ { "TreatWarningAsError", "WX", "", "true", 0 },
+ { "SDLCheck", "sdl-", "", "false", 0 },
+ { "SDLCheck", "sdl", "", "true", 0 },
+ { "IntrinsicFunctions", "Oi", "", "true", 0 },
+ { "OmitFramePointers", "Oy-", "", "false", 0 },
+ { "OmitFramePointers", "Oy", "", "true", 0 },
+ { "EnableFiberSafeOptimizations", "GT", "", "true", 0 },
+ { "WholeProgramOptimization", "GL", "", "true", 0 },
+ { "UndefineAllPreprocessorDefinitions", "u", "", "true", 0 },
+ { "IgnoreStandardIncludePath", "X", "", "true", 0 },
+ { "PreprocessToFile", "P", "", "true", 0 },
+ { "PreprocessSuppressLineNumbers", "EP", "", "true", 0 },
+ { "PreprocessKeepComments", "C", "", "true", 0 },
+ { "StringPooling", "GF-", "", "false", 0 },
+ { "StringPooling", "GF", "", "true", 0 },
+ { "MinimalRebuild", "Gm-", "", "false", 0 },
+ { "MinimalRebuild", "Gm", "", "true", 0 },
+ { "SmallerTypeCheck", "RTCc", "", "true", 0 },
+ { "BufferSecurityCheck", "GS-", "", "false", 0 },
+ { "BufferSecurityCheck", "GS", "", "true", 0 },
+ { "FunctionLevelLinking", "Gy-", "", "false", 0 },
+ { "FunctionLevelLinking", "Gy", "", "true", 0 },
+ { "EnableParallelCodeGeneration", "Qpar-", "", "false", 0 },
+ { "EnableParallelCodeGeneration", "Qpar", "", "true", 0 },
+ { "FloatingPointExceptions", "fp:except-", "", "false", 0 },
+ { "FloatingPointExceptions", "fp:except", "", "true", 0 },
+ { "CreateHotpatchableImage", "hotpatch", "", "true", 0 },
+ { "DisableLanguageExtensions", "Za", "", "true", 0 },
+ { "TreatWChar_tAsBuiltInType", "Zc:wchar_t-", "", "false", 0 },
+ { "TreatWChar_tAsBuiltInType", "Zc:wchar_t", "", "true", 0 },
+ { "ForceConformanceInForLoopScope", "Zc:forScope-", "", "false", 0 },
+ { "ForceConformanceInForLoopScope", "Zc:forScope", "", "true", 0 },
+ { "RuntimeTypeInfo", "GR-", "", "false", 0 },
+ { "RuntimeTypeInfo", "GR", "", "true", 0 },
+ { "OpenMPSupport", "openmp-", "", "false", 0 },
+ { "OpenMPSupport", "openmp", "", "true", 0 },
+ { "ExpandAttributedSource", "Fx", "", "true", 0 },
+ { "UseUnicodeForAssemblerListing", "FAu", "", "true", 0 },
+ { "ShowIncludes", "showIncludes", "", "true", 0 },
+ { "EnablePREfast", "analyze-", "", "false", 0 },
+ { "EnablePREfast", "analyze", "", "true", 0 },
+ { "UseFullPaths", "FC", "", "true", 0 },
+ { "OmitDefaultLibName", "Zl", "", "true", 0 },
+
+ // Bool Properties With Argument
+ { "MultiProcessorCompilation", "MP", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "ProcessorNumber", "MP", "Multi-processor Compilation", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "GenerateXMLDocumentationFiles", "doc", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "XMLDocumentationFileName", "doc", "Generate XML Documentation Files", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "BrowseInformation", "FR", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "BrowseInformationFile", "FR", "Enable Browse Information", "",
+ cmVS7FlagTable::UserValueRequired },
+
+ // String List Properties
+ { "AdditionalIncludeDirectories", "I", "Additional Include Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AdditionalUsingDirectories", "AI", "Additional #using Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "PreprocessorDefinitions", "D ", "Preprocessor Definitions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "UndefinePreprocessorDefinitions", "U",
+ "Undefine Preprocessor Definitions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "DisableSpecificWarnings", "wd", "Disable Specific Warnings", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ForcedIncludeFiles", "FI", "Forced Include File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ForcedUsingFiles", "FU", "Forced #using File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "PREfastLog", "analyze:log", "Code Analysis Log", "",
+ cmVS7FlagTable::UserFollowing },
+ { "PREfastAdditionalPlugins", "analyze:plugin",
+ "Additional Code Analysis Native plugins", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "TreatSpecificWarningsAsErrors", "we", "Treat Specific Warnings As Errors",
+ "", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // String Properties
+ // Skip [TrackerLogDirectory] - no command line Switch.
+ { "PreprocessOutputPath", "Fi", "Preprocess Output Path", "",
+ cmVS7FlagTable::UserValue },
+ { "PrecompiledHeaderFile", "Yc", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "PrecompiledHeaderFile", "Yu", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "PrecompiledHeaderOutputFile", "Fp", "Precompiled Header Output File", "",
+ cmVS7FlagTable::UserValue },
+ { "AssemblerListingLocation", "Fa", "ASM List Location", "",
+ cmVS7FlagTable::UserValue },
+ { "ObjectFileName", "Fo", "Object File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "ProgramDataBaseFileName", "Fd", "Program Database File Name", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [XMLDocumentationFileName] - no command line Switch.
+ // Skip [BrowseInformationFile] - no command line Switch.
+ // Skip [AdditionalOptions] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS11LibFlagTable.h b/Source/cmVS11LibFlagTable.h
new file mode 100644
index 0000000..8aacaac
--- /dev/null
+++ b/Source/cmVS11LibFlagTable.h
@@ -0,0 +1,76 @@
+static cmVS7FlagTable cmVS11LibFlagTable[] = {
+
+ // Enum Properties
+ { "ErrorReporting", "ERRORREPORT:PROMPT", "PromptImmediately",
+ "PromptImmediately", 0 },
+ { "ErrorReporting", "ERRORREPORT:QUEUE", "Queue For Next Login",
+ "QueueForNextLogin", 0 },
+ { "ErrorReporting", "ERRORREPORT:SEND", "Send Error Report",
+ "SendErrorReport", 0 },
+ { "ErrorReporting", "ERRORREPORT:NONE", "No Error Report", "NoErrorReport",
+ 0 },
+
+ { "TargetMachine", "MACHINE:ARM", "MachineARM", "MachineARM", 0 },
+ { "TargetMachine", "MACHINE:EBC", "MachineEBC", "MachineEBC", 0 },
+ { "TargetMachine", "MACHINE:IA64", "MachineIA64", "MachineIA64", 0 },
+ { "TargetMachine", "MACHINE:MIPS", "MachineMIPS", "MachineMIPS", 0 },
+ { "TargetMachine", "MACHINE:MIPS16", "MachineMIPS16", "MachineMIPS16", 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU", "MachineMIPSFPU", "MachineMIPSFPU",
+ 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU16", "MachineMIPSFPU16",
+ "MachineMIPSFPU16", 0 },
+ { "TargetMachine", "MACHINE:SH4", "MachineSH4", "MachineSH4", 0 },
+ { "TargetMachine", "MACHINE:THUMB", "MachineTHUMB", "MachineTHUMB", 0 },
+ { "TargetMachine", "MACHINE:X64", "MachineX64", "MachineX64", 0 },
+ { "TargetMachine", "MACHINE:X86", "MachineX86", "MachineX86", 0 },
+
+ { "SubSystem", "SUBSYSTEM:CONSOLE", "Console", "Console", 0 },
+ { "SubSystem", "SUBSYSTEM:WINDOWS", "Windows", "Windows", 0 },
+ { "SubSystem", "SUBSYSTEM:NATIVE", "Native", "Native", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_APPLICATION", "EFI Application",
+ "EFI Application", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "EFI Boot Service Driver", "EFI Boot Service Driver", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_ROM", "EFI ROM", "EFI ROM", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_RUNTIME_DRIVER", "EFI Runtime", "EFI Runtime",
+ 0 },
+ { "SubSystem", "SUBSYSTEM:WINDOWSCE", "WindowsCE", "WindowsCE", 0 },
+ { "SubSystem", "SUBSYSTEM:POSIX", "POSIX", "POSIX", 0 },
+
+ // Bool Properties
+ { "SuppressStartupBanner", "NOLOGO", "", "true", 0 },
+ { "IgnoreAllDefaultLibraries", "NODEFAULTLIB", "", "true", 0 },
+ { "TreatLibWarningAsErrors", "WX:NO", "", "false", 0 },
+ { "TreatLibWarningAsErrors", "WX", "", "true", 0 },
+ { "Verbose", "VERBOSE", "", "true", 0 },
+ { "LinkTimeCodeGeneration", "LTCG", "", "true", 0 },
+
+ // Bool Properties With Argument
+
+ // String List Properties
+ // Skip [AdditionalDependencies] - no command line Switch.
+ { "AdditionalLibraryDirectories", "LIBPATH:",
+ "Additional Library Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "IgnoreSpecificDefaultLibraries", "NODEFAULTLIB:",
+ "Ignore Specific Default Libraries", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ExportNamedFunctions", "EXPORT:", "Export Named Functions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "RemoveObjects", "REMOVE:", "Remove Objects", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // String Properties
+ { "OutputFile", "OUT:", "Output File", "", cmVS7FlagTable::UserValue },
+ { "ModuleDefinitionFile", "DEF:", "Module Definition File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "ForceSymbolReferences", "INCLUDE:", "Force Symbol References", "",
+ cmVS7FlagTable::UserValue },
+ { "DisplayLibrary", "LIST:", "Display Library to standard output", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [MinimumRequiredVersion] - no command line Switch.
+ { "Name", "NAME:", "Name", "", cmVS7FlagTable::UserValue },
+ // Skip [AdditionalOptions] - no command line Switch.
+ // Skip [TrackerLogDirectory] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS11LinkFlagTable.h b/Source/cmVS11LinkFlagTable.h
new file mode 100644
index 0000000..1b3a046
--- /dev/null
+++ b/Source/cmVS11LinkFlagTable.h
@@ -0,0 +1,269 @@
+static cmVS7FlagTable cmVS11LinkFlagTable[] = {
+
+ // Enum Properties
+ { "ShowProgress", "", "Not Set", "NotSet", 0 },
+ { "ShowProgress", "VERBOSE", "Display all progress messages", "LinkVerbose",
+ 0 },
+ { "ShowProgress", "VERBOSE:Lib", "For Libraries Searched", "LinkVerboseLib",
+ 0 },
+ { "ShowProgress", "VERBOSE:ICF",
+ "About COMDAT folding during optimized linking", "LinkVerboseICF", 0 },
+ { "ShowProgress", "VERBOSE:REF",
+ "About data removed during optimized linking", "LinkVerboseREF", 0 },
+ { "ShowProgress", "VERBOSE:SAFESEH", "About Modules incompatible with SEH",
+ "LinkVerboseSAFESEH", 0 },
+ { "ShowProgress", "VERBOSE:CLR",
+ "About linker activity related to managed code", "LinkVerboseCLR", 0 },
+
+ { "ForceFileOutput", "FORCE", "Enabled", "Enabled", 0 },
+ { "ForceFileOutput", "FORCE:MULTIPLE", "Multiply Defined Symbol Only",
+ "MultiplyDefinedSymbolOnly", 0 },
+ { "ForceFileOutput", "FORCE:UNRESOLVED", "Undefined Symbol Only",
+ "UndefinedSymbolOnly", 0 },
+
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN", "Enabled", "Enabled", 0 },
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN:5", "X86 Image Only",
+ "X86Image", 0 },
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN:6", "X64 Image Only",
+ "X64Image", 0 },
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN:16", "Itanium Image Only",
+ "ItaniumImage", 0 },
+
+ { "UACExecutionLevel", "level='asInvoker'", "asInvoker", "AsInvoker", 0 },
+ { "UACExecutionLevel", "level='highestAvailable'", "highestAvailable",
+ "HighestAvailable", 0 },
+ { "UACExecutionLevel", "level='requireAdministrator'",
+ "requireAdministrator", "RequireAdministrator", 0 },
+
+ { "SubSystem", "", "Not Set", "NotSet", 0 },
+ { "SubSystem", "SUBSYSTEM:CONSOLE", "Console", "Console", 0 },
+ { "SubSystem", "SUBSYSTEM:WINDOWS", "Windows", "Windows", 0 },
+ { "SubSystem", "SUBSYSTEM:NATIVE", "Native", "Native", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_APPLICATION", "EFI Application",
+ "EFI Application", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "EFI Boot Service Driver", "EFI Boot Service Driver", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_ROM", "EFI ROM", "EFI ROM", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_RUNTIME_DRIVER", "EFI Runtime", "EFI Runtime",
+ 0 },
+ { "SubSystem", "SUBSYSTEM:POSIX", "POSIX", "POSIX", 0 },
+
+ { "Driver", "", "Not Set", "NotSet", 0 },
+ { "Driver", "Driver", "Driver", "Driver", 0 },
+ { "Driver", "DRIVER:UPONLY", "UP Only", "UpOnly", 0 },
+ { "Driver", "DRIVER:WDM", "WDM", "WDM", 0 },
+
+ { "LinkTimeCodeGeneration", "", "Default", "Default", 0 },
+ { "LinkTimeCodeGeneration", "LTCG", "Use Link Time Code Generation",
+ "UseLinkTimeCodeGeneration", 0 },
+ { "LinkTimeCodeGeneration", "LTCG:PGInstrument",
+ "Profile Guided Optimization - Instrument", "PGInstrument", 0 },
+ { "LinkTimeCodeGeneration", "LTCG:PGOptimize",
+ "Profile Guided Optimization - Optimization", "PGOptimization", 0 },
+ { "LinkTimeCodeGeneration", "LTCG:PGUpdate",
+ "Profile Guided Optimization - Update", "PGUpdate", 0 },
+
+ { "GenerateWindowsMetadata", "WINMD", "Yes", "true", 0 },
+ { "GenerateWindowsMetadata", "WINMD:NO", "No", "false", 0 },
+
+ { "WindowsMetadataSignHash", "WINMDSIGNHASH:SHA1", "SHA1", "SHA1", 0 },
+ { "WindowsMetadataSignHash", "WINMDSIGNHASH:SHA256", "SHA256", "SHA256", 0 },
+ { "WindowsMetadataSignHash", "WINMDSIGNHASH:SHA384", "SHA384", "SHA384", 0 },
+ { "WindowsMetadataSignHash", "WINMDSIGNHASH:SHA512", "SHA512", "SHA512", 0 },
+
+ { "TargetMachine", "", "Not Set", "NotSet", 0 },
+ { "TargetMachine", "MACHINE:ARM", "MachineARM", "MachineARM", 0 },
+ { "TargetMachine", "MACHINE:EBC", "MachineEBC", "MachineEBC", 0 },
+ { "TargetMachine", "MACHINE:IA64", "MachineIA64", "MachineIA64", 0 },
+ { "TargetMachine", "MACHINE:MIPS", "MachineMIPS", "MachineMIPS", 0 },
+ { "TargetMachine", "MACHINE:MIPS16", "MachineMIPS16", "MachineMIPS16", 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU", "MachineMIPSFPU", "MachineMIPSFPU",
+ 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU16", "MachineMIPSFPU16",
+ "MachineMIPSFPU16", 0 },
+ { "TargetMachine", "MACHINE:SH4", "MachineSH4", "MachineSH4", 0 },
+ { "TargetMachine", "MACHINE:THUMB", "MachineTHUMB", "MachineTHUMB", 0 },
+ { "TargetMachine", "MACHINE:X64", "MachineX64", "MachineX64", 0 },
+ { "TargetMachine", "MACHINE:X86", "MachineX86", "MachineX86", 0 },
+
+ { "CLRThreadAttribute", "CLRTHREADATTRIBUTE:MTA", "MTA threading attribute",
+ "MTAThreadingAttribute", 0 },
+ { "CLRThreadAttribute", "CLRTHREADATTRIBUTE:STA", "STA threading attribute",
+ "STAThreadingAttribute", 0 },
+ { "CLRThreadAttribute", "CLRTHREADATTRIBUTE:NONE",
+ "Default threading attribute", "DefaultThreadingAttribute", 0 },
+
+ { "CLRImageType", "CLRIMAGETYPE:IJW", "Force IJW image", "ForceIJWImage",
+ 0 },
+ { "CLRImageType", "CLRIMAGETYPE:PURE", "Force Pure IL Image",
+ "ForcePureILImage", 0 },
+ { "CLRImageType", "CLRIMAGETYPE:SAFE", "Force Safe IL Image",
+ "ForceSafeILImage", 0 },
+ { "CLRImageType", "", "Default image type", "Default", 0 },
+
+ { "SignHash", "CLRSIGNHASH:SHA1", "SHA1", "SHA1", 0 },
+ { "SignHash", "CLRSIGNHASH:SHA256", "SHA256", "SHA256", 0 },
+ { "SignHash", "CLRSIGNHASH:SHA384", "SHA384", "SHA384", 0 },
+ { "SignHash", "CLRSIGNHASH:SHA512", "SHA512", "SHA512", 0 },
+
+ { "LinkErrorReporting", "ERRORREPORT:PROMPT", "PromptImmediately",
+ "PromptImmediately", 0 },
+ { "LinkErrorReporting", "ERRORREPORT:QUEUE", "Queue For Next Login",
+ "QueueForNextLogin", 0 },
+ { "LinkErrorReporting", "ERRORREPORT:SEND", "Send Error Report",
+ "SendErrorReport", 0 },
+ { "LinkErrorReporting", "ERRORREPORT:NONE", "No Error Report",
+ "NoErrorReport", 0 },
+
+ { "CLRSupportLastError", "CLRSupportLastError", "Enabled", "Enabled", 0 },
+ { "CLRSupportLastError", "CLRSupportLastError:NO", "Disabled", "Disabled",
+ 0 },
+ { "CLRSupportLastError", "CLRSupportLastError:SYSTEMDLL", "System Dlls Only",
+ "SystemDlls", 0 },
+
+ // Bool Properties
+ { "LinkIncremental", "INCREMENTAL:NO", "", "false", 0 },
+ { "LinkIncremental", "INCREMENTAL", "", "true", 0 },
+ { "SuppressStartupBanner", "NOLOGO", "", "true", 0 },
+ { "LinkStatus", "LTCG:NOSTATUS", "", "false", 0 },
+ { "LinkStatus", "LTCG:STATUS", "", "true", 0 },
+ { "PreventDllBinding", "ALLOWBIND:NO", "", "false", 0 },
+ { "PreventDllBinding", "ALLOWBIND", "", "true", 0 },
+ { "TreatLinkerWarningAsErrors", "WX:NO", "", "false", 0 },
+ { "TreatLinkerWarningAsErrors", "WX", "", "true", 0 },
+ { "IgnoreAllDefaultLibraries", "NODEFAULTLIB", "", "true", 0 },
+ { "GenerateManifest", "MANIFEST:NO", "", "false", 0 },
+ { "GenerateManifest", "MANIFEST", "", "true", 0 },
+ { "AllowIsolation", "ALLOWISOLATION:NO", "", "false", 0 },
+ { "UACUIAccess", "uiAccess='false'", "", "false", 0 },
+ { "UACUIAccess", "uiAccess='true'", "", "true", 0 },
+ { "ManifestEmbed", "manifest:embed", "", "true", 0 },
+ { "GenerateDebugInformation", "DEBUG", "", "true",
+ cmVS7FlagTable::CaseInsensitive },
+ { "MapExports", "MAPINFO:EXPORTS", "", "true", 0 },
+ { "AssemblyDebug", "ASSEMBLYDEBUG:DISABLE", "", "false", 0 },
+ { "AssemblyDebug", "ASSEMBLYDEBUG", "", "true", 0 },
+ { "LargeAddressAware", "LARGEADDRESSAWARE:NO", "", "false", 0 },
+ { "LargeAddressAware", "LARGEADDRESSAWARE", "", "true", 0 },
+ { "TerminalServerAware", "TSAWARE:NO", "", "false", 0 },
+ { "TerminalServerAware", "TSAWARE", "", "true", 0 },
+ { "SwapRunFromCD", "SWAPRUN:CD", "", "true", 0 },
+ { "SwapRunFromNET", "SWAPRUN:NET", "", "true", 0 },
+ { "OptimizeReferences", "OPT:NOREF", "", "false", 0 },
+ { "OptimizeReferences", "OPT:REF", "", "true", 0 },
+ { "EnableCOMDATFolding", "OPT:NOICF", "", "false", 0 },
+ { "EnableCOMDATFolding", "OPT:ICF", "", "true", 0 },
+ { "IgnoreEmbeddedIDL", "IGNOREIDL", "", "true", 0 },
+ { "AppContainer", "APPCONTAINER", "", "true", 0 },
+ { "WindowsMetadataLinkDelaySign", "WINMDDELAYSIGN:NO", "", "false", 0 },
+ { "WindowsMetadataLinkDelaySign", "WINMDDELAYSIGN", "", "true", 0 },
+ { "NoEntryPoint", "NOENTRY", "", "true", 0 },
+ { "SetChecksum", "RELEASE", "", "true", 0 },
+ { "RandomizedBaseAddress", "DYNAMICBASE:NO", "", "false", 0 },
+ { "RandomizedBaseAddress", "DYNAMICBASE", "", "true", 0 },
+ { "FixedBaseAddress", "FIXED:NO", "", "false", 0 },
+ { "FixedBaseAddress", "FIXED", "", "true", 0 },
+ { "DataExecutionPrevention", "NXCOMPAT:NO", "", "false", 0 },
+ { "DataExecutionPrevention", "NXCOMPAT", "", "true", 0 },
+ { "TurnOffAssemblyGeneration", "NOASSEMBLY", "", "true", 0 },
+ { "SupportUnloadOfDelayLoadedDLL", "DELAY:UNLOAD", "", "true", 0 },
+ { "SupportNobindOfDelayLoadedDLL", "DELAY:NOBIND", "", "true", 0 },
+ { "Profile", "PROFILE", "", "true", 0 },
+ { "LinkDelaySign", "DELAYSIGN:NO", "", "false", 0 },
+ { "LinkDelaySign", "DELAYSIGN", "", "true", 0 },
+ { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK:NO", "", "false", 0 },
+ { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK", "", "true", 0 },
+ { "DetectOneDefinitionRule", "ODR", "", "true", 0 },
+ { "ImageHasSafeExceptionHandlers", "SAFESEH:NO", "", "false", 0 },
+ { "ImageHasSafeExceptionHandlers", "SAFESEH", "", "true", 0 },
+ { "LinkDLL", "DLL", "", "true", 0 },
+
+ // Bool Properties With Argument
+ { "EnableUAC", "MANIFESTUAC:NO", "", "false", 0 },
+ { "EnableUAC", "MANIFESTUAC:", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "UACUIAccess", "MANIFESTUAC:", "Enable User Account Control (UAC)", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "GenerateMapFile", "MAP", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "MapFileName", "MAP:", "Generate Map File", "",
+ cmVS7FlagTable::UserValueRequired },
+
+ // String List Properties
+ { "AdditionalLibraryDirectories", "LIBPATH:",
+ "Additional Library Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ // Skip [AdditionalDependencies] - no command line Switch.
+ { "IgnoreSpecificDefaultLibraries", "NODEFAULTLIB:",
+ "Ignore Specific Default Libraries", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AddModuleNamesToAssembly", "ASSEMBLYMODULE:", "Add Module to Assembly",
+ "", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "EmbedManagedResourceFile", "ASSEMBLYRESOURCE:",
+ "Embed Managed Resource File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ForceSymbolReferences", "INCLUDE:", "Force Symbol References", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "DelayLoadDLLs", "DELAYLOAD:", "Delay Loaded Dlls", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AssemblyLinkResource", "ASSEMBLYLINKRESOURCE:", "Assembly Link Resource",
+ "", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AdditionalManifestDependencies", "MANIFESTDEPENDENCY:",
+ "Additional Manifest Dependencies", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ManifestInput", "manifestinput:", "Manifest Input", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // String Properties
+ { "OutputFile", "OUT:", "Output File", "", cmVS7FlagTable::UserValue },
+ { "Version", "VERSION:", "Version", "", cmVS7FlagTable::UserValue },
+ { "SpecifySectionAttributes", "SECTION:", "Specify Section Attributes", "",
+ cmVS7FlagTable::UserValue },
+ { "MSDOSStubFileName", "STUB:", "MS-DOS Stub File Name", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [TrackerLogDirectory] - no command line Switch.
+ { "ModuleDefinitionFile", "DEF:", "Module Definition File", "",
+ cmVS7FlagTable::UserValue },
+ { "ManifestFile", "ManifestFile:", "Manifest File", "",
+ cmVS7FlagTable::UserValue },
+ { "ProgramDatabaseFile", "PDB:", "Generate Program Database File", "",
+ cmVS7FlagTable::UserValue },
+ { "StripPrivateSymbols", "PDBSTRIPPED:", "Strip Private Symbols", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [MapFileName] - no command line Switch.
+ // Skip [MinimumRequiredVersion] - no command line Switch.
+ { "HeapReserveSize", "HEAP:", "Heap Reserve Size", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [HeapCommitSize] - no command line Switch.
+ { "StackReserveSize", "STACK:", "Stack Reserve Size", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [StackCommitSize] - no command line Switch.
+ { "FunctionOrder", "ORDER:@", "Function Order", "",
+ cmVS7FlagTable::UserValue },
+ { "ProfileGuidedDatabase", "PGD:", "Profile Guided Database", "",
+ cmVS7FlagTable::UserValue },
+ { "MidlCommandFile", "MIDL:@", "MIDL Commands", "",
+ cmVS7FlagTable::UserValue },
+ { "MergedIDLBaseFileName", "IDLOUT:", "Merged IDL Base File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "TypeLibraryFile", "TLBOUT:", "Type Library", "",
+ cmVS7FlagTable::UserValue },
+ { "WindowsMetadataFile", "WINMDFILE:", "Windows Metadata File", "",
+ cmVS7FlagTable::UserValue },
+ { "WindowsMetadataLinkKeyFile", "WINMDKEYFILE:", "Windows Metadata Key File",
+ "", cmVS7FlagTable::UserValue },
+ { "WindowsMetadataKeyContainer", "WINMDKEYCONTAINER:",
+ "Windows Metadata Key Container", "", cmVS7FlagTable::UserValue },
+ { "EntryPointSymbol", "ENTRY:", "Entry Point", "",
+ cmVS7FlagTable::UserValue },
+ { "BaseAddress", "BASE:", "Base Address", "", cmVS7FlagTable::UserValue },
+ { "ImportLibrary", "IMPLIB:", "Import Library", "",
+ cmVS7FlagTable::UserValue },
+ { "MergeSections", "MERGE:", "Merge Sections", "",
+ cmVS7FlagTable::UserValue },
+ { "LinkKeyFile", "KEYFILE:", "Key File", "", cmVS7FlagTable::UserValue },
+ { "KeyContainer", "KEYCONTAINER:", "Key Container", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [AdditionalOptions] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS11MASMFlagTable.h b/Source/cmVS11MASMFlagTable.h
new file mode 100644
index 0000000..1aca169
--- /dev/null
+++ b/Source/cmVS11MASMFlagTable.h
@@ -0,0 +1,78 @@
+static cmVS7FlagTable cmVS11MASMFlagTable[] = {
+
+ // Enum Properties
+ { "PreserveIdentifierCase", "", "Default", "0", 0 },
+ { "PreserveIdentifierCase", "/Cp", "Preserves Identifier Case (/Cp)", "1",
+ 0 },
+ { "PreserveIdentifierCase", "/Cu",
+ "Maps all identifiers to upper case. (/Cu)", "2", 0 },
+ { "PreserveIdentifierCase", "/Cx",
+ "Preserves case in public and extern symbols. (/Cx)", "3", 0 },
+
+ { "WarningLevel", "/W0", "Warning Level 0 (/W0)", "0", 0 },
+ { "WarningLevel", "/W1", "Warning Level 1 (/W1)", "1", 0 },
+ { "WarningLevel", "/W2", "Warning Level 2 (/W2)", "2", 0 },
+ { "WarningLevel", "/W3", "Warning Level 3 (/W3)", "3", 0 },
+
+ { "PackAlignmentBoundary", "", "Default", "0", 0 },
+ { "PackAlignmentBoundary", "/Zp1", "One Byte Boundary (/Zp1)", "1", 0 },
+ { "PackAlignmentBoundary", "/Zp2", "Two Byte Boundary (/Zp2)", "2", 0 },
+ { "PackAlignmentBoundary", "/Zp4", "Four Byte Boundary (/Zp4)", "3", 0 },
+ { "PackAlignmentBoundary", "/Zp8", "Eight Byte Boundary (/Zp8)", "4", 0 },
+ { "PackAlignmentBoundary", "/Zp16", "Sixteen Byte Boundary (/Zp16)", "5",
+ 0 },
+
+ { "CallingConvention", "", "Default", "0", 0 },
+ { "CallingConvention", "/Gd", "Use C-style Calling Convention (/Gd)", "1",
+ 0 },
+ { "CallingConvention", "/Gz", "Use stdcall Calling Convention (/Gz)", "2",
+ 0 },
+ { "CallingConvention", "/Gc", "Use Pascal Calling Convention (/Gc)", "3",
+ 0 },
+
+ { "ErrorReporting", "/errorReport:prompt",
+ "Prompt to send report immediately (/errorReport:prompt)", "0", 0 },
+ { "ErrorReporting", "/errorReport:queue",
+ "Prompt to send report at the next logon (/errorReport:queue)", "1", 0 },
+ { "ErrorReporting", "/errorReport:send",
+ "Automatically send report (/errorReport:send)", "2", 0 },
+ { "ErrorReporting", "/errorReport:none",
+ "Do not send report (/errorReport:none)", "3", 0 },
+
+ // Bool Properties
+ { "NoLogo", "/nologo", "", "true", 0 },
+ { "GeneratePreprocessedSourceListing", "/EP", "", "true", 0 },
+ { "ListAllAvailableInformation", "/Sa", "", "true", 0 },
+ { "UseSafeExceptionHandlers", "/safeseh", "", "true", 0 },
+ { "AddFirstPassListing", "/Sf", "", "true", 0 },
+ { "EnableAssemblyGeneratedCodeListing", "/Sg", "", "true", 0 },
+ { "DisableSymbolTable", "/Sn", "", "true", 0 },
+ { "EnableFalseConditionalsInListing", "/Sx", "", "true", 0 },
+ { "TreatWarningsAsErrors", "/WX", "", "true", 0 },
+ { "MakeAllSymbolsPublic", "/Zf", "", "true", 0 },
+ { "GenerateDebugInformation", "/Zi", "", "true", 0 },
+ { "EnableMASM51Compatibility", "/Zm", "", "true", 0 },
+ { "PerformSyntaxCheckOnly", "/Zs", "", "true", 0 },
+
+ // Bool Properties With Argument
+
+ // String List Properties
+ { "PreprocessorDefinitions", "/D", "Preprocessor Definitions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "IncludePaths", "/I", "Include Paths", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "BrowseFile", "/FR", "Generate Browse Information File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ // Skip [AdditionalDependencies] - no command line Switch.
+
+ // String Properties
+ // Skip [Inputs] - no command line Switch.
+ { "ObjectFileName", "/Fo", "Object File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "AssembledCodeListingFile", "/Fl", "Assembled Code Listing File", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [CommandLineTemplate] - no command line Switch.
+ // Skip [ExecutionDescription] - no command line Switch.
+ // Skip [AdditionalOptions] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS11RCFlagTable.h b/Source/cmVS11RCFlagTable.h
new file mode 100644
index 0000000..666e434
--- /dev/null
+++ b/Source/cmVS11RCFlagTable.h
@@ -0,0 +1,6 @@
+static cmVS7FlagTable cmVS11RCFlagTable[] = {
+ // Bool Properties
+ { "NullTerminateStrings", "n", "", "true", 0 },
+
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS12CLFlagTable.h b/Source/cmVS12CLFlagTable.h
new file mode 100644
index 0000000..9515c91
--- /dev/null
+++ b/Source/cmVS12CLFlagTable.h
@@ -0,0 +1,221 @@
+static cmVS7FlagTable cmVS12CLFlagTable[] = {
+
+ // Enum Properties
+ { "DebugInformationFormat", "", "None", "None", 0 },
+ { "DebugInformationFormat", "Z7", "C7 compatible", "OldStyle", 0 },
+ { "DebugInformationFormat", "Zi", "Program Database", "ProgramDatabase", 0 },
+ { "DebugInformationFormat", "ZI", "Program Database for Edit And Continue",
+ "EditAndContinue", 0 },
+
+ { "WarningLevel", "W0", "Turn Off All Warnings", "TurnOffAllWarnings", 0 },
+ { "WarningLevel", "W1", "Level1", "Level1", 0 },
+ { "WarningLevel", "W2", "Level2", "Level2", 0 },
+ { "WarningLevel", "W3", "Level3", "Level3", 0 },
+ { "WarningLevel", "W4", "Level4", "Level4", 0 },
+ { "WarningLevel", "Wall", "EnableAllWarnings", "EnableAllWarnings", 0 },
+
+ { "Optimization", "", "Custom", "Custom", 0 },
+ { "Optimization", "Od", "Disabled", "Disabled", 0 },
+ { "Optimization", "O1", "Minimize Size", "MinSpace", 0 },
+ { "Optimization", "O2", "Maximize Speed", "MaxSpeed", 0 },
+ { "Optimization", "Ox", "Full Optimization", "Full", 0 },
+
+ { "InlineFunctionExpansion", "", "Default", "Default", 0 },
+ { "InlineFunctionExpansion", "Ob0", "Disabled", "Disabled", 0 },
+ { "InlineFunctionExpansion", "Ob1", "Only __inline", "OnlyExplicitInline",
+ 0 },
+ { "InlineFunctionExpansion", "Ob2", "Any Suitable", "AnySuitable", 0 },
+
+ { "FavorSizeOrSpeed", "Os", "Favor small code", "Size", 0 },
+ { "FavorSizeOrSpeed", "Ot", "Favor fast code", "Speed", 0 },
+ { "FavorSizeOrSpeed", "", "Neither", "Neither", 0 },
+
+ { "ExceptionHandling", "EHa", "Yes with SEH Exceptions", "Async", 0 },
+ { "ExceptionHandling", "EHsc", "Yes", "Sync", 0 },
+ { "ExceptionHandling", "EHs", "Yes with Extern C functions", "SyncCThrow",
+ 0 },
+ { "ExceptionHandling", "", "No", "false", 0 },
+
+ { "BasicRuntimeChecks", "RTCs", "Stack Frames", "StackFrameRuntimeCheck",
+ 0 },
+ { "BasicRuntimeChecks", "RTCu", "Uninitialized variables",
+ "UninitializedLocalUsageCheck", 0 },
+ { "BasicRuntimeChecks", "RTC1", "Both (/RTC1, equiv. to /RTCsu)",
+ "EnableFastChecks", 0 },
+ { "BasicRuntimeChecks", "", "Default", "Default", 0 },
+
+ { "RuntimeLibrary", "MT", "Multi-threaded", "MultiThreaded", 0 },
+ { "RuntimeLibrary", "MTd", "Multi-threaded Debug", "MultiThreadedDebug", 0 },
+ { "RuntimeLibrary", "MD", "Multi-threaded DLL", "MultiThreadedDLL", 0 },
+ { "RuntimeLibrary", "MDd", "Multi-threaded Debug DLL",
+ "MultiThreadedDebugDLL", 0 },
+
+ { "StructMemberAlignment", "Zp1", "1 Byte", "1Byte", 0 },
+ { "StructMemberAlignment", "Zp2", "2 Bytes", "2Bytes", 0 },
+ { "StructMemberAlignment", "Zp4", "4 Byte", "4Bytes", 0 },
+ { "StructMemberAlignment", "Zp8", "8 Bytes", "8Bytes", 0 },
+ { "StructMemberAlignment", "Zp16", "16 Bytes", "16Bytes", 0 },
+ { "StructMemberAlignment", "", "Default", "Default", 0 },
+
+ { "BufferSecurityCheck", "GS-", "Disable Security Check", "false", 0 },
+ { "BufferSecurityCheck", "GS", "Enable Security Check", "true", 0 },
+
+ { "EnableEnhancedInstructionSet", "arch:SSE", "Streaming SIMD Extensions",
+ "StreamingSIMDExtensions", 0 },
+ { "EnableEnhancedInstructionSet", "arch:SSE2", "Streaming SIMD Extensions 2",
+ "StreamingSIMDExtensions2", 0 },
+ { "EnableEnhancedInstructionSet", "arch:AVX", "Advanced Vector Extensions",
+ "AdvancedVectorExtensions", 0 },
+ { "EnableEnhancedInstructionSet", "arch:IA32", "No Enhanced Instructions",
+ "NoExtensions", 0 },
+ { "EnableEnhancedInstructionSet", "", "Not Set", "NotSet", 0 },
+
+ { "FloatingPointModel", "fp:precise", "Precise", "Precise", 0 },
+ { "FloatingPointModel", "fp:strict", "Strict", "Strict", 0 },
+ { "FloatingPointModel", "fp:fast", "Fast", "Fast", 0 },
+
+ { "PrecompiledHeader", "Yc", "Create", "Create",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeader", "Yu", "Use", "Use",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeader", "", "Not Using Precompiled Headers", "NotUsing", 0 },
+
+ { "AssemblerOutput", "", "No Listing", "NoListing", 0 },
+ { "AssemblerOutput", "FA", "Assembly-Only Listing", "AssemblyCode", 0 },
+ { "AssemblerOutput", "FAc", "Assembly With Machine Code",
+ "AssemblyAndMachineCode", 0 },
+ { "AssemblerOutput", "FAs", "Assembly With Source Code",
+ "AssemblyAndSourceCode", 0 },
+ { "AssemblerOutput", "FAcs", "Assembly, Machine Code and Source", "All", 0 },
+
+ { "CallingConvention", "Gd", "__cdecl", "Cdecl", 0 },
+ { "CallingConvention", "Gr", "__fastcall", "FastCall", 0 },
+ { "CallingConvention", "Gz", "__stdcall", "StdCall", 0 },
+ { "CallingConvention", "Gv", "__vectorcall", "VectorCall", 0 },
+
+ { "CompileAs", "", "Default", "Default", 0 },
+ { "CompileAs", "TC", "Compile as C Code", "CompileAsC", 0 },
+ { "CompileAs", "TP", "Compile as C++ Code", "CompileAsCpp", 0 },
+
+ { "ErrorReporting", "errorReport:none", "Do Not Send Report", "None", 0 },
+ { "ErrorReporting", "errorReport:prompt", "Prompt Immediately", "Prompt",
+ 0 },
+ { "ErrorReporting", "errorReport:queue", "Queue For Next Login", "Queue",
+ 0 },
+ { "ErrorReporting", "errorReport:send", "Send Automatically", "Send", 0 },
+
+ { "CompileAsManaged", "", "No Common Language RunTime Support", "false", 0 },
+ { "CompileAsManaged", "clr", "Common Language RunTime Support", "true", 0 },
+ { "CompileAsManaged", "clr:pure",
+ "Pure MSIL Common Language RunTime Support", "Pure", 0 },
+ { "CompileAsManaged", "clr:safe",
+ "Safe MSIL Common Language RunTime Support", "Safe", 0 },
+ { "CompileAsManaged", "clr:oldSyntax",
+ "Common Language RunTime Support, Old Syntax", "OldSyntax", 0 },
+
+ // Bool Properties
+ { "CompileAsWinRT", "ZW", "", "true", 0 },
+ { "WinRTNoStdLib", "ZW:nostdlib", "", "true", 0 },
+ { "SuppressStartupBanner", "nologo", "", "true", 0 },
+ { "TreatWarningAsError", "WX-", "", "false", 0 },
+ { "TreatWarningAsError", "WX", "", "true", 0 },
+ { "SDLCheck", "sdl-", "", "false", 0 },
+ { "SDLCheck", "sdl", "", "true", 0 },
+ { "IntrinsicFunctions", "Oi", "", "true", 0 },
+ { "OmitFramePointers", "Oy-", "", "false", 0 },
+ { "OmitFramePointers", "Oy", "", "true", 0 },
+ { "EnableFiberSafeOptimizations", "GT", "", "true", 0 },
+ { "WholeProgramOptimization", "GL", "", "true", 0 },
+ { "UndefineAllPreprocessorDefinitions", "u", "", "true", 0 },
+ { "IgnoreStandardIncludePath", "X", "", "true", 0 },
+ { "PreprocessToFile", "P", "", "true", 0 },
+ { "PreprocessSuppressLineNumbers", "EP", "", "true", 0 },
+ { "PreprocessKeepComments", "C", "", "true", 0 },
+ { "StringPooling", "GF-", "", "false", 0 },
+ { "StringPooling", "GF", "", "true", 0 },
+ { "MinimalRebuild", "Gm-", "", "false", 0 },
+ { "MinimalRebuild", "Gm", "", "true", 0 },
+ { "SmallerTypeCheck", "RTCc", "", "true", 0 },
+ { "FunctionLevelLinking", "Gy-", "", "false", 0 },
+ { "FunctionLevelLinking", "Gy", "", "true", 0 },
+ { "EnableParallelCodeGeneration", "Qpar-", "", "false", 0 },
+ { "EnableParallelCodeGeneration", "Qpar", "", "true", 0 },
+ { "FloatingPointExceptions", "fp:except-", "", "false", 0 },
+ { "FloatingPointExceptions", "fp:except", "", "true", 0 },
+ { "CreateHotpatchableImage", "hotpatch", "", "true", 0 },
+ { "DisableLanguageExtensions", "Za", "", "true", 0 },
+ { "TreatWChar_tAsBuiltInType", "Zc:wchar_t-", "", "false", 0 },
+ { "TreatWChar_tAsBuiltInType", "Zc:wchar_t", "", "true", 0 },
+ { "ForceConformanceInForLoopScope", "Zc:forScope-", "", "false", 0 },
+ { "ForceConformanceInForLoopScope", "Zc:forScope", "", "true", 0 },
+ { "RuntimeTypeInfo", "GR-", "", "false", 0 },
+ { "RuntimeTypeInfo", "GR", "", "true", 0 },
+ { "OpenMPSupport", "openmp-", "", "false", 0 },
+ { "OpenMPSupport", "openmp", "", "true", 0 },
+ { "ExpandAttributedSource", "Fx", "", "true", 0 },
+ { "UseUnicodeForAssemblerListing", "FAu", "", "true", 0 },
+ { "ShowIncludes", "showIncludes", "", "true", 0 },
+ { "EnablePREfast", "analyze-", "", "false", 0 },
+ { "EnablePREfast", "analyze", "", "true", 0 },
+ { "UseFullPaths", "FC", "", "true", 0 },
+ { "OmitDefaultLibName", "Zl", "", "true", 0 },
+
+ // Bool Properties With Argument
+ { "MultiProcessorCompilation", "MP", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "ProcessorNumber", "MP", "Multi-processor Compilation", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "GenerateXMLDocumentationFiles", "doc", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "XMLDocumentationFileName", "doc", "Generate XML Documentation Files", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "BrowseInformation", "FR", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "BrowseInformationFile", "FR", "Enable Browse Information", "",
+ cmVS7FlagTable::UserValueRequired },
+
+ // String List Properties
+ { "AdditionalIncludeDirectories", "I", "Additional Include Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AdditionalUsingDirectories", "AI", "Additional #using Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "PreprocessorDefinitions", "D ", "Preprocessor Definitions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "UndefinePreprocessorDefinitions", "U",
+ "Undefine Preprocessor Definitions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "DisableSpecificWarnings", "wd", "Disable Specific Warnings", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ForcedIncludeFiles", "FI", "Forced Include File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ForcedUsingFiles", "FU", "Forced #using File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "PREfastLog", "analyze:log", "Code Analysis Log", "",
+ cmVS7FlagTable::UserFollowing },
+ { "PREfastAdditionalPlugins", "analyze:plugin",
+ "Additional Code Analysis Native plugins", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "TreatSpecificWarningsAsErrors", "we", "Treat Specific Warnings As Errors",
+ "", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // String Properties
+ // Skip [TrackerLogDirectory] - no command line Switch.
+ { "PreprocessOutputPath", "Fi", "Preprocess Output Path", "",
+ cmVS7FlagTable::UserValue },
+ { "PrecompiledHeaderFile", "Yc", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "PrecompiledHeaderFile", "Yu", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "PrecompiledHeaderOutputFile", "Fp", "Precompiled Header Output File", "",
+ cmVS7FlagTable::UserValue },
+ { "AssemblerListingLocation", "Fa", "ASM List Location", "",
+ cmVS7FlagTable::UserValue },
+ { "ObjectFileName", "Fo", "Object File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "ProgramDataBaseFileName", "Fd", "Program Database File Name", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [XMLDocumentationFileName] - no command line Switch.
+ // Skip [BrowseInformationFile] - no command line Switch.
+ // Skip [AdditionalOptions] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS12LibFlagTable.h b/Source/cmVS12LibFlagTable.h
new file mode 100644
index 0000000..0f7a259
--- /dev/null
+++ b/Source/cmVS12LibFlagTable.h
@@ -0,0 +1,76 @@
+static cmVS7FlagTable cmVS12LibFlagTable[] = {
+
+ // Enum Properties
+ { "ErrorReporting", "ERRORREPORT:PROMPT", "PromptImmediately",
+ "PromptImmediately", 0 },
+ { "ErrorReporting", "ERRORREPORT:QUEUE", "Queue For Next Login",
+ "QueueForNextLogin", 0 },
+ { "ErrorReporting", "ERRORREPORT:SEND", "Send Error Report",
+ "SendErrorReport", 0 },
+ { "ErrorReporting", "ERRORREPORT:NONE", "No Error Report", "NoErrorReport",
+ 0 },
+
+ { "TargetMachine", "MACHINE:ARM", "MachineARM", "MachineARM", 0 },
+ { "TargetMachine", "MACHINE:EBC", "MachineEBC", "MachineEBC", 0 },
+ { "TargetMachine", "MACHINE:IA64", "MachineIA64", "MachineIA64", 0 },
+ { "TargetMachine", "MACHINE:MIPS", "MachineMIPS", "MachineMIPS", 0 },
+ { "TargetMachine", "MACHINE:MIPS16", "MachineMIPS16", "MachineMIPS16", 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU", "MachineMIPSFPU", "MachineMIPSFPU",
+ 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU16", "MachineMIPSFPU16",
+ "MachineMIPSFPU16", 0 },
+ { "TargetMachine", "MACHINE:SH4", "MachineSH4", "MachineSH4", 0 },
+ { "TargetMachine", "MACHINE:THUMB", "MachineTHUMB", "MachineTHUMB", 0 },
+ { "TargetMachine", "MACHINE:X64", "MachineX64", "MachineX64", 0 },
+ { "TargetMachine", "MACHINE:X86", "MachineX86", "MachineX86", 0 },
+
+ { "SubSystem", "SUBSYSTEM:CONSOLE", "Console", "Console", 0 },
+ { "SubSystem", "SUBSYSTEM:WINDOWS", "Windows", "Windows", 0 },
+ { "SubSystem", "SUBSYSTEM:NATIVE", "Native", "Native", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_APPLICATION", "EFI Application",
+ "EFI Application", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "EFI Boot Service Driver", "EFI Boot Service Driver", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_ROM", "EFI ROM", "EFI ROM", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_RUNTIME_DRIVER", "EFI Runtime", "EFI Runtime",
+ 0 },
+ { "SubSystem", "SUBSYSTEM:WINDOWSCE", "WindowsCE", "WindowsCE", 0 },
+ { "SubSystem", "SUBSYSTEM:POSIX", "POSIX", "POSIX", 0 },
+
+ // Bool Properties
+ { "SuppressStartupBanner", "NOLOGO", "", "true", 0 },
+ { "IgnoreAllDefaultLibraries", "NODEFAULTLIB", "", "true", 0 },
+ { "TreatLibWarningAsErrors", "WX:NO", "", "false", 0 },
+ { "TreatLibWarningAsErrors", "WX", "", "true", 0 },
+ { "Verbose", "VERBOSE", "", "true", 0 },
+ { "LinkTimeCodeGeneration", "LTCG", "", "true", 0 },
+
+ // Bool Properties With Argument
+
+ // String List Properties
+ // Skip [AdditionalDependencies] - no command line Switch.
+ { "AdditionalLibraryDirectories", "LIBPATH:",
+ "Additional Library Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "IgnoreSpecificDefaultLibraries", "NODEFAULTLIB:",
+ "Ignore Specific Default Libraries", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ExportNamedFunctions", "EXPORT:", "Export Named Functions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "RemoveObjects", "REMOVE:", "Remove Objects", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // String Properties
+ { "OutputFile", "OUT:", "Output File", "", cmVS7FlagTable::UserValue },
+ { "ModuleDefinitionFile", "DEF:", "Module Definition File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "ForceSymbolReferences", "INCLUDE:", "Force Symbol References", "",
+ cmVS7FlagTable::UserValue },
+ { "DisplayLibrary", "LIST:", "Display Library to standard output", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [MinimumRequiredVersion] - no command line Switch.
+ { "Name", "NAME:", "Name", "", cmVS7FlagTable::UserValue },
+ // Skip [AdditionalOptions] - no command line Switch.
+ // Skip [TrackerLogDirectory] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS12LinkFlagTable.h b/Source/cmVS12LinkFlagTable.h
new file mode 100644
index 0000000..168c34c
--- /dev/null
+++ b/Source/cmVS12LinkFlagTable.h
@@ -0,0 +1,269 @@
+static cmVS7FlagTable cmVS12LinkFlagTable[] = {
+
+ // Enum Properties
+ { "ShowProgress", "", "Not Set", "NotSet", 0 },
+ { "ShowProgress", "VERBOSE", "Display all progress messages", "LinkVerbose",
+ 0 },
+ { "ShowProgress", "VERBOSE:Lib", "For Libraries Searched", "LinkVerboseLib",
+ 0 },
+ { "ShowProgress", "VERBOSE:ICF",
+ "About COMDAT folding during optimized linking", "LinkVerboseICF", 0 },
+ { "ShowProgress", "VERBOSE:REF",
+ "About data removed during optimized linking", "LinkVerboseREF", 0 },
+ { "ShowProgress", "VERBOSE:SAFESEH", "About Modules incompatible with SEH",
+ "LinkVerboseSAFESEH", 0 },
+ { "ShowProgress", "VERBOSE:CLR",
+ "About linker activity related to managed code", "LinkVerboseCLR", 0 },
+
+ { "ForceFileOutput", "FORCE", "Enabled", "Enabled", 0 },
+ { "ForceFileOutput", "FORCE:MULTIPLE", "Multiply Defined Symbol Only",
+ "MultiplyDefinedSymbolOnly", 0 },
+ { "ForceFileOutput", "FORCE:UNRESOLVED", "Undefined Symbol Only",
+ "UndefinedSymbolOnly", 0 },
+
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN", "Enabled", "Enabled", 0 },
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN:5", "X86 Image Only",
+ "X86Image", 0 },
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN:6", "X64 Image Only",
+ "X64Image", 0 },
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN:16", "Itanium Image Only",
+ "ItaniumImage", 0 },
+
+ { "UACExecutionLevel", "level='asInvoker'", "asInvoker", "AsInvoker", 0 },
+ { "UACExecutionLevel", "level='highestAvailable'", "highestAvailable",
+ "HighestAvailable", 0 },
+ { "UACExecutionLevel", "level='requireAdministrator'",
+ "requireAdministrator", "RequireAdministrator", 0 },
+
+ { "SubSystem", "", "Not Set", "NotSet", 0 },
+ { "SubSystem", "SUBSYSTEM:CONSOLE", "Console", "Console", 0 },
+ { "SubSystem", "SUBSYSTEM:WINDOWS", "Windows", "Windows", 0 },
+ { "SubSystem", "SUBSYSTEM:NATIVE", "Native", "Native", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_APPLICATION", "EFI Application",
+ "EFI Application", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "EFI Boot Service Driver", "EFI Boot Service Driver", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_ROM", "EFI ROM", "EFI ROM", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_RUNTIME_DRIVER", "EFI Runtime", "EFI Runtime",
+ 0 },
+ { "SubSystem", "SUBSYSTEM:POSIX", "POSIX", "POSIX", 0 },
+
+ { "Driver", "", "Not Set", "NotSet", 0 },
+ { "Driver", "Driver", "Driver", "Driver", 0 },
+ { "Driver", "DRIVER:UPONLY", "UP Only", "UpOnly", 0 },
+ { "Driver", "DRIVER:WDM", "WDM", "WDM", 0 },
+
+ { "LinkTimeCodeGeneration", "", "Default", "Default", 0 },
+ { "LinkTimeCodeGeneration", "LTCG", "Use Link Time Code Generation",
+ "UseLinkTimeCodeGeneration", 0 },
+ { "LinkTimeCodeGeneration", "LTCG:PGInstrument",
+ "Profile Guided Optimization - Instrument", "PGInstrument", 0 },
+ { "LinkTimeCodeGeneration", "LTCG:PGOptimize",
+ "Profile Guided Optimization - Optimization", "PGOptimization", 0 },
+ { "LinkTimeCodeGeneration", "LTCG:PGUpdate",
+ "Profile Guided Optimization - Update", "PGUpdate", 0 },
+
+ { "GenerateWindowsMetadata", "WINMD", "Yes", "true", 0 },
+ { "GenerateWindowsMetadata", "WINMD:NO", "No", "false", 0 },
+
+ { "WindowsMetadataSignHash", "WINMDSIGNHASH:SHA1", "SHA1", "SHA1", 0 },
+ { "WindowsMetadataSignHash", "WINMDSIGNHASH:SHA256", "SHA256", "SHA256", 0 },
+ { "WindowsMetadataSignHash", "WINMDSIGNHASH:SHA384", "SHA384", "SHA384", 0 },
+ { "WindowsMetadataSignHash", "WINMDSIGNHASH:SHA512", "SHA512", "SHA512", 0 },
+
+ { "TargetMachine", "", "Not Set", "NotSet", 0 },
+ { "TargetMachine", "MACHINE:ARM", "MachineARM", "MachineARM", 0 },
+ { "TargetMachine", "MACHINE:EBC", "MachineEBC", "MachineEBC", 0 },
+ { "TargetMachine", "MACHINE:IA64", "MachineIA64", "MachineIA64", 0 },
+ { "TargetMachine", "MACHINE:MIPS", "MachineMIPS", "MachineMIPS", 0 },
+ { "TargetMachine", "MACHINE:MIPS16", "MachineMIPS16", "MachineMIPS16", 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU", "MachineMIPSFPU", "MachineMIPSFPU",
+ 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU16", "MachineMIPSFPU16",
+ "MachineMIPSFPU16", 0 },
+ { "TargetMachine", "MACHINE:SH4", "MachineSH4", "MachineSH4", 0 },
+ { "TargetMachine", "MACHINE:THUMB", "MachineTHUMB", "MachineTHUMB", 0 },
+ { "TargetMachine", "MACHINE:X64", "MachineX64", "MachineX64", 0 },
+ { "TargetMachine", "MACHINE:X86", "MachineX86", "MachineX86", 0 },
+
+ { "CLRThreadAttribute", "CLRTHREADATTRIBUTE:MTA", "MTA threading attribute",
+ "MTAThreadingAttribute", 0 },
+ { "CLRThreadAttribute", "CLRTHREADATTRIBUTE:STA", "STA threading attribute",
+ "STAThreadingAttribute", 0 },
+ { "CLRThreadAttribute", "CLRTHREADATTRIBUTE:NONE",
+ "Default threading attribute", "DefaultThreadingAttribute", 0 },
+
+ { "CLRImageType", "CLRIMAGETYPE:IJW", "Force IJW image", "ForceIJWImage",
+ 0 },
+ { "CLRImageType", "CLRIMAGETYPE:PURE", "Force Pure IL Image",
+ "ForcePureILImage", 0 },
+ { "CLRImageType", "CLRIMAGETYPE:SAFE", "Force Safe IL Image",
+ "ForceSafeILImage", 0 },
+ { "CLRImageType", "", "Default image type", "Default", 0 },
+
+ { "SignHash", "CLRSIGNHASH:SHA1", "SHA1", "SHA1", 0 },
+ { "SignHash", "CLRSIGNHASH:SHA256", "SHA256", "SHA256", 0 },
+ { "SignHash", "CLRSIGNHASH:SHA384", "SHA384", "SHA384", 0 },
+ { "SignHash", "CLRSIGNHASH:SHA512", "SHA512", "SHA512", 0 },
+
+ { "LinkErrorReporting", "ERRORREPORT:PROMPT", "PromptImmediately",
+ "PromptImmediately", 0 },
+ { "LinkErrorReporting", "ERRORREPORT:QUEUE", "Queue For Next Login",
+ "QueueForNextLogin", 0 },
+ { "LinkErrorReporting", "ERRORREPORT:SEND", "Send Error Report",
+ "SendErrorReport", 0 },
+ { "LinkErrorReporting", "ERRORREPORT:NONE", "No Error Report",
+ "NoErrorReport", 0 },
+
+ { "CLRSupportLastError", "CLRSupportLastError", "Enabled", "Enabled", 0 },
+ { "CLRSupportLastError", "CLRSupportLastError:NO", "Disabled", "Disabled",
+ 0 },
+ { "CLRSupportLastError", "CLRSupportLastError:SYSTEMDLL", "System Dlls Only",
+ "SystemDlls", 0 },
+
+ // Bool Properties
+ { "LinkIncremental", "INCREMENTAL:NO", "", "false", 0 },
+ { "LinkIncremental", "INCREMENTAL", "", "true", 0 },
+ { "SuppressStartupBanner", "NOLOGO", "", "true", 0 },
+ { "LinkStatus", "LTCG:NOSTATUS", "", "false", 0 },
+ { "LinkStatus", "LTCG:STATUS", "", "true", 0 },
+ { "PreventDllBinding", "ALLOWBIND:NO", "", "false", 0 },
+ { "PreventDllBinding", "ALLOWBIND", "", "true", 0 },
+ { "TreatLinkerWarningAsErrors", "WX:NO", "", "false", 0 },
+ { "TreatLinkerWarningAsErrors", "WX", "", "true", 0 },
+ { "IgnoreAllDefaultLibraries", "NODEFAULTLIB", "", "true", 0 },
+ { "GenerateManifest", "MANIFEST:NO", "", "false", 0 },
+ { "GenerateManifest", "MANIFEST", "", "true", 0 },
+ { "AllowIsolation", "ALLOWISOLATION:NO", "", "false", 0 },
+ { "UACUIAccess", "uiAccess='false'", "", "false", 0 },
+ { "UACUIAccess", "uiAccess='true'", "", "true", 0 },
+ { "ManifestEmbed", "manifest:embed", "", "true", 0 },
+ { "GenerateDebugInformation", "DEBUG", "", "true",
+ cmVS7FlagTable::CaseInsensitive },
+ { "MapExports", "MAPINFO:EXPORTS", "", "true", 0 },
+ { "AssemblyDebug", "ASSEMBLYDEBUG:DISABLE", "", "false", 0 },
+ { "AssemblyDebug", "ASSEMBLYDEBUG", "", "true", 0 },
+ { "LargeAddressAware", "LARGEADDRESSAWARE:NO", "", "false", 0 },
+ { "LargeAddressAware", "LARGEADDRESSAWARE", "", "true", 0 },
+ { "TerminalServerAware", "TSAWARE:NO", "", "false", 0 },
+ { "TerminalServerAware", "TSAWARE", "", "true", 0 },
+ { "SwapRunFromCD", "SWAPRUN:CD", "", "true", 0 },
+ { "SwapRunFromNET", "SWAPRUN:NET", "", "true", 0 },
+ { "OptimizeReferences", "OPT:NOREF", "", "false", 0 },
+ { "OptimizeReferences", "OPT:REF", "", "true", 0 },
+ { "EnableCOMDATFolding", "OPT:NOICF", "", "false", 0 },
+ { "EnableCOMDATFolding", "OPT:ICF", "", "true", 0 },
+ { "IgnoreEmbeddedIDL", "IGNOREIDL", "", "true", 0 },
+ { "AppContainer", "APPCONTAINER", "", "true", 0 },
+ { "WindowsMetadataLinkDelaySign", "WINMDDELAYSIGN:NO", "", "false", 0 },
+ { "WindowsMetadataLinkDelaySign", "WINMDDELAYSIGN", "", "true", 0 },
+ { "NoEntryPoint", "NOENTRY", "", "true", 0 },
+ { "SetChecksum", "RELEASE", "", "true", 0 },
+ { "RandomizedBaseAddress", "DYNAMICBASE:NO", "", "false", 0 },
+ { "RandomizedBaseAddress", "DYNAMICBASE", "", "true", 0 },
+ { "FixedBaseAddress", "FIXED:NO", "", "false", 0 },
+ { "FixedBaseAddress", "FIXED", "", "true", 0 },
+ { "DataExecutionPrevention", "NXCOMPAT:NO", "", "false", 0 },
+ { "DataExecutionPrevention", "NXCOMPAT", "", "true", 0 },
+ { "TurnOffAssemblyGeneration", "NOASSEMBLY", "", "true", 0 },
+ { "SupportUnloadOfDelayLoadedDLL", "DELAY:UNLOAD", "", "true", 0 },
+ { "SupportNobindOfDelayLoadedDLL", "DELAY:NOBIND", "", "true", 0 },
+ { "Profile", "PROFILE", "", "true", 0 },
+ { "LinkDelaySign", "DELAYSIGN:NO", "", "false", 0 },
+ { "LinkDelaySign", "DELAYSIGN", "", "true", 0 },
+ { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK:NO", "", "false", 0 },
+ { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK", "", "true", 0 },
+ { "DetectOneDefinitionRule", "ODR", "", "true", 0 },
+ { "ImageHasSafeExceptionHandlers", "SAFESEH:NO", "", "false", 0 },
+ { "ImageHasSafeExceptionHandlers", "SAFESEH", "", "true", 0 },
+ { "LinkDLL", "DLL", "", "true", 0 },
+
+ // Bool Properties With Argument
+ { "EnableUAC", "MANIFESTUAC:NO", "", "false", 0 },
+ { "EnableUAC", "MANIFESTUAC:", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "UACUIAccess", "MANIFESTUAC:", "Enable User Account Control (UAC)", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "GenerateMapFile", "MAP", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "MapFileName", "MAP:", "Generate Map File", "",
+ cmVS7FlagTable::UserValueRequired },
+
+ // String List Properties
+ { "AdditionalLibraryDirectories", "LIBPATH:",
+ "Additional Library Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ // Skip [AdditionalDependencies] - no command line Switch.
+ { "IgnoreSpecificDefaultLibraries", "NODEFAULTLIB:",
+ "Ignore Specific Default Libraries", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AddModuleNamesToAssembly", "ASSEMBLYMODULE:", "Add Module to Assembly",
+ "", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "EmbedManagedResourceFile", "ASSEMBLYRESOURCE:",
+ "Embed Managed Resource File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ForceSymbolReferences", "INCLUDE:", "Force Symbol References", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "DelayLoadDLLs", "DELAYLOAD:", "Delay Loaded Dlls", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AssemblyLinkResource", "ASSEMBLYLINKRESOURCE:", "Assembly Link Resource",
+ "", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AdditionalManifestDependencies", "MANIFESTDEPENDENCY:",
+ "Additional Manifest Dependencies", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ManifestInput", "manifestinput:", "Manifest Input", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // String Properties
+ { "OutputFile", "OUT:", "Output File", "", cmVS7FlagTable::UserValue },
+ { "Version", "VERSION:", "Version", "", cmVS7FlagTable::UserValue },
+ { "SpecifySectionAttributes", "SECTION:", "Specify Section Attributes", "",
+ cmVS7FlagTable::UserValue },
+ { "MSDOSStubFileName", "STUB:", "MS-DOS Stub File Name", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [TrackerLogDirectory] - no command line Switch.
+ { "ModuleDefinitionFile", "DEF:", "Module Definition File", "",
+ cmVS7FlagTable::UserValue },
+ { "ManifestFile", "ManifestFile:", "Manifest File", "",
+ cmVS7FlagTable::UserValue },
+ { "ProgramDatabaseFile", "PDB:", "Generate Program Database File", "",
+ cmVS7FlagTable::UserValue },
+ { "StripPrivateSymbols", "PDBSTRIPPED:", "Strip Private Symbols", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [MapFileName] - no command line Switch.
+ // Skip [MinimumRequiredVersion] - no command line Switch.
+ { "HeapReserveSize", "HEAP:", "Heap Reserve Size", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [HeapCommitSize] - no command line Switch.
+ { "StackReserveSize", "STACK:", "Stack Reserve Size", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [StackCommitSize] - no command line Switch.
+ { "FunctionOrder", "ORDER:@", "Function Order", "",
+ cmVS7FlagTable::UserValue },
+ { "ProfileGuidedDatabase", "PGD:", "Profile Guided Database", "",
+ cmVS7FlagTable::UserValue },
+ { "MidlCommandFile", "MIDL:@", "MIDL Commands", "",
+ cmVS7FlagTable::UserValue },
+ { "MergedIDLBaseFileName", "IDLOUT:", "Merged IDL Base File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "TypeLibraryFile", "TLBOUT:", "Type Library", "",
+ cmVS7FlagTable::UserValue },
+ { "WindowsMetadataFile", "WINMDFILE:", "Windows Metadata File", "",
+ cmVS7FlagTable::UserValue },
+ { "WindowsMetadataLinkKeyFile", "WINMDKEYFILE:", "Windows Metadata Key File",
+ "", cmVS7FlagTable::UserValue },
+ { "WindowsMetadataKeyContainer", "WINMDKEYCONTAINER:",
+ "Windows Metadata Key Container", "", cmVS7FlagTable::UserValue },
+ { "EntryPointSymbol", "ENTRY:", "Entry Point", "",
+ cmVS7FlagTable::UserValue },
+ { "BaseAddress", "BASE:", "Base Address", "", cmVS7FlagTable::UserValue },
+ { "ImportLibrary", "IMPLIB:", "Import Library", "",
+ cmVS7FlagTable::UserValue },
+ { "MergeSections", "MERGE:", "Merge Sections", "",
+ cmVS7FlagTable::UserValue },
+ { "LinkKeyFile", "KEYFILE:", "Key File", "", cmVS7FlagTable::UserValue },
+ { "KeyContainer", "KEYCONTAINER:", "Key Container", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [AdditionalOptions] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS12MASMFlagTable.h b/Source/cmVS12MASMFlagTable.h
new file mode 100644
index 0000000..a7e4a80
--- /dev/null
+++ b/Source/cmVS12MASMFlagTable.h
@@ -0,0 +1,78 @@
+static cmVS7FlagTable cmVS12MASMFlagTable[] = {
+
+ // Enum Properties
+ { "PreserveIdentifierCase", "", "Default", "0", 0 },
+ { "PreserveIdentifierCase", "/Cp", "Preserves Identifier Case (/Cp)", "1",
+ 0 },
+ { "PreserveIdentifierCase", "/Cu",
+ "Maps all identifiers to upper case. (/Cu)", "2", 0 },
+ { "PreserveIdentifierCase", "/Cx",
+ "Preserves case in public and extern symbols. (/Cx)", "3", 0 },
+
+ { "WarningLevel", "/W0", "Warning Level 0 (/W0)", "0", 0 },
+ { "WarningLevel", "/W1", "Warning Level 1 (/W1)", "1", 0 },
+ { "WarningLevel", "/W2", "Warning Level 2 (/W2)", "2", 0 },
+ { "WarningLevel", "/W3", "Warning Level 3 (/W3)", "3", 0 },
+
+ { "PackAlignmentBoundary", "", "Default", "0", 0 },
+ { "PackAlignmentBoundary", "/Zp1", "One Byte Boundary (/Zp1)", "1", 0 },
+ { "PackAlignmentBoundary", "/Zp2", "Two Byte Boundary (/Zp2)", "2", 0 },
+ { "PackAlignmentBoundary", "/Zp4", "Four Byte Boundary (/Zp4)", "3", 0 },
+ { "PackAlignmentBoundary", "/Zp8", "Eight Byte Boundary (/Zp8)", "4", 0 },
+ { "PackAlignmentBoundary", "/Zp16", "Sixteen Byte Boundary (/Zp16)", "5",
+ 0 },
+
+ { "CallingConvention", "", "Default", "0", 0 },
+ { "CallingConvention", "/Gd", "Use C-style Calling Convention (/Gd)", "1",
+ 0 },
+ { "CallingConvention", "/Gz", "Use stdcall Calling Convention (/Gz)", "2",
+ 0 },
+ { "CallingConvention", "/Gc", "Use Pascal Calling Convention (/Gc)", "3",
+ 0 },
+
+ { "ErrorReporting", "/errorReport:prompt",
+ "Prompt to send report immediately (/errorReport:prompt)", "0", 0 },
+ { "ErrorReporting", "/errorReport:queue",
+ "Prompt to send report at the next logon (/errorReport:queue)", "1", 0 },
+ { "ErrorReporting", "/errorReport:send",
+ "Automatically send report (/errorReport:send)", "2", 0 },
+ { "ErrorReporting", "/errorReport:none",
+ "Do not send report (/errorReport:none)", "3", 0 },
+
+ // Bool Properties
+ { "NoLogo", "/nologo", "", "true", 0 },
+ { "GeneratePreprocessedSourceListing", "/EP", "", "true", 0 },
+ { "ListAllAvailableInformation", "/Sa", "", "true", 0 },
+ { "UseSafeExceptionHandlers", "/safeseh", "", "true", 0 },
+ { "AddFirstPassListing", "/Sf", "", "true", 0 },
+ { "EnableAssemblyGeneratedCodeListing", "/Sg", "", "true", 0 },
+ { "DisableSymbolTable", "/Sn", "", "true", 0 },
+ { "EnableFalseConditionalsInListing", "/Sx", "", "true", 0 },
+ { "TreatWarningsAsErrors", "/WX", "", "true", 0 },
+ { "MakeAllSymbolsPublic", "/Zf", "", "true", 0 },
+ { "GenerateDebugInformation", "/Zi", "", "true", 0 },
+ { "EnableMASM51Compatibility", "/Zm", "", "true", 0 },
+ { "PerformSyntaxCheckOnly", "/Zs", "", "true", 0 },
+
+ // Bool Properties With Argument
+
+ // String List Properties
+ { "PreprocessorDefinitions", "/D", "Preprocessor Definitions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "IncludePaths", "/I", "Include Paths", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "BrowseFile", "/FR", "Generate Browse Information File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ // Skip [AdditionalDependencies] - no command line Switch.
+
+ // String Properties
+ // Skip [Inputs] - no command line Switch.
+ { "ObjectFileName", "/Fo", "Object File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "AssembledCodeListingFile", "/Fl", "Assembled Code Listing File", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [CommandLineTemplate] - no command line Switch.
+ // Skip [ExecutionDescription] - no command line Switch.
+ // Skip [AdditionalOptions] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS12RCFlagTable.h b/Source/cmVS12RCFlagTable.h
new file mode 100644
index 0000000..d047f824
--- /dev/null
+++ b/Source/cmVS12RCFlagTable.h
@@ -0,0 +1,6 @@
+static cmVS7FlagTable cmVS12RCFlagTable[] = {
+ // Bool Properties
+ { "NullTerminateStrings", "n", "", "true", 0 },
+
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS14CLFlagTable.h b/Source/cmVS14CLFlagTable.h
new file mode 100644
index 0000000..5812e79
--- /dev/null
+++ b/Source/cmVS14CLFlagTable.h
@@ -0,0 +1,237 @@
+static cmVS7FlagTable cmVS14CLFlagTable[] = {
+
+ // Enum Properties
+ { "DebugInformationFormat", "", "None", "None", 0 },
+ { "DebugInformationFormat", "Z7", "C7 compatible", "OldStyle", 0 },
+ { "DebugInformationFormat", "Zi", "Program Database", "ProgramDatabase", 0 },
+ { "DebugInformationFormat", "ZI", "Program Database for Edit And Continue",
+ "EditAndContinue", 0 },
+
+ { "WarningLevel", "W0", "Turn Off All Warnings", "TurnOffAllWarnings", 0 },
+ { "WarningLevel", "W1", "Level1", "Level1", 0 },
+ { "WarningLevel", "W2", "Level2", "Level2", 0 },
+ { "WarningLevel", "W3", "Level3", "Level3", 0 },
+ { "WarningLevel", "W4", "Level4", "Level4", 0 },
+ { "WarningLevel", "Wall", "EnableAllWarnings", "EnableAllWarnings", 0 },
+
+ { "Optimization", "", "Custom", "Custom", 0 },
+ { "Optimization", "Od", "Disabled", "Disabled", 0 },
+ { "Optimization", "O1", "Minimize Size", "MinSpace", 0 },
+ { "Optimization", "O2", "Maximize Speed", "MaxSpeed", 0 },
+ { "Optimization", "Ox", "Full Optimization", "Full", 0 },
+
+ { "InlineFunctionExpansion", "", "Default", "Default", 0 },
+ { "InlineFunctionExpansion", "Ob0", "Disabled", "Disabled", 0 },
+ { "InlineFunctionExpansion", "Ob1", "Only __inline", "OnlyExplicitInline",
+ 0 },
+ { "InlineFunctionExpansion", "Ob2", "Any Suitable", "AnySuitable", 0 },
+
+ { "FavorSizeOrSpeed", "Os", "Favor small code", "Size", 0 },
+ { "FavorSizeOrSpeed", "Ot", "Favor fast code", "Speed", 0 },
+ { "FavorSizeOrSpeed", "", "Neither", "Neither", 0 },
+
+ { "ExceptionHandling", "EHa", "Yes with SEH Exceptions", "Async", 0 },
+ { "ExceptionHandling", "EHsc", "Yes", "Sync", 0 },
+ { "ExceptionHandling", "EHs", "Yes with Extern C functions", "SyncCThrow",
+ 0 },
+ { "ExceptionHandling", "", "No", "false", 0 },
+
+ { "BasicRuntimeChecks", "RTCs", "Stack Frames", "StackFrameRuntimeCheck",
+ 0 },
+ { "BasicRuntimeChecks", "RTCu", "Uninitialized variables",
+ "UninitializedLocalUsageCheck", 0 },
+ { "BasicRuntimeChecks", "RTC1", "Both (/RTC1, equiv. to /RTCsu)",
+ "EnableFastChecks", 0 },
+ { "BasicRuntimeChecks", "", "Default", "Default", 0 },
+
+ { "RuntimeLibrary", "MT", "Multi-threaded", "MultiThreaded", 0 },
+ { "RuntimeLibrary", "MTd", "Multi-threaded Debug", "MultiThreadedDebug", 0 },
+ { "RuntimeLibrary", "MD", "Multi-threaded DLL", "MultiThreadedDLL", 0 },
+ { "RuntimeLibrary", "MDd", "Multi-threaded Debug DLL",
+ "MultiThreadedDebugDLL", 0 },
+
+ { "StructMemberAlignment", "Zp1", "1 Byte", "1Byte", 0 },
+ { "StructMemberAlignment", "Zp2", "2 Bytes", "2Bytes", 0 },
+ { "StructMemberAlignment", "Zp4", "4 Byte", "4Bytes", 0 },
+ { "StructMemberAlignment", "Zp8", "8 Bytes", "8Bytes", 0 },
+ { "StructMemberAlignment", "Zp16", "16 Bytes", "16Bytes", 0 },
+ { "StructMemberAlignment", "", "Default", "Default", 0 },
+
+ { "BufferSecurityCheck", "GS-", "Disable Security Check", "false", 0 },
+ { "BufferSecurityCheck", "GS", "Enable Security Check", "true", 0 },
+
+ { "EnableEnhancedInstructionSet", "arch:SSE", "Streaming SIMD Extensions",
+ "StreamingSIMDExtensions", 0 },
+ { "EnableEnhancedInstructionSet", "arch:SSE2", "Streaming SIMD Extensions 2",
+ "StreamingSIMDExtensions2", 0 },
+ { "EnableEnhancedInstructionSet", "arch:AVX", "Advanced Vector Extensions",
+ "AdvancedVectorExtensions", 0 },
+ { "EnableEnhancedInstructionSet", "arch:AVX2",
+ "Advanced Vector Extensions 2", "AdvancedVectorExtensions2", 0 },
+ { "EnableEnhancedInstructionSet", "arch:IA32", "No Enhanced Instructions",
+ "NoExtensions", 0 },
+ { "EnableEnhancedInstructionSet", "", "Not Set", "NotSet", 0 },
+
+ { "FloatingPointModel", "fp:precise", "Precise", "Precise", 0 },
+ { "FloatingPointModel", "fp:strict", "Strict", "Strict", 0 },
+ { "FloatingPointModel", "fp:fast", "Fast", "Fast", 0 },
+
+ { "PrecompiledHeader", "Yc", "Create", "Create",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeader", "Yu", "Use", "Use",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeader", "", "Not Using Precompiled Headers", "NotUsing", 0 },
+
+ { "AssemblerOutput", "", "No Listing", "NoListing", 0 },
+ { "AssemblerOutput", "FA", "Assembly-Only Listing", "AssemblyCode", 0 },
+ { "AssemblerOutput", "FAc", "Assembly With Machine Code",
+ "AssemblyAndMachineCode", 0 },
+ { "AssemblerOutput", "FAs", "Assembly With Source Code",
+ "AssemblyAndSourceCode", 0 },
+ { "AssemblerOutput", "FAcs", "Assembly, Machine Code and Source", "All", 0 },
+
+ { "CallingConvention", "Gd", "__cdecl", "Cdecl", 0 },
+ { "CallingConvention", "Gr", "__fastcall", "FastCall", 0 },
+ { "CallingConvention", "Gz", "__stdcall", "StdCall", 0 },
+ { "CallingConvention", "Gv", "__vectorcall", "VectorCall", 0 },
+
+ { "CompileAs", "", "Default", "Default", 0 },
+ { "CompileAs", "TC", "Compile as C Code", "CompileAsC", 0 },
+ { "CompileAs", "TP", "Compile as C++ Code", "CompileAsCpp", 0 },
+
+ { "ErrorReporting", "errorReport:none", "Do Not Send Report", "None", 0 },
+ { "ErrorReporting", "errorReport:prompt", "Prompt Immediately", "Prompt",
+ 0 },
+ { "ErrorReporting", "errorReport:queue", "Queue For Next Login", "Queue",
+ 0 },
+ { "ErrorReporting", "errorReport:send", "Send Automatically", "Send", 0 },
+
+ { "CompileAsManaged", "", "No Common Language RunTime Support", "false", 0 },
+ { "CompileAsManaged", "clr", "Common Language RunTime Support", "true", 0 },
+ { "CompileAsManaged", "clr:pure",
+ "Pure MSIL Common Language RunTime Support", "Pure", 0 },
+ { "CompileAsManaged", "clr:safe",
+ "Safe MSIL Common Language RunTime Support", "Safe", 0 },
+ { "CompileAsManaged", "clr:oldSyntax",
+ "Common Language RunTime Support, Old Syntax", "OldSyntax", 0 },
+
+ { "CppLanguageStandard", "", "Default", "Default", 0 },
+ { "CppLanguageStandard", "std=c++98", "C++03", "c++98", 0 },
+ { "CppLanguageStandard", "std=c++11", "C++11", "c++11", 0 },
+ { "CppLanguageStandard", "std=c++1y", "C++14", "c++1y", 0 },
+ { "CppLanguageStandard", "std=c++14", "C++14", "c++1y", 0 },
+ { "CppLanguageStandard", "std=gnu++98", "C++03 (GNU Dialect)", "gnu++98",
+ 0 },
+ { "CppLanguageStandard", "std=gnu++11", "C++11 (GNU Dialect)", "gnu++11",
+ 0 },
+ { "CppLanguageStandard", "std=gnu++1y", "C++14 (GNU Dialect)", "gnu++1y",
+ 0 },
+ { "CppLanguageStandard", "std=gnu++14", "C++14 (GNU Dialect)", "gnu++1y",
+ 0 },
+
+ // Bool Properties
+ { "CompileAsWinRT", "ZW", "", "true", 0 },
+ { "WinRTNoStdLib", "ZW:nostdlib", "", "true", 0 },
+ { "SuppressStartupBanner", "nologo", "", "true", 0 },
+ { "TreatWarningAsError", "WX-", "", "false", 0 },
+ { "TreatWarningAsError", "WX", "", "true", 0 },
+ { "SDLCheck", "sdl-", "", "false", 0 },
+ { "SDLCheck", "sdl", "", "true", 0 },
+ { "IntrinsicFunctions", "Oi", "", "true", 0 },
+ { "OmitFramePointers", "Oy-", "", "false", 0 },
+ { "OmitFramePointers", "Oy", "", "true", 0 },
+ { "EnableFiberSafeOptimizations", "GT", "", "true", 0 },
+ { "WholeProgramOptimization", "GL", "", "true", 0 },
+ { "UndefineAllPreprocessorDefinitions", "u", "", "true", 0 },
+ { "IgnoreStandardIncludePath", "X", "", "true", 0 },
+ { "PreprocessToFile", "P", "", "true", 0 },
+ { "PreprocessSuppressLineNumbers", "EP", "", "true", 0 },
+ { "PreprocessKeepComments", "C", "", "true", 0 },
+ { "StringPooling", "GF-", "", "false", 0 },
+ { "StringPooling", "GF", "", "true", 0 },
+ { "MinimalRebuild", "Gm-", "", "false", 0 },
+ { "MinimalRebuild", "Gm", "", "true", 0 },
+ { "SmallerTypeCheck", "RTCc", "", "true", 0 },
+ { "FunctionLevelLinking", "Gy-", "", "false", 0 },
+ { "FunctionLevelLinking", "Gy", "", "true", 0 },
+ { "EnableParallelCodeGeneration", "Qpar-", "", "false", 0 },
+ { "EnableParallelCodeGeneration", "Qpar", "", "true", 0 },
+ { "FloatingPointExceptions", "fp:except-", "", "false", 0 },
+ { "FloatingPointExceptions", "fp:except", "", "true", 0 },
+ { "CreateHotpatchableImage", "hotpatch", "", "true", 0 },
+ { "DisableLanguageExtensions", "Za", "", "true", 0 },
+ { "TreatWChar_tAsBuiltInType", "Zc:wchar_t-", "", "false", 0 },
+ { "TreatWChar_tAsBuiltInType", "Zc:wchar_t", "", "true", 0 },
+ { "ForceConformanceInForLoopScope", "Zc:forScope-", "", "false", 0 },
+ { "ForceConformanceInForLoopScope", "Zc:forScope", "", "true", 0 },
+ { "RuntimeTypeInfo", "GR-", "", "false", 0 },
+ { "RuntimeTypeInfo", "GR", "", "true", 0 },
+ { "OpenMPSupport", "openmp-", "", "false", 0 },
+ { "OpenMPSupport", "openmp", "", "true", 0 },
+ { "ExpandAttributedSource", "Fx", "", "true", 0 },
+ { "UseUnicodeForAssemblerListing", "FAu", "", "true", 0 },
+ { "ShowIncludes", "showIncludes", "", "true", 0 },
+ { "EnablePREfast", "analyze-", "", "false", 0 },
+ { "EnablePREfast", "analyze", "", "true", 0 },
+ { "UseFullPaths", "FC", "", "true", 0 },
+ { "OmitDefaultLibName", "Zl", "", "true", 0 },
+
+ // Bool Properties With Argument
+ { "MultiProcessorCompilation", "MP", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "ProcessorNumber", "MP", "Multi-processor Compilation", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "GenerateXMLDocumentationFiles", "doc", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "XMLDocumentationFileName", "doc", "Generate XML Documentation Files", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "BrowseInformation", "FR", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "BrowseInformationFile", "FR", "Enable Browse Information", "",
+ cmVS7FlagTable::UserValueRequired },
+
+ // String List Properties
+ { "AdditionalIncludeDirectories", "I", "Additional Include Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AdditionalUsingDirectories", "AI", "Additional #using Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "PreprocessorDefinitions", "D ", "Preprocessor Definitions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "UndefinePreprocessorDefinitions", "U",
+ "Undefine Preprocessor Definitions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "DisableSpecificWarnings", "wd", "Disable Specific Warnings", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ForcedIncludeFiles", "FI", "Forced Include File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ForcedUsingFiles", "FU", "Forced #using File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "PREfastLog", "analyze:log", "Code Analysis Log", "",
+ cmVS7FlagTable::UserFollowing },
+ { "PREfastAdditionalPlugins", "analyze:plugin",
+ "Additional Code Analysis Native plugins", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "TreatSpecificWarningsAsErrors", "we", "Treat Specific Warnings As Errors",
+ "", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // String Properties
+ // Skip [TrackerLogDirectory] - no command line Switch.
+ { "PreprocessOutputPath", "Fi", "Preprocess Output Path", "",
+ cmVS7FlagTable::UserValue },
+ { "PrecompiledHeaderFile", "Yc", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "PrecompiledHeaderFile", "Yu", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "PrecompiledHeaderOutputFile", "Fp", "Precompiled Header Output File", "",
+ cmVS7FlagTable::UserValue },
+ { "AssemblerListingLocation", "Fa", "ASM List Location", "",
+ cmVS7FlagTable::UserValue },
+ { "ObjectFileName", "Fo", "Object File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "ProgramDataBaseFileName", "Fd", "Program Database File Name", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [XMLDocumentationFileName] - no command line Switch.
+ // Skip [BrowseInformationFile] - no command line Switch.
+ // Skip [AdditionalOptions] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS14LibFlagTable.h b/Source/cmVS14LibFlagTable.h
new file mode 100644
index 0000000..7fa7138
--- /dev/null
+++ b/Source/cmVS14LibFlagTable.h
@@ -0,0 +1,76 @@
+static cmVS7FlagTable cmVS14LibFlagTable[] = {
+
+ // Enum Properties
+ { "ErrorReporting", "ERRORREPORT:PROMPT", "PromptImmediately",
+ "PromptImmediately", 0 },
+ { "ErrorReporting", "ERRORREPORT:QUEUE", "Queue For Next Login",
+ "QueueForNextLogin", 0 },
+ { "ErrorReporting", "ERRORREPORT:SEND", "Send Error Report",
+ "SendErrorReport", 0 },
+ { "ErrorReporting", "ERRORREPORT:NONE", "No Error Report", "NoErrorReport",
+ 0 },
+
+ { "TargetMachine", "MACHINE:ARM", "MachineARM", "MachineARM", 0 },
+ { "TargetMachine", "MACHINE:EBC", "MachineEBC", "MachineEBC", 0 },
+ { "TargetMachine", "MACHINE:IA64", "MachineIA64", "MachineIA64", 0 },
+ { "TargetMachine", "MACHINE:MIPS", "MachineMIPS", "MachineMIPS", 0 },
+ { "TargetMachine", "MACHINE:MIPS16", "MachineMIPS16", "MachineMIPS16", 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU", "MachineMIPSFPU", "MachineMIPSFPU",
+ 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU16", "MachineMIPSFPU16",
+ "MachineMIPSFPU16", 0 },
+ { "TargetMachine", "MACHINE:SH4", "MachineSH4", "MachineSH4", 0 },
+ { "TargetMachine", "MACHINE:THUMB", "MachineTHUMB", "MachineTHUMB", 0 },
+ { "TargetMachine", "MACHINE:X64", "MachineX64", "MachineX64", 0 },
+ { "TargetMachine", "MACHINE:X86", "MachineX86", "MachineX86", 0 },
+
+ { "SubSystem", "SUBSYSTEM:CONSOLE", "Console", "Console", 0 },
+ { "SubSystem", "SUBSYSTEM:WINDOWS", "Windows", "Windows", 0 },
+ { "SubSystem", "SUBSYSTEM:NATIVE", "Native", "Native", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_APPLICATION", "EFI Application",
+ "EFI Application", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "EFI Boot Service Driver", "EFI Boot Service Driver", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_ROM", "EFI ROM", "EFI ROM", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_RUNTIME_DRIVER", "EFI Runtime", "EFI Runtime",
+ 0 },
+ { "SubSystem", "SUBSYSTEM:WINDOWSCE", "WindowsCE", "WindowsCE", 0 },
+ { "SubSystem", "SUBSYSTEM:POSIX", "POSIX", "POSIX", 0 },
+
+ // Bool Properties
+ { "SuppressStartupBanner", "NOLOGO", "", "true", 0 },
+ { "IgnoreAllDefaultLibraries", "NODEFAULTLIB", "", "true", 0 },
+ { "TreatLibWarningAsErrors", "WX:NO", "", "false", 0 },
+ { "TreatLibWarningAsErrors", "WX", "", "true", 0 },
+ { "Verbose", "VERBOSE", "", "true", 0 },
+ { "LinkTimeCodeGeneration", "LTCG", "", "true", 0 },
+
+ // Bool Properties With Argument
+
+ // String List Properties
+ // Skip [AdditionalDependencies] - no command line Switch.
+ { "AdditionalLibraryDirectories", "LIBPATH:",
+ "Additional Library Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "IgnoreSpecificDefaultLibraries", "NODEFAULTLIB:",
+ "Ignore Specific Default Libraries", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ExportNamedFunctions", "EXPORT:", "Export Named Functions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "RemoveObjects", "REMOVE:", "Remove Objects", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // String Properties
+ { "OutputFile", "OUT:", "Output File", "", cmVS7FlagTable::UserValue },
+ { "ModuleDefinitionFile", "DEF:", "Module Definition File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "ForceSymbolReferences", "INCLUDE:", "Force Symbol References", "",
+ cmVS7FlagTable::UserValue },
+ { "DisplayLibrary", "LIST:", "Display Library to standard output", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [MinimumRequiredVersion] - no command line Switch.
+ { "Name", "NAME:", "Name", "", cmVS7FlagTable::UserValue },
+ // Skip [AdditionalOptions] - no command line Switch.
+ // Skip [TrackerLogDirectory] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS14LinkFlagTable.h b/Source/cmVS14LinkFlagTable.h
new file mode 100644
index 0000000..6e56422
--- /dev/null
+++ b/Source/cmVS14LinkFlagTable.h
@@ -0,0 +1,271 @@
+static cmVS7FlagTable cmVS14LinkFlagTable[] = {
+
+ // Enum Properties
+ { "ShowProgress", "", "Not Set", "NotSet", 0 },
+ { "ShowProgress", "VERBOSE", "Display all progress messages", "LinkVerbose",
+ 0 },
+ { "ShowProgress", "VERBOSE:Lib", "For Libraries Searched", "LinkVerboseLib",
+ 0 },
+ { "ShowProgress", "VERBOSE:ICF",
+ "About COMDAT folding during optimized linking", "LinkVerboseICF", 0 },
+ { "ShowProgress", "VERBOSE:REF",
+ "About data removed during optimized linking", "LinkVerboseREF", 0 },
+ { "ShowProgress", "VERBOSE:SAFESEH", "About Modules incompatible with SEH",
+ "LinkVerboseSAFESEH", 0 },
+ { "ShowProgress", "VERBOSE:CLR",
+ "About linker activity related to managed code", "LinkVerboseCLR", 0 },
+
+ { "ForceFileOutput", "FORCE", "Enabled", "Enabled", 0 },
+ { "ForceFileOutput", "FORCE:MULTIPLE", "Multiply Defined Symbol Only",
+ "MultiplyDefinedSymbolOnly", 0 },
+ { "ForceFileOutput", "FORCE:UNRESOLVED", "Undefined Symbol Only",
+ "UndefinedSymbolOnly", 0 },
+
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN", "Enabled", "Enabled", 0 },
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN:5", "X86 Image Only",
+ "X86Image", 0 },
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN:6", "X64 Image Only",
+ "X64Image", 0 },
+ { "CreateHotPatchableImage", "FUNCTIONPADMIN:16", "Itanium Image Only",
+ "ItaniumImage", 0 },
+
+ { "UACExecutionLevel", "level='asInvoker'", "asInvoker", "AsInvoker", 0 },
+ { "UACExecutionLevel", "level='highestAvailable'", "highestAvailable",
+ "HighestAvailable", 0 },
+ { "UACExecutionLevel", "level='requireAdministrator'",
+ "requireAdministrator", "RequireAdministrator", 0 },
+
+ { "SubSystem", "", "Not Set", "NotSet", 0 },
+ { "SubSystem", "SUBSYSTEM:CONSOLE", "Console", "Console", 0 },
+ { "SubSystem", "SUBSYSTEM:WINDOWS", "Windows", "Windows", 0 },
+ { "SubSystem", "SUBSYSTEM:NATIVE", "Native", "Native", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_APPLICATION", "EFI Application",
+ "EFI Application", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "EFI Boot Service Driver", "EFI Boot Service Driver", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_ROM", "EFI ROM", "EFI ROM", 0 },
+ { "SubSystem", "SUBSYSTEM:EFI_RUNTIME_DRIVER", "EFI Runtime", "EFI Runtime",
+ 0 },
+ { "SubSystem", "SUBSYSTEM:POSIX", "POSIX", "POSIX", 0 },
+
+ { "Driver", "", "Not Set", "NotSet", 0 },
+ { "Driver", "Driver", "Driver", "Driver", 0 },
+ { "Driver", "DRIVER:UPONLY", "UP Only", "UpOnly", 0 },
+ { "Driver", "DRIVER:WDM", "WDM", "WDM", 0 },
+
+ { "LinkTimeCodeGeneration", "", "Default", "Default", 0 },
+ { "LinkTimeCodeGeneration", "LTCG", "Use Link Time Code Generation",
+ "UseLinkTimeCodeGeneration", 0 },
+ { "LinkTimeCodeGeneration", "LTCG:PGInstrument",
+ "Profile Guided Optimization - Instrument", "PGInstrument", 0 },
+ { "LinkTimeCodeGeneration", "LTCG:PGOptimize",
+ "Profile Guided Optimization - Optimization", "PGOptimization", 0 },
+ { "LinkTimeCodeGeneration", "LTCG:PGUpdate",
+ "Profile Guided Optimization - Update", "PGUpdate", 0 },
+
+ { "GenerateWindowsMetadata", "WINMD", "Yes", "true", 0 },
+ { "GenerateWindowsMetadata", "WINMD:NO", "No", "false", 0 },
+
+ { "WindowsMetadataSignHash", "WINMDSIGNHASH:SHA1", "SHA1", "SHA1", 0 },
+ { "WindowsMetadataSignHash", "WINMDSIGNHASH:SHA256", "SHA256", "SHA256", 0 },
+ { "WindowsMetadataSignHash", "WINMDSIGNHASH:SHA384", "SHA384", "SHA384", 0 },
+ { "WindowsMetadataSignHash", "WINMDSIGNHASH:SHA512", "SHA512", "SHA512", 0 },
+
+ { "TargetMachine", "", "Not Set", "NotSet", 0 },
+ { "TargetMachine", "MACHINE:ARM", "MachineARM", "MachineARM", 0 },
+ { "TargetMachine", "MACHINE:EBC", "MachineEBC", "MachineEBC", 0 },
+ { "TargetMachine", "MACHINE:IA64", "MachineIA64", "MachineIA64", 0 },
+ { "TargetMachine", "MACHINE:MIPS", "MachineMIPS", "MachineMIPS", 0 },
+ { "TargetMachine", "MACHINE:MIPS16", "MachineMIPS16", "MachineMIPS16", 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU", "MachineMIPSFPU", "MachineMIPSFPU",
+ 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU16", "MachineMIPSFPU16",
+ "MachineMIPSFPU16", 0 },
+ { "TargetMachine", "MACHINE:SH4", "MachineSH4", "MachineSH4", 0 },
+ { "TargetMachine", "MACHINE:THUMB", "MachineTHUMB", "MachineTHUMB", 0 },
+ { "TargetMachine", "MACHINE:X64", "MachineX64", "MachineX64", 0 },
+ { "TargetMachine", "MACHINE:X86", "MachineX86", "MachineX86", 0 },
+
+ { "CLRThreadAttribute", "CLRTHREADATTRIBUTE:MTA", "MTA threading attribute",
+ "MTAThreadingAttribute", 0 },
+ { "CLRThreadAttribute", "CLRTHREADATTRIBUTE:STA", "STA threading attribute",
+ "STAThreadingAttribute", 0 },
+ { "CLRThreadAttribute", "CLRTHREADATTRIBUTE:NONE",
+ "Default threading attribute", "DefaultThreadingAttribute", 0 },
+
+ { "CLRImageType", "CLRIMAGETYPE:IJW", "Force IJW image", "ForceIJWImage",
+ 0 },
+ { "CLRImageType", "CLRIMAGETYPE:PURE", "Force Pure IL Image",
+ "ForcePureILImage", 0 },
+ { "CLRImageType", "CLRIMAGETYPE:SAFE", "Force Safe IL Image",
+ "ForceSafeILImage", 0 },
+ { "CLRImageType", "", "Default image type", "Default", 0 },
+
+ { "SignHash", "CLRSIGNHASH:SHA1", "SHA1", "SHA1", 0 },
+ { "SignHash", "CLRSIGNHASH:SHA256", "SHA256", "SHA256", 0 },
+ { "SignHash", "CLRSIGNHASH:SHA384", "SHA384", "SHA384", 0 },
+ { "SignHash", "CLRSIGNHASH:SHA512", "SHA512", "SHA512", 0 },
+
+ { "LinkErrorReporting", "ERRORREPORT:PROMPT", "PromptImmediately",
+ "PromptImmediately", 0 },
+ { "LinkErrorReporting", "ERRORREPORT:QUEUE", "Queue For Next Login",
+ "QueueForNextLogin", 0 },
+ { "LinkErrorReporting", "ERRORREPORT:SEND", "Send Error Report",
+ "SendErrorReport", 0 },
+ { "LinkErrorReporting", "ERRORREPORT:NONE", "No Error Report",
+ "NoErrorReport", 0 },
+
+ { "CLRSupportLastError", "CLRSupportLastError", "Enabled", "Enabled", 0 },
+ { "CLRSupportLastError", "CLRSupportLastError:NO", "Disabled", "Disabled",
+ 0 },
+ { "CLRSupportLastError", "CLRSupportLastError:SYSTEMDLL", "System Dlls Only",
+ "SystemDlls", 0 },
+
+ // Bool Properties
+ { "LinkIncremental", "INCREMENTAL:NO", "", "false", 0 },
+ { "LinkIncremental", "INCREMENTAL", "", "true", 0 },
+ { "SuppressStartupBanner", "NOLOGO", "", "true", 0 },
+ { "LinkStatus", "LTCG:NOSTATUS", "", "false", 0 },
+ { "LinkStatus", "LTCG:STATUS", "", "true", 0 },
+ { "PreventDllBinding", "ALLOWBIND:NO", "", "false", 0 },
+ { "PreventDllBinding", "ALLOWBIND", "", "true", 0 },
+ { "TreatLinkerWarningAsErrors", "WX:NO", "", "false", 0 },
+ { "TreatLinkerWarningAsErrors", "WX", "", "true", 0 },
+ { "IgnoreAllDefaultLibraries", "NODEFAULTLIB", "", "true", 0 },
+ { "GenerateManifest", "MANIFEST:NO", "", "false", 0 },
+ { "GenerateManifest", "MANIFEST", "", "true", 0 },
+ { "AllowIsolation", "ALLOWISOLATION:NO", "", "false", 0 },
+ { "UACUIAccess", "uiAccess='false'", "", "false", 0 },
+ { "UACUIAccess", "uiAccess='true'", "", "true", 0 },
+ { "ManifestEmbed", "manifest:embed", "", "true", 0 },
+ { "GenerateDebugInformation", "DEBUG:FASTLINK", "", "DebugFastLink",
+ cmVS7FlagTable::CaseInsensitive },
+ { "GenerateDebugInformation", "DEBUG", "", "Debug",
+ cmVS7FlagTable::CaseInsensitive },
+ { "MapExports", "MAPINFO:EXPORTS", "", "true", 0 },
+ { "AssemblyDebug", "ASSEMBLYDEBUG:DISABLE", "", "false", 0 },
+ { "AssemblyDebug", "ASSEMBLYDEBUG", "", "true", 0 },
+ { "LargeAddressAware", "LARGEADDRESSAWARE:NO", "", "false", 0 },
+ { "LargeAddressAware", "LARGEADDRESSAWARE", "", "true", 0 },
+ { "TerminalServerAware", "TSAWARE:NO", "", "false", 0 },
+ { "TerminalServerAware", "TSAWARE", "", "true", 0 },
+ { "SwapRunFromCD", "SWAPRUN:CD", "", "true", 0 },
+ { "SwapRunFromNET", "SWAPRUN:NET", "", "true", 0 },
+ { "OptimizeReferences", "OPT:NOREF", "", "false", 0 },
+ { "OptimizeReferences", "OPT:REF", "", "true", 0 },
+ { "EnableCOMDATFolding", "OPT:NOICF", "", "false", 0 },
+ { "EnableCOMDATFolding", "OPT:ICF", "", "true", 0 },
+ { "IgnoreEmbeddedIDL", "IGNOREIDL", "", "true", 0 },
+ { "AppContainer", "APPCONTAINER", "", "true", 0 },
+ { "WindowsMetadataLinkDelaySign", "WINMDDELAYSIGN:NO", "", "false", 0 },
+ { "WindowsMetadataLinkDelaySign", "WINMDDELAYSIGN", "", "true", 0 },
+ { "NoEntryPoint", "NOENTRY", "", "true", 0 },
+ { "SetChecksum", "RELEASE", "", "true", 0 },
+ { "RandomizedBaseAddress", "DYNAMICBASE:NO", "", "false", 0 },
+ { "RandomizedBaseAddress", "DYNAMICBASE", "", "true", 0 },
+ { "FixedBaseAddress", "FIXED:NO", "", "false", 0 },
+ { "FixedBaseAddress", "FIXED", "", "true", 0 },
+ { "DataExecutionPrevention", "NXCOMPAT:NO", "", "false", 0 },
+ { "DataExecutionPrevention", "NXCOMPAT", "", "true", 0 },
+ { "TurnOffAssemblyGeneration", "NOASSEMBLY", "", "true", 0 },
+ { "SupportUnloadOfDelayLoadedDLL", "DELAY:UNLOAD", "", "true", 0 },
+ { "SupportNobindOfDelayLoadedDLL", "DELAY:NOBIND", "", "true", 0 },
+ { "Profile", "PROFILE", "", "true", 0 },
+ { "LinkDelaySign", "DELAYSIGN:NO", "", "false", 0 },
+ { "LinkDelaySign", "DELAYSIGN", "", "true", 0 },
+ { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK:NO", "", "false", 0 },
+ { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK", "", "true", 0 },
+ { "DetectOneDefinitionRule", "ODR", "", "true", 0 },
+ { "ImageHasSafeExceptionHandlers", "SAFESEH:NO", "", "false", 0 },
+ { "ImageHasSafeExceptionHandlers", "SAFESEH", "", "true", 0 },
+ { "LinkDLL", "DLL", "", "true", 0 },
+
+ // Bool Properties With Argument
+ { "EnableUAC", "MANIFESTUAC:NO", "", "false", 0 },
+ { "EnableUAC", "MANIFESTUAC:", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "UACUIAccess", "MANIFESTUAC:", "Enable User Account Control (UAC)", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "GenerateMapFile", "MAP", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "MapFileName", "MAP:", "Generate Map File", "",
+ cmVS7FlagTable::UserValueRequired },
+
+ // String List Properties
+ { "AdditionalLibraryDirectories", "LIBPATH:",
+ "Additional Library Directories", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ // Skip [AdditionalDependencies] - no command line Switch.
+ { "IgnoreSpecificDefaultLibraries", "NODEFAULTLIB:",
+ "Ignore Specific Default Libraries", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AddModuleNamesToAssembly", "ASSEMBLYMODULE:", "Add Module to Assembly",
+ "", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "EmbedManagedResourceFile", "ASSEMBLYRESOURCE:",
+ "Embed Managed Resource File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ForceSymbolReferences", "INCLUDE:", "Force Symbol References", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "DelayLoadDLLs", "DELAYLOAD:", "Delay Loaded Dlls", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AssemblyLinkResource", "ASSEMBLYLINKRESOURCE:", "Assembly Link Resource",
+ "", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "AdditionalManifestDependencies", "MANIFESTDEPENDENCY:",
+ "Additional Manifest Dependencies", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "ManifestInput", "manifestinput:", "Manifest Input", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // String Properties
+ { "OutputFile", "OUT:", "Output File", "", cmVS7FlagTable::UserValue },
+ { "Version", "VERSION:", "Version", "", cmVS7FlagTable::UserValue },
+ { "SpecifySectionAttributes", "SECTION:", "Specify Section Attributes", "",
+ cmVS7FlagTable::UserValue },
+ { "MSDOSStubFileName", "STUB:", "MS-DOS Stub File Name", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [TrackerLogDirectory] - no command line Switch.
+ { "ModuleDefinitionFile", "DEF:", "Module Definition File", "",
+ cmVS7FlagTable::UserValue },
+ { "ManifestFile", "ManifestFile:", "Manifest File", "",
+ cmVS7FlagTable::UserValue },
+ { "ProgramDatabaseFile", "PDB:", "Generate Program Database File", "",
+ cmVS7FlagTable::UserValue },
+ { "StripPrivateSymbols", "PDBSTRIPPED:", "Strip Private Symbols", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [MapFileName] - no command line Switch.
+ // Skip [MinimumRequiredVersion] - no command line Switch.
+ { "HeapReserveSize", "HEAP:", "Heap Reserve Size", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [HeapCommitSize] - no command line Switch.
+ { "StackReserveSize", "STACK:", "Stack Reserve Size", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [StackCommitSize] - no command line Switch.
+ { "FunctionOrder", "ORDER:@", "Function Order", "",
+ cmVS7FlagTable::UserValue },
+ { "ProfileGuidedDatabase", "PGD:", "Profile Guided Database", "",
+ cmVS7FlagTable::UserValue },
+ { "MidlCommandFile", "MIDL:@", "MIDL Commands", "",
+ cmVS7FlagTable::UserValue },
+ { "MergedIDLBaseFileName", "IDLOUT:", "Merged IDL Base File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "TypeLibraryFile", "TLBOUT:", "Type Library", "",
+ cmVS7FlagTable::UserValue },
+ { "WindowsMetadataFile", "WINMDFILE:", "Windows Metadata File", "",
+ cmVS7FlagTable::UserValue },
+ { "WindowsMetadataLinkKeyFile", "WINMDKEYFILE:", "Windows Metadata Key File",
+ "", cmVS7FlagTable::UserValue },
+ { "WindowsMetadataKeyContainer", "WINMDKEYCONTAINER:",
+ "Windows Metadata Key Container", "", cmVS7FlagTable::UserValue },
+ { "EntryPointSymbol", "ENTRY:", "Entry Point", "",
+ cmVS7FlagTable::UserValue },
+ { "BaseAddress", "BASE:", "Base Address", "", cmVS7FlagTable::UserValue },
+ { "ImportLibrary", "IMPLIB:", "Import Library", "",
+ cmVS7FlagTable::UserValue },
+ { "MergeSections", "MERGE:", "Merge Sections", "",
+ cmVS7FlagTable::UserValue },
+ { "LinkKeyFile", "KEYFILE:", "Key File", "", cmVS7FlagTable::UserValue },
+ { "KeyContainer", "KEYCONTAINER:", "Key Container", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [AdditionalOptions] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS14MASMFlagTable.h b/Source/cmVS14MASMFlagTable.h
new file mode 100644
index 0000000..c4e5e1e
--- /dev/null
+++ b/Source/cmVS14MASMFlagTable.h
@@ -0,0 +1,78 @@
+static cmVS7FlagTable cmVS14MASMFlagTable[] = {
+
+ // Enum Properties
+ { "PreserveIdentifierCase", "", "Default", "0", 0 },
+ { "PreserveIdentifierCase", "/Cp", "Preserves Identifier Case (/Cp)", "1",
+ 0 },
+ { "PreserveIdentifierCase", "/Cu",
+ "Maps all identifiers to upper case. (/Cu)", "2", 0 },
+ { "PreserveIdentifierCase", "/Cx",
+ "Preserves case in public and extern symbols. (/Cx)", "3", 0 },
+
+ { "WarningLevel", "/W0", "Warning Level 0 (/W0)", "0", 0 },
+ { "WarningLevel", "/W1", "Warning Level 1 (/W1)", "1", 0 },
+ { "WarningLevel", "/W2", "Warning Level 2 (/W2)", "2", 0 },
+ { "WarningLevel", "/W3", "Warning Level 3 (/W3)", "3", 0 },
+
+ { "PackAlignmentBoundary", "", "Default", "0", 0 },
+ { "PackAlignmentBoundary", "/Zp1", "One Byte Boundary (/Zp1)", "1", 0 },
+ { "PackAlignmentBoundary", "/Zp2", "Two Byte Boundary (/Zp2)", "2", 0 },
+ { "PackAlignmentBoundary", "/Zp4", "Four Byte Boundary (/Zp4)", "3", 0 },
+ { "PackAlignmentBoundary", "/Zp8", "Eight Byte Boundary (/Zp8)", "4", 0 },
+ { "PackAlignmentBoundary", "/Zp16", "Sixteen Byte Boundary (/Zp16)", "5",
+ 0 },
+
+ { "CallingConvention", "", "Default", "0", 0 },
+ { "CallingConvention", "/Gd", "Use C-style Calling Convention (/Gd)", "1",
+ 0 },
+ { "CallingConvention", "/Gz", "Use stdcall Calling Convention (/Gz)", "2",
+ 0 },
+ { "CallingConvention", "/Gc", "Use Pascal Calling Convention (/Gc)", "3",
+ 0 },
+
+ { "ErrorReporting", "/errorReport:prompt",
+ "Prompt to send report immediately (/errorReport:prompt)", "0", 0 },
+ { "ErrorReporting", "/errorReport:queue",
+ "Prompt to send report at the next logon (/errorReport:queue)", "1", 0 },
+ { "ErrorReporting", "/errorReport:send",
+ "Automatically send report (/errorReport:send)", "2", 0 },
+ { "ErrorReporting", "/errorReport:none",
+ "Do not send report (/errorReport:none)", "3", 0 },
+
+ // Bool Properties
+ { "NoLogo", "/nologo", "", "true", 0 },
+ { "GeneratePreprocessedSourceListing", "/EP", "", "true", 0 },
+ { "ListAllAvailableInformation", "/Sa", "", "true", 0 },
+ { "UseSafeExceptionHandlers", "/safeseh", "", "true", 0 },
+ { "AddFirstPassListing", "/Sf", "", "true", 0 },
+ { "EnableAssemblyGeneratedCodeListing", "/Sg", "", "true", 0 },
+ { "DisableSymbolTable", "/Sn", "", "true", 0 },
+ { "EnableFalseConditionalsInListing", "/Sx", "", "true", 0 },
+ { "TreatWarningsAsErrors", "/WX", "", "true", 0 },
+ { "MakeAllSymbolsPublic", "/Zf", "", "true", 0 },
+ { "GenerateDebugInformation", "/Zi", "", "true", 0 },
+ { "EnableMASM51Compatibility", "/Zm", "", "true", 0 },
+ { "PerformSyntaxCheckOnly", "/Zs", "", "true", 0 },
+
+ // Bool Properties With Argument
+
+ // String List Properties
+ { "PreprocessorDefinitions", "/D", "Preprocessor Definitions", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "IncludePaths", "/I", "Include Paths", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "BrowseFile", "/FR", "Generate Browse Information File", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ // Skip [AdditionalDependencies] - no command line Switch.
+
+ // String Properties
+ // Skip [Inputs] - no command line Switch.
+ { "ObjectFileName", "/Fo", "Object File Name", "",
+ cmVS7FlagTable::UserValue },
+ { "AssembledCodeListingFile", "/Fl", "Assembled Code Listing File", "",
+ cmVS7FlagTable::UserValue },
+ // Skip [CommandLineTemplate] - no command line Switch.
+ // Skip [ExecutionDescription] - no command line Switch.
+ // Skip [AdditionalOptions] - no command line Switch.
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS14RCFlagTable.h b/Source/cmVS14RCFlagTable.h
new file mode 100644
index 0000000..11e00d5
--- /dev/null
+++ b/Source/cmVS14RCFlagTable.h
@@ -0,0 +1,6 @@
+static cmVS7FlagTable cmVS14RCFlagTable[] = {
+ // Bool Properties
+ { "NullTerminateStrings", "n", "", "true", 0 },
+
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVariableRequiresCommand.cxx b/Source/cmVariableRequiresCommand.cxx
new file mode 100644
index 0000000..8d55b0e
--- /dev/null
+++ b/Source/cmVariableRequiresCommand.cxx
@@ -0,0 +1,74 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmVariableRequiresCommand.h"
+
+#include "cmState.h"
+
+// cmLibraryCommand
+bool cmVariableRequiresCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ if (this->Disallowed(
+ cmPolicies::CMP0035,
+ "The variable_requires command should not be called; see CMP0035.")) {
+ return true;
+ }
+ if (args.size() < 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string testVariable = args[0];
+ if (!this->Makefile->IsOn(testVariable)) {
+ return true;
+ }
+ std::string resultVariable = args[1];
+ bool requirementsMet = true;
+ std::string notSet;
+ bool hasAdvanced = false;
+ cmState* state = this->Makefile->GetState();
+ for (unsigned int i = 2; i < args.size(); ++i) {
+ if (!this->Makefile->IsOn(args[i])) {
+ requirementsMet = false;
+ notSet += args[i];
+ notSet += "\n";
+ if (state->GetCacheEntryValue(args[i]) &&
+ state->GetCacheEntryPropertyAsBool(args[i], "ADVANCED")) {
+ hasAdvanced = true;
+ }
+ }
+ }
+ const char* reqVar = this->Makefile->GetDefinition(resultVariable);
+ // if reqVar is unset, then set it to requirementsMet
+ // if reqVar is set to true, but requirementsMet is false , then
+ // set reqVar to false.
+ if (!reqVar || (!requirementsMet && this->Makefile->IsOn(reqVar))) {
+ this->Makefile->AddDefinition(resultVariable, requirementsMet);
+ }
+
+ if (!requirementsMet) {
+ std::string message = "Variable assertion failed:\n";
+ message +=
+ testVariable + " Requires that the following unset variables are set:\n";
+ message += notSet;
+ message += "\nPlease set them, or set ";
+ message += testVariable + " to false, and re-configure.\n";
+ if (hasAdvanced) {
+ message +=
+ "One or more of the required variables is advanced."
+ " To set the variable, you must turn on advanced mode in cmake.";
+ }
+ cmSystemTools::Error(message.c_str());
+ }
+
+ return true;
+}
diff --git a/Source/cmVariableRequiresCommand.h b/Source/cmVariableRequiresCommand.h
new file mode 100644
index 0000000..c4b0817
--- /dev/null
+++ b/Source/cmVariableRequiresCommand.h
@@ -0,0 +1,27 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmVariableRequiresCommand_h
+#define cmVariableRequiresCommand_h
+
+#include "cmCommand.h"
+
+class cmVariableRequiresCommand : public cmCommand
+{
+public:
+ cmTypeMacro(cmVariableRequiresCommand, cmCommand);
+ cmCommand* Clone() CM_OVERRIDE { return new cmVariableRequiresCommand; }
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+ std::string GetName() const CM_OVERRIDE { return "variable_requires"; }
+};
+
+#endif
diff --git a/Source/cmVariableWatch.cxx b/Source/cmVariableWatch.cxx
new file mode 100644
index 0000000..56e2770
--- /dev/null
+++ b/Source/cmVariableWatch.cxx
@@ -0,0 +1,104 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmVariableWatch.h"
+
+#include "cmAlgorithms.h"
+
+#include <cm_auto_ptr.hxx>
+
+static const char* const cmVariableWatchAccessStrings[] = {
+ "READ_ACCESS", "UNKNOWN_READ_ACCESS", "UNKNOWN_DEFINED_ACCESS",
+ "MODIFIED_ACCESS", "REMOVED_ACCESS", "NO_ACCESS"
+};
+
+const char* cmVariableWatch::GetAccessAsString(int access_type)
+{
+ if (access_type < 0 || access_type >= cmVariableWatch::NO_ACCESS) {
+ return "NO_ACCESS";
+ }
+ return cmVariableWatchAccessStrings[access_type];
+}
+
+cmVariableWatch::cmVariableWatch()
+{
+}
+
+template <typename C>
+void deleteAllSecond(typename C::value_type it)
+{
+ cmDeleteAll(it.second);
+}
+
+cmVariableWatch::~cmVariableWatch()
+{
+ std::for_each(this->WatchMap.begin(), this->WatchMap.end(),
+ deleteAllSecond<cmVariableWatch::StringToVectorOfPairs>);
+}
+
+bool cmVariableWatch::AddWatch(const std::string& variable, WatchMethod method,
+ void* client_data /*=0*/,
+ DeleteData delete_data /*=0*/)
+{
+ CM_AUTO_PTR<cmVariableWatch::Pair> p(new cmVariableWatch::Pair);
+ p->Method = method;
+ p->ClientData = client_data;
+ p->DeleteDataCall = delete_data;
+ cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable];
+ cmVariableWatch::VectorOfPairs::size_type cc;
+ for (cc = 0; cc < vp->size(); cc++) {
+ cmVariableWatch::Pair* pair = (*vp)[cc];
+ if (pair->Method == method && client_data &&
+ client_data == pair->ClientData) {
+ // Callback already exists
+ return false;
+ }
+ }
+ vp->push_back(p.release());
+ return true;
+}
+
+void cmVariableWatch::RemoveWatch(const std::string& variable,
+ WatchMethod method, void* client_data /*=0*/)
+{
+ if (!this->WatchMap.count(variable)) {
+ return;
+ }
+ cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable];
+ cmVariableWatch::VectorOfPairs::iterator it;
+ for (it = vp->begin(); it != vp->end(); ++it) {
+ if ((*it)->Method == method &&
+ // If client_data is NULL, we want to disconnect all watches against
+ // the given method; otherwise match ClientData as well.
+ (!client_data || (client_data == (*it)->ClientData))) {
+ delete *it;
+ vp->erase(it);
+ return;
+ }
+ }
+}
+
+bool cmVariableWatch::VariableAccessed(const std::string& variable,
+ int access_type, const char* newValue,
+ const cmMakefile* mf) const
+{
+ cmVariableWatch::StringToVectorOfPairs::const_iterator mit =
+ this->WatchMap.find(variable);
+ if (mit != this->WatchMap.end()) {
+ const cmVariableWatch::VectorOfPairs* vp = &mit->second;
+ cmVariableWatch::VectorOfPairs::const_iterator it;
+ for (it = vp->begin(); it != vp->end(); it++) {
+ (*it)->Method(variable, access_type, (*it)->ClientData, newValue, mf);
+ }
+ return true;
+ }
+ return false;
+}
diff --git a/Source/cmVariableWatch.h b/Source/cmVariableWatch.h
new file mode 100644
index 0000000..5ddb907
--- /dev/null
+++ b/Source/cmVariableWatch.h
@@ -0,0 +1,94 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmVariableWatch_h
+#define cmVariableWatch_h
+
+#include "cmStandardIncludes.h"
+
+class cmMakefile;
+
+/** \class cmVariableWatch
+ * \brief Helper class for watching of variable accesses.
+ *
+ * Calls function when variable is accessed
+ */
+class cmVariableWatch
+{
+public:
+ typedef void (*WatchMethod)(const std::string& variable, int access_type,
+ void* client_data, const char* newValue,
+ const cmMakefile* mf);
+ typedef void (*DeleteData)(void* client_data);
+
+ cmVariableWatch();
+ ~cmVariableWatch();
+
+ /**
+ * Add watch to the variable
+ */
+ bool AddWatch(const std::string& variable, WatchMethod method,
+ void* client_data = CM_NULLPTR,
+ DeleteData delete_data = CM_NULLPTR);
+ void RemoveWatch(const std::string& variable, WatchMethod method,
+ void* client_data = CM_NULLPTR);
+
+ /**
+ * This method is called when variable is accessed
+ */
+ bool VariableAccessed(const std::string& variable, int access_type,
+ const char* newValue, const cmMakefile* mf) const;
+
+ /**
+ * Different access types.
+ */
+ enum
+ {
+ VARIABLE_READ_ACCESS = 0,
+ UNKNOWN_VARIABLE_READ_ACCESS,
+ UNKNOWN_VARIABLE_DEFINED_ACCESS,
+ VARIABLE_MODIFIED_ACCESS,
+ VARIABLE_REMOVED_ACCESS,
+ NO_ACCESS
+ };
+
+ /**
+ * Return the access as string
+ */
+ static const char* GetAccessAsString(int access_type);
+
+protected:
+ struct Pair
+ {
+ WatchMethod Method;
+ void* ClientData;
+ DeleteData DeleteDataCall;
+ Pair()
+ : Method(CM_NULLPTR)
+ , ClientData(CM_NULLPTR)
+ , DeleteDataCall(CM_NULLPTR)
+ {
+ }
+ ~Pair()
+ {
+ if (this->DeleteDataCall && this->ClientData) {
+ this->DeleteDataCall(this->ClientData);
+ }
+ }
+ };
+
+ typedef std::vector<Pair*> VectorOfPairs;
+ typedef std::map<std::string, VectorOfPairs> StringToVectorOfPairs;
+
+ StringToVectorOfPairs WatchMap;
+};
+
+#endif
diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx
new file mode 100644
index 0000000..f30ffe8
--- /dev/null
+++ b/Source/cmVariableWatchCommand.cxx
@@ -0,0 +1,137 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmVariableWatchCommand.h"
+
+#include "cmVariableWatch.h"
+
+struct cmVariableWatchCallbackData
+{
+ bool InCallback;
+ std::string Command;
+};
+
+static void cmVariableWatchCommandVariableAccessed(const std::string& variable,
+ int access_type,
+ void* client_data,
+ const char* newValue,
+ const cmMakefile* mf)
+{
+ cmVariableWatchCallbackData* data =
+ static_cast<cmVariableWatchCallbackData*>(client_data);
+
+ if (data->InCallback) {
+ return;
+ }
+ data->InCallback = true;
+
+ cmListFileFunction newLFF;
+ cmListFileArgument arg;
+ bool processed = false;
+ const char* accessString = cmVariableWatch::GetAccessAsString(access_type);
+ const char* currentListFile = mf->GetDefinition("CMAKE_CURRENT_LIST_FILE");
+
+ /// Ultra bad!!
+ cmMakefile* makefile = const_cast<cmMakefile*>(mf);
+
+ std::string stack = makefile->GetProperty("LISTFILE_STACK");
+ if (!data->Command.empty()) {
+ newLFF.Arguments.clear();
+ newLFF.Arguments.push_back(
+ cmListFileArgument(variable, cmListFileArgument::Quoted, 9999));
+ newLFF.Arguments.push_back(
+ cmListFileArgument(accessString, cmListFileArgument::Quoted, 9999));
+ newLFF.Arguments.push_back(cmListFileArgument(
+ newValue ? newValue : "", cmListFileArgument::Quoted, 9999));
+ newLFF.Arguments.push_back(
+ cmListFileArgument(currentListFile, cmListFileArgument::Quoted, 9999));
+ newLFF.Arguments.push_back(
+ cmListFileArgument(stack, cmListFileArgument::Quoted, 9999));
+ newLFF.Name = data->Command;
+ newLFF.Line = 9999;
+ cmExecutionStatus status;
+ if (!makefile->ExecuteCommand(newLFF, status)) {
+ std::ostringstream error;
+ error << "Error in cmake code at\nUnknown:0:\n"
+ << "A command failed during the invocation of callback \""
+ << data->Command << "\".";
+ cmSystemTools::Error(error.str().c_str());
+ data->InCallback = false;
+ return;
+ }
+ processed = true;
+ }
+ if (!processed) {
+ std::ostringstream msg;
+ msg << "Variable \"" << variable << "\" was accessed using "
+ << accessString << " with value \"" << (newValue ? newValue : "")
+ << "\".";
+ makefile->IssueMessage(cmake::LOG, msg.str());
+ }
+
+ data->InCallback = false;
+}
+
+static void deleteVariableWatchCallbackData(void* client_data)
+{
+ cmVariableWatchCallbackData* data =
+ static_cast<cmVariableWatchCallbackData*>(client_data);
+ delete data;
+}
+
+cmVariableWatchCommand::cmVariableWatchCommand()
+{
+}
+
+cmVariableWatchCommand::~cmVariableWatchCommand()
+{
+ std::set<std::string>::const_iterator it;
+ for (it = this->WatchedVariables.begin(); it != this->WatchedVariables.end();
+ ++it) {
+ this->Makefile->GetCMakeInstance()->GetVariableWatch()->RemoveWatch(
+ *it, cmVariableWatchCommandVariableAccessed);
+ }
+}
+
+bool cmVariableWatchCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("must be called with at least one argument.");
+ return false;
+ }
+ std::string variable = args[0];
+ std::string command;
+ if (args.size() > 1) {
+ command = args[1];
+ }
+ if (variable == "CMAKE_CURRENT_LIST_FILE") {
+ std::ostringstream ostr;
+ ostr << "cannot be set on the variable: " << variable;
+ this->SetError(ostr.str());
+ return false;
+ }
+
+ cmVariableWatchCallbackData* data = new cmVariableWatchCallbackData;
+
+ data->InCallback = false;
+ data->Command = command;
+
+ this->WatchedVariables.insert(variable);
+ if (!this->Makefile->GetCMakeInstance()->GetVariableWatch()->AddWatch(
+ variable, cmVariableWatchCommandVariableAccessed, data,
+ deleteVariableWatchCallbackData)) {
+ deleteVariableWatchCallbackData(data);
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmVariableWatchCommand.h b/Source/cmVariableWatchCommand.h
new file mode 100644
index 0000000..1d402af
--- /dev/null
+++ b/Source/cmVariableWatchCommand.h
@@ -0,0 +1,62 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmVariableWatchCommand_h
+#define cmVariableWatchCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmVariableWatchCommand
+ * \brief Watch when the variable changes and invoke command
+ *
+ */
+class cmVariableWatchCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmVariableWatchCommand; }
+
+ //! Default constructor
+ cmVariableWatchCommand();
+
+ //! Destructor.
+ ~cmVariableWatchCommand() CM_OVERRIDE;
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /** This command does not really have a final pass but it needs to
+ stay alive since it owns variable watch callback information. */
+ bool HasFinalPass() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "variable_watch"; }
+
+ cmTypeMacro(cmVariableWatchCommand, cmCommand);
+
+protected:
+ std::set<std::string> WatchedVariables;
+};
+
+#endif
diff --git a/Source/cmVersion.cxx b/Source/cmVersion.cxx
new file mode 100644
index 0000000..4c2e4ce
--- /dev/null
+++ b/Source/cmVersion.cxx
@@ -0,0 +1,36 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmVersion.h"
+
+#include "cmVersionMacros.h"
+
+unsigned int cmVersion::GetMajorVersion()
+{
+ return CMake_VERSION_MAJOR;
+}
+unsigned int cmVersion::GetMinorVersion()
+{
+ return CMake_VERSION_MINOR;
+}
+unsigned int cmVersion::GetPatchVersion()
+{
+ return CMake_VERSION_PATCH;
+}
+unsigned int cmVersion::GetTweakVersion()
+{
+ return 0;
+}
+
+const char* cmVersion::GetCMakeVersion()
+{
+ return CMake_VERSION;
+}
diff --git a/Source/cmVersion.h b/Source/cmVersion.h
new file mode 100644
index 0000000..46fd5a6
--- /dev/null
+++ b/Source/cmVersion.h
@@ -0,0 +1,43 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmVersion_h
+#define cmVersion_h
+
+#include "cmStandardIncludes.h"
+
+/** \class cmVersion
+ * \brief Helper class for providing CMake and CTest version information.
+ *
+ * Finds all version related information.
+ */
+class cmVersion
+{
+public:
+ /**
+ * Return major and minor version numbers for cmake.
+ */
+ static unsigned int GetMajorVersion();
+ static unsigned int GetMinorVersion();
+ static unsigned int GetPatchVersion();
+ static unsigned int GetTweakVersion();
+ static const char* GetCMakeVersion();
+};
+
+/* Encode with room for up to 1000 minor releases between major releases
+ and to encode dates until the year 10000 in the patch level. */
+#define CMake_VERSION_ENCODE__BASE KWIML_INT_UINT64_C(100000000)
+#define CMake_VERSION_ENCODE(major, minor, patch) \
+ ((((major)*1000u) * CMake_VERSION_ENCODE__BASE) + \
+ (((minor) % 1000u) * CMake_VERSION_ENCODE__BASE) + \
+ (((patch) % CMake_VERSION_ENCODE__BASE)))
+
+#endif
diff --git a/Source/cmVersionConfig.h.in b/Source/cmVersionConfig.h.in
new file mode 100644
index 0000000..16aeabe
--- /dev/null
+++ b/Source/cmVersionConfig.h.in
@@ -0,0 +1,15 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#define CMake_VERSION_MAJOR @CMake_VERSION_MAJOR@
+#define CMake_VERSION_MINOR @CMake_VERSION_MINOR@
+#define CMake_VERSION_PATCH @CMake_VERSION_PATCH@
+#define CMake_VERSION "@CMake_VERSION@"
diff --git a/Source/cmVersionMacros.h b/Source/cmVersionMacros.h
new file mode 100644
index 0000000..a2dcce4
--- /dev/null
+++ b/Source/cmVersionMacros.h
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmVersionMacros_h
+#define cmVersionMacros_h
+
+#include "cmVersionConfig.h"
+
+#define CMake_VERSION_PATCH_IS_RELEASE(patch) ((patch) < 20000000)
+#if CMake_VERSION_PATCH_IS_RELEASE(CMake_VERSION_PATCH)
+#define CMake_VERSION_IS_RELEASE 1
+#endif
+
+#endif
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
new file mode 100644
index 0000000..13e7c89
--- /dev/null
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -0,0 +1,3383 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmVisualStudio10TargetGenerator.h"
+
+#include "cmComputeLinkInformation.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalVisualStudio10Generator.h"
+#include "cmLocalVisualStudio7Generator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmVS10CLFlagTable.h"
+#include "cmVS10LibFlagTable.h"
+#include "cmVS10LinkFlagTable.h"
+#include "cmVS10MASMFlagTable.h"
+#include "cmVS10RCFlagTable.h"
+#include "cmVS11CLFlagTable.h"
+#include "cmVS11LibFlagTable.h"
+#include "cmVS11LinkFlagTable.h"
+#include "cmVS11MASMFlagTable.h"
+#include "cmVS11RCFlagTable.h"
+#include "cmVS12CLFlagTable.h"
+#include "cmVS12LibFlagTable.h"
+#include "cmVS12LinkFlagTable.h"
+#include "cmVS12MASMFlagTable.h"
+#include "cmVS12RCFlagTable.h"
+#include "cmVS14CLFlagTable.h"
+#include "cmVS14LibFlagTable.h"
+#include "cmVS14LinkFlagTable.h"
+#include "cmVS14MASMFlagTable.h"
+#include "cmVS14RCFlagTable.h"
+#include "cmVisualStudioGeneratorOptions.h"
+#include "windows.h"
+
+#include <cm_auto_ptr.hxx>
+
+cmIDEFlagTable const* cmVisualStudio10TargetGenerator::GetClFlagTable() const
+{
+ if (this->MSTools) {
+ cmGlobalVisualStudioGenerator::VSVersion v =
+ this->LocalGenerator->GetVersion();
+ if (v >= cmGlobalVisualStudioGenerator::VS14) {
+ return cmVS14CLFlagTable;
+ } else if (v >= cmGlobalVisualStudioGenerator::VS12) {
+ return cmVS12CLFlagTable;
+ } else if (v == cmGlobalVisualStudioGenerator::VS11) {
+ return cmVS11CLFlagTable;
+ } else {
+ return cmVS10CLFlagTable;
+ }
+ }
+ return 0;
+}
+
+cmIDEFlagTable const* cmVisualStudio10TargetGenerator::GetRcFlagTable() const
+{
+ if (this->MSTools) {
+ cmGlobalVisualStudioGenerator::VSVersion v =
+ this->LocalGenerator->GetVersion();
+ if (v >= cmGlobalVisualStudioGenerator::VS14) {
+ return cmVS14RCFlagTable;
+ } else if (v >= cmGlobalVisualStudioGenerator::VS12) {
+ return cmVS12RCFlagTable;
+ } else if (v == cmGlobalVisualStudioGenerator::VS11) {
+ return cmVS11RCFlagTable;
+ } else {
+ return cmVS10RCFlagTable;
+ }
+ }
+ return 0;
+}
+
+cmIDEFlagTable const* cmVisualStudio10TargetGenerator::GetLibFlagTable() const
+{
+ if (this->MSTools) {
+ cmGlobalVisualStudioGenerator::VSVersion v =
+ this->LocalGenerator->GetVersion();
+ if (v >= cmGlobalVisualStudioGenerator::VS14) {
+ return cmVS14LibFlagTable;
+ } else if (v >= cmGlobalVisualStudioGenerator::VS12) {
+ return cmVS12LibFlagTable;
+ } else if (v == cmGlobalVisualStudioGenerator::VS11) {
+ return cmVS11LibFlagTable;
+ } else {
+ return cmVS10LibFlagTable;
+ }
+ }
+ return 0;
+}
+
+cmIDEFlagTable const* cmVisualStudio10TargetGenerator::GetLinkFlagTable() const
+{
+ if (this->MSTools) {
+ cmGlobalVisualStudioGenerator::VSVersion v =
+ this->LocalGenerator->GetVersion();
+ if (v >= cmGlobalVisualStudioGenerator::VS14) {
+ return cmVS14LinkFlagTable;
+ } else if (v >= cmGlobalVisualStudioGenerator::VS12) {
+ return cmVS12LinkFlagTable;
+ } else if (v == cmGlobalVisualStudioGenerator::VS11) {
+ return cmVS11LinkFlagTable;
+ } else {
+ return cmVS10LinkFlagTable;
+ }
+ }
+ return 0;
+}
+
+cmIDEFlagTable const* cmVisualStudio10TargetGenerator::GetMasmFlagTable() const
+{
+ if (this->MSTools) {
+ cmGlobalVisualStudioGenerator::VSVersion v =
+ this->LocalGenerator->GetVersion();
+ if (v >= cmGlobalVisualStudioGenerator::VS14) {
+ return cmVS14MASMFlagTable;
+ } else if (v >= cmGlobalVisualStudioGenerator::VS12) {
+ return cmVS12MASMFlagTable;
+ } else if (v == cmGlobalVisualStudioGenerator::VS11) {
+ return cmVS11MASMFlagTable;
+ } else {
+ return cmVS10MASMFlagTable;
+ }
+ }
+ return 0;
+}
+
+static std::string cmVS10EscapeXML(std::string arg)
+{
+ cmSystemTools::ReplaceString(arg, "&", "&amp;");
+ cmSystemTools::ReplaceString(arg, "<", "&lt;");
+ cmSystemTools::ReplaceString(arg, ">", "&gt;");
+ return arg;
+}
+
+static std::string cmVS10EscapeComment(std::string comment)
+{
+ // MSBuild takes the CDATA of a <Message></Message> element and just
+ // does "echo $CDATA" with no escapes. We must encode the string.
+ // http://technet.microsoft.com/en-us/library/cc772462%28WS.10%29.aspx
+ std::string echoable;
+ for (std::string::iterator c = comment.begin(); c != comment.end(); ++c) {
+ switch (*c) {
+ case '\r':
+ break;
+ case '\n':
+ echoable += '\t';
+ break;
+ case '"': /* no break */
+ case '|': /* no break */
+ case '&': /* no break */
+ case '<': /* no break */
+ case '>': /* no break */
+ case '^':
+ echoable += '^'; /* no break */
+ default:
+ echoable += *c;
+ break;
+ }
+ }
+ return echoable;
+}
+
+cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
+ cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg)
+{
+ this->GlobalGenerator = gg;
+ this->GeneratorTarget = target;
+ this->Makefile = target->Target->GetMakefile();
+ this->Makefile->GetConfigurations(this->Configurations);
+ this->LocalGenerator =
+ (cmLocalVisualStudio7Generator*)this->GeneratorTarget->GetLocalGenerator();
+ this->Name = this->GeneratorTarget->GetName();
+ this->GUID = this->GlobalGenerator->GetGUID(this->Name.c_str());
+ this->Platform = gg->GetPlatformName();
+ this->NsightTegra = gg->IsNsightTegra();
+ for (int i =
+ sscanf(gg->GetNsightTegraVersion().c_str(), "%u.%u.%u.%u",
+ &this->NsightTegraVersion[0], &this->NsightTegraVersion[1],
+ &this->NsightTegraVersion[2], &this->NsightTegraVersion[3]);
+ i < 4; ++i) {
+ this->NsightTegraVersion[i] = 0;
+ }
+ this->MSTools = !this->NsightTegra;
+ this->TargetCompileAsWinRT = false;
+ this->BuildFileStream = 0;
+ this->IsMissingFiles = false;
+ this->DefaultArtifactDir =
+ this->LocalGenerator->GetCurrentBinaryDirectory() + std::string("/") +
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+}
+
+cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator()
+{
+ for (OptionsMap::iterator i = this->ClOptions.begin();
+ i != this->ClOptions.end(); ++i) {
+ delete i->second;
+ }
+ for (OptionsMap::iterator i = this->LinkOptions.begin();
+ i != this->LinkOptions.end(); ++i) {
+ delete i->second;
+ }
+ if (!this->BuildFileStream) {
+ return;
+ }
+ if (this->BuildFileStream->Close()) {
+ this->GlobalGenerator->FileReplacedDuringGenerate(this->PathToVcxproj);
+ }
+ delete this->BuildFileStream;
+}
+
+void cmVisualStudio10TargetGenerator::WritePlatformConfigTag(
+ const char* tag, const std::string& config, int indentLevel,
+ const char* attribute, const char* end, std::ostream* stream)
+
+{
+ if (!stream) {
+ stream = this->BuildFileStream;
+ }
+ stream->fill(' ');
+ stream->width(indentLevel * 2);
+ (*stream) << "";
+ (*stream) << "<" << tag << " Condition=\"'$(Configuration)|$(Platform)'=='";
+ (*stream) << config << "|" << this->Platform << "'\"";
+ if (attribute) {
+ (*stream) << attribute;
+ }
+ // close the tag
+ (*stream) << ">";
+ if (end) {
+ (*stream) << end;
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteString(const char* line,
+ int indentLevel)
+{
+ this->BuildFileStream->fill(' ');
+ this->BuildFileStream->width(indentLevel * 2);
+ // write an empty string to get the fill level indent to print
+ (*this->BuildFileStream) << "";
+ (*this->BuildFileStream) << line;
+}
+
+#define VS10_USER_PROPS "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props"
+
+void cmVisualStudio10TargetGenerator::Generate()
+{
+ // do not generate external ms projects
+ if (this->GeneratorTarget->GetType() == cmState::INTERFACE_LIBRARY ||
+ this->GeneratorTarget->GetProperty("EXTERNAL_MSPROJECT")) {
+ return;
+ }
+ // Tell the global generator the name of the project file
+ this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME",
+ this->Name.c_str());
+ this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME_EXT",
+ ".vcxproj");
+ if (this->GeneratorTarget->GetType() <= cmState::OBJECT_LIBRARY) {
+ if (!this->ComputeClOptions()) {
+ return;
+ }
+ if (!this->ComputeRcOptions()) {
+ return;
+ }
+ if (!this->ComputeMasmOptions()) {
+ return;
+ }
+ if (!this->ComputeLinkOptions()) {
+ return;
+ }
+ }
+ std::string path = this->LocalGenerator->GetCurrentBinaryDirectory();
+ path += "/";
+ path += this->Name;
+ path += ".vcxproj";
+ this->BuildFileStream = new cmGeneratedFileStream(path.c_str());
+ this->PathToVcxproj = path;
+ this->BuildFileStream->SetCopyIfDifferent(true);
+
+ // Write the encoding header into the file
+ char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
+ this->BuildFileStream->write(magic, 3);
+
+ // get the tools version to use
+ const std::string toolsVer(this->GlobalGenerator->GetToolsVersion());
+ std::string project_defaults = "<?xml version=\"1.0\" encoding=\"" +
+ this->GlobalGenerator->Encoding() + "\"?>\n";
+ project_defaults.append("<Project DefaultTargets=\"Build\" ToolsVersion=\"");
+ project_defaults.append(toolsVer + "\" ");
+ project_defaults.append(
+ "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n");
+ this->WriteString(project_defaults.c_str(), 0);
+
+ if (this->NsightTegra) {
+ this->WriteString("<PropertyGroup Label=\"NsightTegraProject\">\n", 1);
+ const int nsightTegraMajorVersion = this->NsightTegraVersion[0];
+ const int nsightTegraMinorVersion = this->NsightTegraVersion[1];
+ if (nsightTegraMajorVersion >= 2) {
+ this->WriteString("<NsightTegraProjectRevisionNumber>", 2);
+ if (nsightTegraMajorVersion > 3 ||
+ (nsightTegraMajorVersion == 3 && nsightTegraMinorVersion >= 1)) {
+ (*this->BuildFileStream) << "11";
+ } else {
+ // Nsight Tegra 2.0 uses project revision 9.
+ (*this->BuildFileStream) << "9";
+ }
+ (*this->BuildFileStream) << "</NsightTegraProjectRevisionNumber>\n";
+ // Tell newer versions to upgrade silently when loading.
+ this->WriteString("<NsightTegraUpgradeOnceWithoutPrompt>"
+ "true"
+ "</NsightTegraUpgradeOnceWithoutPrompt>\n",
+ 2);
+ } else {
+ // Require Nsight Tegra 1.6 for JCompile support.
+ this->WriteString("<NsightTegraProjectRevisionNumber>"
+ "7"
+ "</NsightTegraProjectRevisionNumber>\n",
+ 2);
+ }
+ this->WriteString("</PropertyGroup>\n", 1);
+ }
+
+ this->WriteProjectConfigurations();
+ this->WriteString("<PropertyGroup Label=\"Globals\">\n", 1);
+ this->WriteString("<ProjectGUID>", 2);
+ (*this->BuildFileStream) << "{" << this->GUID << "}</ProjectGUID>\n";
+
+ if (this->MSTools &&
+ this->GeneratorTarget->GetType() <= cmState::GLOBAL_TARGET) {
+ this->WriteApplicationTypeSettings();
+ this->VerifyNecessaryFiles();
+ }
+
+ const char* vsProjectTypes =
+ this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES");
+ if (vsProjectTypes) {
+ this->WriteString("<ProjectTypes>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(vsProjectTypes)
+ << "</ProjectTypes>\n";
+ }
+
+ const char* vsProjectName =
+ this->GeneratorTarget->GetProperty("VS_SCC_PROJECTNAME");
+ const char* vsLocalPath =
+ this->GeneratorTarget->GetProperty("VS_SCC_LOCALPATH");
+ const char* vsProvider =
+ this->GeneratorTarget->GetProperty("VS_SCC_PROVIDER");
+
+ if (vsProjectName && vsLocalPath && vsProvider) {
+ this->WriteString("<SccProjectName>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(vsProjectName)
+ << "</SccProjectName>\n";
+ this->WriteString("<SccLocalPath>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(vsLocalPath)
+ << "</SccLocalPath>\n";
+ this->WriteString("<SccProvider>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(vsProvider)
+ << "</SccProvider>\n";
+
+ const char* vsAuxPath =
+ this->GeneratorTarget->GetProperty("VS_SCC_AUXPATH");
+ if (vsAuxPath) {
+ this->WriteString("<SccAuxPath>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(vsAuxPath)
+ << "</SccAuxPath>\n";
+ }
+ }
+
+ if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT")) {
+ this->WriteString("<WinMDAssembly>true</WinMDAssembly>\n", 2);
+ }
+
+ const char* vsGlobalKeyword =
+ this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD");
+ if (!vsGlobalKeyword) {
+ this->WriteString("<Keyword>Win32Proj</Keyword>\n", 2);
+ } else {
+ this->WriteString("<Keyword>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(vsGlobalKeyword)
+ << "</Keyword>\n";
+ }
+
+ const char* vsGlobalRootNamespace =
+ this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE");
+ if (vsGlobalRootNamespace) {
+ this->WriteString("<RootNamespace>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(vsGlobalRootNamespace)
+ << "</RootNamespace>\n";
+ }
+
+ this->WriteString("<Platform>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(this->Platform)
+ << "</Platform>\n";
+ const char* projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL");
+ if (!projLabel) {
+ projLabel = this->Name.c_str();
+ }
+ this->WriteString("<ProjectName>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(projLabel) << "</ProjectName>\n";
+ if (const char* targetFrameworkVersion = this->GeneratorTarget->GetProperty(
+ "VS_DOTNET_TARGET_FRAMEWORK_VERSION")) {
+ this->WriteString("<TargetFrameworkVersion>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(targetFrameworkVersion)
+ << "</TargetFrameworkVersion>\n";
+ }
+
+ std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys();
+ for (std::vector<std::string>::const_iterator keyIt = keys.begin();
+ keyIt != keys.end(); ++keyIt) {
+ static const char* prefix = "VS_GLOBAL_";
+ if (keyIt->find(prefix) != 0)
+ continue;
+ std::string globalKey = keyIt->substr(strlen(prefix));
+ // Skip invalid or separately-handled properties.
+ if (globalKey == "" || globalKey == "PROJECT_TYPES" ||
+ globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") {
+ continue;
+ }
+ const char* value = this->GeneratorTarget->GetProperty(keyIt->c_str());
+ if (!value)
+ continue;
+ this->WriteString("<", 2);
+ (*this->BuildFileStream) << globalKey << ">" << cmVS10EscapeXML(value)
+ << "</" << globalKey << ">\n";
+ }
+
+ this->WriteString("</PropertyGroup>\n", 1);
+ this->WriteString("<Import Project="
+ "\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n",
+ 1);
+ this->WriteProjectConfigurationValues();
+ this->WriteString(
+ "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n", 1);
+ this->WriteString("<ImportGroup Label=\"ExtensionSettings\">\n", 1);
+ if (this->GlobalGenerator->IsMasmEnabled()) {
+ this->WriteString("<Import Project=\"$(VCTargetsPath)\\"
+ "BuildCustomizations\\masm.props\" />\n",
+ 2);
+ }
+ this->WriteString("</ImportGroup>\n", 1);
+ this->WriteString("<ImportGroup Label=\"PropertySheets\">\n", 1);
+ this->WriteString("<Import Project=\"" VS10_USER_PROPS "\""
+ " Condition=\"exists('" VS10_USER_PROPS "')\""
+ " Label=\"LocalAppDataPlatform\" />\n",
+ 2);
+ this->WritePlatformExtensions();
+ this->WriteString("</ImportGroup>\n", 1);
+ this->WriteString("<PropertyGroup Label=\"UserMacros\" />\n", 1);
+ this->WriteWinRTPackageCertificateKeyFile();
+ this->WritePathAndIncrementalLinkOptions();
+ this->WriteItemDefinitionGroups();
+ this->WriteCustomCommands();
+ this->WriteAllSources();
+ this->WriteDotNetReferences();
+ this->WriteEmbeddedResourceGroup();
+ this->WriteXamlFilesGroup();
+ this->WriteWinRTReferences();
+ this->WriteProjectReferences();
+ this->WriteSDKReferences();
+ this->WriteString(
+ "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\""
+ " />\n",
+ 1);
+ this->WriteTargetSpecificReferences();
+ this->WriteString("<ImportGroup Label=\"ExtensionTargets\">\n", 1);
+ if (this->GlobalGenerator->IsMasmEnabled()) {
+ this->WriteString("<Import Project=\"$(VCTargetsPath)\\"
+ "BuildCustomizations\\masm.targets\" />\n",
+ 2);
+ }
+ this->WriteString("</ImportGroup>\n", 1);
+ this->WriteString("</Project>", 0);
+ // The groups are stored in a separate file for VS 10
+ this->WriteGroups();
+}
+
+void cmVisualStudio10TargetGenerator::WriteDotNetReferences()
+{
+ std::vector<std::string> references;
+ if (const char* vsDotNetReferences =
+ this->GeneratorTarget->GetProperty("VS_DOTNET_REFERENCES")) {
+ cmSystemTools::ExpandListArgument(vsDotNetReferences, references);
+ }
+ if (!references.empty()) {
+ this->WriteString("<ItemGroup>\n", 1);
+ for (std::vector<std::string>::iterator ri = references.begin();
+ ri != references.end(); ++ri) {
+ this->WriteString("<Reference Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(*ri) << "\">\n";
+ this->WriteString("<CopyLocalSatelliteAssemblies>true"
+ "</CopyLocalSatelliteAssemblies>\n",
+ 3);
+ this->WriteString("<ReferenceOutputAssembly>true"
+ "</ReferenceOutputAssembly>\n",
+ 3);
+ this->WriteString("</Reference>\n", 2);
+ }
+ this->WriteString("</ItemGroup>\n", 1);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup()
+{
+ std::vector<cmSourceFile const*> resxObjs;
+ this->GeneratorTarget->GetResxSources(resxObjs, "");
+ if (!resxObjs.empty()) {
+ this->WriteString("<ItemGroup>\n", 1);
+ for (std::vector<cmSourceFile const*>::const_iterator oi =
+ resxObjs.begin();
+ oi != resxObjs.end(); ++oi) {
+ std::string obj = (*oi)->GetFullPath();
+ this->WriteString("<EmbeddedResource Include=\"", 2);
+ this->ConvertToWindowsSlash(obj);
+ (*this->BuildFileStream) << obj << "\">\n";
+
+ this->WriteString("<DependentUpon>", 3);
+ std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h";
+ (*this->BuildFileStream) << hFileName << "</DependentUpon>\n";
+
+ for (std::vector<std::string>::const_iterator i =
+ this->Configurations.begin();
+ i != this->Configurations.end(); ++i) {
+ this->WritePlatformConfigTag("LogicalName", i->c_str(), 3);
+ if (this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE")) {
+ (*this->BuildFileStream) << "$(RootNamespace).";
+ }
+ (*this->BuildFileStream) << "%(Filename)";
+ (*this->BuildFileStream) << ".resources";
+ (*this->BuildFileStream) << "</LogicalName>\n";
+ }
+
+ this->WriteString("</EmbeddedResource>\n", 2);
+ }
+ this->WriteString("</ItemGroup>\n", 1);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup()
+{
+ std::vector<cmSourceFile const*> xamlObjs;
+ this->GeneratorTarget->GetXamlSources(xamlObjs, "");
+ if (!xamlObjs.empty()) {
+ this->WriteString("<ItemGroup>\n", 1);
+ for (std::vector<cmSourceFile const*>::const_iterator oi =
+ xamlObjs.begin();
+ oi != xamlObjs.end(); ++oi) {
+ std::string obj = (*oi)->GetFullPath();
+ std::string xamlType;
+ const char* xamlTypeProperty = (*oi)->GetProperty("VS_XAML_TYPE");
+ if (xamlTypeProperty) {
+ xamlType = xamlTypeProperty;
+ } else {
+ xamlType = "Page";
+ }
+
+ this->WriteSource(xamlType, *oi, ">\n");
+ this->WriteString("<SubType>Designer</SubType>\n", 3);
+ this->WriteString("</", 2);
+ (*this->BuildFileStream) << xamlType << ">\n";
+ }
+ this->WriteString("</ItemGroup>\n", 1);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteTargetSpecificReferences()
+{
+ if (this->MSTools) {
+ if (this->GlobalGenerator->TargetsWindowsPhone() &&
+ this->GlobalGenerator->GetSystemVersion() == "8.0") {
+ this->WriteString("<Import Project=\""
+ "$(MSBuildExtensionsPath)\\Microsoft\\WindowsPhone\\v"
+ "$(TargetPlatformVersion)\\Microsoft.Cpp.WindowsPhone."
+ "$(TargetPlatformVersion).targets\" />\n",
+ 1);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteWinRTReferences()
+{
+ std::vector<std::string> references;
+ if (const char* vsWinRTReferences =
+ this->GeneratorTarget->GetProperty("VS_WINRT_REFERENCES")) {
+ cmSystemTools::ExpandListArgument(vsWinRTReferences, references);
+ }
+
+ if (this->GlobalGenerator->TargetsWindowsPhone() &&
+ this->GlobalGenerator->GetSystemVersion() == "8.0" &&
+ references.empty()) {
+ references.push_back("platform.winmd");
+ }
+ if (!references.empty()) {
+ this->WriteString("<ItemGroup>\n", 1);
+ for (std::vector<std::string>::iterator ri = references.begin();
+ ri != references.end(); ++ri) {
+ this->WriteString("<Reference Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(*ri) << "\">\n";
+ this->WriteString("<IsWinMDFile>true</IsWinMDFile>\n", 3);
+ this->WriteString("</Reference>\n", 2);
+ }
+ this->WriteString("</ItemGroup>\n", 1);
+ }
+}
+
+// ConfigurationType Application, Utility StaticLibrary DynamicLibrary
+
+void cmVisualStudio10TargetGenerator::WriteProjectConfigurations()
+{
+ this->WriteString("<ItemGroup Label=\"ProjectConfigurations\">\n", 1);
+ for (std::vector<std::string>::const_iterator i =
+ this->Configurations.begin();
+ i != this->Configurations.end(); ++i) {
+ this->WriteString("<ProjectConfiguration Include=\"", 2);
+ (*this->BuildFileStream) << *i << "|" << this->Platform << "\">\n";
+ this->WriteString("<Configuration>", 3);
+ (*this->BuildFileStream) << *i << "</Configuration>\n";
+ this->WriteString("<Platform>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(this->Platform)
+ << "</Platform>\n";
+ this->WriteString("</ProjectConfiguration>\n", 2);
+ }
+ this->WriteString("</ItemGroup>\n", 1);
+}
+
+void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
+{
+ for (std::vector<std::string>::const_iterator i =
+ this->Configurations.begin();
+ i != this->Configurations.end(); ++i) {
+ this->WritePlatformConfigTag("PropertyGroup", i->c_str(), 1,
+ " Label=\"Configuration\"", "\n");
+ std::string configType = "<ConfigurationType>";
+ if (const char* vsConfigurationType =
+ this->GeneratorTarget->GetProperty("VS_CONFIGURATION_TYPE")) {
+ configType += cmVS10EscapeXML(vsConfigurationType);
+ } else {
+ switch (this->GeneratorTarget->GetType()) {
+ case cmState::SHARED_LIBRARY:
+ case cmState::MODULE_LIBRARY:
+ configType += "DynamicLibrary";
+ break;
+ case cmState::OBJECT_LIBRARY:
+ case cmState::STATIC_LIBRARY:
+ configType += "StaticLibrary";
+ break;
+ case cmState::EXECUTABLE:
+ if (this->NsightTegra &&
+ !this->GeneratorTarget->GetPropertyAsBool("ANDROID_GUI")) {
+ // Android executables are .so too.
+ configType += "DynamicLibrary";
+ } else {
+ configType += "Application";
+ }
+ break;
+ case cmState::UTILITY:
+ case cmState::GLOBAL_TARGET:
+ if (this->NsightTegra) {
+ // Tegra-Android platform does not understand "Utility".
+ configType += "StaticLibrary";
+ } else {
+ configType += "Utility";
+ }
+ break;
+ case cmState::UNKNOWN_LIBRARY:
+ case cmState::INTERFACE_LIBRARY:
+ break;
+ }
+ }
+ configType += "</ConfigurationType>\n";
+ this->WriteString(configType.c_str(), 2);
+
+ if (this->MSTools) {
+ this->WriteMSToolConfigurationValues(*i);
+ } else if (this->NsightTegra) {
+ this->WriteNsightTegraConfigurationValues(*i);
+ }
+
+ this->WriteString("</PropertyGroup>\n", 1);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues(
+ std::string const& config)
+{
+ cmGlobalVisualStudio10Generator* gg =
+ static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+ const char* mfcFlag =
+ this->GeneratorTarget->Target->GetMakefile()->GetDefinition(
+ "CMAKE_MFC_FLAG");
+ std::string mfcFlagValue = mfcFlag ? mfcFlag : "0";
+
+ std::string useOfMfcValue = "false";
+ if (this->GeneratorTarget->GetType() <= cmState::OBJECT_LIBRARY) {
+ if (mfcFlagValue == "1") {
+ useOfMfcValue = "Static";
+ } else if (mfcFlagValue == "2") {
+ useOfMfcValue = "Dynamic";
+ }
+ }
+ std::string mfcLine = "<UseOfMfc>";
+ mfcLine += useOfMfcValue + "</UseOfMfc>\n";
+ this->WriteString(mfcLine.c_str(), 2);
+
+ if ((this->GeneratorTarget->GetType() <= cmState::OBJECT_LIBRARY &&
+ this->ClOptions[config]->UsingUnicode()) ||
+ this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT") ||
+ this->GlobalGenerator->TargetsWindowsPhone() ||
+ this->GlobalGenerator->TargetsWindowsStore() ||
+ this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) {
+ this->WriteString("<CharacterSet>Unicode</CharacterSet>\n", 2);
+ } else if (this->GeneratorTarget->GetType() <= cmState::MODULE_LIBRARY &&
+ this->ClOptions[config]->UsingSBCS()) {
+ this->WriteString("<CharacterSet>NotSet</CharacterSet>\n", 2);
+ } else {
+ this->WriteString("<CharacterSet>MultiByte</CharacterSet>\n", 2);
+ }
+ if (const char* toolset = gg->GetPlatformToolset()) {
+ std::string pts = "<PlatformToolset>";
+ pts += toolset;
+ pts += "</PlatformToolset>\n";
+ this->WriteString(pts.c_str(), 2);
+ }
+ if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT") ||
+ this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) {
+ this->WriteString("<WindowsAppContainer>true"
+ "</WindowsAppContainer>\n",
+ 2);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues(
+ std::string const&)
+{
+ cmGlobalVisualStudio10Generator* gg =
+ static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+ const char* toolset = gg->GetPlatformToolset();
+ std::string ntv = "<NdkToolchainVersion>";
+ ntv += toolset ? toolset : "Default";
+ ntv += "</NdkToolchainVersion>\n";
+ this->WriteString(ntv.c_str(), 2);
+ if (const char* minApi =
+ this->GeneratorTarget->GetProperty("ANDROID_API_MIN")) {
+ this->WriteString("<AndroidMinAPI>", 2);
+ (*this->BuildFileStream) << "android-" << cmVS10EscapeXML(minApi)
+ << "</AndroidMinAPI>\n";
+ }
+ if (const char* api = this->GeneratorTarget->GetProperty("ANDROID_API")) {
+ this->WriteString("<AndroidTargetAPI>", 2);
+ (*this->BuildFileStream) << "android-" << cmVS10EscapeXML(api)
+ << "</AndroidTargetAPI>\n";
+ }
+
+ if (const char* cpuArch =
+ this->GeneratorTarget->GetProperty("ANDROID_ARCH")) {
+ this->WriteString("<AndroidArch>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(cpuArch) << "</AndroidArch>\n";
+ }
+
+ if (const char* stlType =
+ this->GeneratorTarget->GetProperty("ANDROID_STL_TYPE")) {
+ this->WriteString("<AndroidStlType>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(stlType)
+ << "</AndroidStlType>\n";
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteCustomCommands()
+{
+ this->SourcesVisited.clear();
+ std::vector<cmSourceFile const*> customCommands;
+ this->GeneratorTarget->GetCustomCommands(customCommands, "");
+ for (std::vector<cmSourceFile const*>::const_iterator si =
+ customCommands.begin();
+ si != customCommands.end(); ++si) {
+ this->WriteCustomCommand(*si);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteCustomCommand(
+ cmSourceFile const* sf)
+{
+ if (this->SourcesVisited.insert(sf).second) {
+ if (std::vector<cmSourceFile*> const* depends =
+ this->GeneratorTarget->GetSourceDepends(sf)) {
+ for (std::vector<cmSourceFile*>::const_iterator di = depends->begin();
+ di != depends->end(); ++di) {
+ this->WriteCustomCommand(*di);
+ }
+ }
+ if (cmCustomCommand const* command = sf->GetCustomCommand()) {
+ this->WriteString("<ItemGroup>\n", 1);
+ this->WriteCustomRule(sf, *command);
+ this->WriteString("</ItemGroup>\n", 1);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteCustomRule(
+ cmSourceFile const* source, cmCustomCommand const& command)
+{
+ std::string sourcePath = source->GetFullPath();
+ // VS 10 will always rebuild a custom command attached to a .rule
+ // file that doesn't exist so create the file explicitly.
+ if (source->GetPropertyAsBool("__CMAKE_RULE")) {
+ if (!cmSystemTools::FileExists(sourcePath.c_str())) {
+ // Make sure the path exists for the file
+ std::string path = cmSystemTools::GetFilenamePath(sourcePath);
+ cmSystemTools::MakeDirectory(path.c_str());
+ cmsys::ofstream fout(sourcePath.c_str());
+ if (fout) {
+ fout << "# generated from CMake\n";
+ fout.flush();
+ fout.close();
+ // Force given file to have a very old timestamp, thus
+ // preventing dependent rebuilds.
+ this->ForceOld(sourcePath);
+ } else {
+ std::string error = "Could not create file: [";
+ error += sourcePath;
+ error += "] ";
+ cmSystemTools::Error(error.c_str(),
+ cmSystemTools::GetLastSystemError().c_str());
+ }
+ }
+ }
+ cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
+
+ this->WriteSource("CustomBuild", source, ">\n");
+
+ for (std::vector<std::string>::const_iterator i =
+ this->Configurations.begin();
+ i != this->Configurations.end(); ++i) {
+ cmCustomCommandGenerator ccg(command, *i, this->LocalGenerator);
+ std::string comment = lg->ConstructComment(ccg);
+ comment = cmVS10EscapeComment(comment);
+ std::string script = cmVS10EscapeXML(lg->ConstructScript(ccg));
+ this->WritePlatformConfigTag("Message", i->c_str(), 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(comment) << "</Message>\n";
+ this->WritePlatformConfigTag("Command", i->c_str(), 3);
+ (*this->BuildFileStream) << script << "</Command>\n";
+ this->WritePlatformConfigTag("AdditionalInputs", i->c_str(), 3);
+
+ (*this->BuildFileStream) << cmVS10EscapeXML(source->GetFullPath());
+ for (std::vector<std::string>::const_iterator d = ccg.GetDepends().begin();
+ d != ccg.GetDepends().end(); ++d) {
+ std::string dep;
+ if (this->LocalGenerator->GetRealDependency(d->c_str(), i->c_str(),
+ dep)) {
+ this->ConvertToWindowsSlash(dep);
+ (*this->BuildFileStream) << ";" << cmVS10EscapeXML(dep);
+ }
+ }
+ (*this->BuildFileStream) << ";%(AdditionalInputs)</AdditionalInputs>\n";
+ this->WritePlatformConfigTag("Outputs", i->c_str(), 3);
+ const char* sep = "";
+ for (std::vector<std::string>::const_iterator o = ccg.GetOutputs().begin();
+ o != ccg.GetOutputs().end(); ++o) {
+ std::string out = *o;
+ this->ConvertToWindowsSlash(out);
+ (*this->BuildFileStream) << sep << cmVS10EscapeXML(out);
+ sep = ";";
+ }
+ (*this->BuildFileStream) << "</Outputs>\n";
+ if (this->LocalGenerator->GetVersion() >
+ cmGlobalVisualStudioGenerator::VS10) {
+ // VS >= 11 let us turn off linking of custom command outputs.
+ this->WritePlatformConfigTag("LinkObjects", i->c_str(), 3);
+ (*this->BuildFileStream) << "false</LinkObjects>\n";
+ }
+ }
+ this->WriteString("</CustomBuild>\n", 2);
+}
+
+std::string cmVisualStudio10TargetGenerator::ConvertPath(
+ std::string const& path, bool forceRelative)
+{
+ return forceRelative
+ ? cmSystemTools::RelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), path.c_str())
+ : path.c_str();
+}
+
+void cmVisualStudio10TargetGenerator::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++;
+ }
+}
+void cmVisualStudio10TargetGenerator::WriteGroups()
+{
+ // collect up group information
+ std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
+ std::vector<cmSourceFile*> classes;
+ if (!this->GeneratorTarget->GetConfigCommonSourceFiles(classes)) {
+ return;
+ }
+
+ std::set<cmSourceGroup*> groupsUsed;
+ for (std::vector<cmSourceFile*>::const_iterator s = classes.begin();
+ s != classes.end(); s++) {
+ cmSourceFile* sf = *s;
+ std::string const& source = sf->GetFullPath();
+ cmSourceGroup* sourceGroup =
+ this->Makefile->FindSourceGroup(source.c_str(), sourceGroups);
+ groupsUsed.insert(sourceGroup);
+ }
+
+ this->AddMissingSourceGroups(groupsUsed, sourceGroups);
+
+ // Write out group file
+ std::string path = this->LocalGenerator->GetCurrentBinaryDirectory();
+ path += "/";
+ path += this->Name;
+ path += ".vcxproj.filters";
+ cmGeneratedFileStream fout(path.c_str());
+ fout.SetCopyIfDifferent(true);
+ char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
+ fout.write(magic, 3);
+ cmGeneratedFileStream* save = this->BuildFileStream;
+ this->BuildFileStream = &fout;
+
+ // get the tools version to use
+ const std::string toolsVer(this->GlobalGenerator->GetToolsVersion());
+ std::string project_defaults = "<?xml version=\"1.0\" encoding=\"" +
+ this->GlobalGenerator->Encoding() + "\"?>\n";
+ project_defaults.append("<Project ToolsVersion=\"");
+ project_defaults.append(toolsVer + "\" ");
+ project_defaults.append(
+ "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n");
+ this->WriteString(project_defaults.c_str(), 0);
+
+ for (ToolSourceMap::const_iterator ti = this->Tools.begin();
+ ti != this->Tools.end(); ++ti) {
+ this->WriteGroupSources(ti->first.c_str(), ti->second, sourceGroups);
+ }
+
+ // Added files are images and the manifest.
+ if (!this->AddedFiles.empty()) {
+ this->WriteString("<ItemGroup>\n", 1);
+ for (std::vector<std::string>::const_iterator oi =
+ this->AddedFiles.begin();
+ oi != this->AddedFiles.end(); ++oi) {
+ std::string fileName =
+ cmSystemTools::LowerCase(cmSystemTools::GetFilenameName(*oi));
+ if (fileName == "wmappmanifest.xml") {
+ this->WriteString("<XML Include=\"", 2);
+ (*this->BuildFileStream) << *oi << "\">\n";
+ this->WriteString("<Filter>Resource Files</Filter>\n", 3);
+ this->WriteString("</XML>\n", 2);
+ } else if (cmSystemTools::GetFilenameExtension(fileName) ==
+ ".appxmanifest") {
+ this->WriteString("<AppxManifest Include=\"", 2);
+ (*this->BuildFileStream) << *oi << "\">\n";
+ this->WriteString("<Filter>Resource Files</Filter>\n", 3);
+ this->WriteString("</AppxManifest>\n", 2);
+ } else if (cmSystemTools::GetFilenameExtension(fileName) == ".pfx") {
+ this->WriteString("<None Include=\"", 2);
+ (*this->BuildFileStream) << *oi << "\">\n";
+ this->WriteString("<Filter>Resource Files</Filter>\n", 3);
+ this->WriteString("</None>\n", 2);
+ } else {
+ this->WriteString("<Image Include=\"", 2);
+ (*this->BuildFileStream) << *oi << "\">\n";
+ this->WriteString("<Filter>Resource Files</Filter>\n", 3);
+ this->WriteString("</Image>\n", 2);
+ }
+ }
+ this->WriteString("</ItemGroup>\n", 1);
+ }
+
+ std::vector<cmSourceFile const*> resxObjs;
+ this->GeneratorTarget->GetResxSources(resxObjs, "");
+ if (!resxObjs.empty()) {
+ this->WriteString("<ItemGroup>\n", 1);
+ for (std::vector<cmSourceFile const*>::const_iterator oi =
+ resxObjs.begin();
+ oi != resxObjs.end(); ++oi) {
+ std::string obj = (*oi)->GetFullPath();
+ this->WriteString("<EmbeddedResource Include=\"", 2);
+ this->ConvertToWindowsSlash(obj);
+ (*this->BuildFileStream) << cmVS10EscapeXML(obj) << "\">\n";
+ this->WriteString("<Filter>Resource Files</Filter>\n", 3);
+ this->WriteString("</EmbeddedResource>\n", 2);
+ }
+ this->WriteString("</ItemGroup>\n", 1);
+ }
+
+ // Add object library contents as external objects.
+ std::vector<std::string> objs;
+ this->GeneratorTarget->UseObjectLibraries(objs, "");
+ if (!objs.empty()) {
+ this->WriteString("<ItemGroup>\n", 1);
+ for (std::vector<std::string>::const_iterator oi = objs.begin();
+ oi != objs.end(); ++oi) {
+ std::string obj = *oi;
+ this->WriteString("<Object Include=\"", 2);
+ this->ConvertToWindowsSlash(obj);
+ (*this->BuildFileStream) << cmVS10EscapeXML(obj) << "\">\n";
+ this->WriteString("<Filter>Object Libraries</Filter>\n", 3);
+ this->WriteString("</Object>\n", 2);
+ }
+ this->WriteString("</ItemGroup>\n", 1);
+ }
+
+ this->WriteString("<ItemGroup>\n", 1);
+ for (std::set<cmSourceGroup*>::iterator g = groupsUsed.begin();
+ g != groupsUsed.end(); ++g) {
+ cmSourceGroup* sg = *g;
+ const char* name = sg->GetFullName();
+ if (strlen(name) != 0) {
+ this->WriteString("<Filter Include=\"", 2);
+ (*this->BuildFileStream) << name << "\">\n";
+ std::string guidName = "SG_Filter_";
+ guidName += name;
+ this->WriteString("<UniqueIdentifier>", 3);
+ std::string guid = this->GlobalGenerator->GetGUID(guidName.c_str());
+ (*this->BuildFileStream) << "{" << guid << "}"
+ << "</UniqueIdentifier>\n";
+ this->WriteString("</Filter>\n", 2);
+ }
+ }
+ if (!objs.empty()) {
+ this->WriteString("<Filter Include=\"Object Libraries\">\n", 2);
+ std::string guidName = "SG_Filter_Object Libraries";
+ this->WriteString("<UniqueIdentifier>", 3);
+ std::string guid = this->GlobalGenerator->GetGUID(guidName.c_str());
+ (*this->BuildFileStream) << "{" << guid << "}"
+ << "</UniqueIdentifier>\n";
+ this->WriteString("</Filter>\n", 2);
+ }
+
+ if (!resxObjs.empty() || !this->AddedFiles.empty()) {
+ this->WriteString("<Filter Include=\"Resource Files\">\n", 2);
+ std::string guidName = "SG_Filter_Resource Files";
+ this->WriteString("<UniqueIdentifier>", 3);
+ std::string guid = this->GlobalGenerator->GetGUID(guidName.c_str());
+ (*this->BuildFileStream) << "{" << guid << "}"
+ << "</UniqueIdentifier>\n";
+ this->WriteString("<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;", 3);
+ (*this->BuildFileStream) << "gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;";
+ (*this->BuildFileStream) << "mfcribbon-ms</Extensions>\n";
+ this->WriteString("</Filter>\n", 2);
+ }
+
+ this->WriteString("</ItemGroup>\n", 1);
+ this->WriteString("</Project>\n", 0);
+ // restore stream pointer
+ this->BuildFileStream = save;
+
+ if (fout.Close()) {
+ this->GlobalGenerator->FileReplacedDuringGenerate(path);
+ }
+}
+
+// Add to groupsUsed empty source groups that have non-empty children.
+void cmVisualStudio10TargetGenerator::AddMissingSourceGroups(
+ std::set<cmSourceGroup*>& groupsUsed,
+ const std::vector<cmSourceGroup>& allGroups)
+{
+ for (std::vector<cmSourceGroup>::const_iterator current = allGroups.begin();
+ current != allGroups.end(); ++current) {
+ std::vector<cmSourceGroup> const& children = current->GetGroupChildren();
+ if (children.empty()) {
+ continue; // the group is really empty
+ }
+
+ this->AddMissingSourceGroups(groupsUsed, children);
+
+ cmSourceGroup* current_ptr = const_cast<cmSourceGroup*>(&(*current));
+ if (groupsUsed.find(current_ptr) != groupsUsed.end()) {
+ 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();
+ while (child_it != children.end()) {
+ cmSourceGroup* child_ptr = const_cast<cmSourceGroup*>(&(*child_it));
+ if (groupsUsed.find(child_ptr) != groupsUsed.end()) {
+ break; // found a child that was already added => add current group too
+ }
+ child_it++;
+ }
+
+ if (child_it == children.end()) {
+ continue; // no descendants have source files => ignore this group
+ }
+
+ groupsUsed.insert(current_ptr);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteGroupSources(
+ const char* name, ToolSources const& sources,
+ std::vector<cmSourceGroup>& sourceGroups)
+{
+ this->WriteString("<ItemGroup>\n", 1);
+ for (ToolSources::const_iterator s = sources.begin(); s != sources.end();
+ ++s) {
+ cmSourceFile const* sf = s->SourceFile;
+ std::string const& source = sf->GetFullPath();
+ cmSourceGroup* sourceGroup =
+ this->Makefile->FindSourceGroup(source.c_str(), sourceGroups);
+ const char* filter = sourceGroup->GetFullName();
+ this->WriteString("<", 2);
+ std::string path = this->ConvertPath(source, s->RelativePath);
+ this->ConvertToWindowsSlash(path);
+ (*this->BuildFileStream) << name << " Include=\"" << cmVS10EscapeXML(path);
+ if (strlen(filter)) {
+ (*this->BuildFileStream) << "\">\n";
+ this->WriteString("<Filter>", 3);
+ (*this->BuildFileStream) << filter << "</Filter>\n";
+ this->WriteString("</", 2);
+ (*this->BuildFileStream) << name << ">\n";
+ } else {
+ (*this->BuildFileStream) << "\" />\n";
+ }
+ }
+ this->WriteString("</ItemGroup>\n", 1);
+}
+
+void cmVisualStudio10TargetGenerator::WriteHeaderSource(cmSourceFile const* sf)
+{
+ std::string const& fileName = sf->GetFullPath();
+ if (this->IsResxHeader(fileName)) {
+ this->WriteSource("ClInclude", sf, ">\n");
+ this->WriteString("<FileType>CppForm</FileType>\n", 3);
+ this->WriteString("</ClInclude>\n", 2);
+ } else if (this->IsXamlHeader(fileName)) {
+ this->WriteSource("ClInclude", sf, ">\n");
+ this->WriteString("<DependentUpon>", 3);
+ std::string xamlFileName = fileName.substr(0, fileName.find_last_of("."));
+ (*this->BuildFileStream) << xamlFileName << "</DependentUpon>\n";
+ this->WriteString("</ClInclude>\n", 2);
+ } else {
+ this->WriteSource("ClInclude", sf);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf)
+{
+ bool toolHasSettings = false;
+ std::string tool = "None";
+ std::string shaderType;
+ std::string shaderEntryPoint;
+ std::string shaderModel;
+ std::string shaderAdditionalFlags;
+ std::string ext = cmSystemTools::LowerCase(sf->GetExtension());
+ if (ext == "hlsl") {
+ tool = "FXCompile";
+ // Figure out the type of shader compiler to use.
+ if (const char* st = sf->GetProperty("VS_SHADER_TYPE")) {
+ shaderType = st;
+ toolHasSettings = true;
+ }
+ // Figure out which entry point to use if any
+ if (const char* se = sf->GetProperty("VS_SHADER_ENTRYPOINT")) {
+ shaderEntryPoint = se;
+ toolHasSettings = true;
+ }
+ // Figure out which shader model to use if any
+ if (const char* sm = sf->GetProperty("VS_SHADER_MODEL")) {
+ shaderModel = sm;
+ toolHasSettings = true;
+ }
+ // Figure out if there's any additional flags to use
+ if (const char* saf = sf->GetProperty("VS_SHADER_FLAGS")) {
+ shaderAdditionalFlags = saf;
+ toolHasSettings = true;
+ }
+ } else if (ext == "jpg" || ext == "png") {
+ tool = "Image";
+ } else if (ext == "resw") {
+ tool = "PRIResource";
+ } else if (ext == "xml") {
+ tool = "XML";
+ }
+
+ if (this->NsightTegra) {
+ // Nsight Tegra needs specific file types to check up-to-dateness.
+ std::string name = cmSystemTools::LowerCase(sf->GetLocation().GetName());
+ if (name == "androidmanifest.xml" || name == "build.xml" ||
+ name == "proguard.cfg" || name == "proguard-project.txt" ||
+ ext == "properties") {
+ tool = "AndroidBuild";
+ } else if (ext == "java") {
+ tool = "JCompile";
+ } else if (ext == "asm" || ext == "s") {
+ tool = "ClCompile";
+ }
+ }
+
+ const char* toolOverride = sf->GetProperty("VS_TOOL_OVERRIDE");
+ if (toolOverride && *toolOverride) {
+ tool = toolOverride;
+ }
+
+ std::string deployContent;
+ std::string deployLocation;
+ if (this->GlobalGenerator->TargetsWindowsPhone() ||
+ this->GlobalGenerator->TargetsWindowsStore()) {
+ const char* content = sf->GetProperty("VS_DEPLOYMENT_CONTENT");
+ if (content && *content) {
+ toolHasSettings = true;
+ deployContent = content;
+
+ const char* location = sf->GetProperty("VS_DEPLOYMENT_LOCATION");
+ if (location && *location) {
+ deployLocation = location;
+ }
+ }
+ }
+
+ if (toolHasSettings) {
+ this->WriteSource(tool, sf, ">\n");
+
+ if (!deployContent.empty()) {
+ cmGeneratorExpression ge;
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(deployContent);
+ // Deployment location cannot be set on a configuration basis
+ if (!deployLocation.empty()) {
+ this->WriteString("<Link>", 3);
+ (*this->BuildFileStream) << deployLocation
+ << "\\%(FileName)%(Extension)";
+ this->WriteString("</Link>\n", 0);
+ }
+ for (size_t i = 0; i != this->Configurations.size(); ++i) {
+ if (0 == strcmp(cge->Evaluate(this->LocalGenerator,
+ this->Configurations[i]),
+ "1")) {
+ this->WriteString("<DeploymentContent Condition=\""
+ "'$(Configuration)|$(Platform)'=='",
+ 3);
+ (*this->BuildFileStream) << this->Configurations[i] << "|"
+ << this->Platform << "'\">true";
+ this->WriteString("</DeploymentContent>\n", 0);
+ } else {
+ this->WriteString("<ExcludedFromBuild Condition=\""
+ "'$(Configuration)|$(Platform)'=='",
+ 3);
+ (*this->BuildFileStream) << this->Configurations[i] << "|"
+ << this->Platform << "'\">true";
+ this->WriteString("</ExcludedFromBuild>\n", 0);
+ }
+ }
+ }
+ if (!shaderType.empty()) {
+ this->WriteString("<ShaderType>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(shaderType)
+ << "</ShaderType>\n";
+ }
+ if (!shaderEntryPoint.empty()) {
+ this->WriteString("<EntryPointName>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(shaderEntryPoint)
+ << "</EntryPointName>\n";
+ }
+ if (!shaderModel.empty()) {
+ this->WriteString("<ShaderModel>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(shaderModel)
+ << "</ShaderModel>\n";
+ }
+ if (!shaderAdditionalFlags.empty()) {
+ this->WriteString("<AdditionalOptions>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(shaderAdditionalFlags)
+ << "</AdditionalOptions>\n";
+ }
+ this->WriteString("</", 2);
+ (*this->BuildFileStream) << tool << ">\n";
+ } else {
+ this->WriteSource(tool, sf);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteSource(std::string const& tool,
+ cmSourceFile const* sf,
+ const char* end)
+{
+ // Visual Studio tools append relative paths to the current dir, as in:
+ //
+ // c:\path\to\current\dir\..\..\..\relative\path\to\source.c
+ //
+ // and fail if this exceeds the maximum allowed path length. Our path
+ // conversion uses full paths when possible to allow deeper trees.
+ bool forceRelative = false;
+ std::string sourceFile = this->ConvertPath(sf->GetFullPath(), false);
+ if (this->LocalGenerator->GetVersion() ==
+ cmGlobalVisualStudioGenerator::VS10 &&
+ cmSystemTools::FileIsFullPath(sourceFile.c_str())) {
+ // Normal path conversion resulted in a full path. VS 10 (but not 11)
+ // refuses to show the property page in the IDE for a source file with a
+ // full path (not starting in a '.' or '/' AFAICT). CMake <= 2.8.4 used a
+ // relative path but to allow deeper build trees CMake 2.8.[5678] used a
+ // full path except for custom commands. Custom commands do not work
+ // without a relative path, but they do not seem to be involved in tools
+ // with the above behavior. For other sources we now use a relative path
+ // when the combined path will not be too long so property pages appear.
+ std::string sourceRel = this->ConvertPath(sf->GetFullPath(), true);
+ size_t const maxLen = 250;
+ if (sf->GetCustomCommand() ||
+ ((strlen(this->LocalGenerator->GetCurrentBinaryDirectory()) + 1 +
+ sourceRel.length()) <= maxLen)) {
+ forceRelative = true;
+ sourceFile = sourceRel;
+ } else {
+ this->GlobalGenerator->PathTooLong(this->GeneratorTarget, sf, sourceRel);
+ }
+ }
+ this->ConvertToWindowsSlash(sourceFile);
+ this->WriteString("<", 2);
+ (*this->BuildFileStream) << tool << " Include=\""
+ << cmVS10EscapeXML(sourceFile) << "\""
+ << (end ? end : " />\n");
+
+ ToolSource toolSource = { sf, forceRelative };
+ this->Tools[tool].push_back(toolSource);
+}
+
+void cmVisualStudio10TargetGenerator::WriteSources(
+ std::string const& tool, std::vector<cmSourceFile const*> const& sources)
+{
+ for (std::vector<cmSourceFile const*>::const_iterator si = sources.begin();
+ si != sources.end(); ++si) {
+ this->WriteSource(tool, *si);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteAllSources()
+{
+ if (this->GeneratorTarget->GetType() > cmState::UTILITY) {
+ return;
+ }
+ this->WriteString("<ItemGroup>\n", 1);
+
+ std::vector<cmSourceFile const*> headerSources;
+ this->GeneratorTarget->GetHeaderSources(headerSources, "");
+ for (std::vector<cmSourceFile const*>::const_iterator si =
+ headerSources.begin();
+ si != headerSources.end(); ++si) {
+ this->WriteHeaderSource(*si);
+ }
+ std::vector<cmSourceFile const*> idlSources;
+ this->GeneratorTarget->GetIDLSources(idlSources, "");
+ this->WriteSources("Midl", idlSources);
+
+ std::vector<cmSourceFile const*> objectSources;
+ this->GeneratorTarget->GetObjectSources(objectSources, "");
+ for (std::vector<cmSourceFile const*>::const_iterator si =
+ objectSources.begin();
+ si != objectSources.end(); ++si) {
+ const std::string& lang = (*si)->GetLanguage();
+ std::string tool;
+ if (lang == "C" || lang == "CXX") {
+ tool = "ClCompile";
+ } else if (lang == "ASM_MASM" && this->GlobalGenerator->IsMasmEnabled()) {
+ tool = "MASM";
+ } else if (lang == "RC") {
+ tool = "ResourceCompile";
+ }
+
+ if (!tool.empty()) {
+ this->WriteSource(tool, *si, " ");
+ if (this->OutputSourceSpecificFlags(*si)) {
+ this->WriteString("</", 2);
+ (*this->BuildFileStream) << tool << ">\n";
+ } else {
+ (*this->BuildFileStream) << " />\n";
+ }
+ } else {
+ this->WriteSource("None", *si);
+ }
+ }
+
+ std::vector<cmSourceFile const*> manifestSources;
+ this->GeneratorTarget->GetAppManifest(manifestSources, "");
+ this->WriteSources("AppxManifest", manifestSources);
+
+ std::vector<cmSourceFile const*> certificateSources;
+ this->GeneratorTarget->GetCertificates(certificateSources, "");
+ this->WriteSources("None", certificateSources);
+
+ std::vector<cmSourceFile const*> externalObjects;
+ this->GeneratorTarget->GetExternalObjects(externalObjects, "");
+ for (std::vector<cmSourceFile const*>::iterator si = externalObjects.begin();
+ si != externalObjects.end();) {
+ if (!(*si)->GetObjectLibrary().empty()) {
+ si = externalObjects.erase(si);
+ } else {
+ ++si;
+ }
+ }
+ if (this->LocalGenerator->GetVersion() >
+ cmGlobalVisualStudioGenerator::VS10) {
+ // For VS >= 11 we use LinkObjects to avoid linking custom command
+ // outputs. Use Object for all external objects, generated or not.
+ this->WriteSources("Object", externalObjects);
+ } else {
+ // If an object file is generated in this target, then vs10 will use
+ // it in the build, and we have to list it as None instead of Object.
+ for (std::vector<cmSourceFile const*>::const_iterator si =
+ externalObjects.begin();
+ si != externalObjects.end(); ++si) {
+ std::vector<cmSourceFile*> const* d =
+ this->GeneratorTarget->GetSourceDepends(*si);
+ this->WriteSource((d && !d->empty()) ? "None" : "Object", *si);
+ }
+ }
+
+ std::vector<cmSourceFile const*> extraSources;
+ this->GeneratorTarget->GetExtraSources(extraSources, "");
+ for (std::vector<cmSourceFile const*>::const_iterator si =
+ extraSources.begin();
+ si != extraSources.end(); ++si) {
+ this->WriteExtraSource(*si);
+ }
+
+ // Add object library contents as external objects.
+ std::vector<std::string> objs;
+ this->GeneratorTarget->UseObjectLibraries(objs, "");
+ for (std::vector<std::string>::const_iterator oi = objs.begin();
+ oi != objs.end(); ++oi) {
+ std::string obj = *oi;
+ this->WriteString("<Object Include=\"", 2);
+ this->ConvertToWindowsSlash(obj);
+ (*this->BuildFileStream) << cmVS10EscapeXML(obj) << "\" />\n";
+ }
+
+ if (cmSourceFile const* defsrc =
+ this->GeneratorTarget->GetModuleDefinitionFile("")) {
+ this->WriteSource("None", defsrc);
+ }
+
+ if (this->IsMissingFiles) {
+ this->WriteMissingFiles();
+ }
+
+ this->WriteString("</ItemGroup>\n", 1);
+}
+
+bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
+ cmSourceFile const* source)
+{
+ cmSourceFile const& sf = *source;
+
+ std::string objectName;
+ if (this->GeneratorTarget->HasExplicitObjectName(&sf)) {
+ objectName = this->GeneratorTarget->GetObjectName(&sf);
+ }
+ std::string flags;
+ std::string defines;
+ if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) {
+ flags += cflags;
+ }
+ if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) {
+ defines += cdefs;
+ }
+ std::string lang =
+ this->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str());
+ std::string sourceLang = this->LocalGenerator->GetSourceFileLanguage(sf);
+ const std::string& linkLanguage = this->GeneratorTarget->GetLinkerLanguage();
+ bool needForceLang = false;
+ // source file does not match its extension language
+ if (lang != sourceLang) {
+ needForceLang = true;
+ lang = sourceLang;
+ }
+ // if the source file does not match the linker language
+ // then force c or c++
+ const char* compileAs = 0;
+ if (needForceLang || (linkLanguage != lang)) {
+ if (lang == "CXX") {
+ // force a C++ file type
+ compileAs = "CompileAsCpp";
+ } else if (lang == "C") {
+ // force to c
+ compileAs = "CompileAsC";
+ }
+ }
+ bool noWinRT = this->TargetCompileAsWinRT && lang == "C";
+ bool hasFlags = false;
+ // for the first time we need a new line if there is something
+ // produced here.
+ const char* firstString = ">\n";
+ if (!objectName.empty()) {
+ (*this->BuildFileStream) << firstString;
+ firstString = "";
+ hasFlags = true;
+ this->WriteString("<ObjectFileName>", 3);
+ (*this->BuildFileStream) << "$(IntDir)/" << objectName
+ << "</ObjectFileName>\n";
+ }
+ for (std::vector<std::string>::const_iterator config =
+ this->Configurations.begin();
+ config != this->Configurations.end(); ++config) {
+ std::string configUpper = cmSystemTools::UpperCase(*config);
+ std::string configDefines = defines;
+ std::string defPropName = "COMPILE_DEFINITIONS_";
+ defPropName += configUpper;
+ if (const char* ccdefs = sf.GetProperty(defPropName.c_str())) {
+ if (!configDefines.empty()) {
+ configDefines += ";";
+ }
+ configDefines += ccdefs;
+ }
+ // if we have flags or defines for this config then
+ // use them
+ if (!flags.empty() || !configDefines.empty() || compileAs || noWinRT) {
+ (*this->BuildFileStream) << firstString;
+ firstString = ""; // only do firstString once
+ hasFlags = true;
+ cmVisualStudioGeneratorOptions clOptions(
+ this->LocalGenerator, cmVisualStudioGeneratorOptions::Compiler,
+ this->GetClFlagTable(), 0, this);
+ if (compileAs) {
+ clOptions.AddFlag("CompileAs", compileAs);
+ }
+ if (noWinRT) {
+ clOptions.AddFlag("CompileAsWinRT", "false");
+ }
+ clOptions.Parse(flags.c_str());
+ if (clOptions.HasFlag("AdditionalIncludeDirectories")) {
+ clOptions.AppendFlag("AdditionalIncludeDirectories",
+ "%(AdditionalIncludeDirectories)");
+ }
+ if (clOptions.HasFlag("DisableSpecificWarnings")) {
+ clOptions.AppendFlag("DisableSpecificWarnings",
+ "%(DisableSpecificWarnings)");
+ }
+ clOptions.AddDefines(configDefines.c_str());
+ clOptions.SetConfiguration((*config).c_str());
+ clOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
+ clOptions.OutputFlagMap(*this->BuildFileStream, " ");
+ clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
+ "\n", lang);
+ }
+ }
+ if (this->IsXamlSource(source->GetFullPath())) {
+ (*this->BuildFileStream) << firstString;
+ firstString = ""; // only do firstString once
+ hasFlags = true;
+ this->WriteString("<DependentUpon>", 3);
+ const std::string& fileName = source->GetFullPath();
+ std::string xamlFileName = fileName.substr(0, fileName.find_last_of("."));
+ (*this->BuildFileStream) << xamlFileName << "</DependentUpon>\n";
+ }
+
+ return hasFlags;
+}
+
+void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions()
+{
+ cmState::TargetType ttype = this->GeneratorTarget->GetType();
+ if (ttype > cmState::GLOBAL_TARGET) {
+ return;
+ }
+
+ this->WriteString("<PropertyGroup>\n", 2);
+ this->WriteString("<_ProjectFileVersion>10.0.20506.1"
+ "</_ProjectFileVersion>\n",
+ 3);
+ for (std::vector<std::string>::const_iterator config =
+ this->Configurations.begin();
+ config != this->Configurations.end(); ++config) {
+ if (ttype >= cmState::UTILITY) {
+ this->WritePlatformConfigTag("IntDir", config->c_str(), 3);
+ *this->BuildFileStream
+ << "$(Platform)\\$(Configuration)\\$(ProjectName)\\"
+ << "</IntDir>\n";
+ } else {
+ std::string intermediateDir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ intermediateDir += "/";
+ intermediateDir += *config;
+ intermediateDir += "/";
+ std::string outDir;
+ std::string targetNameFull;
+ if (ttype == cmState::OBJECT_LIBRARY) {
+ outDir = intermediateDir;
+ targetNameFull = this->GeneratorTarget->GetName();
+ targetNameFull += ".lib";
+ } else {
+ outDir = this->GeneratorTarget->GetDirectory(config->c_str()) + "/";
+ targetNameFull = this->GeneratorTarget->GetFullName(config->c_str());
+ }
+ this->ConvertToWindowsSlash(intermediateDir);
+ this->ConvertToWindowsSlash(outDir);
+
+ this->WritePlatformConfigTag("OutDir", config->c_str(), 3);
+ *this->BuildFileStream << cmVS10EscapeXML(outDir) << "</OutDir>\n";
+
+ this->WritePlatformConfigTag("IntDir", config->c_str(), 3);
+ *this->BuildFileStream << cmVS10EscapeXML(intermediateDir)
+ << "</IntDir>\n";
+
+ std::string name =
+ cmSystemTools::GetFilenameWithoutLastExtension(targetNameFull);
+ this->WritePlatformConfigTag("TargetName", config->c_str(), 3);
+ *this->BuildFileStream << cmVS10EscapeXML(name) << "</TargetName>\n";
+
+ std::string ext =
+ cmSystemTools::GetFilenameLastExtension(targetNameFull);
+ if (ext.empty()) {
+ // An empty TargetExt causes a default extension to be used.
+ // A single "." appears to be treated as an empty extension.
+ ext = ".";
+ }
+ this->WritePlatformConfigTag("TargetExt", config->c_str(), 3);
+ *this->BuildFileStream << cmVS10EscapeXML(ext) << "</TargetExt>\n";
+
+ this->OutputLinkIncremental(*config);
+ }
+ }
+ this->WriteString("</PropertyGroup>\n", 2);
+}
+
+void cmVisualStudio10TargetGenerator::OutputLinkIncremental(
+ std::string const& configName)
+{
+ if (!this->MSTools) {
+ return;
+ }
+ // static libraries and things greater than modules do not need
+ // to set this option
+ if (this->GeneratorTarget->GetType() == cmState::STATIC_LIBRARY ||
+ this->GeneratorTarget->GetType() > cmState::MODULE_LIBRARY) {
+ return;
+ }
+ Options& linkOptions = *(this->LinkOptions[configName]);
+
+ const char* incremental = linkOptions.GetFlag("LinkIncremental");
+ this->WritePlatformConfigTag("LinkIncremental", configName.c_str(), 3);
+ *this->BuildFileStream << (incremental ? incremental : "true")
+ << "</LinkIncremental>\n";
+ linkOptions.RemoveFlag("LinkIncremental");
+
+ const char* manifest = linkOptions.GetFlag("GenerateManifest");
+ this->WritePlatformConfigTag("GenerateManifest", configName.c_str(), 3);
+ *this->BuildFileStream << (manifest ? manifest : "true")
+ << "</GenerateManifest>\n";
+ linkOptions.RemoveFlag("GenerateManifest");
+
+ // Some link options belong here. Use them now and remove them so that
+ // WriteLinkOptions does not use them.
+ const char* flags[] = { "LinkDelaySign", "LinkKeyFile", 0 };
+ for (const char** f = flags; *f; ++f) {
+ const char* flag = *f;
+ if (const char* value = linkOptions.GetFlag(flag)) {
+ this->WritePlatformConfigTag(flag, configName.c_str(), 3);
+ *this->BuildFileStream << value << "</" << flag << ">\n";
+ linkOptions.RemoveFlag(flag);
+ }
+ }
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeClOptions()
+{
+ for (std::vector<std::string>::const_iterator i =
+ this->Configurations.begin();
+ i != this->Configurations.end(); ++i) {
+ if (!this->ComputeClOptions(*i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeClOptions(
+ std::string const& configName)
+{
+ // much of this was copied from here:
+ // copied from cmLocalVisualStudio7Generator.cxx 805
+ // TODO: Integrate code below with cmLocalVisualStudio7Generator.
+
+ CM_AUTO_PTR<Options> pOptions(new Options(
+ this->LocalGenerator, Options::Compiler, this->GetClFlagTable()));
+ Options& clOptions = *pOptions;
+
+ std::string flags;
+ const std::string& linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(configName.c_str());
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error(
+ "CMake can not determine linker language for target: ",
+ this->Name.c_str());
+ return false;
+ }
+ if (linkLanguage == "C" || linkLanguage == "CXX" ||
+ linkLanguage == "Fortran") {
+ std::string baseFlagVar = "CMAKE_";
+ baseFlagVar += linkLanguage;
+ baseFlagVar += "_FLAGS";
+ flags =
+ this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition(
+ baseFlagVar.c_str());
+ std::string flagVar =
+ baseFlagVar + std::string("_") + cmSystemTools::UpperCase(configName);
+ flags += " ";
+ flags +=
+ this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition(
+ flagVar.c_str());
+ }
+ // set the correct language
+ if (linkLanguage == "C") {
+ clOptions.AddFlag("CompileAs", "CompileAsC");
+ }
+ if (linkLanguage == "CXX") {
+ clOptions.AddFlag("CompileAs", "CompileAsCpp");
+ }
+ this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
+ linkLanguage, configName.c_str());
+
+ // Get preprocessor definitions for this directory.
+ std::string defineFlags =
+ this->GeneratorTarget->Target->GetMakefile()->GetDefineFlags();
+ if (this->MSTools) {
+ clOptions.FixExceptionHandlingDefault();
+ clOptions.AddFlag("PrecompiledHeader", "NotUsing");
+ std::string asmLocation = configName + "/";
+ clOptions.AddFlag("AssemblerListingLocation", asmLocation.c_str());
+ }
+ clOptions.Parse(flags.c_str());
+ clOptions.Parse(defineFlags.c_str());
+ std::vector<std::string> targetDefines;
+ this->GeneratorTarget->GetCompileDefinitions(targetDefines,
+ configName.c_str(), "CXX");
+ clOptions.AddDefines(targetDefines);
+ if (this->MSTools) {
+ clOptions.SetVerboseMakefile(
+ this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
+ }
+
+ // Add a definition for the configuration name.
+ std::string configDefine = "CMAKE_INTDIR=\"";
+ configDefine += configName;
+ configDefine += "\"";
+ clOptions.AddDefine(configDefine);
+ if (const char* exportMacro = this->GeneratorTarget->GetExportMacro()) {
+ clOptions.AddDefine(exportMacro);
+ }
+
+ if (this->MSTools) {
+ // If we have the VS_WINRT_COMPONENT set then force Compile as WinRT.
+ if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT")) {
+ clOptions.AddFlag("CompileAsWinRT", "true");
+ // For WinRT components, add the _WINRT_DLL define to produce a lib
+ if (this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmState::MODULE_LIBRARY) {
+ clOptions.AddDefine("_WINRT_DLL");
+ }
+ } else if (this->GlobalGenerator->TargetsWindowsStore() ||
+ this->GlobalGenerator->TargetsWindowsPhone()) {
+ if (!clOptions.IsWinRt()) {
+ clOptions.AddFlag("CompileAsWinRT", "false");
+ }
+ }
+ if (const char* winRT = clOptions.GetFlag("CompileAsWinRT")) {
+ if (cmSystemTools::IsOn(winRT)) {
+ this->TargetCompileAsWinRT = true;
+ }
+ }
+ }
+
+ this->ClOptions[configName] = pOptions.release();
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteClOptions(
+ std::string const& configName, std::vector<std::string> const& includes)
+{
+ Options& clOptions = *(this->ClOptions[configName]);
+ this->WriteString("<ClCompile>\n", 2);
+ clOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
+ clOptions.AppendFlag("AdditionalIncludeDirectories", includes);
+ clOptions.AppendFlag("AdditionalIncludeDirectories",
+ "%(AdditionalIncludeDirectories)");
+ clOptions.OutputFlagMap(*this->BuildFileStream, " ");
+ clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
+ "\n", "CXX");
+
+ if (this->NsightTegra) {
+ if (const char* processMax =
+ this->GeneratorTarget->GetProperty("ANDROID_PROCESS_MAX")) {
+ this->WriteString("<ProcessMax>", 3);
+ *this->BuildFileStream << cmVS10EscapeXML(processMax)
+ << "</ProcessMax>\n";
+ }
+ }
+
+ if (this->MSTools) {
+ cmsys::RegularExpression clangToolset("v[0-9]+_clang_.*");
+ const char* toolset = this->GlobalGenerator->GetPlatformToolset();
+ if (toolset && clangToolset.find(toolset)) {
+ this->WriteString("<ObjectFileName>"
+ "$(IntDir)%(filename).obj"
+ "</ObjectFileName>\n",
+ 3);
+ } else {
+ this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3);
+ }
+
+ // If not in debug mode, write the DebugInformationFormat field
+ // without value so PDBs don't get generated uselessly.
+ if (!clOptions.IsDebug()) {
+ this->WriteString("<DebugInformationFormat>"
+ "</DebugInformationFormat>\n",
+ 3);
+ }
+
+ // Specify the compiler program database file if configured.
+ std::string pdb =
+ this->GeneratorTarget->GetCompilePDBPath(configName.c_str());
+ if (!pdb.empty()) {
+ this->ConvertToWindowsSlash(pdb);
+ this->WriteString("<ProgramDataBaseFileName>", 3);
+ *this->BuildFileStream << cmVS10EscapeXML(pdb)
+ << "</ProgramDataBaseFileName>\n";
+ }
+ }
+
+ this->WriteString("</ClCompile>\n", 2);
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeRcOptions()
+{
+ for (std::vector<std::string>::const_iterator i =
+ this->Configurations.begin();
+ i != this->Configurations.end(); ++i) {
+ if (!this->ComputeRcOptions(*i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeRcOptions(
+ std::string const& configName)
+{
+ CM_AUTO_PTR<Options> pOptions(new Options(
+ this->LocalGenerator, Options::ResourceCompiler, this->GetRcFlagTable()));
+ Options& rcOptions = *pOptions;
+
+ std::string CONFIG = cmSystemTools::UpperCase(configName);
+ std::string rcConfigFlagsVar = std::string("CMAKE_RC_FLAGS_") + CONFIG;
+ std::string flags =
+ std::string(this->Makefile->GetSafeDefinition("CMAKE_RC_FLAGS")) +
+ std::string(" ") +
+ std::string(this->Makefile->GetSafeDefinition(rcConfigFlagsVar));
+
+ rcOptions.Parse(flags.c_str());
+ this->RcOptions[configName] = pOptions.release();
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteRCOptions(
+ std::string const& configName, std::vector<std::string> const& includes)
+{
+ if (!this->MSTools) {
+ return;
+ }
+ this->WriteString("<ResourceCompile>\n", 2);
+
+ // Preprocessor definitions and includes are shared with clOptions.
+ Options& clOptions = *(this->ClOptions[configName]);
+ clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
+ "\n", "RC");
+
+ Options& rcOptions = *(this->RcOptions[configName]);
+ rcOptions.AppendFlag("AdditionalIncludeDirectories", includes);
+ rcOptions.AppendFlag("AdditionalIncludeDirectories",
+ "%(AdditionalIncludeDirectories)");
+ rcOptions.OutputFlagMap(*this->BuildFileStream, " ");
+ rcOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
+
+ this->WriteString("</ResourceCompile>\n", 2);
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeMasmOptions()
+{
+ if (!this->GlobalGenerator->IsMasmEnabled()) {
+ return true;
+ }
+ for (std::vector<std::string>::const_iterator i =
+ this->Configurations.begin();
+ i != this->Configurations.end(); ++i) {
+ if (!this->ComputeMasmOptions(*i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeMasmOptions(
+ std::string const& configName)
+{
+ CM_AUTO_PTR<Options> pOptions(new Options(
+ this->LocalGenerator, Options::MasmCompiler, this->GetMasmFlagTable()));
+ Options& masmOptions = *pOptions;
+
+ std::string CONFIG = cmSystemTools::UpperCase(configName);
+ std::string configFlagsVar = std::string("CMAKE_ASM_MASM_FLAGS_") + CONFIG;
+ std::string flags =
+ std::string(this->Makefile->GetSafeDefinition("CMAKE_ASM_MASM_FLAGS")) +
+ std::string(" ") +
+ std::string(this->Makefile->GetSafeDefinition(configFlagsVar));
+
+ masmOptions.Parse(flags.c_str());
+ this->MasmOptions[configName] = pOptions.release();
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteMasmOptions(
+ std::string const& configName, std::vector<std::string> const& includes)
+{
+ if (!this->MSTools || !this->GlobalGenerator->IsMasmEnabled()) {
+ return;
+ }
+ this->WriteString("<MASM>\n", 2);
+
+ // Preprocessor definitions and includes are shared with clOptions.
+ Options& clOptions = *(this->ClOptions[configName]);
+ clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
+ "\n", "ASM_MASM");
+
+ Options& masmOptions = *(this->MasmOptions[configName]);
+ masmOptions.AppendFlag("IncludePaths", includes);
+ masmOptions.AppendFlag("IncludePaths", "%(IncludePaths)");
+ masmOptions.OutputFlagMap(*this->BuildFileStream, " ");
+ masmOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
+
+ this->WriteString("</MASM>\n", 2);
+}
+
+void cmVisualStudio10TargetGenerator::WriteLibOptions(
+ std::string const& config)
+{
+ if (this->GeneratorTarget->GetType() != cmState::STATIC_LIBRARY &&
+ this->GeneratorTarget->GetType() != cmState::OBJECT_LIBRARY) {
+ return;
+ }
+ std::string libflags;
+ this->LocalGenerator->GetStaticLibraryFlags(
+ libflags, cmSystemTools::UpperCase(config), this->GeneratorTarget);
+ if (!libflags.empty()) {
+ this->WriteString("<Lib>\n", 2);
+ cmVisualStudioGeneratorOptions libOptions(
+ this->LocalGenerator, cmVisualStudioGeneratorOptions::Linker,
+ this->GetLibFlagTable(), 0, this);
+ libOptions.Parse(libflags.c_str());
+ libOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
+ libOptions.OutputFlagMap(*this->BuildFileStream, " ");
+ this->WriteString("</Lib>\n", 2);
+ }
+
+ // We cannot generate metadata for static libraries. WindowsPhone
+ // and WindowsStore tools look at GenerateWindowsMetadata in the
+ // Link tool options even for static libraries.
+ if (this->GlobalGenerator->TargetsWindowsPhone() ||
+ this->GlobalGenerator->TargetsWindowsStore()) {
+ this->WriteString("<Link>\n", 2);
+ this->WriteString("<GenerateWindowsMetadata>false"
+ "</GenerateWindowsMetadata>\n",
+ 3);
+ this->WriteString("</Link>\n", 2);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteManifestOptions(
+ std::string const& config)
+{
+ if (this->GeneratorTarget->GetType() != cmState::EXECUTABLE &&
+ this->GeneratorTarget->GetType() != cmState::SHARED_LIBRARY &&
+ this->GeneratorTarget->GetType() != cmState::MODULE_LIBRARY) {
+ return;
+ }
+
+ std::vector<cmSourceFile const*> manifest_srcs;
+ this->GeneratorTarget->GetManifests(manifest_srcs, config);
+ if (!manifest_srcs.empty()) {
+ this->WriteString("<Manifest>\n", 2);
+ this->WriteString("<AdditionalManifestFiles>", 3);
+ for (std::vector<cmSourceFile const*>::const_iterator mi =
+ manifest_srcs.begin();
+ mi != manifest_srcs.end(); ++mi) {
+ std::string m = this->ConvertPath((*mi)->GetFullPath(), false);
+ this->ConvertToWindowsSlash(m);
+ (*this->BuildFileStream) << m << ";";
+ }
+ (*this->BuildFileStream) << "</AdditionalManifestFiles>\n";
+ this->WriteString("</Manifest>\n", 2);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteAntBuildOptions(
+ std::string const& configName)
+{
+ // Look through the sources for AndroidManifest.xml and use
+ // its location as the root source directory.
+ std::string rootDir = this->LocalGenerator->GetCurrentSourceDirectory();
+ {
+ std::vector<cmSourceFile const*> extraSources;
+ this->GeneratorTarget->GetExtraSources(extraSources, "");
+ for (std::vector<cmSourceFile const*>::const_iterator si =
+ extraSources.begin();
+ si != extraSources.end(); ++si) {
+ if ("androidmanifest.xml" ==
+ cmSystemTools::LowerCase((*si)->GetLocation().GetName())) {
+ rootDir = (*si)->GetLocation().GetDirectory();
+ break;
+ }
+ }
+ }
+
+ // Tell MSBuild to launch Ant.
+ {
+ std::string antBuildPath = rootDir;
+ this->WriteString("<AntBuild>\n", 2);
+ this->WriteString("<AntBuildPath>", 3);
+ this->ConvertToWindowsSlash(antBuildPath);
+ (*this->BuildFileStream) << cmVS10EscapeXML(antBuildPath)
+ << "</AntBuildPath>\n";
+ }
+
+ if (this->GeneratorTarget->GetPropertyAsBool("ANDROID_SKIP_ANT_STEP")) {
+ this->WriteString("<SkipAntStep>true</SkipAntStep>\n", 3);
+ }
+
+ if (this->GeneratorTarget->GetPropertyAsBool("ANDROID_PROGUARD")) {
+ this->WriteString("<EnableProGuard>true</EnableProGuard>\n", 3);
+ }
+
+ if (const char* proGuardConfigLocation =
+ this->GeneratorTarget->GetProperty("ANDROID_PROGUARD_CONFIG_PATH")) {
+ this->WriteString("<ProGuardConfigLocation>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(proGuardConfigLocation)
+ << "</ProGuardConfigLocation>\n";
+ }
+
+ if (const char* securePropertiesLocation =
+ this->GeneratorTarget->GetProperty("ANDROID_SECURE_PROPS_PATH")) {
+ this->WriteString("<SecurePropertiesLocation>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(securePropertiesLocation)
+ << "</SecurePropertiesLocation>\n";
+ }
+
+ if (const char* nativeLibDirectoriesExpression =
+ this->GeneratorTarget->GetProperty("ANDROID_NATIVE_LIB_DIRECTORIES")) {
+ cmGeneratorExpression ge;
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge =
+ ge.Parse(nativeLibDirectoriesExpression);
+ std::string nativeLibDirs =
+ cge->Evaluate(this->LocalGenerator, configName);
+ this->WriteString("<NativeLibDirectories>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(nativeLibDirs)
+ << "</NativeLibDirectories>\n";
+ }
+
+ if (const char* nativeLibDependenciesExpression =
+ this->GeneratorTarget->GetProperty(
+ "ANDROID_NATIVE_LIB_DEPENDENCIES")) {
+ cmGeneratorExpression ge;
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge =
+ ge.Parse(nativeLibDependenciesExpression);
+ std::string nativeLibDeps =
+ cge->Evaluate(this->LocalGenerator, configName);
+ this->WriteString("<NativeLibDependencies>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(nativeLibDeps)
+ << "</NativeLibDependencies>\n";
+ }
+
+ if (const char* javaSourceDir =
+ this->GeneratorTarget->GetProperty("ANDROID_JAVA_SOURCE_DIR")) {
+ this->WriteString("<JavaSourceDir>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(javaSourceDir)
+ << "</JavaSourceDir>\n";
+ }
+
+ if (const char* jarDirectoriesExpression =
+ this->GeneratorTarget->GetProperty("ANDROID_JAR_DIRECTORIES")) {
+ cmGeneratorExpression ge;
+ CM_AUTO_PTR<cmCompiledGeneratorExpression> cge =
+ ge.Parse(jarDirectoriesExpression);
+ std::string jarDirectories =
+ cge->Evaluate(this->LocalGenerator, configName);
+ this->WriteString("<JarDirectories>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(jarDirectories)
+ << "</JarDirectories>\n";
+ }
+
+ if (const char* jarDeps =
+ this->GeneratorTarget->GetProperty("ANDROID_JAR_DEPENDENCIES")) {
+ this->WriteString("<JarDependencies>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(jarDeps)
+ << "</JarDependencies>\n";
+ }
+
+ if (const char* assetsDirectories =
+ this->GeneratorTarget->GetProperty("ANDROID_ASSETS_DIRECTORIES")) {
+ this->WriteString("<AssetsDirectories>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(assetsDirectories)
+ << "</AssetsDirectories>\n";
+ }
+
+ {
+ std::string manifest_xml = rootDir + "/AndroidManifest.xml";
+ this->ConvertToWindowsSlash(manifest_xml);
+ this->WriteString("<AndroidManifestLocation>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(manifest_xml)
+ << "</AndroidManifestLocation>\n";
+ }
+
+ if (const char* antAdditionalOptions =
+ this->GeneratorTarget->GetProperty("ANDROID_ANT_ADDITIONAL_OPTIONS")) {
+ this->WriteString("<AdditionalOptions>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(antAdditionalOptions)
+ << " %(AdditionalOptions)</AdditionalOptions>\n";
+ }
+
+ this->WriteString("</AntBuild>\n", 2);
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeLinkOptions()
+{
+ if (this->GeneratorTarget->GetType() == cmState::EXECUTABLE ||
+ this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmState::MODULE_LIBRARY) {
+ for (std::vector<std::string>::const_iterator i =
+ this->Configurations.begin();
+ i != this->Configurations.end(); ++i) {
+ if (!this->ComputeLinkOptions(*i)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
+ std::string const& config)
+{
+ CM_AUTO_PTR<Options> pOptions(new Options(
+ this->LocalGenerator, Options::Linker, this->GetLinkFlagTable(), 0, this));
+ Options& linkOptions = *pOptions;
+
+ const std::string& linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(config.c_str());
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error(
+ "CMake can not determine linker language for target: ",
+ this->Name.c_str());
+ return false;
+ }
+
+ std::string CONFIG = cmSystemTools::UpperCase(config);
+
+ const char* linkType = "SHARED";
+ if (this->GeneratorTarget->GetType() == cmState::MODULE_LIBRARY) {
+ linkType = "MODULE";
+ }
+ if (this->GeneratorTarget->GetType() == cmState::EXECUTABLE) {
+ linkType = "EXE";
+ }
+ std::string flags;
+ std::string linkFlagVarBase = "CMAKE_";
+ linkFlagVarBase += linkType;
+ linkFlagVarBase += "_LINKER_FLAGS";
+ flags += " ";
+ flags += this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition(
+ linkFlagVarBase.c_str());
+ std::string linkFlagVar = linkFlagVarBase + "_" + CONFIG;
+ flags += " ";
+ flags += this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition(
+ linkFlagVar.c_str());
+ const char* targetLinkFlags =
+ this->GeneratorTarget->GetProperty("LINK_FLAGS");
+ if (targetLinkFlags) {
+ flags += " ";
+ flags += targetLinkFlags;
+ }
+ std::string flagsProp = "LINK_FLAGS_";
+ flagsProp += CONFIG;
+ if (const char* flagsConfig =
+ this->GeneratorTarget->GetProperty(flagsProp.c_str())) {
+ flags += " ";
+ flags += flagsConfig;
+ }
+ std::string standardLibsVar = "CMAKE_";
+ standardLibsVar += linkLanguage;
+ standardLibsVar += "_STANDARD_LIBRARIES";
+ std::string libs =
+ this->Makefile->GetSafeDefinition(standardLibsVar.c_str());
+ // Remove trailing spaces from libs
+ std::string::size_type pos = libs.size() - 1;
+ if (!libs.empty()) {
+ while (libs[pos] == ' ') {
+ pos--;
+ }
+ }
+ if (pos != libs.size() - 1) {
+ libs = libs.substr(0, pos + 1);
+ }
+ // Replace spaces in libs with ;
+ std::replace(libs.begin(), libs.end(), ' ', ';');
+ std::vector<std::string> libVec;
+ cmSystemTools::ExpandListArgument(libs, libVec);
+
+ cmComputeLinkInformation* pcli =
+ this->GeneratorTarget->GetLinkInformation(config.c_str());
+ if (!pcli) {
+ cmSystemTools::Error(
+ "CMake can not compute cmComputeLinkInformation for target: ",
+ this->Name.c_str());
+ return false;
+ }
+ // add the libraries for the target to libs string
+ cmComputeLinkInformation& cli = *pcli;
+ this->AddLibraries(cli, libVec);
+ linkOptions.AddFlag("AdditionalDependencies", libVec);
+
+ std::vector<std::string> const& ldirs = cli.GetDirectories();
+ std::vector<std::string> linkDirs;
+ for (std::vector<std::string>::const_iterator d = ldirs.begin();
+ d != ldirs.end(); ++d) {
+ // first just full path
+ linkDirs.push_back(*d);
+ // next path with configuration type Debug, Release, etc
+ linkDirs.push_back(*d + "/$(Configuration)");
+ }
+ linkDirs.push_back("%(AdditionalLibraryDirectories)");
+ linkOptions.AddFlag("AdditionalLibraryDirectories", linkDirs);
+
+ std::string targetName;
+ std::string targetNameSO;
+ std::string targetNameFull;
+ std::string targetNameImport;
+ std::string targetNamePDB;
+ if (this->GeneratorTarget->GetType() == cmState::EXECUTABLE) {
+ this->GeneratorTarget->GetExecutableNames(targetName, targetNameFull,
+ targetNameImport, targetNamePDB,
+ config.c_str());
+ } else {
+ this->GeneratorTarget->GetLibraryNames(targetName, targetNameSO,
+ targetNameFull, targetNameImport,
+ targetNamePDB, config.c_str());
+ }
+
+ if (this->MSTools) {
+ linkOptions.AddFlag("Version", "");
+
+ if (this->GeneratorTarget->GetPropertyAsBool("WIN32_EXECUTABLE")) {
+ if (this->GlobalGenerator->TargetsWindowsCE()) {
+ linkOptions.AddFlag("SubSystem", "WindowsCE");
+ if (this->GeneratorTarget->GetType() == cmState::EXECUTABLE) {
+ if (this->ClOptions[config]->UsingUnicode()) {
+ linkOptions.AddFlag("EntryPointSymbol", "wWinMainCRTStartup");
+ } else {
+ linkOptions.AddFlag("EntryPointSymbol", "WinMainCRTStartup");
+ }
+ }
+ } else {
+ linkOptions.AddFlag("SubSystem", "Windows");
+ }
+ } else {
+ if (this->GlobalGenerator->TargetsWindowsCE()) {
+ linkOptions.AddFlag("SubSystem", "WindowsCE");
+ if (this->GeneratorTarget->GetType() == cmState::EXECUTABLE) {
+ if (this->ClOptions[config]->UsingUnicode()) {
+ linkOptions.AddFlag("EntryPointSymbol", "mainWCRTStartup");
+ } else {
+ linkOptions.AddFlag("EntryPointSymbol", "mainACRTStartup");
+ }
+ }
+ } else {
+ linkOptions.AddFlag("SubSystem", "Console");
+ };
+ }
+
+ if (const char* stackVal = this->Makefile->GetDefinition(
+ "CMAKE_" + linkLanguage + "_STACK_SIZE")) {
+ linkOptions.AddFlag("StackReserveSize", stackVal);
+ }
+
+ if (this->LocalGenerator->GetVersion() >=
+ cmGlobalVisualStudioGenerator::VS14) {
+ linkOptions.AddFlag("GenerateDebugInformation", "No");
+ } else {
+ linkOptions.AddFlag("GenerateDebugInformation", "false");
+ }
+
+ std::string pdb = this->GeneratorTarget->GetPDBDirectory(config.c_str());
+ pdb += "/";
+ pdb += targetNamePDB;
+ std::string imLib =
+ this->GeneratorTarget->GetDirectory(config.c_str(), true);
+ imLib += "/";
+ imLib += targetNameImport;
+
+ linkOptions.AddFlag("ImportLibrary", imLib.c_str());
+ linkOptions.AddFlag("ProgramDataBaseFile", pdb.c_str());
+
+ // A Windows Runtime component uses internal .NET metadata,
+ // so does not have an import library.
+ if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT") &&
+ this->GeneratorTarget->GetType() != cmState::EXECUTABLE) {
+ linkOptions.AddFlag("GenerateWindowsMetadata", "true");
+ } else if (this->GlobalGenerator->TargetsWindowsPhone() ||
+ this->GlobalGenerator->TargetsWindowsStore()) {
+ // WindowsPhone and WindowsStore components are in an app container
+ // and produce WindowsMetadata. If we are not producing a WINRT
+ // component, then do not generate the metadata here.
+ linkOptions.AddFlag("GenerateWindowsMetadata", "false");
+ }
+
+ if (this->GlobalGenerator->TargetsWindowsPhone() &&
+ this->GlobalGenerator->GetSystemVersion() == "8.0") {
+ // WindowsPhone 8.0 does not have ole32.
+ linkOptions.AppendFlag("IgnoreSpecificDefaultLibraries", "ole32.lib");
+ }
+ } else if (this->NsightTegra) {
+ linkOptions.AddFlag("SoName", targetNameSO.c_str());
+ }
+
+ linkOptions.Parse(flags.c_str());
+
+ if (this->MSTools) {
+ if (cmSourceFile const* defsrc =
+ this->GeneratorTarget->GetModuleDefinitionFile("")) {
+ linkOptions.AddFlag("ModuleDefinitionFile",
+ defsrc->GetFullPath().c_str());
+ }
+ linkOptions.AppendFlag("IgnoreSpecificDefaultLibraries",
+ "%(IgnoreSpecificDefaultLibraries)");
+ }
+
+ if (this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY &&
+ this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS")) {
+ if (this->GeneratorTarget->GetPropertyAsBool(
+ "WINDOWS_EXPORT_ALL_SYMBOLS")) {
+ linkOptions.AddFlag("ModuleDefinitionFile", "$(IntDir)exportall.def");
+ }
+ }
+
+ // Hack to fix flag version selection in a common use case.
+ // FIXME: Select flag table based on toolset instead of VS version.
+ if (this->LocalGenerator->GetVersion() >=
+ cmGlobalVisualStudioGenerator::VS14) {
+ cmGlobalVisualStudio10Generator* gg =
+ static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+ const char* toolset = gg->GetPlatformToolset();
+ if (toolset && (cmHasLiteralPrefix(toolset, "v100") ||
+ cmHasLiteralPrefix(toolset, "v110") ||
+ cmHasLiteralPrefix(toolset, "v120"))) {
+ if (const char* debug =
+ linkOptions.GetFlag("GenerateDebugInformation")) {
+ // Convert value from enumeration back to boolean for older toolsets.
+ if (strcmp(debug, "No") == 0) {
+ linkOptions.AddFlag("GenerateDebugInformation", "false");
+ } else if (strcmp(debug, "Debug") == 0) {
+ linkOptions.AddFlag("GenerateDebugInformation", "true");
+ }
+ }
+ }
+ }
+
+ this->LinkOptions[config] = pOptions.release();
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteLinkOptions(
+ std::string const& config)
+{
+ if (this->GeneratorTarget->GetType() == cmState::STATIC_LIBRARY ||
+ this->GeneratorTarget->GetType() > cmState::MODULE_LIBRARY) {
+ return;
+ }
+ Options& linkOptions = *(this->LinkOptions[config]);
+ this->WriteString("<Link>\n", 2);
+
+ linkOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
+ linkOptions.OutputFlagMap(*this->BuildFileStream, " ");
+
+ this->WriteString("</Link>\n", 2);
+ if (!this->GlobalGenerator->NeedLinkLibraryDependencies(
+ this->GeneratorTarget)) {
+ this->WriteString("<ProjectReference>\n", 2);
+ this->WriteString(
+ "<LinkLibraryDependencies>false</LinkLibraryDependencies>\n", 3);
+ this->WriteString("</ProjectReference>\n", 2);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::AddLibraries(
+ cmComputeLinkInformation& cli, std::vector<std::string>& libVec)
+{
+ typedef cmComputeLinkInformation::ItemVector ItemVector;
+ ItemVector libs = cli.GetItems();
+ for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) {
+ if (l->IsPath) {
+ std::string path = this->LocalGenerator->Convert(
+ l->Value.c_str(), cmOutputConverter::START_OUTPUT,
+ cmOutputConverter::UNCHANGED);
+ this->ConvertToWindowsSlash(path);
+ libVec.push_back(path);
+ } else if (!l->Target ||
+ l->Target->GetType() != cmState::INTERFACE_LIBRARY) {
+ libVec.push_back(l->Value);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteMidlOptions(
+ std::string const& /*config*/, std::vector<std::string> const& includes)
+{
+ if (!this->MSTools) {
+ return;
+ }
+
+ // This processes *any* of the .idl files specified in the project's file
+ // list (and passed as the item metadata %(Filename) expressing the rule
+ // input filename) into output files at the per-config *build* dir
+ // ($(IntDir)) each.
+ //
+ // IOW, this MIDL section is intended to provide a fully generic syntax
+ // content suitable for most cases (read: if you get errors, then it's quite
+ // probable that the error is on your side of the .idl setup).
+ //
+ // Also, note that the marked-as-generated _i.c file in the Visual Studio
+ // generator case needs to be referred to as $(IntDir)\foo_i.c at the
+ // project's file list, otherwise the compiler-side processing won't pick it
+ // up (for non-directory form, it ends up looking in project binary dir
+ // only). Perhaps there's something to be done to make this more automatic
+ // on the CMake side?
+ this->WriteString("<Midl>\n", 2);
+ this->WriteString("<AdditionalIncludeDirectories>", 3);
+ for (std::vector<std::string>::const_iterator i = includes.begin();
+ i != includes.end(); ++i) {
+ *this->BuildFileStream << cmVS10EscapeXML(*i) << ";";
+ }
+ this->WriteString("%(AdditionalIncludeDirectories)"
+ "</AdditionalIncludeDirectories>\n",
+ 0);
+ this->WriteString("<OutputDirectory>$(ProjectDir)/$(IntDir)"
+ "</OutputDirectory>\n",
+ 3);
+ this->WriteString("<HeaderFileName>%(Filename).h</HeaderFileName>\n", 3);
+ this->WriteString("<TypeLibraryName>%(Filename).tlb</TypeLibraryName>\n", 3);
+ this->WriteString("<InterfaceIdentifierFileName>"
+ "%(Filename)_i.c</InterfaceIdentifierFileName>\n",
+ 3);
+ this->WriteString("<ProxyFileName>%(Filename)_p.c</ProxyFileName>\n", 3);
+ this->WriteString("</Midl>\n", 2);
+}
+
+void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups()
+{
+ for (std::vector<std::string>::const_iterator i =
+ this->Configurations.begin();
+ i != this->Configurations.end(); ++i) {
+ std::vector<std::string> includes;
+ this->LocalGenerator->GetIncludeDirectories(
+ includes, this->GeneratorTarget, "C", i->c_str());
+ for (std::vector<std::string>::iterator ii = includes.begin();
+ ii != includes.end(); ++ii) {
+ this->ConvertToWindowsSlash(*ii);
+ }
+ this->WritePlatformConfigTag("ItemDefinitionGroup", i->c_str(), 1);
+ *this->BuildFileStream << "\n";
+ // output cl compile flags <ClCompile></ClCompile>
+ if (this->GeneratorTarget->GetType() <= cmState::OBJECT_LIBRARY) {
+ this->WriteClOptions(*i, includes);
+ // output rc compile flags <ResourceCompile></ResourceCompile>
+ this->WriteRCOptions(*i, includes);
+ this->WriteMasmOptions(*i, includes);
+ }
+ // output midl flags <Midl></Midl>
+ this->WriteMidlOptions(*i, includes);
+ // write events
+ this->WriteEvents(*i);
+ // output link flags <Link></Link>
+ this->WriteLinkOptions(*i);
+ // output lib flags <Lib></Lib>
+ this->WriteLibOptions(*i);
+ // output manifest flags <Manifest></Manifest>
+ this->WriteManifestOptions(*i);
+ if (this->NsightTegra &&
+ this->GeneratorTarget->GetType() == cmState::EXECUTABLE &&
+ this->GeneratorTarget->GetPropertyAsBool("ANDROID_GUI")) {
+ this->WriteAntBuildOptions(*i);
+ }
+ this->WriteString("</ItemDefinitionGroup>\n", 1);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteEvents(
+ std::string const& configName)
+{
+ bool addedPrelink = false;
+ if (this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY &&
+ this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS")) {
+ if (this->GeneratorTarget->GetPropertyAsBool(
+ "WINDOWS_EXPORT_ALL_SYMBOLS")) {
+ addedPrelink = true;
+ std::vector<cmCustomCommand> commands =
+ this->GeneratorTarget->GetPreLinkCommands();
+ this->GlobalGenerator->AddSymbolExportCommand(this->GeneratorTarget,
+ commands, configName);
+ this->WriteEvent("PreLinkEvent", commands, configName);
+ }
+ }
+ if (!addedPrelink) {
+ this->WriteEvent("PreLinkEvent",
+ this->GeneratorTarget->GetPreLinkCommands(), configName);
+ }
+ this->WriteEvent("PreBuildEvent",
+ this->GeneratorTarget->GetPreBuildCommands(), configName);
+ this->WriteEvent("PostBuildEvent",
+ this->GeneratorTarget->GetPostBuildCommands(), configName);
+}
+
+void cmVisualStudio10TargetGenerator::WriteEvent(
+ const char* name, std::vector<cmCustomCommand> const& commands,
+ std::string const& configName)
+{
+ if (commands.empty()) {
+ return;
+ }
+ this->WriteString("<", 2);
+ (*this->BuildFileStream) << name << ">\n";
+ cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
+ std::string script;
+ const char* pre = "";
+ std::string comment;
+ for (std::vector<cmCustomCommand>::const_iterator i = commands.begin();
+ i != commands.end(); ++i) {
+ cmCustomCommandGenerator ccg(*i, configName, this->LocalGenerator);
+ comment += pre;
+ comment += lg->ConstructComment(ccg);
+ script += pre;
+ pre = "\n";
+ script += cmVS10EscapeXML(lg->ConstructScript(ccg));
+ }
+ comment = cmVS10EscapeComment(comment);
+ this->WriteString("<Message>", 3);
+ (*this->BuildFileStream) << cmVS10EscapeXML(comment) << "</Message>\n";
+ this->WriteString("<Command>", 3);
+ (*this->BuildFileStream) << script;
+ (*this->BuildFileStream) << "</Command>"
+ << "\n";
+ this->WriteString("</", 2);
+ (*this->BuildFileStream) << name << ">\n";
+}
+
+void cmVisualStudio10TargetGenerator::WriteProjectReferences()
+{
+ cmGlobalGenerator::TargetDependSet const& unordered =
+ this->GlobalGenerator->GetTargetDirectDepends(this->GeneratorTarget);
+ typedef cmGlobalVisualStudioGenerator::OrderedTargetDependSet
+ OrderedTargetDependSet;
+ OrderedTargetDependSet depends(unordered, CMAKE_CHECK_BUILD_SYSTEM_TARGET);
+ this->WriteString("<ItemGroup>\n", 1);
+ for (OrderedTargetDependSet::const_iterator i = depends.begin();
+ i != depends.end(); ++i) {
+ cmGeneratorTarget const* dt = *i;
+ if (dt->GetType() == cmState::INTERFACE_LIBRARY) {
+ continue;
+ }
+ // skip fortran targets as they can not be processed by MSBuild
+ // the only reference will be in the .sln file
+ if (static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator)
+ ->TargetIsFortranOnly(dt)) {
+ continue;
+ }
+ this->WriteString("<ProjectReference Include=\"", 2);
+ cmLocalGenerator* lg = dt->GetLocalGenerator();
+ std::string name = dt->GetName();
+ std::string path;
+ const char* p = dt->GetProperty("EXTERNAL_MSPROJECT");
+ if (p) {
+ path = p;
+ } else {
+ path = lg->GetCurrentBinaryDirectory();
+ path += "/";
+ path += dt->GetName();
+ path += ".vcxproj";
+ }
+ (*this->BuildFileStream) << cmVS10EscapeXML(path) << "\">\n";
+ this->WriteString("<Project>", 3);
+ (*this->BuildFileStream) << this->GlobalGenerator->GetGUID(name.c_str())
+ << "</Project>\n";
+ this->WriteString("</ProjectReference>\n", 2);
+ }
+ this->WriteString("</ItemGroup>\n", 1);
+}
+
+void cmVisualStudio10TargetGenerator::WritePlatformExtensions()
+{
+ // This only applies to Windows 10 apps
+ if (this->GlobalGenerator->TargetsWindowsStore() &&
+ cmHasLiteralPrefix(this->GlobalGenerator->GetSystemVersion(), "10.0")) {
+ const char* desktopExtensionsVersion =
+ this->GeneratorTarget->GetProperty("VS_DESKTOP_EXTENSIONS_VERSION");
+ if (desktopExtensionsVersion) {
+ this->WriteSinglePlatformExtension("WindowsDesktop",
+ desktopExtensionsVersion);
+ }
+ const char* mobileExtensionsVersion =
+ this->GeneratorTarget->GetProperty("VS_MOBILE_EXTENSIONS_VERSION");
+ if (mobileExtensionsVersion) {
+ this->WriteSinglePlatformExtension("WindowsMobile",
+ mobileExtensionsVersion);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteSinglePlatformExtension(
+ std::string const& extension, std::string const& version)
+{
+ this->WriteString("<Import Project=", 2);
+ (*this->BuildFileStream)
+ << "\"$([Microsoft.Build.Utilities.ToolLocationHelper]"
+ << "::GetPlatformExtensionSDKLocation(`" << extension
+ << ", Version=" << version
+ << "`, $(TargetPlatformIdentifier), $(TargetPlatformVersion), null, "
+ << "$(ExtensionSDKDirectoryRoot), null))"
+ << "\\DesignTime\\CommonConfiguration\\Neutral\\" << extension
+ << ".props\" "
+ << "Condition=\"exists('$("
+ << "[Microsoft.Build.Utilities.ToolLocationHelper]"
+ << "::GetPlatformExtensionSDKLocation(`" << extension
+ << ", Version=" << version
+ << "`, $(TargetPlatformIdentifier), $(TargetPlatformVersion), null, "
+ << "$(ExtensionSDKDirectoryRoot), null))"
+ << "\\DesignTime\\CommonConfiguration\\Neutral\\" << extension
+ << ".props')\" />\n";
+}
+
+void cmVisualStudio10TargetGenerator::WriteSDKReferences()
+{
+ std::vector<std::string> sdkReferences;
+ bool hasWrittenItemGroup = false;
+ if (const char* vsSDKReferences =
+ this->GeneratorTarget->GetProperty("VS_SDK_REFERENCES")) {
+ cmSystemTools::ExpandListArgument(vsSDKReferences, sdkReferences);
+ this->WriteString("<ItemGroup>\n", 1);
+ hasWrittenItemGroup = true;
+ for (std::vector<std::string>::iterator ri = sdkReferences.begin();
+ ri != sdkReferences.end(); ++ri) {
+ this->WriteString("<SDKReference Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(*ri) << "\"/>\n";
+ }
+ }
+
+ // This only applies to Windows 10 apps
+ if (this->GlobalGenerator->TargetsWindowsStore() &&
+ cmHasLiteralPrefix(this->GlobalGenerator->GetSystemVersion(), "10.0")) {
+ const char* desktopExtensionsVersion =
+ this->GeneratorTarget->GetProperty("VS_DESKTOP_EXTENSIONS_VERSION");
+ const char* mobileExtensionsVersion =
+ this->GeneratorTarget->GetProperty("VS_MOBILE_EXTENSIONS_VERSION");
+ const char* iotExtensionsVersion =
+ this->GeneratorTarget->GetProperty("VS_IOT_EXTENSIONS_VERSION");
+
+ if (desktopExtensionsVersion || mobileExtensionsVersion ||
+ iotExtensionsVersion) {
+ if (!hasWrittenItemGroup) {
+ this->WriteString("<ItemGroup>\n", 1);
+ hasWrittenItemGroup = true;
+ }
+ if (desktopExtensionsVersion) {
+ this->WriteSingleSDKReference("WindowsDesktop",
+ desktopExtensionsVersion);
+ }
+ if (mobileExtensionsVersion) {
+ this->WriteSingleSDKReference("WindowsMobile",
+ mobileExtensionsVersion);
+ }
+ if (iotExtensionsVersion) {
+ this->WriteSingleSDKReference("WindowsIoT", iotExtensionsVersion);
+ }
+ }
+
+ if (hasWrittenItemGroup) {
+ this->WriteString("</ItemGroup>\n", 1);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteSingleSDKReference(
+ std::string const& extension, std::string const& version)
+{
+ this->WriteString("<SDKReference Include=\"", 2);
+ (*this->BuildFileStream) << extension << ", Version=" << version
+ << "\" />\n";
+}
+
+void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile()
+{
+ if ((this->GlobalGenerator->TargetsWindowsStore() ||
+ this->GlobalGenerator->TargetsWindowsPhone()) &&
+ (cmState::EXECUTABLE == this->GeneratorTarget->GetType())) {
+ std::string pfxFile;
+ std::vector<cmSourceFile const*> certificates;
+ this->GeneratorTarget->GetCertificates(certificates, "");
+ for (std::vector<cmSourceFile const*>::const_iterator si =
+ certificates.begin();
+ si != certificates.end(); ++si) {
+ pfxFile = this->ConvertPath((*si)->GetFullPath(), false);
+ this->ConvertToWindowsSlash(pfxFile);
+ break;
+ }
+
+ if (this->IsMissingFiles &&
+ !(this->GlobalGenerator->TargetsWindowsPhone() &&
+ this->GlobalGenerator->GetSystemVersion() == "8.0")) {
+ // Move the manifest to a project directory to avoid clashes
+ std::string artifactDir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ this->ConvertToWindowsSlash(artifactDir);
+ this->WriteString("<PropertyGroup>\n", 1);
+ this->WriteString("<AppxPackageArtifactsDir>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(artifactDir)
+ << "\\</AppxPackageArtifactsDir>\n";
+ this->WriteString("<ProjectPriFullPath>"
+ "$(TargetDir)resources.pri</ProjectPriFullPath>\n",
+ 2);
+
+ // If we are missing files and we don't have a certificate and
+ // aren't targeting WP8.0, add a default certificate
+ if (pfxFile.empty()) {
+ std::string templateFolder =
+ cmSystemTools::GetCMakeRoot() + "/Templates/Windows";
+ pfxFile = this->DefaultArtifactDir + "/Windows_TemporaryKey.pfx";
+ cmSystemTools::CopyAFile(templateFolder + "/Windows_TemporaryKey.pfx",
+ pfxFile, false);
+ this->ConvertToWindowsSlash(pfxFile);
+ this->AddedFiles.push_back(pfxFile);
+ }
+
+ this->WriteString("<", 2);
+ (*this->BuildFileStream) << "PackageCertificateKeyFile>" << pfxFile
+ << "</PackageCertificateKeyFile>\n";
+ std::string thumb = cmSystemTools::ComputeCertificateThumbprint(pfxFile);
+ if (!thumb.empty()) {
+ this->WriteString("<PackageCertificateThumbprint>", 2);
+ (*this->BuildFileStream) << thumb
+ << "</PackageCertificateThumbprint>\n";
+ }
+ this->WriteString("</PropertyGroup>\n", 1);
+ } else if (!pfxFile.empty()) {
+ this->WriteString("<PropertyGroup>\n", 1);
+ this->WriteString("<", 2);
+ (*this->BuildFileStream) << "PackageCertificateKeyFile>" << pfxFile
+ << "</PackageCertificateKeyFile>\n";
+ std::string thumb = cmSystemTools::ComputeCertificateThumbprint(pfxFile);
+ if (!thumb.empty()) {
+ this->WriteString("<PackageCertificateThumbprint>", 2);
+ (*this->BuildFileStream) << thumb
+ << "</PackageCertificateThumbprint>\n";
+ }
+ this->WriteString("</PropertyGroup>\n", 1);
+ }
+ }
+}
+
+bool cmVisualStudio10TargetGenerator::IsResxHeader(
+ const std::string& headerFile)
+{
+ std::set<std::string> expectedResxHeaders;
+ this->GeneratorTarget->GetExpectedResxHeaders(expectedResxHeaders, "");
+
+ std::set<std::string>::const_iterator it =
+ expectedResxHeaders.find(headerFile);
+ return it != expectedResxHeaders.end();
+}
+
+bool cmVisualStudio10TargetGenerator::IsXamlHeader(
+ const std::string& headerFile)
+{
+ std::set<std::string> expectedXamlHeaders;
+ this->GeneratorTarget->GetExpectedXamlHeaders(expectedXamlHeaders, "");
+
+ std::set<std::string>::const_iterator it =
+ expectedXamlHeaders.find(headerFile);
+ return it != expectedXamlHeaders.end();
+}
+
+bool cmVisualStudio10TargetGenerator::IsXamlSource(
+ const std::string& sourceFile)
+{
+ std::set<std::string> expectedXamlSources;
+ this->GeneratorTarget->GetExpectedXamlSources(expectedXamlSources, "");
+
+ std::set<std::string>::const_iterator it =
+ expectedXamlSources.find(sourceFile);
+ return it != expectedXamlSources.end();
+}
+
+void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings()
+{
+ cmGlobalVisualStudio10Generator* gg =
+ static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+ bool isAppContainer = false;
+ bool const isWindowsPhone = this->GlobalGenerator->TargetsWindowsPhone();
+ bool const isWindowsStore = this->GlobalGenerator->TargetsWindowsStore();
+ std::string const& v = this->GlobalGenerator->GetSystemVersion();
+ if (isWindowsPhone || isWindowsStore) {
+ this->WriteString("<ApplicationType>", 2);
+ (*this->BuildFileStream)
+ << (isWindowsPhone ? "Windows Phone" : "Windows Store")
+ << "</ApplicationType>\n";
+ this->WriteString("<DefaultLanguage>en-US"
+ "</DefaultLanguage>\n",
+ 2);
+ if (cmHasLiteralPrefix(v, "10.0")) {
+ this->WriteString("<ApplicationTypeRevision>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML("10.0")
+ << "</ApplicationTypeRevision>\n";
+ // Visual Studio 14.0 is necessary for building 10.0 apps
+ this->WriteString("<MinimumVisualStudioVersion>14.0"
+ "</MinimumVisualStudioVersion>\n",
+ 2);
+
+ if (this->GeneratorTarget->GetType() < cmState::UTILITY) {
+ isAppContainer = true;
+ }
+ } else if (v == "8.1") {
+ this->WriteString("<ApplicationTypeRevision>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(v)
+ << "</ApplicationTypeRevision>\n";
+ // Visual Studio 12.0 is necessary for building 8.1 apps
+ this->WriteString("<MinimumVisualStudioVersion>12.0"
+ "</MinimumVisualStudioVersion>\n",
+ 2);
+
+ if (this->GeneratorTarget->GetType() < cmState::UTILITY) {
+ isAppContainer = true;
+ }
+ } else if (v == "8.0") {
+ this->WriteString("<ApplicationTypeRevision>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(v)
+ << "</ApplicationTypeRevision>\n";
+ // Visual Studio 11.0 is necessary for building 8.0 apps
+ this->WriteString("<MinimumVisualStudioVersion>11.0"
+ "</MinimumVisualStudioVersion>\n",
+ 2);
+
+ if (isWindowsStore &&
+ this->GeneratorTarget->GetType() < cmState::UTILITY) {
+ isAppContainer = true;
+ } else if (isWindowsPhone &&
+ this->GeneratorTarget->GetType() == cmState::EXECUTABLE) {
+ this->WriteString("<XapOutputs>true</XapOutputs>\n", 2);
+ this->WriteString("<XapFilename>", 2);
+ (*this->BuildFileStream)
+ << cmVS10EscapeXML(this->Name.c_str())
+ << "_$(Configuration)_$(Platform).xap</XapFilename>\n";
+ }
+ }
+ }
+ if (isAppContainer) {
+ this->WriteString("<AppContainerApplication>true"
+ "</AppContainerApplication>\n",
+ 2);
+ } else if (this->Platform == "ARM") {
+ this->WriteString("<WindowsSDKDesktopARMSupport>true"
+ "</WindowsSDKDesktopARMSupport>\n",
+ 2);
+ }
+ std::string const& targetPlatformVersion =
+ gg->GetWindowsTargetPlatformVersion();
+ if (!targetPlatformVersion.empty()) {
+ this->WriteString("<WindowsTargetPlatformVersion>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(targetPlatformVersion)
+ << "</WindowsTargetPlatformVersion>\n";
+ }
+ const char* targetPlatformMinVersion = this->GeneratorTarget->GetProperty(
+ "VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION");
+ if (targetPlatformMinVersion) {
+ this->WriteString("<WindowsTargetPlatformMinVersion>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(targetPlatformMinVersion)
+ << "</WindowsTargetPlatformMinVersion>\n";
+ } else if (isWindowsStore && cmHasLiteralPrefix(v, "10.0")) {
+ // If the min version is not set, then use the TargetPlatformVersion
+ if (!targetPlatformVersion.empty()) {
+ this->WriteString("<WindowsTargetPlatformMinVersion>", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(targetPlatformVersion)
+ << "</WindowsTargetPlatformMinVersion>\n";
+ }
+ }
+
+ // Added IoT Startup Task support
+ if (this->GeneratorTarget->GetPropertyAsBool("VS_IOT_STARTUP_TASK")) {
+ this->WriteString("<ContainsStartupTask>true</ContainsStartupTask>\n", 2);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::VerifyNecessaryFiles()
+{
+ // For Windows and Windows Phone executables, we will assume that if a
+ // manifest is not present that we need to add all the necessary files
+ if (this->GeneratorTarget->GetType() == cmState::EXECUTABLE) {
+ std::vector<cmSourceFile const*> manifestSources;
+ this->GeneratorTarget->GetAppManifest(manifestSources, "");
+ {
+ std::string const& v = this->GlobalGenerator->GetSystemVersion();
+ if (this->GlobalGenerator->TargetsWindowsPhone()) {
+ if (v == "8.0") {
+ // Look through the sources for WMAppManifest.xml
+ std::vector<cmSourceFile const*> extraSources;
+ this->GeneratorTarget->GetExtraSources(extraSources, "");
+ bool foundManifest = false;
+ for (std::vector<cmSourceFile const*>::const_iterator si =
+ extraSources.begin();
+ si != extraSources.end(); ++si) {
+ // Need to do a lowercase comparison on the filename
+ if ("wmappmanifest.xml" ==
+ cmSystemTools::LowerCase((*si)->GetLocation().GetName())) {
+ foundManifest = true;
+ break;
+ }
+ }
+ if (!foundManifest) {
+ this->IsMissingFiles = true;
+ }
+ } else if (v == "8.1") {
+ if (manifestSources.empty()) {
+ this->IsMissingFiles = true;
+ }
+ }
+ } else if (this->GlobalGenerator->TargetsWindowsStore()) {
+ if (manifestSources.empty()) {
+ if (v == "8.0") {
+ this->IsMissingFiles = true;
+ } else if (v == "8.1" || cmHasLiteralPrefix(v, "10.0")) {
+ this->IsMissingFiles = true;
+ }
+ }
+ }
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteMissingFiles()
+{
+ std::string const& v = this->GlobalGenerator->GetSystemVersion();
+ if (this->GlobalGenerator->TargetsWindowsPhone()) {
+ if (v == "8.0") {
+ this->WriteMissingFilesWP80();
+ } else if (v == "8.1") {
+ this->WriteMissingFilesWP81();
+ }
+ } else if (this->GlobalGenerator->TargetsWindowsStore()) {
+ if (v == "8.0") {
+ this->WriteMissingFilesWS80();
+ } else if (v == "8.1") {
+ this->WriteMissingFilesWS81();
+ } else if (cmHasLiteralPrefix(v, "10.0")) {
+ this->WriteMissingFilesWS10_0();
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteMissingFilesWP80()
+{
+ std::string templateFolder =
+ cmSystemTools::GetCMakeRoot() + "/Templates/Windows";
+
+ // For WP80, the manifest needs to be in the same folder as the project
+ // this can cause an overwrite problem if projects aren't organized in
+ // folders
+ std::string manifestFile =
+ this->LocalGenerator->GetCurrentBinaryDirectory() +
+ std::string("/WMAppManifest.xml");
+ std::string artifactDir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ this->ConvertToWindowsSlash(artifactDir);
+ std::string artifactDirXML = cmVS10EscapeXML(artifactDir);
+ std::string targetNameXML =
+ cmVS10EscapeXML(this->GeneratorTarget->GetName());
+
+ cmGeneratedFileStream fout(manifestFile.c_str());
+ fout.SetCopyIfDifferent(true);
+
+ /* clang-format off */
+ fout <<
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<Deployment"
+ " xmlns=\"http://schemas.microsoft.com/windowsphone/2012/deployment\""
+ " AppPlatformVersion=\"8.0\">\n"
+ "\t<DefaultLanguage xmlns=\"\" code=\"en-US\"/>\n"
+ "\t<App xmlns=\"\" ProductID=\"{" << this->GUID << "}\""
+ " Title=\"CMake Test Program\" RuntimeType=\"Modern Native\""
+ " Version=\"1.0.0.0\" Genre=\"apps.normal\" Author=\"CMake\""
+ " Description=\"Default CMake App\" Publisher=\"CMake\""
+ " PublisherID=\"{" << this->GUID << "}\">\n"
+ "\t\t<IconPath IsRelative=\"true\" IsResource=\"false\">"
+ << artifactDirXML << "\\ApplicationIcon.png</IconPath>\n"
+ "\t\t<Capabilities/>\n"
+ "\t\t<Tasks>\n"
+ "\t\t\t<DefaultTask Name=\"_default\""
+ " ImagePath=\"" << targetNameXML << ".exe\" ImageParams=\"\" />\n"
+ "\t\t</Tasks>\n"
+ "\t\t<Tokens>\n"
+ "\t\t\t<PrimaryToken TokenID=\"" << targetNameXML << "Token\""
+ " TaskName=\"_default\">\n"
+ "\t\t\t\t<TemplateFlip>\n"
+ "\t\t\t\t\t<SmallImageURI IsRelative=\"true\" IsResource=\"false\">"
+ << artifactDirXML << "\\SmallLogo.png</SmallImageURI>\n"
+ "\t\t\t\t\t<Count>0</Count>\n"
+ "\t\t\t\t\t<BackgroundImageURI IsRelative=\"true\" IsResource=\"false\">"
+ << artifactDirXML << "\\Logo.png</BackgroundImageURI>\n"
+ "\t\t\t\t</TemplateFlip>\n"
+ "\t\t\t</PrimaryToken>\n"
+ "\t\t</Tokens>\n"
+ "\t\t<ScreenResolutions>\n"
+ "\t\t\t<ScreenResolution Name=\"ID_RESOLUTION_WVGA\" />\n"
+ "\t\t</ScreenResolutions>\n"
+ "\t</App>\n"
+ "</Deployment>\n";
+ /* clang-format on */
+
+ std::string sourceFile = this->ConvertPath(manifestFile, false);
+ this->ConvertToWindowsSlash(sourceFile);
+ this->WriteString("<Xml Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(sourceFile) << "\">\n";
+ this->WriteString("<SubType>Designer</SubType>\n", 3);
+ this->WriteString("</Xml>\n", 2);
+ this->AddedFiles.push_back(sourceFile);
+
+ std::string smallLogo = this->DefaultArtifactDir + "/SmallLogo.png";
+ cmSystemTools::CopyAFile(templateFolder + "/SmallLogo.png", smallLogo,
+ false);
+ this->ConvertToWindowsSlash(smallLogo);
+ this->WriteString("<Image Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(smallLogo) << "\" />\n";
+ this->AddedFiles.push_back(smallLogo);
+
+ std::string logo = this->DefaultArtifactDir + "/Logo.png";
+ cmSystemTools::CopyAFile(templateFolder + "/Logo.png", logo, false);
+ this->ConvertToWindowsSlash(logo);
+ this->WriteString("<Image Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(logo) << "\" />\n";
+ this->AddedFiles.push_back(logo);
+
+ std::string applicationIcon =
+ this->DefaultArtifactDir + "/ApplicationIcon.png";
+ cmSystemTools::CopyAFile(templateFolder + "/ApplicationIcon.png",
+ applicationIcon, false);
+ this->ConvertToWindowsSlash(applicationIcon);
+ this->WriteString("<Image Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(applicationIcon) << "\" />\n";
+ this->AddedFiles.push_back(applicationIcon);
+}
+
+void cmVisualStudio10TargetGenerator::WriteMissingFilesWP81()
+{
+ std::string manifestFile =
+ this->DefaultArtifactDir + "/package.appxManifest";
+ std::string artifactDir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ this->ConvertToWindowsSlash(artifactDir);
+ std::string artifactDirXML = cmVS10EscapeXML(artifactDir);
+ std::string targetNameXML =
+ cmVS10EscapeXML(this->GeneratorTarget->GetName());
+
+ cmGeneratedFileStream fout(manifestFile.c_str());
+ fout.SetCopyIfDifferent(true);
+
+ /* clang-format off */
+ fout <<
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<Package xmlns=\"http://schemas.microsoft.com/appx/2010/manifest\""
+ " xmlns:m2=\"http://schemas.microsoft.com/appx/2013/manifest\""
+ " xmlns:mp=\"http://schemas.microsoft.com/appx/2014/phone/manifest\">\n"
+ "\t<Identity Name=\"" << this->GUID << "\" Publisher=\"CN=CMake\""
+ " Version=\"1.0.0.0\" />\n"
+ "\t<mp:PhoneIdentity PhoneProductId=\"" << this->GUID << "\""
+ " PhonePublisherId=\"00000000-0000-0000-0000-000000000000\"/>\n"
+ "\t<Properties>\n"
+ "\t\t<DisplayName>" << targetNameXML << "</DisplayName>\n"
+ "\t\t<PublisherDisplayName>CMake</PublisherDisplayName>\n"
+ "\t\t<Logo>" << artifactDirXML << "\\StoreLogo.png</Logo>\n"
+ "\t</Properties>\n"
+ "\t<Prerequisites>\n"
+ "\t\t<OSMinVersion>6.3.1</OSMinVersion>\n"
+ "\t\t<OSMaxVersionTested>6.3.1</OSMaxVersionTested>\n"
+ "\t</Prerequisites>\n"
+ "\t<Resources>\n"
+ "\t\t<Resource Language=\"x-generate\" />\n"
+ "\t</Resources>\n"
+ "\t<Applications>\n"
+ "\t\t<Application Id=\"App\""
+ " Executable=\"" << targetNameXML << ".exe\""
+ " EntryPoint=\"" << targetNameXML << ".App\">\n"
+ "\t\t\t<m2:VisualElements\n"
+ "\t\t\t\tDisplayName=\"" << targetNameXML << "\"\n"
+ "\t\t\t\tDescription=\"" << targetNameXML << "\"\n"
+ "\t\t\t\tBackgroundColor=\"#336699\"\n"
+ "\t\t\t\tForegroundText=\"light\"\n"
+ "\t\t\t\tSquare150x150Logo=\"" << artifactDirXML << "\\Logo.png\"\n"
+ "\t\t\t\tSquare30x30Logo=\"" << artifactDirXML << "\\SmallLogo.png\">\n"
+ "\t\t\t\t<m2:DefaultTile ShortName=\"" << targetNameXML << "\">\n"
+ "\t\t\t\t\t<m2:ShowNameOnTiles>\n"
+ "\t\t\t\t\t\t<m2:ShowOn Tile=\"square150x150Logo\" />\n"
+ "\t\t\t\t\t</m2:ShowNameOnTiles>\n"
+ "\t\t\t\t</m2:DefaultTile>\n"
+ "\t\t\t\t<m2:SplashScreen"
+ " Image=\"" << artifactDirXML << "\\SplashScreen.png\" />\n"
+ "\t\t\t</m2:VisualElements>\n"
+ "\t\t</Application>\n"
+ "\t</Applications>\n"
+ "</Package>\n";
+ /* clang-format on */
+
+ this->WriteCommonMissingFiles(manifestFile);
+}
+
+void cmVisualStudio10TargetGenerator::WriteMissingFilesWS80()
+{
+ std::string manifestFile =
+ this->DefaultArtifactDir + "/package.appxManifest";
+ std::string artifactDir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ this->ConvertToWindowsSlash(artifactDir);
+ std::string artifactDirXML = cmVS10EscapeXML(artifactDir);
+ std::string targetNameXML =
+ cmVS10EscapeXML(this->GeneratorTarget->GetName());
+
+ cmGeneratedFileStream fout(manifestFile.c_str());
+ fout.SetCopyIfDifferent(true);
+
+ /* clang-format off */
+ fout <<
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<Package xmlns=\"http://schemas.microsoft.com/appx/2010/manifest\">\n"
+ "\t<Identity Name=\"" << this->GUID << "\" Publisher=\"CN=CMake\""
+ " Version=\"1.0.0.0\" />\n"
+ "\t<Properties>\n"
+ "\t\t<DisplayName>" << targetNameXML << "</DisplayName>\n"
+ "\t\t<PublisherDisplayName>CMake</PublisherDisplayName>\n"
+ "\t\t<Logo>" << artifactDirXML << "\\StoreLogo.png</Logo>\n"
+ "\t</Properties>\n"
+ "\t<Prerequisites>\n"
+ "\t\t<OSMinVersion>6.2.1</OSMinVersion>\n"
+ "\t\t<OSMaxVersionTested>6.2.1</OSMaxVersionTested>\n"
+ "\t</Prerequisites>\n"
+ "\t<Resources>\n"
+ "\t\t<Resource Language=\"x-generate\" />\n"
+ "\t</Resources>\n"
+ "\t<Applications>\n"
+ "\t\t<Application Id=\"App\""
+ " Executable=\"" << targetNameXML << ".exe\""
+ " EntryPoint=\"" << targetNameXML << ".App\">\n"
+ "\t\t\t<VisualElements"
+ " DisplayName=\"" << targetNameXML << "\""
+ " Description=\"" << targetNameXML << "\""
+ " BackgroundColor=\"#336699\" ForegroundText=\"light\""
+ " Logo=\"" << artifactDirXML << "\\Logo.png\""
+ " SmallLogo=\"" << artifactDirXML << "\\SmallLogo.png\">\n"
+ "\t\t\t\t<DefaultTile ShowName=\"allLogos\""
+ " ShortName=\"" << targetNameXML << "\" />\n"
+ "\t\t\t\t<SplashScreen"
+ " Image=\"" << artifactDirXML << "\\SplashScreen.png\" />\n"
+ "\t\t\t</VisualElements>\n"
+ "\t\t</Application>\n"
+ "\t</Applications>\n"
+ "</Package>\n";
+ /* clang-format on */
+
+ this->WriteCommonMissingFiles(manifestFile);
+}
+
+void cmVisualStudio10TargetGenerator::WriteMissingFilesWS81()
+{
+ std::string manifestFile =
+ this->DefaultArtifactDir + "/package.appxManifest";
+ std::string artifactDir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ this->ConvertToWindowsSlash(artifactDir);
+ std::string artifactDirXML = cmVS10EscapeXML(artifactDir);
+ std::string targetNameXML =
+ cmVS10EscapeXML(this->GeneratorTarget->GetName());
+
+ cmGeneratedFileStream fout(manifestFile.c_str());
+ fout.SetCopyIfDifferent(true);
+
+ /* clang-format off */
+ fout <<
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<Package xmlns=\"http://schemas.microsoft.com/appx/2010/manifest\""
+ " xmlns:m2=\"http://schemas.microsoft.com/appx/2013/manifest\">\n"
+ "\t<Identity Name=\"" << this->GUID << "\" Publisher=\"CN=CMake\""
+ " Version=\"1.0.0.0\" />\n"
+ "\t<Properties>\n"
+ "\t\t<DisplayName>" << targetNameXML << "</DisplayName>\n"
+ "\t\t<PublisherDisplayName>CMake</PublisherDisplayName>\n"
+ "\t\t<Logo>" << artifactDirXML << "\\StoreLogo.png</Logo>\n"
+ "\t</Properties>\n"
+ "\t<Prerequisites>\n"
+ "\t\t<OSMinVersion>6.3</OSMinVersion>\n"
+ "\t\t<OSMaxVersionTested>6.3</OSMaxVersionTested>\n"
+ "\t</Prerequisites>\n"
+ "\t<Resources>\n"
+ "\t\t<Resource Language=\"x-generate\" />\n"
+ "\t</Resources>\n"
+ "\t<Applications>\n"
+ "\t\t<Application Id=\"App\""
+ " Executable=\"" << targetNameXML << ".exe\""
+ " EntryPoint=\"" << targetNameXML << ".App\">\n"
+ "\t\t\t<m2:VisualElements\n"
+ "\t\t\t\tDisplayName=\"" << targetNameXML << "\"\n"
+ "\t\t\t\tDescription=\"" << targetNameXML << "\"\n"
+ "\t\t\t\tBackgroundColor=\"#336699\"\n"
+ "\t\t\t\tForegroundText=\"light\"\n"
+ "\t\t\t\tSquare150x150Logo=\"" << artifactDirXML << "\\Logo.png\"\n"
+ "\t\t\t\tSquare30x30Logo=\"" << artifactDirXML << "\\SmallLogo.png\">\n"
+ "\t\t\t\t<m2:DefaultTile ShortName=\"" << targetNameXML << "\">\n"
+ "\t\t\t\t\t<m2:ShowNameOnTiles>\n"
+ "\t\t\t\t\t\t<m2:ShowOn Tile=\"square150x150Logo\" />\n"
+ "\t\t\t\t\t</m2:ShowNameOnTiles>\n"
+ "\t\t\t\t</m2:DefaultTile>\n"
+ "\t\t\t\t<m2:SplashScreen"
+ " Image=\"" << artifactDirXML << "\\SplashScreen.png\" />\n"
+ "\t\t\t</m2:VisualElements>\n"
+ "\t\t</Application>\n"
+ "\t</Applications>\n"
+ "</Package>\n";
+ /* clang-format on */
+
+ this->WriteCommonMissingFiles(manifestFile);
+}
+
+void cmVisualStudio10TargetGenerator::WriteMissingFilesWS10_0()
+{
+ std::string manifestFile =
+ this->DefaultArtifactDir + "/package.appxManifest";
+ std::string artifactDir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ this->ConvertToWindowsSlash(artifactDir);
+ std::string artifactDirXML = cmVS10EscapeXML(artifactDir);
+ std::string targetNameXML =
+ cmVS10EscapeXML(this->GeneratorTarget->GetName());
+
+ cmGeneratedFileStream fout(manifestFile.c_str());
+ fout.SetCopyIfDifferent(true);
+
+ /* clang-format off */
+ fout <<
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<Package\n\t"
+ "xmlns=\"http://schemas.microsoft.com/appx/manifest/foundation/windows10\""
+ "\txmlns:mp=\"http://schemas.microsoft.com/appx/2014/phone/manifest\"\n"
+ "\txmlns:uap=\"http://schemas.microsoft.com/appx/manifest/uap/windows10\""
+ "\n\tIgnorableNamespaces=\"uap mp\">\n\n"
+ "\t<Identity Name=\"" << this->GUID << "\" Publisher=\"CN=CMake\""
+ " Version=\"1.0.0.0\" />\n"
+ "\t<mp:PhoneIdentity PhoneProductId=\"" << this->GUID <<
+ "\" PhonePublisherId=\"00000000-0000-0000-0000-000000000000\"/>\n"
+ "\t<Properties>\n"
+ "\t\t<DisplayName>" << targetNameXML << "</DisplayName>\n"
+ "\t\t<PublisherDisplayName>CMake</PublisherDisplayName>\n"
+ "\t\t<Logo>" << artifactDirXML << "\\StoreLogo.png</Logo>\n"
+ "\t</Properties>\n"
+ "\t<Dependencies>\n"
+ "\t\t<TargetDeviceFamily Name=\"Windows.Universal\" "
+ "MinVersion=\"10.0.0.0\" MaxVersionTested=\"10.0.0.0\" />\n"
+ "\t</Dependencies>\n"
+
+ "\t<Resources>\n"
+ "\t\t<Resource Language=\"x-generate\" />\n"
+ "\t</Resources>\n"
+ "\t<Applications>\n"
+ "\t\t<Application Id=\"App\""
+ " Executable=\"" << targetNameXML << ".exe\""
+ " EntryPoint=\"" << targetNameXML << ".App\">\n"
+ "\t\t\t<uap:VisualElements\n"
+ "\t\t\t\tDisplayName=\"" << targetNameXML << "\"\n"
+ "\t\t\t\tDescription=\"" << targetNameXML << "\"\n"
+ "\t\t\t\tBackgroundColor=\"#336699\"\n"
+ "\t\t\t\tSquare150x150Logo=\"" << artifactDirXML << "\\Logo.png\"\n"
+ "\t\t\t\tSquare44x44Logo=\"" << artifactDirXML <<
+ "\\SmallLogo44x44.png\">\n"
+ "\t\t\t\t<uap:SplashScreen"
+ " Image=\"" << artifactDirXML << "\\SplashScreen.png\" />\n"
+ "\t\t\t</uap:VisualElements>\n"
+ "\t\t</Application>\n"
+ "\t</Applications>\n"
+ "</Package>\n";
+ /* clang-format on */
+
+ this->WriteCommonMissingFiles(manifestFile);
+}
+
+void cmVisualStudio10TargetGenerator::WriteCommonMissingFiles(
+ const std::string& manifestFile)
+{
+ std::string templateFolder =
+ cmSystemTools::GetCMakeRoot() + "/Templates/Windows";
+
+ std::string sourceFile = this->ConvertPath(manifestFile, false);
+ this->ConvertToWindowsSlash(sourceFile);
+ this->WriteString("<AppxManifest Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(sourceFile) << "\">\n";
+ this->WriteString("<SubType>Designer</SubType>\n", 3);
+ this->WriteString("</AppxManifest>\n", 2);
+ this->AddedFiles.push_back(sourceFile);
+
+ std::string smallLogo = this->DefaultArtifactDir + "/SmallLogo.png";
+ cmSystemTools::CopyAFile(templateFolder + "/SmallLogo.png", smallLogo,
+ false);
+ this->ConvertToWindowsSlash(smallLogo);
+ this->WriteString("<Image Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(smallLogo) << "\" />\n";
+ this->AddedFiles.push_back(smallLogo);
+
+ std::string smallLogo44 = this->DefaultArtifactDir + "/SmallLogo44x44.png";
+ cmSystemTools::CopyAFile(templateFolder + "/SmallLogo44x44.png", smallLogo44,
+ false);
+ this->ConvertToWindowsSlash(smallLogo44);
+ this->WriteString("<Image Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(smallLogo44) << "\" />\n";
+ this->AddedFiles.push_back(smallLogo44);
+
+ std::string logo = this->DefaultArtifactDir + "/Logo.png";
+ cmSystemTools::CopyAFile(templateFolder + "/Logo.png", logo, false);
+ this->ConvertToWindowsSlash(logo);
+ this->WriteString("<Image Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(logo) << "\" />\n";
+ this->AddedFiles.push_back(logo);
+
+ std::string storeLogo = this->DefaultArtifactDir + "/StoreLogo.png";
+ cmSystemTools::CopyAFile(templateFolder + "/StoreLogo.png", storeLogo,
+ false);
+ this->ConvertToWindowsSlash(storeLogo);
+ this->WriteString("<Image Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(storeLogo) << "\" />\n";
+ this->AddedFiles.push_back(storeLogo);
+
+ std::string splashScreen = this->DefaultArtifactDir + "/SplashScreen.png";
+ cmSystemTools::CopyAFile(templateFolder + "/SplashScreen.png", splashScreen,
+ false);
+ this->ConvertToWindowsSlash(splashScreen);
+ this->WriteString("<Image Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(splashScreen) << "\" />\n";
+ this->AddedFiles.push_back(splashScreen);
+
+ // This file has already been added to the build so don't copy it
+ std::string keyFile = this->DefaultArtifactDir + "/Windows_TemporaryKey.pfx";
+ this->ConvertToWindowsSlash(keyFile);
+ this->WriteString("<None Include=\"", 2);
+ (*this->BuildFileStream) << cmVS10EscapeXML(keyFile) << "\" />\n";
+}
+
+bool cmVisualStudio10TargetGenerator::ForceOld(const std::string& source) const
+{
+ HANDLE h =
+ CreateFileW(cmSystemTools::ConvertToWindowsExtendedPath(source).c_str(),
+ FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, 0);
+ if (!h) {
+ return false;
+ }
+
+ FILETIME const ftime_20010101 = { 3365781504u, 29389701u };
+ if (!SetFileTime(h, &ftime_20010101, &ftime_20010101, &ftime_20010101)) {
+ CloseHandle(h);
+ return false;
+ }
+
+ CloseHandle(h);
+ return true;
+}
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
new file mode 100644
index 0000000..109a100
--- /dev/null
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -0,0 +1,169 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmVisualStudioTargetGenerator_h
+#define cmVisualStudioTargetGenerator_h
+
+#include "cmStandardIncludes.h"
+
+class cmMakefile;
+class cmGeneratorTarget;
+class cmGeneratedFileStream;
+class cmGlobalVisualStudio10Generator;
+class cmSourceFile;
+class cmCustomCommand;
+class cmLocalVisualStudio7Generator;
+class cmComputeLinkInformation;
+class cmVisualStudioGeneratorOptions;
+struct cmIDEFlagTable;
+#include "cmSourceGroup.h"
+
+class cmVisualStudio10TargetGenerator
+{
+public:
+ cmVisualStudio10TargetGenerator(cmGeneratorTarget* target,
+ cmGlobalVisualStudio10Generator* gg);
+ ~cmVisualStudio10TargetGenerator();
+ void Generate();
+ // used by cmVisualStudioGeneratorOptions
+ void WritePlatformConfigTag(const char* tag, const std::string& config,
+ int indentLevel, const char* attribute = 0,
+ const char* end = 0, std::ostream* strm = 0);
+
+private:
+ struct ToolSource
+ {
+ cmSourceFile const* SourceFile;
+ bool RelativePath;
+ };
+ struct ToolSources : public std::vector<ToolSource>
+ {
+ };
+
+ std::string ConvertPath(std::string const& path, bool forceRelative);
+ void ConvertToWindowsSlash(std::string& s);
+ void WriteString(const char* line, int indentLevel);
+ void WriteProjectConfigurations();
+ void WriteProjectConfigurationValues();
+ void WriteMSToolConfigurationValues(std::string const& config);
+ void WriteHeaderSource(cmSourceFile const* sf);
+ void WriteExtraSource(cmSourceFile const* sf);
+ void WriteNsightTegraConfigurationValues(std::string const& config);
+ void WriteSource(std::string const& tool, cmSourceFile const* sf,
+ const char* end = 0);
+ void WriteSources(std::string const& tool,
+ std::vector<cmSourceFile const*> const&);
+ void WriteAllSources();
+ void WriteDotNetReferences();
+ void WriteEmbeddedResourceGroup();
+ void WriteWinRTReferences();
+ void WriteWinRTPackageCertificateKeyFile();
+ void WriteXamlFilesGroup();
+ void WritePathAndIncrementalLinkOptions();
+ void WriteItemDefinitionGroups();
+ void VerifyNecessaryFiles();
+ void WriteMissingFiles();
+ void WriteMissingFilesWP80();
+ void WriteMissingFilesWP81();
+ void WriteMissingFilesWS80();
+ void WriteMissingFilesWS81();
+ void WriteMissingFilesWS10_0();
+ void WritePlatformExtensions();
+ void WriteSinglePlatformExtension(std::string const& extension,
+ std::string const& version);
+ void WriteSDKReferences();
+ void WriteSingleSDKReference(std::string const& extension,
+ std::string const& version);
+ void WriteCommonMissingFiles(const std::string& manifestFile);
+ void WriteTargetSpecificReferences();
+
+ bool ComputeClOptions();
+ bool ComputeClOptions(std::string const& configName);
+ void WriteClOptions(std::string const& config,
+ std::vector<std::string> const& includes);
+ bool ComputeRcOptions();
+ bool ComputeRcOptions(std::string const& config);
+ void WriteRCOptions(std::string const& config,
+ std::vector<std::string> const& includes);
+ bool ComputeMasmOptions();
+ bool ComputeMasmOptions(std::string const& config);
+ void WriteMasmOptions(std::string const& config,
+ std::vector<std::string> const& includes);
+ bool ComputeLinkOptions();
+ bool ComputeLinkOptions(std::string const& config);
+ void WriteLinkOptions(std::string const& config);
+ void WriteMidlOptions(std::string const& config,
+ std::vector<std::string> const& includes);
+ void WriteAntBuildOptions(std::string const& config);
+ void OutputLinkIncremental(std::string const& configName);
+ void WriteCustomRule(cmSourceFile const* source,
+ cmCustomCommand const& command);
+ void WriteCustomCommands();
+ void WriteCustomCommand(cmSourceFile const* sf);
+ void WriteGroups();
+ void WriteProjectReferences();
+ void WriteApplicationTypeSettings();
+ bool OutputSourceSpecificFlags(cmSourceFile const* source);
+ void AddLibraries(cmComputeLinkInformation& cli,
+ std::vector<std::string>& libVec);
+ void WriteLibOptions(std::string const& config);
+ void WriteManifestOptions(std::string const& config);
+ void WriteEvents(std::string const& configName);
+ void WriteEvent(const char* name,
+ std::vector<cmCustomCommand> const& commands,
+ std::string const& configName);
+ void WriteGroupSources(const char* name, ToolSources const& sources,
+ std::vector<cmSourceGroup>&);
+ void AddMissingSourceGroups(std::set<cmSourceGroup*>& groupsUsed,
+ const std::vector<cmSourceGroup>& allGroups);
+ bool IsResxHeader(const std::string& headerFile);
+ bool IsXamlHeader(const std::string& headerFile);
+ bool IsXamlSource(const std::string& headerFile);
+
+ cmIDEFlagTable const* GetClFlagTable() const;
+ cmIDEFlagTable const* GetRcFlagTable() const;
+ cmIDEFlagTable const* GetLibFlagTable() const;
+ cmIDEFlagTable const* GetLinkFlagTable() const;
+ cmIDEFlagTable const* GetMasmFlagTable() const;
+
+ bool ForceOld(const std::string& source) const;
+
+private:
+ typedef cmVisualStudioGeneratorOptions Options;
+ typedef std::map<std::string, Options*> OptionsMap;
+ OptionsMap ClOptions;
+ OptionsMap RcOptions;
+ OptionsMap MasmOptions;
+ OptionsMap LinkOptions;
+ std::string PathToVcxproj;
+ std::vector<std::string> Configurations;
+ cmGeneratorTarget* GeneratorTarget;
+ cmMakefile* Makefile;
+ std::string Platform;
+ std::string GUID;
+ std::string Name;
+ bool MSTools;
+ bool NsightTegra;
+ int NsightTegraVersion[4];
+ bool TargetCompileAsWinRT;
+ cmGlobalVisualStudio10Generator* GlobalGenerator;
+ cmGeneratedFileStream* BuildFileStream;
+ cmLocalVisualStudio7Generator* LocalGenerator;
+ std::set<cmSourceFile const*> SourcesVisited;
+ bool IsMissingFiles;
+ std::vector<std::string> AddedFiles;
+ std::string DefaultArtifactDir;
+
+ typedef std::map<std::string, ToolSources> ToolSourceMap;
+ ToolSourceMap Tools;
+};
+
+#endif
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
new file mode 100644
index 0000000..3b31d7b
--- /dev/null
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -0,0 +1,339 @@
+#include "cmVisualStudioGeneratorOptions.h"
+
+#include "cmOutputConverter.h"
+#include "cmSystemTools.h"
+#include "cmVisualStudio10TargetGenerator.h"
+
+static std::string cmVisualStudio10GeneratorOptionsEscapeForXML(
+ std::string ret)
+{
+ cmSystemTools::ReplaceString(ret, ";", "%3B");
+ cmSystemTools::ReplaceString(ret, "&", "&amp;");
+ cmSystemTools::ReplaceString(ret, "<", "&lt;");
+ cmSystemTools::ReplaceString(ret, ">", "&gt;");
+ return ret;
+}
+
+static std::string cmVisualStudioGeneratorOptionsEscapeForXML(std::string ret)
+{
+ cmSystemTools::ReplaceString(ret, "&", "&amp;");
+ cmSystemTools::ReplaceString(ret, "\"", "&quot;");
+ cmSystemTools::ReplaceString(ret, "<", "&lt;");
+ cmSystemTools::ReplaceString(ret, ">", "&gt;");
+ cmSystemTools::ReplaceString(ret, "\n", "&#x0D;&#x0A;");
+ return ret;
+}
+
+cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions(
+ cmLocalVisualStudioGenerator* lg, Tool tool,
+ cmVisualStudio10TargetGenerator* g)
+ : cmIDEOptions()
+ , LocalGenerator(lg)
+ , Version(lg->GetVersion())
+ , CurrentTool(tool)
+ , TargetGenerator(g)
+{
+ // Preprocessor definitions are not allowed for linker tools.
+ this->AllowDefine = (tool != Linker);
+
+ // Slash options are allowed for VS.
+ this->AllowSlash = true;
+
+ this->FortranRuntimeDebug = false;
+ this->FortranRuntimeDLL = false;
+ this->FortranRuntimeMT = false;
+}
+
+cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions(
+ cmLocalVisualStudioGenerator* lg, Tool tool, cmVS7FlagTable const* table,
+ cmVS7FlagTable const* extraTable, cmVisualStudio10TargetGenerator* g)
+ : cmIDEOptions()
+ , LocalGenerator(lg)
+ , Version(lg->GetVersion())
+ , CurrentTool(tool)
+ , TargetGenerator(g)
+{
+ // Store the given flag tables.
+ this->AddTable(table);
+ this->AddTable(extraTable);
+
+ // Preprocessor definitions are not allowed for linker tools.
+ this->AllowDefine = (tool != Linker);
+
+ // Slash options are allowed for VS.
+ this->AllowSlash = true;
+
+ this->FortranRuntimeDebug = false;
+ this->FortranRuntimeDLL = false;
+ this->FortranRuntimeMT = false;
+}
+
+void cmVisualStudioGeneratorOptions::AddTable(cmVS7FlagTable const* table)
+{
+ if (table) {
+ for (int i = 0; i < FlagTableCount; ++i) {
+ if (!this->FlagTable[i]) {
+ this->FlagTable[i] = table;
+ break;
+ }
+ }
+ }
+}
+
+void cmVisualStudioGeneratorOptions::FixExceptionHandlingDefault()
+{
+ // Exception handling is on by default because the platform file has
+ // "/EHsc" in the flags. Normally, that will override this
+ // initialization to off, but the user has the option of removing
+ // the flag to disable exception handling. When the user does
+ // remove the flag we need to override the IDE default of on.
+ switch (this->Version) {
+ case cmGlobalVisualStudioGenerator::VS7:
+ case cmGlobalVisualStudioGenerator::VS71:
+ this->FlagMap["ExceptionHandling"] = "FALSE";
+ break;
+ case cmGlobalVisualStudioGenerator::VS10:
+ case cmGlobalVisualStudioGenerator::VS11:
+ case cmGlobalVisualStudioGenerator::VS12:
+ case cmGlobalVisualStudioGenerator::VS14:
+ // by default VS puts <ExceptionHandling></ExceptionHandling> empty
+ // for a project, to make our projects look the same put a new line
+ // and space over for the closing </ExceptionHandling> as the default
+ // value
+ this->FlagMap["ExceptionHandling"] = "\n ";
+ break;
+ default:
+ this->FlagMap["ExceptionHandling"] = "0";
+ break;
+ }
+}
+
+void cmVisualStudioGeneratorOptions::SetVerboseMakefile(bool verbose)
+{
+ // If verbose makefiles have been requested and the /nologo option
+ // was not given explicitly in the flags we want to add an attribute
+ // to the generated project to disable logo suppression. Otherwise
+ // the GUI default is to enable suppression.
+ //
+ // On Visual Studio 10 (and later!), the value of this attribute should be
+ // an empty string, instead of "FALSE", in order to avoid a warning:
+ // "cl ... warning D9035: option 'nologo-' has been deprecated"
+ //
+ if (verbose &&
+ this->FlagMap.find("SuppressStartupBanner") == this->FlagMap.end()) {
+ this->FlagMap["SuppressStartupBanner"] =
+ this->Version < cmGlobalVisualStudioGenerator::VS10 ? "FALSE" : "";
+ }
+}
+
+bool cmVisualStudioGeneratorOptions::IsDebug() const
+{
+ return this->FlagMap.find("DebugInformationFormat") != this->FlagMap.end();
+}
+
+bool cmVisualStudioGeneratorOptions::IsWinRt() const
+{
+ return this->FlagMap.find("CompileAsWinRT") != this->FlagMap.end();
+}
+
+bool cmVisualStudioGeneratorOptions::UsingUnicode() const
+{
+ // Look for the a _UNICODE definition.
+ for (std::vector<std::string>::const_iterator di = this->Defines.begin();
+ di != this->Defines.end(); ++di) {
+ if (*di == "_UNICODE") {
+ return true;
+ }
+ }
+ return false;
+}
+bool cmVisualStudioGeneratorOptions::UsingSBCS() const
+{
+ // Look for the a _SBCS definition.
+ for (std::vector<std::string>::const_iterator di = this->Defines.begin();
+ di != this->Defines.end(); ++di) {
+ if (*di == "_SBCS") {
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmVisualStudioGeneratorOptions::Parse(const char* flags)
+{
+ // Parse the input string as a windows command line since the string
+ // is intended for writing directly into the build files.
+ std::vector<std::string> args;
+ cmSystemTools::ParseWindowsCommandLine(flags, args);
+
+ // Process flags that need to be represented specially in the IDE
+ // project file.
+ for (std::vector<std::string>::iterator ai = args.begin(); ai != args.end();
+ ++ai) {
+ this->HandleFlag(ai->c_str());
+ }
+}
+
+void cmVisualStudioGeneratorOptions::ParseFinish()
+{
+ if (this->CurrentTool == FortranCompiler) {
+ // "RuntimeLibrary" attribute values:
+ // "rtMultiThreaded", "0", /threads /libs:static
+ // "rtMultiThreadedDLL", "2", /threads /libs:dll
+ // "rtMultiThreadedDebug", "1", /threads /dbglibs /libs:static
+ // "rtMultiThreadedDebugDLL", "3", /threads /dbglibs /libs:dll
+ // These seem unimplemented by the IDE:
+ // "rtSingleThreaded", "4", /libs:static
+ // "rtSingleThreadedDLL", "10", /libs:dll
+ // "rtSingleThreadedDebug", "5", /dbglibs /libs:static
+ // "rtSingleThreadedDebugDLL", "11", /dbglibs /libs:dll
+ std::string rl = "rtMultiThreaded";
+ rl += this->FortranRuntimeDebug ? "Debug" : "";
+ rl += this->FortranRuntimeDLL ? "DLL" : "";
+ this->FlagMap["RuntimeLibrary"] = rl;
+ }
+}
+
+void cmVisualStudioGeneratorOptions::StoreUnknownFlag(const char* flag)
+{
+ // Look for Intel Fortran flags that do not map well in the flag table.
+ if (this->CurrentTool == FortranCompiler) {
+ if (strcmp(flag, "/dbglibs") == 0) {
+ this->FortranRuntimeDebug = true;
+ return;
+ }
+ if (strcmp(flag, "/threads") == 0) {
+ this->FortranRuntimeMT = true;
+ return;
+ }
+ if (strcmp(flag, "/libs:dll") == 0) {
+ this->FortranRuntimeDLL = true;
+ return;
+ }
+ if (strcmp(flag, "/libs:static") == 0) {
+ this->FortranRuntimeDLL = false;
+ return;
+ }
+ }
+
+ // This option is not known. Store it in the output flags.
+ this->FlagString += " ";
+ this->FlagString += cmOutputConverter::EscapeWindowsShellArgument(
+ flag, cmOutputConverter::Shell_Flag_AllowMakeVariables |
+ cmOutputConverter::Shell_Flag_VSIDE);
+}
+
+void cmVisualStudioGeneratorOptions::SetConfiguration(const char* config)
+{
+ this->Configuration = config;
+}
+
+void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions(
+ std::ostream& fout, const char* prefix, const char* suffix,
+ const std::string& lang)
+{
+ if (this->Defines.empty()) {
+ return;
+ }
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
+ // if there are configuration specific flags, then
+ // use the configuration specific tag for PreprocessorDefinitions
+ if (!this->Configuration.empty()) {
+ fout << prefix;
+ this->TargetGenerator->WritePlatformConfigTag(
+ "PreprocessorDefinitions", this->Configuration.c_str(), 0, 0, 0,
+ &fout);
+ } else {
+ fout << prefix << "<PreprocessorDefinitions>";
+ }
+ } else {
+ fout << prefix << "PreprocessorDefinitions=\"";
+ }
+ const char* sep = "";
+ for (std::vector<std::string>::const_iterator di = this->Defines.begin();
+ di != this->Defines.end(); ++di) {
+ // Escape the definition for the compiler.
+ std::string define;
+ if (this->Version < cmGlobalVisualStudioGenerator::VS10) {
+ define = this->LocalGenerator->EscapeForShell(di->c_str(), true);
+ } else {
+ define = *di;
+ }
+ // Escape this flag for the IDE.
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
+ define = cmVisualStudio10GeneratorOptionsEscapeForXML(define);
+
+ if (lang == "RC") {
+ cmSystemTools::ReplaceString(define, "\"", "\\\"");
+ }
+ } else {
+ define = cmVisualStudioGeneratorOptionsEscapeForXML(define);
+ }
+ // Store the flag in the project file.
+ fout << sep << define;
+ sep = ";";
+ }
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
+ fout << ";%(PreprocessorDefinitions)</PreprocessorDefinitions>" << suffix;
+ } else {
+ fout << "\"" << suffix;
+ }
+}
+
+void cmVisualStudioGeneratorOptions::OutputFlagMap(std::ostream& fout,
+ const char* indent)
+{
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
+ for (std::map<std::string, FlagValue>::iterator m = this->FlagMap.begin();
+ m != this->FlagMap.end(); ++m) {
+ fout << indent;
+ if (!this->Configuration.empty()) {
+ this->TargetGenerator->WritePlatformConfigTag(
+ m->first.c_str(), this->Configuration.c_str(), 0, 0, 0, &fout);
+ } else {
+ fout << "<" << m->first << ">";
+ }
+ const char* sep = "";
+ for (std::vector<std::string>::iterator i = m->second.begin();
+ i != m->second.end(); ++i) {
+ fout << sep << cmVisualStudio10GeneratorOptionsEscapeForXML(*i);
+ sep = ";";
+ }
+ fout << "</" << m->first << ">\n";
+ }
+ } else {
+ for (std::map<std::string, FlagValue>::iterator m = this->FlagMap.begin();
+ m != this->FlagMap.end(); ++m) {
+ fout << indent << m->first << "=\"";
+ const char* sep = "";
+ for (std::vector<std::string>::iterator i = m->second.begin();
+ i != m->second.end(); ++i) {
+ fout << sep << cmVisualStudioGeneratorOptionsEscapeForXML(*i);
+ sep = ";";
+ }
+ fout << "\"\n";
+ }
+ }
+}
+
+void cmVisualStudioGeneratorOptions::OutputAdditionalOptions(
+ std::ostream& fout, const char* prefix, const char* suffix)
+{
+ if (!this->FlagString.empty()) {
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
+ fout << prefix;
+ if (!this->Configuration.empty()) {
+ this->TargetGenerator->WritePlatformConfigTag(
+ "AdditionalOptions", this->Configuration.c_str(), 0, 0, 0, &fout);
+ } else {
+ fout << "<AdditionalOptions>";
+ }
+ fout << cmVisualStudio10GeneratorOptionsEscapeForXML(this->FlagString)
+ << " %(AdditionalOptions)</AdditionalOptions>\n";
+ } else {
+ fout << prefix << "AdditionalOptions=\"";
+ fout << cmVisualStudioGeneratorOptionsEscapeForXML(this->FlagString);
+ fout << "\"" << suffix;
+ }
+ }
+}
diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h
new file mode 100644
index 0000000..219b009
--- /dev/null
+++ b/Source/cmVisualStudioGeneratorOptions.h
@@ -0,0 +1,85 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmVisualStudioGeneratorOptions_h
+#define cmVisualStudioGeneratorOptions_h
+
+#include "cmLocalVisualStudioGenerator.h"
+
+#include "cmIDEOptions.h"
+typedef cmIDEFlagTable cmVS7FlagTable;
+
+class cmVisualStudio10TargetGenerator;
+
+class cmVisualStudioGeneratorOptions : public cmIDEOptions
+{
+public:
+ // Construct an options table for a given tool.
+ enum Tool
+ {
+ Compiler,
+ ResourceCompiler,
+ MasmCompiler,
+ Linker,
+ FortranCompiler
+ };
+ cmVisualStudioGeneratorOptions(cmLocalVisualStudioGenerator* lg, Tool tool,
+ cmVS7FlagTable const* table,
+ cmVS7FlagTable const* extraTable = 0,
+ cmVisualStudio10TargetGenerator* g = 0);
+
+ cmVisualStudioGeneratorOptions(cmLocalVisualStudioGenerator* lg, Tool tool,
+ cmVisualStudio10TargetGenerator* g = 0);
+
+ // Add a table of flags.
+ void AddTable(cmVS7FlagTable const* table);
+
+ // Store options from command line flags.
+ void Parse(const char* flags);
+ void ParseFinish();
+
+ // Fix the ExceptionHandling option to default to off.
+ void FixExceptionHandlingDefault();
+
+ // Store options for verbose builds.
+ void SetVerboseMakefile(bool verbose);
+
+ // Check for specific options.
+ bool UsingUnicode() const;
+ bool UsingSBCS() const;
+
+ bool IsDebug() const;
+ bool IsWinRt() const;
+ // Write options to output.
+ void OutputPreprocessorDefinitions(std::ostream& fout, const char* prefix,
+ const char* suffix,
+ const std::string& lang);
+ void OutputFlagMap(std::ostream& fout, const char* indent);
+ void OutputAdditionalOptions(std::ostream& fout, const char* prefix,
+ const char* suffix);
+ void SetConfiguration(const char* config);
+
+private:
+ cmLocalVisualStudioGenerator* LocalGenerator;
+ cmGlobalVisualStudioGenerator::VSVersion Version;
+
+ std::string Configuration;
+ Tool CurrentTool;
+ cmVisualStudio10TargetGenerator* TargetGenerator;
+
+ bool FortranRuntimeDebug;
+ bool FortranRuntimeDLL;
+ bool FortranRuntimeMT;
+
+ virtual void StoreUnknownFlag(const char* flag);
+};
+
+#endif
diff --git a/Source/cmVisualStudioSlnData.cxx b/Source/cmVisualStudioSlnData.cxx
new file mode 100644
index 0000000..7ffa0b5
--- /dev/null
+++ b/Source/cmVisualStudioSlnData.cxx
@@ -0,0 +1,58 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2013 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmVisualStudioSlnData.h"
+
+const cmSlnProjectEntry* cmSlnData::GetProjectByGUID(
+ const std::string& projectGUID) const
+{
+ ProjectStorage::const_iterator it(ProjectsByGUID.find(projectGUID));
+ if (it != ProjectsByGUID.end())
+ return &it->second;
+ else
+ return NULL;
+}
+
+const cmSlnProjectEntry* cmSlnData::GetProjectByName(
+ const std::string& projectName) const
+{
+ ProjectStringIndex::const_iterator it(ProjectNameIndex.find(projectName));
+ if (it != ProjectNameIndex.end())
+ return &it->second->second;
+ else
+ return NULL;
+}
+
+std::vector<cmSlnProjectEntry> cmSlnData::GetProjects() const
+{
+ ProjectStringIndex::const_iterator it(this->ProjectNameIndex.begin()),
+ itEnd(this->ProjectNameIndex.end());
+ std::vector<cmSlnProjectEntry> result;
+ for (; it != itEnd; ++it)
+ result.push_back(it->second->second);
+ return result;
+}
+
+cmSlnProjectEntry* cmSlnData::AddProject(
+ const std::string& projectGUID, const std::string& projectName,
+ const std::string& projectRelativePath)
+{
+ ProjectStorage::iterator it(ProjectsByGUID.find(projectGUID));
+ if (it != ProjectsByGUID.end())
+ return NULL;
+ it = ProjectsByGUID
+ .insert(ProjectStorage::value_type(
+ projectGUID,
+ cmSlnProjectEntry(projectGUID, projectName, projectRelativePath)))
+ .first;
+ ProjectNameIndex[projectName] = it;
+ return &it->second;
+}
diff --git a/Source/cmVisualStudioSlnData.h b/Source/cmVisualStudioSlnData.h
new file mode 100644
index 0000000..4508370
--- /dev/null
+++ b/Source/cmVisualStudioSlnData.h
@@ -0,0 +1,59 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2013 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmVisualStudioSlnData_h
+#define cmVisualStudioSlnData_h
+
+#include "cmStandardIncludes.h"
+
+class cmSlnProjectEntry
+{
+public:
+ cmSlnProjectEntry() {}
+ cmSlnProjectEntry(const std::string& guid, const std::string& name,
+ const std::string& relativePath)
+ : Guid(guid)
+ , Name(name)
+ , RelativePath(relativePath)
+ {
+ }
+
+ std::string GetGUID() const { return Guid; }
+ std::string GetName() const { return Name; }
+ std::string GetRelativePath() const { return RelativePath; }
+
+private:
+ std::string Guid, Name, RelativePath;
+};
+
+class cmSlnData
+{
+public:
+ const cmSlnProjectEntry* GetProjectByGUID(
+ const std::string& projectGUID) const;
+
+ const cmSlnProjectEntry* GetProjectByName(
+ const std::string& projectName) const;
+
+ std::vector<cmSlnProjectEntry> GetProjects() const;
+
+ cmSlnProjectEntry* AddProject(const std::string& projectGUID,
+ const std::string& projectName,
+ const std::string& projectRelativePath);
+
+private:
+ typedef std::map<std::string, cmSlnProjectEntry> ProjectStorage;
+ ProjectStorage ProjectsByGUID;
+ typedef std::map<std::string, ProjectStorage::iterator> ProjectStringIndex;
+ ProjectStringIndex ProjectNameIndex;
+};
+
+#endif
diff --git a/Source/cmVisualStudioSlnParser.cxx b/Source/cmVisualStudioSlnParser.cxx
new file mode 100644
index 0000000..7d7bb5b
--- /dev/null
+++ b/Source/cmVisualStudioSlnParser.cxx
@@ -0,0 +1,637 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2013 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmVisualStudioSlnParser.h"
+
+#include "cmSystemTools.h"
+#include "cmVisualStudioSlnData.h"
+#include <cmsys/FStream.hxx>
+
+#include <cassert>
+#include <stack>
+
+namespace {
+enum LineFormat
+{
+ LineMultiValueTag,
+ LineSingleValueTag,
+ LineKeyValuePair,
+ LineVerbatim
+};
+}
+
+class cmVisualStudioSlnParser::ParsedLine
+{
+public:
+ bool IsComment() const;
+ bool IsKeyValuePair() const;
+
+ const std::string& GetTag() const { return this->Tag; }
+ const std::string& GetArg() const { return this->Arg.first; }
+ std::string GetArgVerbatim() const;
+ size_t GetValueCount() const { return this->Values.size(); }
+ const std::string& GetValue(size_t idxValue) const;
+ std::string GetValueVerbatim(size_t idxValue) const;
+
+ void SetTag(const std::string& tag) { this->Tag = tag; }
+ void SetArg(const std::string& arg) { this->Arg = StringData(arg, false); }
+ void SetQuotedArg(const std::string& arg)
+ {
+ this->Arg = StringData(arg, true);
+ }
+ void AddValue(const std::string& value)
+ {
+ this->Values.push_back(StringData(value, false));
+ }
+ void AddQuotedValue(const std::string& value)
+ {
+ this->Values.push_back(StringData(value, true));
+ }
+
+ void CopyVerbatim(const std::string& line) { this->Tag = line; }
+
+private:
+ typedef std::pair<std::string, bool> StringData;
+ std::string Tag;
+ StringData Arg;
+ std::vector<StringData> Values;
+ static const std::string BadString;
+ static const std::string Quote;
+};
+
+const std::string cmVisualStudioSlnParser::ParsedLine::BadString;
+const std::string cmVisualStudioSlnParser::ParsedLine::Quote("\"");
+
+bool cmVisualStudioSlnParser::ParsedLine::IsComment() const
+{
+ assert(!this->Tag.empty());
+ return (this->Tag[0] == '#');
+}
+
+bool cmVisualStudioSlnParser::ParsedLine::IsKeyValuePair() const
+{
+ assert(!this->Tag.empty());
+ return this->Arg.first.empty() && this->Values.size() == 1;
+}
+
+std::string cmVisualStudioSlnParser::ParsedLine::GetArgVerbatim() const
+{
+ if (this->Arg.second)
+ return Quote + this->Arg.first + Quote;
+ else
+ return this->Arg.first;
+}
+
+const std::string& cmVisualStudioSlnParser::ParsedLine::GetValue(
+ size_t idxValue) const
+{
+ if (idxValue < this->Values.size())
+ return this->Values[idxValue].first;
+ else
+ return BadString;
+}
+
+std::string cmVisualStudioSlnParser::ParsedLine::GetValueVerbatim(
+ size_t idxValue) const
+{
+ if (idxValue < this->Values.size()) {
+ const StringData& data = this->Values[idxValue];
+ if (data.second)
+ return Quote + data.first + Quote;
+ else
+ return data.first;
+ } else
+ return BadString;
+}
+
+class cmVisualStudioSlnParser::State
+{
+public:
+ explicit State(DataGroupSet requestedData);
+
+ size_t GetCurrentLine() const { return this->CurrentLine; }
+ bool ReadLine(std::istream& input, std::string& line);
+
+ LineFormat NextLineFormat() const;
+
+ bool Process(const cmVisualStudioSlnParser::ParsedLine& line,
+ cmSlnData& output, cmVisualStudioSlnParser::ResultData& result);
+
+ bool Finished(cmVisualStudioSlnParser::ResultData& result);
+
+private:
+ enum FileState
+ {
+ FileStateStart,
+ FileStateTopLevel,
+ FileStateProject,
+ FileStateProjectDependencies,
+ FileStateGlobal,
+ FileStateSolutionConfigurations,
+ FileStateProjectConfigurations,
+ FileStateSolutionFilters,
+ FileStateGlobalSection,
+ FileStateIgnore
+ };
+ std::stack<FileState> Stack;
+ std::string EndIgnoreTag;
+ DataGroupSet RequestedData;
+ size_t CurrentLine;
+
+ void IgnoreUntilTag(const std::string& endTag);
+};
+
+cmVisualStudioSlnParser::State::State(DataGroupSet requestedData)
+ : RequestedData(requestedData)
+ , CurrentLine(0)
+{
+ if (this->RequestedData.test(DataGroupProjectDependenciesBit))
+ this->RequestedData.set(DataGroupProjectsBit);
+ this->Stack.push(FileStateStart);
+}
+
+bool cmVisualStudioSlnParser::State::ReadLine(std::istream& input,
+ std::string& line)
+{
+ ++this->CurrentLine;
+ return !std::getline(input, line).fail();
+}
+
+LineFormat cmVisualStudioSlnParser::State::NextLineFormat() const
+{
+ switch (this->Stack.top()) {
+ case FileStateStart:
+ return LineVerbatim;
+ case FileStateTopLevel:
+ return LineMultiValueTag;
+ case FileStateProject:
+ return LineSingleValueTag;
+ case FileStateProjectDependencies:
+ return LineKeyValuePair;
+ case FileStateGlobal:
+ return LineSingleValueTag;
+ case FileStateSolutionConfigurations:
+ return LineKeyValuePair;
+ case FileStateProjectConfigurations:
+ return LineKeyValuePair;
+ case FileStateSolutionFilters:
+ return LineKeyValuePair;
+ case FileStateGlobalSection:
+ return LineKeyValuePair;
+ case FileStateIgnore:
+ return LineVerbatim;
+ default:
+ assert(false);
+ return LineVerbatim;
+ }
+}
+
+bool cmVisualStudioSlnParser::State::Process(
+ const cmVisualStudioSlnParser::ParsedLine& line, cmSlnData& output,
+ cmVisualStudioSlnParser::ResultData& result)
+{
+ assert(!line.IsComment());
+ switch (this->Stack.top()) {
+ case FileStateStart:
+ if (!cmSystemTools::StringStartsWith(
+ line.GetTag().c_str(), "Microsoft Visual Studio Solution File")) {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ this->Stack.pop();
+ this->Stack.push(FileStateTopLevel);
+ break;
+ case FileStateTopLevel:
+ if (line.GetTag().compare("Project") == 0) {
+ if (line.GetValueCount() != 3) {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ if (this->RequestedData.test(DataGroupProjectsBit)) {
+ if (!output.AddProject(line.GetValue(2), line.GetValue(0),
+ line.GetValue(1))) {
+ result.SetError(ResultErrorInputData, this->GetCurrentLine());
+ return false;
+ }
+ this->Stack.push(FileStateProject);
+ } else
+ this->IgnoreUntilTag("EndProject");
+ } else if (line.GetTag().compare("Global") == 0)
+ this->Stack.push(FileStateGlobal);
+ else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateProject:
+ if (line.GetTag().compare("EndProject") == 0)
+ this->Stack.pop();
+ else if (line.GetTag().compare("ProjectSection") == 0) {
+ if (line.GetArg().compare("ProjectDependencies") == 0 &&
+ line.GetValue(0).compare("postProject") == 0) {
+ if (this->RequestedData.test(DataGroupProjectDependenciesBit))
+ this->Stack.push(FileStateProjectDependencies);
+ else
+ this->IgnoreUntilTag("EndProjectSection");
+ } else
+ this->IgnoreUntilTag("EndProjectSection");
+ } else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateProjectDependencies:
+ if (line.GetTag().compare("EndProjectSection") == 0)
+ this->Stack.pop();
+ else if (line.IsKeyValuePair())
+ // implement dependency storing here, once needed
+ ;
+ else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateGlobal:
+ if (line.GetTag().compare("EndGlobal") == 0)
+ this->Stack.pop();
+ else if (line.GetTag().compare("GlobalSection") == 0) {
+ if (line.GetArg().compare("SolutionConfigurationPlatforms") == 0 &&
+ line.GetValue(0).compare("preSolution") == 0) {
+ if (this->RequestedData.test(DataGroupSolutionConfigurationsBit))
+ this->Stack.push(FileStateSolutionConfigurations);
+ else
+ this->IgnoreUntilTag("EndGlobalSection");
+ } else if (line.GetArg().compare("ProjectConfigurationPlatforms") ==
+ 0 &&
+ line.GetValue(0).compare("postSolution") == 0) {
+ if (this->RequestedData.test(DataGroupProjectConfigurationsBit))
+ this->Stack.push(FileStateProjectConfigurations);
+ else
+ this->IgnoreUntilTag("EndGlobalSection");
+ } else if (line.GetArg().compare("NestedProjects") == 0 &&
+ line.GetValue(0).compare("preSolution") == 0) {
+ if (this->RequestedData.test(DataGroupSolutionFiltersBit))
+ this->Stack.push(FileStateSolutionFilters);
+ else
+ this->IgnoreUntilTag("EndGlobalSection");
+ } else if (this->RequestedData.test(DataGroupGenericGlobalSectionsBit))
+ this->Stack.push(FileStateGlobalSection);
+ else
+ this->IgnoreUntilTag("EndGlobalSection");
+ } else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateSolutionConfigurations:
+ if (line.GetTag().compare("EndGlobalSection") == 0)
+ this->Stack.pop();
+ else if (line.IsKeyValuePair())
+ // implement configuration storing here, once needed
+ ;
+ else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateProjectConfigurations:
+ if (line.GetTag().compare("EndGlobalSection") == 0)
+ this->Stack.pop();
+ else if (line.IsKeyValuePair())
+ // implement configuration storing here, once needed
+ ;
+ else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateSolutionFilters:
+ if (line.GetTag().compare("EndGlobalSection") == 0)
+ this->Stack.pop();
+ else if (line.IsKeyValuePair())
+ // implement filter storing here, once needed
+ ;
+ else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateGlobalSection:
+ if (line.GetTag().compare("EndGlobalSection") == 0)
+ this->Stack.pop();
+ else if (line.IsKeyValuePair())
+ // implement section storing here, once needed
+ ;
+ else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateIgnore:
+ if (line.GetTag() == this->EndIgnoreTag) {
+ this->Stack.pop();
+ this->EndIgnoreTag = "";
+ }
+ break;
+ default:
+ result.SetError(ResultErrorBadInternalState, this->GetCurrentLine());
+ return false;
+ }
+ return true;
+}
+
+bool cmVisualStudioSlnParser::State::Finished(
+ cmVisualStudioSlnParser::ResultData& result)
+{
+ if (this->Stack.top() != FileStateTopLevel) {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ result.Result = ResultOK;
+ return true;
+}
+
+void cmVisualStudioSlnParser::State::IgnoreUntilTag(const std::string& endTag)
+{
+ this->Stack.push(FileStateIgnore);
+ this->EndIgnoreTag = endTag;
+}
+
+cmVisualStudioSlnParser::ResultData::ResultData()
+ : Result(ResultOK)
+ , ResultLine(0)
+{
+}
+
+void cmVisualStudioSlnParser::ResultData::Clear()
+{
+ *this = ResultData();
+}
+
+void cmVisualStudioSlnParser::ResultData::SetError(ParseResult error,
+ size_t line)
+{
+ this->Result = error;
+ this->ResultLine = line;
+}
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupProjects(
+ 1 << cmVisualStudioSlnParser::DataGroupProjectsBit);
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupProjectDependencies(
+ 1 << cmVisualStudioSlnParser::DataGroupProjectDependenciesBit);
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupSolutionConfigurations(
+ 1 << cmVisualStudioSlnParser::DataGroupSolutionConfigurationsBit);
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupProjectConfigurations(
+ 1 << cmVisualStudioSlnParser::DataGroupProjectConfigurationsBit);
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupSolutionFilters(
+ 1 << cmVisualStudioSlnParser::DataGroupSolutionFiltersBit);
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupGenericGlobalSections(
+ 1 << cmVisualStudioSlnParser::DataGroupGenericGlobalSectionsBit);
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupAll(~0);
+
+bool cmVisualStudioSlnParser::Parse(std::istream& input, cmSlnData& output,
+ DataGroupSet dataGroups)
+{
+ this->LastResult.Clear();
+ if (!this->IsDataGroupSetSupported(dataGroups)) {
+ this->LastResult.SetError(ResultErrorUnsupportedDataGroup, 0);
+ return false;
+ }
+ State state(dataGroups);
+ return this->ParseImpl(input, output, state);
+}
+
+bool cmVisualStudioSlnParser::ParseFile(const std::string& file,
+ cmSlnData& output,
+ DataGroupSet dataGroups)
+{
+ this->LastResult.Clear();
+ if (!this->IsDataGroupSetSupported(dataGroups)) {
+ this->LastResult.SetError(ResultErrorUnsupportedDataGroup, 0);
+ return false;
+ }
+ cmsys::ifstream f(file.c_str());
+ if (!f) {
+ this->LastResult.SetError(ResultErrorOpeningInput, 0);
+ return false;
+ }
+ State state(dataGroups);
+ return this->ParseImpl(f, output, state);
+}
+
+cmVisualStudioSlnParser::ParseResult cmVisualStudioSlnParser::GetParseResult()
+ const
+{
+ return this->LastResult.Result;
+}
+
+size_t cmVisualStudioSlnParser::GetParseResultLine() const
+{
+ return this->LastResult.ResultLine;
+}
+
+bool cmVisualStudioSlnParser::GetParseHadBOM() const
+{
+ return this->LastResult.HadBOM;
+}
+
+bool cmVisualStudioSlnParser::IsDataGroupSetSupported(
+ DataGroupSet dataGroups) const
+{
+ return (dataGroups & DataGroupProjects) == dataGroups;
+ // only supporting DataGroupProjects for now
+}
+
+bool cmVisualStudioSlnParser::ParseImpl(std::istream& input, cmSlnData& output,
+ State& state)
+{
+ std::string line;
+ // Does the .sln start with a Byte Order Mark?
+ if (!this->ParseBOM(input, line, state))
+ return false;
+ do {
+ line = cmSystemTools::TrimWhitespace(line);
+ if (line.empty())
+ continue;
+ ParsedLine parsedLine;
+ switch (state.NextLineFormat()) {
+ case LineMultiValueTag:
+ if (!this->ParseMultiValueTag(line, parsedLine, state))
+ return false;
+ break;
+ case LineSingleValueTag:
+ if (!this->ParseSingleValueTag(line, parsedLine, state))
+ return false;
+ break;
+ case LineKeyValuePair:
+ if (!this->ParseKeyValuePair(line, parsedLine, state))
+ return false;
+ break;
+ case LineVerbatim:
+ parsedLine.CopyVerbatim(line);
+ break;
+ }
+ if (parsedLine.IsComment())
+ continue;
+ if (!state.Process(parsedLine, output, this->LastResult))
+ return false;
+ } while (state.ReadLine(input, line));
+ return state.Finished(this->LastResult);
+}
+
+bool cmVisualStudioSlnParser::ParseBOM(std::istream& input, std::string& line,
+ State& state)
+{
+ char bom[4];
+ if (!input.get(bom, 4)) {
+ this->LastResult.SetError(ResultErrorReadingInput, 1);
+ return false;
+ }
+ this->LastResult.HadBOM =
+ (bom[0] == char(0xEF) && bom[1] == char(0xBB) && bom[2] == char(0xBF));
+ if (!state.ReadLine(input, line)) {
+ this->LastResult.SetError(ResultErrorReadingInput, 1);
+ return false;
+ }
+ if (!this->LastResult.HadBOM)
+ line = bom + line; // it wasn't a BOM, prepend it to first line
+ return true;
+}
+
+bool cmVisualStudioSlnParser::ParseMultiValueTag(const std::string& line,
+ ParsedLine& parsedLine,
+ State& state)
+{
+ size_t idxEqualSign = line.find('=');
+ const std::string& fullTag = line.substr(0, idxEqualSign);
+ if (!this->ParseTag(fullTag, parsedLine, state))
+ return false;
+ if (idxEqualSign != line.npos) {
+ size_t idxFieldStart = idxEqualSign + 1;
+ if (idxFieldStart < line.size()) {
+ size_t idxParsing = idxFieldStart;
+ bool inQuotes = false;
+ for (;;) {
+ idxParsing = line.find_first_of(",\"", idxParsing);
+ bool fieldOver = false;
+ if (idxParsing == line.npos) {
+ fieldOver = true;
+ if (inQuotes) {
+ this->LastResult.SetError(ResultErrorInputStructure,
+ state.GetCurrentLine());
+ return false;
+ }
+ } else if (line[idxParsing] == ',' && !inQuotes)
+ fieldOver = true;
+ else if (line[idxParsing] == '"')
+ inQuotes = !inQuotes;
+ if (fieldOver) {
+ if (!this->ParseValue(
+ line.substr(idxFieldStart, idxParsing - idxFieldStart),
+ parsedLine))
+ return false;
+ if (idxParsing == line.npos)
+ break; // end of last field
+ idxFieldStart = idxParsing + 1;
+ }
+ ++idxParsing;
+ }
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudioSlnParser::ParseSingleValueTag(const std::string& line,
+ ParsedLine& parsedLine,
+ State& state)
+{
+ size_t idxEqualSign = line.find('=');
+ const std::string& fullTag = line.substr(0, idxEqualSign);
+ if (!this->ParseTag(fullTag, parsedLine, state))
+ return false;
+ if (idxEqualSign != line.npos) {
+ if (!this->ParseValue(line.substr(idxEqualSign + 1), parsedLine))
+ return false;
+ }
+ return true;
+}
+
+bool cmVisualStudioSlnParser::ParseKeyValuePair(const std::string& line,
+ ParsedLine& parsedLine,
+ State& /*state*/)
+{
+ size_t idxEqualSign = line.find('=');
+ if (idxEqualSign == line.npos) {
+ parsedLine.CopyVerbatim(line);
+ return true;
+ }
+ const std::string& key = line.substr(0, idxEqualSign);
+ parsedLine.SetTag(cmSystemTools::TrimWhitespace(key));
+ const std::string& value = line.substr(idxEqualSign + 1);
+ parsedLine.AddValue(cmSystemTools::TrimWhitespace(value));
+ return true;
+}
+
+bool cmVisualStudioSlnParser::ParseTag(const std::string& fullTag,
+ ParsedLine& parsedLine, State& state)
+{
+ size_t idxLeftParen = fullTag.find('(');
+ if (idxLeftParen == fullTag.npos) {
+ parsedLine.SetTag(cmSystemTools::TrimWhitespace(fullTag));
+ return true;
+ }
+ parsedLine.SetTag(
+ cmSystemTools::TrimWhitespace(fullTag.substr(0, idxLeftParen)));
+ size_t idxRightParen = fullTag.rfind(')');
+ if (idxRightParen == fullTag.npos) {
+ this->LastResult.SetError(ResultErrorInputStructure,
+ state.GetCurrentLine());
+ return false;
+ }
+ const std::string& arg = cmSystemTools::TrimWhitespace(
+ fullTag.substr(idxLeftParen + 1, idxRightParen - idxLeftParen - 1));
+ if (arg[0] == '"') {
+ if (arg[arg.size() - 1] != '"') {
+ this->LastResult.SetError(ResultErrorInputStructure,
+ state.GetCurrentLine());
+ return false;
+ }
+ parsedLine.SetQuotedArg(arg.substr(1, arg.size() - 2));
+ } else
+ parsedLine.SetArg(arg);
+ return true;
+}
+
+bool cmVisualStudioSlnParser::ParseValue(const std::string& value,
+ ParsedLine& parsedLine)
+{
+ const std::string& trimmed = cmSystemTools::TrimWhitespace(value);
+ if (trimmed.empty())
+ parsedLine.AddValue(trimmed);
+ else if (trimmed[0] == '"' && trimmed[trimmed.size() - 1] == '"')
+ parsedLine.AddQuotedValue(trimmed.substr(1, trimmed.size() - 2));
+ else
+ parsedLine.AddValue(trimmed);
+ return true;
+}
diff --git a/Source/cmVisualStudioSlnParser.h b/Source/cmVisualStudioSlnParser.h
new file mode 100644
index 0000000..b9f8a92
--- /dev/null
+++ b/Source/cmVisualStudioSlnParser.h
@@ -0,0 +1,110 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2013 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmVisualStudioSlnParser_h
+#define cmVisualStudioSlnParser_h
+
+#include "cmStandardIncludes.h"
+
+#include <bitset>
+
+class cmSlnData;
+
+class cmVisualStudioSlnParser
+{
+public:
+ enum ParseResult
+ {
+ ResultOK = 0,
+
+ ResultInternalError = -1,
+ ResultExternalError = 1,
+
+ ResultErrorOpeningInput = ResultExternalError,
+ ResultErrorReadingInput,
+ ResultErrorInputStructure,
+ ResultErrorInputData,
+
+ ResultErrorBadInternalState = ResultInternalError,
+ ResultErrorUnsupportedDataGroup = ResultInternalError - 1
+ };
+
+ enum DataGroup
+ {
+ DataGroupProjectsBit,
+ DataGroupProjectDependenciesBit,
+ DataGroupSolutionConfigurationsBit,
+ DataGroupProjectConfigurationsBit,
+ DataGroupSolutionFiltersBit,
+ DataGroupGenericGlobalSectionsBit,
+ DataGroupCount
+ };
+
+ typedef std::bitset<DataGroupCount> DataGroupSet;
+
+ static const DataGroupSet DataGroupProjects;
+ static const DataGroupSet DataGroupProjectDependencies;
+ static const DataGroupSet DataGroupSolutionConfigurations;
+ static const DataGroupSet DataGroupProjectConfigurations;
+ static const DataGroupSet DataGroupSolutionFilters;
+ static const DataGroupSet DataGroupGenericGlobalSections;
+ static const DataGroupSet DataGroupAll;
+
+ bool Parse(std::istream& input, cmSlnData& output,
+ DataGroupSet dataGroups = DataGroupAll);
+
+ bool ParseFile(const std::string& file, cmSlnData& output,
+ DataGroupSet dataGroups = DataGroupAll);
+
+ ParseResult GetParseResult() const;
+
+ size_t GetParseResultLine() const;
+
+ bool GetParseHadBOM() const;
+
+protected:
+ class State;
+ friend class State;
+ class ParsedLine;
+
+ struct ResultData
+ {
+ ParseResult Result;
+ size_t ResultLine;
+ bool HadBOM;
+
+ ResultData();
+ void Clear();
+ void SetError(ParseResult error, size_t line);
+ } LastResult;
+
+ bool IsDataGroupSetSupported(DataGroupSet dataGroups) const;
+
+ bool ParseImpl(std::istream& input, cmSlnData& output, State& state);
+
+ bool ParseBOM(std::istream& input, std::string& line, State& state);
+
+ bool ParseMultiValueTag(const std::string& line, ParsedLine& parsedLine,
+ State& state);
+
+ bool ParseSingleValueTag(const std::string& line, ParsedLine& parsedLine,
+ State& state);
+
+ bool ParseKeyValuePair(const std::string& line, ParsedLine& parsedLine,
+ State& state);
+
+ bool ParseTag(const std::string& fullTag, ParsedLine& parsedLine,
+ State& state);
+
+ bool ParseValue(const std::string& value, ParsedLine& parsedLine);
+};
+
+#endif
diff --git a/Source/cmVisualStudioWCEPlatformParser.cxx b/Source/cmVisualStudioWCEPlatformParser.cxx
new file mode 100644
index 0000000..bc6b0bf
--- /dev/null
+++ b/Source/cmVisualStudioWCEPlatformParser.cxx
@@ -0,0 +1,148 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmVisualStudioWCEPlatformParser.h"
+
+#include "cmGlobalVisualStudioGenerator.h"
+#include "cmXMLParser.h"
+
+int cmVisualStudioWCEPlatformParser::ParseVersion(const char* version)
+{
+ const std::string registryBase =
+ cmGlobalVisualStudioGenerator::GetRegistryBase(version);
+ const std::string vckey = registryBase + "\\Setup\\VC;ProductDir";
+ const std::string vskey = registryBase + "\\Setup\\VS;ProductDir";
+
+ if (!cmSystemTools::ReadRegistryValue(vckey.c_str(), this->VcInstallDir,
+ cmSystemTools::KeyWOW64_32) ||
+ !cmSystemTools::ReadRegistryValue(vskey.c_str(), this->VsInstallDir,
+ cmSystemTools::KeyWOW64_32)) {
+ return 0;
+ }
+ cmSystemTools::ConvertToUnixSlashes(this->VcInstallDir);
+ cmSystemTools::ConvertToUnixSlashes(this->VsInstallDir);
+ this->VcInstallDir.append("/");
+ this->VsInstallDir.append("/");
+
+ const std::string configFilename =
+ this->VcInstallDir + "vcpackages/WCE.VCPlatform.config";
+
+ return this->ParseFile(configFilename.c_str());
+}
+
+std::string cmVisualStudioWCEPlatformParser::GetOSVersion() const
+{
+ if (this->OSMinorVersion.empty()) {
+ return OSMajorVersion;
+ }
+
+ return OSMajorVersion + "." + OSMinorVersion;
+}
+
+const char* cmVisualStudioWCEPlatformParser::GetArchitectureFamily() const
+{
+ std::map<std::string, std::string>::const_iterator it =
+ this->Macros.find("ARCHFAM");
+ if (it != this->Macros.end()) {
+ return it->second.c_str();
+ }
+
+ return 0;
+}
+
+void cmVisualStudioWCEPlatformParser::StartElement(const std::string& name,
+ const char** attributes)
+{
+ if (this->FoundRequiredName) {
+ return;
+ }
+
+ this->CharacterData = "";
+
+ if (name == "PlatformData") {
+ this->PlatformName = "";
+ this->OSMajorVersion = "";
+ this->OSMinorVersion = "";
+ this->Macros.clear();
+ }
+
+ if (name == "Macro") {
+ std::string macroName;
+ std::string macroValue;
+
+ for (const char** attr = attributes; *attr; attr += 2) {
+ if (strcmp(attr[0], "Name") == 0) {
+ macroName = attr[1];
+ } else if (strcmp(attr[0], "Value") == 0) {
+ macroValue = attr[1];
+ }
+ }
+
+ if (!macroName.empty()) {
+ this->Macros[macroName] = macroValue;
+ }
+ } else if (name == "Directories") {
+ for (const char** attr = attributes; *attr; attr += 2) {
+ if (strcmp(attr[0], "Include") == 0) {
+ this->Include = attr[1];
+ } else if (strcmp(attr[0], "Library") == 0) {
+ this->Library = attr[1];
+ } else if (strcmp(attr[0], "Path") == 0) {
+ this->Path = attr[1];
+ }
+ }
+ }
+}
+
+void cmVisualStudioWCEPlatformParser::EndElement(const std::string& name)
+{
+ if (!this->RequiredName) {
+ if (name == "PlatformName") {
+ this->AvailablePlatforms.push_back(this->CharacterData);
+ }
+ return;
+ }
+
+ if (this->FoundRequiredName) {
+ return;
+ }
+
+ if (name == "PlatformName") {
+ this->PlatformName = this->CharacterData;
+ } else if (name == "OSMajorVersion") {
+ this->OSMajorVersion = this->CharacterData;
+ } else if (name == "OSMinorVersion") {
+ this->OSMinorVersion = this->CharacterData;
+ } else if (name == "Platform") {
+ if (this->PlatformName == this->RequiredName) {
+ this->FoundRequiredName = true;
+ }
+ }
+}
+
+void cmVisualStudioWCEPlatformParser::CharacterDataHandler(const char* data,
+ int length)
+{
+ this->CharacterData.append(data, length);
+}
+
+std::string cmVisualStudioWCEPlatformParser::FixPaths(
+ const std::string& paths) const
+{
+ std::string ret = paths;
+ cmSystemTools::ReplaceString(ret, "$(PATH)", "%PATH%");
+ cmSystemTools::ReplaceString(ret, "$(VCInstallDir)", VcInstallDir.c_str());
+ cmSystemTools::ReplaceString(ret, "$(VSInstallDir)", VsInstallDir.c_str());
+ std::replace(ret.begin(), ret.end(), '\\', '/');
+ cmSystemTools::ReplaceString(ret, "//", "/");
+ std::replace(ret.begin(), ret.end(), '/', '\\');
+ return ret;
+}
diff --git a/Source/cmVisualStudioWCEPlatformParser.h b/Source/cmVisualStudioWCEPlatformParser.h
new file mode 100644
index 0000000..2b20eba
--- /dev/null
+++ b/Source/cmVisualStudioWCEPlatformParser.h
@@ -0,0 +1,74 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmVisualStudioWCEPlatformParser_h
+#define cmVisualStudioWCEPlatformParser_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmXMLParser.h"
+
+// This class is used to parse XML with configuration
+// of installed SDKs in system
+class cmVisualStudioWCEPlatformParser : public cmXMLParser
+{
+public:
+ cmVisualStudioWCEPlatformParser(const char* name = NULL)
+ : RequiredName(name)
+ , FoundRequiredName(false)
+ {
+ }
+
+ int ParseVersion(const char* version);
+
+ bool Found() const { return this->FoundRequiredName; }
+ const char* GetArchitectureFamily() const;
+ std::string GetOSVersion() const;
+ std::string GetIncludeDirectories() const
+ {
+ return this->FixPaths(this->Include);
+ }
+ std::string GetLibraryDirectories() const
+ {
+ return this->FixPaths(this->Library);
+ }
+ std::string GetPathDirectories() const { return this->FixPaths(this->Path); }
+ const std::vector<std::string>& GetAvailablePlatforms() const
+ {
+ return this->AvailablePlatforms;
+ }
+
+protected:
+ virtual void StartElement(const std::string& name, const char** attributes);
+ void EndElement(const std::string& name);
+ void CharacterDataHandler(const char* data, int length);
+
+private:
+ std::string FixPaths(const std::string& paths) const;
+
+ std::string CharacterData;
+
+ std::string Include;
+ std::string Library;
+ std::string Path;
+ std::string PlatformName;
+ std::string OSMajorVersion;
+ std::string OSMinorVersion;
+ std::map<std::string, std::string> Macros;
+ std::vector<std::string> AvailablePlatforms;
+
+ const char* RequiredName;
+ bool FoundRequiredName;
+ std::string VcInstallDir;
+ std::string VsInstallDir;
+};
+
+#endif
diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx
new file mode 100644
index 0000000..93a6271
--- /dev/null
+++ b/Source/cmWhileCommand.cxx
@@ -0,0 +1,147 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmWhileCommand.h"
+
+#include "cmConditionEvaluator.h"
+
+cmWhileFunctionBlocker::cmWhileFunctionBlocker(cmMakefile* mf)
+ : Makefile(mf)
+ , Depth(0)
+{
+ this->Makefile->PushLoopBlock();
+}
+
+cmWhileFunctionBlocker::~cmWhileFunctionBlocker()
+{
+ this->Makefile->PopLoopBlock();
+}
+
+bool cmWhileFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
+ cmMakefile& mf,
+ cmExecutionStatus& inStatus)
+{
+ // at end of for each execute recorded commands
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(), "while")) {
+ // record the number of while commands past this one
+ this->Depth++;
+ } else if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endwhile")) {
+ // if this is the endwhile for this while loop then execute
+ if (!this->Depth) {
+ // Remove the function blocker for this scope or bail.
+ CM_AUTO_PTR<cmFunctionBlocker> fb(mf.RemoveFunctionBlocker(this, lff));
+ if (!fb.get()) {
+ return false;
+ }
+
+ std::string errorString;
+
+ std::vector<cmExpandedCommandArgument> expandedArguments;
+ mf.ExpandArguments(this->Args, expandedArguments);
+ cmake::MessageType messageType;
+
+ cmListFileContext execContext = this->GetStartingContext();
+
+ cmCommandContext commandContext;
+ commandContext.Line = execContext.Line;
+ commandContext.Name = execContext.Name;
+
+ cmConditionEvaluator conditionEvaluator(mf, this->GetStartingContext(),
+ mf.GetBacktrace(commandContext));
+
+ bool isTrue =
+ conditionEvaluator.IsTrue(expandedArguments, errorString, messageType);
+
+ while (isTrue) {
+ if (!errorString.empty()) {
+ std::string err = "had incorrect arguments: ";
+ unsigned int i;
+ for (i = 0; i < this->Args.size(); ++i) {
+ err += (this->Args[i].Delim ? "\"" : "");
+ err += this->Args[i].Value;
+ err += (this->Args[i].Delim ? "\"" : "");
+ err += " ";
+ }
+ err += "(";
+ err += errorString;
+ err += ").";
+ mf.IssueMessage(messageType, err);
+ if (messageType == cmake::FATAL_ERROR) {
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ }
+
+ // Invoke all the functions that were collected in the block.
+ for (unsigned int c = 0; c < this->Functions.size(); ++c) {
+ cmExecutionStatus status;
+ mf.ExecuteCommand(this->Functions[c], status);
+ if (status.GetReturnInvoked()) {
+ inStatus.SetReturnInvoked(true);
+ return true;
+ }
+ if (status.GetBreakInvoked()) {
+ return true;
+ }
+ if (status.GetContinueInvoked()) {
+ break;
+ }
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return true;
+ }
+ }
+ expandedArguments.clear();
+ mf.ExpandArguments(this->Args, expandedArguments);
+ isTrue = conditionEvaluator.IsTrue(expandedArguments, errorString,
+ messageType);
+ }
+ return true;
+ } else {
+ // decrement for each nested while that ends
+ this->Depth--;
+ }
+ }
+
+ // record the command
+ this->Functions.push_back(lff);
+
+ // always return true
+ return true;
+}
+
+bool cmWhileFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
+ cmMakefile&)
+{
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endwhile")) {
+ // if the endwhile has arguments, then make sure
+ // they match the arguments of the matching while
+ if (lff.Arguments.empty() || lff.Arguments == this->Args) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmWhileCommand::InvokeInitialPass(
+ const std::vector<cmListFileArgument>& args, cmExecutionStatus&)
+{
+ if (args.size() < 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // create a function blocker
+ cmWhileFunctionBlocker* f = new cmWhileFunctionBlocker(this->Makefile);
+ f->Args = args;
+ this->Makefile->AddFunctionBlocker(f);
+
+ return true;
+}
diff --git a/Source/cmWhileCommand.h b/Source/cmWhileCommand.h
new file mode 100644
index 0000000..bd354c7
--- /dev/null
+++ b/Source/cmWhileCommand.h
@@ -0,0 +1,76 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmWhileCommand_h
+#define cmWhileCommand_h
+
+#include "cmCommand.h"
+
+#include "cmFunctionBlocker.h"
+#include "cmListFileCache.h"
+
+class cmWhileFunctionBlocker : public cmFunctionBlocker
+{
+public:
+ cmWhileFunctionBlocker(cmMakefile* mf);
+ ~cmWhileFunctionBlocker() CM_OVERRIDE;
+ bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf,
+ cmExecutionStatus&) CM_OVERRIDE;
+ bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) CM_OVERRIDE;
+
+ std::vector<cmListFileArgument> Args;
+ std::vector<cmListFileFunction> Functions;
+
+private:
+ cmMakefile* Makefile;
+ int Depth;
+};
+
+/// \brief Starts a while loop
+class cmWhileCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmWhileCommand; }
+
+ /**
+ * This overrides the default InvokeInitialPass implementation.
+ * It records the arguments before expansion.
+ */
+ bool InvokeInitialPass(const std::vector<cmListFileArgument>& args,
+ cmExecutionStatus&) CM_OVERRIDE;
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const&,
+ cmExecutionStatus&) CM_OVERRIDE
+ {
+ return false;
+ }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "while"; }
+
+ cmTypeMacro(cmWhileCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmWriteFileCommand.cxx b/Source/cmWriteFileCommand.cxx
new file mode 100644
index 0000000..3966d38
--- /dev/null
+++ b/Source/cmWriteFileCommand.cxx
@@ -0,0 +1,84 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmWriteFileCommand.h"
+
+#include <cmsys/FStream.hxx>
+
+#include <sys/types.h>
+// include sys/stat.h after sys/types.h
+#include <sys/stat.h>
+
+// cmLibraryCommand
+bool cmWriteFileCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ std::string message;
+ std::vector<std::string>::const_iterator i = args.begin();
+
+ std::string fileName = *i;
+ bool overwrite = true;
+ i++;
+
+ for (; i != args.end(); ++i) {
+ if (*i == "APPEND") {
+ overwrite = false;
+ } else {
+ message += *i;
+ }
+ }
+
+ if (!this->Makefile->CanIWriteThisFile(fileName.c_str())) {
+ std::string e =
+ "attempted to write a file: " + fileName + " into a source directory.";
+ this->SetError(e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ std::string dir = cmSystemTools::GetFilenamePath(fileName);
+ cmSystemTools::MakeDirectory(dir.c_str());
+
+ mode_t mode = 0;
+
+ // Set permissions to writable
+ if (cmSystemTools::GetPermissions(fileName.c_str(), mode)) {
+ cmSystemTools::SetPermissions(fileName.c_str(),
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ mode | S_IWRITE
+#else
+ mode | S_IWUSR | S_IWGRP
+#endif
+ );
+ }
+ // If GetPermissions fails, pretend like it is ok. File open will fail if
+ // the file is not writable
+ cmsys::ofstream file(fileName.c_str(),
+ overwrite ? std::ios::out : std::ios::app);
+ if (!file) {
+ std::string error = "Internal CMake error when trying to open file: ";
+ error += fileName.c_str();
+ error += " for writing.";
+ this->SetError(error);
+ return false;
+ }
+ file << message << std::endl;
+ file.close();
+ if (mode) {
+ cmSystemTools::SetPermissions(fileName.c_str(), mode);
+ }
+
+ return true;
+}
diff --git a/Source/cmWriteFileCommand.h b/Source/cmWriteFileCommand.h
new file mode 100644
index 0000000..db24b0e
--- /dev/null
+++ b/Source/cmWriteFileCommand.h
@@ -0,0 +1,49 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmWriteFileCommand_h
+#define cmWriteFileCommand_h
+
+#include "cmCommand.h"
+
+/** \class cmWriteFileCommand
+ * \brief Writes a message to a file
+ *
+ */
+class cmWriteFileCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() CM_OVERRIDE { return new cmWriteFileCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ bool IsScriptable() const CM_OVERRIDE { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const CM_OVERRIDE { return "write_file"; }
+
+ cmTypeMacro(cmWriteFileCommand, cmCommand);
+};
+
+#endif
diff --git a/Source/cmXCode21Object.cxx b/Source/cmXCode21Object.cxx
new file mode 100644
index 0000000..1abdf66
--- /dev/null
+++ b/Source/cmXCode21Object.cxx
@@ -0,0 +1,96 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmXCode21Object.h"
+
+#include "cmSystemTools.h"
+
+cmXCode21Object::cmXCode21Object(PBXType ptype, Type type)
+ : cmXCodeObject(ptype, type)
+{
+ this->Version = 21;
+}
+
+void cmXCode21Object::PrintComment(std::ostream& out)
+{
+ if (this->Comment.empty()) {
+ cmXCodeObject* n = this->GetObject("name");
+ if (n) {
+ this->Comment = n->GetString();
+ cmSystemTools::ReplaceString(this->Comment, "\"", "");
+ }
+ }
+ if (this->Comment.empty()) {
+ return;
+ }
+ out << " /* ";
+ out << this->Comment;
+ out << " */";
+}
+
+void cmXCode21Object::PrintList(std::vector<cmXCodeObject*> const& v,
+ std::ostream& out, PBXType t)
+{
+ bool hasOne = false;
+ for (std::vector<cmXCodeObject*>::const_iterator i = v.begin(); i != v.end();
+ ++i) {
+ cmXCodeObject* obj = *i;
+ if (obj->GetType() == OBJECT && obj->GetIsA() == t) {
+ hasOne = true;
+ break;
+ }
+ }
+ if (!hasOne) {
+ return;
+ }
+ out << "\n/* Begin " << PBXTypeNames[t] << " section */\n";
+ for (std::vector<cmXCodeObject*>::const_iterator i = v.begin(); i != v.end();
+ ++i) {
+ cmXCodeObject* obj = *i;
+ if (obj->GetType() == OBJECT && obj->GetIsA() == t) {
+ obj->Print(out);
+ }
+ }
+ out << "/* End " << PBXTypeNames[t] << " section */\n";
+}
+
+void cmXCode21Object::PrintList(std::vector<cmXCodeObject*> const& v,
+ std::ostream& out)
+{
+ cmXCodeObject::Indent(1, out);
+ out << "objects = {\n";
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXAggregateTarget);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXBuildFile);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXBuildStyle);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXContainerItemProxy);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXFileReference);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXFrameworksBuildPhase);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXGroup);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXHeadersBuildPhase);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXNativeTarget);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXProject);
+ cmXCode21Object::PrintList(v, out,
+ cmXCode21Object::PBXShellScriptBuildPhase);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXResourcesBuildPhase);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXSourcesBuildPhase);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXCopyFilesBuildPhase);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXApplicationReference);
+ cmXCode21Object::PrintList(v, out,
+ cmXCode21Object::PBXExecutableFileReference);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXLibraryReference);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXToolTarget);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXLibraryTarget);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXTargetDependency);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::XCBuildConfiguration);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::XCConfigurationList);
+ cmXCodeObject::Indent(1, out);
+ out << "};\n";
+}
diff --git a/Source/cmXCode21Object.h b/Source/cmXCode21Object.h
new file mode 100644
index 0000000..9e51e0d
--- /dev/null
+++ b/Source/cmXCode21Object.h
@@ -0,0 +1,26 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmXCode21Object_h
+#define cmXCode21Object_h
+
+#include "cmXCodeObject.h"
+
+class cmXCode21Object : public cmXCodeObject
+{
+public:
+ cmXCode21Object(PBXType ptype, Type type);
+ virtual void PrintComment(std::ostream&);
+ static void PrintList(std::vector<cmXCodeObject*> const&, std::ostream& out,
+ PBXType t);
+ static void PrintList(std::vector<cmXCodeObject*> const&, std::ostream& out);
+};
+#endif
diff --git a/Source/cmXCodeObject.cxx b/Source/cmXCodeObject.cxx
new file mode 100644
index 0000000..fabf097
--- /dev/null
+++ b/Source/cmXCodeObject.cxx
@@ -0,0 +1,263 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmXCodeObject.h"
+
+#include "cmSystemTools.h"
+
+#include <CoreFoundation/CoreFoundation.h> // CFUUIDCreate
+
+const char* cmXCodeObject::PBXTypeNames[] = {
+ /* clang-format needs this comment to break after the opening brace */
+ "PBXGroup",
+ "PBXBuildStyle",
+ "PBXProject",
+ "PBXHeadersBuildPhase",
+ "PBXSourcesBuildPhase",
+ "PBXFrameworksBuildPhase",
+ "PBXNativeTarget",
+ "PBXFileReference",
+ "PBXBuildFile",
+ "PBXContainerItemProxy",
+ "PBXTargetDependency",
+ "PBXShellScriptBuildPhase",
+ "PBXResourcesBuildPhase",
+ "PBXApplicationReference",
+ "PBXExecutableFileReference",
+ "PBXLibraryReference",
+ "PBXToolTarget",
+ "PBXLibraryTarget",
+ "PBXAggregateTarget",
+ "XCBuildConfiguration",
+ "XCConfigurationList",
+ "PBXCopyFilesBuildPhase",
+ "None"
+};
+
+cmXCodeObject::~cmXCodeObject()
+{
+ this->Version = 15;
+}
+
+cmXCodeObject::cmXCodeObject(PBXType ptype, Type type)
+{
+ this->Version = 15;
+ this->Target = 0;
+ this->Object = 0;
+
+ this->IsA = ptype;
+
+ if (type == OBJECT) {
+ // Set the Id of an Xcode object to a unique string for each instance.
+ // However the Xcode user file references certain Ids: for those cases,
+ // override the generated Id using SetId().
+ //
+ char cUuid[40] = { 0 };
+ CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
+ CFStringRef s = CFUUIDCreateString(kCFAllocatorDefault, uuid);
+ CFStringGetCString(s, cUuid, sizeof(cUuid), kCFStringEncodingUTF8);
+ this->Id = cUuid;
+ CFRelease(s);
+ CFRelease(uuid);
+ } else {
+ this->Id =
+ "Temporary cmake object, should not be referred to in Xcode file";
+ }
+
+ cmSystemTools::ReplaceString(this->Id, "-", "");
+ if (this->Id.size() > 24) {
+ this->Id = this->Id.substr(0, 24);
+ }
+
+ this->TypeValue = type;
+ if (this->TypeValue == OBJECT) {
+ this->AddAttribute("isa", 0);
+ }
+}
+
+bool cmXCodeObject::IsEmpty() const
+{
+ switch (this->TypeValue) {
+ case OBJECT_LIST:
+ return this->List.empty();
+ case STRING:
+ return this->String.empty();
+ case ATTRIBUTE_GROUP:
+ return this->ObjectAttributes.empty();
+ case OBJECT_REF:
+ case OBJECT:
+ return this->Object == 0;
+ }
+ return true; // unreachable, but quiets warnings
+}
+
+void cmXCodeObject::Indent(int level, std::ostream& out)
+{
+ while (level) {
+ out << "\t";
+ level--;
+ }
+}
+
+void cmXCodeObject::Print(std::ostream& out)
+{
+ std::string separator = "\n";
+ int indentFactor = 1;
+ cmXCodeObject::Indent(2 * indentFactor, out);
+ if (this->Version > 15 &&
+ (this->IsA == PBXFileReference || this->IsA == PBXBuildFile)) {
+ separator = " ";
+ indentFactor = 0;
+ }
+ out << this->Id;
+ this->PrintComment(out);
+ out << " = {";
+ if (separator == "\n") {
+ out << separator;
+ }
+ std::map<std::string, cmXCodeObject*>::iterator i;
+ cmXCodeObject::Indent(3 * indentFactor, out);
+ out << "isa = " << PBXTypeNames[this->IsA] << ";" << separator;
+ for (i = this->ObjectAttributes.begin(); i != this->ObjectAttributes.end();
+ ++i) {
+ if (i->first == "isa")
+ continue;
+
+ PrintAttribute(out, 3, separator, indentFactor, i->first, i->second, this);
+ }
+ cmXCodeObject::Indent(2 * indentFactor, out);
+ out << "};\n";
+}
+
+void cmXCodeObject::PrintAttribute(std::ostream& out, const int level,
+ const std::string separator,
+ const int factor, const std::string& name,
+ const cmXCodeObject* object,
+ const cmXCodeObject* parent)
+{
+ cmXCodeObject::Indent(level * factor, out);
+ switch (object->TypeValue) {
+ case OBJECT_LIST: {
+ out << name << " = (";
+ if (parent->TypeValue != ATTRIBUTE_GROUP) {
+ out << separator;
+ }
+ for (unsigned int i = 0; i < object->List.size(); ++i) {
+ if (object->List[i]->TypeValue == STRING) {
+ object->List[i]->PrintString(out);
+ if (i + 1 < object->List.size()) {
+ out << ",";
+ }
+ } else {
+ cmXCodeObject::Indent((level + 1) * factor, out);
+ out << object->List[i]->Id;
+ object->List[i]->PrintComment(out);
+ out << "," << separator;
+ }
+ }
+ if (parent->TypeValue != ATTRIBUTE_GROUP) {
+ cmXCodeObject::Indent(level * factor, out);
+ }
+ out << ");" << separator;
+ } break;
+
+ case ATTRIBUTE_GROUP: {
+ out << name << " = {";
+ if (separator == "\n") {
+ out << separator;
+ }
+ std::map<std::string, cmXCodeObject*>::const_iterator i;
+ for (i = object->ObjectAttributes.begin();
+ i != object->ObjectAttributes.end(); ++i) {
+ PrintAttribute(out, (level + 1) * factor, separator, factor, i->first,
+ i->second, object);
+ }
+ cmXCodeObject::Indent(level * factor, out);
+ out << "};" << separator;
+ } break;
+
+ case OBJECT_REF: {
+ cmXCodeObject::PrintString(out, name);
+ out << " = " << object->Object->Id;
+ if (object->Object->HasComment() && name != "remoteGlobalIDString") {
+ object->Object->PrintComment(out);
+ }
+ out << ";" << separator;
+ } break;
+
+ case STRING: {
+ cmXCodeObject::PrintString(out, name);
+ out << " = ";
+ object->PrintString(out);
+ out << ";" << separator;
+ } break;
+
+ default: {
+ break;
+ }
+ }
+}
+
+void cmXCodeObject::PrintList(std::vector<cmXCodeObject*> const& objs,
+ std::ostream& out)
+{
+ cmXCodeObject::Indent(1, out);
+ out << "objects = {\n";
+ for (unsigned int i = 0; i < objs.size(); ++i) {
+ if (objs[i]->TypeValue == OBJECT) {
+ objs[i]->Print(out);
+ }
+ }
+ cmXCodeObject::Indent(1, out);
+ out << "};\n";
+}
+
+void cmXCodeObject::CopyAttributes(cmXCodeObject* copy)
+{
+ this->ObjectAttributes = copy->ObjectAttributes;
+ this->List = copy->List;
+ this->String = copy->String;
+ this->Object = copy->Object;
+}
+
+void cmXCodeObject::PrintString(std::ostream& os, std::string String)
+{
+ // The string needs to be quoted if it contains any characters
+ // considered special by the Xcode project file parser.
+ bool needQuote = (String.empty() || String.find("//") != String.npos ||
+ String.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "$_./") != String.npos);
+ const char* quote = needQuote ? "\"" : "";
+
+ // Print the string, quoted and escaped as necessary.
+ os << quote;
+ for (std::string::const_iterator i = String.begin(); i != String.end();
+ ++i) {
+ if (*i == '"' || *i == '\\') {
+ // Escape double-quotes and backslashes.
+ os << '\\';
+ }
+ os << *i;
+ }
+ os << quote;
+}
+
+void cmXCodeObject::PrintString(std::ostream& os) const
+{
+ cmXCodeObject::PrintString(os, this->String);
+}
+
+void cmXCodeObject::SetString(const std::string& s)
+{
+ this->String = s;
+}
diff --git a/Source/cmXCodeObject.h b/Source/cmXCodeObject.h
new file mode 100644
index 0000000..ed917af
--- /dev/null
+++ b/Source/cmXCodeObject.h
@@ -0,0 +1,175 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmXCodeObject_h
+#define cmXCodeObject_h
+
+#include "cmStandardIncludes.h"
+
+class cmGeneratorTarget;
+
+class cmXCodeObject
+{
+public:
+ enum Type
+ {
+ OBJECT_LIST,
+ STRING,
+ ATTRIBUTE_GROUP,
+ OBJECT_REF,
+ OBJECT
+ };
+ enum PBXType
+ {
+ PBXGroup,
+ PBXBuildStyle,
+ PBXProject,
+ PBXHeadersBuildPhase,
+ PBXSourcesBuildPhase,
+ PBXFrameworksBuildPhase,
+ PBXNativeTarget,
+ PBXFileReference,
+ PBXBuildFile,
+ PBXContainerItemProxy,
+ PBXTargetDependency,
+ PBXShellScriptBuildPhase,
+ PBXResourcesBuildPhase,
+ PBXApplicationReference,
+ PBXExecutableFileReference,
+ PBXLibraryReference,
+ PBXToolTarget,
+ PBXLibraryTarget,
+ PBXAggregateTarget,
+ XCBuildConfiguration,
+ XCConfigurationList,
+ PBXCopyFilesBuildPhase,
+ None
+ };
+ class StringVec : public std::vector<std::string>
+ {
+ };
+ static const char* PBXTypeNames[];
+ virtual ~cmXCodeObject();
+ cmXCodeObject(PBXType ptype, Type type);
+ Type GetType() const { return this->TypeValue; }
+ PBXType GetIsA() const { return this->IsA; }
+
+ bool IsEmpty() const;
+
+ void SetString(const std::string& s);
+ const std::string& GetString() const { return this->String; }
+
+ void AddAttribute(const std::string& name, cmXCodeObject* value)
+ {
+ this->ObjectAttributes[name] = value;
+ }
+
+ void AddAttributeIfNotEmpty(const std::string& name, cmXCodeObject* value)
+ {
+ if (value && !value->IsEmpty()) {
+ AddAttribute(name, value);
+ }
+ }
+
+ void SetObject(cmXCodeObject* value) { this->Object = value; }
+ cmXCodeObject* GetObject() { return this->Object; }
+ void AddObject(cmXCodeObject* value) { this->List.push_back(value); }
+ bool HasObject(cmXCodeObject* o) const
+ {
+ return !(std::find(this->List.begin(), this->List.end(), o) ==
+ this->List.end());
+ }
+ void AddUniqueObject(cmXCodeObject* value)
+ {
+ if (std::find(this->List.begin(), this->List.end(), value) ==
+ this->List.end()) {
+ this->List.push_back(value);
+ }
+ }
+ static void Indent(int level, std::ostream& out);
+ void Print(std::ostream& out);
+ void PrintAttribute(std::ostream& out, const int level,
+ const std::string separator, const int factor,
+ const std::string& name, const cmXCodeObject* object,
+ const cmXCodeObject* parent);
+ virtual void PrintComment(std::ostream&) {}
+
+ static void PrintList(std::vector<cmXCodeObject*> const&, std::ostream& out);
+ const std::string& GetId() const { return this->Id; }
+ void SetId(const std::string& id) { this->Id = id; }
+ cmGeneratorTarget* GetTarget() const { return this->Target; }
+ void SetTarget(cmGeneratorTarget* t) { this->Target = t; }
+ const std::string& GetComment() const { return this->Comment; }
+ bool HasComment() const { return (!this->Comment.empty()); }
+ cmXCodeObject* GetObject(const char* name) const
+ {
+ std::map<std::string, cmXCodeObject*>::const_iterator i =
+ this->ObjectAttributes.find(name);
+ if (i != this->ObjectAttributes.end()) {
+ return i->second;
+ }
+ return 0;
+ }
+ // search the attribute list for an object of the specified type
+ cmXCodeObject* GetObject(cmXCodeObject::PBXType t) const
+ {
+ for (std::vector<cmXCodeObject*>::const_iterator i = this->List.begin();
+ i != this->List.end(); ++i) {
+ cmXCodeObject* o = *i;
+ if (o->IsA == t) {
+ return o;
+ }
+ }
+ return 0;
+ }
+
+ void CopyAttributes(cmXCodeObject*);
+
+ void AddDependLibrary(const std::string& configName, const std::string& l)
+ {
+ this->DependLibraries[configName].push_back(l);
+ }
+ std::map<std::string, StringVec> const& GetDependLibraries() const
+ {
+ return this->DependLibraries;
+ }
+ void AddDependTarget(const std::string& configName, const std::string& tName)
+ {
+ this->DependTargets[configName].push_back(tName);
+ }
+ std::map<std::string, StringVec> const& GetDependTargets() const
+ {
+ return this->DependTargets;
+ }
+ std::vector<cmXCodeObject*> const& GetObjectList() const
+ {
+ return this->List;
+ }
+ void SetComment(const std::string& c) { this->Comment = c; }
+ static void PrintString(std::ostream& os, std::string String);
+
+protected:
+ void PrintString(std::ostream& os) const;
+
+ cmGeneratorTarget* Target;
+ Type TypeValue;
+ std::string Id;
+ PBXType IsA;
+ int Version;
+ std::string Comment;
+ std::string String;
+ cmXCodeObject* Object;
+ std::vector<cmXCodeObject*> List;
+ std::map<std::string, StringVec> DependLibraries;
+ std::map<std::string, StringVec> DependTargets;
+ std::map<std::string, cmXCodeObject*> ObjectAttributes;
+};
+#endif
diff --git a/Source/cmXMLParser.cxx b/Source/cmXMLParser.cxx
new file mode 100644
index 0000000..5e06d36
--- /dev/null
+++ b/Source/cmXMLParser.cxx
@@ -0,0 +1,209 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmXMLParser.h"
+
+#include <cmsys/FStream.hxx>
+
+#include <cm_expat.h>
+#include <ctype.h>
+
+cmXMLParser::cmXMLParser()
+{
+ this->Parser = 0;
+ this->ParseError = 0;
+ this->ReportCallback = 0;
+ this->ReportCallbackData = 0;
+}
+
+cmXMLParser::~cmXMLParser()
+{
+ if (this->Parser) {
+ this->CleanupParser();
+ }
+}
+
+int cmXMLParser::Parse(const char* string)
+{
+ return (int)this->InitializeParser() &&
+ this->ParseChunk(string, strlen(string)) && this->CleanupParser();
+}
+
+int cmXMLParser::ParseFile(const char* file)
+{
+ if (!file) {
+ return 0;
+ }
+
+ cmsys::ifstream ifs(file);
+ if (!ifs) {
+ return 0;
+ }
+
+ std::ostringstream str;
+ str << ifs.rdbuf();
+ return this->Parse(str.str().c_str());
+}
+
+int cmXMLParser::InitializeParser()
+{
+ if (this->Parser) {
+ std::cerr << "Parser already initialized" << std::endl;
+ this->ParseError = 1;
+ return 0;
+ }
+
+ // Create the expat XML parser.
+ this->Parser = XML_ParserCreate(0);
+ XML_SetElementHandler(static_cast<XML_Parser>(this->Parser),
+ &cmXMLParserStartElement, &cmXMLParserEndElement);
+ XML_SetCharacterDataHandler(static_cast<XML_Parser>(this->Parser),
+ &cmXMLParserCharacterDataHandler);
+ XML_SetUserData(static_cast<XML_Parser>(this->Parser), this);
+ this->ParseError = 0;
+ return 1;
+}
+
+int cmXMLParser::ParseChunk(const char* inputString,
+ std::string::size_type length)
+{
+ if (!this->Parser) {
+ std::cerr << "Parser not initialized" << std::endl;
+ this->ParseError = 1;
+ return 0;
+ }
+ int res;
+ res = this->ParseBuffer(inputString, length);
+ if (res == 0) {
+ this->ParseError = 1;
+ }
+ return res;
+}
+
+int cmXMLParser::CleanupParser()
+{
+ if (!this->Parser) {
+ std::cerr << "Parser not initialized" << std::endl;
+ this->ParseError = 1;
+ return 0;
+ }
+ int result = !this->ParseError;
+ if (result) {
+ // Tell the expat XML parser about the end-of-input.
+ if (!XML_Parse(static_cast<XML_Parser>(this->Parser), "", 0, 1)) {
+ this->ReportXmlParseError();
+ result = 0;
+ }
+ }
+
+ // Clean up the parser.
+ XML_ParserFree(static_cast<XML_Parser>(this->Parser));
+ this->Parser = 0;
+
+ return result;
+}
+
+int cmXMLParser::ParseBuffer(const char* buffer, std::string::size_type count)
+{
+ // Pass the buffer to the expat XML parser.
+ if (!XML_Parse(static_cast<XML_Parser>(this->Parser), buffer,
+ static_cast<int>(count), 0)) {
+ this->ReportXmlParseError();
+ return 0;
+ }
+ return 1;
+}
+
+int cmXMLParser::ParseBuffer(const char* buffer)
+{
+ return this->ParseBuffer(buffer, static_cast<int>(strlen(buffer)));
+}
+
+int cmXMLParser::ParsingComplete()
+{
+ // Default behavior is to parse to end of stream.
+ return 0;
+}
+
+void cmXMLParser::StartElement(const std::string& name, const char** /*atts*/)
+{
+ std::cout << "Start element: " << name << std::endl;
+}
+
+void cmXMLParser::EndElement(const std::string& name)
+{
+ std::cout << "End element: " << name << std::endl;
+}
+
+void cmXMLParser::CharacterDataHandler(const char* /*inData*/,
+ int /*inLength*/)
+{
+}
+
+int cmXMLParser::IsSpace(char c)
+{
+ return isspace(c);
+}
+
+const char* cmXMLParser::FindAttribute(const char** atts,
+ const char* attribute)
+{
+ if (atts && attribute) {
+ for (const char** a = atts; *a && *(a + 1); a += 2) {
+ if (strcmp(*a, attribute) == 0) {
+ return *(a + 1);
+ }
+ }
+ }
+ return 0;
+}
+
+void cmXMLParserStartElement(void* parser, const char* name, const char** atts)
+{
+ // Begin element handler that is registered with the XML_Parser.
+ // This just casts the user data to a cmXMLParser and calls
+ // StartElement.
+ static_cast<cmXMLParser*>(parser)->StartElement(name, atts);
+}
+
+void cmXMLParserEndElement(void* parser, const char* name)
+{
+ // End element handler that is registered with the XML_Parser. This
+ // just casts the user data to a cmXMLParser and calls EndElement.
+ static_cast<cmXMLParser*>(parser)->EndElement(name);
+}
+
+void cmXMLParserCharacterDataHandler(void* parser, const char* data,
+ int length)
+{
+ // Character data handler that is registered with the XML_Parser.
+ // This just casts the user data to a cmXMLParser and calls
+ // CharacterDataHandler.
+ static_cast<cmXMLParser*>(parser)->CharacterDataHandler(data, length);
+}
+
+void cmXMLParser::ReportXmlParseError()
+{
+ XML_Parser parser = static_cast<XML_Parser>(this->Parser);
+ this->ReportError(XML_GetCurrentLineNumber(parser),
+ XML_GetCurrentColumnNumber(parser),
+ XML_ErrorString(XML_GetErrorCode(parser)));
+}
+
+void cmXMLParser::ReportError(int line, int, const char* msg)
+{
+ if (this->ReportCallback) {
+ this->ReportCallback(line, msg, this->ReportCallbackData);
+ } else {
+ std::cerr << "Error parsing XML in stream at line " << line << ": " << msg
+ << std::endl;
+ }
+}
diff --git a/Source/cmXMLParser.h b/Source/cmXMLParser.h
new file mode 100644
index 0000000..6aae81d
--- /dev/null
+++ b/Source/cmXMLParser.h
@@ -0,0 +1,118 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmXMLParser_h
+#define cmXMLParser_h
+
+#include "cmStandardIncludes.h"
+
+extern "C" {
+void cmXMLParserStartElement(void*, const char*, const char**);
+void cmXMLParserEndElement(void*, const char*);
+void cmXMLParserCharacterDataHandler(void*, const char*, int);
+}
+
+/** \class cmXMLParser
+ * \brief Helper class for performing XML parsing
+ *
+ * Superclass for all XML parsers.
+ */
+class cmXMLParser
+{
+public:
+ cmXMLParser();
+ virtual ~cmXMLParser();
+
+ //! Parse given XML string
+ virtual int Parse(const char* string);
+
+ //! Parse given XML file
+ virtual int ParseFile(const char* file);
+
+ /**
+ * When parsing fragments of XML or streaming XML, use the following
+ * three methods. InitializeParser method initialize parser but does
+ * not perform any actual parsing. ParseChunk parses framgent of
+ * XML. This has to match to what was already parsed. CleanupParser
+ * finishes parsing. If there were errors, CleanupParser will report
+ * them.
+ */
+ virtual int InitializeParser();
+ virtual int ParseChunk(const char* inputString,
+ std::string::size_type length);
+ virtual int CleanupParser();
+ typedef void (*ReportFunction)(int, const char*, void*);
+ void SetErrorCallback(ReportFunction f, void* d)
+ {
+ this->ReportCallback = f;
+ this->ReportCallbackData = d;
+ }
+
+protected:
+ //! This variable is true if there was a parse error while parsing in
+ // chunks.
+ int ParseError;
+ ReportFunction ReportCallback;
+ void* ReportCallbackData;
+
+ // 1 Expat parser structure. Exists only during call to Parse().
+ void* Parser;
+
+ /**
+ * Called before each block of input is read from the stream to check if
+ * parsing is complete. Can be replaced by subclasses to change the
+ * terminating condition for parsing. Parsing always stops when the end of
+ * file is reached in the stream.
+ */
+
+ virtual int ParsingComplete();
+
+ /**
+ * Called when a new element is opened in the XML source. Should be
+ * replaced by subclasses to handle each element. name = Name of new
+ * element. atts = Null-terminated array of attribute name/value pairs.
+ * Even indices are attribute names, and odd indices are values.
+ */
+ virtual void StartElement(const std::string& name, const char** atts);
+
+ //! Called at the end of an element in the XML source opened when
+ // StartElement was called.
+ virtual void EndElement(const std::string& name);
+
+ //! Called when there is character data to handle.
+ virtual void CharacterDataHandler(const char* data, int length);
+
+ //! Called by Parse to report an XML syntax error.
+ virtual void ReportXmlParseError();
+
+ /** Called by ReportXmlParseError with basic error info. */
+ virtual void ReportError(int line, int column, const char* msg);
+
+ //! Utility for convenience of subclasses. Wraps isspace C library
+ // routine.
+ static int IsSpace(char c);
+
+ //! Send the given buffer to the XML parser.
+ virtual int ParseBuffer(const char* buffer, std::string::size_type length);
+
+ //! Send the given c-style string to the XML parser.
+ int ParseBuffer(const char* buffer);
+
+ /** Helps subclasses search for attributes on elements. */
+ static const char* FindAttribute(const char** atts, const char* attribute);
+
+ //! Callbacks for the expat
+ friend void cmXMLParserStartElement(void*, const char*, const char**);
+ friend void cmXMLParserEndElement(void*, const char*);
+ friend void cmXMLParserCharacterDataHandler(void*, const char*, int);
+};
+
+#endif
diff --git a/Source/cmXMLSafe.cxx b/Source/cmXMLSafe.cxx
new file mode 100644
index 0000000..f899f57
--- /dev/null
+++ b/Source/cmXMLSafe.cxx
@@ -0,0 +1,101 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmXMLSafe.h"
+
+#include "cm_utf8.h"
+
+#include <iostream>
+#include <sstream>
+
+#include <stdio.h>
+#include <string.h>
+
+cmXMLSafe::cmXMLSafe(const char* s)
+ : Data(s)
+ , Size(static_cast<unsigned long>(strlen(s)))
+ , DoQuotes(true)
+{
+}
+
+cmXMLSafe::cmXMLSafe(std::string const& s)
+ : Data(s.c_str())
+ , Size(static_cast<unsigned long>(s.length()))
+ , DoQuotes(true)
+{
+}
+
+cmXMLSafe& cmXMLSafe::Quotes(bool b)
+{
+ this->DoQuotes = b;
+ return *this;
+}
+
+std::string cmXMLSafe::str()
+{
+ std::ostringstream ss;
+ ss << *this;
+ return ss.str();
+}
+
+std::ostream& operator<<(std::ostream& os, cmXMLSafe const& self)
+{
+ char const* first = self.Data;
+ char const* last = self.Data + self.Size;
+ while (first != last) {
+ unsigned int ch;
+ if (const char* next = cm_utf8_decode_character(first, last, &ch)) {
+ // http://www.w3.org/TR/REC-xml/#NT-Char
+ if ((ch >= 0x20 && ch <= 0xD7FF) || (ch >= 0xE000 && ch <= 0xFFFD) ||
+ (ch >= 0x10000 && ch <= 0x10FFFF) || ch == 0x9 || ch == 0xA ||
+ ch == 0xD) {
+ switch (ch) {
+ // Escape XML control characters.
+ case '&':
+ os << "&amp;";
+ break;
+ case '<':
+ os << "&lt;";
+ break;
+ case '>':
+ os << "&gt;";
+ break;
+ case '"':
+ os << (self.DoQuotes ? "&quot;" : "\"");
+ break;
+ case '\'':
+ os << (self.DoQuotes ? "&apos;" : "'");
+ break;
+ case '\r':
+ break; // Ignore CR
+ // Print the UTF-8 character.
+ default:
+ os.write(first, next - first);
+ break;
+ }
+ } else {
+ // Use a human-readable hex value for this invalid character.
+ char buf[16];
+ sprintf(buf, "%X", ch);
+ os << "[NON-XML-CHAR-0x" << buf << "]";
+ }
+
+ first = next;
+ } else {
+ ch = static_cast<unsigned char>(*first++);
+ // Use a human-readable hex value for this invalid byte.
+ char buf[16];
+ sprintf(buf, "%X", ch);
+ os << "[NON-UTF-8-BYTE-0x" << buf << "]";
+ }
+ }
+ return os;
+}
diff --git a/Source/cmXMLSafe.h b/Source/cmXMLSafe.h
new file mode 100644
index 0000000..11ced13
--- /dev/null
+++ b/Source/cmXMLSafe.h
@@ -0,0 +1,46 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmXMLSafe_h
+#define cmXMLSafe_h
+
+#include <cmsys/Configure.hxx>
+
+#include <iosfwd>
+#include <string>
+
+/** \class cmXMLSafe
+ * \brief Write strings to XML with proper escapes
+ */
+class cmXMLSafe
+{
+public:
+ /** Construct with the data to be written. This assumes the data
+ will exist for the duration of this object's life. */
+ cmXMLSafe(const char* s);
+ cmXMLSafe(std::string const& s);
+
+ /** Specify whether to escape quotes too. This is needed when
+ writing the content of an attribute value. By default quotes
+ are escaped. */
+ cmXMLSafe& Quotes(bool b = true);
+
+ /** Get the escaped data as a string. */
+ std::string str();
+
+private:
+ char const* Data;
+ unsigned long Size;
+ bool DoQuotes;
+ friend std::ostream& operator<<(std::ostream&, cmXMLSafe const&);
+};
+
+#endif
diff --git a/Source/cmXMLWriter.cxx b/Source/cmXMLWriter.cxx
new file mode 100644
index 0000000..e2dce93d
--- /dev/null
+++ b/Source/cmXMLWriter.cxx
@@ -0,0 +1,143 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Daniel Pfeifer <daniel@pfeifer-mail.de>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmXMLWriter.h"
+
+#include "cmXMLSafe.h"
+
+#include <cassert>
+#include <cmsys/FStream.hxx>
+
+cmXMLWriter::cmXMLWriter(std::ostream& output, std::size_t level)
+ : Output(output)
+ , Level(level)
+ , ElementOpen(false)
+ , BreakAttrib(false)
+ , IsContent(false)
+{
+}
+
+cmXMLWriter::~cmXMLWriter()
+{
+ assert(this->Elements.empty());
+}
+
+void cmXMLWriter::StartDocument(const char* encoding)
+{
+ this->Output << "<?xml version=\"1.0\" encoding=\"" << encoding << "\"?>";
+}
+
+void cmXMLWriter::EndDocument()
+{
+ assert(this->Elements.empty());
+ this->Output << '\n';
+}
+
+void cmXMLWriter::StartElement(std::string const& name)
+{
+ this->CloseStartElement();
+ this->ConditionalLineBreak(!this->IsContent, this->Elements.size());
+ this->Output << '<' << name;
+ this->Elements.push(name);
+ this->ElementOpen = true;
+ this->BreakAttrib = false;
+}
+
+void cmXMLWriter::EndElement()
+{
+ assert(!this->Elements.empty());
+ if (this->ElementOpen) {
+ this->Output << "/>";
+ } else {
+ this->ConditionalLineBreak(!this->IsContent, this->Elements.size() - 1);
+ this->IsContent = false;
+ this->Output << "</" << this->Elements.top() << '>';
+ }
+ this->Elements.pop();
+ this->ElementOpen = false;
+}
+
+void cmXMLWriter::Element(const char* name)
+{
+ this->CloseStartElement();
+ this->ConditionalLineBreak(!this->IsContent, this->Elements.size());
+ this->Output << '<' << name << "/>";
+}
+
+void cmXMLWriter::BreakAttributes()
+{
+ this->BreakAttrib = true;
+}
+
+void cmXMLWriter::Comment(const char* comment)
+{
+ this->CloseStartElement();
+ this->ConditionalLineBreak(!this->IsContent, this->Elements.size());
+ this->Output << "<!-- " << comment << " -->";
+}
+
+void cmXMLWriter::CData(std::string const& data)
+{
+ this->PreContent();
+ this->Output << "<![CDATA[" << data << "]]>";
+}
+
+void cmXMLWriter::Doctype(const char* doctype)
+{
+ this->CloseStartElement();
+ this->ConditionalLineBreak(!this->IsContent, this->Elements.size());
+ this->Output << "<!DOCTYPE " << doctype << ">";
+}
+
+void cmXMLWriter::ProcessingInstruction(const char* target, const char* data)
+{
+ this->CloseStartElement();
+ this->ConditionalLineBreak(!this->IsContent, this->Elements.size());
+ this->Output << "<?" << target << ' ' << data << "?>";
+}
+
+void cmXMLWriter::FragmentFile(const char* fname)
+{
+ this->CloseStartElement();
+ cmsys::ifstream fin(fname, std::ios::in | std::ios::binary);
+ this->Output << fin.rdbuf();
+}
+
+void cmXMLWriter::ConditionalLineBreak(bool condition, std::size_t indent)
+{
+ if (condition) {
+ this->Output << '\n' << std::string(indent + this->Level, '\t');
+ }
+}
+
+void cmXMLWriter::PreAttribute()
+{
+ assert(this->ElementOpen);
+ this->ConditionalLineBreak(this->BreakAttrib, this->Elements.size());
+ if (!this->BreakAttrib) {
+ this->Output << ' ';
+ }
+}
+
+void cmXMLWriter::PreContent()
+{
+ this->CloseStartElement();
+ this->IsContent = true;
+}
+
+void cmXMLWriter::CloseStartElement()
+{
+ if (this->ElementOpen) {
+ this->ConditionalLineBreak(this->BreakAttrib, this->Elements.size());
+ this->Output << '>';
+ this->ElementOpen = false;
+ }
+}
diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h
new file mode 100644
index 0000000..8a88dd4
--- /dev/null
+++ b/Source/cmXMLWriter.h
@@ -0,0 +1,125 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Daniel Pfeifer <daniel@pfeifer-mail.de>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmXMLWiter_h
+#define cmXMLWiter_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmXMLSafe.h"
+
+#include <ostream>
+#include <stack>
+#include <string>
+#include <vector>
+
+class cmXMLWriter
+{
+public:
+ cmXMLWriter(std::ostream& output, std::size_t level = 0);
+ ~cmXMLWriter();
+
+ void StartDocument(const char* encoding = "UTF-8");
+ void EndDocument();
+
+ void StartElement(std::string const& name);
+ void EndElement();
+
+ void BreakAttributes();
+
+ template <typename T>
+ void Attribute(const char* name, T const& value)
+ {
+ this->PreAttribute();
+ this->Output << name << "=\"" << SafeAttribute(value) << '"';
+ }
+
+ void Element(const char* name);
+
+ template <typename T>
+ void Element(std::string const& name, T const& value)
+ {
+ this->StartElement(name);
+ this->Content(value);
+ this->EndElement();
+ }
+
+ template <typename T>
+ void Content(T const& content)
+ {
+ this->PreContent();
+ this->Output << SafeContent(content);
+ }
+
+ void Comment(const char* comment);
+
+ void CData(std::string const& data);
+
+ void Doctype(const char* doctype);
+
+ void ProcessingInstruction(const char* target, const char* data);
+
+ void FragmentFile(const char* fname);
+
+private:
+ cmXMLWriter(const cmXMLWriter&);
+ cmXMLWriter& operator=(const cmXMLWriter&);
+
+ void ConditionalLineBreak(bool condition, std::size_t indent);
+
+ void PreAttribute();
+ void PreContent();
+
+ void CloseStartElement();
+
+private:
+ static cmXMLSafe SafeAttribute(const char* value)
+ {
+ return cmXMLSafe(value);
+ }
+
+ static cmXMLSafe SafeAttribute(std::string const& value)
+ {
+ return cmXMLSafe(value);
+ }
+
+ template <typename T>
+ static T SafeAttribute(T value)
+ {
+ return value;
+ }
+
+ static cmXMLSafe SafeContent(const char* value)
+ {
+ return cmXMLSafe(value).Quotes(false);
+ }
+
+ static cmXMLSafe SafeContent(std::string const& value)
+ {
+ return cmXMLSafe(value).Quotes(false);
+ }
+
+ template <typename T>
+ static T SafeContent(T value)
+ {
+ return value;
+ }
+
+private:
+ std::ostream& Output;
+ std::stack<std::string, std::vector<std::string> > Elements;
+ std::size_t Level;
+ bool ElementOpen;
+ bool BreakAttrib;
+ bool IsContent;
+};
+
+#endif
diff --git a/Source/cm_auto_ptr.hxx b/Source/cm_auto_ptr.hxx
new file mode 100644
index 0000000..2cd35c3
--- /dev/null
+++ b/Source/cm_auto_ptr.hxx
@@ -0,0 +1,221 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2016 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef CM_AUTO_PTR_HXX
+#define CM_AUTO_PTR_HXX
+
+#include <cmsys/Configure.hxx>
+
+// FIXME: Use std::auto_ptr on compilers that do not warn about it.
+#define CM_AUTO_PTR cm::auto_ptr
+
+// The HP compiler cannot handle the conversions necessary to use
+// auto_ptr_ref to pass an auto_ptr returned from one function
+// directly to another function as in use_auto_ptr(get_auto_ptr()).
+// We instead use const_cast to achieve the syntax on those platforms.
+// We do not use const_cast on other platforms to maintain the C++
+// standard design and guarantee that if an auto_ptr is bound
+// to a reference-to-const then ownership will be maintained.
+#if defined(__HP_aCC)
+#define cm_AUTO_PTR_REF 0
+#define cm_AUTO_PTR_CONST const
+#define cm_AUTO_PTR_CAST(a) cast(a)
+#else
+#define cm_AUTO_PTR_REF 1
+#define cm_AUTO_PTR_CONST
+#define cm_AUTO_PTR_CAST(a) a
+#endif
+
+// In C++11, clang will warn about using dynamic exception specifications
+// as they are deprecated. But as this class is trying to faithfully
+// mimic std::auto_ptr, we want to keep the 'throw()' decorations below.
+// So we suppress the warning.
+#if defined(__clang__) && defined(__has_warning)
+#if __has_warning("-Wdeprecated")
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated"
+#endif
+#endif
+
+namespace cm {
+
+template <class X>
+class auto_ptr;
+
+#if cm_AUTO_PTR_REF
+namespace detail {
+// The auto_ptr_ref template is supposed to be a private member of
+// auto_ptr but Borland 5.8 cannot handle it. Instead put it in
+// a private namespace.
+template <class Y>
+struct auto_ptr_ref
+{
+ Y* p_;
+
+ // The extra constructor argument prevents implicit conversion to
+ // auto_ptr_ref from auto_ptr through the constructor. Normally
+ // this should be done with the explicit keyword but Borland 5.x
+ // generates code in the conversion operator to call itself
+ // infinately.
+ auto_ptr_ref(Y* p, int)
+ : p_(p)
+ {
+ }
+};
+}
+#endif
+
+/** C++98 Standard Section 20.4.5 - Template class auto_ptr. */
+template <class X>
+class auto_ptr
+{
+#if !cm_AUTO_PTR_REF
+ template <typename Y>
+ static inline auto_ptr<Y>& cast(auto_ptr<Y> const& a)
+ {
+ return const_cast<auto_ptr<Y>&>(a);
+ }
+#endif
+
+ /** The pointer to the object held. */
+ X* x_;
+
+public:
+ /** The type of object held by the auto_ptr. */
+ typedef X element_type;
+
+ /** Construct from an auto_ptr holding a compatible object. This
+ transfers ownership to the newly constructed auto_ptr. */
+ template <class Y>
+ auto_ptr(auto_ptr<Y> cm_AUTO_PTR_CONST& a) throw()
+ : x_(cm_AUTO_PTR_CAST(a).release())
+ {
+ }
+
+ /** Assign from an auto_ptr holding a compatible object. This
+ transfers ownership to the left-hand-side of the assignment. */
+ template <class Y>
+ auto_ptr& operator=(auto_ptr<Y> cm_AUTO_PTR_CONST& a) throw()
+ {
+ this->reset(cm_AUTO_PTR_CAST(a).release());
+ return *this;
+ }
+
+ /**
+ * Explicitly construct from a raw pointer. This is typically
+ * called with the result of operator new. For example:
+ *
+ * auto_ptr<X> ptr(new X());
+ */
+ explicit auto_ptr(X* p = 0) throw()
+ : x_(p)
+ {
+ }
+
+ /** Construct from another auto_ptr holding an object of the same
+ type. This transfers ownership to the newly constructed
+ auto_ptr. */
+ auto_ptr(auto_ptr cm_AUTO_PTR_CONST& a) throw()
+ : x_(cm_AUTO_PTR_CAST(a).release())
+ {
+ }
+
+ /** Assign from another auto_ptr holding an object of the same type.
+ This transfers ownership to the newly constructed auto_ptr. */
+ auto_ptr& operator=(auto_ptr cm_AUTO_PTR_CONST& a) throw()
+ {
+ this->reset(cm_AUTO_PTR_CAST(a).release());
+ return *this;
+ }
+
+ /** Destruct and delete the object held. */
+ ~auto_ptr() throw()
+ {
+ // Assume object destructor is nothrow.
+ delete this->x_;
+ }
+
+ /** Dereference and return a reference to the object held. */
+ X& operator*() const throw() { return *this->x_; }
+
+ /** Return a pointer to the object held. */
+ X* operator->() const throw() { return this->x_; }
+
+ /** Return a pointer to the object held. */
+ X* get() const throw() { return this->x_; }
+
+ /** Return a pointer to the object held and reset to hold no object.
+ This transfers ownership to the caller. */
+ X* release() throw()
+ {
+ X* x = this->x_;
+ this->x_ = 0;
+ return x;
+ }
+
+ /** Assume ownership of the given object. The object previously
+ held is deleted. */
+ void reset(X* p = 0) throw()
+ {
+ if (this->x_ != p) {
+ // Assume object destructor is nothrow.
+ delete this->x_;
+ this->x_ = p;
+ }
+ }
+
+ /** Convert to an auto_ptr holding an object of a compatible type.
+ This transfers ownership to the returned auto_ptr. */
+ template <class Y>
+ operator auto_ptr<Y>() throw()
+ {
+ return auto_ptr<Y>(this->release());
+ }
+
+#if cm_AUTO_PTR_REF
+ /** Construct from an auto_ptr_ref. This is used when the
+ constructor argument is a call to a function returning an
+ auto_ptr. */
+ auto_ptr(detail::auto_ptr_ref<X> r) throw()
+ : x_(r.p_)
+ {
+ }
+
+ /** Assign from an auto_ptr_ref. This is used when a function
+ returning an auto_ptr is passed on the right-hand-side of an
+ assignment. */
+ auto_ptr& operator=(detail::auto_ptr_ref<X> r) throw()
+ {
+ this->reset(r.p_);
+ return *this;
+ }
+
+ /** Convert to an auto_ptr_ref. This is used when a function
+ returning an auto_ptr is the argument to the constructor of
+ another auto_ptr. */
+ template <class Y>
+ operator detail::auto_ptr_ref<Y>() throw()
+ {
+ return detail::auto_ptr_ref<Y>(this->release(), 1);
+ }
+#endif
+};
+
+} // namespace cm
+
+// Undo warning suppression.
+#if defined(__clang__) && defined(__has_warning)
+#if __has_warning("-Wdeprecated")
+#pragma clang diagnostic pop
+#endif
+#endif
+
+#endif
diff --git a/Source/cm_get_date.c b/Source/cm_get_date.c
new file mode 100644
index 0000000..2e0d4bd
--- /dev/null
+++ b/Source/cm_get_date.c
@@ -0,0 +1,16 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cm_get_date.h"
+
+#define __archive_get_date cm_get_date
+
+#include "../Utilities/cmlibarchive/libarchive/archive_getdate.c"
diff --git a/Source/cm_get_date.h b/Source/cm_get_date.h
new file mode 100644
index 0000000..3045775
--- /dev/null
+++ b/Source/cm_get_date.h
@@ -0,0 +1,28 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cm_get_date_h
+#define cm_get_date_h
+
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Parse a date/time string. Treat relative times with respect to 'now'. */
+time_t cm_get_date(time_t now, const char* str);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/Source/cm_sha2.c b/Source/cm_sha2.c
new file mode 100644
index 0000000..649c39a
--- /dev/null
+++ b/Source/cm_sha2.c
@@ -0,0 +1,1613 @@
+/*
+ * FILE: sha2.c
+ * AUTHOR: Aaron D. Gifford
+ * http://www.aarongifford.com/computers/sha.html
+ *
+ * Copyright (c) 2000-2003, Aaron D. Gifford
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sha2.c,v 1.4 2004/01/07 22:58:18 adg Exp $
+ */
+
+#include <string.h> /* memcpy()/memset() or bcopy()/bzero() */
+#include <assert.h> /* assert() */
+#include "cm_sha2.h" /* "sha2.h" -> "cm_sha2.h" renamed for CMake */
+
+/*
+ * ASSERT NOTE:
+ * Some sanity checking code is included using assert(). On my FreeBSD
+ * system, this additional code can be removed by compiling with NDEBUG
+ * defined. Check your own systems manpage on assert() to see how to
+ * compile WITHOUT the sanity checking code on your system.
+ *
+ * UNROLLED TRANSFORM LOOP NOTE:
+ * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
+ * loop version for the hash transform rounds (defined using macros
+ * later in this file). Either define on the command line, for example:
+ *
+ * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
+ *
+ * or define below:
+ *
+ * #define SHA2_UNROLL_TRANSFORM
+ *
+ */
+
+
+/*** SHA-224/256/384/512 Machine Architecture Definitions *************/
+/*
+ * BYTE_ORDER NOTE:
+ *
+ * Please make sure that your system defines BYTE_ORDER. If your
+ * architecture is little-endian, make sure it also defines
+ * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
+ * equivilent.
+ *
+ * If your system does not define the above, then you can do so by
+ * hand like this:
+ *
+ * #define LITTLE_ENDIAN 1234
+ * #define BIG_ENDIAN 4321
+ *
+ * And for little-endian machines, add:
+ *
+ * #define BYTE_ORDER LITTLE_ENDIAN
+ *
+ * Or for big-endian machines:
+ *
+ * #define BYTE_ORDER BIG_ENDIAN
+ *
+ * The FreeBSD machine this was written on defines BYTE_ORDER
+ * appropriately by including <sys/types.h> (which in turn includes
+ * <machine/endian.h> where the appropriate definitions are actually
+ * made).
+ */
+#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN)
+/* CMake modification: use byte order from KWIML. */
+# undef BYTE_ORDER
+# undef BIG_ENDIAN
+# undef LITTLE_ENDIAN
+# define BYTE_ORDER KWIML_ABI_ENDIAN_ID
+# define BIG_ENDIAN KWIML_ABI_ENDIAN_ID_BIG
+# define LITTLE_ENDIAN KWIML_ABI_ENDIAN_ID_LITTLE
+#endif
+
+/* CMake modification: use types computed in header. */
+typedef cm_sha2_uint8_t sha_byte; /* Exactly 1 byte */
+typedef cm_sha2_uint32_t sha_word32; /* Exactly 4 bytes */
+typedef cm_sha2_uint64_t sha_word64; /* Exactly 8 bytes */
+#define SHA_UINT32_C(x) KWIML_INT_UINT32_C(x)
+#define SHA_UINT64_C(x) KWIML_INT_UINT64_C(x)
+#if defined(__clang__)
+# pragma clang diagnostic ignored "-Wcast-align"
+#endif
+
+/*** ENDIAN REVERSAL MACROS *******************************************/
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define REVERSE32(w,x) { \
+ sha_word32 tmp = (w); \
+ tmp = (tmp >> 16) | (tmp << 16); \
+ (x) = ((tmp & SHA_UINT32_C(0xff00ff00)) >> 8) | \
+ ((tmp & SHA_UINT32_C(0x00ff00ff)) << 8); \
+}
+#define REVERSE64(w,x) { \
+ sha_word64 tmp = (w); \
+ tmp = (tmp >> 32) | (tmp << 32); \
+ tmp = ((tmp & SHA_UINT64_C(0xff00ff00ff00ff00)) >> 8) | \
+ ((tmp & SHA_UINT64_C(0x00ff00ff00ff00ff)) << 8); \
+ (x) = ((tmp & SHA_UINT64_C(0xffff0000ffff0000)) >> 16) | \
+ ((tmp & SHA_UINT64_C(0x0000ffff0000ffff)) << 16); \
+}
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+/*
+ * Macro for incrementally adding the unsigned 64-bit integer n to the
+ * unsigned 128-bit integer (represented using a two-element array of
+ * 64-bit words):
+ */
+#define ADDINC128(w,n) { \
+ (w)[0] += (sha_word64)(n); \
+ if ((w)[0] < (n)) { \
+ (w)[1]++; \
+ } \
+}
+
+/*
+ * Macros for copying blocks of memory and for zeroing out ranges
+ * of memory. Using these macros makes it easy to switch from
+ * using memset()/memcpy() and using bzero()/bcopy().
+ *
+ * Please define either SHA2_USE_MEMSET_MEMCPY or define
+ * SHA2_USE_BZERO_BCOPY depending on which function set you
+ * choose to use:
+ */
+#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY)
+/* Default to memset()/memcpy() if no option is specified */
+#define SHA2_USE_MEMSET_MEMCPY 1
+#endif
+#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY)
+/* Abort with an error if BOTH options are defined */
+#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both!
+#endif
+
+#ifdef SHA2_USE_MEMSET_MEMCPY
+#define MEMSET_BZERO(p,l) memset((p), 0, (l))
+#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l))
+#endif
+#ifdef SHA2_USE_BZERO_BCOPY
+#define MEMSET_BZERO(p,l) bzero((p), (l))
+#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l))
+#endif
+
+
+/*** THE SIX LOGICAL FUNCTIONS ****************************************/
+/*
+ * Bit shifting and rotation (used by the six SHA-XYZ logical functions:
+ *
+ * NOTE: In the original SHA-256/384/512 document, the shift-right
+ * function was named R and the rotate-right function was called S.
+ * (See: http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf on the
+ * web.)
+ *
+ * The newer NIST FIPS 180-2 document uses a much clearer naming
+ * scheme, SHR for shift-right, ROTR for rotate-right, and ROTL for
+ * rotate-left. (See:
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+ * on the web.)
+ *
+ * WARNING: These macros must be used cautiously, since they reference
+ * supplied parameters sometimes more than once, and thus could have
+ * unexpected side-effects if used without taking this into account.
+ */
+/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
+#define SHR(b,x) ((x) >> (b))
+/* 32-bit Rotate-right (used in SHA-256): */
+#define ROTR32(b,x) (((x) >> (b)) | ((x) << (32 - (b))))
+/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
+#define ROTR64(b,x) (((x) >> (b)) | ((x) << (64 - (b))))
+/* 32-bit Rotate-left (used in SHA-1): */
+#define ROTL32(b,x) (((x) << (b)) | ((x) >> (32 - (b))))
+
+/* Two logical functions used in SHA-1, SHA-254, SHA-256, SHA-384, and SHA-512: */
+#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+/* Function used in SHA-1: */
+#define Parity(x,y,z) ((x) ^ (y) ^ (z))
+
+/* Four logical functions used in SHA-256: */
+#define Sigma0_256(x) (ROTR32(2, (x)) ^ ROTR32(13, (x)) ^ ROTR32(22, (x)))
+#define Sigma1_256(x) (ROTR32(6, (x)) ^ ROTR32(11, (x)) ^ ROTR32(25, (x)))
+#define sigma0_256(x) (ROTR32(7, (x)) ^ ROTR32(18, (x)) ^ SHR( 3 , (x)))
+#define sigma1_256(x) (ROTR32(17, (x)) ^ ROTR32(19, (x)) ^ SHR( 10, (x)))
+
+/* Four of six logical functions used in SHA-384 and SHA-512: */
+#define Sigma0_512(x) (ROTR64(28, (x)) ^ ROTR64(34, (x)) ^ ROTR64(39, (x)))
+#define Sigma1_512(x) (ROTR64(14, (x)) ^ ROTR64(18, (x)) ^ ROTR64(41, (x)))
+#define sigma0_512(x) (ROTR64( 1, (x)) ^ ROTR64( 8, (x)) ^ SHR( 7, (x)))
+#define sigma1_512(x) (ROTR64(19, (x)) ^ ROTR64(61, (x)) ^ SHR( 6, (x)))
+
+/*** INTERNAL FUNCTION PROTOTYPES *************************************/
+
+/* SHA-224 and SHA-256: */
+void SHA256_Internal_Init(SHA_CTX*, const sha_word32*);
+void SHA256_Internal_Last(SHA_CTX*);
+void SHA256_Internal_Transform(SHA_CTX*, const sha_word32*);
+
+/* SHA-384 and SHA-512: */
+void SHA512_Internal_Init(SHA_CTX*, const sha_word64*);
+void SHA512_Internal_Last(SHA_CTX*);
+void SHA512_Internal_Transform(SHA_CTX*, const sha_word64*);
+
+
+/*** SHA2 INITIAL HASH VALUES AND CONSTANTS ***************************/
+
+/* Hash constant words K for SHA-1: */
+#define K1_0_TO_19 SHA_UINT32_C(0x5a827999)
+#define K1_20_TO_39 SHA_UINT32_C(0x6ed9eba1)
+#define K1_40_TO_59 SHA_UINT32_C(0x8f1bbcdc)
+#define K1_60_TO_79 SHA_UINT32_C(0xca62c1d6)
+
+/* Initial hash value H for SHA-1: */
+static const sha_word32 sha1_initial_hash_value[5] = {
+ SHA_UINT32_C(0x67452301),
+ SHA_UINT32_C(0xefcdab89),
+ SHA_UINT32_C(0x98badcfe),
+ SHA_UINT32_C(0x10325476),
+ SHA_UINT32_C(0xc3d2e1f0)
+};
+
+/* Hash constant words K for SHA-224 and SHA-256: */
+static const sha_word32 K256[64] = {
+ SHA_UINT32_C(0x428a2f98), SHA_UINT32_C(0x71374491),
+ SHA_UINT32_C(0xb5c0fbcf), SHA_UINT32_C(0xe9b5dba5),
+ SHA_UINT32_C(0x3956c25b), SHA_UINT32_C(0x59f111f1),
+ SHA_UINT32_C(0x923f82a4), SHA_UINT32_C(0xab1c5ed5),
+ SHA_UINT32_C(0xd807aa98), SHA_UINT32_C(0x12835b01),
+ SHA_UINT32_C(0x243185be), SHA_UINT32_C(0x550c7dc3),
+ SHA_UINT32_C(0x72be5d74), SHA_UINT32_C(0x80deb1fe),
+ SHA_UINT32_C(0x9bdc06a7), SHA_UINT32_C(0xc19bf174),
+ SHA_UINT32_C(0xe49b69c1), SHA_UINT32_C(0xefbe4786),
+ SHA_UINT32_C(0x0fc19dc6), SHA_UINT32_C(0x240ca1cc),
+ SHA_UINT32_C(0x2de92c6f), SHA_UINT32_C(0x4a7484aa),
+ SHA_UINT32_C(0x5cb0a9dc), SHA_UINT32_C(0x76f988da),
+ SHA_UINT32_C(0x983e5152), SHA_UINT32_C(0xa831c66d),
+ SHA_UINT32_C(0xb00327c8), SHA_UINT32_C(0xbf597fc7),
+ SHA_UINT32_C(0xc6e00bf3), SHA_UINT32_C(0xd5a79147),
+ SHA_UINT32_C(0x06ca6351), SHA_UINT32_C(0x14292967),
+ SHA_UINT32_C(0x27b70a85), SHA_UINT32_C(0x2e1b2138),
+ SHA_UINT32_C(0x4d2c6dfc), SHA_UINT32_C(0x53380d13),
+ SHA_UINT32_C(0x650a7354), SHA_UINT32_C(0x766a0abb),
+ SHA_UINT32_C(0x81c2c92e), SHA_UINT32_C(0x92722c85),
+ SHA_UINT32_C(0xa2bfe8a1), SHA_UINT32_C(0xa81a664b),
+ SHA_UINT32_C(0xc24b8b70), SHA_UINT32_C(0xc76c51a3),
+ SHA_UINT32_C(0xd192e819), SHA_UINT32_C(0xd6990624),
+ SHA_UINT32_C(0xf40e3585), SHA_UINT32_C(0x106aa070),
+ SHA_UINT32_C(0x19a4c116), SHA_UINT32_C(0x1e376c08),
+ SHA_UINT32_C(0x2748774c), SHA_UINT32_C(0x34b0bcb5),
+ SHA_UINT32_C(0x391c0cb3), SHA_UINT32_C(0x4ed8aa4a),
+ SHA_UINT32_C(0x5b9cca4f), SHA_UINT32_C(0x682e6ff3),
+ SHA_UINT32_C(0x748f82ee), SHA_UINT32_C(0x78a5636f),
+ SHA_UINT32_C(0x84c87814), SHA_UINT32_C(0x8cc70208),
+ SHA_UINT32_C(0x90befffa), SHA_UINT32_C(0xa4506ceb),
+ SHA_UINT32_C(0xbef9a3f7), SHA_UINT32_C(0xc67178f2)
+};
+
+/* Initial hash value H for SHA-224: */
+static const sha_word32 sha224_initial_hash_value[8] = {
+ SHA_UINT32_C(0xc1059ed8),
+ SHA_UINT32_C(0x367cd507),
+ SHA_UINT32_C(0x3070dd17),
+ SHA_UINT32_C(0xf70e5939),
+ SHA_UINT32_C(0xffc00b31),
+ SHA_UINT32_C(0x68581511),
+ SHA_UINT32_C(0x64f98fa7),
+ SHA_UINT32_C(0xbefa4fa4)
+};
+
+/* Initial hash value H for SHA-256: */
+static const sha_word32 sha256_initial_hash_value[8] = {
+ SHA_UINT32_C(0x6a09e667),
+ SHA_UINT32_C(0xbb67ae85),
+ SHA_UINT32_C(0x3c6ef372),
+ SHA_UINT32_C(0xa54ff53a),
+ SHA_UINT32_C(0x510e527f),
+ SHA_UINT32_C(0x9b05688c),
+ SHA_UINT32_C(0x1f83d9ab),
+ SHA_UINT32_C(0x5be0cd19)
+};
+
+/* Hash constant words K for SHA-384 and SHA-512: */
+static const sha_word64 K512[80] = {
+ SHA_UINT64_C(0x428a2f98d728ae22), SHA_UINT64_C(0x7137449123ef65cd),
+ SHA_UINT64_C(0xb5c0fbcfec4d3b2f), SHA_UINT64_C(0xe9b5dba58189dbbc),
+ SHA_UINT64_C(0x3956c25bf348b538), SHA_UINT64_C(0x59f111f1b605d019),
+ SHA_UINT64_C(0x923f82a4af194f9b), SHA_UINT64_C(0xab1c5ed5da6d8118),
+ SHA_UINT64_C(0xd807aa98a3030242), SHA_UINT64_C(0x12835b0145706fbe),
+ SHA_UINT64_C(0x243185be4ee4b28c), SHA_UINT64_C(0x550c7dc3d5ffb4e2),
+ SHA_UINT64_C(0x72be5d74f27b896f), SHA_UINT64_C(0x80deb1fe3b1696b1),
+ SHA_UINT64_C(0x9bdc06a725c71235), SHA_UINT64_C(0xc19bf174cf692694),
+ SHA_UINT64_C(0xe49b69c19ef14ad2), SHA_UINT64_C(0xefbe4786384f25e3),
+ SHA_UINT64_C(0x0fc19dc68b8cd5b5), SHA_UINT64_C(0x240ca1cc77ac9c65),
+ SHA_UINT64_C(0x2de92c6f592b0275), SHA_UINT64_C(0x4a7484aa6ea6e483),
+ SHA_UINT64_C(0x5cb0a9dcbd41fbd4), SHA_UINT64_C(0x76f988da831153b5),
+ SHA_UINT64_C(0x983e5152ee66dfab), SHA_UINT64_C(0xa831c66d2db43210),
+ SHA_UINT64_C(0xb00327c898fb213f), SHA_UINT64_C(0xbf597fc7beef0ee4),
+ SHA_UINT64_C(0xc6e00bf33da88fc2), SHA_UINT64_C(0xd5a79147930aa725),
+ SHA_UINT64_C(0x06ca6351e003826f), SHA_UINT64_C(0x142929670a0e6e70),
+ SHA_UINT64_C(0x27b70a8546d22ffc), SHA_UINT64_C(0x2e1b21385c26c926),
+ SHA_UINT64_C(0x4d2c6dfc5ac42aed), SHA_UINT64_C(0x53380d139d95b3df),
+ SHA_UINT64_C(0x650a73548baf63de), SHA_UINT64_C(0x766a0abb3c77b2a8),
+ SHA_UINT64_C(0x81c2c92e47edaee6), SHA_UINT64_C(0x92722c851482353b),
+ SHA_UINT64_C(0xa2bfe8a14cf10364), SHA_UINT64_C(0xa81a664bbc423001),
+ SHA_UINT64_C(0xc24b8b70d0f89791), SHA_UINT64_C(0xc76c51a30654be30),
+ SHA_UINT64_C(0xd192e819d6ef5218), SHA_UINT64_C(0xd69906245565a910),
+ SHA_UINT64_C(0xf40e35855771202a), SHA_UINT64_C(0x106aa07032bbd1b8),
+ SHA_UINT64_C(0x19a4c116b8d2d0c8), SHA_UINT64_C(0x1e376c085141ab53),
+ SHA_UINT64_C(0x2748774cdf8eeb99), SHA_UINT64_C(0x34b0bcb5e19b48a8),
+ SHA_UINT64_C(0x391c0cb3c5c95a63), SHA_UINT64_C(0x4ed8aa4ae3418acb),
+ SHA_UINT64_C(0x5b9cca4f7763e373), SHA_UINT64_C(0x682e6ff3d6b2b8a3),
+ SHA_UINT64_C(0x748f82ee5defb2fc), SHA_UINT64_C(0x78a5636f43172f60),
+ SHA_UINT64_C(0x84c87814a1f0ab72), SHA_UINT64_C(0x8cc702081a6439ec),
+ SHA_UINT64_C(0x90befffa23631e28), SHA_UINT64_C(0xa4506cebde82bde9),
+ SHA_UINT64_C(0xbef9a3f7b2c67915), SHA_UINT64_C(0xc67178f2e372532b),
+ SHA_UINT64_C(0xca273eceea26619c), SHA_UINT64_C(0xd186b8c721c0c207),
+ SHA_UINT64_C(0xeada7dd6cde0eb1e), SHA_UINT64_C(0xf57d4f7fee6ed178),
+ SHA_UINT64_C(0x06f067aa72176fba), SHA_UINT64_C(0x0a637dc5a2c898a6),
+ SHA_UINT64_C(0x113f9804bef90dae), SHA_UINT64_C(0x1b710b35131c471b),
+ SHA_UINT64_C(0x28db77f523047d84), SHA_UINT64_C(0x32caab7b40c72493),
+ SHA_UINT64_C(0x3c9ebe0a15c9bebc), SHA_UINT64_C(0x431d67c49c100d4c),
+ SHA_UINT64_C(0x4cc5d4becb3e42b6), SHA_UINT64_C(0x597f299cfc657e2a),
+ SHA_UINT64_C(0x5fcb6fab3ad6faec), SHA_UINT64_C(0x6c44198c4a475817)
+};
+
+/* Initial hash value H for SHA-384 */
+static const sha_word64 sha384_initial_hash_value[8] = {
+ SHA_UINT64_C(0xcbbb9d5dc1059ed8),
+ SHA_UINT64_C(0x629a292a367cd507),
+ SHA_UINT64_C(0x9159015a3070dd17),
+ SHA_UINT64_C(0x152fecd8f70e5939),
+ SHA_UINT64_C(0x67332667ffc00b31),
+ SHA_UINT64_C(0x8eb44a8768581511),
+ SHA_UINT64_C(0xdb0c2e0d64f98fa7),
+ SHA_UINT64_C(0x47b5481dbefa4fa4)
+};
+
+/* Initial hash value H for SHA-512 */
+static const sha_word64 sha512_initial_hash_value[8] = {
+ SHA_UINT64_C(0x6a09e667f3bcc908),
+ SHA_UINT64_C(0xbb67ae8584caa73b),
+ SHA_UINT64_C(0x3c6ef372fe94f82b),
+ SHA_UINT64_C(0xa54ff53a5f1d36f1),
+ SHA_UINT64_C(0x510e527fade682d1),
+ SHA_UINT64_C(0x9b05688c2b3e6c1f),
+ SHA_UINT64_C(0x1f83d9abfb41bd6b),
+ SHA_UINT64_C(0x5be0cd19137e2179)
+};
+
+/*
+ * Constant used by SHA224/256/384/512_End() functions for converting the
+ * digest to a readable hexadecimal character string:
+ */
+static const char *sha_hex_digits = "0123456789abcdef";
+
+
+/*** SHA-1: ***********************************************************/
+void SHA1_Init(SHA_CTX* context) {
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0);
+
+ MEMCPY_BCOPY(context->s1.state, sha1_initial_hash_value, sizeof(sha_word32) * 5);
+ MEMSET_BZERO(context->s1.buffer, 64);
+ context->s1.bitcount = 0;
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-1 round macros: */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND1_0_TO_15(a,b,c,d,e) \
+ REVERSE32(*data++, W1[j]); \
+ (e) = ROTL32(5, (a)) + Ch((b), (c), (d)) + (e) + \
+ K1_0_TO_19 + W1[j]; \
+ (b) = ROTL32(30, (b)); \
+ j++;
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND1_0_TO_15(a,b,c,d,e) \
+ (e) = ROTL32(5, (a)) + Ch((b), (c), (d)) + (e) + \
+ K1_0_TO_19 + ( W1[j] = *data++ ); \
+ (b) = ROTL32(30, (b)); \
+ j++;
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND1_16_TO_19(a,b,c,d,e) \
+ T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \
+ (e) = ROTL32(5, a) + Ch(b,c,d) + e + K1_0_TO_19 + ( W1[j&0x0f] = ROTL32(1, T1) ); \
+ (b) = ROTL32(30, b); \
+ j++;
+
+#define ROUND1_20_TO_39(a,b,c,d,e) \
+ T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \
+ (e) = ROTL32(5, a) + Parity(b,c,d) + e + K1_20_TO_39 + ( W1[j&0x0f] = ROTL32(1, T1) ); \
+ (b) = ROTL32(30, b); \
+ j++;
+
+#define ROUND1_40_TO_59(a,b,c,d,e) \
+ T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \
+ (e) = ROTL32(5, a) + Maj(b,c,d) + e + K1_40_TO_59 + ( W1[j&0x0f] = ROTL32(1, T1) ); \
+ (b) = ROTL32(30, b); \
+ j++;
+
+#define ROUND1_60_TO_79(a,b,c,d,e) \
+ T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \
+ (e) = ROTL32(5, a) + Parity(b,c,d) + e + K1_60_TO_79 + ( W1[j&0x0f] = ROTL32(1, T1) ); \
+ (b) = ROTL32(30, b); \
+ j++;
+
+void SHA1_Internal_Transform(SHA_CTX* context, const sha_word32* data) {
+ sha_word32 a, b, c, d, e;
+ sha_word32 T1, *W1;
+ int j;
+
+ W1 = (sha_word32*)context->s1.buffer;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->s1.state[0];
+ b = context->s1.state[1];
+ c = context->s1.state[2];
+ d = context->s1.state[3];
+ e = context->s1.state[4];
+
+ j = 0;
+
+ /* Rounds 0 to 15 unrolled: */
+ ROUND1_0_TO_15(a,b,c,d,e);
+ ROUND1_0_TO_15(e,a,b,c,d);
+ ROUND1_0_TO_15(d,e,a,b,c);
+ ROUND1_0_TO_15(c,d,e,a,b);
+ ROUND1_0_TO_15(b,c,d,e,a);
+ ROUND1_0_TO_15(a,b,c,d,e);
+ ROUND1_0_TO_15(e,a,b,c,d);
+ ROUND1_0_TO_15(d,e,a,b,c);
+ ROUND1_0_TO_15(c,d,e,a,b);
+ ROUND1_0_TO_15(b,c,d,e,a);
+ ROUND1_0_TO_15(a,b,c,d,e);
+ ROUND1_0_TO_15(e,a,b,c,d);
+ ROUND1_0_TO_15(d,e,a,b,c);
+ ROUND1_0_TO_15(c,d,e,a,b);
+ ROUND1_0_TO_15(b,c,d,e,a);
+ ROUND1_0_TO_15(a,b,c,d,e);
+
+ /* Rounds 16 to 19 unrolled: */
+ ROUND1_16_TO_19(e,a,b,c,d);
+ ROUND1_16_TO_19(d,e,a,b,c);
+ ROUND1_16_TO_19(c,d,e,a,b);
+ ROUND1_16_TO_19(b,c,d,e,a);
+
+ /* Rounds 20 to 39 unrolled: */
+ ROUND1_20_TO_39(a,b,c,d,e);
+ ROUND1_20_TO_39(e,a,b,c,d);
+ ROUND1_20_TO_39(d,e,a,b,c);
+ ROUND1_20_TO_39(c,d,e,a,b);
+ ROUND1_20_TO_39(b,c,d,e,a);
+ ROUND1_20_TO_39(a,b,c,d,e);
+ ROUND1_20_TO_39(e,a,b,c,d);
+ ROUND1_20_TO_39(d,e,a,b,c);
+ ROUND1_20_TO_39(c,d,e,a,b);
+ ROUND1_20_TO_39(b,c,d,e,a);
+ ROUND1_20_TO_39(a,b,c,d,e);
+ ROUND1_20_TO_39(e,a,b,c,d);
+ ROUND1_20_TO_39(d,e,a,b,c);
+ ROUND1_20_TO_39(c,d,e,a,b);
+ ROUND1_20_TO_39(b,c,d,e,a);
+ ROUND1_20_TO_39(a,b,c,d,e);
+ ROUND1_20_TO_39(e,a,b,c,d);
+ ROUND1_20_TO_39(d,e,a,b,c);
+ ROUND1_20_TO_39(c,d,e,a,b);
+ ROUND1_20_TO_39(b,c,d,e,a);
+
+ /* Rounds 40 to 59 unrolled: */
+ ROUND1_40_TO_59(a,b,c,d,e);
+ ROUND1_40_TO_59(e,a,b,c,d);
+ ROUND1_40_TO_59(d,e,a,b,c);
+ ROUND1_40_TO_59(c,d,e,a,b);
+ ROUND1_40_TO_59(b,c,d,e,a);
+ ROUND1_40_TO_59(a,b,c,d,e);
+ ROUND1_40_TO_59(e,a,b,c,d);
+ ROUND1_40_TO_59(d,e,a,b,c);
+ ROUND1_40_TO_59(c,d,e,a,b);
+ ROUND1_40_TO_59(b,c,d,e,a);
+ ROUND1_40_TO_59(a,b,c,d,e);
+ ROUND1_40_TO_59(e,a,b,c,d);
+ ROUND1_40_TO_59(d,e,a,b,c);
+ ROUND1_40_TO_59(c,d,e,a,b);
+ ROUND1_40_TO_59(b,c,d,e,a);
+ ROUND1_40_TO_59(a,b,c,d,e);
+ ROUND1_40_TO_59(e,a,b,c,d);
+ ROUND1_40_TO_59(d,e,a,b,c);
+ ROUND1_40_TO_59(c,d,e,a,b);
+ ROUND1_40_TO_59(b,c,d,e,a);
+
+ /* Rounds 60 to 79 unrolled: */
+ ROUND1_60_TO_79(a,b,c,d,e);
+ ROUND1_60_TO_79(e,a,b,c,d);
+ ROUND1_60_TO_79(d,e,a,b,c);
+ ROUND1_60_TO_79(c,d,e,a,b);
+ ROUND1_60_TO_79(b,c,d,e,a);
+ ROUND1_60_TO_79(a,b,c,d,e);
+ ROUND1_60_TO_79(e,a,b,c,d);
+ ROUND1_60_TO_79(d,e,a,b,c);
+ ROUND1_60_TO_79(c,d,e,a,b);
+ ROUND1_60_TO_79(b,c,d,e,a);
+ ROUND1_60_TO_79(a,b,c,d,e);
+ ROUND1_60_TO_79(e,a,b,c,d);
+ ROUND1_60_TO_79(d,e,a,b,c);
+ ROUND1_60_TO_79(c,d,e,a,b);
+ ROUND1_60_TO_79(b,c,d,e,a);
+ ROUND1_60_TO_79(a,b,c,d,e);
+ ROUND1_60_TO_79(e,a,b,c,d);
+ ROUND1_60_TO_79(d,e,a,b,c);
+ ROUND1_60_TO_79(c,d,e,a,b);
+ ROUND1_60_TO_79(b,c,d,e,a);
+
+ /* Compute the current intermediate hash value */
+ context->s1.state[0] += a;
+ context->s1.state[1] += b;
+ context->s1.state[2] += c;
+ context->s1.state[3] += d;
+ context->s1.state[4] += e;
+
+ /* Clean up */
+ a = b = c = d = e = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+void SHA1_Internal_Transform(SHA_CTX* context, const sha_word32* data) {
+ sha_word32 a, b, c, d, e;
+ sha_word32 T1, *W1;
+ int j;
+
+ W1 = (sha_word32*)context->s1.buffer;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->s1.state[0];
+ b = context->s1.state[1];
+ c = context->s1.state[2];
+ d = context->s1.state[3];
+ e = context->s1.state[4];
+ j = 0;
+ do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ T1 = data[j];
+ /* Copy data while converting to host byte order */
+ REVERSE32(*data++, W1[j]);
+ T1 = ROTL32(5, a) + Ch(b, c, d) + e + K1_0_TO_19 + W1[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+ T1 = ROTL32(5, a) + Ch(b, c, d) + e + K1_0_TO_19 + (W1[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+ e = d;
+ d = c;
+ c = ROTL32(30, b);
+ b = a;
+ a = T1;
+ j++;
+ } while (j < 16);
+
+ do {
+ T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f];
+ T1 = ROTL32(5, a) + Ch(b,c,d) + e + K1_0_TO_19 + (W1[j&0x0f] = ROTL32(1, T1));
+ e = d;
+ d = c;
+ c = ROTL32(30, b);
+ b = a;
+ a = T1;
+ j++;
+ } while (j < 20);
+
+ do {
+ T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f];
+ T1 = ROTL32(5, a) + Parity(b,c,d) + e + K1_20_TO_39 + (W1[j&0x0f] = ROTL32(1, T1));
+ e = d;
+ d = c;
+ c = ROTL32(30, b);
+ b = a;
+ a = T1;
+ j++;
+ } while (j < 40);
+
+ do {
+ T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f];
+ T1 = ROTL32(5, a) + Maj(b,c,d) + e + K1_40_TO_59 + (W1[j&0x0f] = ROTL32(1, T1));
+ e = d;
+ d = c;
+ c = ROTL32(30, b);
+ b = a;
+ a = T1;
+ j++;
+ } while (j < 60);
+
+ do {
+ T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f];
+ T1 = ROTL32(5, a) + Parity(b,c,d) + e + K1_60_TO_79 + (W1[j&0x0f] = ROTL32(1, T1));
+ e = d;
+ d = c;
+ c = ROTL32(30, b);
+ b = a;
+ a = T1;
+ j++;
+ } while (j < 80);
+
+
+ /* Compute the current intermediate hash value */
+ context->s1.state[0] += a;
+ context->s1.state[1] += b;
+ context->s1.state[2] += c;
+ context->s1.state[3] += d;
+ context->s1.state[4] += e;
+
+ /* Clean up */
+ a = b = c = d = e = T1 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void SHA1_Update(SHA_CTX* context, const sha_byte *data, size_t len) {
+ unsigned int freespace, usedspace;
+ if (len == 0) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0 && data != (sha_byte*)0);
+
+ usedspace = (unsigned int)((context->s1.bitcount >> 3) % 64);
+ if (usedspace > 0) {
+ /* Calculate how much free space is available in the buffer */
+ freespace = 64 - usedspace;
+
+ if (len >= freespace) {
+ /* Fill the buffer completely and process it */
+ MEMCPY_BCOPY(&context->s1.buffer[usedspace], data, freespace);
+ context->s1.bitcount += freespace << 3;
+ len -= freespace;
+ data += freespace;
+ SHA1_Internal_Transform(context, (const sha_word32*)context->s1.buffer);
+ } else {
+ /* The buffer is not yet full */
+ MEMCPY_BCOPY(&context->s1.buffer[usedspace], data, len);
+ context->s1.bitcount += len << 3;
+ /* Clean up: */
+ usedspace = freespace = 0;
+ return;
+ }
+ }
+ while (len >= 64) {
+ /* Process as many complete blocks as we can */
+ SHA1_Internal_Transform(context, (const sha_word32*)data);
+ context->s1.bitcount += 512;
+ len -= 64;
+ data += 64;
+ }
+ if (len > 0) {
+ /* There's left-overs, so save 'em */
+ MEMCPY_BCOPY(context->s1.buffer, data, len);
+ context->s1.bitcount += len << 3;
+ }
+ /* Clean up: */
+ usedspace = freespace = 0;
+}
+
+void SHA1_Final(sha_byte digest[], SHA_CTX* context) {
+ sha_word32 *d = (sha_word32*)digest;
+ unsigned int usedspace;
+
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0);
+
+ if (digest == (sha_byte*)0) {
+ /*
+ * No digest buffer, so we can do nothing
+ * except clean up and go home
+ */
+ MEMSET_BZERO(context, sizeof(*context));
+ return;
+ }
+
+ usedspace = (unsigned int)((context->s1.bitcount >> 3) % 64);
+ if (usedspace == 0) {
+ /* Set-up for the last transform: */
+ MEMSET_BZERO(context->s1.buffer, 56);
+
+ /* Begin padding with a 1 bit: */
+ *context->s1.buffer = 0x80;
+ } else {
+ /* Begin padding with a 1 bit: */
+ context->s1.buffer[usedspace++] = 0x80;
+
+ if (usedspace <= 56) {
+ /* Set-up for the last transform: */
+ MEMSET_BZERO(&context->s1.buffer[usedspace], 56 - usedspace);
+ } else {
+ if (usedspace < 64) {
+ MEMSET_BZERO(&context->s1.buffer[usedspace], 64 - usedspace);
+ }
+ /* Do second-to-last transform: */
+ SHA1_Internal_Transform(context, (const sha_word32*)context->s1.buffer);
+
+ /* And set-up for the last transform: */
+ MEMSET_BZERO(context->s1.buffer, 56);
+ }
+ /* Clean up: */
+ usedspace = 0;
+ }
+ /* Set the bit count: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert FROM host byte order */
+ REVERSE64(context->s1.bitcount,context->s1.bitcount);
+#endif
+ MEMCPY_BCOPY(&context->s1.buffer[56], &context->s1.bitcount,
+ sizeof(sha_word64));
+
+ /* Final transform: */
+ SHA1_Internal_Transform(context, (const sha_word32*)context->s1.buffer);
+
+ /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < (SHA1_DIGEST_LENGTH >> 2); j++) {
+ REVERSE32(context->s1.state[j],context->s1.state[j]);
+ *d++ = context->s1.state[j];
+ }
+ }
+#else
+ MEMCPY_BCOPY(d, context->s1.state, SHA1_DIGEST_LENGTH);
+#endif
+
+ /* Clean up: */
+ MEMSET_BZERO(context, sizeof(*context));
+}
+
+char *SHA1_End(SHA_CTX* context, char buffer[]) {
+ sha_byte digest[SHA1_DIGEST_LENGTH], *d = digest;
+ int i;
+
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0);
+
+ if (buffer != (char*)0) {
+ SHA1_Final(digest, context);
+
+ for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
+ *buffer++ = sha_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+ MEMSET_BZERO(context, sizeof(*context));
+ }
+ MEMSET_BZERO(digest, SHA1_DIGEST_LENGTH);
+ return buffer;
+}
+
+char* SHA1_Data(const sha_byte* data, size_t len, char digest[SHA1_DIGEST_STRING_LENGTH]) {
+ SHA_CTX context;
+
+ SHA1_Init(&context);
+ SHA1_Update(&context, data, len);
+ return SHA1_End(&context, digest);
+}
+
+
+/*** SHA-256: *********************************************************/
+void SHA256_Internal_Init(SHA_CTX* context, const sha_word32* ihv) {
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0);
+
+ MEMCPY_BCOPY(context->s256.state, ihv, sizeof(sha_word32) * 8);
+ MEMSET_BZERO(context->s256.buffer, 64);
+ context->s256.bitcount = 0;
+}
+
+void SHA256_Init(SHA_CTX* context) {
+ SHA256_Internal_Init(context, sha256_initial_hash_value);
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-256 round macros: */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
+ REVERSE32(*data++, W256[j]); \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+ K256[j] + W256[j]; \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+ K256[j] + (W256[j] = *data++); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256(a,b,c,d,e,f,g,h) \
+ s0 = W256[(j+1)&0x0f]; \
+ s0 = sigma0_256(s0); \
+ s1 = W256[(j+14)&0x0f]; \
+ s1 = sigma1_256(s1); \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+void SHA256_Internal_Transform(SHA_CTX* context, const sha_word32* data) {
+ sha_word32 a, b, c, d, e, f, g, h, s0, s1;
+ sha_word32 T1, *W256;
+ int j;
+
+ W256 = (sha_word32*)context->s256.buffer;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->s256.state[0];
+ b = context->s256.state[1];
+ c = context->s256.state[2];
+ d = context->s256.state[3];
+ e = context->s256.state[4];
+ f = context->s256.state[5];
+ g = context->s256.state[6];
+ h = context->s256.state[7];
+
+ j = 0;
+ do {
+ /* Rounds 0 to 15 (unrolled): */
+ ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
+ ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
+ ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
+ ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
+ ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
+ ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
+ ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
+ ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
+ } while (j < 16);
+
+ /* Now for the remaining rounds to 64: */
+ do {
+ ROUND256(a,b,c,d,e,f,g,h);
+ ROUND256(h,a,b,c,d,e,f,g);
+ ROUND256(g,h,a,b,c,d,e,f);
+ ROUND256(f,g,h,a,b,c,d,e);
+ ROUND256(e,f,g,h,a,b,c,d);
+ ROUND256(d,e,f,g,h,a,b,c);
+ ROUND256(c,d,e,f,g,h,a,b);
+ ROUND256(b,c,d,e,f,g,h,a);
+ } while (j < 64);
+
+ /* Compute the current intermediate hash value */
+ context->s256.state[0] += a;
+ context->s256.state[1] += b;
+ context->s256.state[2] += c;
+ context->s256.state[3] += d;
+ context->s256.state[4] += e;
+ context->s256.state[5] += f;
+ context->s256.state[6] += g;
+ context->s256.state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+void SHA256_Internal_Transform(SHA_CTX* context, const sha_word32* data) {
+ sha_word32 a, b, c, d, e, f, g, h, s0, s1;
+ sha_word32 T1, T2, *W256;
+ int j;
+
+ W256 = (sha_word32*)context->s256.buffer;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->s256.state[0];
+ b = context->s256.state[1];
+ c = context->s256.state[2];
+ d = context->s256.state[3];
+ e = context->s256.state[4];
+ f = context->s256.state[5];
+ g = context->s256.state[6];
+ h = context->s256.state[7];
+
+ j = 0;
+ do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Copy data while converting to host byte order */
+ REVERSE32(*data++,W256[j]);
+ /* Apply the SHA-256 compression function to update a..h */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+ /* Apply the SHA-256 compression function to update a..h with copy */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+ T2 = Sigma0_256(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 16);
+
+ do {
+ /* Part of the message block expansion: */
+ s0 = W256[(j+1)&0x0f];
+ s0 = sigma0_256(s0);
+ s1 = W256[(j+14)&0x0f];
+ s1 = sigma1_256(s1);
+
+ /* Apply the SHA-256 compression function to update a..h */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
+ T2 = Sigma0_256(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 64);
+
+ /* Compute the current intermediate hash value */
+ context->s256.state[0] += a;
+ context->s256.state[1] += b;
+ context->s256.state[2] += c;
+ context->s256.state[3] += d;
+ context->s256.state[4] += e;
+ context->s256.state[5] += f;
+ context->s256.state[6] += g;
+ context->s256.state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void SHA256_Update(SHA_CTX* context, const sha_byte *data, size_t len) {
+ unsigned int freespace, usedspace;
+
+ if (len == 0) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0 && data != (sha_byte*)0);
+
+ usedspace = (unsigned int)((context->s256.bitcount >> 3) % 64);
+ if (usedspace > 0) {
+ /* Calculate how much free space is available in the buffer */
+ freespace = 64 - usedspace;
+
+ if (len >= freespace) {
+ /* Fill the buffer completely and process it */
+ MEMCPY_BCOPY(&context->s256.buffer[usedspace], data, freespace);
+ context->s256.bitcount += freespace << 3;
+ len -= freespace;
+ data += freespace;
+ SHA256_Internal_Transform(context, (const sha_word32*)context->s256.buffer);
+ } else {
+ /* The buffer is not yet full */
+ MEMCPY_BCOPY(&context->s256.buffer[usedspace], data, len);
+ context->s256.bitcount += len << 3;
+ /* Clean up: */
+ usedspace = freespace = 0;
+ return;
+ }
+ }
+ while (len >= 64) {
+ /* Process as many complete blocks as we can */
+ SHA256_Internal_Transform(context, (const sha_word32*)data);
+ context->s256.bitcount += 512;
+ len -= 64;
+ data += 64;
+ }
+ if (len > 0) {
+ /* There's left-overs, so save 'em */
+ MEMCPY_BCOPY(context->s256.buffer, data, len);
+ context->s256.bitcount += len << 3;
+ }
+ /* Clean up: */
+ usedspace = freespace = 0;
+}
+
+void SHA256_Internal_Last(SHA_CTX* context) {
+ unsigned int usedspace;
+
+ usedspace = (unsigned int)((context->s256.bitcount >> 3) % 64);
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert FROM host byte order */
+ REVERSE64(context->s256.bitcount,context->s256.bitcount);
+#endif
+ if (usedspace > 0) {
+ /* Begin padding with a 1 bit: */
+ context->s256.buffer[usedspace++] = 0x80;
+
+ if (usedspace <= 56) {
+ /* Set-up for the last transform: */
+ MEMSET_BZERO(&context->s256.buffer[usedspace], 56 - usedspace);
+ } else {
+ if (usedspace < 64) {
+ MEMSET_BZERO(&context->s256.buffer[usedspace], 64 - usedspace);
+ }
+ /* Do second-to-last transform: */
+ SHA256_Internal_Transform(context, (const sha_word32*)context->s256.buffer);
+
+ /* And set-up for the last transform: */
+ MEMSET_BZERO(context->s256.buffer, 56);
+ }
+ /* Clean up: */
+ usedspace = 0;
+ } else {
+ /* Set-up for the last transform: */
+ MEMSET_BZERO(context->s256.buffer, 56);
+
+ /* Begin padding with a 1 bit: */
+ *context->s256.buffer = 0x80;
+ }
+ /* Set the bit count: */
+ MEMCPY_BCOPY(&context->s256.buffer[56], &context->s256.bitcount,
+ sizeof(sha_word64));
+
+ /* Final transform: */
+ SHA256_Internal_Transform(context, (const sha_word32*)context->s256.buffer);
+}
+
+void SHA256_Final(sha_byte digest[], SHA_CTX* context) {
+ sha_word32 *d = (sha_word32*)digest;
+
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (sha_byte*)0) {
+ SHA256_Internal_Last(context);
+
+ /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < (SHA256_DIGEST_LENGTH >> 2); j++) {
+ REVERSE32(context->s256.state[j],context->s256.state[j]);
+ *d++ = context->s256.state[j];
+ }
+ }
+#else
+ MEMCPY_BCOPY(d, context->s256.state, SHA256_DIGEST_LENGTH);
+#endif
+ }
+
+ /* Clean up state data: */
+ MEMSET_BZERO(context, sizeof(*context));
+}
+
+char *SHA256_End(SHA_CTX* context, char buffer[]) {
+ sha_byte digest[SHA256_DIGEST_LENGTH], *d = digest;
+ int i;
+
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0);
+
+ if (buffer != (char*)0) {
+ SHA256_Final(digest, context);
+
+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
+ *buffer++ = sha_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+ MEMSET_BZERO(context, sizeof(*context));
+ }
+ MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH);
+ return buffer;
+}
+
+char* SHA256_Data(const sha_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) {
+ SHA_CTX context;
+
+ SHA256_Init(&context);
+ SHA256_Update(&context, data, len);
+ return SHA256_End(&context, digest);
+}
+
+
+/*** SHA-224: *********************************************************/
+void SHA224_Init(SHA_CTX* context) {
+ SHA256_Internal_Init(context, sha224_initial_hash_value);
+}
+
+void SHA224_Internal_Transform(SHA_CTX* context, const sha_word32* data) {
+ SHA256_Internal_Transform(context, data);
+}
+
+void SHA224_Update(SHA_CTX* context, const sha_byte *data, size_t len) {
+ SHA256_Update(context, data, len);
+}
+
+void SHA224_Final(sha_byte digest[], SHA_CTX* context) {
+ sha_word32 *d = (sha_word32*)digest;
+
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (sha_byte*)0) {
+ SHA256_Internal_Last(context);
+
+ /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < (SHA224_DIGEST_LENGTH >> 2); j++) {
+ REVERSE32(context->s256.state[j],context->s256.state[j]);
+ *d++ = context->s256.state[j];
+ }
+ }
+#else
+ MEMCPY_BCOPY(d, context->s256.state, SHA224_DIGEST_LENGTH);
+#endif
+ }
+
+ /* Clean up state data: */
+ MEMSET_BZERO(context, sizeof(*context));
+}
+
+char *SHA224_End(SHA_CTX* context, char buffer[]) {
+ sha_byte digest[SHA224_DIGEST_LENGTH], *d = digest;
+ int i;
+
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0);
+
+ if (buffer != (char*)0) {
+ SHA224_Final(digest, context);
+
+ for (i = 0; i < SHA224_DIGEST_LENGTH; i++) {
+ *buffer++ = sha_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+ MEMSET_BZERO(context, sizeof(*context));
+ }
+ MEMSET_BZERO(digest, SHA224_DIGEST_LENGTH);
+ return buffer;
+}
+
+char* SHA224_Data(const sha_byte* data, size_t len, char digest[SHA224_DIGEST_STRING_LENGTH]) {
+ SHA_CTX context;
+
+ SHA224_Init(&context);
+ SHA224_Update(&context, data, len);
+ return SHA224_End(&context, digest);
+}
+
+
+/*** SHA-512: *********************************************************/
+void SHA512_Internal_Init(SHA_CTX* context, const sha_word64* ihv) {
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0);
+
+ MEMCPY_BCOPY(context->s512.state, ihv, sizeof(sha_word64) * 8);
+ MEMSET_BZERO(context->s512.buffer, 128);
+ context->s512.bitcount[0] = context->s512.bitcount[1] = 0;
+}
+
+void SHA512_Init(SHA_CTX* context) {
+ SHA512_Internal_Init(context, sha512_initial_hash_value);
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-512 round macros: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
+ REVERSE64(*data++, W512[j]); \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+ K512[j] + W512[j]; \
+ (d) += T1, \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \
+ j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+ K512[j] + (W512[j] = *data++); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+ j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512(a,b,c,d,e,f,g,h) \
+ s0 = W512[(j+1)&0x0f]; \
+ s0 = sigma0_512(s0); \
+ s1 = W512[(j+14)&0x0f]; \
+ s1 = sigma1_512(s1); \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \
+ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+ j++
+
+void SHA512_Internal_Transform(SHA_CTX* context, const sha_word64* data) {
+ sha_word64 a, b, c, d, e, f, g, h, s0, s1;
+ sha_word64 T1, *W512 = (sha_word64*)context->s512.buffer;
+ int j;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->s512.state[0];
+ b = context->s512.state[1];
+ c = context->s512.state[2];
+ d = context->s512.state[3];
+ e = context->s512.state[4];
+ f = context->s512.state[5];
+ g = context->s512.state[6];
+ h = context->s512.state[7];
+
+ j = 0;
+ do {
+ ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
+ ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
+ ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
+ ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
+ ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
+ ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
+ ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
+ ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
+ } while (j < 16);
+
+ /* Now for the remaining rounds up to 79: */
+ do {
+ ROUND512(a,b,c,d,e,f,g,h);
+ ROUND512(h,a,b,c,d,e,f,g);
+ ROUND512(g,h,a,b,c,d,e,f);
+ ROUND512(f,g,h,a,b,c,d,e);
+ ROUND512(e,f,g,h,a,b,c,d);
+ ROUND512(d,e,f,g,h,a,b,c);
+ ROUND512(c,d,e,f,g,h,a,b);
+ ROUND512(b,c,d,e,f,g,h,a);
+ } while (j < 80);
+
+ /* Compute the current intermediate hash value */
+ context->s512.state[0] += a;
+ context->s512.state[1] += b;
+ context->s512.state[2] += c;
+ context->s512.state[3] += d;
+ context->s512.state[4] += e;
+ context->s512.state[5] += f;
+ context->s512.state[6] += g;
+ context->s512.state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+void SHA512_Internal_Transform(SHA_CTX* context, const sha_word64* data) {
+ sha_word64 a, b, c, d, e, f, g, h, s0, s1;
+ sha_word64 T1, T2, *W512 = (sha_word64*)context->s512.buffer;
+ int j;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->s512.state[0];
+ b = context->s512.state[1];
+ c = context->s512.state[2];
+ d = context->s512.state[3];
+ e = context->s512.state[4];
+ f = context->s512.state[5];
+ g = context->s512.state[6];
+ h = context->s512.state[7];
+
+ j = 0;
+ do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert TO host byte order */
+ REVERSE64(*data++, W512[j]);
+ /* Apply the SHA-512 compression function to update a..h */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+ /* Apply the SHA-512 compression function to update a..h with copy */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+ T2 = Sigma0_512(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 16);
+
+ do {
+ /* Part of the message block expansion: */
+ s0 = W512[(j+1)&0x0f];
+ s0 = sigma0_512(s0);
+ s1 = W512[(j+14)&0x0f];
+ s1 = sigma1_512(s1);
+
+ /* Apply the SHA-512 compression function to update a..h */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
+ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
+ T2 = Sigma0_512(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 80);
+
+ /* Compute the current intermediate hash value */
+ context->s512.state[0] += a;
+ context->s512.state[1] += b;
+ context->s512.state[2] += c;
+ context->s512.state[3] += d;
+ context->s512.state[4] += e;
+ context->s512.state[5] += f;
+ context->s512.state[6] += g;
+ context->s512.state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void SHA512_Update(SHA_CTX* context, const sha_byte *data, size_t len) {
+ unsigned int freespace, usedspace;
+
+ if (len == 0) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0 && data != (sha_byte*)0);
+
+ usedspace = (unsigned int)((context->s512.bitcount[0] >> 3) % 128);
+ if (usedspace > 0) {
+ /* Calculate how much free space is available in the buffer */
+ freespace = 128 - usedspace;
+
+ if (len >= freespace) {
+ /* Fill the buffer completely and process it */
+ MEMCPY_BCOPY(&context->s512.buffer[usedspace], data, freespace);
+ ADDINC128(context->s512.bitcount, freespace << 3);
+ len -= freespace;
+ data += freespace;
+ SHA512_Internal_Transform(context, (const sha_word64*)context->s512.buffer);
+ } else {
+ /* The buffer is not yet full */
+ MEMCPY_BCOPY(&context->s512.buffer[usedspace], data, len);
+ ADDINC128(context->s512.bitcount, len << 3);
+ /* Clean up: */
+ usedspace = freespace = 0;
+ return;
+ }
+ }
+ while (len >= 128) {
+ /* Process as many complete blocks as we can */
+ SHA512_Internal_Transform(context, (const sha_word64*)data);
+ ADDINC128(context->s512.bitcount, 1024);
+ len -= 128;
+ data += 128;
+ }
+ if (len > 0) {
+ /* There's left-overs, so save 'em */
+ MEMCPY_BCOPY(context->s512.buffer, data, len);
+ ADDINC128(context->s512.bitcount, len << 3);
+ }
+ /* Clean up: */
+ usedspace = freespace = 0;
+}
+
+void SHA512_Internal_Last(SHA_CTX* context) {
+ unsigned int usedspace;
+
+ usedspace = (unsigned int)((context->s512.bitcount[0] >> 3) % 128);
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert FROM host byte order */
+ REVERSE64(context->s512.bitcount[0],context->s512.bitcount[0]);
+ REVERSE64(context->s512.bitcount[1],context->s512.bitcount[1]);
+#endif
+ if (usedspace > 0) {
+ /* Begin padding with a 1 bit: */
+ context->s512.buffer[usedspace++] = 0x80;
+
+ if (usedspace <= 112) {
+ /* Set-up for the last transform: */
+ MEMSET_BZERO(&context->s512.buffer[usedspace], 112 - usedspace);
+ } else {
+ if (usedspace < 128) {
+ MEMSET_BZERO(&context->s512.buffer[usedspace], 128 - usedspace);
+ }
+ /* Do second-to-last transform: */
+ SHA512_Internal_Transform(context, (const sha_word64*)context->s512.buffer);
+
+ /* And set-up for the last transform: */
+ MEMSET_BZERO(context->s512.buffer, 112);
+ }
+ /* Clean up: */
+ usedspace = 0;
+ } else {
+ /* Prepare for final transform: */
+ MEMSET_BZERO(context->s512.buffer, 112);
+
+ /* Begin padding with a 1 bit: */
+ *context->s512.buffer = 0x80;
+ }
+ /* Store the length of input data (in bits): */
+ MEMCPY_BCOPY(&context->s512.buffer[112], &context->s512.bitcount[1],
+ sizeof(sha_word64));
+ MEMCPY_BCOPY(&context->s512.buffer[120], &context->s512.bitcount[0],
+ sizeof(sha_word64));
+
+ /* Final transform: */
+ SHA512_Internal_Transform(context, (const sha_word64*)context->s512.buffer);
+}
+
+void SHA512_Final(sha_byte digest[], SHA_CTX* context) {
+ sha_word64 *d = (sha_word64*)digest;
+
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (sha_byte*)0) {
+ SHA512_Internal_Last(context);
+
+ /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < (SHA512_DIGEST_LENGTH >> 3); j++) {
+ REVERSE64(context->s512.state[j],context->s512.state[j]);
+ *d++ = context->s512.state[j];
+ }
+ }
+#else
+ MEMCPY_BCOPY(d, context->s512.state, SHA512_DIGEST_LENGTH);
+#endif
+ }
+
+ /* Zero out state data */
+ MEMSET_BZERO(context, sizeof(*context));
+}
+
+char *SHA512_End(SHA_CTX* context, char buffer[]) {
+ sha_byte digest[SHA512_DIGEST_LENGTH], *d = digest;
+ int i;
+
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0);
+
+ if (buffer != (char*)0) {
+ SHA512_Final(digest, context);
+
+ for (i = 0; i < SHA512_DIGEST_LENGTH; i++) {
+ *buffer++ = sha_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+ MEMSET_BZERO(context, sizeof(*context));
+ }
+ MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH);
+ return buffer;
+}
+
+char* SHA512_Data(const sha_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) {
+ SHA_CTX context;
+
+ SHA512_Init(&context);
+ SHA512_Update(&context, data, len);
+ return SHA512_End(&context, digest);
+}
+
+
+/*** SHA-384: *********************************************************/
+void SHA384_Init(SHA_CTX* context) {
+ SHA512_Internal_Init(context, sha384_initial_hash_value);
+}
+
+void SHA384_Update(SHA_CTX* context, const sha_byte* data, size_t len) {
+ SHA512_Update(context, data, len);
+}
+
+void SHA384_Final(sha_byte digest[], SHA_CTX* context) {
+ sha_word64 *d = (sha_word64*)digest;
+
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (sha_byte*)0) {
+ SHA512_Internal_Last(context);
+
+ /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < (SHA384_DIGEST_LENGTH >> 3); j++) {
+ REVERSE64(context->s512.state[j],context->s512.state[j]);
+ *d++ = context->s512.state[j];
+ }
+ }
+#else
+ MEMCPY_BCOPY(d, context->s512.state, SHA384_DIGEST_LENGTH);
+#endif
+ }
+
+ /* Zero out state data */
+ MEMSET_BZERO(context, sizeof(*context));
+}
+
+char *SHA384_End(SHA_CTX* context, char buffer[]) {
+ sha_byte digest[SHA384_DIGEST_LENGTH], *d = digest;
+ int i;
+
+ /* Sanity check: */
+ assert(context != (SHA_CTX*)0);
+
+ if (buffer != (char*)0) {
+ SHA384_Final(digest, context);
+
+ for (i = 0; i < SHA384_DIGEST_LENGTH; i++) {
+ *buffer++ = sha_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+ MEMSET_BZERO(context, sizeof(*context));
+ }
+ MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH);
+ return buffer;
+}
+
+char* SHA384_Data(const sha_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) {
+ SHA_CTX context;
+
+ SHA384_Init(&context);
+ SHA384_Update(&context, data, len);
+ return SHA384_End(&context, digest);
+}
diff --git a/Source/cm_sha2.h b/Source/cm_sha2.h
new file mode 100644
index 0000000..f151031
--- /dev/null
+++ b/Source/cm_sha2.h
@@ -0,0 +1,140 @@
+/*
+ * FILE: sha2.h
+ * AUTHOR: Aaron D. Gifford
+ * http://www.aarongifford.com/computers/sha.html
+ *
+ * Copyright (c) 2000-2003, Aaron D. Gifford
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sha2.h,v 1.4 2004/01/07 19:06:18 adg Exp $
+ */
+
+#ifndef __SHA2_H__
+#define __SHA2_H__
+
+#include "cm_sha2_mangle.h"
+
+/* CMake modification: use integer types from KWIML. */
+#include <cm_kwiml.h>
+typedef KWIML_INT_uint8_t cm_sha2_uint8_t;
+typedef KWIML_INT_uint32_t cm_sha2_uint32_t;
+typedef KWIML_INT_uint64_t cm_sha2_uint64_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Import u_intXX_t size_t type definitions from system headers. You
+ * may need to change this, or define these things yourself in this
+ * file.
+ */
+#include <sys/types.h>
+
+/*** SHA-224/256/384/512 Various Length Definitions *******************/
+
+/* Digest lengths for SHA-1/224/256/384/512 */
+#define SHA1_DIGEST_LENGTH 20
+#define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1)
+#define SHA224_DIGEST_LENGTH 28
+#define SHA224_DIGEST_STRING_LENGTH (SHA224_DIGEST_LENGTH * 2 + 1)
+#define SHA256_DIGEST_LENGTH 32
+#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1)
+#define SHA384_DIGEST_LENGTH 48
+#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1)
+#define SHA512_DIGEST_LENGTH 64
+#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1)
+
+
+/*** SHA-224/256/384/512 Context Structures ***************************/
+
+typedef union _SHA_CTX {
+ /* SHA-1 uses this part of the union: */
+ struct {
+ cm_sha2_uint32_t state[5];
+ cm_sha2_uint64_t bitcount;
+ cm_sha2_uint8_t buffer[64];
+ } s1;
+
+ /* SHA-224 and SHA-256 use this part of the union: */
+ struct {
+ cm_sha2_uint32_t state[8];
+ cm_sha2_uint64_t bitcount;
+ cm_sha2_uint8_t buffer[64];
+ } s256;
+
+ /* SHA-384 and SHA-512 use this part of the union: */
+ struct {
+ cm_sha2_uint64_t state[8];
+ cm_sha2_uint64_t bitcount[2];
+ cm_sha2_uint8_t buffer[128];
+ } s512;
+} SHA_CTX;
+
+/*** SHA-256/384/512 Function Prototypes ******************************/
+
+void SHA1_Init(SHA_CTX*);
+void SHA1_Update(SHA_CTX*, const cm_sha2_uint8_t*, size_t);
+void SHA1_Final(cm_sha2_uint8_t[SHA1_DIGEST_LENGTH], SHA_CTX*);
+char* SHA1_End(SHA_CTX*, char[SHA1_DIGEST_STRING_LENGTH]);
+char* SHA1_Data(const cm_sha2_uint8_t*, size_t,
+ char[SHA1_DIGEST_STRING_LENGTH]);
+
+void SHA224_Init(SHA_CTX*);
+void SHA224_Update(SHA_CTX*, const cm_sha2_uint8_t*, size_t);
+void SHA224_Final(cm_sha2_uint8_t[SHA224_DIGEST_LENGTH], SHA_CTX*);
+char* SHA224_End(SHA_CTX*, char[SHA224_DIGEST_STRING_LENGTH]);
+char* SHA224_Data(const cm_sha2_uint8_t*, size_t,
+ char[SHA224_DIGEST_STRING_LENGTH]);
+
+void SHA256_Init(SHA_CTX*);
+void SHA256_Update(SHA_CTX*, const cm_sha2_uint8_t*, size_t);
+void SHA256_Final(cm_sha2_uint8_t[SHA256_DIGEST_LENGTH], SHA_CTX*);
+char* SHA256_End(SHA_CTX*, char[SHA256_DIGEST_STRING_LENGTH]);
+char* SHA256_Data(const cm_sha2_uint8_t*, size_t,
+ char[SHA256_DIGEST_STRING_LENGTH]);
+
+void SHA384_Init(SHA_CTX*);
+void SHA384_Update(SHA_CTX*, const cm_sha2_uint8_t*, size_t);
+void SHA384_Final(cm_sha2_uint8_t[SHA384_DIGEST_LENGTH], SHA_CTX*);
+char* SHA384_End(SHA_CTX*, char[SHA384_DIGEST_STRING_LENGTH]);
+char* SHA384_Data(const cm_sha2_uint8_t*, size_t,
+ char[SHA384_DIGEST_STRING_LENGTH]);
+
+void SHA512_Init(SHA_CTX*);
+void SHA512_Update(SHA_CTX*, const cm_sha2_uint8_t*, size_t);
+void SHA512_Final(cm_sha2_uint8_t[SHA512_DIGEST_LENGTH], SHA_CTX*);
+char* SHA512_End(SHA_CTX*, char[SHA512_DIGEST_STRING_LENGTH]);
+char* SHA512_Data(const cm_sha2_uint8_t*, size_t,
+ char[SHA512_DIGEST_STRING_LENGTH]);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __SHA2_H__ */
diff --git a/Source/cm_sha2_mangle.h b/Source/cm_sha2_mangle.h
new file mode 100644
index 0000000..e73d131
--- /dev/null
+++ b/Source/cm_sha2_mangle.h
@@ -0,0 +1,51 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2011 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cm_sha2_mangle_h
+#define cm_sha2_mangle_h
+
+/* Mangle sha2 symbol names to avoid possible conflict with
+ implementations in other libraries to which CMake links. */
+#define SHA1_Data cmSHA1_Data
+#define SHA1_End cmSHA1_End
+#define SHA1_Final cmSHA1_Final
+#define SHA1_Init cmSHA1_Init
+#define SHA1_Internal_Transform cmSHA1_Internal_Transform
+#define SHA1_Update cmSHA1_Update
+#define SHA224_Data cmSHA224_Data
+#define SHA224_End cmSHA224_End
+#define SHA224_Final cmSHA224_Final
+#define SHA224_Init cmSHA224_Init
+#define SHA224_Internal_Transform cmSHA224_Internal_Transform
+#define SHA224_Update cmSHA224_Update
+#define SHA256_Data cmSHA256_Data
+#define SHA256_End cmSHA256_End
+#define SHA256_Final cmSHA256_Final
+#define SHA256_Init cmSHA256_Init
+#define SHA256_Internal_Init cmSHA256_Internal_Init
+#define SHA256_Internal_Last cmSHA256_Internal_Last
+#define SHA256_Internal_Transform cmSHA256_Internal_Transform
+#define SHA256_Update cmSHA256_Update
+#define SHA384_Data cmSHA384_Data
+#define SHA384_End cmSHA384_End
+#define SHA384_Final cmSHA384_Final
+#define SHA384_Init cmSHA384_Init
+#define SHA384_Update cmSHA384_Update
+#define SHA512_Data cmSHA512_Data
+#define SHA512_End cmSHA512_End
+#define SHA512_Final cmSHA512_Final
+#define SHA512_Init cmSHA512_Init
+#define SHA512_Internal_Init cmSHA512_Internal_Init
+#define SHA512_Internal_Last cmSHA512_Internal_Last
+#define SHA512_Internal_Transform cmSHA512_Internal_Transform
+#define SHA512_Update cmSHA512_Update
+
+#endif
diff --git a/Source/cm_utf8.c b/Source/cm_utf8.c
new file mode 100644
index 0000000..2352507
--- /dev/null
+++ b/Source/cm_utf8.c
@@ -0,0 +1,86 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cm_utf8.h"
+
+/*
+ RFC 3629
+ 07-bit: 0xxxxxxx
+ 11-bit: 110xxxxx 10xxxxxx
+ 16-bit: 1110xxxx 10xxxxxx 10xxxxxx
+ 21-bit: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+ Pre-RFC Compatibility
+ 26-bit: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ 31-bit: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+*/
+
+/* Number of leading ones before a zero in the byte. */
+static unsigned char const cm_utf8_ones[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8
+};
+
+/* Mask away control bits from bytes with n leading ones. */
+static unsigned char const cm_utf8_mask[7] = { 0xEF, 0x3F, 0x1F, 0x0F,
+ 0x07, 0x03, 0x01 };
+
+/* Minimum allowed value when first byte has n leading ones. */
+static unsigned int const cm_utf8_min[7] = {
+ 0, 0, 1u << 7, 1u << 11, 1u << 16, 1u << 21, 1u << 26 /*, 1u<<31 */
+};
+
+const char* cm_utf8_decode_character(const char* first, const char* last,
+ unsigned int* pc)
+{
+ /* Count leading ones in the first byte. */
+ unsigned char c = (unsigned char)*first++;
+ unsigned char const ones = cm_utf8_ones[c];
+ switch (ones) {
+ case 0:
+ *pc = c;
+ return first; /* One-byte character. */
+ case 1:
+ case 7:
+ case 8:
+ return 0; /* Invalid leading byte. */
+ default:
+ break;
+ }
+
+ /* Extract bits from this multi-byte character. */
+ {
+ unsigned int uc = c & cm_utf8_mask[ones];
+ int left;
+ for (left = ones - 1; left && first != last; --left) {
+ c = (unsigned char)*first++;
+ if (cm_utf8_ones[c] != 1) {
+ return 0;
+ }
+ uc = (uc << 6) | (c & cm_utf8_mask[1]);
+ }
+
+ if (left > 0 || uc < cm_utf8_min[ones]) {
+ return 0;
+ }
+
+ *pc = uc;
+ return first;
+ }
+}
diff --git a/Source/cm_utf8.h b/Source/cm_utf8.h
new file mode 100644
index 0000000..06e2868
--- /dev/null
+++ b/Source/cm_utf8.h
@@ -0,0 +1,29 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cm_utf8_h
+#define cm_utf8_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Decode one UTF-8 character from the input byte range. On success,
+ stores the unicode character number in *pc and returns the first
+ position not extracted. On failure, returns 0. */
+const char* cm_utf8_decode_character(const char* first, const char* last,
+ unsigned int* pc);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
new file mode 100644
index 0000000..c597605
--- /dev/null
+++ b/Source/cmake.cxx
@@ -0,0 +1,2560 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmake.h"
+
+#include "cmAlgorithms.h"
+#include "cmCommand.h"
+#include "cmCommands.h"
+#include "cmDocumentationFormatter.h"
+#include "cmExternalMakefileProjectGenerator.h"
+#include "cmFileTimeComparison.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmTest.h"
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmGraphVizWriter.h"
+#include "cmVariableWatch.h"
+#include <cmsys/SystemInformation.hxx>
+#endif
+
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/RegularExpression.hxx>
+
+// only build kdevelop generator on non-windows platforms
+// when not bootstrapping cmake
+#if !defined(_WIN32)
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#define CMAKE_USE_KDEVELOP
+#endif
+#endif
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#define CMAKE_USE_ECLIPSE
+#endif
+
+#if defined(__MINGW32__) && !defined(CMAKE_BUILD_WITH_CMAKE)
+#define CMAKE_BOOT_MINGW
+#endif
+
+// include the generator
+#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"
+#include "cmGlobalVisualStudio11Generator.h"
+#include "cmGlobalVisualStudio12Generator.h"
+#include "cmGlobalVisualStudio14Generator.h"
+#include "cmGlobalVisualStudio71Generator.h"
+#include "cmGlobalVisualStudio8Generator.h"
+#include "cmGlobalVisualStudio9Generator.h"
+#define CMAKE_HAVE_VS_GENERATORS
+#endif
+#include "cmGlobalMSYSMakefileGenerator.h"
+#include "cmGlobalMinGWMakefileGenerator.h"
+#else
+#endif
+#if defined(CMAKE_USE_WMAKE)
+#include "cmGlobalWatcomWMakeGenerator.h"
+#endif
+#include "cmGlobalUnixMakefileGenerator3.h"
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmGlobalNinjaGenerator.h"
+#endif
+#include "cmExtraCodeLiteGenerator.h"
+
+#if !defined(CMAKE_BOOT_MINGW)
+#include "cmExtraCodeBlocksGenerator.h"
+#endif
+#include "cmExtraKateGenerator.h"
+#include "cmExtraSublimeTextGenerator.h"
+
+#ifdef CMAKE_USE_KDEVELOP
+#include "cmGlobalKdevelopGenerator.h"
+#endif
+
+#ifdef CMAKE_USE_ECLIPSE
+#include "cmExtraEclipseCDT4Generator.h"
+#endif
+
+#include <stdlib.h> // required for atoi
+
+#if defined(__APPLE__)
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmGlobalXCodeGenerator.h"
+#define CMAKE_USE_XCODE 1
+#endif
+#include <sys/resource.h>
+#include <sys/time.h>
+#endif
+
+#include <sys/types.h>
+// include sys/stat.h after sys/types.h
+#include <sys/stat.h> // struct stat
+
+#include <list>
+
+static bool cmakeCheckStampFile(const char* stampName);
+static bool cmakeCheckStampList(const char* stampName);
+
+void cmWarnUnusedCliWarning(const std::string& variable, int, void* ctx,
+ const char*, const cmMakefile*)
+{
+ cmake* cm = reinterpret_cast<cmake*>(ctx);
+ cm->MarkCliAsUsed(variable);
+}
+
+cmake::cmake()
+{
+ this->Trace = false;
+ this->TraceExpand = false;
+ this->WarnUninitialized = false;
+ this->WarnUnused = false;
+ this->WarnUnusedCli = true;
+ this->CheckSystemVars = false;
+ this->DebugOutput = false;
+ this->DebugTryCompile = false;
+ this->ClearBuildSystem = false;
+ this->FileComparison = new cmFileTimeComparison;
+
+ this->State = new cmState;
+ this->CurrentSnapshot = this->State->CreateBaseSnapshot();
+
+#ifdef __APPLE__
+ struct rlimit rlp;
+ if (!getrlimit(RLIMIT_STACK, &rlp)) {
+ if (rlp.rlim_cur != rlp.rlim_max) {
+ rlp.rlim_cur = rlp.rlim_max;
+ setrlimit(RLIMIT_STACK, &rlp);
+ }
+ }
+#endif
+
+ this->GlobalGenerator = CM_NULLPTR;
+ this->ProgressCallback = CM_NULLPTR;
+ this->ProgressCallbackClientData = CM_NULLPTR;
+ this->CurrentWorkingMode = NORMAL_MODE;
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ this->VariableWatch = new cmVariableWatch;
+#endif
+
+ this->AddDefaultGenerators();
+ this->AddDefaultExtraGenerators();
+ this->AddDefaultCommands();
+
+ // Make sure we can capture the build tool output.
+ cmSystemTools::EnableVSConsoleOutput();
+
+ // Set up a list of source and header extensions
+ // these are used to find files when the extension
+ // is not given
+ // The "c" extension MUST precede the "C" extension.
+ this->SourceFileExtensions.push_back("c");
+ this->SourceFileExtensions.push_back("C");
+
+ this->SourceFileExtensions.push_back("c++");
+ this->SourceFileExtensions.push_back("cc");
+ this->SourceFileExtensions.push_back("cpp");
+ this->SourceFileExtensions.push_back("cxx");
+ this->SourceFileExtensions.push_back("m");
+ this->SourceFileExtensions.push_back("M");
+ this->SourceFileExtensions.push_back("mm");
+
+ this->HeaderFileExtensions.push_back("h");
+ this->HeaderFileExtensions.push_back("hh");
+ this->HeaderFileExtensions.push_back("h++");
+ this->HeaderFileExtensions.push_back("hm");
+ this->HeaderFileExtensions.push_back("hpp");
+ this->HeaderFileExtensions.push_back("hxx");
+ this->HeaderFileExtensions.push_back("in");
+ this->HeaderFileExtensions.push_back("txx");
+}
+
+cmake::~cmake()
+{
+ delete this->State;
+ if (this->GlobalGenerator) {
+ delete this->GlobalGenerator;
+ this->GlobalGenerator = CM_NULLPTR;
+ }
+ cmDeleteAll(this->Generators);
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ delete this->VariableWatch;
+#endif
+ delete this->FileComparison;
+}
+
+void cmake::CleanupCommandsAndMacros()
+{
+ this->CurrentSnapshot = this->State->Reset();
+ this->State->RemoveUserDefinedCommands();
+ this->CurrentSnapshot.SetDefaultDefinitions();
+}
+
+// Parse the args
+bool cmake::SetCacheArgs(const std::vector<std::string>& args)
+{
+ bool findPackageMode = false;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ std::string arg = args[i];
+ if (arg.find("-D", 0) == 0) {
+ std::string entry = arg.substr(2);
+ if (entry.empty()) {
+ ++i;
+ if (i < args.size()) {
+ entry = args[i];
+ } else {
+ cmSystemTools::Error("-D must be followed with VAR=VALUE.");
+ return false;
+ }
+ }
+ std::string var, value;
+ cmState::CacheEntryType type = cmState::UNINITIALIZED;
+ if (cmState::ParseCacheEntry(entry, var, value, type)) {
+ // The value is transformed if it is a filepath for example, so
+ // we can't compare whether the value is already in the cache until
+ // after we call AddCacheEntry.
+ bool haveValue = false;
+ std::string cachedValue;
+ if (this->WarnUnusedCli) {
+ if (const char* v = this->State->GetInitializedCacheValue(var)) {
+ haveValue = true;
+ cachedValue = v;
+ }
+ }
+
+ this->AddCacheEntry(var, value.c_str(),
+ "No help, variable specified on the command line.",
+ type);
+
+ if (this->WarnUnusedCli) {
+ if (!haveValue ||
+ cachedValue != this->State->GetInitializedCacheValue(var)) {
+ this->WatchUnusedCli(var);
+ }
+ }
+ } else {
+ std::cerr << "Parse error in command line argument: " << arg << "\n"
+ << "Should be: VAR:type=value\n";
+ cmSystemTools::Error("No cmake script provided.");
+ return false;
+ }
+ } else if (cmHasLiteralPrefix(arg, "-W")) {
+ std::string entry = arg.substr(2);
+ if (entry.empty()) {
+ ++i;
+ if (i < args.size()) {
+ entry = args[i];
+ } else {
+ cmSystemTools::Error("-W must be followed with [no-]<name>.");
+ return false;
+ }
+ }
+
+ std::string name;
+ bool foundNo = false;
+ bool foundError = false;
+ unsigned int nameStartPosition = 0;
+
+ if (entry.find("no-", nameStartPosition) == 0) {
+ foundNo = true;
+ nameStartPosition += 3;
+ }
+
+ if (entry.find("error=", nameStartPosition) == 0) {
+ foundError = true;
+ nameStartPosition += 6;
+ }
+
+ name = entry.substr(nameStartPosition);
+ if (name.empty()) {
+ cmSystemTools::Error("No warning name provided.");
+ return false;
+ }
+
+ if (!foundNo && !foundError) {
+ // -W<name>
+ this->DiagLevels[name] = std::max(this->DiagLevels[name], DIAG_WARN);
+ } else if (foundNo && !foundError) {
+ // -Wno<name>
+ this->DiagLevels[name] = DIAG_IGNORE;
+ } else if (!foundNo && foundError) {
+ // -Werror=<name>
+ this->DiagLevels[name] = DIAG_ERROR;
+ } else {
+ // -Wno-error=<name>
+ this->DiagLevels[name] = std::min(this->DiagLevels[name], DIAG_WARN);
+ }
+ } else if (arg.find("-U", 0) == 0) {
+ std::string entryPattern = arg.substr(2);
+ if (entryPattern.empty()) {
+ ++i;
+ if (i < args.size()) {
+ entryPattern = args[i];
+ } else {
+ cmSystemTools::Error("-U must be followed with VAR.");
+ return false;
+ }
+ }
+ cmsys::RegularExpression regex(
+ cmsys::Glob::PatternToRegex(entryPattern, true, true).c_str());
+ // go through all cache entries and collect the vars which will be
+ // removed
+ std::vector<std::string> entriesToDelete;
+ std::vector<std::string> cacheKeys = this->State->GetCacheEntryKeys();
+ for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
+ it != cacheKeys.end(); ++it) {
+ cmState::CacheEntryType t = this->State->GetCacheEntryType(*it);
+ if (t != cmState::STATIC) {
+ if (regex.find(it->c_str())) {
+ entriesToDelete.push_back(*it);
+ }
+ }
+ }
+
+ // now remove them from the cache
+ for (std::vector<std::string>::const_iterator currentEntry =
+ entriesToDelete.begin();
+ currentEntry != entriesToDelete.end(); ++currentEntry) {
+ this->State->RemoveCacheEntry(*currentEntry);
+ }
+ } else if (arg.find("-C", 0) == 0) {
+ std::string path = arg.substr(2);
+ if (path.empty()) {
+ ++i;
+ if (i < args.size()) {
+ path = args[i];
+ } else {
+ cmSystemTools::Error("-C must be followed by a file name.");
+ return false;
+ }
+ }
+ std::cout << "loading initial cache file " << path << "\n";
+ this->ReadListFile(args, path.c_str());
+ } else if (arg.find("-P", 0) == 0) {
+ i++;
+ if (i >= args.size()) {
+ cmSystemTools::Error("-P must be followed by a file name.");
+ return false;
+ }
+ std::string path = args[i];
+ if (path.empty()) {
+ cmSystemTools::Error("No cmake script provided.");
+ return false;
+ }
+ this->ReadListFile(args, path.c_str());
+ } else if (arg.find("--find-package", 0) == 0) {
+ findPackageMode = true;
+ }
+ }
+
+ if (findPackageMode) {
+ return this->FindPackage(args);
+ }
+
+ return true;
+}
+
+void cmake::ReadListFile(const std::vector<std::string>& args,
+ const char* path)
+{
+ // if a generator was not yet created, temporarily create one
+ cmGlobalGenerator* gg = this->GetGlobalGenerator();
+ bool created = false;
+
+ // if a generator was not specified use a generic one
+ if (!gg) {
+ gg = new cmGlobalGenerator(this);
+ created = true;
+ }
+
+ // read in the list file to fill the cache
+ if (path) {
+ this->CurrentSnapshot = this->State->Reset();
+ std::string homeDir = this->GetHomeDirectory();
+ std::string homeOutputDir = this->GetHomeOutputDirectory();
+ this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ cmState::Snapshot snapshot = this->GetCurrentSnapshot();
+ snapshot.GetDirectory().SetCurrentBinary(
+ cmSystemTools::GetCurrentWorkingDirectory());
+ snapshot.GetDirectory().SetCurrentSource(
+ cmSystemTools::GetCurrentWorkingDirectory());
+ snapshot.SetDefaultDefinitions();
+ CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(gg, snapshot));
+ if (this->GetWorkingMode() != NORMAL_MODE) {
+ std::string file(cmSystemTools::CollapseFullPath(path));
+ cmSystemTools::ConvertToUnixSlashes(file);
+ mf->SetScriptModeFile(file.c_str());
+
+ mf->SetArgcArgv(args);
+ }
+ if (!mf->ReadListFile(path)) {
+ cmSystemTools::Error("Error processing file: ", path);
+ }
+ this->SetHomeDirectory(homeDir);
+ this->SetHomeOutputDirectory(homeOutputDir);
+ }
+
+ // free generic one if generated
+ if (created) {
+ delete gg;
+ }
+}
+
+bool cmake::FindPackage(const std::vector<std::string>& args)
+{
+ this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+
+ // if a generator was not yet created, temporarily create one
+ cmGlobalGenerator* gg = new cmGlobalGenerator(this);
+ this->SetGlobalGenerator(gg);
+
+ cmState::Snapshot snapshot = this->GetCurrentSnapshot();
+ snapshot.GetDirectory().SetCurrentBinary(
+ cmSystemTools::GetCurrentWorkingDirectory());
+ snapshot.GetDirectory().SetCurrentSource(
+ cmSystemTools::GetCurrentWorkingDirectory());
+ // read in the list file to fill the cache
+ snapshot.SetDefaultDefinitions();
+ cmMakefile* mf = new cmMakefile(gg, snapshot);
+ gg->AddMakefile(mf);
+
+ mf->SetArgcArgv(args);
+
+ std::string systemFile = mf->GetModulesFile("CMakeFindPackageMode.cmake");
+ mf->ReadListFile(systemFile.c_str());
+
+ std::string language = mf->GetSafeDefinition("LANGUAGE");
+ std::string mode = mf->GetSafeDefinition("MODE");
+ std::string packageName = mf->GetSafeDefinition("NAME");
+ bool packageFound = mf->IsOn("PACKAGE_FOUND");
+ bool quiet = mf->IsOn("PACKAGE_QUIET");
+
+ if (!packageFound) {
+ if (!quiet) {
+ printf("%s not found.\n", packageName.c_str());
+ }
+ } else if (mode == "EXIST") {
+ if (!quiet) {
+ printf("%s found.\n", packageName.c_str());
+ }
+ } else if (mode == "COMPILE") {
+ std::string includes = mf->GetSafeDefinition("PACKAGE_INCLUDE_DIRS");
+ std::vector<std::string> includeDirs;
+ cmSystemTools::ExpandListArgument(includes, includeDirs);
+
+ gg->CreateGenerationObjects();
+ cmLocalGenerator* lg = gg->LocalGenerators[0];
+ std::string includeFlags =
+ lg->GetIncludeFlags(includeDirs, CM_NULLPTR, language);
+
+ std::string definitions = mf->GetSafeDefinition("PACKAGE_DEFINITIONS");
+ printf("%s %s\n", includeFlags.c_str(), definitions.c_str());
+ } else if (mode == "LINK") {
+ const char* targetName = "dummy";
+ std::vector<std::string> srcs;
+ cmTarget* tgt = mf->AddExecutable(targetName, srcs, true);
+ tgt->SetProperty("LINKER_LANGUAGE", language.c_str());
+
+ std::string libs = mf->GetSafeDefinition("PACKAGE_LIBRARIES");
+ std::vector<std::string> libList;
+ cmSystemTools::ExpandListArgument(libs, libList);
+ for (std::vector<std::string>::const_iterator libIt = libList.begin();
+ libIt != libList.end(); ++libIt) {
+ mf->AddLinkLibraryForTarget(targetName, *libIt, GENERAL_LibraryType);
+ }
+
+ std::string buildType = mf->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ buildType = cmSystemTools::UpperCase(buildType);
+
+ std::string linkLibs;
+ std::string frameworkPath;
+ std::string linkPath;
+ std::string flags;
+ std::string linkFlags;
+ gg->CreateGenerationObjects();
+ cmGeneratorTarget* gtgt = gg->FindGeneratorTarget(tgt->GetName());
+ cmLocalGenerator* lg = gtgt->GetLocalGenerator();
+ lg->GetTargetFlags(buildType, linkLibs, frameworkPath, linkPath, flags,
+ linkFlags, gtgt, false);
+ linkLibs = frameworkPath + linkPath + linkLibs;
+
+ printf("%s\n", linkLibs.c_str());
+
+ /* if ( use_win32 )
+ {
+ tgt->SetProperty("WIN32_EXECUTABLE", "ON");
+ }
+ if ( use_macbundle)
+ {
+ tgt->SetProperty("MACOSX_BUNDLE", "ON");
+ }*/
+ }
+
+ // free generic one if generated
+ // this->SetGlobalGenerator(0); // setting 0-pointer is not possible
+ // delete gg; // this crashes inside the cmake instance
+
+ return packageFound;
+}
+
+// Parse the args
+void cmake::SetArgs(const std::vector<std::string>& args,
+ bool directoriesSetBefore)
+{
+ bool directoriesSet = directoriesSetBefore;
+ bool haveToolset = false;
+ bool havePlatform = false;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ std::string arg = args[i];
+ if (arg.find("-H", 0) == 0) {
+ directoriesSet = true;
+ std::string path = arg.substr(2);
+ path = cmSystemTools::CollapseFullPath(path);
+ cmSystemTools::ConvertToUnixSlashes(path);
+ this->SetHomeDirectory(path);
+ } else if (arg.find("-S", 0) == 0) {
+ // There is no local generate anymore. Ignore -S option.
+ } else if (arg.find("-O", 0) == 0) {
+ // There is no local generate anymore. Ignore -O option.
+ } else if (arg.find("-B", 0) == 0) {
+ directoriesSet = true;
+ std::string path = arg.substr(2);
+ path = cmSystemTools::CollapseFullPath(path);
+ cmSystemTools::ConvertToUnixSlashes(path);
+ this->SetHomeOutputDirectory(path);
+ } else if ((i < args.size() - 2) &&
+ (arg.find("--check-build-system", 0) == 0)) {
+ this->CheckBuildSystemArgument = args[++i];
+ this->ClearBuildSystem = (atoi(args[++i].c_str()) > 0);
+ } else if ((i < args.size() - 1) &&
+ (arg.find("--check-stamp-file", 0) == 0)) {
+ this->CheckStampFile = args[++i];
+ } else if ((i < args.size() - 1) &&
+ (arg.find("--check-stamp-list", 0) == 0)) {
+ this->CheckStampList = args[++i];
+ }
+#if defined(CMAKE_HAVE_VS_GENERATORS)
+ else if ((i < args.size() - 1) &&
+ (arg.find("--vs-solution-file", 0) == 0)) {
+ this->VSSolutionFile = args[++i];
+ }
+#endif
+ else if (arg.find("-D", 0) == 0) {
+ // skip for now
+ } else if (arg.find("-U", 0) == 0) {
+ // skip for now
+ } else if (arg.find("-C", 0) == 0) {
+ // skip for now
+ } else if (arg.find("-P", 0) == 0) {
+ // skip for now
+ i++;
+ } else if (arg.find("--find-package", 0) == 0) {
+ // skip for now
+ i++;
+ } else if (arg.find("-W", 0) == 0) {
+ // skip for now
+ } else if (arg.find("--graphviz=", 0) == 0) {
+ std::string path = arg.substr(strlen("--graphviz="));
+ path = cmSystemTools::CollapseFullPath(path);
+ cmSystemTools::ConvertToUnixSlashes(path);
+ this->GraphVizFile = path;
+ if (this->GraphVizFile.empty()) {
+ cmSystemTools::Error("No file specified for --graphviz");
+ }
+ } else if (arg.find("--debug-trycompile", 0) == 0) {
+ std::cout << "debug trycompile on\n";
+ this->DebugTryCompileOn();
+ } else if (arg.find("--debug-output", 0) == 0) {
+ std::cout << "Running with debug output on.\n";
+ this->SetDebugOutputOn(true);
+ } else if (arg.find("--trace-expand", 0) == 0) {
+ std::cout << "Running with expanded trace output on.\n";
+ this->SetTrace(true);
+ this->SetTraceExpand(true);
+ } else if (arg.find("--trace-source=", 0) == 0) {
+ std::string file = arg.substr(strlen("--trace-source="));
+ cmSystemTools::ConvertToUnixSlashes(file);
+ this->AddTraceSource(file);
+ this->SetTrace(true);
+ } else if (arg.find("--trace", 0) == 0) {
+ std::cout << "Running with trace output on.\n";
+ this->SetTrace(true);
+ this->SetTraceExpand(false);
+ } else if (arg.find("--warn-uninitialized", 0) == 0) {
+ std::cout << "Warn about uninitialized values.\n";
+ this->SetWarnUninitialized(true);
+ } else if (arg.find("--warn-unused-vars", 0) == 0) {
+ std::cout << "Finding unused variables.\n";
+ this->SetWarnUnused(true);
+ } else if (arg.find("--no-warn-unused-cli", 0) == 0) {
+ std::cout << "Not searching for unused variables given on the "
+ << "command line.\n";
+ this->SetWarnUnusedCli(false);
+ } else if (arg.find("--check-system-vars", 0) == 0) {
+ std::cout << "Also check system files when warning about unused and "
+ << "uninitialized variables.\n";
+ this->SetCheckSystemVars(true);
+ } else if (arg.find("-A", 0) == 0) {
+ std::string value = arg.substr(2);
+ if (value.empty()) {
+ ++i;
+ if (i >= args.size()) {
+ cmSystemTools::Error("No platform specified for -A");
+ return;
+ }
+ value = args[i];
+ }
+ if (havePlatform) {
+ cmSystemTools::Error("Multiple -A options not allowed");
+ return;
+ }
+ this->GeneratorPlatform = value;
+ havePlatform = true;
+ } else if (arg.find("-T", 0) == 0) {
+ std::string value = arg.substr(2);
+ if (value.empty()) {
+ ++i;
+ if (i >= args.size()) {
+ cmSystemTools::Error("No toolset specified for -T");
+ return;
+ }
+ value = args[i];
+ }
+ if (haveToolset) {
+ cmSystemTools::Error("Multiple -T options not allowed");
+ return;
+ }
+ this->GeneratorToolset = value;
+ haveToolset = true;
+ } else if (arg.find("-G", 0) == 0) {
+ std::string value = arg.substr(2);
+ if (value.empty()) {
+ ++i;
+ if (i >= args.size()) {
+ cmSystemTools::Error("No generator specified for -G");
+ this->PrintGeneratorList();
+ return;
+ }
+ value = args[i];
+ }
+ cmGlobalGenerator* gen = this->CreateGlobalGenerator(value);
+ if (!gen) {
+ cmSystemTools::Error("Could not create named generator ",
+ value.c_str());
+ this->PrintGeneratorList();
+ } else {
+ this->SetGlobalGenerator(gen);
+ }
+ }
+ // no option assume it is the path to the source
+ else {
+ directoriesSet = true;
+ this->SetDirectoriesFromFile(arg.c_str());
+ }
+ }
+ if (!directoriesSet) {
+ this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ }
+}
+
+void cmake::SetDirectoriesFromFile(const char* arg)
+{
+ // Check if the argument refers to a CMakeCache.txt or
+ // CMakeLists.txt file.
+ std::string listPath;
+ std::string cachePath;
+ bool argIsFile = false;
+ if (cmSystemTools::FileIsDirectory(arg)) {
+ std::string path = cmSystemTools::CollapseFullPath(arg);
+ cmSystemTools::ConvertToUnixSlashes(path);
+ std::string cacheFile = path;
+ cacheFile += "/CMakeCache.txt";
+ std::string listFile = path;
+ listFile += "/CMakeLists.txt";
+ if (cmSystemTools::FileExists(cacheFile.c_str())) {
+ cachePath = path;
+ }
+ if (cmSystemTools::FileExists(listFile.c_str())) {
+ listPath = path;
+ }
+ } else if (cmSystemTools::FileExists(arg)) {
+ argIsFile = true;
+ std::string fullPath = cmSystemTools::CollapseFullPath(arg);
+ std::string name = cmSystemTools::GetFilenameName(fullPath);
+ name = cmSystemTools::LowerCase(name);
+ if (name == "cmakecache.txt") {
+ cachePath = cmSystemTools::GetFilenamePath(fullPath);
+ } else if (name == "cmakelists.txt") {
+ listPath = cmSystemTools::GetFilenamePath(fullPath);
+ }
+ } else {
+ // Specified file or directory does not exist. Try to set things
+ // up to produce a meaningful error message.
+ std::string fullPath = cmSystemTools::CollapseFullPath(arg);
+ std::string name = cmSystemTools::GetFilenameName(fullPath);
+ name = cmSystemTools::LowerCase(name);
+ if (name == "cmakecache.txt" || name == "cmakelists.txt") {
+ argIsFile = true;
+ listPath = cmSystemTools::GetFilenamePath(fullPath);
+ } else {
+ listPath = fullPath;
+ }
+ }
+
+ // If there is a CMakeCache.txt file, use its settings.
+ if (!cachePath.empty()) {
+ if (this->LoadCache(cachePath)) {
+ const char* existingValue =
+ this->State->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
+ if (existingValue) {
+ this->SetHomeOutputDirectory(cachePath);
+ this->SetHomeDirectory(existingValue);
+ return;
+ }
+ }
+ }
+
+ // If there is a CMakeLists.txt file, use it as the source tree.
+ if (!listPath.empty()) {
+ this->SetHomeDirectory(listPath);
+
+ if (argIsFile) {
+ // Source CMakeLists.txt file given. It was probably dropped
+ // onto the executable in a GUI. Default to an in-source build.
+ this->SetHomeOutputDirectory(listPath);
+ } else {
+ // Source directory given on command line. Use current working
+ // directory as build tree.
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ this->SetHomeOutputDirectory(cwd);
+ }
+ return;
+ }
+
+ // We didn't find a CMakeLists.txt or CMakeCache.txt file from the
+ // argument. Assume it is the path to the source tree, and use the
+ // current working directory as the build tree.
+ std::string full = cmSystemTools::CollapseFullPath(arg);
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ this->SetHomeDirectory(full);
+ this->SetHomeOutputDirectory(cwd);
+}
+
+// at the end of this CMAKE_ROOT and CMAKE_COMMAND should be added to the
+// cache
+int cmake::AddCMakePaths()
+{
+ // Save the value in the cache
+ this->AddCacheEntry("CMAKE_COMMAND",
+ cmSystemTools::GetCMakeCommand().c_str(),
+ "Path to CMake executable.", cmState::INTERNAL);
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ this->AddCacheEntry("CMAKE_CTEST_COMMAND",
+ cmSystemTools::GetCTestCommand().c_str(),
+ "Path to ctest program executable.", cmState::INTERNAL);
+ this->AddCacheEntry("CMAKE_CPACK_COMMAND",
+ cmSystemTools::GetCPackCommand().c_str(),
+ "Path to cpack program executable.", cmState::INTERNAL);
+#endif
+ if (!cmSystemTools::FileExists(
+ (cmSystemTools::GetCMakeRoot() + "/Modules/CMake.cmake").c_str())) {
+ // couldn't find modules
+ 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());
+ return 0;
+ }
+ this->AddCacheEntry("CMAKE_ROOT", cmSystemTools::GetCMakeRoot().c_str(),
+ "Path to CMake installation.", cmState::INTERNAL);
+
+ return 1;
+}
+
+void cmake::AddExtraGenerator(const std::string& name,
+ CreateExtraGeneratorFunctionType newFunction)
+{
+ cmExternalMakefileProjectGenerator* extraGenerator = newFunction();
+ const std::vector<std::string>& supportedGlobalGenerators =
+ extraGenerator->GetSupportedGlobalGenerators();
+
+ for (std::vector<std::string>::const_iterator it =
+ supportedGlobalGenerators.begin();
+ it != supportedGlobalGenerators.end(); ++it) {
+ std::string fullName =
+ cmExternalMakefileProjectGenerator::CreateFullGeneratorName(*it, name);
+ this->ExtraGenerators[fullName] = newFunction;
+ }
+ delete extraGenerator;
+}
+
+void cmake::AddDefaultExtraGenerators()
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#if defined(_WIN32) && !defined(__CYGWIN__)
+// e.g. kdevelop4 ?
+#endif
+
+ this->AddExtraGenerator(cmExtraCodeBlocksGenerator::GetActualName(),
+ &cmExtraCodeBlocksGenerator::New);
+ this->AddExtraGenerator(cmExtraCodeLiteGenerator::GetActualName(),
+ &cmExtraCodeLiteGenerator::New);
+ this->AddExtraGenerator(cmExtraSublimeTextGenerator::GetActualName(),
+ &cmExtraSublimeTextGenerator::New);
+ this->AddExtraGenerator(cmExtraKateGenerator::GetActualName(),
+ &cmExtraKateGenerator::New);
+
+#ifdef CMAKE_USE_ECLIPSE
+ this->AddExtraGenerator(cmExtraEclipseCDT4Generator::GetActualName(),
+ &cmExtraEclipseCDT4Generator::New);
+#endif
+
+#ifdef CMAKE_USE_KDEVELOP
+ this->AddExtraGenerator(cmGlobalKdevelopGenerator::GetActualName(),
+ &cmGlobalKdevelopGenerator::New);
+ // for kdevelop also add the generator with just the name of the
+ // extra generator, since it was this way since cmake 2.2
+ this->ExtraGenerators[cmGlobalKdevelopGenerator::GetActualName()] =
+ &cmGlobalKdevelopGenerator::New;
+#endif
+
+#endif
+}
+
+void cmake::GetRegisteredGenerators(std::vector<GeneratorInfo>& generators)
+{
+ for (RegisteredGeneratorsVector::const_iterator i = this->Generators.begin(),
+ e = this->Generators.end();
+ i != e; ++i) {
+ std::vector<std::string> names;
+ (*i)->GetGenerators(names);
+
+ for (size_t j = 0; j < names.size(); ++j) {
+ GeneratorInfo info;
+ info.supportsToolset = (*i)->SupportsToolset();
+ info.name = names[j];
+ generators.push_back(info);
+ }
+ }
+
+ for (RegisteredExtraGeneratorsMap::const_iterator
+ i = this->ExtraGenerators.begin(),
+ e = this->ExtraGenerators.end();
+ i != e; ++i) {
+ GeneratorInfo info;
+ info.name = i->first;
+ info.supportsToolset = false;
+ generators.push_back(info);
+ }
+}
+
+cmGlobalGenerator* cmake::CreateGlobalGenerator(const std::string& gname)
+{
+ cmExternalMakefileProjectGenerator* extraGenerator = CM_NULLPTR;
+ std::string name = gname;
+ RegisteredExtraGeneratorsMap::const_iterator extraGenIt =
+ this->ExtraGenerators.find(name);
+ if (extraGenIt != this->ExtraGenerators.end()) {
+ extraGenerator = (extraGenIt->second)();
+ name = extraGenerator->GetGlobalGeneratorName(name);
+ }
+
+ cmGlobalGenerator* generator = CM_NULLPTR;
+ for (RegisteredGeneratorsVector::const_iterator i = this->Generators.begin();
+ i != this->Generators.end(); ++i) {
+ generator = (*i)->CreateGlobalGenerator(name, this);
+ if (generator) {
+ break;
+ }
+ }
+
+ if (generator) {
+ generator->SetExternalMakefileProjectGenerator(extraGenerator);
+ } else {
+ delete extraGenerator;
+ }
+
+ return generator;
+}
+
+void cmake::SetHomeDirectory(const std::string& dir)
+{
+ this->State->SetSourceDirectory(dir);
+ if (this->CurrentSnapshot.IsValid()) {
+ this->CurrentSnapshot.SetDefinition("CMAKE_SOURCE_DIR", dir);
+ }
+}
+
+const char* cmake::GetHomeDirectory() const
+{
+ return this->State->GetSourceDirectory();
+}
+
+void cmake::SetHomeOutputDirectory(const std::string& dir)
+{
+ this->State->SetBinaryDirectory(dir);
+ if (this->CurrentSnapshot.IsValid()) {
+ this->CurrentSnapshot.SetDefinition("CMAKE_BINARY_DIR", dir);
+ }
+}
+
+const char* cmake::GetHomeOutputDirectory() const
+{
+ return this->State->GetBinaryDirectory();
+}
+
+void cmake::SetGlobalGenerator(cmGlobalGenerator* gg)
+{
+ if (!gg) {
+ cmSystemTools::Error("Error SetGlobalGenerator called with null");
+ return;
+ }
+ // delete the old generator
+ if (this->GlobalGenerator) {
+ delete this->GlobalGenerator;
+ // restore the original environment variables CXX and CC
+ // Restore CC
+ std::string env = "CC=";
+ if (!this->CCEnvironment.empty()) {
+ env += this->CCEnvironment;
+ }
+ cmSystemTools::PutEnv(env);
+ env = "CXX=";
+ if (!this->CXXEnvironment.empty()) {
+ env += this->CXXEnvironment;
+ }
+ cmSystemTools::PutEnv(env);
+ }
+
+ // set the new
+ this->GlobalGenerator = gg;
+
+ // set the global flag for unix style paths on cmSystemTools as soon as
+ // the generator is set. This allows gmake to be used on windows.
+ cmSystemTools::SetForceUnixPaths(this->GlobalGenerator->GetForceUnixPaths());
+
+ // Save the environment variables CXX and CC
+ const char* cxx = getenv("CXX");
+ const char* cc = getenv("CC");
+ if (cxx) {
+ this->CXXEnvironment = cxx;
+ } else {
+ this->CXXEnvironment = "";
+ }
+ if (cc) {
+ this->CCEnvironment = cc;
+ } else {
+ this->CCEnvironment = "";
+ }
+}
+
+int cmake::DoPreConfigureChecks()
+{
+ // Make sure the Source directory contains a CMakeLists.txt file.
+ std::string srcList = this->GetHomeDirectory();
+ srcList += "/CMakeLists.txt";
+ if (!cmSystemTools::FileExists(srcList.c_str())) {
+ std::ostringstream err;
+ if (cmSystemTools::FileIsDirectory(this->GetHomeDirectory())) {
+ err << "The source directory \"" << this->GetHomeDirectory()
+ << "\" does not appear to contain CMakeLists.txt.\n";
+ } else if (cmSystemTools::FileExists(this->GetHomeDirectory())) {
+ err << "The source directory \"" << this->GetHomeDirectory()
+ << "\" is a file, not a directory.\n";
+ } else {
+ err << "The source directory \"" << this->GetHomeDirectory()
+ << "\" does not exist.\n";
+ }
+ err << "Specify --help for usage, or press the help button on the CMake "
+ "GUI.";
+ cmSystemTools::Error(err.str().c_str());
+ return -2;
+ }
+
+ // do a sanity check on some values
+ if (this->State->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY")) {
+ std::string cacheStart =
+ this->State->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY");
+ cacheStart += "/CMakeLists.txt";
+ std::string currentStart = this->GetHomeDirectory();
+ currentStart += "/CMakeLists.txt";
+ if (!cmSystemTools::SameFile(cacheStart, currentStart)) {
+ std::string message = "The source \"";
+ message += currentStart;
+ message += "\" does not match the source \"";
+ message += cacheStart;
+ message += "\" used to generate cache. ";
+ message += "Re-run cmake with a different source directory.";
+ cmSystemTools::Error(message.c_str());
+ return -2;
+ }
+ } else {
+ return 0;
+ }
+ return 1;
+}
+struct SaveCacheEntry
+{
+ std::string key;
+ std::string value;
+ std::string help;
+ cmState::CacheEntryType type;
+};
+
+int cmake::HandleDeleteCacheVariables(const std::string& var)
+{
+ std::vector<std::string> argsSplit;
+ cmSystemTools::ExpandListArgument(std::string(var), argsSplit, true);
+ // erase the property to avoid infinite recursion
+ this->State->SetGlobalProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_", "");
+ if (this->State->GetIsInTryCompile()) {
+ return 0;
+ }
+ std::vector<SaveCacheEntry> saved;
+ std::ostringstream warning;
+ /* clang-format off */
+ warning
+ << "You have changed variables that require your cache to be deleted.\n"
+ << "Configure will be re-run and you may have to reset some variables.\n"
+ << "The following variables have changed:\n";
+ /* clang-format on */
+ for (std::vector<std::string>::iterator i = argsSplit.begin();
+ i != argsSplit.end(); ++i) {
+ SaveCacheEntry save;
+ save.key = *i;
+ warning << *i << "= ";
+ i++;
+ save.value = *i;
+ warning << *i << "\n";
+ const char* existingValue = this->State->GetCacheEntryValue(save.key);
+ if (existingValue) {
+ save.type = this->State->GetCacheEntryType(save.key);
+ if (const char* help =
+ this->State->GetCacheEntryProperty(save.key, "HELPSTRING")) {
+ save.help = help;
+ }
+ }
+ saved.push_back(save);
+ }
+
+ // remove the cache
+ this->DeleteCache(this->GetHomeOutputDirectory());
+ // load the empty cache
+ this->LoadCache();
+ // restore the changed compilers
+ for (std::vector<SaveCacheEntry>::iterator i = saved.begin();
+ i != saved.end(); ++i) {
+ this->AddCacheEntry(i->key, i->value.c_str(), i->help.c_str(), i->type);
+ }
+ cmSystemTools::Message(warning.str().c_str());
+ // avoid reconfigure if there were errors
+ if (!cmSystemTools::GetErrorOccuredFlag()) {
+ // re-run configure
+ return this->Configure();
+ }
+ return 0;
+}
+
+int cmake::Configure()
+{
+ DiagLevel diagLevel;
+
+ if (this->DiagLevels.count("deprecated") == 1) {
+
+ diagLevel = this->DiagLevels["deprecated"];
+ if (diagLevel == DIAG_IGNORE) {
+ this->SetSuppressDeprecatedWarnings(true);
+ this->SetDeprecatedWarningsAsErrors(false);
+ } else if (diagLevel == DIAG_WARN) {
+ this->SetSuppressDeprecatedWarnings(false);
+ this->SetDeprecatedWarningsAsErrors(false);
+ } else if (diagLevel == DIAG_ERROR) {
+ this->SetSuppressDeprecatedWarnings(false);
+ this->SetDeprecatedWarningsAsErrors(true);
+ }
+ }
+
+ if (this->DiagLevels.count("dev") == 1) {
+ bool setDeprecatedVariables = false;
+
+ const char* cachedWarnDeprecated =
+ this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED");
+ const char* cachedErrorDeprecated =
+ this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED");
+
+ // don't overwrite deprecated warning setting from a previous invocation
+ if (!cachedWarnDeprecated && !cachedErrorDeprecated) {
+ setDeprecatedVariables = true;
+ }
+
+ diagLevel = this->DiagLevels["dev"];
+ if (diagLevel == DIAG_IGNORE) {
+ this->SetSuppressDevWarnings(true);
+ this->SetDevWarningsAsErrors(false);
+
+ if (setDeprecatedVariables) {
+ this->SetSuppressDeprecatedWarnings(true);
+ this->SetDeprecatedWarningsAsErrors(false);
+ }
+ } else if (diagLevel == DIAG_WARN) {
+ this->SetSuppressDevWarnings(false);
+ this->SetDevWarningsAsErrors(false);
+
+ if (setDeprecatedVariables) {
+ this->SetSuppressDeprecatedWarnings(false);
+ this->SetDeprecatedWarningsAsErrors(false);
+ }
+ } else if (diagLevel == DIAG_ERROR) {
+ this->SetSuppressDevWarnings(false);
+ this->SetDevWarningsAsErrors(true);
+
+ if (setDeprecatedVariables) {
+ this->SetSuppressDeprecatedWarnings(false);
+ this->SetDeprecatedWarningsAsErrors(true);
+ }
+ }
+ }
+
+ int ret = this->ActualConfigure();
+ const char* delCacheVars =
+ this->State->GetGlobalProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_");
+ if (delCacheVars && delCacheVars[0] != 0) {
+ return this->HandleDeleteCacheVariables(delCacheVars);
+ }
+ return ret;
+}
+
+int cmake::ActualConfigure()
+{
+ // Construct right now our path conversion table before it's too late:
+ this->UpdateConversionPathTable();
+ this->CleanupCommandsAndMacros();
+
+ int res = 0;
+ if (this->GetWorkingMode() == NORMAL_MODE) {
+ res = this->DoPreConfigureChecks();
+ }
+ if (res < 0) {
+ return -2;
+ }
+ if (!res) {
+ this->AddCacheEntry(
+ "CMAKE_HOME_DIRECTORY", this->GetHomeDirectory(),
+ "Source directory with the top level CMakeLists.txt file for this "
+ "project",
+ cmState::INTERNAL);
+ }
+
+ // no generator specified on the command line
+ if (!this->GlobalGenerator) {
+ const char* genName =
+ this->State->GetInitializedCacheValue("CMAKE_GENERATOR");
+ const char* extraGenName =
+ this->State->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
+ if (genName) {
+ std::string fullName =
+ cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
+ genName, extraGenName ? extraGenName : "");
+ this->GlobalGenerator = this->CreateGlobalGenerator(fullName);
+ }
+ if (this->GlobalGenerator) {
+ // set the global flag for unix style paths on cmSystemTools as
+ // soon as the generator is set. This allows gmake to be used
+ // on windows.
+ cmSystemTools::SetForceUnixPaths(
+ this->GlobalGenerator->GetForceUnixPaths());
+ } else {
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
+ std::string installedCompiler;
+ // Try to find the newest VS installed on the computer and
+ // use that as a default if -G is not specified
+ const std::string vsregBase =
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\";
+ std::vector<std::string> vsVerions;
+ vsVerions.push_back("VisualStudio\\");
+ vsVerions.push_back("VCExpress\\");
+ vsVerions.push_back("WDExpress\\");
+ struct VSRegistryEntryName
+ {
+ const char* MSVersion;
+ const char* GeneratorName;
+ };
+ VSRegistryEntryName version[] = {
+ /* clang-format needs this comment to break after the opening brace */
+ { "7.1", "Visual Studio 7 .NET 2003" },
+ { "8.0", "Visual Studio 8 2005" },
+ { "9.0", "Visual Studio 9 2008" },
+ { "10.0", "Visual Studio 10 2010" },
+ { "11.0", "Visual Studio 11 2012" },
+ { "12.0", "Visual Studio 12 2013" },
+ { "14.0", "Visual Studio 14 2015" },
+ { 0, 0 }
+ };
+ for (int i = 0; version[i].MSVersion != 0; i++) {
+ for (size_t b = 0; b < vsVerions.size(); b++) {
+ std::string reg = vsregBase + vsVerions[b] + version[i].MSVersion;
+ reg += ";InstallDir]";
+ cmSystemTools::ExpandRegistryValues(reg, cmSystemTools::KeyWOW64_32);
+ if (!(reg == "/registry")) {
+ installedCompiler = version[i].GeneratorName;
+ break;
+ }
+ }
+ }
+ cmGlobalGenerator* gen =
+ this->CreateGlobalGenerator(installedCompiler.c_str());
+ if (!gen) {
+ gen = new cmGlobalNMakeMakefileGenerator(this);
+ }
+ this->SetGlobalGenerator(gen);
+ std::cout << "-- Building for: " << gen->GetName() << "\n";
+#else
+ this->SetGlobalGenerator(new cmGlobalUnixMakefileGenerator3(this));
+#endif
+ }
+ if (!this->GlobalGenerator) {
+ cmSystemTools::Error("Could not create generator");
+ return -1;
+ }
+ }
+
+ const char* genName =
+ this->State->GetInitializedCacheValue("CMAKE_GENERATOR");
+ if (genName) {
+ if (!this->GlobalGenerator->MatchesGeneratorName(genName)) {
+ std::string message = "Error: generator : ";
+ message += this->GlobalGenerator->GetName();
+ message += "\nDoes not match the generator used previously: ";
+ message += genName;
+ message += "\nEither remove the CMakeCache.txt file and CMakeFiles "
+ "directory or choose a different binary directory.";
+ cmSystemTools::Error(message.c_str());
+ return -2;
+ }
+ }
+ if (!this->State->GetInitializedCacheValue("CMAKE_GENERATOR")) {
+ this->AddCacheEntry("CMAKE_GENERATOR",
+ this->GlobalGenerator->GetName().c_str(),
+ "Name of generator.", cmState::INTERNAL);
+ this->AddCacheEntry("CMAKE_EXTRA_GENERATOR",
+ this->GlobalGenerator->GetExtraGeneratorName().c_str(),
+ "Name of external makefile project generator.",
+ cmState::INTERNAL);
+ }
+
+ if (const char* platformName =
+ this->State->GetInitializedCacheValue("CMAKE_GENERATOR_PLATFORM")) {
+ if (this->GeneratorPlatform.empty()) {
+ this->GeneratorPlatform = platformName;
+ } else if (this->GeneratorPlatform != platformName) {
+ std::string message = "Error: generator platform: ";
+ message += this->GeneratorPlatform;
+ message += "\nDoes not match the platform used previously: ";
+ message += platformName;
+ message += "\nEither remove the CMakeCache.txt file and CMakeFiles "
+ "directory or choose a different binary directory.";
+ cmSystemTools::Error(message.c_str());
+ return -2;
+ }
+ } else {
+ this->AddCacheEntry("CMAKE_GENERATOR_PLATFORM",
+ this->GeneratorPlatform.c_str(),
+ "Name of generator platform.", cmState::INTERNAL);
+ }
+
+ if (const char* tsName =
+ this->State->GetInitializedCacheValue("CMAKE_GENERATOR_TOOLSET")) {
+ if (this->GeneratorToolset.empty()) {
+ this->GeneratorToolset = tsName;
+ } else if (this->GeneratorToolset != tsName) {
+ std::string message = "Error: generator toolset: ";
+ message += this->GeneratorToolset;
+ message += "\nDoes not match the toolset used previously: ";
+ message += tsName;
+ message += "\nEither remove the CMakeCache.txt file and CMakeFiles "
+ "directory or choose a different binary directory.";
+ cmSystemTools::Error(message.c_str());
+ return -2;
+ }
+ } else {
+ this->AddCacheEntry("CMAKE_GENERATOR_TOOLSET",
+ this->GeneratorToolset.c_str(),
+ "Name of generator toolset.", cmState::INTERNAL);
+ }
+
+ // reset any system configuration information, except for when we are
+ // InTryCompile. With TryCompile the system info is taken from the parent's
+ // info to save time
+ if (!this->State->GetIsInTryCompile()) {
+ this->GlobalGenerator->ClearEnabledLanguages();
+
+ this->TruncateOutputLog("CMakeOutput.log");
+ this->TruncateOutputLog("CMakeError.log");
+ }
+
+ // actually do the configure
+ this->GlobalGenerator->Configure();
+ // Before saving the cache
+ // if the project did not define one of the entries below, add them now
+ // so users can edit the values in the cache:
+
+ // We used to always present LIBRARY_OUTPUT_PATH and
+ // EXECUTABLE_OUTPUT_PATH. They are now documented as old-style and
+ // should no longer be used. Therefore we present them only if the
+ // project requires compatibility with CMake 2.4. We detect this
+ // here by looking for the old CMAKE_BACKWARDS_COMPATIBILITY
+ // variable created when CMP0001 is not set to NEW.
+ if (this->State->GetInitializedCacheValue("CMAKE_BACKWARDS_COMPATIBILITY")) {
+ if (!this->State->GetInitializedCacheValue("LIBRARY_OUTPUT_PATH")) {
+ this->AddCacheEntry(
+ "LIBRARY_OUTPUT_PATH", "",
+ "Single output directory for building all libraries.", cmState::PATH);
+ }
+ if (!this->State->GetInitializedCacheValue("EXECUTABLE_OUTPUT_PATH")) {
+ this->AddCacheEntry(
+ "EXECUTABLE_OUTPUT_PATH", "",
+ "Single output directory for building all executables.",
+ cmState::PATH);
+ }
+ }
+
+ cmMakefile* mf = this->GlobalGenerator->GetMakefiles()[0];
+ if (mf->IsOn("CTEST_USE_LAUNCHERS") &&
+ !this->State->GetGlobalProperty("RULE_LAUNCH_COMPILE")) {
+ cmSystemTools::Error(
+ "CTEST_USE_LAUNCHERS is enabled, but the "
+ "RULE_LAUNCH_COMPILE global property is not defined.\n"
+ "Did you forget to include(CTest) in the toplevel "
+ "CMakeLists.txt ?");
+ }
+
+ // only save the cache if there were no fatal errors
+ if (this->GetWorkingMode() == NORMAL_MODE) {
+ this->SaveCache(this->GetHomeOutputDirectory());
+ }
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return -1;
+ }
+ return 0;
+}
+
+void cmake::PreLoadCMakeFiles()
+{
+ std::vector<std::string> args;
+ std::string pre_load = this->GetHomeDirectory();
+ if (!pre_load.empty()) {
+ pre_load += "/PreLoad.cmake";
+ if (cmSystemTools::FileExists(pre_load.c_str())) {
+ this->ReadListFile(args, pre_load.c_str());
+ }
+ }
+ pre_load = this->GetHomeOutputDirectory();
+ if (!pre_load.empty()) {
+ pre_load += "/PreLoad.cmake";
+ if (cmSystemTools::FileExists(pre_load.c_str())) {
+ this->ReadListFile(args, pre_load.c_str());
+ }
+ }
+}
+
+// handle a command line invocation
+int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
+{
+ // Process the arguments
+ this->SetArgs(args);
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return -1;
+ }
+
+ // If we are given a stamp list file check if it is really out of date.
+ if (!this->CheckStampList.empty() &&
+ cmakeCheckStampList(this->CheckStampList.c_str())) {
+ return 0;
+ }
+
+ // If we are given a stamp file check if it is really out of date.
+ if (!this->CheckStampFile.empty() &&
+ cmakeCheckStampFile(this->CheckStampFile.c_str())) {
+ return 0;
+ }
+
+ if (this->GetWorkingMode() == NORMAL_MODE) {
+ // load the cache
+ if (this->LoadCache() < 0) {
+ cmSystemTools::Error("Error executing cmake::LoadCache(). Aborting.\n");
+ return -1;
+ }
+ } else {
+ this->AddCMakePaths();
+ }
+
+ // Add any cache args
+ if (!this->SetCacheArgs(args)) {
+ cmSystemTools::Error("Problem processing arguments. Aborting.\n");
+ return -1;
+ }
+
+ // In script mode we terminate after running the script.
+ if (this->GetWorkingMode() != NORMAL_MODE) {
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
+ // If MAKEFLAGS are given in the environment, remove the environment
+ // variable. This will prevent try-compile from succeeding when it
+ // should fail (if "-i" is an option). We cannot simply test
+ // whether "-i" is given and remove it because some make programs
+ // encode the MAKEFLAGS variable in a strange way.
+ if (getenv("MAKEFLAGS")) {
+ cmSystemTools::PutEnv("MAKEFLAGS=");
+ }
+
+ this->PreLoadCMakeFiles();
+
+ if (noconfigure) {
+ return 0;
+ }
+
+ // now run the global generate
+ // Check the state of the build system to see if we need to regenerate.
+ if (!this->CheckBuildSystem()) {
+ return 0;
+ }
+
+ int ret = this->Configure();
+ if (ret || this->GetWorkingMode() != NORMAL_MODE) {
+#if defined(CMAKE_HAVE_VS_GENERATORS)
+ if (!this->VSSolutionFile.empty() && this->GlobalGenerator) {
+ // CMake is running to regenerate a Visual Studio build tree
+ // during a build from the VS IDE. The build files cannot be
+ // regenerated, so we should stop the build.
+ cmSystemTools::Message("CMake Configure step failed. "
+ "Build files cannot be regenerated correctly. "
+ "Attempting to stop IDE build.");
+ cmGlobalVisualStudioGenerator* gg =
+ static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
+ gg->CallVisualStudioMacro(cmGlobalVisualStudioGenerator::MacroStop,
+ this->VSSolutionFile.c_str());
+ }
+#endif
+ return ret;
+ }
+ ret = this->Generate();
+ std::string message = "Build files have been written to: ";
+ message += this->GetHomeOutputDirectory();
+ this->UpdateProgress(message.c_str(), -1);
+ return ret;
+}
+
+int cmake::Generate()
+{
+ if (!this->GlobalGenerator) {
+ return -1;
+ }
+ if (!this->GlobalGenerator->Compute()) {
+ return -1;
+ }
+ this->GlobalGenerator->Generate();
+ if (!this->GraphVizFile.empty()) {
+ std::cout << "Generate graphviz: " << this->GraphVizFile << std::endl;
+ this->GenerateGraphViz(this->GraphVizFile.c_str());
+ }
+ if (this->WarnUnusedCli) {
+ this->RunCheckForUnusedVariables();
+ }
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return -1;
+ }
+ // Save the cache again after a successful Generate so that any internal
+ // variables created during Generate are saved. (Specifically target GUIDs
+ // for the Visual Studio and Xcode generators.)
+ if (this->GetWorkingMode() == NORMAL_MODE) {
+ this->SaveCache(this->GetHomeOutputDirectory());
+ }
+ return 0;
+}
+
+void cmake::AddCacheEntry(const std::string& key, const char* value,
+ const char* helpString, int type)
+{
+ this->State->AddCacheEntry(key, value, helpString,
+ cmState::CacheEntryType(type));
+ this->UnwatchUnusedCli(key);
+}
+
+const char* cmake::GetCacheDefinition(const std::string& name) const
+{
+ return this->State->GetInitializedCacheValue(name);
+}
+
+void cmake::AddDefaultCommands()
+{
+ std::vector<cmCommand*> commands;
+ GetBootstrapCommands1(commands);
+ GetBootstrapCommands2(commands);
+ GetPredefinedCommands(commands);
+ for (std::vector<cmCommand*>::iterator i = commands.begin();
+ i != commands.end(); ++i) {
+ this->State->AddCommand(*i);
+ }
+}
+
+void cmake::AddDefaultGenerators()
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#if !defined(CMAKE_BOOT_MINGW)
+ this->Generators.push_back(cmGlobalVisualStudio14Generator::NewFactory());
+ this->Generators.push_back(cmGlobalVisualStudio12Generator::NewFactory());
+ this->Generators.push_back(cmGlobalVisualStudio11Generator::NewFactory());
+ this->Generators.push_back(cmGlobalVisualStudio10Generator::NewFactory());
+ this->Generators.push_back(cmGlobalVisualStudio9Generator::NewFactory());
+ this->Generators.push_back(cmGlobalVisualStudio8Generator::NewFactory());
+ this->Generators.push_back(cmGlobalVisualStudio71Generator::NewFactory());
+ 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)
+ this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory());
+#endif
+#if defined(CMAKE_USE_WMAKE)
+ this->Generators.push_back(cmGlobalWatcomWMakeGenerator::NewFactory());
+#endif
+#ifdef CMAKE_USE_XCODE
+ this->Generators.push_back(cmGlobalXCodeGenerator::NewFactory());
+#endif
+}
+
+bool cmake::ParseCacheEntry(const std::string& entry, std::string& var,
+ std::string& value, cmState::CacheEntryType& type)
+{
+ return cmState::ParseCacheEntry(entry, var, value, type);
+}
+
+int cmake::LoadCache()
+{
+ // could we not read the cache
+ if (!this->LoadCache(this->GetHomeOutputDirectory())) {
+ // if it does exist, but isn't readable then warn the user
+ std::string cacheFile = this->GetHomeOutputDirectory();
+ cacheFile += "/CMakeCache.txt";
+ if (cmSystemTools::FileExists(cacheFile.c_str())) {
+ cmSystemTools::Error(
+ "There is a CMakeCache.txt file for the current binary tree but "
+ "cmake does not have permission to read it. Please check the "
+ "permissions of the directory you are trying to run CMake on.");
+ return -1;
+ }
+ }
+
+ // setup CMAKE_ROOT and CMAKE_COMMAND
+ if (!this->AddCMakePaths()) {
+ return -3;
+ }
+ return 0;
+}
+
+bool cmake::LoadCache(const std::string& path)
+{
+ std::set<std::string> emptySet;
+ return this->LoadCache(path, true, emptySet, emptySet);
+}
+
+bool cmake::LoadCache(const std::string& path, bool internal,
+ std::set<std::string>& excludes,
+ 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 = cmArrayBegin(entries);
+ nameIt != cmArrayEnd(entries); ++nameIt) {
+ this->UnwatchUnusedCli(*nameIt);
+ }
+ return result;
+}
+
+bool cmake::SaveCache(const std::string& path)
+{
+ bool result = this->State->SaveCache(path);
+ static const char* entries[] = { "CMAKE_CACHE_MAJOR_VERSION",
+ "CMAKE_CACHE_MINOR_VERSION",
+ "CMAKE_CACHE_PATCH_VERSION",
+ "CMAKE_CACHEFILE_DIR" };
+ for (const char* const* nameIt = cmArrayBegin(entries);
+ nameIt != cmArrayEnd(entries); ++nameIt) {
+ this->UnwatchUnusedCli(*nameIt);
+ }
+ return result;
+}
+
+bool cmake::DeleteCache(const std::string& path)
+{
+ return this->State->DeleteCache(path);
+}
+
+void cmake::SetProgressCallback(ProgressCallbackType f, void* cd)
+{
+ this->ProgressCallback = f;
+ this->ProgressCallbackClientData = cd;
+}
+
+void cmake::UpdateProgress(const char* msg, float prog)
+{
+ if (this->ProgressCallback && !this->State->GetIsInTryCompile()) {
+ (*this->ProgressCallback)(msg, prog, this->ProgressCallbackClientData);
+ return;
+ }
+}
+
+bool cmake::GetIsInTryCompile() const
+{
+ return this->State->GetIsInTryCompile();
+}
+
+void cmake::SetIsInTryCompile(bool b)
+{
+ this->State->SetIsInTryCompile(b);
+}
+
+void cmake::GetGeneratorDocumentation(std::vector<cmDocumentationEntry>& v)
+{
+ for (RegisteredGeneratorsVector::const_iterator i = this->Generators.begin();
+ i != this->Generators.end(); ++i) {
+ cmDocumentationEntry e;
+ (*i)->GetDocumentation(e);
+ v.push_back(e);
+ }
+ for (RegisteredExtraGeneratorsMap::const_iterator i =
+ this->ExtraGenerators.begin();
+ i != this->ExtraGenerators.end(); ++i) {
+ cmDocumentationEntry e;
+ cmExternalMakefileProjectGenerator* generator = (i->second)();
+ generator->GetDocumentation(e, i->first);
+ e.Name = i->first;
+ delete generator;
+ v.push_back(e);
+ }
+}
+
+void cmake::PrintGeneratorList()
+{
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ cmDocumentation doc;
+ std::vector<cmDocumentationEntry> generators;
+ this->GetGeneratorDocumentation(generators);
+ doc.AppendSection("Generators", generators);
+ std::cerr << "\n";
+ doc.PrintDocumentation(cmDocumentation::ListGenerators, std::cerr);
+#endif
+}
+
+void cmake::UpdateConversionPathTable()
+{
+ // Update the path conversion table with any specified file:
+ const char* tablepath =
+ this->State->GetInitializedCacheValue("CMAKE_PATH_TRANSLATION_FILE");
+
+ if (tablepath) {
+ cmsys::ifstream table(tablepath);
+ if (!table) {
+ 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;
+ while (!table.eof()) {
+ // two entries per line
+ table >> a;
+ table >> b;
+ cmSystemTools::AddTranslationPath(a, b);
+ }
+ }
+ }
+}
+
+int cmake::CheckBuildSystem()
+{
+ // We do not need to rerun CMake. Check dependency integrity. Use
+ // the make system's VERBOSE environment variable to enable verbose
+ // output. This can be skipped by setting CMAKE_NO_VERBOSE (which is set
+ // by the Eclipse and KDevelop generators).
+ bool verbose = ((cmSystemTools::GetEnv("VERBOSE") != CM_NULLPTR) &&
+ (cmSystemTools::GetEnv("CMAKE_NO_VERBOSE") == CM_NULLPTR));
+
+ // This method will check the integrity of the build system if the
+ // option was given on the command line. It reads the given file to
+ // determine whether CMake should rerun.
+
+ // If no file is provided for the check, we have to rerun.
+ if (this->CheckBuildSystemArgument.empty()) {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Re-run cmake no build system arguments\n";
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ return 1;
+ }
+
+ // If the file provided does not exist, we have to rerun.
+ if (!cmSystemTools::FileExists(this->CheckBuildSystemArgument.c_str())) {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Re-run cmake missing file: " << this->CheckBuildSystemArgument
+ << "\n";
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ return 1;
+ }
+
+ // Read the rerun check file and use it to decide whether to do the
+ // global generate.
+ cmake cm;
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator gg(&cm);
+ CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(&gg, cm.GetCurrentSnapshot()));
+ if (!mf->ReadListFile(this->CheckBuildSystemArgument.c_str()) ||
+ cmSystemTools::GetErrorOccuredFlag()) {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Re-run cmake error reading : " << this->CheckBuildSystemArgument
+ << "\n";
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ // There was an error reading the file. Just rerun.
+ return 1;
+ }
+
+ if (this->ClearBuildSystem) {
+ // Get the generator used for this build system.
+ const char* genName = mf->GetDefinition("CMAKE_DEPENDS_GENERATOR");
+ if (!genName || genName[0] == '\0') {
+ genName = "Unix Makefiles";
+ }
+
+ // Create the generator and use it to clear the dependencies.
+ CM_AUTO_PTR<cmGlobalGenerator> ggd(this->CreateGlobalGenerator(genName));
+ if (ggd.get()) {
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ CM_AUTO_PTR<cmMakefile> mfd(
+ new cmMakefile(ggd.get(), cm.GetCurrentSnapshot()));
+ CM_AUTO_PTR<cmLocalGenerator> lgd(ggd->CreateLocalGenerator(mfd.get()));
+ lgd->ClearDependencies(mfd.get(), verbose);
+ }
+ }
+
+ // If any byproduct of makefile generation is missing we must re-run.
+ std::vector<std::string> products;
+ if (const char* productStr = mf->GetDefinition("CMAKE_MAKEFILE_PRODUCTS")) {
+ cmSystemTools::ExpandListArgument(productStr, products);
+ }
+ for (std::vector<std::string>::const_iterator pi = products.begin();
+ pi != products.end(); ++pi) {
+ if (!(cmSystemTools::FileExists(pi->c_str()) ||
+ cmSystemTools::FileIsSymlink(*pi))) {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Re-run cmake, missing byproduct: " << *pi << "\n";
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ return 1;
+ }
+ }
+
+ // Get the set of dependencies and outputs.
+ std::vector<std::string> depends;
+ std::vector<std::string> outputs;
+ const char* dependsStr = mf->GetDefinition("CMAKE_MAKEFILE_DEPENDS");
+ const char* outputsStr = mf->GetDefinition("CMAKE_MAKEFILE_OUTPUTS");
+ if (dependsStr && outputsStr) {
+ cmSystemTools::ExpandListArgument(dependsStr, depends);
+ cmSystemTools::ExpandListArgument(outputsStr, outputs);
+ }
+ if (depends.empty() || outputs.empty()) {
+ // Not enough information was provided to do the test. Just rerun.
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Re-run cmake no CMAKE_MAKEFILE_DEPENDS "
+ "or CMAKE_MAKEFILE_OUTPUTS :\n";
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ return 1;
+ }
+
+ // Find the newest dependency.
+ std::vector<std::string>::iterator dep = depends.begin();
+ std::string dep_newest = *dep++;
+ for (; dep != depends.end(); ++dep) {
+ int result = 0;
+ if (this->FileComparison->FileTimeCompare(dep_newest.c_str(), dep->c_str(),
+ &result)) {
+ if (result < 0) {
+ dep_newest = *dep;
+ }
+ } else {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Re-run cmake: build system dependency is missing\n";
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ return 1;
+ }
+ }
+
+ // Find the oldest output.
+ std::vector<std::string>::iterator out = outputs.begin();
+ std::string out_oldest = *out++;
+ for (; out != outputs.end(); ++out) {
+ int result = 0;
+ if (this->FileComparison->FileTimeCompare(out_oldest.c_str(), out->c_str(),
+ &result)) {
+ if (result > 0) {
+ out_oldest = *out;
+ }
+ } else {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Re-run cmake: build system output is missing\n";
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ return 1;
+ }
+ }
+
+ // If any output is older than any dependency then rerun.
+ {
+ int result = 0;
+ if (!this->FileComparison->FileTimeCompare(out_oldest.c_str(),
+ dep_newest.c_str(), &result) ||
+ result < 0) {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Re-run cmake file: " << out_oldest
+ << " older than: " << dep_newest << "\n";
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ return 1;
+ }
+ }
+
+ // No need to rerun.
+ return 0;
+}
+
+void cmake::TruncateOutputLog(const char* fname)
+{
+ std::string fullPath = this->GetHomeOutputDirectory();
+ fullPath += "/";
+ fullPath += fname;
+ struct stat st;
+ if (::stat(fullPath.c_str(), &st)) {
+ return;
+ }
+ if (!this->State->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR")) {
+ cmSystemTools::RemoveFile(fullPath);
+ return;
+ }
+ off_t fsize = st.st_size;
+ const off_t maxFileSize = 50 * 1024;
+ if (fsize < maxFileSize) {
+ // TODO: truncate file
+ return;
+ }
+}
+
+inline std::string removeQuotes(const std::string& s)
+{
+ if (s[0] == '\"' && s[s.size() - 1] == '\"') {
+ return s.substr(1, s.size() - 2);
+ }
+ return s;
+}
+
+void cmake::MarkCliAsUsed(const std::string& variable)
+{
+ this->UsedCliVariables[variable] = true;
+}
+
+void cmake::GenerateGraphViz(const char* fileName) const
+{
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ CM_AUTO_PTR<cmGraphVizWriter> gvWriter(
+ new cmGraphVizWriter(this->GetGlobalGenerator()->GetLocalGenerators()));
+
+ std::string settingsFile = this->GetHomeOutputDirectory();
+ settingsFile += "/CMakeGraphVizOptions.cmake";
+ std::string fallbackSettingsFile = this->GetHomeDirectory();
+ fallbackSettingsFile += "/CMakeGraphVizOptions.cmake";
+
+ gvWriter->ReadSettings(settingsFile.c_str(), fallbackSettingsFile.c_str());
+
+ gvWriter->WritePerTargetFiles(fileName);
+ gvWriter->WriteTargetDependersFiles(fileName);
+ gvWriter->WriteGlobalFile(fileName);
+
+#endif
+}
+
+void cmake::SetProperty(const std::string& prop, const char* value)
+{
+ this->State->SetGlobalProperty(prop, value);
+}
+
+void cmake::AppendProperty(const std::string& prop, const char* value,
+ bool asString)
+{
+ this->State->AppendGlobalProperty(prop, value, asString);
+}
+
+const char* cmake::GetProperty(const std::string& prop)
+{
+ return this->State->GetGlobalProperty(prop);
+}
+
+bool cmake::GetPropertyAsBool(const std::string& prop)
+{
+ return this->State->GetGlobalPropertyAsBool(prop);
+}
+
+cmInstalledFile* cmake::GetOrCreateInstalledFile(cmMakefile* mf,
+ const std::string& name)
+{
+ std::map<std::string, cmInstalledFile>::iterator i =
+ this->InstalledFiles.find(name);
+
+ if (i != this->InstalledFiles.end()) {
+ cmInstalledFile& file = i->second;
+ return &file;
+ } else {
+ cmInstalledFile& file = this->InstalledFiles[name];
+ file.SetName(mf, name);
+ return &file;
+ }
+}
+
+cmInstalledFile const* cmake::GetInstalledFile(const std::string& name) const
+{
+ std::map<std::string, cmInstalledFile>::const_iterator i =
+ this->InstalledFiles.find(name);
+
+ if (i != this->InstalledFiles.end()) {
+ cmInstalledFile const& file = i->second;
+ return &file;
+ } else {
+ return CM_NULLPTR;
+ }
+}
+
+int cmake::GetSystemInformation(std::vector<std::string>& args)
+{
+ // so create the directory
+ std::string resultFile;
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ std::string destPath = cwd + "/__cmake_systeminformation";
+ cmSystemTools::RemoveADirectory(destPath);
+ if (!cmSystemTools::MakeDirectory(destPath.c_str())) {
+ std::cerr << "Error: --system-information must be run from a "
+ "writable directory!\n";
+ return 1;
+ }
+
+ // process the arguments
+ bool writeToStdout = true;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ std::string arg = args[i];
+ if (arg.find("-G", 0) == 0) {
+ std::string value = arg.substr(2);
+ if (value.empty()) {
+ ++i;
+ if (i >= args.size()) {
+ cmSystemTools::Error("No generator specified for -G");
+ this->PrintGeneratorList();
+ return -1;
+ }
+ value = args[i];
+ }
+ cmGlobalGenerator* gen = this->CreateGlobalGenerator(value);
+ if (!gen) {
+ cmSystemTools::Error("Could not create named generator ",
+ value.c_str());
+ this->PrintGeneratorList();
+ } else {
+ this->SetGlobalGenerator(gen);
+ }
+ }
+ // no option assume it is the output file
+ else {
+ if (!cmSystemTools::FileIsFullPath(arg.c_str())) {
+ resultFile = cwd;
+ resultFile += "/";
+ }
+ resultFile += arg;
+ writeToStdout = false;
+ }
+ }
+
+ // we have to find the module directory, so we can copy the files
+ this->AddCMakePaths();
+ std::string modulesPath = cmSystemTools::GetCMakeRoot();
+ modulesPath += "/Modules";
+ std::string inFile = modulesPath;
+ inFile += "/SystemInformation.cmake";
+ std::string outFile = destPath;
+ outFile += "/CMakeLists.txt";
+
+ // Copy file
+ if (!cmSystemTools::cmCopyFile(inFile.c_str(), outFile.c_str())) {
+ std::cerr << "Error copying file \"" << inFile << "\" to \"" << outFile
+ << "\".\n";
+ return 1;
+ }
+
+ // do we write to a file or to stdout?
+ if (resultFile.empty()) {
+ resultFile = cwd;
+ resultFile += "/__cmake_systeminformation/results.txt";
+ }
+
+ // now run cmake on the CMakeLists file
+ cmSystemTools::ChangeDirectory(destPath);
+ std::vector<std::string> args2;
+ args2.push_back(args[0]);
+ args2.push_back(destPath);
+ std::string resultArg = "-DRESULT_FILE=";
+ resultArg += resultFile;
+ args2.push_back(resultArg);
+ int res = this->Run(args2, false);
+
+ if (res != 0) {
+ std::cerr << "Error: --system-information failed on internal CMake!\n";
+ return res;
+ }
+
+ // change back to the original directory
+ cmSystemTools::ChangeDirectory(cwd);
+
+ // echo results to stdout if needed
+ if (writeToStdout) {
+ FILE* fin = cmsys::SystemTools::Fopen(resultFile, "r");
+ if (fin) {
+ const int bufferSize = 4096;
+ char buffer[bufferSize];
+ size_t n;
+ while ((n = fread(buffer, 1, bufferSize, fin)) > 0) {
+ for (char* c = buffer; c < buffer + n; ++c) {
+ putc(*c, stdout);
+ }
+ fflush(stdout);
+ }
+ fclose(fin);
+ }
+ }
+
+ // clean up the directory
+ cmSystemTools::RemoveADirectory(destPath);
+ return 0;
+}
+
+static bool cmakeCheckStampFile(const char* stampName)
+{
+ // The stamp file does not exist. Use the stamp dependencies to
+ // determine whether it is really out of date. This works in
+ // conjunction with cmLocalVisualStudio7Generator to avoid
+ // repeatedly re-running CMake when the user rebuilds the entire
+ // solution.
+ std::string stampDepends = stampName;
+ stampDepends += ".depend";
+#if defined(_WIN32) || defined(__CYGWIN__)
+ cmsys::ifstream fin(stampDepends.c_str(), std::ios::in | std::ios::binary);
+#else
+ cmsys::ifstream fin(stampDepends.c_str());
+#endif
+ if (!fin) {
+ // The stamp dependencies file cannot be read. Just assume the
+ // build system is really out of date.
+ std::cout << "CMake is re-running because " << stampName
+ << " dependency file is missing.\n";
+ return false;
+ }
+
+ // 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.c_str(), dep.c_str(), &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;
+ }
+ }
+
+ // The build system is up to date. The stamp file has been removed
+ // by the VS IDE due to a "rebuild" request. Restore it atomically.
+ std::ostringstream stampTempStream;
+ stampTempStream << stampName << ".tmp" << cmSystemTools::RandomSeed();
+ std::string stampTempString = stampTempStream.str();
+ const char* stampTemp = stampTempString.c_str();
+ {
+ // TODO: Teach cmGeneratedFileStream to use a random temp file (with
+ // multiple tries in unlikely case of conflict) and use that here.
+ cmsys::ofstream stamp(stampTemp);
+ stamp << "# CMake generation timestamp file for this directory.\n";
+ }
+ if (cmSystemTools::RenameFile(stampTemp, stampName)) {
+ // 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";
+ return true;
+ } else {
+ cmSystemTools::RemoveFile(stampTemp);
+ cmSystemTools::Error("Cannot restore timestamp ", stampName);
+ return false;
+ }
+}
+
+static bool cmakeCheckStampList(const char* stampList)
+{
+ // If the stamp list does not exist CMake must rerun to generate it.
+ if (!cmSystemTools::FileExists(stampList)) {
+ std::cout << "CMake is re-running because generate.stamp.list "
+ << "is missing.\n";
+ return false;
+ }
+ cmsys::ifstream fin(stampList);
+ if (!fin) {
+ std::cout << "CMake is re-running because generate.stamp.list "
+ << "could not be read.\n";
+ return false;
+ }
+
+ // Check each stamp.
+ std::string stampName;
+ while (cmSystemTools::GetLineFromStream(fin, stampName)) {
+ if (!cmakeCheckStampFile(stampName.c_str())) {
+ return false;
+ }
+ }
+ return true;
+}
+
+cmake::MessageType cmake::ConvertMessageType(cmake::MessageType t) const
+{
+ bool warningsAsErrors;
+
+ if (t == cmake::AUTHOR_WARNING || t == cmake::AUTHOR_ERROR) {
+ warningsAsErrors = this->GetDevWarningsAsErrors();
+ if (warningsAsErrors && t == cmake::AUTHOR_WARNING) {
+ t = cmake::AUTHOR_ERROR;
+ } else if (!warningsAsErrors && t == cmake::AUTHOR_ERROR) {
+ t = cmake::AUTHOR_WARNING;
+ }
+ } else if (t == cmake::DEPRECATION_WARNING ||
+ t == cmake::DEPRECATION_ERROR) {
+ warningsAsErrors = this->GetDeprecatedWarningsAsErrors();
+ if (warningsAsErrors && t == cmake::DEPRECATION_WARNING) {
+ t = cmake::DEPRECATION_ERROR;
+ } else if (!warningsAsErrors && t == cmake::DEPRECATION_ERROR) {
+ t = cmake::DEPRECATION_WARNING;
+ }
+ }
+
+ return t;
+}
+
+bool cmake::IsMessageTypeVisible(cmake::MessageType t) const
+{
+ bool isVisible = true;
+
+ if (t == cmake::DEPRECATION_ERROR) {
+ if (!this->GetDeprecatedWarningsAsErrors()) {
+ isVisible = false;
+ }
+ } else if (t == cmake::DEPRECATION_WARNING) {
+ if (this->GetSuppressDeprecatedWarnings()) {
+ isVisible = false;
+ }
+ } else if (t == cmake::AUTHOR_ERROR) {
+ if (!this->GetDevWarningsAsErrors()) {
+ isVisible = false;
+ }
+ } else if (t == cmake::AUTHOR_WARNING) {
+ if (this->GetSuppressDevWarnings()) {
+ isVisible = false;
+ }
+ }
+
+ return isVisible;
+}
+
+static bool printMessagePreamble(cmake::MessageType t, std::ostream& msg)
+{
+ // Construct the message header.
+ if (t == cmake::FATAL_ERROR) {
+ msg << "CMake Error";
+ } else if (t == cmake::INTERNAL_ERROR) {
+ msg << "CMake Internal Error (please report a bug)";
+ } else if (t == cmake::LOG) {
+ msg << "CMake Debug Log";
+ } else if (t == cmake::DEPRECATION_ERROR) {
+ msg << "CMake Deprecation Error";
+ } else if (t == cmake::DEPRECATION_WARNING) {
+ msg << "CMake Deprecation Warning";
+ } else if (t == cmake::AUTHOR_WARNING) {
+ msg << "CMake Warning (dev)";
+ } else if (t == cmake::AUTHOR_ERROR) {
+ msg << "CMake Error (dev)";
+ } else {
+ msg << "CMake Warning";
+ }
+ return true;
+}
+
+void printMessageText(std::ostream& msg, std::string const& text)
+{
+ msg << ":\n";
+ cmDocumentationFormatter formatter;
+ formatter.SetIndent(" ");
+ formatter.PrintFormatted(msg, text.c_str());
+}
+
+void displayMessage(cmake::MessageType t, std::ostringstream& msg)
+{
+
+ // Add a note about warning suppression.
+ if (t == cmake::AUTHOR_WARNING) {
+ msg << "This warning is for project developers. Use -Wno-dev to suppress "
+ "it.";
+ } else if (t == cmake::AUTHOR_ERROR) {
+ msg << "This error is for project developers. Use -Wno-error=dev to "
+ "suppress "
+ "it.";
+ }
+
+ // Add a terminating blank line.
+ msg << "\n";
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ // Add a C++ stack trace to internal errors.
+ if (t == cmake::INTERNAL_ERROR) {
+ std::string stack = cmsys::SystemInformation::GetProgramStack(0, 0);
+ if (!stack.empty()) {
+ if (cmHasLiteralPrefix(stack, "WARNING:")) {
+ stack = "Note:" + stack.substr(8);
+ }
+ msg << stack << "\n";
+ }
+ }
+#endif
+
+ // Output the message.
+ if (t == cmake::FATAL_ERROR || t == cmake::INTERNAL_ERROR ||
+ t == cmake::DEPRECATION_ERROR || t == cmake::AUTHOR_ERROR) {
+ cmSystemTools::SetErrorOccured();
+ cmSystemTools::Message(msg.str().c_str(), "Error");
+ } else {
+ cmSystemTools::Message(msg.str().c_str(), "Warning");
+ }
+}
+
+void cmake::IssueMessage(cmake::MessageType t, std::string const& text,
+ cmListFileBacktrace const& backtrace) const
+{
+ bool force = false;
+ // override the message type, if needed, for warnings and errors
+ cmake::MessageType override = this->ConvertMessageType(t);
+ if (override != t) {
+ t = override;
+ force = true;
+ }
+
+ if (!force && !this->IsMessageTypeVisible(t)) {
+ return;
+ }
+
+ this->DisplayMessage(t, text, backtrace);
+}
+
+void cmake::DisplayMessage(cmake::MessageType t, std::string const& text,
+ cmListFileBacktrace const& backtrace) const
+{
+ std::ostringstream msg;
+ if (!printMessagePreamble(t, msg)) {
+ return;
+ }
+
+ // Add the immediate context.
+ backtrace.PrintTitle(msg);
+
+ printMessageText(msg, text);
+
+ // Add the rest of the context.
+ backtrace.PrintCallStack(msg);
+
+ displayMessage(t, msg);
+}
+
+std::vector<std::string> cmake::GetDebugConfigs()
+{
+ std::vector<std::string> configs;
+ if (const char* config_list =
+ this->State->GetGlobalProperty("DEBUG_CONFIGURATIONS")) {
+ // Expand the specified list and convert to upper-case.
+ cmSystemTools::ExpandListArgument(config_list, configs);
+ std::transform(configs.begin(), configs.end(), configs.begin(),
+ cmSystemTools::UpperCase);
+ }
+ // If no configurations were specified, use a default list.
+ if (configs.empty()) {
+ configs.push_back("DEBUG");
+ }
+ return configs;
+}
+
+int cmake::Build(const std::string& dir, const std::string& target,
+ const std::string& config,
+ const std::vector<std::string>& nativeOptions, bool clean)
+{
+
+ this->SetHomeDirectory("");
+ this->SetHomeOutputDirectory("");
+ if (!cmSystemTools::FileIsDirectory(dir)) {
+ std::cerr << "Error: " << dir << " is not a directory\n";
+ return 1;
+ }
+ std::string cachePath = dir;
+ cmSystemTools::ConvertToUnixSlashes(cachePath);
+ std::string cacheFile = cachePath;
+ cacheFile += "/CMakeCache.txt";
+ if (!cmSystemTools::FileExists(cacheFile.c_str())) {
+ // search in parent directories for cache
+ std::string cmakeFiles = cachePath;
+ cmakeFiles += "/CMakeFiles";
+ if (cmSystemTools::FileExists(cmakeFiles.c_str())) {
+ std::string cachePathFound =
+ cmSystemTools::FileExistsInParentDirectories("CMakeCache.txt",
+ cachePath.c_str(), "/");
+ if (!cachePathFound.empty()) {
+ cachePath = cmSystemTools::GetFilenamePath(cachePathFound);
+ }
+ }
+ }
+
+ if (!this->LoadCache(cachePath)) {
+ std::cerr << "Error: could not load cache\n";
+ return 1;
+ }
+ const char* cachedGenerator =
+ this->State->GetCacheEntryValue("CMAKE_GENERATOR");
+ if (!cachedGenerator) {
+ std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n";
+ return 1;
+ }
+ CM_AUTO_PTR<cmGlobalGenerator> gen(
+ this->CreateGlobalGenerator(cachedGenerator));
+ if (!gen.get()) {
+ std::cerr << "Error: could create CMAKE_GENERATOR \"" << cachedGenerator
+ << "\"\n";
+ return 1;
+ }
+ std::string output;
+ std::string projName;
+ const char* cachedProjectName =
+ this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME");
+ if (!cachedProjectName) {
+ std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n";
+ return 1;
+ }
+ projName = cachedProjectName;
+ bool verbose = false;
+ const char* cachedVerbose =
+ this->State->GetCacheEntryValue("CMAKE_VERBOSE_MAKEFILE");
+ if (cachedVerbose) {
+ verbose = cmSystemTools::IsOn(cachedVerbose);
+ }
+ return gen->Build("", dir, projName, target, output, "", config, clean,
+ false, verbose, 0, cmSystemTools::OUTPUT_PASSTHROUGH,
+ nativeOptions);
+}
+
+void cmake::WatchUnusedCli(const std::string& var)
+{
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ this->VariableWatch->AddWatch(var, cmWarnUnusedCliWarning, this);
+ if (this->UsedCliVariables.find(var) == this->UsedCliVariables.end()) {
+ this->UsedCliVariables[var] = false;
+ }
+#endif
+}
+
+void cmake::UnwatchUnusedCli(const std::string& var)
+{
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ this->VariableWatch->RemoveWatch(var, cmWarnUnusedCliWarning);
+ this->UsedCliVariables.erase(var);
+#endif
+}
+
+void cmake::RunCheckForUnusedVariables()
+{
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ bool haveUnused = false;
+ std::ostringstream msg;
+ msg << "Manually-specified variables were not used by the project:";
+ for (std::map<std::string, bool>::const_iterator it =
+ this->UsedCliVariables.begin();
+ it != this->UsedCliVariables.end(); ++it) {
+ if (!it->second) {
+ haveUnused = true;
+ msg << "\n " << it->first;
+ }
+ }
+ if (haveUnused) {
+ this->IssueMessage(cmake::WARNING, msg.str());
+ }
+#endif
+}
+
+bool cmake::GetSuppressDevWarnings() const
+{
+ const char* cacheEntryValue =
+ this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_WARNINGS");
+ return cmSystemTools::IsOn(cacheEntryValue);
+}
+
+void cmake::SetSuppressDevWarnings(bool b)
+{
+ std::string value;
+
+ // equivalent to -Wno-dev
+ if (b) {
+ value = "TRUE";
+ }
+ // equivalent to -Wdev
+ else {
+ value = "FALSE";
+ }
+
+ this->AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", value.c_str(),
+ "Suppress Warnings that are meant for"
+ " the author of the CMakeLists.txt files.",
+ cmState::INTERNAL);
+}
+
+bool cmake::GetSuppressDeprecatedWarnings() const
+{
+ const char* cacheEntryValue =
+ this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED");
+ return cacheEntryValue && cmSystemTools::IsOff(cacheEntryValue);
+}
+
+void cmake::SetSuppressDeprecatedWarnings(bool b)
+{
+ std::string value;
+
+ // equivalent to -Wno-deprecated
+ if (b) {
+ value = "FALSE";
+ }
+ // equivalent to -Wdeprecated
+ else {
+ value = "TRUE";
+ }
+
+ this->AddCacheEntry("CMAKE_WARN_DEPRECATED", value.c_str(),
+ "Whether to issue warnings for deprecated "
+ "functionality.",
+ cmState::INTERNAL);
+}
+
+bool cmake::GetDevWarningsAsErrors() const
+{
+ const char* cacheEntryValue =
+ this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_ERRORS");
+ return cacheEntryValue && cmSystemTools::IsOff(cacheEntryValue);
+}
+
+void cmake::SetDevWarningsAsErrors(bool b)
+{
+ std::string value;
+
+ // equivalent to -Werror=dev
+ if (b) {
+ value = "FALSE";
+ }
+ // equivalent to -Wno-error=dev
+ else {
+ value = "TRUE";
+ }
+
+ this->AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_ERRORS", value.c_str(),
+ "Suppress errors that are meant for"
+ " the author of the CMakeLists.txt files.",
+ cmState::INTERNAL);
+}
+
+bool cmake::GetDeprecatedWarningsAsErrors() const
+{
+ const char* cacheEntryValue =
+ this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED");
+ return cmSystemTools::IsOn(cacheEntryValue);
+}
+
+void cmake::SetDeprecatedWarningsAsErrors(bool b)
+{
+ std::string value;
+
+ // equivalent to -Werror=deprecated
+ if (b) {
+ value = "TRUE";
+ }
+ // equivalent to -Wno-error=deprecated
+ else {
+ value = "FALSE";
+ }
+
+ this->AddCacheEntry("CMAKE_ERROR_DEPRECATED", value.c_str(),
+ "Whether to issue deprecation errors for macros"
+ " and functions.",
+ cmState::INTERNAL);
+}
diff --git a/Source/cmake.h b/Source/cmake.h
new file mode 100644
index 0000000..4a5376d
--- /dev/null
+++ b/Source/cmake.h
@@ -0,0 +1,600 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmake_h
+#define cmake_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmCacheManager.h"
+#include "cmInstalledFile.h"
+#include "cmListFileCache.h"
+#include "cmState.h"
+#include "cmSystemTools.h"
+
+class cmGlobalGeneratorFactory;
+class cmGlobalGenerator;
+class cmLocalGenerator;
+class cmMakefile;
+class cmVariableWatch;
+class cmFileTimeComparison;
+class cmExternalMakefileProjectGenerator;
+class cmDocumentationSection;
+class cmTarget;
+class cmGeneratedFileStream;
+
+/** \brief Represents a cmake invocation.
+ *
+ * This class represents a cmake invocation. It is the top level class when
+ * running cmake. Most cmake based GUIs should primarily create an instance
+ * of this class and communicate with it.
+ *
+ * The basic process for a GUI is as follows:
+ *
+ * -# Create a cmake instance
+ * -# Set the Home directories, generator, and cmake command. this
+ * can be done using the Set methods or by using SetArgs and passing in
+ * command line arguments.
+ * -# Load the cache by calling LoadCache (duh)
+ * -# if you are using command line arguments with -D or -C flags then
+ * call SetCacheArgs (or if for some other reason you want to modify the
+ * cache), do it now.
+ * -# Finally call Configure
+ * -# Let the user change values and go back to step 5
+ * -# call Generate
+
+ * If your GUI allows the user to change the home directories then
+ * you must at a minimum redo steps 2 through 7.
+ */
+
+class cmake
+{
+public:
+ enum MessageType
+ {
+ AUTHOR_WARNING,
+ AUTHOR_ERROR,
+ FATAL_ERROR,
+ INTERNAL_ERROR,
+ MESSAGE,
+ WARNING,
+ LOG,
+ DEPRECATION_ERROR,
+ DEPRECATION_WARNING
+ };
+
+ enum DiagLevel
+ {
+ DIAG_IGNORE,
+ DIAG_WARN,
+ DIAG_ERROR
+ };
+
+ /** \brief Describes the working modes of cmake */
+ enum WorkingMode
+ {
+ NORMAL_MODE, ///< Cmake runs to create project files
+ /** \brief Script mode (started by using -P).
+ *
+ * In script mode there is no generator and no cache. Also,
+ * languages are not enabled, so add_executable and things do
+ * nothing.
+ */
+ SCRIPT_MODE,
+ /** \brief A pkg-config like mode
+ *
+ * In this mode cmake just searches for a package and prints the results to
+ * stdout. This is similar to SCRIPT_MODE, but commands like add_library()
+ * work too, since they may be used e.g. in exported target files. Started
+ * via --find-package.
+ */
+ FIND_PACKAGE_MODE
+ };
+
+ struct GeneratorInfo
+ {
+ std::string name;
+ bool supportsToolset;
+ };
+
+ typedef std::map<std::string, cmInstalledFile> InstalledFilesMap;
+
+ /// Default constructor
+ cmake();
+ /// Destructor
+ ~cmake();
+
+ static const char* GetCMakeFilesDirectory() { return "/CMakeFiles"; }
+ static const char* GetCMakeFilesDirectoryPostSlash()
+ {
+ return "CMakeFiles/";
+ }
+
+ //@{
+ /**
+ * Set/Get the home directory (or output directory) in the project. The
+ * home directory is the top directory of the project. It is the
+ * path-to-source cmake was run with.
+ */
+ void SetHomeDirectory(const std::string& dir);
+ const char* GetHomeDirectory() const;
+ void SetHomeOutputDirectory(const std::string& dir);
+ const char* GetHomeOutputDirectory() const;
+ //@}
+
+ /**
+ * Handle a command line invocation of cmake.
+ */
+ int Run(const std::vector<std::string>& args)
+ {
+ return this->Run(args, false);
+ }
+ int Run(const std::vector<std::string>& args, bool noconfigure);
+
+ /**
+ * Run the global generator Generate step.
+ */
+ int Generate();
+
+ /**
+ * Configure the cmMakefiles. This routine will create a GlobalGenerator if
+ * one has not already been set. It will then Call Configure on the
+ * GlobalGenerator. This in turn will read in an process all the CMakeList
+ * files for the tree. It will not produce any actual Makefiles, or
+ * workspaces. Generate does that. */
+ int Configure();
+ int ActualConfigure();
+
+ ///! 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,
+ cmState::CacheEntryType& type);
+
+ int LoadCache();
+ bool LoadCache(const std::string& path);
+ bool LoadCache(const std::string& path, bool internal,
+ std::set<std::string>& excludes,
+ std::set<std::string>& includes);
+ bool SaveCache(const std::string& path);
+ bool DeleteCache(const std::string& path);
+ void PreLoadCMakeFiles();
+
+ ///! Create a GlobalGenerator
+ cmGlobalGenerator* CreateGlobalGenerator(const std::string& name);
+
+ ///! 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
+ const cmGlobalGenerator* GetGlobalGenerator() const
+ {
+ return this->GlobalGenerator;
+ }
+
+ ///! Return the global generator assigned to this instance of cmake
+ void SetGlobalGenerator(cmGlobalGenerator*);
+
+ ///! Get the names of the current registered generators
+ void GetRegisteredGenerators(std::vector<GeneratorInfo>& generators);
+
+ ///! Set the name of the selected generator-specific platform.
+ void SetGeneratorPlatform(std::string const& ts)
+ {
+ this->GeneratorPlatform = ts;
+ }
+
+ ///! Get the name of the selected generator-specific platform.
+ std::string const& GetGeneratorPlatform() const
+ {
+ return this->GeneratorPlatform;
+ }
+
+ ///! Set the name of the selected generator-specific toolset.
+ void SetGeneratorToolset(std::string const& ts)
+ {
+ this->GeneratorToolset = ts;
+ }
+
+ ///! Get the name of the selected generator-specific toolset.
+ std::string const& GetGeneratorToolset() const
+ {
+ return this->GeneratorToolset;
+ }
+
+ const std::vector<std::string>& GetSourceExtensions() const
+ {
+ return this->SourceFileExtensions;
+ }
+ const std::vector<std::string>& GetHeaderExtensions() const
+ {
+ return this->HeaderFileExtensions;
+ }
+
+ /**
+ * Given a variable name, return its value (as a string).
+ */
+ const char* GetCacheDefinition(const std::string&) const;
+ ///! Add an entry into the cache
+ void AddCacheEntry(const std::string& key, const char* value,
+ const char* helpString, int type);
+
+ /**
+ * Get the system information and write it to the file specified
+ */
+ int GetSystemInformation(std::vector<std::string>&);
+
+ ///! Parse command line arguments
+ void SetArgs(const std::vector<std::string>&,
+ bool directoriesSetBefore = false);
+
+ ///! 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
+ bool SetCacheArgs(const std::vector<std::string>&);
+
+ typedef void (*ProgressCallbackType)(const char* msg, float progress, void*);
+ /**
+ * Set the function used by GUIs to receive progress updates
+ * Function gets passed: message as a const char*, a progress
+ * amount ranging from 0 to 1.0 and client data. The progress
+ * number provided may be negative in cases where a message is
+ * to be displayed without any progress percentage.
+ */
+ void SetProgressCallback(ProgressCallbackType f,
+ void* clientData = CM_NULLPTR);
+
+ ///! this is called by generators to update the progress
+ void UpdateProgress(const char* msg, float prog);
+
+ ///! Get the variable watch object
+ cmVariableWatch* GetVariableWatch() { return this->VariableWatch; }
+
+ void GetGeneratorDocumentation(std::vector<cmDocumentationEntry>&);
+
+ ///! 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
+ cmInstalledFile* GetOrCreateInstalledFile(cmMakefile* mf,
+ const std::string& name);
+
+ cmInstalledFile const* GetInstalledFile(const std::string& name) const;
+
+ InstalledFilesMap const& GetInstalledFiles() const
+ {
+ return this->InstalledFiles;
+ }
+
+ ///! 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
+ bool GetDebugTryCompile() { return this->DebugTryCompile; }
+ void DebugTryCompileOn() { this->DebugTryCompile = true; }
+
+ /**
+ * Generate CMAKE_ROOT and CMAKE_COMMAND cache entries
+ */
+ int AddCMakePaths();
+
+ /**
+ * Get the file comparison class
+ */
+ cmFileTimeComparison* GetFileComparison() { return this->FileComparison; }
+
+ // Do we want debug output during the cmake run.
+ bool GetDebugOutput() { return this->DebugOutput; }
+ void SetDebugOutputOn(bool b) { this->DebugOutput = b; }
+
+ // Do we want trace output during the cmake run.
+ bool GetTrace() { return this->Trace; }
+ void SetTrace(bool b) { this->Trace = b; }
+ bool GetTraceExpand() { return this->TraceExpand; }
+ void SetTraceExpand(bool b) { this->TraceExpand = b; }
+ void AddTraceSource(std::string const& file)
+ {
+ this->TraceOnlyThisSources.push_back(file);
+ }
+ std::vector<std::string> const& GetTraceSources() const
+ {
+ return this->TraceOnlyThisSources;
+ }
+ bool GetWarnUninitialized() { return this->WarnUninitialized; }
+ void SetWarnUninitialized(bool b) { this->WarnUninitialized = b; }
+ bool GetWarnUnused() { return this->WarnUnused; }
+ void SetWarnUnused(bool b) { this->WarnUnused = b; }
+ bool GetWarnUnusedCli() { return this->WarnUnusedCli; }
+ void SetWarnUnusedCli(bool b) { this->WarnUnusedCli = b; }
+ bool GetCheckSystemVars() { return this->CheckSystemVars; }
+ void SetCheckSystemVars(bool b) { this->CheckSystemVars = b; }
+
+ void MarkCliAsUsed(const std::string& variable);
+
+ /** Get the list of configurations (in upper case) considered to be
+ debugging configurations.*/
+ std::vector<std::string> GetDebugConfigs();
+
+ void SetCMakeEditCommand(std::string const& s)
+ {
+ this->CMakeEditCommand = s;
+ }
+ std::string const& GetCMakeEditCommand() const
+ {
+ return this->CMakeEditCommand;
+ }
+
+ /*
+ * Get the state of the suppression of developer (author) warnings.
+ * Returns false, by default, if developer warnings should be shown, true
+ * otherwise.
+ */
+ bool GetSuppressDevWarnings() const;
+ /*
+ * Set the state of the suppression of developer (author) warnings.
+ */
+ void SetSuppressDevWarnings(bool v);
+
+ /*
+ * Get the state of the suppression of deprecated warnings.
+ * Returns false, by default, if deprecated warnings should be shown, true
+ * otherwise.
+ */
+ bool GetSuppressDeprecatedWarnings() const;
+ /*
+ * Set the state of the suppression of deprecated warnings.
+ */
+ void SetSuppressDeprecatedWarnings(bool v);
+
+ /*
+ * Get the state of treating developer (author) warnings as errors.
+ * Returns false, by default, if warnings should not be treated as errors,
+ * true otherwise.
+ */
+ bool GetDevWarningsAsErrors() const;
+ /**
+ * Set the state of treating developer (author) warnings as errors.
+ */
+ void SetDevWarningsAsErrors(bool v);
+
+ /*
+ * Get the state of treating deprecated warnings as errors.
+ * Returns false, by default, if warnings should not be treated as errors,
+ * true otherwise.
+ */
+ bool GetDeprecatedWarningsAsErrors() const;
+ /**
+ * Set the state of treating developer (author) warnings as errors.
+ */
+ void SetDeprecatedWarningsAsErrors(bool v);
+
+ /** Display a message to the user. */
+ void IssueMessage(
+ cmake::MessageType t, std::string const& text,
+ cmListFileBacktrace const& backtrace = cmListFileBacktrace()) const;
+
+ void DisplayMessage(cmake::MessageType t, std::string const& text,
+ cmListFileBacktrace const& backtrace) const;
+
+ ///! run the --build option
+ int Build(const std::string& dir, const std::string& target,
+ const std::string& config,
+ const std::vector<std::string>& nativeOptions, bool clean);
+
+ void UnwatchUnusedCli(const std::string& var);
+ void WatchUnusedCli(const std::string& var);
+
+ cmState* GetState() const { return this->State; }
+ void SetCurrentSnapshot(cmState::Snapshot snapshot)
+ {
+ this->CurrentSnapshot = snapshot;
+ }
+ cmState::Snapshot GetCurrentSnapshot() const
+ {
+ return this->CurrentSnapshot;
+ }
+
+protected:
+ void RunCheckForUnusedVariables();
+ void InitializeProperties();
+ int HandleDeleteCacheVariables(const std::string& var);
+
+ typedef cmExternalMakefileProjectGenerator* (
+ *CreateExtraGeneratorFunctionType)();
+ typedef std::map<std::string, CreateExtraGeneratorFunctionType>
+ RegisteredExtraGeneratorsMap;
+ typedef std::vector<cmGlobalGeneratorFactory*> RegisteredGeneratorsVector;
+ RegisteredGeneratorsVector Generators;
+ RegisteredExtraGeneratorsMap ExtraGenerators;
+ void AddDefaultCommands();
+ void AddDefaultGenerators();
+ void AddDefaultExtraGenerators();
+ void AddExtraGenerator(const std::string& name,
+ CreateExtraGeneratorFunctionType newFunction);
+
+ cmGlobalGenerator* GlobalGenerator;
+ std::map<std::string, DiagLevel> DiagLevels;
+ std::string GeneratorPlatform;
+ std::string GeneratorToolset;
+
+ ///! read in a cmake list file to initialize the cache
+ void ReadListFile(const std::vector<std::string>& args, const char* path);
+ bool FindPackage(const std::vector<std::string>& args);
+
+ ///! 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);
+
+ /**
+ * Method called to check build system integrity at build time.
+ * Returns 1 if CMake should rerun and 0 otherwise.
+ */
+ int CheckBuildSystem();
+
+ void SetDirectoriesFromFile(const char* arg);
+
+ //! Make sure all commands are what they say they are and there is no
+ /// macros.
+ void CleanupCommandsAndMacros();
+
+ void GenerateGraphViz(const char* fileName) const;
+
+ cmVariableWatch* VariableWatch;
+
+private:
+ cmake(const cmake&); // Not implemented.
+ void operator=(const cmake&); // Not implemented.
+ ProgressCallbackType ProgressCallback;
+ void* ProgressCallbackClientData;
+ bool InTryCompile;
+ WorkingMode CurrentWorkingMode;
+ bool DebugOutput;
+ bool Trace;
+ bool TraceExpand;
+ bool WarnUninitialized;
+ bool WarnUnused;
+ bool WarnUnusedCli;
+ bool CheckSystemVars;
+ std::map<std::string, bool> UsedCliVariables;
+ std::string CMakeEditCommand;
+ std::string CXXEnvironment;
+ std::string CCEnvironment;
+ std::string CheckBuildSystemArgument;
+ std::string CheckStampFile;
+ std::string CheckStampList;
+ std::string VSSolutionFile;
+ std::vector<std::string> SourceFileExtensions;
+ std::vector<std::string> HeaderFileExtensions;
+ bool ClearBuildSystem;
+ bool DebugTryCompile;
+ cmFileTimeComparison* FileComparison;
+ std::string GraphVizFile;
+ InstalledFilesMap InstalledFiles;
+
+ cmState* State;
+ cmState::Snapshot CurrentSnapshot;
+
+ std::vector<std::string> TraceOnlyThisSources;
+
+ void UpdateConversionPathTable();
+
+ // Print a list of valid generators to stderr.
+ void PrintGeneratorList();
+
+ /**
+ * Convert a message type between a warning and an error, based on the state
+ * of the error output CMake variables, in the cache.
+ */
+ cmake::MessageType ConvertMessageType(cmake::MessageType t) const;
+
+ /*
+ * Check if messages of this type should be output, based on the state of the
+ * warning and error output CMake variables, in the cache.
+ */
+ bool IsMessageTypeVisible(cmake::MessageType t) const;
+};
+
+#define CMAKE_STANDARD_OPTIONS_TABLE \
+ { "-C <initial-cache>", "Pre-load a script to populate the cache." }, \
+ { "-D <var>[:<type>]=<value>", "Create a cmake cache entry." }, \
+ { "-U <globbing_expr>", "Remove matching entries from CMake cache." }, \
+ { "-G <generator-name>", "Specify a build system generator." }, \
+ { "-T <toolset-name>", \
+ "Specify toolset name if supported by generator." }, \
+ { "-A <platform-name>", \
+ "Specify platform name if supported by generator." }, \
+ { "-Wdev", "Enable developer warnings." }, \
+ { "-Wno-dev", "Suppress developer warnings." }, \
+ { "-Werror=dev", "Make developer warnings errors." }, \
+ { "-Wno-error=dev", "Make developer warnings not errors." }, \
+ { "-Wdeprecated", "Enable deprecation warnings." }, \
+ { "-Wno-deprecated", "Suppress deprecation warnings." }, \
+ { "-Werror=deprecated", "Make deprecated macro and function warnings " \
+ "errors." }, \
+ { \
+ "-Wno-error=deprecated", "Make deprecated macro and function warnings " \
+ "not errors." \
+ }
+
+#define FOR_EACH_C_FEATURE(F) \
+ F(c_function_prototypes) \
+ F(c_restrict) \
+ F(c_static_assert) \
+ F(c_variadic_macros)
+
+#define FOR_EACH_CXX_FEATURE(F) \
+ F(cxx_aggregate_default_initializers) \
+ 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) \
+ F(cxx_extern_templates) \
+ 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) \
+ F(cxx_nonstatic_member_init) \
+ F(cxx_nullptr) \
+ F(cxx_override) \
+ 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)
+
+#endif
diff --git a/Source/cmake.version.manifest b/Source/cmake.version.manifest
new file mode 100644
index 0000000..e7010c9
--- /dev/null
+++ b/Source/cmake.version.manifest
@@ -0,0 +1,18 @@
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+ manifestVersion="1.0"
+ xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!-- Windows Vista -->
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+ <!-- Windows 7 -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ <!-- Windows 8 -->
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+ <!-- Windows 8.1 -->
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+ <!-- Windows 10 -->
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+ </application>
+ </compatibility>
+</assembly>
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
new file mode 100644
index 0000000..521a5bf
--- /dev/null
+++ b/Source/cmakemain.cxx
@@ -0,0 +1,399 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+// include these first, otherwise there will be problems on Windows
+// with GetCurrentDirectory() being redefined
+#ifdef CMAKE_BUILD_WITH_CMAKE
+#include "cmDocumentation.h"
+#include "cmDynamicLoader.h"
+#endif
+
+#include "cmAlgorithms.h"
+#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmake.h"
+#include "cmcmd.h"
+#include <cmsys/Encoding.hxx>
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+static const char* cmDocumentationName[][2] = {
+ { CM_NULLPTR, " cmake - Cross-Platform Makefile Generator." },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+static const char* cmDocumentationUsage[][2] = {
+ { CM_NULLPTR, " cmake [options] <path-to-source>\n"
+ " cmake [options] <path-to-existing-build>" },
+ { CM_NULLPTR,
+ "Specify a source directory to (re-)generate a build system for "
+ "it in the current working directory. Specify an existing build "
+ "directory to re-generate its build system." },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+static const char* cmDocumentationUsageNote[][2] = {
+ { CM_NULLPTR, "Run 'cmake --help' for more information." },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+#define CMAKE_BUILD_OPTIONS \
+ " <dir> = Project binary directory to be built.\n" \
+ " --target <tgt> = Build <tgt> instead of default targets.\n" \
+ " May only be specified once.\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" \
+ " -- = Pass remaining options to the native tool.\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." },
+ { "-N", "View mode only." },
+ { "-P <file>", "Process script mode." },
+ { "--find-package", "Run in pkg-config like mode." },
+ { "--graphviz=[file]", "Generate graphviz of dependencies, see "
+ "CMakeGraphVizOptions.cmake for more." },
+ { "--system-information [file]", "Dump information about this system." },
+ { "--debug-trycompile", "Do not delete the try_compile build tree. Only "
+ "useful on one try_compile at a time." },
+ { "--debug-output", "Put cmake in a debug mode." },
+ { "--trace", "Put cmake in trace mode." },
+ { "--trace-expand", "Put cmake in trace mode with variable expansion." },
+ { "--trace-source=<file>",
+ "Trace only this CMake file/module. Multiple options allowed." },
+ { "--warn-uninitialized", "Warn about uninitialized values." },
+ { "--warn-unused-vars", "Warn about unused variables." },
+ { "--no-warn-unused-cli", "Don't warn about command line options." },
+ { "--check-system-vars", "Find problems with variable usage in system "
+ "files." },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+#endif
+
+static int do_command(int ac, char const* const* av)
+{
+ std::vector<std::string> args;
+ args.reserve(ac - 1);
+ args.push_back(av[0]);
+ args.insert(args.end(), 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 cmMakefile* cmakemainGetMakefile(void* clientdata)
+{
+ cmake* cm = (cmake*)clientdata;
+ if (cm && cm->GetDebugOutput()) {
+ cmGlobalGenerator* gg = cm->GetGlobalGenerator();
+ if (gg) {
+ return gg->GetCurrentMakefile();
+ }
+ }
+ return CM_NULLPTR;
+}
+
+static std::string cmakemainGetStack(void* clientdata)
+{
+ std::string msg;
+ cmMakefile* mf = cmakemainGetMakefile(clientdata);
+ if (mf) {
+ msg = mf->FormatListFileStack();
+ if (!msg.empty()) {
+ msg = "\n Called from: " + msg;
+ }
+ }
+
+ return msg;
+}
+
+static void cmakemainMessageCallback(const char* m, const char*, bool&,
+ void* clientdata)
+{
+ std::cerr << m << cmakemainGetStack(clientdata) << std::endl << std::flush;
+}
+
+static void cmakemainProgressCallback(const char* m, float prog,
+ void* clientdata)
+{
+ cmMakefile* mf = cmakemainGetMakefile(clientdata);
+ std::string dir;
+ if ((mf) && (strstr(m, "Configuring") == m) && (prog < 0)) {
+ dir = " ";
+ dir += mf->GetCurrentSourceDirectory();
+ } else if ((mf) && (strstr(m, "Generating") == m)) {
+ dir = " ";
+ dir += mf->GetCurrentBinaryDirectory();
+ }
+
+ if ((prog < 0) || (!dir.empty())) {
+ std::cout << "-- " << m << dir << cmakemainGetStack(clientdata)
+ << std::endl;
+ }
+
+ std::cout.flush();
+}
+
+int main(int ac, char const* const* av)
+{
+ cmsys::Encoding::CommandLineArguments args =
+ cmsys::Encoding::CommandLineArguments::Main(ac, av);
+ ac = args.argc();
+ av = args.argv();
+
+ cmSystemTools::EnableMSVCDebugHook();
+ cmSystemTools::FindCMakeResources(av[0]);
+ if (ac > 1) {
+ if (strcmp(av[1], "--build") == 0) {
+ return do_build(ac, av);
+ } else if (strcmp(av[1], "-E") == 0) {
+ return do_command(ac, av);
+ }
+ }
+ int ret = do_cmake(ac, av);
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ cmDynamicLoader::FlushCache();
+#endif
+ return ret;
+}
+
+int do_cmake(int ac, char const* const* av)
+{
+ if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
+ std::cerr << "Current working directory cannot be established."
+ << std::endl;
+ return 1;
+ }
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ cmDocumentation doc;
+ doc.addCMakeStandardDocSections();
+ if (doc.CheckOptions(ac, av)) {
+ // Construct and print requested documentation.
+ cmake hcm;
+ hcm.SetHomeDirectory("");
+ hcm.SetHomeOutputDirectory("");
+ hcm.AddCMakePaths();
+
+ // the command line args are processed here so that you can do
+ // -DCMAKE_MODULE_PATH=/some/path and have this value accessible here
+ std::vector<std::string> args(av, av + ac);
+ hcm.SetCacheArgs(args);
+
+ std::vector<cmDocumentationEntry> generators;
+
+ hcm.GetGeneratorDocumentation(generators);
+
+ doc.SetName("cmake");
+ doc.SetSection("Name", cmDocumentationName);
+ doc.SetSection("Usage", cmDocumentationUsage);
+ if (ac == 1) {
+ doc.AppendSection("Usage", cmDocumentationUsageNote);
+ }
+ doc.AppendSection("Generators", generators);
+ doc.PrependSection("Options", cmDocumentationOptions);
+
+ return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
+ }
+#else
+ if (ac == 1) {
+ std::cout
+ << "Bootstrap CMake should not be used outside CMake build process."
+ << std::endl;
+ return 0;
+ }
+#endif
+
+ bool sysinfo = false;
+ bool list_cached = false;
+ bool list_all_cached = false;
+ bool list_help = false;
+ bool view_only = false;
+ cmake::WorkingMode workingMode = cmake::NORMAL_MODE;
+ std::vector<std::string> args;
+ for (int i = 0; i < ac; ++i) {
+ if (strcmp(av[i], "-i") == 0) {
+ /* clang-format off */
+ std::cerr <<
+ "The \"cmake -i\" wizard mode is no longer supported.\n"
+ "Use the -D option to set cache values on the command line.\n"
+ "Use cmake-gui or ccmake for an interactive dialog.\n";
+ /* clang-format on */
+ return 1;
+ } else if (strcmp(av[i], "--system-information") == 0) {
+ sysinfo = true;
+ } else if (strcmp(av[i], "-N") == 0) {
+ view_only = true;
+ } else if (strcmp(av[i], "-L") == 0) {
+ list_cached = true;
+ } else if (strcmp(av[i], "-LA") == 0) {
+ list_all_cached = true;
+ } else if (strcmp(av[i], "-LH") == 0) {
+ list_cached = true;
+ list_help = true;
+ } else if (strcmp(av[i], "-LAH") == 0) {
+ list_all_cached = true;
+ list_help = true;
+ } else if (cmHasLiteralPrefix(av[i], "-P")) {
+ if (i == ac - 1) {
+ cmSystemTools::Error("No script specified for argument -P");
+ } else {
+ workingMode = cmake::SCRIPT_MODE;
+ args.push_back(av[i]);
+ i++;
+ args.push_back(av[i]);
+ }
+ } else if (cmHasLiteralPrefix(av[i], "--find-package")) {
+ workingMode = cmake::FIND_PACKAGE_MODE;
+ args.push_back(av[i]);
+ } else {
+ args.push_back(av[i]);
+ }
+ }
+ if (sysinfo) {
+ cmake cm;
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ int ret = cm.GetSystemInformation(args);
+ return ret;
+ }
+ cmake cm;
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cmSystemTools::SetMessageCallback(cmakemainMessageCallback, (void*)&cm);
+ cm.SetProgressCallback(cmakemainProgressCallback, (void*)&cm);
+ cm.SetWorkingMode(workingMode);
+
+ int res = cm.Run(args, view_only);
+ if (list_cached || list_all_cached) {
+ std::cout << "-- Cache values" << std::endl;
+ std::vector<std::string> keys = cm.GetState()->GetCacheEntryKeys();
+ for (std::vector<std::string>::const_iterator it = keys.begin();
+ it != keys.end(); ++it) {
+ cmState::CacheEntryType t = cm.GetState()->GetCacheEntryType(*it);
+ if (t != cmState::INTERNAL && t != cmState::STATIC &&
+ t != cmState::UNINITIALIZED) {
+ const char* advancedProp =
+ cm.GetState()->GetCacheEntryProperty(*it, "ADVANCED");
+ if (list_all_cached || !advancedProp) {
+ if (list_help) {
+ std::cout << "// "
+ << cm.GetState()->GetCacheEntryProperty(*it,
+ "HELPSTRING")
+ << std::endl;
+ }
+ std::cout << *it << ":" << cmState::CacheEntryTypeToString(t) << "="
+ << cm.GetState()->GetCacheEntryValue(*it) << std::endl;
+ if (list_help) {
+ std::cout << std::endl;
+ }
+ }
+ }
+ }
+ }
+
+ // Always return a non-negative value. Windows tools do not always
+ // interpret negative return values as errors.
+ if (res != 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int do_build(int ac, char const* const* av)
+{
+#ifndef CMAKE_BUILD_WITH_CMAKE
+ std::cerr << "This cmake does not support --build\n";
+ return -1;
+#else
+ std::string target;
+ std::string config = "Debug";
+ std::string dir;
+ std::vector<std::string> nativeOptions;
+ bool clean = false;
+ bool hasTarget = false;
+
+ enum Doing
+ {
+ DoingNone,
+ DoingDir,
+ DoingTarget,
+ DoingConfig,
+ DoingNative
+ };
+ Doing doing = DoingDir;
+ for (int i = 2; i < ac; ++i) {
+ if (doing == DoingNative) {
+ nativeOptions.push_back(av[i]);
+ } 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 = "";
+ break;
+ }
+ } else if (strcmp(av[i], "--config") == 0) {
+ doing = DoingConfig;
+ } else if (strcmp(av[i], "--clean-first") == 0) {
+ clean = true;
+ doing = DoingNone;
+ } else if (strcmp(av[i], "--use-stderr") == 0) {
+ /* tolerate legacy option */
+ } else if (strcmp(av[i], "--") == 0) {
+ doing = DoingNative;
+ } else {
+ switch (doing) {
+ case DoingDir:
+ dir = cmSystemTools::CollapseFullPath(av[i]);
+ doing = DoingNone;
+ break;
+ case DoingTarget:
+ target = av[i];
+ doing = DoingNone;
+ break;
+ case DoingConfig:
+ config = av[i];
+ doing = DoingNone;
+ break;
+ default:
+ std::cerr << "Unknown argument " << av[i] << std::endl;
+ dir = "";
+ break;
+ }
+ }
+ }
+ if (dir.empty()) {
+ /* clang-format off */
+ std::cerr <<
+ "Usage: cmake --build <dir> [options] [-- [native-options]]\n"
+ "Options:\n"
+ CMAKE_BUILD_OPTIONS
+ ;
+ /* clang-format on */
+ return 1;
+ }
+
+ cmake cm;
+ return cm.Build(dir, target, config, nativeOptions, clean);
+#endif
+}
diff --git a/Source/cmakexbuild.cxx b/Source/cmakexbuild.cxx
new file mode 100644
index 0000000..bdbc4da
--- /dev/null
+++ b/Source/cmakexbuild.cxx
@@ -0,0 +1,80 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmStandardIncludes.h"
+
+#include "cmSystemTools.h"
+#include <cmsys/Process.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, 100.0, out, err);
+ while (pipe != cmsysProcess_Pipe_None) {
+ if (line.find("/bin/sh: bad interpreter: Text file busy") != line.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") == line.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, 100, out, err);
+ }
+ cmsysProcess_WaitForExit(cp, 0);
+ 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(0);
+ 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
new file mode 100644
index 0000000..44f71f1
--- /dev/null
+++ b/Source/cmcldeps.cxx
@@ -0,0 +1,310 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Wrapper around cl that adds /showIncludes to command line, and uses that to
+// generate .d files that match the style from gcc -MD.
+//
+// /showIncludes is equivalent to -MD, not -MMD, that is, system headers are
+// included.
+
+#include <cmSystemTools.h>
+#include <cmsys/Encoding.hxx>
+
+#include <sstream>
+#include <windows.h>
+
+// We don't want any wildcard expansion.
+// See http://msdn.microsoft.com/en-us/library/zay8tzh6(v=vs.85).aspx
+void _setargv()
+{
+}
+
+static void Fatal(const char* msg, ...)
+{
+ va_list ap;
+ fprintf(stderr, "ninja: FATAL: ");
+ va_start(ap, msg);
+ vfprintf(stderr, msg, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ // On Windows, some tools may inject extra threads.
+ // exit() may block on locks held by those threads, so forcibly exit.
+ fflush(stderr);
+ fflush(stdout);
+ ExitProcess(1);
+}
+
+static void usage(const char* msg)
+{
+ Fatal("%s\n\nusage:\n "
+ "cmcldeps "
+ "<language C, CXX or RC> "
+ "<source file path> "
+ "<output path for *.d file> "
+ "<output path for *.obj file> "
+ "<prefix of /showIncludes> "
+ "<path to cl.exe> "
+ "<path to tool (cl or rc)> "
+ "<rest of command ...>\n",
+ msg);
+}
+
+static std::string trimLeadingSpace(const std::string& cmdline)
+{
+ int i = 0;
+ for (; cmdline[i] == ' '; ++i)
+ ;
+ return cmdline.substr(i);
+}
+
+static void replaceAll(std::string& str, const std::string& search,
+ const std::string& repl)
+{
+ std::string::size_type pos = 0;
+ while ((pos = str.find(search, pos)) != std::string::npos) {
+ str.replace(pos, search.size(), repl);
+ pos += repl.size();
+ }
+}
+
+bool startsWith(const std::string& str, const std::string& what)
+{
+ return str.compare(0, what.size(), what) == 0;
+}
+
+// Strips one argument from the cmdline and returns it. "surrounding quotes"
+// are removed from the argument if there were any.
+static std::string getArg(std::string& cmdline)
+{
+ std::string ret;
+ bool in_quoted = false;
+ unsigned int i = 0;
+
+ cmdline = trimLeadingSpace(cmdline);
+
+ for (;; ++i) {
+ if (i >= cmdline.size())
+ usage("Couldn't parse arguments.");
+ if (!in_quoted && cmdline[i] == ' ')
+ break; // "a b" "x y"
+ if (cmdline[i] == '"')
+ in_quoted = !in_quoted;
+ }
+
+ ret = cmdline.substr(0, i);
+ if (ret[0] == '"' && ret[i - 1] == '"')
+ ret = ret.substr(1, ret.size() - 2);
+ cmdline = cmdline.substr(i);
+ return ret;
+}
+
+static void parseCommandLine(LPWSTR wincmdline, std::string& lang,
+ std::string& srcfile, std::string& dfile,
+ std::string& objfile, std::string& prefix,
+ std::string& clpath, std::string& binpath,
+ std::string& rest)
+{
+ std::string cmdline = cmsys::Encoding::ToNarrow(wincmdline);
+ /* self */ getArg(cmdline);
+ lang = getArg(cmdline);
+ srcfile = getArg(cmdline);
+ dfile = getArg(cmdline);
+ objfile = getArg(cmdline);
+ prefix = getArg(cmdline);
+ clpath = getArg(cmdline);
+ binpath = getArg(cmdline);
+ rest = trimLeadingSpace(cmdline);
+}
+
+// Not all backslashes need to be escaped in a depfile, but it's easier that
+// way. See the re2c grammar in ninja's source code for more info.
+static void escapePath(std::string& path)
+{
+ replaceAll(path, "\\", "\\\\");
+ replaceAll(path, " ", "\\ ");
+}
+
+static void outputDepFile(const std::string& dfile, const std::string& objfile,
+ std::vector<std::string>& incs)
+{
+
+ if (dfile.empty())
+ return;
+
+ // strip duplicates
+ std::sort(incs.begin(), incs.end());
+ incs.erase(std::unique(incs.begin(), incs.end()), incs.end());
+
+ FILE* out = cmsys::SystemTools::Fopen(dfile.c_str(), "wb");
+
+ // FIXME should this be fatal or not? delete obj? delete d?
+ if (!out)
+ return;
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ replaceAll(cwd, "/", "\\");
+ cwd += "\\";
+
+ std::string tmp = objfile;
+ escapePath(tmp);
+ fprintf(out, "%s: \\\n", tmp.c_str());
+
+ std::vector<std::string>::iterator it = incs.begin();
+ for (; it != incs.end(); ++it) {
+ tmp = *it;
+ // The paths need to match the ones used to identify build artifacts in the
+ // build.ninja file. Therefore we need to canonicalize the path to use
+ // backward slashes and relativize the path to the build directory.
+ replaceAll(tmp, "/", "\\");
+ if (startsWith(tmp, cwd))
+ tmp = tmp.substr(cwd.size());
+ escapePath(tmp);
+ fprintf(out, "%s \\\n", tmp.c_str());
+ }
+
+ fprintf(out, "\n");
+ fclose(out);
+}
+
+bool contains(const std::string& str, const std::string& what)
+{
+ return str.find(what) != std::string::npos;
+}
+
+std::string replace(const std::string& str, const std::string& what,
+ const std::string& replacement)
+{
+ size_t pos = str.find(what);
+ if (pos == std::string::npos)
+ return str;
+ std::string replaced = str;
+ return replaced.replace(pos, what.size(), replacement);
+}
+
+static int process(const std::string& srcfilename, const std::string& dfile,
+ const std::string& objfile, const std::string& prefix,
+ const std::string& cmd, const std::string& dir = "",
+ bool quiet = false)
+{
+ std::string output;
+ // break up command line into a vector
+ std::vector<std::string> args;
+ cmSystemTools::ParseWindowsCommandLine(cmd.c_str(), args);
+ // convert to correct vector type for RunSingleCommand
+ std::vector<std::string> command;
+ for (std::vector<std::string>::iterator i = args.begin(); i != args.end();
+ ++i) {
+ command.push_back(i->c_str());
+ }
+ // run the command
+ int exit_code = 0;
+ bool run =
+ cmSystemTools::RunSingleCommand(command, &output, &output, &exit_code,
+ dir.c_str(), cmSystemTools::OUTPUT_NONE);
+
+ // process the include directives and output everything else
+ std::istringstream ss(output);
+ std::string line;
+ std::vector<std::string> includes;
+ bool isFirstLine = true; // cl prints always first the source filename
+ while (std::getline(ss, line)) {
+ if (startsWith(line, prefix)) {
+ std::string inc = trimLeadingSpace(line.substr(prefix.size()).c_str());
+ if (inc[inc.size() - 1] == '\r') // blech, stupid \r\n
+ inc = inc.substr(0, inc.size() - 1);
+ includes.push_back(inc);
+ } else {
+ if (!isFirstLine || !startsWith(line, srcfilename)) {
+ if (!quiet || exit_code != 0) {
+ fprintf(stdout, "%s\n", line.c_str());
+ }
+ } else {
+ isFirstLine = false;
+ }
+ }
+ }
+
+ // don't update .d until/unless we succeed compilation
+ if (run && exit_code == 0)
+ outputDepFile(dfile, objfile, includes);
+
+ return exit_code;
+}
+
+int main()
+{
+
+ // Use the Win32 API instead of argc/argv so we can avoid interpreting the
+ // rest of command line after the .d and .obj. Custom parsing seemed
+ // preferable to the ugliness you get into in trying to re-escape quotes for
+ // subprocesses, so by avoiding argc/argv, the subprocess is called with
+ // the same command line verbatim.
+
+ std::string lang, srcfile, dfile, objfile, prefix, cl, binpath, rest;
+ parseCommandLine(GetCommandLineW(), lang, srcfile, dfile, objfile, prefix,
+ cl, binpath, rest);
+
+ // needed to suppress filename output of msvc tools
+ std::string srcfilename;
+ {
+ std::string::size_type pos = srcfile.rfind("\\");
+ if (pos == std::string::npos) {
+ srcfilename = srcfile;
+ } else {
+ srcfilename = srcfile.substr(pos + 1);
+ }
+ }
+
+ std::string nol = " /nologo ";
+ std::string show = " /showIncludes ";
+ if (lang == "C" || lang == "CXX") {
+ return process(srcfilename, dfile, objfile, prefix,
+ binpath + nol + show + rest);
+ } else if (lang == "RC") {
+ // "misuse" cl.exe to get headers from .rc files
+
+ 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, objfile, objfile + ".dep.obj ");
+
+ // rc: src\x\x.rc -> cl: /Tc src\x\x.rc
+ if (srcfile.find(" ") != std::string::npos)
+ srcfile = "\"" + srcfile + "\"";
+ clrest = replace(clrest, srcfile, "/Tc " + srcfile);
+
+ cl = "\"" + cl + "\" /P /DRC_INVOKED ";
+
+ // call cl in object dir so the .i is generated there
+ std::string objdir;
+ {
+ std::string::size_type pos = objfile.rfind("\\");
+ if (pos != std::string::npos) {
+ objdir = objfile.substr(0, pos);
+ }
+ }
+
+ // extract dependencies with cl.exe
+ int exit_code = process(srcfilename, dfile, objfile, prefix,
+ cl + nol + show + clrest, objdir, true);
+
+ if (exit_code != 0)
+ return exit_code;
+
+ // compile rc file with rc.exe
+ return process(srcfilename, "", objfile, prefix, binpath + " " + rest);
+ }
+
+ usage("Invalid language specified.");
+ return 1;
+}
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
new file mode 100644
index 0000000..010a3b2
--- /dev/null
+++ b/Source/cmcmd.cxx
@@ -0,0 +1,1539 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmcmd.h"
+
+#include "cmAlgorithms.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmQtAutoGenerators.h"
+#include "cmVersion.h"
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback.
+#endif
+
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Process.h>
+#include <cmsys/Terminal.h>
+
+#if defined(CMAKE_HAVE_VS_GENERATORS)
+#include "cmCallVisualStudioMacro.h"
+#include "cmVisualStudioWCEPlatformParser.h"
+#endif
+
+#include <time.h>
+
+#include <stdlib.h> // required for atoi
+#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
+#include "bindexplib.h"
+#endif
+
+void CMakeCommandUsage(const char* program)
+{
+ std::ostringstream errorStream;
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ /* clang-format off */
+ errorStream
+ << "cmake version " << cmVersion::GetCMakeVersion() << "\n";
+/* clang-format on */
+#else
+ /* clang-format off */
+ errorStream
+ << "cmake bootstrap\n";
+/* clang-format on */
+#endif
+ // If you add new commands, change here,
+ // and in cmakemain.cxx in the options table
+ /* clang-format off */
+ errorStream
+ << "Usage: " << program << " -E <command> [arguments...]\n"
+ << "Available commands: \n"
+ << " chdir dir cmd [args...] - run command in a given directory\n"
+ << " compare_files file1 file2 - check if file1 is same as file2\n"
+ << " copy <file>... destination - copy files to destination "
+ "(either file or directory)\n"
+ << " copy_directory <dir>... destination - copy content of <dir>... "
+ "directories to 'destination' directory\n"
+ << " copy_if_different <file>... destination - copy files if it has "
+ "changed\n"
+ << " echo [<string>...] - displays arguments as text\n"
+ << " echo_append [<string>...] - displays arguments as text but no new "
+ "line\n"
+ << " env [--unset=NAME]... [NAME=VALUE]... COMMAND [ARG]...\n"
+ << " - run command in a modified environment\n"
+ << " environment - display the current environment\n"
+ << " make_directory <dir>... - create parent and <dir> directories\n"
+ << " md5sum <file>... - create MD5 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"
+ << " rename oldname newname - rename a file or directory "
+ "(on one volume)\n"
+ << " tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n"
+ << " - create or extract a tar or zip archive\n"
+ << " sleep <number>... - sleep for given number of seconds\n"
+ << " time command [args...] - run command and return elapsed time\n"
+ << " touch file - touch a file.\n"
+ << " touch_nocreate file - touch a file but do not create it.\n"
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ << "Available on Windows only:\n"
+ << " delete_regv key - delete registry value\n"
+ << " env_vs8_wince sdkname - displays a batch file which sets the "
+ "environment for the provided Windows CE SDK installed in VS2005\n"
+ << " env_vs9_wince sdkname - displays a batch file which sets the "
+ "environment for the provided Windows CE SDK installed in VS2008\n"
+ << " write_regv key value - write registry value\n"
+#else
+ << "Available on UNIX only:\n"
+ << " create_symlink old new - create a symbolic link new -> old\n"
+#endif
+ ;
+ /* clang-format on */
+
+ cmSystemTools::Error(errorStream.str().c_str());
+}
+
+static bool cmTarFilesFrom(std::string const& file,
+ std::vector<std::string>& files)
+{
+ if (cmSystemTools::FileIsDirectory(file)) {
+ std::ostringstream e;
+ e << "-E tar --files-from= file '" << file << "' is a directory";
+ cmSystemTools::Error(e.str().c_str());
+ return false;
+ }
+ cmsys::ifstream fin(file.c_str());
+ if (!fin) {
+ std::ostringstream e;
+ e << "-E tar --files-from= file '" << file << "' not found";
+ cmSystemTools::Error(e.str().c_str());
+ return false;
+ }
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (line.empty()) {
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, "--add-file=")) {
+ files.push_back(line.substr(11));
+ } else if (cmHasLiteralPrefix(line, "-")) {
+ std::ostringstream e;
+ e << "-E tar --files-from='" << file << "' file invalid line:\n"
+ << line << "\n";
+ cmSystemTools::Error(e.str().c_str());
+ return false;
+ } else {
+ files.push_back(line);
+ }
+ }
+ return true;
+}
+
+int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
+{
+ // IF YOU ADD A NEW COMMAND, DOCUMENT IT ABOVE and in cmakemain.cxx
+ if (args.size() > 1) {
+ // Copy file
+ if (args[1] == "copy" && args.size() > 3) {
+ // If multiple source files specified,
+ // then destination must be directory
+ if ((args.size() > 4) &&
+ (!cmSystemTools::FileIsDirectory(args[args.size() - 1]))) {
+ std::cerr << "Error: Target (for copy command) \""
+ << args[args.size() - 1] << "\" is not a directory.\n";
+ return 1;
+ }
+ // If error occurs we want to continue copying next files.
+ bool return_value = 0;
+ for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) {
+ if (!cmSystemTools::cmCopyFile(args[cc].c_str(),
+ args[args.size() - 1].c_str())) {
+ std::cerr << "Error copying file \"" << args[cc] << "\" to \""
+ << args[args.size() - 1] << "\".\n";
+ return_value = 1;
+ }
+ }
+ return return_value;
+ }
+
+ // Copy file if different.
+ if (args[1] == "copy_if_different" && args.size() > 3) {
+ // If multiple source files specified,
+ // then destination must be directory
+ if ((args.size() > 4) &&
+ (!cmSystemTools::FileIsDirectory(args[args.size() - 1]))) {
+ std::cerr << "Error: Target (for copy_if_different command) \""
+ << args[args.size() - 1] << "\" is not a directory.\n";
+ return 1;
+ }
+ // If error occurs we want to continue copying next files.
+ bool return_value = 0;
+ for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) {
+ if (!cmSystemTools::CopyFileIfDifferent(
+ args[cc].c_str(), args[args.size() - 1].c_str())) {
+ std::cerr << "Error copying file (if different) from \"" << args[cc]
+ << "\" to \"" << args[args.size() - 1] << "\".\n";
+ return_value = 1;
+ }
+ }
+ return return_value;
+ }
+
+ // Copy directory content
+ if (args[1] == "copy_directory" && args.size() > 3) {
+ // If error occurs we want to continue copying next files.
+ bool return_value = 0;
+ for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) {
+ if (!cmSystemTools::CopyADirectory(args[cc], args[args.size() - 1])) {
+ std::cerr << "Error copying directory from \"" << args[cc]
+ << "\" to \"" << args[args.size() - 1] << "\".\n";
+ return_value = 1;
+ }
+ }
+ return return_value;
+ }
+
+ // Rename a file or directory
+ if (args[1] == "rename" && args.size() == 4) {
+ if (!cmSystemTools::RenameFile(args[2].c_str(), args[3].c_str())) {
+ std::string e = cmSystemTools::GetLastSystemError();
+ std::cerr << "Error renaming from \"" << args[2] << "\" to \""
+ << args[3] << "\": " << e << "\n";
+ return 1;
+ }
+ return 0;
+ }
+
+ // Compare files
+ if (args[1] == "compare_files" && args.size() == 4) {
+ if (cmSystemTools::FilesDiffer(args[2], args[3])) {
+ std::cerr << "Files \"" << args[2] << "\" to \"" << args[3]
+ << "\" are different.\n";
+ return 1;
+ }
+ return 0;
+ }
+
+#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
+ else if (args[1] == "__create_def") {
+ if (args.size() < 4) {
+ std::cerr
+ << "__create_def Usage: -E __create_def outfile.def objlistfile\n";
+ return 1;
+ }
+ FILE* fout = cmsys::SystemTools::Fopen(args[2].c_str(), "w+");
+ if (!fout) {
+ std::cerr << "could not open output .def file: " << args[2].c_str()
+ << "\n";
+ return 1;
+ }
+ cmsys::ifstream fin(args[3].c_str(), std::ios::in | std::ios::binary);
+ if (!fin) {
+ std::cerr << "could not open object list file: " << args[3].c_str()
+ << "\n";
+ return 1;
+ }
+ std::string objfile;
+ bindexplib deffile;
+ while (cmSystemTools::GetLineFromStream(fin, objfile)) {
+ if (!deffile.AddObjectFile(objfile.c_str())) {
+ return 1;
+ }
+ }
+ deffile.WriteFile(fout);
+ fclose(fout);
+ return 0;
+ }
+#endif
+ // run include what you use command and then run the compile
+ // command. This is an internal undocumented option and should
+ // only be used by CMake itself when running iwyu.
+ else if (args[1] == "__run_iwyu") {
+ if (args.size() < 3) {
+ std::cerr << "__run_iwyu Usage: -E __run_iwyu [--iwyu=/path/iwyu]"
+ " [--tidy=/path/tidy] -- compile command\n";
+ return 1;
+ }
+ bool doing_options = true;
+ std::vector<std::string> orig_cmd;
+ std::string iwyu;
+ std::string tidy;
+ std::string sourceFile;
+ std::string lwyu;
+ for (std::string::size_type cc = 2; cc < args.size(); cc++) {
+ std::string const& arg = args[cc];
+ if (arg == "--") {
+ doing_options = false;
+ } else if (doing_options && cmHasLiteralPrefix(arg, "--iwyu=")) {
+ iwyu = arg.substr(7);
+ } else if (doing_options && cmHasLiteralPrefix(arg, "--tidy=")) {
+ tidy = arg.substr(7);
+ } else if (doing_options && cmHasLiteralPrefix(arg, "--source=")) {
+ sourceFile = arg.substr(9);
+ } else if (doing_options && cmHasLiteralPrefix(arg, "--lwyu=")) {
+ lwyu = arg.substr(7);
+ } else if (doing_options) {
+ std::cerr << "__run_iwyu given unknown argument: " << arg << "\n";
+ return 1;
+ } else {
+ orig_cmd.push_back(arg);
+ }
+ }
+ if (tidy.empty() && iwyu.empty() && lwyu.empty()) {
+ std::cerr << "__run_iwyu missing --tidy= or --iwyu=\n";
+ return 1;
+ }
+ if (!tidy.empty() && sourceFile.empty()) {
+ std::cerr << "__run_iwyu --tidy= requires --source=\n";
+ return 1;
+ }
+ if (orig_cmd.empty() && lwyu.empty()) {
+ std::cerr << "__run_iwyu missing compile command after --\n";
+ return 1;
+ }
+
+ int ret = 0;
+
+ if (!iwyu.empty()) {
+ // Construct the iwyu command line by taking what was given
+ // and adding all the arguments we give to the compiler.
+ std::vector<std::string> iwyu_cmd;
+ cmSystemTools::ExpandListArgument(iwyu, iwyu_cmd, true);
+ iwyu_cmd.insert(iwyu_cmd.end(), orig_cmd.begin() + 1, orig_cmd.end());
+
+ // Run the iwyu command line. Capture its stderr and hide its stdout.
+ std::string stdErr;
+ if (!cmSystemTools::RunSingleCommand(iwyu_cmd, CM_NULLPTR, &stdErr,
+ &ret, CM_NULLPTR,
+ cmSystemTools::OUTPUT_NONE)) {
+ std::cerr << "Error running '" << iwyu_cmd[0] << "': " << stdErr
+ << "\n";
+ return 1;
+ }
+
+ // Warn if iwyu reported anything.
+ if (stdErr.find("should remove these lines:") != stdErr.npos ||
+ stdErr.find("should add these lines:") != stdErr.npos) {
+ std::cerr << "Warning: include-what-you-use reported diagnostics:\n"
+ << stdErr << "\n";
+ }
+ }
+
+ if (!tidy.empty()) {
+ // Construct the clang-tidy command line by taking what was given
+ // and adding our compiler command line. The clang-tidy tool will
+ // automatically skip over the compiler itself and extract the
+ // options.
+ std::vector<std::string> tidy_cmd;
+ cmSystemTools::ExpandListArgument(tidy, tidy_cmd, true);
+ tidy_cmd.push_back(sourceFile);
+ tidy_cmd.push_back("--");
+ tidy_cmd.insert(tidy_cmd.end(), orig_cmd.begin(), orig_cmd.end());
+
+ // Run the tidy command line. Capture its stdout and hide its stderr.
+ std::string stdOut;
+ if (!cmSystemTools::RunSingleCommand(tidy_cmd, &stdOut, CM_NULLPTR,
+ &ret, CM_NULLPTR,
+ cmSystemTools::OUTPUT_NONE)) {
+ std::cerr << "Error running '" << tidy_cmd[0] << "'\n";
+ return 1;
+ }
+ // Output the stdout from clang-tidy to stderr
+ std::cerr << stdOut;
+ }
+ if (!lwyu.empty()) {
+ // Construct the ldd -r -u (link what you use lwyu) command line
+ // ldd -u -r lwuy target
+ std::vector<std::string> lwyu_cmd;
+ lwyu_cmd.push_back("ldd");
+ lwyu_cmd.push_back("-u");
+ lwyu_cmd.push_back("-r");
+ lwyu_cmd.push_back(lwyu);
+
+ // Run the ldd -u -r command line.
+ // Capture its stdout and hide its stderr.
+ std::string stdOut;
+ if (!cmSystemTools::RunSingleCommand(lwyu_cmd, &stdOut, CM_NULLPTR,
+ &ret, CM_NULLPTR,
+ cmSystemTools::OUTPUT_NONE)) {
+ std::cerr << "Error running '" << lwyu_cmd[0] << "'\n";
+ return 1;
+ }
+
+ // Output the stdout from ldd -r -u to stderr
+ // Warn if lwyu reported anything.
+ if (stdOut.find("Unused direct dependencies:") != stdOut.npos) {
+ std::cerr << "Warning: " << stdOut;
+ }
+ }
+ ret = 0;
+ // Now run the real compiler command and return its result value.
+ if (lwyu.empty() &&
+ !cmSystemTools::RunSingleCommand(
+ orig_cmd, CM_NULLPTR, CM_NULLPTR, &ret, CM_NULLPTR,
+ cmSystemTools::OUTPUT_PASSTHROUGH)) {
+ std::cerr << "Error running '" << orig_cmd[0] << "'\n";
+ return 1;
+ }
+ return ret;
+ }
+
+ // Echo string
+ else if (args[1] == "echo") {
+ std::cout << cmJoin(cmMakeRange(args).advance(2), " ") << std::endl;
+ return 0;
+ }
+
+ // Echo string no new line
+ else if (args[1] == "echo_append") {
+ std::cout << cmJoin(cmMakeRange(args).advance(2), " ");
+ return 0;
+ }
+
+ else if (args[1] == "env") {
+ std::vector<std::string>::const_iterator ai = args.begin() + 2;
+ std::vector<std::string>::const_iterator ae = args.end();
+ for (; ai != ae; ++ai) {
+ std::string const& a = *ai;
+ if (cmHasLiteralPrefix(a, "--unset=")) {
+ // Unset environment variable.
+ cmSystemTools::UnPutEnv(a.c_str() + 8);
+ } else if (!a.empty() && a[0] == '-') {
+ // Environment variable and command names cannot start in '-',
+ // so this must be an unknown option.
+ std::cerr << "cmake -E env: unknown option '" << a << "'"
+ << std::endl;
+ return 1;
+ } else if (a.find('=') != a.npos) {
+ // Set environment variable.
+ cmSystemTools::PutEnv(a);
+ } else {
+ // This is the beginning of the command.
+ break;
+ }
+ }
+
+ if (ai == ae) {
+ std::cerr << "cmake -E env: no command given" << std::endl;
+ return 1;
+ }
+
+ // Execute command from remaining arguments.
+ std::vector<std::string> cmd(ai, ae);
+ int retval;
+ if (cmSystemTools::RunSingleCommand(cmd, CM_NULLPTR, CM_NULLPTR, &retval,
+ CM_NULLPTR,
+ cmSystemTools::OUTPUT_PASSTHROUGH)) {
+ return retval;
+ }
+ return 1;
+ }
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ else 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;
+ }
+ return 0;
+ }
+#endif
+
+ else if (args[1] == "make_directory" && args.size() > 2) {
+ // If error occurs we want to continue copying next files.
+ bool return_value = 0;
+ for (std::string::size_type cc = 2; cc < args.size(); cc++) {
+ if (!cmSystemTools::MakeDirectory(args[cc].c_str())) {
+ std::cerr << "Error creating directory \"" << args[cc] << "\".\n";
+ return_value = 1;
+ }
+ }
+ return return_value;
+ }
+
+ else 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;
+ }
+ return 0;
+ }
+
+ // Remove file
+ else 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") {
+ 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].c_str())) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+ }
+ // Touch file
+ else if (args[1] == "touch" && args.size() > 2) {
+ for (std::string::size_type cc = 2; cc < args.size(); cc++) {
+ if (!cmSystemTools::Touch(args[cc], true)) {
+ return 1;
+ }
+ }
+ return 0;
+ }
+ // Touch file
+ else if (args[1] == "touch_nocreate" && args.size() > 2) {
+ for (std::string::size_type cc = 2; cc < args.size(); cc++) {
+ // Complain if the file could not be removed, still exists,
+ // and the -f option was not given.
+ if (!cmSystemTools::Touch(args[cc], false)) {
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ // Sleep command
+ else if (args[1] == "sleep" && args.size() > 2) {
+ double total = 0;
+ for (size_t i = 2; i < args.size(); ++i) {
+ double num = 0.0;
+ char unit;
+ char extra;
+ int n = sscanf(args[i].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";
+ return 1;
+ }
+ }
+ if (total > 0) {
+ cmSystemTools::Delay(static_cast<unsigned int>(total * 1000));
+ }
+ return 0;
+ }
+
+ // Clock command
+ else if (args[1] == "time" && args.size() > 2) {
+ std::vector<std::string> command(args.begin() + 2, args.end());
+
+ clock_t clock_start, clock_finish;
+ time_t time_start, time_finish;
+
+ time(&time_start);
+ clock_start = clock();
+ int ret = 0;
+ cmSystemTools::RunSingleCommand(command, CM_NULLPTR, CM_NULLPTR, &ret);
+
+ clock_finish = clock();
+ time(&time_finish);
+
+ double clocks_per_sec = static_cast<double>(CLOCKS_PER_SEC);
+ std::cout << "Elapsed time: "
+ << static_cast<long>(time_finish - time_start) << " s. (time)"
+ << ", "
+ << static_cast<double>(clock_finish - clock_start) /
+ clocks_per_sec
+ << " s. (clock)"
+ << "\n";
+ return ret;
+ }
+ // Command to calculate the md5sum of a file
+ else if (args[1] == "md5sum" && args.size() >= 3) {
+ char md5out[32];
+ int retval = 0;
+ for (std::string::size_type cc = 2; cc < args.size(); cc++) {
+ const char* filename = args[cc].c_str();
+ // Cannot compute md5sum of a directory
+ if (cmSystemTools::FileIsDirectory(filename)) {
+ std::cerr << "Error: " << filename << " is a directory" << std::endl;
+ retval++;
+ } else if (!cmSystemTools::ComputeFileMD5(filename, md5out)) {
+ // To mimic md5sum behavior in a shell:
+ std::cerr << filename << ": No such file or directory" << std::endl;
+ retval++;
+ } else {
+ std::cout << std::string(md5out, 32) << " " << filename
+ << std::endl;
+ }
+ }
+ return retval;
+ }
+
+ // Command to change directory and run a program.
+ else if (args[1] == "chdir" && args.size() >= 4) {
+ std::string directory = args[2];
+ if (!cmSystemTools::FileExists(directory.c_str())) {
+ cmSystemTools::Error("Directory does not exist for chdir command: ",
+ args[2].c_str());
+ return 1;
+ }
+
+ std::string command =
+ cmWrap('"', cmMakeRange(args).advance(3), '"', " ");
+ int retval = 0;
+ int timeout = 0;
+ if (cmSystemTools::RunSingleCommand(
+ command.c_str(), CM_NULLPTR, CM_NULLPTR, &retval,
+ directory.c_str(), cmSystemTools::OUTPUT_PASSTHROUGH, timeout)) {
+ return retval;
+ }
+
+ return 1;
+ }
+
+ // Command to start progress for a build
+ else if (args[1] == "cmake_progress_start" && args.size() == 4) {
+ // basically remove the directory
+ std::string dirName = args[2];
+ dirName += "/Progress";
+ cmSystemTools::RemoveADirectory(dirName);
+
+ // is the last argument a filename that exists?
+ FILE* countFile = cmsys::SystemTools::Fopen(args[3], "r");
+ int count;
+ if (countFile) {
+ if (1 != fscanf(countFile, "%i", &count)) {
+ cmSystemTools::Message("Could not read from count file.");
+ }
+ fclose(countFile);
+ } else {
+ count = atoi(args[3].c_str());
+ }
+ if (count) {
+ cmSystemTools::MakeDirectory(dirName.c_str());
+ // write the count into the directory
+ std::string fName = dirName;
+ fName += "/count.txt";
+ FILE* progFile = cmsys::SystemTools::Fopen(fName, "w");
+ if (progFile) {
+ fprintf(progFile, "%i\n", count);
+ fclose(progFile);
+ }
+ }
+ return 0;
+ }
+
+ // Command to report progress for a build
+ else if (args[1] == "cmake_progress_report" && args.size() >= 3) {
+ // This has been superseded by cmake_echo_color --progress-*
+ // options. We leave it here to avoid errors if somehow this
+ // is invoked by an existing makefile without regenerating.
+ return 0;
+ }
+
+ // Command to create a symbolic link. Fails on platforms not
+ // supporting them.
+ else if (args[1] == "create_symlink" && args.size() == 4) {
+ const char* destinationFileName = args[3].c_str();
+ if ((cmSystemTools::FileExists(destinationFileName) ||
+ cmSystemTools::FileIsSymlink(destinationFileName)) &&
+ !cmSystemTools::RemoveFile(destinationFileName)) {
+ std::string emsg = cmSystemTools::GetLastSystemError();
+ std::cerr << "failed to create symbolic link '" << destinationFileName
+ << "' because existing path cannot be removed: " << emsg
+ << "\n";
+ return 1;
+ }
+ if (!cmSystemTools::CreateSymlink(args[2], args[3])) {
+ std::string emsg = cmSystemTools::GetLastSystemError();
+ std::cerr << "failed to create symbolic link '" << destinationFileName
+ << "': " << emsg << "\n";
+ return 1;
+ }
+ return 0;
+ }
+
+ // Internal CMake shared library support.
+ else if (args[1] == "cmake_symlink_library" && args.size() == 5) {
+ return cmcmd::SymlinkLibrary(args);
+ }
+ // Internal CMake versioned executable support.
+ else if (args[1] == "cmake_symlink_executable" && args.size() == 4) {
+ return cmcmd::SymlinkExecutable(args);
+ }
+
+#if defined(CMAKE_HAVE_VS_GENERATORS)
+ // Internal CMake support for calling Visual Studio macros.
+ else if (args[1] == "cmake_call_visual_studio_macro" && args.size() >= 4) {
+ // args[2] = full path to .sln file or "ALL"
+ // args[3] = name of Visual Studio macro to call
+ // args[4..args.size()-1] = [optional] args for Visual Studio macro
+
+ std::string macroArgs;
+
+ if (args.size() > 4) {
+ macroArgs = args[4];
+
+ for (size_t i = 5; i < args.size(); ++i) {
+ macroArgs += " ";
+ macroArgs += args[i];
+ }
+ }
+
+ return cmCallVisualStudioMacro::CallMacro(args[2], args[3], macroArgs,
+ true);
+ }
+#endif
+
+ // Internal CMake dependency scanning support.
+ else if (args[1] == "cmake_depends" && args.size() >= 6) {
+ // Use the make system's VERBOSE environment variable to enable
+ // verbose output. This can be skipped by also setting CMAKE_NO_VERBOSE
+ // (which is set by the Eclipse and KDevelop generators).
+ bool verbose =
+ ((cmSystemTools::GetEnv("VERBOSE") != CM_NULLPTR) &&
+ (cmSystemTools::GetEnv("CMAKE_NO_VERBOSE") == CM_NULLPTR));
+
+ // Create a cmake object instance to process dependencies.
+ cmake cm;
+ std::string gen;
+ std::string homeDir;
+ std::string startDir;
+ std::string homeOutDir;
+ std::string startOutDir;
+ std::string depInfo;
+ bool color = false;
+ if (args.size() >= 8) {
+ // Full signature:
+ //
+ // -E cmake_depends <generator>
+ // <home-src-dir> <start-src-dir>
+ // <home-out-dir> <start-out-dir>
+ // <dep-info> [--color=$(COLOR)]
+ //
+ // All paths are provided.
+ gen = args[2];
+ homeDir = args[3];
+ startDir = args[4];
+ homeOutDir = args[5];
+ startOutDir = args[6];
+ depInfo = args[7];
+ if (args.size() >= 9 && args[8].length() >= 8 &&
+ args[8].substr(0, 8) == "--color=") {
+ // Enable or disable color based on the switch value.
+ color = (args[8].size() == 8 ||
+ cmSystemTools::IsOn(args[8].substr(8).c_str()));
+ }
+ } else {
+ // Support older signature for existing makefiles:
+ //
+ // -E cmake_depends <generator>
+ // <home-out-dir> <start-out-dir>
+ // <dep-info>
+ //
+ // Just pretend the source directories are the same as the
+ // binary directories so at least scanning will work.
+ gen = args[2];
+ homeDir = args[3];
+ startDir = args[4];
+ homeOutDir = args[3];
+ startOutDir = args[3];
+ depInfo = args[5];
+ }
+
+ // Create a local generator configured for the directory in
+ // which dependencies will be scanned.
+ homeDir = cmSystemTools::CollapseFullPath(homeDir);
+ startDir = cmSystemTools::CollapseFullPath(startDir);
+ homeOutDir = cmSystemTools::CollapseFullPath(homeOutDir);
+ startOutDir = cmSystemTools::CollapseFullPath(startOutDir);
+ cm.SetHomeDirectory(homeDir);
+ cm.SetHomeOutputDirectory(homeOutDir);
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ if (cmGlobalGenerator* ggd = cm.CreateGlobalGenerator(gen)) {
+ cm.SetGlobalGenerator(ggd);
+ cmState::Snapshot snapshot = cm.GetCurrentSnapshot();
+ snapshot.GetDirectory().SetCurrentBinary(startOutDir);
+ snapshot.GetDirectory().SetCurrentSource(startDir);
+ CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(ggd, snapshot));
+ CM_AUTO_PTR<cmLocalGenerator> lgd(ggd->CreateLocalGenerator(mf.get()));
+
+ // Actually scan dependencies.
+ return lgd->UpdateDependencies(depInfo.c_str(), verbose, color) ? 0
+ : 2;
+ }
+ return 1;
+ }
+
+ // Internal CMake link script support.
+ else if (args[1] == "cmake_link_script" && args.size() >= 3) {
+ return cmcmd::ExecuteLinkScript(args);
+ }
+
+ // Internal CMake unimplemented feature notification.
+ else if (args[1] == "cmake_unimplemented_variable") {
+ std::cerr << "Feature not implemented for this platform.";
+ if (args.size() == 3) {
+ std::cerr << " Variable " << args[2] << " is not set.";
+ }
+ std::cerr << std::endl;
+ return 1;
+ } else if (args[1] == "vs_link_exe") {
+ return cmcmd::VisualStudioLink(args, 1);
+ } else if (args[1] == "vs_link_dll") {
+ return cmcmd::VisualStudioLink(args, 2);
+ }
+ // Internal CMake color makefile support.
+ else if (args[1] == "cmake_echo_color") {
+ return cmcmd::ExecuteEchoColor(args);
+ }
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ else if (args[1] == "cmake_autogen" && args.size() >= 4) {
+ cmQtAutoGenerators autogen;
+ std::string const& config = args[3];
+ bool autogenSuccess = autogen.Run(args[2], config);
+ return autogenSuccess ? 0 : 1;
+ }
+#endif
+
+ // Tar files
+ else if (args[1] == "tar" && args.size() > 3) {
+ const char* knownFormats[] = { "7zip", "gnutar", "pax", "paxr", "zip" };
+
+ std::string flags = args[2];
+ std::string outFile = args[3];
+ std::vector<std::string> files;
+ std::string mtime;
+ std::string format;
+ bool doing_options = true;
+ for (std::string::size_type cc = 4; cc < args.size(); cc++) {
+ std::string const& arg = args[cc];
+ if (doing_options && cmHasLiteralPrefix(arg, "--")) {
+ if (arg == "--") {
+ doing_options = false;
+ } else if (cmHasLiteralPrefix(arg, "--mtime=")) {
+ mtime = arg.substr(8);
+ } else if (cmHasLiteralPrefix(arg, "--files-from=")) {
+ std::string const& files_from = arg.substr(13);
+ if (!cmTarFilesFrom(files_from, files)) {
+ return 1;
+ }
+ } else if (cmHasLiteralPrefix(arg, "--format=")) {
+ format = arg.substr(9);
+ bool isKnown =
+ std::find(cmArrayBegin(knownFormats), cmArrayEnd(knownFormats),
+ format) != cmArrayEnd(knownFormats);
+
+ if (!isKnown) {
+ cmSystemTools::Error("Unknown -E tar --format= argument: ",
+ format.c_str());
+ return 1;
+ }
+ } else {
+ cmSystemTools::Error("Unknown option to -E tar: ", arg.c_str());
+ return 1;
+ }
+ } else {
+ files.push_back(arg);
+ }
+ }
+ cmSystemTools::cmTarCompression compress =
+ cmSystemTools::TarCompressNone;
+ bool verbose = false;
+ int nCompress = 0;
+ if (flags.find_first_of('j') != flags.npos) {
+ compress = cmSystemTools::TarCompressBZip2;
+ ++nCompress;
+ }
+ if (flags.find_first_of('J') != flags.npos) {
+ compress = cmSystemTools::TarCompressXZ;
+ ++nCompress;
+ }
+ if (flags.find_first_of('z') != flags.npos) {
+ compress = cmSystemTools::TarCompressGZip;
+ ++nCompress;
+ }
+ if ((format == "7zip" || format == "zip") && nCompress > 0) {
+ cmSystemTools::Error("Can not use compression flags with format: ",
+ format.c_str());
+ return 1;
+ } else if (nCompress > 1) {
+ cmSystemTools::Error("Can only compress a tar file one way; "
+ "at most one flag of z, j, or J may be used");
+ return 1;
+ }
+ if (flags.find_first_of('v') != flags.npos) {
+ verbose = true;
+ }
+
+ if (flags.find_first_of('t') != flags.npos) {
+ if (!cmSystemTools::ListTar(outFile.c_str(), verbose)) {
+ cmSystemTools::Error("Problem listing tar: ", outFile.c_str());
+ return 1;
+ }
+ } else if (flags.find_first_of('c') != flags.npos) {
+ if (!cmSystemTools::CreateTar(outFile.c_str(), files, compress,
+ verbose, mtime, format)) {
+ cmSystemTools::Error("Problem creating tar: ", outFile.c_str());
+ return 1;
+ }
+ } else if (flags.find_first_of('x') != flags.npos) {
+ if (!cmSystemTools::ExtractTar(outFile.c_str(), verbose)) {
+ cmSystemTools::Error("Problem extracting tar: ", outFile.c_str());
+ return 1;
+ }
+#ifdef WIN32
+ // OK, on windows 7 after we untar some files,
+ // sometimes we can not rename the directory after
+ // the untar is done. This breaks the external project
+ // untar and rename code. So, by default we will wait
+ // 1/10th of a second after the untar. If CMAKE_UNTAR_DELAY
+ // is set in the env, its value will be used instead of 100.
+ int delay = 100;
+ const char* delayVar = cmSystemTools::GetEnv("CMAKE_UNTAR_DELAY");
+ if (delayVar) {
+ delay = atoi(delayVar);
+ }
+ if (delay) {
+ cmSystemTools::Delay(delay);
+ }
+#endif
+ }
+ return 0;
+ }
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ // Internal CMake Fortran module support.
+ else if (args[1] == "cmake_copy_f90_mod" && args.size() >= 4) {
+ return cmDependsFortran::CopyModule(args) ? 0 : 1;
+ }
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // Write registry value
+ else if (args[1] == "write_regv" && args.size() > 3) {
+ return cmSystemTools::WriteRegistryValue(args[2].c_str(),
+ args[3].c_str())
+ ? 0
+ : 1;
+ }
+
+ // Delete registry value
+ else if (args[1] == "delete_regv" && args.size() > 2) {
+ return cmSystemTools::DeleteRegistryValue(args[2].c_str()) ? 0 : 1;
+ }
+ // Remove file
+ else if (args[1] == "comspec" && args.size() > 2) {
+ std::cerr << "Win9x helper \"cmake -E comspec\" no longer supported\n";
+ return 1;
+ } else if (args[1] == "env_vs8_wince" && args.size() == 3) {
+ return cmcmd::WindowsCEEnvironment("8.0", args[2]);
+ } else if (args[1] == "env_vs9_wince" && args.size() == 3) {
+ return cmcmd::WindowsCEEnvironment("9.0", args[2]);
+ }
+#endif
+ }
+
+ ::CMakeCommandUsage(args[0].c_str());
+ return 1;
+}
+
+int cmcmd::SymlinkLibrary(std::vector<std::string>& args)
+{
+ int result = 0;
+ std::string realName = args[2];
+ std::string soName = args[3];
+ std::string name = args[4];
+ if (soName != realName) {
+ if (!cmcmd::SymlinkInternal(realName, soName)) {
+ cmSystemTools::ReportLastSystemError("cmake_symlink_library");
+ result = 1;
+ }
+ }
+ if (name != soName) {
+ if (!cmcmd::SymlinkInternal(soName, name)) {
+ cmSystemTools::ReportLastSystemError("cmake_symlink_library");
+ result = 1;
+ }
+ }
+ return result;
+}
+
+int cmcmd::SymlinkExecutable(std::vector<std::string>& args)
+{
+ int result = 0;
+ std::string realName = args[2];
+ std::string name = args[3];
+ if (name != realName) {
+ if (!cmcmd::SymlinkInternal(realName, name)) {
+ cmSystemTools::ReportLastSystemError("cmake_symlink_executable");
+ result = 1;
+ }
+ }
+ return result;
+}
+
+bool cmcmd::SymlinkInternal(std::string const& file, std::string const& link)
+{
+ if (cmSystemTools::FileExists(link.c_str()) ||
+ cmSystemTools::FileIsSymlink(link)) {
+ cmSystemTools::RemoveFile(link);
+ }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ return cmSystemTools::CopyFileAlways(file.c_str(), link.c_str());
+#else
+ std::string linktext = cmSystemTools::GetFilenameName(file);
+ return cmSystemTools::CreateSymlink(linktext, link);
+#endif
+}
+
+static void cmcmdProgressReport(std::string const& dir, std::string const& num)
+{
+ std::string dirName = dir;
+ dirName += "/Progress";
+ std::string fName;
+ FILE* progFile;
+
+ // read the count
+ fName = dirName;
+ fName += "/count.txt";
+ progFile = cmsys::SystemTools::Fopen(fName, "r");
+ int count = 0;
+ if (!progFile) {
+ return;
+ } else {
+ if (1 != fscanf(progFile, "%i", &count)) {
+ cmSystemTools::Message("Could not read from progress file.");
+ }
+ fclose(progFile);
+ }
+ const char* last = num.c_str();
+ for (const char* c = last;; ++c) {
+ if (*c == ',' || *c == '\0') {
+ if (c != last) {
+ fName = dirName;
+ fName += "/";
+ fName.append(last, c - last);
+ progFile = cmsys::SystemTools::Fopen(fName, "w");
+ if (progFile) {
+ fprintf(progFile, "empty");
+ fclose(progFile);
+ }
+ }
+ if (*c == '\0') {
+ break;
+ }
+ last = c + 1;
+ }
+ }
+ int fileNum =
+ static_cast<int>(cmsys::Directory::GetNumberOfFilesInDirectory(dirName));
+ if (count > 0) {
+ // print the progress
+ fprintf(stdout, "[%3i%%] ", ((fileNum - 3) * 100) / count);
+ }
+}
+
+int cmcmd::ExecuteEchoColor(std::vector<std::string>& args)
+{
+ // The arguments are
+ // argv[0] == <cmake-executable>
+ // argv[1] == cmake_echo_color
+
+ bool enabled = true;
+ 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) {
+ // Enable or disable color based on the switch value.
+ std::string value = args[i].substr(9);
+ if (!value.empty()) {
+ enabled = cmSystemTools::IsOn(value.c_str());
+ }
+ } else if (cmHasLiteralPrefix(args[i], "--progress-dir=")) {
+ progressDir = args[i].substr(15);
+ } else if (cmHasLiteralPrefix(args[i], "--progress-num=")) {
+ if (!progressDir.empty()) {
+ std::string const& progressNum = args[i].substr(15);
+ cmcmdProgressReport(progressDir, progressNum);
+ }
+ } else if (args[i] == "--normal") {
+ color = cmsysTerminal_Color_Normal;
+ } else if (args[i] == "--black") {
+ color = cmsysTerminal_Color_ForegroundBlack;
+ } else if (args[i] == "--red") {
+ color = cmsysTerminal_Color_ForegroundRed;
+ } else if (args[i] == "--green") {
+ color = cmsysTerminal_Color_ForegroundGreen;
+ } else if (args[i] == "--yellow") {
+ color = cmsysTerminal_Color_ForegroundYellow;
+ } else if (args[i] == "--blue") {
+ color = cmsysTerminal_Color_ForegroundBlue;
+ } else if (args[i] == "--magenta") {
+ color = cmsysTerminal_Color_ForegroundMagenta;
+ } else if (args[i] == "--cyan") {
+ color = cmsysTerminal_Color_ForegroundCyan;
+ } else if (args[i] == "--white") {
+ color = cmsysTerminal_Color_ForegroundWhite;
+ } else if (args[i] == "--bold") {
+ color |= cmsysTerminal_Color_ForegroundBold;
+ } else if (args[i] == "--no-newline") {
+ newline = false;
+ } else if (args[i] == "--newline") {
+ newline = true;
+ } else {
+ // Color is enabled. Print with the current color.
+ cmSystemTools::MakefileColorEcho(color, args[i].c_str(), newline,
+ enabled);
+ }
+ }
+
+ return 0;
+}
+
+int cmcmd::ExecuteLinkScript(std::vector<std::string>& args)
+{
+ // The arguments are
+ // argv[0] == <cmake-executable>
+ // argv[1] == cmake_link_script
+ // argv[2] == <link-script-name>
+ // argv[3] == --verbose=?
+ bool verbose = false;
+ if (args.size() >= 4) {
+ if (args[3].find("--verbose=") == 0) {
+ if (!cmSystemTools::IsOff(args[3].substr(10).c_str())) {
+ verbose = true;
+ }
+ }
+ }
+
+ // Allocate a process instance.
+ cmsysProcess* cp = cmsysProcess_New();
+ if (!cp) {
+ std::cerr << "Error allocating process instance in link script."
+ << std::endl;
+ return 1;
+ }
+
+ // Children should share stdout and stderr with this process.
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
+
+ // Run the command lines verbatim.
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
+
+ // Read command lines from the script.
+ cmsys::ifstream fin(args[2].c_str());
+ if (!fin) {
+ std::cerr << "Error opening link script \"" << args[2] << "\""
+ << std::endl;
+ return 1;
+ }
+
+ // Run one command at a time.
+ std::string command;
+ int result = 0;
+ while (result == 0 && cmSystemTools::GetLineFromStream(fin, command)) {
+ // Skip empty command lines.
+ if (command.find_first_not_of(" \t") == command.npos) {
+ continue;
+ }
+
+ // Setup this command line.
+ const char* cmd[2] = { command.c_str(), CM_NULLPTR };
+ cmsysProcess_SetCommand(cp, cmd);
+
+ // Report the command if verbose output is enabled.
+ if (verbose) {
+ std::cout << command << std::endl;
+ }
+
+ // Run the command and wait for it to exit.
+ cmsysProcess_Execute(cp);
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+
+ // Report failure if any.
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited: {
+ int value = cmsysProcess_GetExitValue(cp);
+ if (value != 0) {
+ result = value;
+ }
+ } break;
+ case cmsysProcess_State_Exception:
+ std::cerr << "Error running link command: "
+ << cmsysProcess_GetExceptionString(cp) << std::endl;
+ result = 1;
+ break;
+ case cmsysProcess_State_Error:
+ std::cerr << "Error running link command: "
+ << cmsysProcess_GetErrorString(cp) << std::endl;
+ result = 2;
+ break;
+ default:
+ break;
+ };
+ }
+
+ // Free the process instance.
+ cmsysProcess_Delete(cp);
+
+ // Return the final resulting return value.
+ return result;
+}
+
+int cmcmd::WindowsCEEnvironment(const char* version, const std::string& name)
+{
+#if defined(CMAKE_HAVE_VS_GENERATORS)
+ cmVisualStudioWCEPlatformParser parser(name.c_str());
+ parser.ParseVersion(version);
+ if (parser.Found()) {
+ std::cout << "@echo off" << std::endl;
+ std::cout << "echo Environment Selection: " << name << std::endl;
+ std::cout << "set PATH=" << parser.GetPathDirectories() << std::endl;
+ std::cout << "set INCLUDE=" << parser.GetIncludeDirectories() << std::endl;
+ std::cout << "set LIB=" << parser.GetLibraryDirectories() << std::endl;
+ return 0;
+ }
+#else
+ (void)version;
+#endif
+
+ std::cerr << "Could not find " << name;
+ return -1;
+}
+
+class cmVSLink
+{
+ int Type;
+ bool Verbose;
+ bool Incremental;
+ bool LinkGeneratesManifest;
+ std::vector<std::string> LinkCommand;
+ std::vector<std::string> UserManifests;
+ std::string LinkerManifestFile;
+ std::string ManifestFile;
+ std::string ManifestFileRC;
+ std::string ManifestFileRes;
+ std::string TargetFile;
+
+public:
+ cmVSLink(int type, bool verbose)
+ : Type(type)
+ , Verbose(verbose)
+ , Incremental(false)
+ , LinkGeneratesManifest(true)
+ {
+ }
+ bool Parse(std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd);
+ int Link();
+
+private:
+ int LinkIncremental();
+ int LinkNonIncremental();
+ int RunMT(std::string const& out, bool notify);
+};
+
+// For visual studio 2005 and newer manifest files need to be embedded into
+// exe and dll's. This code does that in such a way that incremental linking
+// still works.
+int cmcmd::VisualStudioLink(std::vector<std::string>& args, int type)
+{
+ if (args.size() < 2) {
+ return -1;
+ }
+ bool verbose = cmSystemTools::GetEnv("VERBOSE") != CM_NULLPTR;
+ std::vector<std::string> expandedArgs;
+ for (std::vector<std::string>::iterator i = args.begin(); i != args.end();
+ ++i) {
+ // check for nmake temporary files
+ if ((*i)[0] == '@' && i->find("@CMakeFiles") != 0) {
+ cmsys::ifstream fin(i->substr(1).c_str());
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ cmSystemTools::ParseWindowsCommandLine(line.c_str(), expandedArgs);
+ }
+ } else {
+ expandedArgs.push_back(*i);
+ }
+ }
+
+ cmVSLink vsLink(type, verbose);
+ if (!vsLink.Parse(expandedArgs.begin() + 2, expandedArgs.end())) {
+ return -1;
+ }
+ return vsLink.Link();
+}
+
+static bool RunCommand(const char* comment, std::vector<std::string>& command,
+ bool verbose, int* retCodeOut = CM_NULLPTR)
+{
+ if (verbose) {
+ std::cout << comment << ":\n";
+ std::cout << cmJoin(command, " ") << "\n";
+ }
+ std::string output;
+ int retCode = 0;
+ // use rc command to create .res file
+ bool res =
+ cmSystemTools::RunSingleCommand(command, &output, &output, &retCode,
+ CM_NULLPTR, cmSystemTools::OUTPUT_NONE);
+ // always print the output of the command, unless
+ // it is the dumb rc command banner, but if the command
+ // returned an error code then print the output anyway as
+ // the banner may be mixed with some other important information.
+ if (output.find("Resource Compiler Version") == output.npos || !res ||
+ retCode) {
+ std::cout << output;
+ }
+ if (!res) {
+ std::cout << comment << " failed to run." << std::endl;
+ return false;
+ }
+ // if retCodeOut is requested then always return true
+ // and set the retCodeOut to retCode
+ if (retCodeOut) {
+ *retCodeOut = retCode;
+ return true;
+ }
+ if (retCode != 0) {
+ std::cout << comment << " failed. with " << retCode << "\n";
+ }
+ return retCode == 0;
+}
+
+bool cmVSLink::Parse(std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd)
+{
+ // Parse our own arguments.
+ std::string intDir;
+ std::vector<std::string>::const_iterator arg = argBeg;
+ while (arg != argEnd && cmHasLiteralPrefix(*arg, "-")) {
+ if (*arg == "--") {
+ ++arg;
+ break;
+ } else if (*arg == "--manifests") {
+ for (++arg; arg != argEnd && !cmHasLiteralPrefix(*arg, "-"); ++arg) {
+ this->UserManifests.push_back(*arg);
+ }
+ } else if (cmHasLiteralPrefix(*arg, "--intdir=")) {
+ intDir = arg->substr(9);
+ ++arg;
+ } else {
+ std::cerr << "unknown argument '" << *arg << "'\n";
+ return false;
+ }
+ }
+ if (intDir.empty()) {
+ return false;
+ }
+
+ // The rest of the arguments form the link command.
+ if (arg == argEnd) {
+ return false;
+ }
+ this->LinkCommand.insert(this->LinkCommand.begin(), arg, argEnd);
+
+ // Parse the link command to extract information we need.
+ for (; arg != argEnd; ++arg) {
+ if (cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL:YES") == 0) {
+ this->Incremental = true;
+ } else if (cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL") == 0) {
+ this->Incremental = true;
+ } else if (cmSystemTools::Strucmp(arg->c_str(), "/MANIFEST:NO") == 0) {
+ this->LinkGeneratesManifest = false;
+ } else if (cmHasLiteralPrefix(*arg, "/Fe")) {
+ this->TargetFile = arg->substr(3);
+ } else if (cmHasLiteralPrefix(*arg, "/out:")) {
+ this->TargetFile = arg->substr(5);
+ }
+ }
+
+ if (this->TargetFile.empty()) {
+ return false;
+ }
+
+ this->ManifestFile = intDir + "/embed.manifest";
+ this->LinkerManifestFile = intDir + "/intermediate.manifest";
+
+ if (this->Incremental) {
+ // We will compile a resource containing the manifest and
+ // pass it to the link command.
+ this->ManifestFileRC = intDir + "/manifest.rc";
+ this->ManifestFileRes = intDir + "/manifest.res";
+ } else if (this->UserManifests.empty()) {
+ // Prior to support for user-specified manifests CMake placed the
+ // linker-generated manifest next to the binary (as if it were not to be
+ // embedded) when not linking incrementally. Preserve this behavior.
+ this->ManifestFile = this->TargetFile + ".manifest";
+ this->LinkerManifestFile = this->ManifestFile;
+ }
+
+ if (this->LinkGeneratesManifest) {
+ this->LinkCommand.push_back("/MANIFEST");
+ this->LinkCommand.push_back("/MANIFESTFILE:" + this->LinkerManifestFile);
+ }
+
+ return true;
+}
+
+int cmVSLink::Link()
+{
+ if (this->Incremental &&
+ (this->LinkGeneratesManifest || !this->UserManifests.empty())) {
+ if (this->Verbose) {
+ std::cout << "Visual Studio Incremental Link with embedded manifests\n";
+ }
+ return LinkIncremental();
+ }
+ if (this->Verbose) {
+ if (!this->Incremental) {
+ std::cout << "Visual Studio Non-Incremental Link\n";
+ } else {
+ std::cout << "Visual Studio Incremental Link without manifests\n";
+ }
+ }
+ return LinkNonIncremental();
+}
+
+int cmVSLink::LinkIncremental()
+{
+ // This follows the steps listed here:
+ // http://blogs.msdn.com/zakramer/archive/2006/05/22/603558.aspx
+
+ // 1. Compiler compiles the application and generates the *.obj files.
+ // 2. An empty manifest file is generated if this is a clean build and if
+ // not the previous one is reused.
+ // 3. The resource compiler (rc.exe) compiles the *.manifest file to a
+ // *.res file.
+ // 4. Linker generates the binary (EXE or DLL) with the /incremental
+ // switch and embeds the dummy manifest file. The linker also generates
+ // the real manifest file based on the binaries that your binary depends
+ // on.
+ // 5. The manifest tool (mt.exe) is then used to generate the final
+ // manifest.
+
+ // If the final manifest is changed, then 6 and 7 are run, if not
+ // they are skipped, and it is done.
+
+ // 6. The resource compiler is invoked one more time.
+ // 7. Finally, the Linker does another incremental link, but since the
+ // only thing that has changed is the *.res file that contains the
+ // manifest it is a short link.
+
+ // Create a resource file referencing the manifest.
+ std::string absManifestFile =
+ cmSystemTools::CollapseFullPath(this->ManifestFile);
+ if (this->Verbose) {
+ std::cout << "Create " << this->ManifestFileRC << "\n";
+ }
+ {
+ cmsys::ofstream fout(this->ManifestFileRC.c_str());
+ if (!fout) {
+ return -1;
+ }
+ fout << this->Type << " /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ "
+ "24 /* RT_MANIFEST */ \""
+ << absManifestFile << "\"";
+ }
+
+ // If we have not previously generated a manifest file,
+ // generate an empty one so the resource compiler succeeds.
+ if (!cmSystemTools::FileExists(this->ManifestFile)) {
+ if (this->Verbose) {
+ std::cout << "Create empty: " << this->ManifestFile << "\n";
+ }
+ cmsys::ofstream foutTmp(this->ManifestFile.c_str());
+ }
+
+ // Compile the resource file.
+ std::vector<std::string> rcCommand;
+ rcCommand.push_back(cmSystemTools::FindProgram("rc.exe"));
+ rcCommand.push_back("/fo" + this->ManifestFileRes);
+ rcCommand.push_back(this->ManifestFileRC);
+ if (!RunCommand("RC Pass 1", rcCommand, this->Verbose)) {
+ return -1;
+ }
+
+ // Tell the linker to use our manifest compiled into a resource.
+ this->LinkCommand.push_back(this->ManifestFileRes);
+
+ // Run the link command (possibly generates intermediate manifest).
+ if (!RunCommand("LINK Pass 1", this->LinkCommand, this->Verbose)) {
+ return -1;
+ }
+
+ // Run the manifest tool to create the final manifest.
+ int mtRet = this->RunMT("/out:" + this->ManifestFile, true);
+
+ // If mt returns 1090650113 (or 187 on a posix host) then it updated the
+ // manifest file so we need to embed it again. Otherwise we are done.
+ if (mtRet != 1090650113 && mtRet != 187) {
+ return mtRet;
+ }
+
+ // Compile the resource file again.
+ if (!RunCommand("RC Pass 2", rcCommand, this->Verbose)) {
+ return -1;
+ }
+
+ // Link incrementally again to use the updated resource.
+ if (!RunCommand("FINAL LINK", this->LinkCommand, this->Verbose)) {
+ return -1;
+ }
+ return 0;
+}
+
+int cmVSLink::LinkNonIncremental()
+{
+ // Run the link command (possibly generates intermediate manifest).
+ if (!RunCommand("LINK", this->LinkCommand, this->Verbose)) {
+ return -1;
+ }
+
+ // If we have no manifest files we are done.
+ if (!this->LinkGeneratesManifest && this->UserManifests.empty()) {
+ return 0;
+ }
+
+ // Run the manifest tool to embed the final manifest in the binary.
+ std::string mtOut =
+ "/outputresource:" + this->TargetFile + (this->Type == 1 ? ";#1" : ";#2");
+ return this->RunMT(mtOut, false);
+}
+
+int cmVSLink::RunMT(std::string const& out, bool notify)
+{
+ std::vector<std::string> mtCommand;
+ mtCommand.push_back(cmSystemTools::FindProgram("mt.exe"));
+ mtCommand.push_back("/nologo");
+ mtCommand.push_back("/manifest");
+ if (this->LinkGeneratesManifest) {
+ mtCommand.push_back(this->LinkerManifestFile);
+ }
+ mtCommand.insert(mtCommand.end(), this->UserManifests.begin(),
+ this->UserManifests.end());
+ mtCommand.push_back(out);
+ if (notify) {
+ // Add an undocumented option that enables a special return
+ // code to notify us when the manifest is modified.
+ mtCommand.push_back("/notify_update");
+ }
+ int mtRet = 0;
+ if (!RunCommand("MT", mtCommand, this->Verbose, &mtRet)) {
+ return -1;
+ }
+ return mtRet;
+}
diff --git a/Source/cmcmd.h b/Source/cmcmd.h
new file mode 100644
index 0000000..8da2103
--- /dev/null
+++ b/Source/cmcmd.h
@@ -0,0 +1,39 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmcmd_h
+#define cmcmd_h
+
+#include "cmStandardIncludes.h"
+
+class cmcmd
+{
+public:
+ /**
+ * Execute commands during the build process. Supports options such
+ * as echo, remove file etc.
+ */
+ static int ExecuteCMakeCommand(std::vector<std::string>&);
+
+protected:
+ static int SymlinkLibrary(std::vector<std::string>& args);
+ static int SymlinkExecutable(std::vector<std::string>& 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 WindowsCEEnvironment(const char* version,
+ const std::string& name);
+ static int VisualStudioLink(std::vector<std::string>& args, int type);
+};
+
+#endif
diff --git a/Source/cmparseMSBuildXML.py b/Source/cmparseMSBuildXML.py
new file mode 100755
index 0000000..056a0db
--- /dev/null
+++ b/Source/cmparseMSBuildXML.py
@@ -0,0 +1,338 @@
+# This python script parses the spec files from MSBuild to create
+# mappings from compiler options to IDE XML specifications. For
+# more information see here:
+
+# http://blogs.msdn.com/vcblog/archive/2008/12/16/msbuild-task.aspx
+# "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/1033/cl.xml"
+# "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/1033/lib.xml"
+# "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/1033/link.xml"
+# "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V110/1033/cl.xml"
+# "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V110/1033/lib.xml"
+# "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V110/1033/link.xml"
+# "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/v120/1033/cl.xml"
+# "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/v120/1033/lib.xml"
+# "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/v120/1033/link.xml"
+# "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V140/1033/cl.xml"
+# "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V140/1033/lib.xml"
+# "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V140/1033/link.xml"
+#
+# BoolProperty <Name>true|false</Name>
+# simple example:
+# <BoolProperty ReverseSwitch="Oy-" Name="OmitFramePointers"
+# Category="Optimization" Switch="Oy">
+# <BoolProperty.DisplayName> <BoolProperty.Description>
+# <CLCompile>
+# <OmitFramePointers>true</OmitFramePointers>
+# </ClCompile>
+#
+# argument means it might be this: /MP3
+# example with argument:
+# <BoolProperty Name="MultiProcessorCompilation" Category="General" Switch="MP">
+# <BoolProperty.DisplayName>
+# <sys:String>Multi-processor Compilation</sys:String>
+# </BoolProperty.DisplayName>
+# <BoolProperty.Description>
+# <sys:String>Multi-processor Compilation</sys:String>
+# </BoolProperty.Description>
+# <Argument Property="ProcessorNumber" IsRequired="false" />
+# </BoolProperty>
+# <CLCompile>
+# <MultiProcessorCompilation>true</MultiProcessorCompilation>
+# <ProcessorNumber>4</ProcessorNumber>
+# </ClCompile>
+# IntProperty
+# not used AFIT
+# <IntProperty Name="ProcessorNumber" Category="General" Visible="false">
+
+
+# per config options example
+# <EnableFiberSafeOptimizations Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EnableFiberSafeOptimizations>
+#
+# EnumProperty
+# <EnumProperty Name="Optimization" Category="Optimization">
+# <EnumProperty.DisplayName>
+# <sys:String>Optimization</sys:String>
+# </EnumProperty.DisplayName>
+# <EnumProperty.Description>
+# <sys:String>Select option for code optimization; choose Custom to use specific optimization options. (/Od, /O1, /O2, /Ox)</sys:String>
+# </EnumProperty.Description>
+# <EnumValue Name="MaxSpeed" Switch="O2">
+# <EnumValue.DisplayName>
+# <sys:String>Maximize Speed</sys:String>
+# </EnumValue.DisplayName>
+# <EnumValue.Description>
+# <sys:String>Equivalent to /Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy</sys:String>
+# </EnumValue.Description>
+# </EnumValue>
+# <EnumValue Name="MinSpace" Switch="O1">
+# <EnumValue.DisplayName>
+# <sys:String>Minimize Size</sys:String>
+# </EnumValue.DisplayName>
+# <EnumValue.Description>
+# <sys:String>Equivalent to /Og /Os /Oy /Ob2 /Gs /GF /Gy</sys:String>
+# </EnumValue.Description>
+# </EnumValue>
+# example for O2 would be this:
+# <Optimization>MaxSpeed</Optimization>
+# example for O1 would be this:
+# <Optimization>MinSpace</Optimization>
+#
+# StringListProperty
+# <StringListProperty Name="PreprocessorDefinitions" Category="Preprocessor" Switch="D ">
+# <StringListProperty.DisplayName>
+# <sys:String>Preprocessor Definitions</sys:String>
+# </StringListProperty.DisplayName>
+# <StringListProperty.Description>
+# <sys:String>Defines a preprocessing symbols for your source file.</sys:String>
+# </StringListProperty.Description>
+# </StringListProperty>
+
+# <StringListProperty Subtype="folder" Name="AdditionalIncludeDirectories" Category="General" Switch="I">
+# <StringListProperty.DisplayName>
+# <sys:String>Additional Include Directories</sys:String>
+# </StringListProperty.DisplayName>
+# <StringListProperty.Description>
+# <sys:String>Specifies one or more directories to add to the include path; separate with semi-colons if more than one. (/I[path])</sys:String>
+# </StringListProperty.Description>
+# </StringListProperty>
+# StringProperty
+
+# Example add bill include:
+
+# <AdditionalIncludeDirectories>..\..\..\..\..\..\bill;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+
+
+import sys
+from xml.dom.minidom import parse, parseString
+
+def getText(node):
+ nodelist = node.childNodes
+ rc = ""
+ for child in nodelist:
+ if child.nodeType == child.TEXT_NODE:
+ rc = rc + child.data
+ return rc
+
+def print_tree(document, spaces=""):
+ for i in range(len(document.childNodes)):
+ if document.childNodes[i].nodeType == document.childNodes[i].ELEMENT_NODE:
+ print spaces+str(document.childNodes[i].nodeName )
+ print_tree(document.childNodes[i],spaces+"----")
+ pass
+
+###########################################################################################
+#Data structure that stores a property of MSBuild
+class Property:
+ #type = type of MSBuild property (ex. if the property is EnumProperty type should be "Enum")
+ #attributeNames = a list of any attributes that this property could have (ex. if this was a EnumProperty it should be ["Name","Category"])
+ #document = the dom file that's root node is the Property node (ex. if you were parsing a BoolProperty the root node should be something like <BoolProperty Name="RegisterOutput" Category="General" IncludeInCommandLine="false">
+ def __init__(self,type,attributeNames,document=None):
+ self.suffix_type = "Property"
+ self.prefix_type = type
+ self.attributeNames = attributeNames
+ self.attributes = {}
+ self.DisplayName = ""
+ self.Description = ""
+ self.argumentProperty = ""
+ self.argumentIsRequired = ""
+ self.values = []
+ if document is not None:
+ self.populate(document)
+ pass
+
+ #document = the dom file that's root node is the Property node (ex. if you were parsing a BoolProperty the root node should be something like <BoolProperty Name="RegisterOutput" Category="General" IncludeInCommandLine="false">
+ #spaces = do not use
+ def populate(self,document, spaces = ""):
+ if document.nodeName == self.prefix_type+self.suffix_type:
+ for i in self.attributeNames:
+ self.attributes[i] = document.getAttribute(i)
+ for i in range(len(document.childNodes)):
+ child = document.childNodes[i]
+ if child.nodeType == child.ELEMENT_NODE:
+ if child.nodeName == self.prefix_type+self.suffix_type+".DisplayName":
+ self.DisplayName = getText(child.childNodes[1])
+ if child.nodeName == self.prefix_type+self.suffix_type+".Description":
+ self.Description = getText(child.childNodes[1])
+ if child.nodeName == "Argument":
+ self.argumentProperty = child.getAttribute("Property")
+ self.argumentIsRequired = child.getAttribute("IsRequired")
+ if child.nodeName == self.prefix_type+"Value":
+ va = Property(self.prefix_type,["Name","DisplayName","Switch"])
+ va.suffix_type = "Value"
+ va.populate(child)
+ self.values.append(va)
+ self.populate(child,spaces+"----")
+ pass
+
+ #toString function
+ def __str__(self):
+ toReturn = self.prefix_type+self.suffix_type+":"
+ for i in self.attributeNames:
+ toReturn += "\n "+i+": "+self.attributes[i]
+ if self.argumentProperty != "":
+ toReturn += "\n Argument:\n Property: "+self.argumentProperty+"\n IsRequired: "+self.argumentIsRequired
+ for i in self.values:
+ toReturn+="\n "+str(i).replace("\n","\n ")
+ return toReturn
+###########################################################################################
+
+###########################################################################################
+#Class that populates itself from an MSBuild file and outputs it in CMake
+#format
+
+class MSBuildToCMake:
+ #document = the entire MSBuild xml file
+ def __init__(self,document=None):
+ self.enumProperties = []
+ self.stringProperties = []
+ self.stringListProperties = []
+ self.boolProperties = []
+ self.intProperties = []
+ if document!=None :
+ self.populate(document)
+ pass
+
+ #document = the entire MSBuild xml file
+ #spaces = don't use
+ #To add a new property (if they exist) copy and paste this code and fill in appropriate places
+ #
+ #if child.nodeName == "<Name>Property":
+ # self.<Name>Properties.append(Property("<Name>",[<List of attributes>],child))
+ #
+ #Replace <Name> with the name of the new property (ex. if property is StringProperty replace <Name> with String)
+ #Replace <List of attributes> with a list of attributes in your property's root node
+ #in the __init__ function add the line self.<Name>Properties = []
+ #
+ #That is all that is required to add new properties
+ #
+ def populate(self,document, spaces=""):
+ for i in range(len(document.childNodes)):
+ child = document.childNodes[i]
+ if child.nodeType == child.ELEMENT_NODE:
+ if child.nodeName == "EnumProperty":
+ self.enumProperties.append(Property("Enum",["Name","Category"],child))
+ if child.nodeName == "StringProperty":
+ self.stringProperties.append(Property("String",["Name","Subtype","Separator","Category","Visible","IncludeInCommandLine","Switch","DisplayName","ReadOnly"],child))
+ if child.nodeName == "StringListProperty":
+ self.stringListProperties.append(Property("StringList",["Name","Category","Switch","DisplayName","Subtype"],child))
+ if child.nodeName == "BoolProperty":
+ self.boolProperties.append(Property("Bool",["ReverseSwitch","Name","Category","Switch","DisplayName","SwitchPrefix","IncludeInCommandLine"],child))
+ if child.nodeName == "IntProperty":
+ self.intProperties.append(Property("Int",["Name","Category","Visible"],child))
+ self.populate(child,spaces+"----")
+ pass
+
+ #outputs information that CMake needs to know about MSBuild xml files
+ def toCMake(self):
+ toReturn = "static cmVS7FlagTable cmVS10CxxTable[] =\n{\n"
+ toReturn += "\n //Enum Properties\n"
+ lastProp = {}
+ for i in self.enumProperties:
+ if i.attributes["Name"] == "CompileAsManaged":
+ #write these out after the rest of the enumProperties
+ lastProp = i
+ continue
+ for j in i.values:
+ #hardcore Brad King's manual fixes for cmVS10CLFlagTable.h
+ if i.attributes["Name"] == "PrecompiledHeader" and j.attributes["Switch"] != "":
+ toReturn+=" {\""+i.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\",\n cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n"
+ else:
+ #default (normal, non-hardcoded) case
+ toReturn+=" {\""+i.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\", 0},\n"
+ toReturn += "\n"
+
+ if lastProp != {}:
+ for j in lastProp.values:
+ toReturn+=" {\""+lastProp.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\", 0},\n"
+ toReturn += "\n"
+
+ toReturn += "\n //Bool Properties\n"
+ for i in self.boolProperties:
+ if i.argumentProperty == "":
+ if i.attributes["ReverseSwitch"] != "":
+ toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \"\", \"false\", 0},\n"
+ if i.attributes["Switch"] != "":
+ toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\", \"\", \"true\", 0},\n"
+
+ toReturn += "\n //Bool Properties With Argument\n"
+ for i in self.boolProperties:
+ if i.argumentProperty != "":
+ if i.attributes["ReverseSwitch"] != "":
+ toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \"\", \"false\",\n cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n"
+ toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \""+i.attributes["DisplayName"]+"\", \"\",\n cmVS7FlagTable::UserValueRequired},\n"
+ if i.attributes["Switch"] != "":
+ toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\", \"\", \"true\",\n cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n"
+ toReturn += " {\""+i.argumentProperty+"\", \""+i.attributes["Switch"]+"\", \""+i.attributes["DisplayName"]+"\", \"\",\n cmVS7FlagTable::UserValueRequired},\n"
+
+ toReturn += "\n //String List Properties\n"
+ for i in self.stringListProperties:
+ if i.attributes["Switch"] == "":
+ toReturn += " // Skip [" + i.attributes["Name"] + "] - no command line Switch.\n";
+ else:
+ toReturn +=" {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\",\n \""+i.attributes["DisplayName"]+"\",\n \"\", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable},\n"
+
+ toReturn += "\n //String Properties\n"
+ for i in self.stringProperties:
+ if i.attributes["Switch"] == "":
+ if i.attributes["Name"] == "PrecompiledHeaderFile":
+ #more hardcoding
+ toReturn += " {\"PrecompiledHeaderFile\", \"Yc\",\n"
+ toReturn += " \"Precompiled Header Name\",\n"
+ toReturn += " \"\", cmVS7FlagTable::UserValueRequired},\n"
+ toReturn += " {\"PrecompiledHeaderFile\", \"Yu\",\n"
+ toReturn += " \"Precompiled Header Name\",\n"
+ toReturn += " \"\", cmVS7FlagTable::UserValueRequired},\n"
+ else:
+ toReturn += " // Skip [" + i.attributes["Name"] + "] - no command line Switch.\n";
+ else:
+ toReturn +=" {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+i.attributes["Separator"]+"\",\n \""+i.attributes["DisplayName"]+"\",\n \"\", cmVS7FlagTable::UserValue},\n"
+
+ toReturn += " {0,0,0,0,0}\n};"
+ return toReturn
+ pass
+
+ #toString function
+ def __str__(self):
+ toReturn = ""
+ allList = [self.enumProperties,self.stringProperties,self.stringListProperties,self.boolProperties,self.intProperties]
+ for p in allList:
+ for i in p:
+ toReturn += "==================================================\n"+str(i).replace("\n","\n ")+"\n==================================================\n"
+
+ return toReturn
+###########################################################################################
+
+###########################################################################################
+# main function
+def main(argv):
+ xml_file = None
+ help = """
+ Please specify an input xml file with -x
+
+ Exiting...
+ Have a nice day :)"""
+ for i in range(0,len(argv)):
+ if argv[i] == "-x":
+ xml_file = argv[i+1]
+ if argv[i] == "-h":
+ print help
+ sys.exit(0)
+ pass
+ if xml_file == None:
+ print help
+ sys.exit(1)
+
+ f = open(xml_file,"r")
+ xml_str = f.read()
+ xml_dom = parseString(xml_str)
+
+ convertor = MSBuildToCMake(xml_dom)
+ print convertor.toCMake()
+
+ xml_dom.unlink()
+###########################################################################################
+# main entry point
+if __name__ == "__main__":
+ main(sys.argv)
+
+sys.exit(0)
diff --git a/Source/ctest.cxx b/Source/ctest.cxx
new file mode 100644
index 0000000..38ff64f
--- /dev/null
+++ b/Source/ctest.cxx
@@ -0,0 +1,190 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+
+// Need these for documentation support.
+#include "cmDocumentation.h"
+#include "cmake.h"
+
+#include "CTest/cmCTestLaunch.h"
+#include "CTest/cmCTestScriptHandler.h"
+#include "cmsys/Encoding.hxx"
+
+static const char* cmDocumentationName[][2] = {
+ { CM_NULLPTR, " ctest - Testing driver provided by CMake." },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+static const char* cmDocumentationUsage[][2] = { { CM_NULLPTR,
+ " ctest [options]" },
+ { CM_NULLPTR, CM_NULLPTR } };
+
+static const char* cmDocumentationOptions[][2] = {
+ { "-C <cfg>, --build-config <cfg>", "Choose configuration to test." },
+ { "-V,--verbose", "Enable verbose output from tests." },
+ { "-VV,--extra-verbose", "Enable more verbose output from tests." },
+ { "--debug", "Displaying more verbose internals of CTest." },
+ { "--output-on-failure", "Output anything outputted by the test program "
+ "if the test should fail." },
+ { "--test-output-size-passed <size>", "Limit the output for passed tests "
+ "to <size> bytes" },
+ { "--test-output-size-failed <size>", "Limit the output for failed tests "
+ "to <size> bytes" },
+ { "-F", "Enable failover." },
+ { "-j <jobs>, --parallel <jobs>", "Run the tests in parallel using the "
+ "given number of jobs." },
+ { "-Q,--quiet", "Make ctest quiet." },
+ { "-O <file>, --output-log <file>", "Output to log file" },
+ { "-N,--show-only", "Disable actual execution of tests." },
+ { "-L <regex>, --label-regex <regex>", "Run tests with labels matching "
+ "regular expression." },
+ { "-R <regex>, --tests-regex <regex>", "Run tests matching regular "
+ "expression." },
+ { "-E <regex>, --exclude-regex <regex>", "Exclude tests matching regular "
+ "expression." },
+ { "-LE <regex>, --label-exclude <regex>", "Exclude tests with labels "
+ "matching regular expression." },
+ { "-D <dashboard>, --dashboard <dashboard>", "Execute dashboard test" },
+ { "-D <var>:<type>=<value>", "Define a variable for script mode" },
+ { "-M <model>, --test-model <model>", "Sets the model for a dashboard" },
+ { "-T <action>, --test-action <action>", "Sets the dashboard action to "
+ "perform" },
+ { "--track <track>", "Specify the track to submit dashboard to" },
+ { "-S <script>, --script <script>", "Execute a dashboard for a "
+ "configuration" },
+ { "-SP <script>, --script-new-process <script>", "Execute a dashboard for a "
+ "configuration" },
+ { "-A <file>, --add-notes <file>", "Add a notes file with submission" },
+ { "-I [Start,End,Stride,test#,test#|Test file], --tests-information",
+ "Run a specific number of tests by number." },
+ { "-U, --union", "Take the Union of -I and -R" },
+ { "--rerun-failed", "Run only the tests that failed previously" },
+ { "--repeat-until-fail <n>", "Require each test to run <n> "
+ "times without failing in order to pass" },
+ { "--max-width <width>", "Set the max width for a test name to output" },
+ { "--interactive-debug-mode [0|1]", "Set the interactive mode to 0 or 1." },
+ { "--no-label-summary", "Disable timing summary information for labels." },
+ { "--build-and-test", "Configure, build and run a test." },
+ { "--build-target", "Specify a specific target to build." },
+ { "--build-nocmake", "Run the build without running cmake first." },
+ { "--build-run-dir", "Specify directory to run programs from." },
+ { "--build-two-config", "Run CMake twice" },
+ { "--build-exe-dir", "Specify the directory for the executable." },
+ { "--build-generator", "Specify the generator to use." },
+ { "--build-generator-platform", "Specify the generator-specific platform." },
+ { "--build-generator-toolset", "Specify the generator-specific toolset." },
+ { "--build-project", "Specify the name of the project to build." },
+ { "--build-makeprogram", "Specify the make program to use." },
+ { "--build-noclean", "Skip the make clean step." },
+ { "--build-config-sample",
+ "A sample executable to use to determine the configuration" },
+ { "--build-options", "Add extra options to the build step." },
+
+ { "--test-command", "The test to run with the --build-and-test option." },
+ { "--test-timeout", "The time limit in seconds, internal use only." },
+ { "--test-load", "CPU load threshold for starting new parallel tests." },
+ { "--tomorrow-tag", "Nightly or experimental starts with next day tag." },
+ { "--ctest-config", "The configuration file used to initialize CTest state "
+ "when submitting dashboards." },
+ { "--overwrite", "Overwrite CTest configuration option." },
+ { "--extra-submit <file>[;<file>]", "Submit extra files to the dashboard." },
+ { "--force-new-ctest-process",
+ "Run child CTest instances as new processes" },
+ { "--schedule-random", "Use a random order for scheduling tests" },
+ { "--submit-index",
+ "Submit individual dashboard tests with specific index" },
+ { "--timeout <seconds>", "Set a global timeout on all tests." },
+ { "--stop-time <time>",
+ "Set a time at which all tests should stop running." },
+ { "--http1.0", "Submit using HTTP 1.0." },
+ { "--no-compress-output", "Do not compress test output when submitting." },
+ { "--print-labels", "Print all available test labels." },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+// this is a test driver program for cmCTest.
+int main(int argc, char const* const* argv)
+{
+ cmsys::Encoding::CommandLineArguments encoding_args =
+ cmsys::Encoding::CommandLineArguments::Main(argc, argv);
+ argc = encoding_args.argc();
+ argv = encoding_args.argv();
+
+ cmSystemTools::DoNotInheritStdPipes();
+ cmSystemTools::EnableMSVCDebugHook();
+ cmSystemTools::FindCMakeResources(argv[0]);
+
+ // Dispatch 'ctest --launch' mode directly.
+ if (argc >= 2 && strcmp(argv[1], "--launch") == 0) {
+ return cmCTestLaunch::Main(argc, argv);
+ }
+
+ cmCTest inst;
+
+ if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
+ cmCTestLog(&inst, ERROR_MESSAGE,
+ "Current working directory cannot be established."
+ << std::endl);
+ return 1;
+ }
+
+ // If there is a testing input file, check for documentation options
+ // only if there are actually arguments. We want running without
+ // arguments to run tests.
+ if (argc > 1 ||
+ !(cmSystemTools::FileExists("CTestTestfile.cmake") ||
+ cmSystemTools::FileExists("DartTestfile.txt"))) {
+ if (argc == 1) {
+ cmCTestLog(&inst, ERROR_MESSAGE, "*********************************"
+ << std::endl
+ << "No test configuration file found!" << std::endl
+ << "*********************************" << std::endl);
+ }
+ cmDocumentation doc;
+ doc.addCTestStandardDocSections();
+ if (doc.CheckOptions(argc, argv)) {
+ cmake hcm;
+ hcm.SetHomeDirectory("");
+ hcm.SetHomeOutputDirectory("");
+ hcm.AddCMakePaths();
+
+ // Construct and print requested documentation.
+ cmCTestScriptHandler* ch =
+ static_cast<cmCTestScriptHandler*>(inst.GetHandler("script"));
+ ch->CreateCMake();
+
+ doc.SetShowGenerators(false);
+ doc.SetName("ctest");
+ doc.SetSection("Name", cmDocumentationName);
+ doc.SetSection("Usage", cmDocumentationUsage);
+ doc.PrependSection("Options", cmDocumentationOptions);
+#ifdef cout
+#undef cout
+#endif
+ return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
+#define cout no_cout_use_cmCTestLog
+ }
+ }
+
+ // copy the args to a vector
+ std::vector<std::string> args;
+ for (int i = 0; i < argc; ++i) {
+ args.push_back(argv[i]);
+ }
+ // run ctest
+ std::string output;
+ int res = inst.Run(args, &output);
+ cmCTestLog(&inst, OUTPUT, output);
+
+ return res;
+}
diff --git a/Source/kwsys/.gitattributes b/Source/kwsys/.gitattributes
new file mode 100644
index 0000000..a9c4e77
--- /dev/null
+++ b/Source/kwsys/.gitattributes
@@ -0,0 +1,12 @@
+.git* export-ignore
+
+/CONTRIBUTING.rst conflict-marker-size=78
+
+*.c whitespace=tab-in-indent,no-lf-at-eof
+*.h whitespace=tab-in-indent,no-lf-at-eof
+*.h.in whitespace=tab-in-indent,no-lf-at-eof
+*.cxx whitespace=tab-in-indent,no-lf-at-eof
+*.hxx whitespace=tab-in-indent,no-lf-at-eof
+*.hxx.in whitespace=tab-in-indent,no-lf-at-eof
+*.txt whitespace=tab-in-indent,no-lf-at-eof
+*.cmake whitespace=tab-in-indent,no-lf-at-eof
diff --git a/Source/kwsys/Base64.c b/Source/kwsys/Base64.c
new file mode 100644
index 0000000..4b8ede2
--- /dev/null
+++ b/Source/kwsys/Base64.c
@@ -0,0 +1,279 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Base64.h)
+
+/* Work-around CMake dependency scanning limitation. This must
+ duplicate the above list of headers. */
+#if 0
+# include "Base64.h.in"
+#endif
+
+/*--------------------------------------------------------------------------*/
+static const unsigned char kwsysBase64EncodeTable[65] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+"abcdefghijklmnopqrstuvwxyz"
+"0123456789+/";
+
+/*--------------------------------------------------------------------------*/
+static const unsigned char kwsysBase64DecodeTable[256] =
+{
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0x3E,0xFF,0xFF,0xFF,0x3F,
+ 0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,
+ 0x3C,0x3D,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
+ 0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,
+ 0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,
+ 0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
+ 0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,
+ 0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
+ 0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,
+ 0x31,0x32,0x33,0xFF,0xFF,0xFF,0xFF,0xFF,
+ /*------------------------------------*/
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+};
+
+/*--------------------------------------------------------------------------*/
+static unsigned char kwsysBase64EncodeChar(int c)
+{
+ return kwsysBase64EncodeTable[(unsigned char)c];
+}
+
+/*--------------------------------------------------------------------------*/
+static unsigned char kwsysBase64DecodeChar(unsigned char c)
+{
+ return kwsysBase64DecodeTable[c];
+}
+
+/*--------------------------------------------------------------------------*/
+/* Encode 3 bytes into a 4 byte string. */
+void kwsysBase64_Encode3(const unsigned char *src, unsigned char *dest)
+{
+ dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F);
+ dest[1] = kwsysBase64EncodeChar(((src[0] << 4) & 0x30)|((src[1] >> 4) & 0x0F));
+ dest[2] = kwsysBase64EncodeChar(((src[1] << 2) & 0x3C)|((src[2] >> 6) & 0x03));
+ dest[3] = kwsysBase64EncodeChar(src[2] & 0x3F);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Encode 2 bytes into a 4 byte string. */
+void kwsysBase64_Encode2(const unsigned char *src, unsigned char *dest)
+{
+ dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F);
+ dest[1] = kwsysBase64EncodeChar(((src[0] << 4) & 0x30)|((src[1] >> 4) & 0x0F));
+ dest[2] = kwsysBase64EncodeChar(((src[1] << 2) & 0x3C));
+ dest[3] = '=';
+}
+
+/*--------------------------------------------------------------------------*/
+/* Encode 1 bytes into a 4 byte string. */
+void kwsysBase64_Encode1(const unsigned char *src, unsigned char *dest)
+{
+ dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F);
+ dest[1] = kwsysBase64EncodeChar(((src[0] << 4) & 0x30));
+ dest[2] = '=';
+ dest[3] = '=';
+}
+
+/*--------------------------------------------------------------------------*/
+/* Encode 'length' bytes from the input buffer and store the
+ encoded stream into the output buffer. Return the length of the encoded
+ buffer (output). Note that the output buffer must be allocated by the caller
+ (length * 1.5 should be a safe estimate). If 'mark_end' is true than an
+ extra set of 4 bytes is added to the end of the stream if the input is a
+ multiple of 3 bytes. These bytes are invalid chars and therefore they will
+ stop the decoder thus enabling the caller to decode a stream without
+ actually knowing how much data to expect (if the input is not a multiple of
+ 3 bytes then the extra padding needed to complete the encode 4 bytes will
+ stop the decoding anyway). */
+size_t kwsysBase64_Encode(const unsigned char *input,
+ size_t length,
+ unsigned char *output,
+ int mark_end)
+{
+ const unsigned char *ptr = input;
+ const unsigned char *end = input + length;
+ unsigned char *optr = output;
+
+ /* Encode complete triplet */
+
+ while ((end - ptr) >= 3)
+ {
+ kwsysBase64_Encode3(ptr, optr);
+ ptr += 3;
+ optr += 4;
+ }
+
+ /* Encodes a 2-byte ending into 3 bytes and 1 pad byte and writes. */
+
+ if (end - ptr == 2)
+ {
+ kwsysBase64_Encode2(ptr, optr);
+ optr += 4;
+ }
+
+ /* Encodes a 1-byte ending into 2 bytes and 2 pad bytes */
+
+ else if (end - ptr == 1)
+ {
+ kwsysBase64_Encode1(ptr, optr);
+ optr += 4;
+ }
+
+ /* Do we need to mark the end */
+
+ else if (mark_end)
+ {
+ optr[0] = optr[1] = optr[2] = optr[3] = '=';
+ optr += 4;
+ }
+
+ return (size_t)(optr - output);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Decode 4 bytes into a 3 byte string. */
+int kwsysBase64_Decode3(const unsigned char *src, unsigned char *dest)
+{
+ unsigned char d0, d1, d2, d3;
+
+ d0 = kwsysBase64DecodeChar(src[0]);
+ d1 = kwsysBase64DecodeChar(src[1]);
+ d2 = kwsysBase64DecodeChar(src[2]);
+ d3 = kwsysBase64DecodeChar(src[3]);
+
+ /* Make sure all characters were valid */
+
+ if (d0 == 0xFF || d1 == 0xFF || d2 == 0xFF || d3 == 0xFF)
+ {
+ return 0;
+ }
+
+ /* Decode the 3 bytes */
+
+ dest[0] = (unsigned char)(((d0 << 2) & 0xFC) | ((d1 >> 4) & 0x03));
+ dest[1] = (unsigned char)(((d1 << 4) & 0xF0) | ((d2 >> 2) & 0x0F));
+ dest[2] = (unsigned char)(((d2 << 6) & 0xC0) | ((d3 >> 0) & 0x3F));
+
+ /* Return the number of bytes actually decoded */
+
+ if (src[2] == '=')
+ {
+ return 1;
+ }
+ if (src[3] == '=')
+ {
+ return 2;
+ }
+ return 3;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Decode bytes from the input buffer and store the decoded stream
+ into the output buffer until 'length' bytes have been decoded. Return the
+ real length of the decoded stream (which should be equal to 'length'). Note
+ that the output buffer must be allocated by the caller. If
+ 'max_input_length' is not null, then it specifies the number of encoded
+ bytes that should be at most read from the input buffer. In that case the
+ 'length' parameter is ignored. This enables the caller to decode a stream
+ without actually knowing how much decoded data to expect (of course, the
+ buffer must be large enough). */
+size_t kwsysBase64_Decode(const unsigned char *input,
+ size_t length,
+ unsigned char *output,
+ size_t max_input_length)
+{
+ const unsigned char *ptr = input;
+ unsigned char *optr = output;
+
+ /* Decode complete triplet */
+
+ if (max_input_length)
+ {
+ const unsigned char *end = input + max_input_length;
+ while (ptr < end)
+ {
+ int len = kwsysBase64_Decode3(ptr, optr);
+ optr += len;
+ if(len < 3)
+ {
+ return (size_t)(optr - output);
+ }
+ ptr += 4;
+ }
+ }
+ else
+ {
+ unsigned char *oend = output + length;
+ while ((oend - optr) >= 3)
+ {
+ int len = kwsysBase64_Decode3(ptr, optr);
+ optr += len;
+ if(len < 3)
+ {
+ return (size_t)(optr - output);
+ }
+ ptr += 4;
+ }
+
+ /* Decode the last triplet */
+
+ if (oend - optr == 2)
+ {
+ unsigned char temp[3];
+ int len = kwsysBase64_Decode3(ptr, temp);
+ if(len >= 2)
+ {
+ optr[0] = temp[0];
+ optr[1] = temp[1];
+ optr += 2;
+ }
+ else if(len > 0)
+ {
+ optr[0] = temp[0];
+ optr += 1;
+ }
+ }
+ else if (oend - optr == 1)
+ {
+ unsigned char temp[3];
+ int len = kwsysBase64_Decode3(ptr, temp);
+ if(len > 0)
+ {
+ optr[0] = temp[0];
+ optr += 1;
+ }
+ }
+ }
+
+ return (size_t)(optr - output);
+}
diff --git a/Source/kwsys/Base64.h.in b/Source/kwsys/Base64.h.in
new file mode 100644
index 0000000..36ed3cc
--- /dev/null
+++ b/Source/kwsys/Base64.h.in
@@ -0,0 +1,122 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_Base64_h
+#define @KWSYS_NAMESPACE@_Base64_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+#include <stddef.h> /* size_t */
+
+/* Redefine all public interface symbol names to be in the proper
+ namespace. These macros are used internally to kwsys only, and are
+ not visible to user code. Use kwsysHeaderDump.pl to reproduce
+ these macros after making changes to the interface. */
+#if !defined(KWSYS_NAMESPACE)
+# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# define kwsysBase64 kwsys_ns(Base64)
+# define kwsysBase64_Decode kwsys_ns(Base64_Decode)
+# define kwsysBase64_Decode3 kwsys_ns(Base64_Decode3)
+# define kwsysBase64_Encode kwsys_ns(Base64_Encode)
+# define kwsysBase64_Encode1 kwsys_ns(Base64_Encode1)
+# define kwsysBase64_Encode2 kwsys_ns(Base64_Encode2)
+# define kwsysBase64_Encode3 kwsys_ns(Base64_Encode3)
+#endif
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/**
+ * Encode 3 bytes into a 4 byte string.
+ */
+kwsysEXPORT void kwsysBase64_Encode3(const unsigned char *src,
+ unsigned char *dest);
+
+/**
+ * Encode 2 bytes into a 4 byte string.
+ */
+kwsysEXPORT void kwsysBase64_Encode2(const unsigned char *src,
+ unsigned char *dest);
+
+/**
+ * Encode 1 bytes into a 4 byte string.
+ */
+kwsysEXPORT void kwsysBase64_Encode1(const unsigned char *src,
+ unsigned char *dest);
+
+/**
+ * Encode 'length' bytes from the input buffer and store the encoded
+ * stream into the output buffer. Return the length of the encoded
+ * buffer (output). Note that the output buffer must be allocated by
+ * the caller (length * 1.5 should be a safe estimate). If 'mark_end'
+ * is true than an extra set of 4 bytes is added to the end of the
+ * stream if the input is a multiple of 3 bytes. These bytes are
+ * invalid chars and therefore they will stop the decoder thus
+ * enabling the caller to decode a stream without actually knowing how
+ * much data to expect (if the input is not a multiple of 3 bytes then
+ * the extra padding needed to complete the encode 4 bytes will stop
+ * the decoding anyway).
+ */
+kwsysEXPORT size_t kwsysBase64_Encode(const unsigned char *input,
+ size_t length,
+ unsigned char *output,
+ int mark_end);
+
+/**
+ * Decode 4 bytes into a 3 byte string. Returns the number of bytes
+ * actually decoded.
+ */
+kwsysEXPORT int kwsysBase64_Decode3(const unsigned char *src,
+ unsigned char *dest);
+
+/**
+ * Decode bytes from the input buffer and store the decoded stream
+ * into the output buffer until 'length' bytes have been decoded.
+ * Return the real length of the decoded stream (which should be equal
+ * to 'length'). Note that the output buffer must be allocated by the
+ * caller. If 'max_input_length' is not null, then it specifies the
+ * number of encoded bytes that should be at most read from the input
+ * buffer. In that case the 'length' parameter is ignored. This
+ * enables the caller to decode a stream without actually knowing how
+ * much decoded data to expect (of course, the buffer must be large
+ * enough).
+ */
+kwsysEXPORT size_t kwsysBase64_Decode(const unsigned char *input,
+ size_t length,
+ unsigned char *output,
+ size_t max_input_length);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+ Otherwise, undefine them to keep the namespace clean. */
+#if !defined(KWSYS_NAMESPACE)
+# undef kwsys_ns
+# undef kwsysEXPORT
+# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# undef kwsysBase64
+# undef kwsysBase64_Decode
+# undef kwsysBase64_Decode3
+# undef kwsysBase64_Encode
+# undef kwsysBase64_Encode1
+# undef kwsysBase64_Encode2
+# undef kwsysBase64_Encode3
+# endif
+#endif
+
+#endif
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
new file mode 100644
index 0000000..39b03b3
--- /dev/null
+++ b/Source/kwsys/CMakeLists.txt
@@ -0,0 +1,1038 @@
+#=============================================================================
+# KWSys - Kitware System Library
+# Copyright 2000-2011 Kitware, Inc., Insight Software Consortium
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# The Kitware System Library is intended to be included in other
+# projects. It is completely configurable in that the library's
+# namespace can be configured and the components that are included can
+# be selected invididually.
+
+# Typical usage is to import the kwsys directory tree into a
+# subdirectory under a parent project and enable the classes that will
+# be used. All classes are disabled by default. The CMake listfile
+# above this one configures the library as follows:
+#
+# SET(KWSYS_NAMESPACE foosys)
+# SET(KWSYS_USE_Directory 1) # Enable Directory class.
+# SUBDIRS(kwsys)
+#
+# Optional settings are as follows:
+#
+# KWSYS_HEADER_ROOT = The directory into which to generate the kwsys headers.
+# A directory called "${KWSYS_NAMESPACE}" will be
+# created under this root directory to hold the files.
+#
+# Example:
+#
+# SET(KWSYS_HEADER_ROOT ${PROJECT_BINARY_DIR})
+# INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR})
+#
+# Optional settings to setup install rules are as follows:
+#
+# KWSYS_INSTALL_BIN_DIR = The installation target directories into
+# KWSYS_INSTALL_LIB_DIR which the libraries and headers from
+# KWSYS_INSTALL_INCLUDE_DIR kwsys should be installed by a "make install".
+# The values should be specified relative to
+# the installation prefix and NOT start with '/'.
+# KWSYS_INSTALL_DOC_DIR = The installation target directory for documentation
+# such as copyright information.
+#
+# KWSYS_INSTALL_COMPONENT_NAME_RUNTIME = Name of runtime and development
+# KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT installation components.
+# If not given the install rules
+# will not be in any component.
+#
+# KWSYS_INSTALL_EXPORT_NAME = The EXPORT option value for install(TARGETS) calls.
+#
+# Example:
+#
+# SET(KWSYS_INSTALL_BIN_DIR bin)
+# SET(KWSYS_INSTALL_LIB_DIR lib)
+# SET(KWSYS_INSTALL_INCLUDE_DIR include)
+# SET(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME Runtime)
+# SET(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT Development)
+
+# Once configured, kwsys should be used as follows from C or C++ code:
+#
+# #include <foosys/Directory.hxx>
+# ...
+# foosys::Directory directory;
+#
+
+# NOTE: This library is intended for internal use by Kitware-driven
+# projects. In order to keep it simple no attempt will be made to
+# maintain backward compatibility when changes are made to KWSys.
+# When an incompatible change is made Kitware's projects that use
+# KWSys will be fixed, but no notification will necessarily be sent to
+# any outside mailing list and no documentation of the change will be
+# written.
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6.3 FATAL_ERROR)
+IF(POLICY CMP0025)
+ CMAKE_POLICY(SET CMP0025 NEW)
+ENDIF()
+IF(POLICY CMP0056)
+ CMAKE_POLICY(SET CMP0056 NEW)
+ENDIF()
+SET(CMAKE_LEGACY_CYGWIN_WIN32 0)
+
+#-----------------------------------------------------------------------------
+# If a namespace is not specified, use "kwsys" and enable testing.
+# This should be the case only when kwsys is not included inside
+# another project and is being tested.
+IF(NOT KWSYS_NAMESPACE)
+ SET(KWSYS_NAMESPACE "kwsys")
+ SET(KWSYS_STANDALONE 1)
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# The project name is that of the specified namespace.
+PROJECT(${KWSYS_NAMESPACE})
+
+# Tell CMake how to follow dependencies of sources in this directory.
+SET_PROPERTY(DIRECTORY
+ PROPERTY IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
+ "KWSYS_HEADER(%)=<${KWSYS_NAMESPACE}/%>"
+ )
+
+# Select library components.
+IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
+ SET(KWSYS_ENABLE_C 1)
+ # Enable all components.
+ SET(KWSYS_USE_Base64 1)
+ SET(KWSYS_USE_Directory 1)
+ SET(KWSYS_USE_DynamicLoader 1)
+ SET(KWSYS_USE_Encoding 1)
+ SET(KWSYS_USE_Glob 1)
+ SET(KWSYS_USE_MD5 1)
+ SET(KWSYS_USE_Process 1)
+ SET(KWSYS_USE_RegularExpression 1)
+ SET(KWSYS_USE_System 1)
+ SET(KWSYS_USE_SystemTools 1)
+ SET(KWSYS_USE_CommandLineArguments 1)
+ SET(KWSYS_USE_Terminal 1)
+ SET(KWSYS_USE_IOStream 1)
+ SET(KWSYS_USE_FStream 1)
+ SET(KWSYS_USE_String 1)
+ SET(KWSYS_USE_SystemInformation 1)
+ENDIF()
+
+# Enforce component dependencies.
+IF(KWSYS_USE_SystemTools)
+ SET(KWSYS_USE_Directory 1)
+ SET(KWSYS_USE_FStream 1)
+ SET(KWSYS_USE_Encoding 1)
+ENDIF()
+IF(KWSYS_USE_Glob)
+ SET(KWSYS_USE_Directory 1)
+ SET(KWSYS_USE_SystemTools 1)
+ SET(KWSYS_USE_RegularExpression 1)
+ SET(KWSYS_USE_FStream 1)
+ SET(KWSYS_USE_Encoding 1)
+ENDIF()
+IF(KWSYS_USE_Process)
+ SET(KWSYS_USE_System 1)
+ SET(KWSYS_USE_Encoding 1)
+ENDIF()
+IF(KWSYS_USE_SystemInformation)
+ SET(KWSYS_USE_Process 1)
+ENDIF()
+IF(KWSYS_USE_System)
+ SET(KWSYS_USE_Encoding 1)
+ENDIF()
+IF(KWSYS_USE_Directory)
+ SET(KWSYS_USE_Encoding 1)
+ENDIF()
+IF(KWSYS_USE_FStream)
+ 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)
+ENDIF()
+
+# Enable testing if building standalone.
+IF(KWSYS_STANDALONE)
+ INCLUDE(Dart)
+ MARK_AS_ADVANCED(BUILD_TESTING DART_ROOT TCL_TCLSH)
+ IF(BUILD_TESTING)
+ ENABLE_TESTING()
+ ENDIF()
+ENDIF()
+
+# Include helper macros.
+INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformTests.cmake)
+INCLUDE(CheckTypeSize)
+
+# Do full dependency headers.
+INCLUDE_REGULAR_EXPRESSION("^.*$")
+
+# Use new KWSYS_INSTALL_*_DIR variable names to control installation.
+# Take defaults from the old names. Note that there was no old name
+# for the bin dir, so we take the old lib dir name so DLLs will be
+# installed in a compatible way for old code.
+IF(NOT KWSYS_INSTALL_INCLUDE_DIR)
+ STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_INCLUDE_DIR
+ "${KWSYS_HEADER_INSTALL_DIR}")
+ENDIF()
+IF(NOT KWSYS_INSTALL_LIB_DIR)
+ STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_LIB_DIR
+ "${KWSYS_LIBRARY_INSTALL_DIR}")
+ENDIF()
+IF(NOT KWSYS_INSTALL_BIN_DIR)
+ STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_BIN_DIR
+ "${KWSYS_LIBRARY_INSTALL_DIR}")
+ENDIF()
+
+# Setup header install rules.
+SET(KWSYS_INSTALL_INCLUDE_OPTIONS)
+IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT)
+ SET(KWSYS_INSTALL_INCLUDE_OPTIONS ${KWSYS_INSTALL_INCLUDE_OPTIONS}
+ COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT}
+ )
+ENDIF()
+
+# Setup library install rules.
+SET(KWSYS_INSTALL_LIBRARY_RULE)
+IF(KWSYS_INSTALL_LIB_DIR)
+ IF(KWSYS_INSTALL_EXPORT_NAME)
+ LIST(APPEND KWSYS_INSTALL_LIBRARY_RULE EXPORT ${KWSYS_INSTALL_EXPORT_NAME})
+ ENDIF()
+ # Install the shared library to the lib directory.
+ SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+ LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR}
+ )
+ # Assign the shared library to the runtime component.
+ IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
+ SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+ COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
+ )
+ ENDIF()
+
+ # Install the archive to the lib directory.
+ SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+ ARCHIVE DESTINATION ${KWSYS_INSTALL_LIB_DIR}
+ )
+ # Assign the archive to the development component.
+ IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT)
+ SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+ COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT}
+ )
+ ENDIF()
+ENDIF()
+IF(KWSYS_INSTALL_BIN_DIR)
+ # Install the runtime library to the bin directory.
+ SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+ RUNTIME DESTINATION ${KWSYS_INSTALL_BIN_DIR}
+ )
+ # Assign the runtime library to the runtime component.
+ IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
+ SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+ COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
+ )
+ ENDIF()
+ENDIF()
+
+# Do not support old KWSYS_*a_INSTALL_DIR variable names.
+SET(KWSYS_HEADER_INSTALL_DIR)
+SET(KWSYS_LIBRARY_INSTALL_DIR)
+
+# Generated source files will need this header.
+STRING(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}"
+ KWSYS_IN_SOURCE_BUILD)
+IF(NOT KWSYS_IN_SOURCE_BUILD)
+ CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/kwsysPrivate.h
+ ${PROJECT_BINARY_DIR}/kwsysPrivate.h COPYONLY IMMEDIATE)
+ENDIF()
+
+# Select plugin module file name convention.
+IF(NOT KWSYS_DynamicLoader_PREFIX)
+ SET(KWSYS_DynamicLoader_PREFIX ${CMAKE_SHARED_MODULE_PREFIX})
+ENDIF()
+IF(NOT KWSYS_DynamicLoader_SUFFIX)
+ SET(KWSYS_DynamicLoader_SUFFIX ${CMAKE_SHARED_MODULE_SUFFIX})
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# We require ANSI support from the C compiler. Add any needed flags.
+IF(CMAKE_ANSI_CFLAGS)
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ANSI_CFLAGS}")
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# Adjust compiler flags for some platforms.
+IF(NOT CMAKE_COMPILER_IS_GNUCXX)
+ IF(CMAKE_SYSTEM MATCHES "OSF1-V.*")
+ STRING(REGEX MATCH "-timplicit_local"
+ KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL "${CMAKE_CXX_FLAGS}")
+ STRING(REGEX MATCH "-no_implicit_include"
+ KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE "${CMAKE_CXX_FLAGS}")
+ IF(NOT KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local")
+ ENDIF()
+ IF(NOT KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no_implicit_include")
+ ENDIF()
+ ENDIF()
+ IF(CMAKE_SYSTEM MATCHES "HP-UX")
+ SET(KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS "+p")
+ IF(CMAKE_CXX_COMPILER_ID MATCHES "HP")
+ # it is known that version 3.85 fails and 6.25 works without these flags
+ IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4)
+ # use new C++ library and improved template support
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -AA +hpxstd98")
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ENDIF()
+IF(KWSYS_STANDALONE)
+ IF(CMAKE_CXX_COMPILER_ID STREQUAL SunPro)
+ IF(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03")
+ ELSE()
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stlport4")
+ ENDIF()
+ ENDIF()
+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.
+
+# Check existence and uniqueness of long long and __int64.
+KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_LONG_LONG
+ "Checking whether C++ compiler has 'long long'" DIRECT)
+KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS___INT64
+ "Checking whether C++ compiler has '__int64'" DIRECT)
+IF(KWSYS_CXX_HAS___INT64)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_AND___INT64
+ "Checking whether long and __int64 are the same type" DIRECT)
+ IF(KWSYS_CXX_HAS_LONG_LONG)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_LONG_AND___INT64
+ "Checking whether long long and __int64 are the same type" DIRECT)
+ ENDIF()
+ENDIF()
+
+# Enable the "long long" type if it is available. It is standard in
+# C99 and C++03 but not in earlier standards.
+IF(KWSYS_CXX_HAS_LONG_LONG)
+ SET(KWSYS_USE_LONG_LONG 1)
+ELSE()
+ SET(KWSYS_USE_LONG_LONG 0)
+ENDIF()
+
+# Enable the "__int64" type if it is available and unique. It is not
+# standard.
+SET(KWSYS_USE___INT64 0)
+IF(KWSYS_CXX_HAS___INT64)
+ IF(NOT KWSYS_CXX_SAME_LONG_AND___INT64)
+ IF(NOT KWSYS_CXX_SAME_LONG_LONG_AND___INT64)
+ SET(KWSYS_USE___INT64 1)
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+IF(KWSYS_USE_Encoding)
+ # Look for type size helper macros.
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_WSTRING
+ "Checking whether wstring is available" DIRECT)
+ENDIF()
+
+IF(KWSYS_USE_IOStream)
+ # Determine whether iostreams support long long.
+ IF(KWSYS_CXX_HAS_LONG_LONG)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM_LONG_LONG
+ "Checking if istream supports long long" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM_LONG_LONG
+ "Checking if ostream supports long long" DIRECT)
+ ELSE()
+ SET(KWSYS_IOS_HAS_ISTREAM_LONG_LONG 0)
+ SET(KWSYS_IOS_HAS_OSTREAM_LONG_LONG 0)
+ ENDIF()
+ IF(KWSYS_CXX_HAS___INT64)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM___INT64
+ "Checking if istream supports __int64" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM___INT64
+ "Checking if ostream supports __int64" DIRECT)
+ ELSE()
+ SET(KWSYS_IOS_HAS_ISTREAM___INT64 0)
+ SET(KWSYS_IOS_HAS_OSTREAM___INT64 0)
+ ENDIF()
+ENDIF()
+
+IF(KWSYS_NAMESPACE MATCHES "^kwsys$")
+ SET(KWSYS_NAME_IS_KWSYS 1)
+ELSE()
+ SET(KWSYS_NAME_IS_KWSYS 0)
+ENDIF()
+
+# Choose default shared/static build if not specified.
+IF(KWSYS_BUILD_SHARED MATCHES "^KWSYS_BUILD_SHARED$")
+ SET(KWSYS_BUILD_SHARED ${BUILD_SHARED_LIBS})
+ENDIF()
+
+IF(KWSYS_BUILD_SHARED)
+ SET(KWSYS_BUILD_SHARED 1)
+ SET(KWSYS_LIBRARY_TYPE SHARED)
+ELSE()
+ SET(KWSYS_BUILD_SHARED 0)
+ SET(KWSYS_LIBRARY_TYPE STATIC)
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# Configure some implementation details.
+
+KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_PTRDIFF_T
+ "Checking whether C compiler has ptrdiff_t in stddef.h" DIRECT)
+KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_SSIZE_T
+ "Checking whether C compiler has ssize_t in unistd.h" DIRECT)
+SET_SOURCE_FILES_PROPERTIES(ProcessUNIX.c System.c PROPERTIES
+ COMPILE_FLAGS "-DKWSYS_C_HAS_PTRDIFF_T=${KWSYS_C_HAS_PTRDIFF_T} -DKWSYS_C_HAS_SSIZE_T=${KWSYS_C_HAS_SSIZE_T}"
+ )
+
+IF(KWSYS_USE_SystemTools)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_SETENV
+ "Checking whether CXX compiler has setenv" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UNSETENV
+ "Checking whether CXX compiler has unsetenv" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
+ "Checking whether CXX compiler has environ in stdlib.h" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMES
+ "Checking whether CXX compiler has utimes" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMENSAT
+ "Checking whether CXX compiler has utimensat" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIM
+ "Checking whether CXX compiler struct stat has st_mtim member" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIMESPEC
+ "Checking whether CXX compiler struct stat has st_mtimespec member" DIRECT)
+ SET_PROPERTY(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS
+ KWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV}
+ KWSYS_CXX_HAS_UNSETENV=${KWSYS_CXX_HAS_UNSETENV}
+ KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=${KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H}
+ KWSYS_CXX_HAS_UTIMES=${KWSYS_CXX_HAS_UTIMES}
+ KWSYS_CXX_HAS_UTIMENSAT=${KWSYS_CXX_HAS_UTIMENSAT}
+ KWSYS_CXX_STAT_HAS_ST_MTIM=${KWSYS_CXX_STAT_HAS_ST_MTIM}
+ KWSYS_CXX_STAT_HAS_ST_MTIMESPEC=${KWSYS_CXX_STAT_HAS_ST_MTIMESPEC}
+ )
+ENDIF()
+
+IF(KWSYS_USE_SystemInformation)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS SIZEOF_VOID_P=${CMAKE_SIZEOF_VOID_P})
+ IF(NOT CYGWIN)
+ INCLUDE(CheckIncludeFiles)
+ CHECK_INCLUDE_FILES("sys/types.h;ifaddrs.h" KWSYS_SYS_HAS_IFADDRS_H)
+ IF(KWSYS_SYS_HAS_IFADDRS_H)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_SYS_HAS_IFADDRS_H=1)
+ ENDIF()
+ ENDIF()
+ IF(WIN32)
+ INCLUDE(CheckSymbolExists)
+ SET(CMAKE_REQUIRED_LIBRARIES Psapi)
+ CHECK_SYMBOL_EXISTS(GetProcessMemoryInfo "windows.h;psapi.h" KWSYS_SYS_HAS_PSAPI)
+ UNSET(CMAKE_REQUIRED_LIBRARIES)
+ IF(KWSYS_SYS_HAS_PSAPI)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_SYS_HAS_PSAPI=1)
+ IF(MSVC70 OR MSVC71)
+ # Suppress LNK4089: all references to 'PSAPI.DLL' discarded by /OPT:REF
+ SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /IGNORE:4089")
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ IF(CMAKE_SYSTEM MATCHES "HP-UX")
+ CHECK_INCLUDE_FILES("sys/mpctl.h" KWSYS_SYS_HAS_MPCTL_H)
+ IF(KWSYS_SYS_HAS_MPCTL_H)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_SYS_HAS_MPCTL_H=1)
+ ENDIF()
+ ENDIF()
+ IF(CMAKE_SYSTEM MATCHES "BSD")
+ CHECK_INCLUDE_FILES("machine/cpu.h" KWSYS_SYS_HAS_MACHINE_CPU_H)
+ IF(KWSYS_SYS_HAS_MACHINE_CPU_H)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ 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)
+ IF(KWSYS_CXX_HAS_RLIMIT64)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_CXX_HAS_RLIMIT64=1)
+ ENDIF()
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOL
+ "Checking whether CXX compiler has atol" DIRECT)
+ IF(KWSYS_CXX_HAS_ATOL)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOL=1)
+ ENDIF()
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOLL
+ "Checking whether CXX compiler has atoll" DIRECT)
+ IF(KWSYS_CXX_HAS_ATOLL)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOLL=1)
+ ENDIF()
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS__ATOI64
+ "Checking whether CXX compiler has _atoi64" DIRECT)
+ IF(KWSYS_CXX_HAS__ATOI64)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_CXX_HAS__ATOI64=1)
+ ENDIF()
+ IF(UNIX)
+ INCLUDE(CheckIncludeFileCXX)
+ # check for simple stack trace
+ # usually it's in libc but on FreeBSD
+ # it's in libexecinfo
+ FIND_LIBRARY(EXECINFO_LIB "execinfo")
+ MARK_AS_ADVANCED(EXECINFO_LIB)
+ IF (NOT EXECINFO_LIB)
+ SET(EXECINFO_LIB "")
+ ENDIF()
+ CHECK_INCLUDE_FILE_CXX("execinfo.h" KWSYS_CXX_HAS_EXECINFOH)
+ IF (KWSYS_CXX_HAS_EXECINFOH)
+ # we have the backtrace header check if it
+ # can be used with this compiler
+ SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${EXECINFO_LIB})
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BACKTRACE
+ "Checking whether backtrace works with this C++ compiler" DIRECT)
+ SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES)
+ IF (KWSYS_CXX_HAS_BACKTRACE)
+ # backtrace is supported by this system and compiler.
+ # now check for the more advanced capabilities.
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE=1)
+ # check for symbol lookup using dladdr
+ CHECK_INCLUDE_FILE_CXX("dlfcn.h" KWSYS_CXX_HAS_DLFCNH)
+ IF (KWSYS_CXX_HAS_DLFCNH)
+ # we have symbol lookup libraries and headers
+ # check if they can be used with this compiler
+ SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${CMAKE_DL_LIBS})
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_DLADDR
+ "Checking whether dladdr works with this C++ compiler" DIRECT)
+ SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES)
+ IF (KWSYS_CXX_HAS_DLADDR)
+ # symbol lookup is supported by this system
+ # and compiler.
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP=1)
+ ENDIF()
+ ENDIF()
+ # c++ demangling support
+ # check for cxxabi headers
+ CHECK_INCLUDE_FILE_CXX("cxxabi.h" KWSYS_CXX_HAS_CXXABIH)
+ IF (KWSYS_CXX_HAS_CXXABIH)
+ # check if cxxabi can be used with this
+ # system and compiler.
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CXXABI
+ "Checking whether cxxabi works with this C++ compiler" DIRECT)
+ IF (KWSYS_CXX_HAS_CXXABI)
+ # c++ demangle using cxxabi is supported with
+ # this system and compiler
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE=1)
+ ENDIF()
+ ENDIF()
+ # basic backtrace works better with release build
+ # don't bother with advanced features for release
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS_DEBUG KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS_RELWITHDEBINFO KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1)
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ IF(BORLAND)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM
+ "Checking whether Borland CXX compiler supports assembler instructions" DIRECT)
+ IF(KWSYS_CXX_HAS_BORLAND_ASM)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM=1)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM_CPUID
+ "Checking whether Borland CXX compiler supports CPUID assembler instruction" DIRECT)
+ IF(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM_CPUID=1)
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ IF(KWSYS_USE___INT64)
+ SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_USE___INT64=1)
+ ENDIF()
+ IF(KWSYS_USE_LONG_LONG)
+ SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_USE_LONG_LONG=1)
+ ENDIF()
+ IF(KWSYS_IOS_HAS_OSTREAM_LONG_LONG)
+ SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM_LONG_LONG=1)
+ ENDIF()
+ IF(KWSYS_IOS_HAS_OSTREAM___INT64)
+ SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM___INT64=1)
+ ENDIF()
+ IF(KWSYS_BUILD_SHARED)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_BUILD_SHARED=1)
+ ENDIF()
+
+ IF(UNIX AND NOT CYGWIN)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_GETLOADAVG
+ "Checking whether CXX compiler has getloadavg" DIRECT)
+ IF(KWSYS_CXX_HAS_GETLOADAVG)
+ SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_CXX_HAS_GETLOADAVG=1)
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# Choose a directory for the generated headers.
+IF(NOT KWSYS_HEADER_ROOT)
+ SET(KWSYS_HEADER_ROOT "${PROJECT_BINARY_DIR}")
+ENDIF()
+SET(KWSYS_HEADER_DIR "${KWSYS_HEADER_ROOT}/${KWSYS_NAMESPACE}")
+INCLUDE_DIRECTORIES(${KWSYS_HEADER_ROOT})
+
+#-----------------------------------------------------------------------------
+IF(KWSYS_INSTALL_DOC_DIR)
+ # Assign the license to the runtime component since it must be
+ # distributed with binary forms of this software.
+ IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
+ SET(KWSYS_INSTALL_LICENSE_OPTIONS ${KWSYS_INSTALL_LICENSE_OPTIONS}
+ COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
+ )
+ ENDIF()
+
+ # Install the license under the documentation directory.
+ INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt
+ DESTINATION ${KWSYS_INSTALL_DOC_DIR}/${KWSYS_NAMESPACE}
+ ${KWSYS_INSTALL_LICENSE_OPTIONS})
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# Build a list of classes and headers we need to implement the
+# selected components. Initialize with required components.
+SET(KWSYS_CLASSES)
+SET(KWSYS_H_FILES Configure SharedForward)
+SET(KWSYS_HXX_FILES Configure String
+ hashtable hash_fun hash_map hash_set
+ )
+
+# Add selected C++ classes.
+SET(cppclasses
+ Directory DynamicLoader Encoding Glob RegularExpression SystemTools
+ CommandLineArguments IOStream FStream SystemInformation
+ )
+FOREACH(cpp ${cppclasses})
+ IF(KWSYS_USE_${cpp})
+ # Use the corresponding class.
+ SET(KWSYS_CLASSES ${KWSYS_CLASSES} ${cpp})
+
+ # Load component-specific CMake code.
+ IF(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake)
+ INCLUDE(${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake)
+ ENDIF()
+ ENDIF()
+ENDFOREACH()
+
+# Add selected C components.
+FOREACH(c
+ Process Base64 Encoding MD5 Terminal System String
+ )
+ IF(KWSYS_USE_${c})
+ # Use the corresponding header file.
+ SET(KWSYS_H_FILES ${KWSYS_H_FILES} ${c})
+
+ # Load component-specific CMake code.
+ IF(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${c}.cmake)
+ INCLUDE(${PROJECT_SOURCE_DIR}/kwsys${c}.cmake)
+ ENDIF()
+ ENDIF()
+ENDFOREACH()
+
+#-----------------------------------------------------------------------------
+# Build a list of sources for the library based on components that are
+# included.
+SET(KWSYS_C_SRCS)
+SET(KWSYS_CXX_SRCS)
+
+# Add the proper sources for this platform's Process implementation.
+IF(KWSYS_USE_Process)
+ IF(NOT UNIX)
+ # Use the Windows implementation.
+ SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c)
+ ELSE()
+ # Use the UNIX implementation.
+ SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessUNIX.c)
+ ENDIF()
+ENDIF()
+
+# Add selected C sources.
+FOREACH(c Base64 Encoding MD5 Terminal System String)
+ IF(KWSYS_USE_${c})
+ IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}C.c)
+ LIST(APPEND KWSYS_C_SRCS ${c}C.c)
+ ELSE()
+ LIST(APPEND KWSYS_C_SRCS ${c}.c)
+ ENDIF()
+ ENDIF()
+ENDFOREACH()
+
+# Configure headers of C++ classes and construct the list of sources.
+FOREACH(c ${KWSYS_CLASSES})
+ # Add this source to the list of source files for the library.
+ IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}CXX.cxx)
+ LIST(APPEND KWSYS_CXX_SRCS ${c}CXX.cxx)
+ ELSEIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}.cxx)
+ LIST(APPEND KWSYS_CXX_SRCS ${c}.cxx)
+ ENDIF()
+
+ # Configure the header for this class.
+ CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${c}.hxx.in ${KWSYS_HEADER_DIR}/${c}.hxx
+ @ONLY IMMEDIATE)
+ SET(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${c}.hxx)
+
+ # Create an install target for the header.
+ IF(KWSYS_INSTALL_INCLUDE_DIR)
+ INSTALL(FILES ${KWSYS_HEADER_DIR}/${c}.hxx
+ DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
+ ${KWSYS_INSTALL_INCLUDE_OPTIONS})
+ ENDIF()
+ENDFOREACH()
+
+# Configure C headers.
+FOREACH(h ${KWSYS_H_FILES})
+ # Configure the header into the given directory.
+ CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${h}.h.in ${KWSYS_HEADER_DIR}/${h}.h
+ @ONLY IMMEDIATE)
+ SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ${KWSYS_HEADER_DIR}/${h}.h)
+
+ # Create an install target for the header.
+ IF(KWSYS_INSTALL_INCLUDE_DIR)
+ INSTALL(FILES ${KWSYS_HEADER_DIR}/${h}.h
+ DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
+ ${KWSYS_INSTALL_INCLUDE_OPTIONS})
+ ENDIF()
+ENDFOREACH()
+
+# Configure other C++ headers.
+FOREACH(h ${KWSYS_HXX_FILES})
+ # Configure the header into the given directory.
+ CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${h}.hxx.in ${KWSYS_HEADER_DIR}/${h}.hxx
+ @ONLY IMMEDIATE)
+ SET(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${h}.hxx)
+
+ # Create an install target for the header.
+ IF(KWSYS_INSTALL_INCLUDE_DIR)
+ INSTALL(FILES ${KWSYS_HEADER_DIR}/${h}.hxx
+ DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
+ ${KWSYS_INSTALL_INCLUDE_OPTIONS})
+ ENDIF()
+ENDFOREACH()
+
+#-----------------------------------------------------------------------------
+# Add the library with the configured name and list of sources.
+IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS)
+ ADD_LIBRARY(${KWSYS_NAMESPACE} ${KWSYS_LIBRARY_TYPE}
+ ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS})
+ SET_PROPERTY(TARGET ${KWSYS_NAMESPACE} PROPERTY LABELS ${KWSYS_LABELS_LIB})
+ IF(KWSYS_USE_DynamicLoader)
+ IF(UNIX)
+ TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ${CMAKE_DL_LIBS})
+ ENDIF()
+ ENDIF()
+
+ IF(KWSYS_USE_SystemInformation)
+ IF(WIN32)
+ TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ws2_32)
+ IF(KWSYS_SYS_HAS_PSAPI)
+ TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} Psapi)
+ ENDIF()
+ ELSEIF(UNIX)
+ IF (EXECINFO_LIB AND KWSYS_CXX_HAS_BACKTRACE)
+ # backtrace on FreeBSD is not in libc
+ TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ${EXECINFO_LIB})
+ ENDIF()
+ IF (KWSYS_CXX_HAS_DLADDR)
+ # for symbol lookup using dladdr
+ TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ${CMAKE_DL_LIBS})
+ ENDIF()
+ ENDIF()
+ ENDIF()
+
+ # Apply user-defined target properties to the library.
+ IF(KWSYS_PROPERTIES_CXX)
+ SET_TARGET_PROPERTIES(${KWSYS_NAMESPACE} PROPERTIES
+ ${KWSYS_PROPERTIES_CXX}
+ )
+ ENDIF()
+
+ # Create an install target for the library.
+ IF(KWSYS_INSTALL_LIBRARY_RULE)
+ INSTALL(TARGETS ${KWSYS_NAMESPACE} ${KWSYS_INSTALL_LIBRARY_RULE})
+ ENDIF()
+ENDIF()
+
+# Add a C-only library if requested.
+IF(KWSYS_ENABLE_C AND KWSYS_C_SRCS)
+ ADD_LIBRARY(${KWSYS_NAMESPACE}_c ${KWSYS_LIBRARY_TYPE} ${KWSYS_C_SRCS})
+ SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}_c PROPERTY LABELS ${KWSYS_LABELS_LIB})
+
+ # Apply user-defined target properties to the library.
+ IF(KWSYS_PROPERTIES_C)
+ SET_TARGET_PROPERTIES(${KWSYS_NAMESPACE}_c PROPERTIES
+ ${KWSYS_PROPERTIES_C}
+ )
+ ENDIF()
+
+ # Create an install target for the library.
+ IF(KWSYS_INSTALL_LIBRARY_RULE)
+ INSTALL(TARGETS ${KWSYS_NAMESPACE}_c ${KWSYS_INSTALL_LIBRARY_RULE})
+ ENDIF()
+ENDIF()
+
+# For building kwsys itself, we use a macro defined on the command
+# line to configure the namespace in the C and C++ source files.
+ADD_DEFINITIONS("-DKWSYS_NAMESPACE=${KWSYS_NAMESPACE}")
+
+# Disable deprecation warnings for standard C functions.
+IF(MSVC OR (WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "Intel"))
+ ADD_DEFINITIONS(
+ -D_CRT_NONSTDC_NO_DEPRECATE
+ -D_CRT_SECURE_NO_DEPRECATE
+ -D_CRT_SECURE_NO_WARNINGS
+ -D_SCL_SECURE_NO_DEPRECATE
+ )
+ENDIF()
+
+IF(WIN32)
+ # Help enforce the use of wide Windows apis.
+ ADD_DEFINITIONS(-DUNICODE -D_UNICODE)
+ENDIF()
+
+IF(KWSYS_USE_String)
+ # Activate code in "String.c". See the comment in the source.
+ SET_SOURCE_FILES_PROPERTIES(String.c PROPERTIES
+ COMPILE_FLAGS "-DKWSYS_STRING_C")
+ENDIF()
+
+IF(KWSYS_USE_Encoding)
+ # Set default 8 bit encoding in "EndcodingC.c".
+ SET_PROPERTY(SOURCE EncodingC.c APPEND PROPERTY COMPILE_DEFINITIONS
+ KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# Setup testing if not being built as part of another project.
+IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
+ IF(BUILD_TESTING)
+ # Compute the location of executables.
+ SET(EXEC_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+ IF(EXECUTABLE_OUTPUT_PATH)
+ SET(EXEC_DIR "${EXECUTABLE_OUTPUT_PATH}")
+ ENDIF()
+
+ # C tests
+ SET(KWSYS_C_TESTS
+ testEncode
+ testTerminal
+ )
+ IF(KWSYS_STANDALONE)
+ SET(KWSYS_C_TESTS ${KWSYS_C_TESTS} testFail)
+ ENDIF()
+ CREATE_TEST_SOURCELIST(
+ KWSYS_C_TEST_SRCS ${KWSYS_NAMESPACE}TestsC.c
+ ${KWSYS_C_TESTS}
+ )
+ ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestsC ${KWSYS_C_TEST_SRCS})
+ SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsC PROPERTY LABELS ${KWSYS_LABELS_EXE})
+ TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestsC ${KWSYS_NAMESPACE}_c)
+ FOREACH(test ${KWSYS_C_TESTS})
+ ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsC ${test} ${KWSYS_TEST_ARGS_${test}})
+ SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST})
+ ENDFOREACH()
+
+ # C++ tests
+ IF(NOT WATCOM)
+ SET(KWSYS_CXX_TESTS
+ testHashSTL
+ )
+ ENDIF()
+ SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
+ testIOS
+ testSystemTools
+ testCommandLineArguments
+ testCommandLineArguments1
+ )
+ IF(KWSYS_STL_HAS_WSTRING)
+ SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
+ testEncoding
+ )
+ ENDIF()
+ IF(KWSYS_USE_FStream)
+ SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
+ testFStream
+ )
+ ENDIF()
+ IF(KWSYS_USE_SystemInformation)
+ SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation)
+ ENDIF()
+ IF(KWSYS_USE_DynamicLoader)
+ SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testDynamicLoader)
+ # If kwsys contains the DynamicLoader, need extra library
+ 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_NAMESPACE})
+ ENDIF()
+ CREATE_TEST_SOURCELIST(
+ KWSYS_CXX_TEST_SRCS ${KWSYS_NAMESPACE}TestsCxx.cxx
+ ${KWSYS_CXX_TESTS}
+ )
+ ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_CXX_TEST_SRCS})
+ SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY LABELS ${KWSYS_LABELS_EXE})
+ TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_NAMESPACE})
+
+ SET(TEST_SYSTEMTOOLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ SET(TEST_SYSTEMTOOLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+ CONFIGURE_FILE(
+ ${PROJECT_SOURCE_DIR}/testSystemTools.h.in
+ ${PROJECT_BINARY_DIR}/testSystemTools.h)
+ INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR})
+
+ IF(CTEST_TEST_KWSYS)
+ CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/ExtraTest.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake")
+ SET_DIRECTORY_PROPERTIES(PROPERTIES TEST_INCLUDE_FILE "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake")
+ ENDIF()
+
+ SET(KWSYS_TEST_ARGS_testCommandLineArguments
+ --another-bool-variable
+ --long3=opt
+ --set-bool-arg1
+ -SSS ken brad bill andy
+ --some-bool-variable=true
+ --some-double-variable12.5
+ --some-int-variable 14
+ "--some-string-variable=test string with space"
+ --some-multi-argument 5 1 8 3 7 1 3 9 7 1
+ -N 12.5 -SS=andy -N 1.31 -N 22
+ -SS=bill -BBtrue -SS=brad
+ -BBtrue
+ -BBfalse
+ -SS=ken
+ -A
+ -C=test
+ --long2 hello
+ )
+ SET(KWSYS_TEST_ARGS_testCommandLineArguments1
+ --ignored
+ -n 24
+ --second-ignored
+ "-m=test value"
+ third-ignored
+ -p
+ some junk at the end
+ )
+ FOREACH(test ${KWSYS_CXX_TESTS})
+ ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsCxx ${test} ${KWSYS_TEST_ARGS_${test}})
+ SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST})
+ ENDFOREACH()
+
+ # Process tests.
+ ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestProcess testProcess.c)
+ SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestProcess PROPERTY LABELS ${KWSYS_LABELS_EXE})
+ TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestProcess ${KWSYS_NAMESPACE}_c)
+ IF(NOT CYGWIN)
+ SET(KWSYS_TEST_PROCESS_7 7)
+ ENDIF()
+ FOREACH(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7} 9 10)
+ ADD_TEST(kwsys.testProcess-${n} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestProcess ${n})
+ SET_PROPERTY(TEST kwsys.testProcess-${n} PROPERTY LABELS ${KWSYS_LABELS_TEST})
+ SET_TESTS_PROPERTIES(kwsys.testProcess-${n} PROPERTIES TIMEOUT 120)
+ ENDFOREACH()
+
+ # Some Apple compilers produce bad optimizations in this source.
+ IF(APPLE AND CMAKE_C_COMPILER_ID MATCHES "^(GNU|LLVM)$")
+ SET_SOURCE_FILES_PROPERTIES(testProcess.c PROPERTIES COMPILE_FLAGS -O0)
+ ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "XL")
+ # Tell IBM XL not to warn about our test infinite loop
+ SET_PROPERTY(SOURCE testProcess.c PROPERTY COMPILE_FLAGS -qsuppress=1500-010)
+ ENDIF()
+
+ # Test SharedForward
+ CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/testSharedForward.c.in
+ ${PROJECT_BINARY_DIR}/testSharedForward.c @ONLY IMMEDIATE)
+ ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestSharedForward
+ ${PROJECT_BINARY_DIR}/testSharedForward.c)
+ SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestSharedForward PROPERTY LABELS ${KWSYS_LABELS_EXE})
+ ADD_DEPENDENCIES(${KWSYS_NAMESPACE}TestSharedForward ${KWSYS_NAMESPACE}_c)
+ ADD_TEST(kwsys.testSharedForward ${EXEC_DIR}/${KWSYS_NAMESPACE}TestSharedForward 1)
+ SET_PROPERTY(TEST kwsys.testSharedForward PROPERTY LABELS ${KWSYS_LABELS_TEST})
+
+ # Configure some test properties.
+ IF(KWSYS_STANDALONE)
+ # We expect test to fail
+ SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES WILL_FAIL ON)
+ GET_TEST_PROPERTY(kwsys.testFail WILL_FAIL wfv)
+ SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES MEASUREMENT "Some Key=Some Value")
+ MESSAGE(STATUS "GET_TEST_PROPERTY returned: ${wfv}")
+ ENDIF()
+
+ # Set up ctest custom configuration file.
+ CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/CTestCustom.cmake.in
+ ${PROJECT_BINARY_DIR}/CTestCustom.cmake @ONLY)
+
+ # Suppress known consistent failures on buggy systems.
+ IF(KWSYS_TEST_BOGUS_FAILURES)
+ SET_TESTS_PROPERTIES(${KWSYS_TEST_BOGUS_FAILURES} PROPERTIES WILL_FAIL ON)
+ ENDIF()
+
+ ENDIF()
+ENDIF()
diff --git a/Source/kwsys/CONTRIBUTING.rst b/Source/kwsys/CONTRIBUTING.rst
new file mode 100644
index 0000000..960eea4
--- /dev/null
+++ b/Source/kwsys/CONTRIBUTING.rst
@@ -0,0 +1,35 @@
+Contributing to KWSys
+*********************
+
+Overview
+========
+
+KWSys is kept in its own Git repository and shared by several projects
+via copies in their source trees. Changes to KWSys should not be made
+directly in a host project, except perhaps in maintenance branches.
+
+Please visit
+
+ http://public.kitware.com/Wiki/KWSys/Git
+
+to contribute changes directly to KWSys upstream. Once changes are
+reviewed, tested, and integrated there then the copies of KWSys within
+dependent projects can be updated to get the changes.
+
+Issues
+======
+
+KWSys has no independent issue tracker. After encountering an issue
+(bug) please try to submit a patch using the above instructions.
+Otherwise please report the issue to the tracker for the project that
+hosts the copy of KWSys in which the problem was found.
+
+License
+=======
+
+We do not require any formal copyright assignment or contributor license
+agreement. Any contributions intentionally sent upstream are presumed
+to be offered under terms of the OSI-approved BSD 3-clause License.
+See `Copyright.txt`_ for details.
+
+.. _`Copyright.txt`: Copyright.txt
diff --git a/Source/kwsys/CTestConfig.cmake b/Source/kwsys/CTestConfig.cmake
new file mode 100644
index 0000000..d977b47
--- /dev/null
+++ b/Source/kwsys/CTestConfig.cmake
@@ -0,0 +1,17 @@
+#=============================================================================
+# KWSys - Kitware System Library
+# Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+set(CTEST_PROJECT_NAME "KWSys")
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/Source/kwsys/CTestCustom.cmake.in b/Source/kwsys/CTestCustom.cmake.in
new file mode 100644
index 0000000..760221b
--- /dev/null
+++ b/Source/kwsys/CTestCustom.cmake.in
@@ -0,0 +1,14 @@
+# kwsys.testProcess-10 involves sending SIGINT to a child process, which then
+# exits abnormally via a call to _exit(). (On Windows, a call to ExitProcess).
+# Naturally, this results in plenty of memory being "leaked" by this child
+# process - the memory check results are not meaningful in this case.
+#
+# kwsys.testProcess-9 also tests sending SIGINT to a child process. However,
+# normal operation of that test involves the child process timing out, and the
+# host process kills (SIGKILL) it as a result. Since it was SIGKILL'ed, the
+# resulting memory leaks are not logged by valgrind anyway. Therefore, we
+# don't have to exclude it.
+
+list(APPEND CTEST_CUSTOM_MEMCHECK_IGNORE
+ kwsys.testProcess-10
+ )
diff --git a/Source/kwsys/CommandLineArguments.cxx b/Source/kwsys/CommandLineArguments.cxx
new file mode 100644
index 0000000..f713294
--- /dev/null
+++ b/Source/kwsys/CommandLineArguments.cxx
@@ -0,0 +1,857 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(CommandLineArguments.hxx)
+
+#include KWSYS_HEADER(Configure.hxx)
+#include KWSYS_HEADER(String.hxx)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "CommandLineArguments.hxx.in"
+# include "Configure.hxx.in"
+# include "String.hxx.in"
+#endif
+
+#include <vector>
+#include <map>
+#include <set>
+#include <sstream>
+#include <iostream>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _MSC_VER
+# pragma warning (disable: 4786)
+#endif
+
+#if defined(__sgi) && !defined(__GNUC__)
+# pragma set woff 1375 /* base class destructor not virtual */
+#endif
+
+#if 0
+# define CommandLineArguments_DEBUG(x) \
+ std::cout << __LINE__ << " CLA: " << x << std::endl
+#else
+# define CommandLineArguments_DEBUG(x)
+#endif
+
+namespace KWSYS_NAMESPACE
+{
+
+//----------------------------------------------------------------------------
+//============================================================================
+struct CommandLineArgumentsCallbackStructure
+{
+ const char* Argument;
+ int ArgumentType;
+ CommandLineArguments::CallbackType Callback;
+ void* CallData;
+ void* Variable;
+ int VariableType;
+ const char* Help;
+};
+
+class CommandLineArgumentsVectorOfStrings :
+ public std::vector<kwsys::String> {};
+class CommandLineArgumentsSetOfStrings :
+ public std::set<kwsys::String> {};
+class CommandLineArgumentsMapOfStrucs :
+ public std::map<kwsys::String,
+ CommandLineArgumentsCallbackStructure> {};
+
+class CommandLineArgumentsInternal
+{
+public:
+ CommandLineArgumentsInternal()
+ {
+ this->UnknownArgumentCallback = 0;
+ this->ClientData = 0;
+ this->LastArgument = 0;
+ }
+
+ typedef CommandLineArgumentsVectorOfStrings VectorOfStrings;
+ typedef CommandLineArgumentsMapOfStrucs CallbacksMap;
+ typedef kwsys::String String;
+ typedef CommandLineArgumentsSetOfStrings SetOfStrings;
+
+ VectorOfStrings Argv;
+ String Argv0;
+ CallbacksMap Callbacks;
+
+ CommandLineArguments::ErrorCallbackType UnknownArgumentCallback;
+ void* ClientData;
+
+ VectorOfStrings::size_type LastArgument;
+
+ VectorOfStrings UnusedArguments;
+};
+//============================================================================
+//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+CommandLineArguments::CommandLineArguments()
+{
+ this->Internals = new CommandLineArguments::Internal;
+ this->Help = "";
+ this->LineLength = 80;
+ this->StoreUnusedArgumentsFlag = false;
+}
+
+//----------------------------------------------------------------------------
+CommandLineArguments::~CommandLineArguments()
+{
+ delete this->Internals;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::Initialize(int argc, const char* const argv[])
+{
+ int cc;
+
+ this->Initialize();
+ this->Internals->Argv0 = argv[0];
+ for ( cc = 1; cc < argc; cc ++ )
+ {
+ this->ProcessArgument(argv[cc]);
+ }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::Initialize(int argc, char* argv[])
+{
+ this->Initialize(argc, static_cast<const char* const*>(argv));
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::Initialize()
+{
+ this->Internals->Argv.clear();
+ this->Internals->LastArgument = 0;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::ProcessArgument(const char* arg)
+{
+ this->Internals->Argv.push_back(arg);
+}
+
+//----------------------------------------------------------------------------
+bool CommandLineArguments::GetMatchedArguments(
+ std::vector<std::string>* matches,
+ const std::string& arg)
+{
+ matches->clear();
+ CommandLineArguments::Internal::CallbacksMap::iterator it;
+
+ // Does the argument match to any we know about?
+ for ( it = this->Internals->Callbacks.begin();
+ it != this->Internals->Callbacks.end();
+ it ++ )
+ {
+ const CommandLineArguments::Internal::String& parg = it->first;
+ CommandLineArgumentsCallbackStructure *cs = &it->second;
+ if (cs->ArgumentType == CommandLineArguments::NO_ARGUMENT ||
+ cs->ArgumentType == CommandLineArguments::SPACE_ARGUMENT)
+ {
+ if ( arg == parg )
+ {
+ matches->push_back(parg);
+ }
+ }
+ else if ( arg.find( parg ) == 0 )
+ {
+ matches->push_back(parg);
+ }
+ }
+ return !matches->empty();
+}
+
+//----------------------------------------------------------------------------
+int CommandLineArguments::Parse()
+{
+ std::vector<std::string>::size_type cc;
+ std::vector<std::string> matches;
+ if ( this->StoreUnusedArgumentsFlag )
+ {
+ this->Internals->UnusedArguments.clear();
+ }
+ for ( cc = 0; cc < this->Internals->Argv.size(); cc ++ )
+ {
+ const std::string& arg = this->Internals->Argv[cc];
+ CommandLineArguments_DEBUG("Process argument: " << arg);
+ this->Internals->LastArgument = cc;
+ if ( this->GetMatchedArguments(&matches, arg) )
+ {
+ // Ok, we found one or more arguments that match what user specified.
+ // Let's find the longest one.
+ CommandLineArguments::Internal::VectorOfStrings::size_type kk;
+ CommandLineArguments::Internal::VectorOfStrings::size_type maxidx = 0;
+ CommandLineArguments::Internal::String::size_type maxlen = 0;
+ for ( kk = 0; kk < matches.size(); kk ++ )
+ {
+ if ( matches[kk].size() > maxlen )
+ {
+ maxlen = matches[kk].size();
+ maxidx = kk;
+ }
+ }
+ // So, the longest one is probably the right one. Now see if it has any
+ // additional value
+ CommandLineArgumentsCallbackStructure *cs
+ = &this->Internals->Callbacks[matches[maxidx]];
+ const std::string& sarg = matches[maxidx];
+ if ( cs->Argument != sarg )
+ {
+ abort();
+ }
+ switch ( cs->ArgumentType )
+ {
+ case NO_ARGUMENT:
+ // No value
+ if ( !this->PopulateVariable(cs, 0) )
+ {
+ return 0;
+ }
+ break;
+ case SPACE_ARGUMENT:
+ if ( cc == this->Internals->Argv.size()-1 )
+ {
+ this->Internals->LastArgument --;
+ return 0;
+ }
+ CommandLineArguments_DEBUG("This is a space argument: " << arg
+ << " value: " << this->Internals->Argv[cc+1]);
+ // Value is the next argument
+ if ( !this->PopulateVariable(cs, this->Internals->Argv[cc+1].c_str()) )
+ {
+ return 0;
+ }
+ cc ++;
+ break;
+ case EQUAL_ARGUMENT:
+ if ( arg.size() == sarg.size() || arg.at(sarg.size()) != '=' )
+ {
+ this->Internals->LastArgument --;
+ return 0;
+ }
+ // Value is everythng followed the '=' sign
+ if ( !this->PopulateVariable(cs, arg.c_str() + sarg.size() + 1) )
+ {
+ return 0;
+ }
+ break;
+ case CONCAT_ARGUMENT:
+ // Value is whatever follows the argument
+ if ( !this->PopulateVariable(cs, arg.c_str() + sarg.size()) )
+ {
+ return 0;
+ }
+ break;
+ case MULTI_ARGUMENT:
+ // Suck in all the rest of the arguments
+ CommandLineArguments_DEBUG("This is a multi argument: " << arg);
+ for (cc++; cc < this->Internals->Argv.size(); ++ cc )
+ {
+ const std::string& marg = this->Internals->Argv[cc];
+ CommandLineArguments_DEBUG(" check multi argument value: " << marg);
+ if ( this->GetMatchedArguments(&matches, marg) )
+ {
+ CommandLineArguments_DEBUG("End of multi argument " << arg << " with value: " << marg);
+ break;
+ }
+ CommandLineArguments_DEBUG(" populate multi argument value: " << marg);
+ if ( !this->PopulateVariable(cs, marg.c_str()) )
+ {
+ return 0;
+ }
+ }
+ if ( cc != this->Internals->Argv.size() )
+ {
+ CommandLineArguments_DEBUG("Again End of multi argument " << arg);
+ cc--;
+ continue;
+ }
+ break;
+ default:
+ std::cerr << "Got unknown argument type: \"" << cs->ArgumentType << "\"" << std::endl;
+ this->Internals->LastArgument --;
+ return 0;
+ }
+ }
+ else
+ {
+ // Handle unknown arguments
+ if ( this->Internals->UnknownArgumentCallback )
+ {
+ if ( !this->Internals->UnknownArgumentCallback(arg.c_str(),
+ this->Internals->ClientData) )
+ {
+ this->Internals->LastArgument --;
+ return 0;
+ }
+ return 1;
+ }
+ else if ( this->StoreUnusedArgumentsFlag )
+ {
+ CommandLineArguments_DEBUG("Store unused argument " << arg);
+ this->Internals->UnusedArguments.push_back(arg);
+ }
+ else
+ {
+ std::cerr << "Got unknown argument: \"" << arg << "\"" << std::endl;
+ this->Internals->LastArgument --;
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::GetRemainingArguments(int* argc, char*** argv)
+{
+ CommandLineArguments::Internal::VectorOfStrings::size_type size
+ = this->Internals->Argv.size() - this->Internals->LastArgument + 1;
+ CommandLineArguments::Internal::VectorOfStrings::size_type cc;
+
+ // Copy Argv0 as the first argument
+ char** args = new char*[ size ];
+ args[0] = new char[ this->Internals->Argv0.size() + 1 ];
+ strcpy(args[0], this->Internals->Argv0.c_str());
+ int cnt = 1;
+
+ // Copy everything after the LastArgument, since that was not parsed.
+ for ( cc = this->Internals->LastArgument+1;
+ cc < this->Internals->Argv.size(); cc ++ )
+ {
+ args[cnt] = new char[ this->Internals->Argv[cc].size() + 1];
+ strcpy(args[cnt], this->Internals->Argv[cc].c_str());
+ cnt ++;
+ }
+ *argc = cnt;
+ *argv = args;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::GetUnusedArguments(int* argc, char*** argv)
+{
+ CommandLineArguments::Internal::VectorOfStrings::size_type size
+ = this->Internals->UnusedArguments.size() + 1;
+ CommandLineArguments::Internal::VectorOfStrings::size_type cc;
+
+ // Copy Argv0 as the first argument
+ char** args = new char*[ size ];
+ args[0] = new char[ this->Internals->Argv0.size() + 1 ];
+ strcpy(args[0], this->Internals->Argv0.c_str());
+ int cnt = 1;
+
+ // Copy everything after the LastArgument, since that was not parsed.
+ for ( cc = 0;
+ cc < this->Internals->UnusedArguments.size(); cc ++ )
+ {
+ kwsys::String &str = this->Internals->UnusedArguments[cc];
+ args[cnt] = new char[ str.size() + 1];
+ strcpy(args[cnt], str.c_str());
+ cnt ++;
+ }
+ *argc = cnt;
+ *argv = args;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::DeleteRemainingArguments(int argc, char*** argv)
+{
+ int cc;
+ for ( cc = 0; cc < argc; ++ cc )
+ {
+ delete [] (*argv)[cc];
+ }
+ delete [] *argv;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::AddCallback(const char* argument, ArgumentTypeEnum type,
+ CallbackType callback, void* call_data, const char* help)
+{
+ CommandLineArgumentsCallbackStructure s;
+ s.Argument = argument;
+ s.ArgumentType = type;
+ s.Callback = callback;
+ s.CallData = call_data;
+ s.VariableType = CommandLineArguments::NO_VARIABLE_TYPE;
+ s.Variable = 0;
+ s.Help = help;
+
+ this->Internals->Callbacks[argument] = s;
+ this->GenerateHelp();
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
+ VariableTypeEnum vtype, void* variable, const char* help)
+{
+ CommandLineArgumentsCallbackStructure s;
+ s.Argument = argument;
+ s.ArgumentType = type;
+ s.Callback = 0;
+ s.CallData = 0;
+ s.VariableType = vtype;
+ s.Variable = variable;
+ s.Help = help;
+
+ this->Internals->Callbacks[argument] = s;
+ this->GenerateHelp();
+}
+
+//----------------------------------------------------------------------------
+#define CommandLineArgumentsAddArgumentMacro(type, ctype) \
+ void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type, \
+ ctype* variable, const char* help) \
+ { \
+ this->AddArgument(argument, type, CommandLineArguments::type##_TYPE, variable, help); \
+ }
+
+CommandLineArgumentsAddArgumentMacro(BOOL, bool)
+CommandLineArgumentsAddArgumentMacro(INT, int)
+CommandLineArgumentsAddArgumentMacro(DOUBLE, double)
+CommandLineArgumentsAddArgumentMacro(STRING, char*)
+CommandLineArgumentsAddArgumentMacro(STL_STRING, std::string)
+
+CommandLineArgumentsAddArgumentMacro(VECTOR_BOOL, std::vector<bool>)
+CommandLineArgumentsAddArgumentMacro(VECTOR_INT, std::vector<int>)
+CommandLineArgumentsAddArgumentMacro(VECTOR_DOUBLE, std::vector<double>)
+CommandLineArgumentsAddArgumentMacro(VECTOR_STRING, std::vector<char*>)
+CommandLineArgumentsAddArgumentMacro(VECTOR_STL_STRING, std::vector<std::string>)
+
+//----------------------------------------------------------------------------
+#define CommandLineArgumentsAddBooleanArgumentMacro(type, ctype) \
+ void CommandLineArguments::AddBooleanArgument(const char* argument, \
+ ctype* variable, const char* help) \
+ { \
+ this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT, \
+ CommandLineArguments::type##_TYPE, variable, help); \
+ }
+
+CommandLineArgumentsAddBooleanArgumentMacro(BOOL, bool)
+CommandLineArgumentsAddBooleanArgumentMacro(INT, int)
+CommandLineArgumentsAddBooleanArgumentMacro(DOUBLE, double)
+CommandLineArgumentsAddBooleanArgumentMacro(STRING, char*)
+CommandLineArgumentsAddBooleanArgumentMacro(STL_STRING, std::string)
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::SetClientData(void* client_data)
+{
+ this->Internals->ClientData = client_data;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::SetUnknownArgumentCallback(
+ CommandLineArguments::ErrorCallbackType callback)
+{
+ this->Internals->UnknownArgumentCallback = callback;
+}
+
+//----------------------------------------------------------------------------
+const char* CommandLineArguments::GetHelp(const char* arg)
+{
+ CommandLineArguments::Internal::CallbacksMap::iterator it
+ = this->Internals->Callbacks.find(arg);
+ if ( it == this->Internals->Callbacks.end() )
+ {
+ return 0;
+ }
+
+ // Since several arguments may point to the same argument, find the one this
+ // one point to if this one is pointing to another argument.
+ CommandLineArgumentsCallbackStructure *cs = &(it->second);
+ for(;;)
+ {
+ CommandLineArguments::Internal::CallbacksMap::iterator hit
+ = this->Internals->Callbacks.find(cs->Help);
+ if ( hit == this->Internals->Callbacks.end() )
+ {
+ break;
+ }
+ cs = &(hit->second);
+ }
+ return cs->Help;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::SetLineLength(unsigned int ll)
+{
+ if ( ll < 9 || ll > 1000 )
+ {
+ return;
+ }
+ this->LineLength = ll;
+ this->GenerateHelp();
+}
+
+//----------------------------------------------------------------------------
+const char* CommandLineArguments::GetArgv0()
+{
+ return this->Internals->Argv0.c_str();
+}
+
+//----------------------------------------------------------------------------
+unsigned int CommandLineArguments::GetLastArgument()
+{
+ return static_cast<unsigned int>(this->Internals->LastArgument + 1);
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::GenerateHelp()
+{
+ std::ostringstream str;
+
+ // Collapse all arguments into the map of vectors of all arguments that do
+ // the same thing.
+ CommandLineArguments::Internal::CallbacksMap::iterator it;
+ typedef std::map<CommandLineArguments::Internal::String,
+ CommandLineArguments::Internal::SetOfStrings > MapArgs;
+ MapArgs mp;
+ MapArgs::iterator mpit, smpit;
+ for ( it = this->Internals->Callbacks.begin();
+ it != this->Internals->Callbacks.end();
+ it ++ )
+ {
+ CommandLineArgumentsCallbackStructure *cs = &(it->second);
+ mpit = mp.find(cs->Help);
+ if ( mpit != mp.end() )
+ {
+ mpit->second.insert(it->first);
+ mp[it->first].insert(it->first);
+ }
+ else
+ {
+ mp[it->first].insert(it->first);
+ }
+ }
+ for ( it = this->Internals->Callbacks.begin();
+ it != this->Internals->Callbacks.end();
+ it ++ )
+ {
+ CommandLineArgumentsCallbackStructure *cs = &(it->second);
+ mpit = mp.find(cs->Help);
+ if ( mpit != mp.end() )
+ {
+ mpit->second.insert(it->first);
+ smpit = mp.find(it->first);
+ CommandLineArguments::Internal::SetOfStrings::iterator sit;
+ for ( sit = smpit->second.begin(); sit != smpit->second.end(); sit++ )
+ {
+ mpit->second.insert(*sit);
+ }
+ mp.erase(smpit);
+ }
+ else
+ {
+ mp[it->first].insert(it->first);
+ }
+ }
+
+ // Find the length of the longest string
+ CommandLineArguments::Internal::String::size_type maxlen = 0;
+ for ( mpit = mp.begin();
+ mpit != mp.end();
+ mpit ++ )
+ {
+ CommandLineArguments::Internal::SetOfStrings::iterator sit;
+ for ( sit = mpit->second.begin(); sit != mpit->second.end(); sit++ )
+ {
+ CommandLineArguments::Internal::String::size_type clen = sit->size();
+ switch ( this->Internals->Callbacks[*sit].ArgumentType )
+ {
+ case CommandLineArguments::NO_ARGUMENT: clen += 0; break;
+ case CommandLineArguments::CONCAT_ARGUMENT: clen += 3; break;
+ case CommandLineArguments::SPACE_ARGUMENT: clen += 4; break;
+ case CommandLineArguments::EQUAL_ARGUMENT: clen += 4; break;
+ }
+ if ( clen > maxlen )
+ {
+ maxlen = clen;
+ }
+ }
+ }
+
+ // Create format for that string
+ char format[80];
+ sprintf(format, " %%-%us ", static_cast<unsigned int>(maxlen));
+
+ maxlen += 4; // For the space before and after the option
+
+ // Print help for each option
+ for ( mpit = mp.begin();
+ mpit != mp.end();
+ mpit ++ )
+ {
+ CommandLineArguments::Internal::SetOfStrings::iterator sit;
+ for ( sit = mpit->second.begin(); sit != mpit->second.end(); sit++ )
+ {
+ str << std::endl;
+ char argument[100];
+ sprintf(argument, "%s", sit->c_str());
+ switch ( this->Internals->Callbacks[*sit].ArgumentType )
+ {
+ case CommandLineArguments::NO_ARGUMENT: break;
+ case CommandLineArguments::CONCAT_ARGUMENT: strcat(argument, "opt"); break;
+ case CommandLineArguments::SPACE_ARGUMENT: strcat(argument, " opt"); break;
+ case CommandLineArguments::EQUAL_ARGUMENT: strcat(argument, "=opt"); break;
+ case CommandLineArguments::MULTI_ARGUMENT: strcat(argument, " opt opt ..."); break;
+ }
+ char buffer[80];
+ sprintf(buffer, format, argument);
+ str << buffer;
+ }
+ const char* ptr = this->Internals->Callbacks[mpit->first].Help;
+ size_t len = strlen(ptr);
+ int cnt = 0;
+ while ( len > 0)
+ {
+ // If argument with help is longer than line length, split it on previous
+ // space (or tab) and continue on the next line
+ CommandLineArguments::Internal::String::size_type cc;
+ for ( cc = 0; ptr[cc]; cc ++ )
+ {
+ if ( *ptr == ' ' || *ptr == '\t' )
+ {
+ ptr ++;
+ len --;
+ }
+ }
+ if ( cnt > 0 )
+ {
+ for ( cc = 0; cc < maxlen; cc ++ )
+ {
+ str << " ";
+ }
+ }
+ CommandLineArguments::Internal::String::size_type skip = len;
+ if ( skip > this->LineLength - maxlen )
+ {
+ skip = this->LineLength - maxlen;
+ for ( cc = skip-1; cc > 0; cc -- )
+ {
+ if ( ptr[cc] == ' ' || ptr[cc] == '\t' )
+ {
+ break;
+ }
+ }
+ if ( cc != 0 )
+ {
+ skip = cc;
+ }
+ }
+ str.write(ptr, static_cast<std::streamsize>(skip));
+ str << std::endl;
+ ptr += skip;
+ len -= skip;
+ cnt ++;
+ }
+ }
+ /*
+ // This can help debugging help string
+ str << endl;
+ unsigned int cc;
+ for ( cc = 0; cc < this->LineLength; cc ++ )
+ {
+ str << cc % 10;
+ }
+ str << endl;
+ */
+ this->Help = str.str();
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+ bool* variable, const std::string& value)
+{
+ if ( value == "1" || value == "ON" || value == "on" || value == "On" ||
+ value == "TRUE" || value == "true" || value == "True" ||
+ value == "yes" || value == "Yes" || value == "YES" )
+ {
+ *variable = true;
+ }
+ else
+ {
+ *variable = false;
+ }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+ int* variable, const std::string& value)
+{
+ char* res = 0;
+ *variable = static_cast<int>(strtol(value.c_str(), &res, 10));
+ //if ( res && *res )
+ // {
+ // Can handle non-int
+ // }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+ double* variable, const std::string& value)
+{
+ char* res = 0;
+ *variable = strtod(value.c_str(), &res);
+ //if ( res && *res )
+ // {
+ // Can handle non-double
+ // }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+ char** variable, const std::string& value)
+{
+ if ( *variable )
+ {
+ delete [] *variable;
+ *variable = 0;
+ }
+ *variable = new char[ value.size() + 1 ];
+ strcpy(*variable, value.c_str());
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+ std::string* variable, const std::string& value)
+{
+ *variable = value;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+ std::vector<bool>* variable, const std::string& value)
+{
+ bool val = false;
+ if ( value == "1" || value == "ON" || value == "on" || value == "On" ||
+ value == "TRUE" || value == "true" || value == "True" ||
+ value == "yes" || value == "Yes" || value == "YES" )
+ {
+ val = true;
+ }
+ variable->push_back(val);
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+ std::vector<int>* variable, const std::string& value)
+{
+ char* res = 0;
+ variable->push_back(static_cast<int>(strtol(value.c_str(), &res, 10)));
+ //if ( res && *res )
+ // {
+ // Can handle non-int
+ // }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+ std::vector<double>* variable, const std::string& value)
+{
+ char* res = 0;
+ variable->push_back(strtod(value.c_str(), &res));
+ //if ( res && *res )
+ // {
+ // Can handle non-int
+ // }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+ std::vector<char*>* variable, const std::string& value)
+{
+ char* var = new char[ value.size() + 1 ];
+ strcpy(var, value.c_str());
+ variable->push_back(var);
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+ std::vector<std::string>* variable,
+ const std::string& value)
+{
+ variable->push_back(value);
+}
+
+//----------------------------------------------------------------------------
+bool CommandLineArguments::PopulateVariable(CommandLineArgumentsCallbackStructure* cs,
+ const char* value)
+{
+ // Call the callback
+ if ( cs->Callback )
+ {
+ if ( !cs->Callback(cs->Argument, value, cs->CallData) )
+ {
+ this->Internals->LastArgument --;
+ return 0;
+ }
+ }
+ CommandLineArguments_DEBUG("Set argument: " << cs->Argument << " to " << value);
+ if ( cs->Variable )
+ {
+ std::string var = "1";
+ if ( value )
+ {
+ var = value;
+ }
+ switch ( cs->VariableType )
+ {
+ case CommandLineArguments::INT_TYPE:
+ this->PopulateVariable(static_cast<int*>(cs->Variable), var);
+ break;
+ case CommandLineArguments::DOUBLE_TYPE:
+ this->PopulateVariable(static_cast<double*>(cs->Variable), var);
+ break;
+ case CommandLineArguments::STRING_TYPE:
+ this->PopulateVariable(static_cast<char**>(cs->Variable), var);
+ break;
+ case CommandLineArguments::STL_STRING_TYPE:
+ this->PopulateVariable(static_cast<std::string*>(cs->Variable), var);
+ break;
+ case CommandLineArguments::BOOL_TYPE:
+ this->PopulateVariable(static_cast<bool*>(cs->Variable), var);
+ break;
+ case CommandLineArguments::VECTOR_BOOL_TYPE:
+ this->PopulateVariable(static_cast<std::vector<bool>*>(cs->Variable), var);
+ break;
+ case CommandLineArguments::VECTOR_INT_TYPE:
+ this->PopulateVariable(static_cast<std::vector<int>*>(cs->Variable), var);
+ break;
+ case CommandLineArguments::VECTOR_DOUBLE_TYPE:
+ this->PopulateVariable(static_cast<std::vector<double>*>(cs->Variable), var);
+ break;
+ case CommandLineArguments::VECTOR_STRING_TYPE:
+ this->PopulateVariable(static_cast<std::vector<char*>*>(cs->Variable), var);
+ break;
+ case CommandLineArguments::VECTOR_STL_STRING_TYPE:
+ this->PopulateVariable(static_cast<std::vector<std::string>*>(cs->Variable), var);
+ break;
+ default:
+ std::cerr << "Got unknown variable type: \"" << cs->VariableType << "\"" << std::endl;
+ this->Internals->LastArgument --;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+} // namespace KWSYS_NAMESPACE
diff --git a/Source/kwsys/CommandLineArguments.hxx.in b/Source/kwsys/CommandLineArguments.hxx.in
new file mode 100644
index 0000000..e4f6d02
--- /dev/null
+++ b/Source/kwsys/CommandLineArguments.hxx.in
@@ -0,0 +1,276 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_CommandLineArguments_hxx
+#define @KWSYS_NAMESPACE@_CommandLineArguments_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <string>
+#include <vector>
+
+namespace @KWSYS_NAMESPACE@
+{
+
+class CommandLineArgumentsInternal;
+struct CommandLineArgumentsCallbackStructure;
+
+/** \class CommandLineArguments
+ * \brief Command line arguments processing code.
+ *
+ * Find specified arguments with optional options and execute specified methods
+ * or set given variables.
+ *
+ * The two interfaces it knows are callback based and variable based. For
+ * callback based, you have to register callback for particular argument using
+ * AddCallback method. When that argument is passed, the callback will be
+ * called with argument, value, and call data. For boolean (NO_ARGUMENT)
+ * arguments, the value is "1". If the callback returns 0 the argument parsing
+ * will stop with an error.
+ *
+ * For the variable interface you associate variable with each argument. When
+ * the argument is specified, the variable is set to the specified value casted
+ * to the appropriate type. For boolean (NO_ARGUMENT), the value is "1".
+ *
+ * Both interfaces can be used at the same time.
+ *
+ * Possible argument types are:
+ * NO_ARGUMENT - The argument takes no value : --A
+ * CONCAT_ARGUMENT - The argument takes value after no space : --Aval
+ * SPACE_ARGUMENT - The argument takes value after space : --A val
+ * EQUAL_ARGUMENT - The argument takes value after equal : --A=val
+ * MULTI_ARGUMENT - The argument takes values after space : --A val1 val2 val3 ...
+ *
+ * Example use:
+ *
+ * kwsys::CommandLineArguments arg;
+ * arg.Initialize(argc, argv);
+ * typedef kwsys::CommandLineArguments argT;
+ * arg.AddArgument("--something", argT::EQUAL_ARGUMENT, &some_variable,
+ * "This is help string for --something");
+ * if ( !arg.Parse() )
+ * {
+ * std::cerr << "Problem parsing arguments" << std::endl;
+ * res = 1;
+ * }
+ *
+ */
+
+class @KWSYS_NAMESPACE@_EXPORT CommandLineArguments
+{
+public:
+ CommandLineArguments();
+ ~CommandLineArguments();
+
+ /**
+ * Various argument types.
+ */
+ enum ArgumentTypeEnum {
+ NO_ARGUMENT,
+ CONCAT_ARGUMENT,
+ SPACE_ARGUMENT,
+ EQUAL_ARGUMENT,
+ MULTI_ARGUMENT
+ };
+
+ /**
+ * Various variable types. When using the variable interface, this specifies
+ * what type the variable is.
+ */
+ enum VariableTypeEnum {
+ NO_VARIABLE_TYPE = 0, // The variable is not specified
+ INT_TYPE, // The variable is integer (int)
+ BOOL_TYPE, // The variable is boolean (bool)
+ DOUBLE_TYPE, // The variable is float (double)
+ STRING_TYPE, // The variable is string (char*)
+ STL_STRING_TYPE, // The variable is string (char*)
+ VECTOR_INT_TYPE, // The variable is integer (int)
+ VECTOR_BOOL_TYPE, // The variable is boolean (bool)
+ VECTOR_DOUBLE_TYPE, // The variable is float (double)
+ VECTOR_STRING_TYPE, // The variable is string (char*)
+ VECTOR_STL_STRING_TYPE, // The variable is string (char*)
+ LAST_VARIABLE_TYPE
+ };
+
+ /**
+ * Prototypes for callbacks for callback interface.
+ */
+ typedef int(*CallbackType)(const char* argument, const char* value,
+ void* call_data);
+ typedef int(*ErrorCallbackType)(const char* argument, void* client_data);
+
+ /**
+ * Initialize internal data structures. This should be called before parsing.
+ */
+ void Initialize(int argc, const char* const argv[]);
+ void Initialize(int argc, char* argv[]);
+
+ /**
+ * Initialize internal data structure and pass arguments one by one. This is
+ * convenience method for use from scripting languages where argc and argv
+ * are not available.
+ */
+ void Initialize();
+ void ProcessArgument(const char* arg);
+
+ /**
+ * This method will parse arguments and call appropriate methods.
+ */
+ int Parse();
+
+ /**
+ * This method will add a callback for a specific argument. The arguments to
+ * it are argument, argument type, callback method, and call data. The
+ * argument help specifies the help string used with this option. The
+ * callback and call_data can be skipped.
+ */
+ void AddCallback(const char* argument, ArgumentTypeEnum type,
+ CallbackType callback, void* call_data, const char* help);
+
+ /**
+ * Add handler for argument which is going to set the variable to the
+ * specified value. If the argument is specified, the option is casted to the
+ * appropriate type.
+ */
+ void AddArgument(const char* argument, ArgumentTypeEnum type,
+ bool* variable, const char* help);
+ void AddArgument(const char* argument, ArgumentTypeEnum type,
+ int* variable, const char* help);
+ void AddArgument(const char* argument, ArgumentTypeEnum type,
+ double* variable, const char* help);
+ void AddArgument(const char* argument, ArgumentTypeEnum type,
+ char** variable, const char* help);
+ void AddArgument(const char* argument, ArgumentTypeEnum type,
+ std::string* variable, const char* help);
+
+ /**
+ * Add handler for argument which is going to set the variable to the
+ * specified value. If the argument is specified, the option is casted to the
+ * appropriate type. This will handle the multi argument values.
+ */
+ void AddArgument(const char* argument, ArgumentTypeEnum type,
+ std::vector<bool>* variable, const char* help);
+ void AddArgument(const char* argument, ArgumentTypeEnum type,
+ std::vector<int>* variable, const char* help);
+ void AddArgument(const char* argument, ArgumentTypeEnum type,
+ std::vector<double>* variable, const char* help);
+ void AddArgument(const char* argument, ArgumentTypeEnum type,
+ std::vector<char*>* variable, const char* help);
+ void AddArgument(const char* argument, ArgumentTypeEnum type,
+ std::vector<std::string>* variable, const char* help);
+
+ /**
+ * Add handler for boolean argument. The argument does not take any option
+ * and if it is specified, the value of the variable is true/1, otherwise it
+ * is false/0.
+ */
+ void AddBooleanArgument(const char* argument,
+ bool* variable, const char* help);
+ void AddBooleanArgument(const char* argument,
+ int* variable, const char* help);
+ void AddBooleanArgument(const char* argument,
+ double* variable, const char* help);
+ void AddBooleanArgument(const char* argument,
+ char** variable, const char* help);
+ void AddBooleanArgument(const char* argument,
+ std::string* variable, const char* help);
+
+ /**
+ * Set the callbacks for error handling.
+ */
+ void SetClientData(void* client_data);
+ void SetUnknownArgumentCallback(ErrorCallbackType callback);
+
+ /**
+ * Get remaining arguments. It allocates space for argv, so you have to call
+ * delete[] on it.
+ */
+ void GetRemainingArguments(int* argc, char*** argv);
+ void DeleteRemainingArguments(int argc, char*** argv);
+
+ /**
+ * If StoreUnusedArguments is set to true, then all unknown arguments will be
+ * stored and the user can access the modified argc, argv without known
+ * arguments.
+ */
+ void StoreUnusedArguments(bool val) { this->StoreUnusedArgumentsFlag = val; }
+ void GetUnusedArguments(int* argc, char*** argv);
+
+ /**
+ * Return string containing help. If the argument is specified, only return
+ * help for that argument.
+ */
+ const char* GetHelp() { return this->Help.c_str(); }
+ const char* GetHelp(const char* arg);
+
+ /**
+ * Get / Set the help line length. This length is used when generating the
+ * help page. Default length is 80.
+ */
+ void SetLineLength(unsigned int);
+ unsigned int GetLineLength();
+
+ /**
+ * Get the executable name (argv0). This is only available when using
+ * Initialize with argc/argv.
+ */
+ const char* GetArgv0();
+
+ /**
+ * Get index of the last argument parsed. This is the last argument that was
+ * parsed ok in the original argc/argv list.
+ */
+ unsigned int GetLastArgument();
+
+protected:
+ void GenerateHelp();
+
+ //! This is internal method that registers variable with argument
+ void AddArgument(const char* argument, ArgumentTypeEnum type,
+ VariableTypeEnum vtype, void* variable, const char* help);
+
+ bool GetMatchedArguments(std::vector<std::string>* matches,
+ const std::string& arg);
+
+ //! Populate individual variables
+ bool PopulateVariable(CommandLineArgumentsCallbackStructure* cs,
+ const char* value);
+
+ //! Populate individual variables of type ...
+ void PopulateVariable(bool* variable, const std::string& value);
+ void PopulateVariable(int* variable, const std::string& value);
+ void PopulateVariable(double* variable, const std::string& value);
+ void PopulateVariable(char** variable, const std::string& value);
+ void PopulateVariable(std::string* variable, const std::string& value);
+ void PopulateVariable(std::vector<bool>* variable, const std::string& value);
+ void PopulateVariable(std::vector<int>* variable, const std::string& value);
+ void PopulateVariable(std::vector<double>* variable, const std::string& value);
+ void PopulateVariable(std::vector<char*>* variable, const std::string& value);
+ void PopulateVariable(std::vector<std::string>* variable, const std::string& value);
+
+ typedef CommandLineArgumentsInternal Internal;
+ Internal* Internals;
+ std::string Help;
+
+ unsigned int LineLength;
+
+ bool StoreUnusedArgumentsFlag;
+};
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
+
+
+
+
+
diff --git a/Source/kwsys/Configure.h.in b/Source/kwsys/Configure.h.in
new file mode 100644
index 0000000..cd2d965
--- /dev/null
+++ b/Source/kwsys/Configure.h.in
@@ -0,0 +1,136 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_Configure_h
+#define @KWSYS_NAMESPACE@_Configure_h
+
+/* If we are building a kwsys .c or .cxx file, let it use the kwsys
+ namespace. When not building a kwsys source file these macros are
+ temporarily defined inside the headers that use them. */
+#if defined(KWSYS_NAMESPACE)
+# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+
+/* Disable some warnings inside kwsys source files. */
+#if defined(KWSYS_NAMESPACE)
+# if defined(__BORLANDC__)
+# pragma warn -8027 /* function not inlined. */
+# endif
+# if defined(__INTEL_COMPILER)
+# pragma warning (disable: 1572) /* floating-point equality test */
+# endif
+# if defined(__sgi) && !defined(__GNUC__)
+# pragma set woff 3970 /* pointer to int conversion */
+# pragma set woff 3968 /* 64 bit conversion */
+# endif
+#endif
+
+/* 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
+# if 0 && (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64)
+# error "_FILE_OFFSET_BITS must be defined to at least 64"
+# endif
+# endif
+#endif
+
+/* Setup the export macro. */
+#if @KWSYS_BUILD_SHARED@
+# if defined(_WIN32) || defined(__CYGWIN__)
+# if defined(@KWSYS_NAMESPACE@_EXPORTS)
+# define @KWSYS_NAMESPACE@_EXPORT __declspec(dllexport)
+# else
+# define @KWSYS_NAMESPACE@_EXPORT __declspec(dllimport)
+# endif
+# elif __GNUC__ >= 4
+# define @KWSYS_NAMESPACE@_EXPORT __attribute__ ((visibility("default")))
+# else
+# define @KWSYS_NAMESPACE@_EXPORT
+# endif
+#else
+# define @KWSYS_NAMESPACE@_EXPORT
+#endif
+
+/* Enable warnings that are off by default but are useful. */
+#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_ENABLE)
+# if defined(_MSC_VER)
+# pragma warning ( default : 4263 ) /* no override, call convention differs */
+# endif
+#endif
+
+/* Disable warnings that are on by default but occur in valid code. */
+#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_DISABLE)
+# if defined(_MSC_VER)
+# pragma warning (disable: 4097) /* typedef is synonym for class */
+# pragma warning (disable: 4127) /* conditional expression is constant */
+# pragma warning (disable: 4244) /* possible loss in conversion */
+# pragma warning (disable: 4251) /* missing DLL-interface */
+# pragma warning (disable: 4305) /* truncation from type1 to type2 */
+# pragma warning (disable: 4309) /* truncation of constant value */
+# pragma warning (disable: 4514) /* unreferenced inline function */
+# pragma warning (disable: 4706) /* assignment in conditional expression */
+# pragma warning (disable: 4710) /* function not inlined */
+# pragma warning (disable: 4786) /* identifier truncated in debug info */
+# endif
+# if defined(__BORLANDC__) && !defined(__cplusplus)
+ /* Code has no effect; raised by winnt.h in C (not C++) when ignoring an
+ unused parameter using "(param)" syntax (i.e. no cast to void). */
+# pragma warn -8019
+# endif
+#endif
+
+/* MSVC 6.0 in release mode will warn about code it produces with its
+ optimizer. Disable the warnings specifically for this
+ configuration. Real warnings will be revealed by a debug build or
+ by other compilers. */
+#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_DISABLE_BOGUS)
+# if defined(_MSC_VER) && (_MSC_VER < 1300) && defined(NDEBUG)
+# pragma warning ( disable : 4701 ) /* Variable may be used uninitialized. */
+# pragma warning ( disable : 4702 ) /* Unreachable code. */
+# endif
+#endif
+
+#endif
diff --git a/Source/kwsys/Configure.hxx.in b/Source/kwsys/Configure.hxx.in
new file mode 100644
index 0000000..ff8e49d
--- /dev/null
+++ b/Source/kwsys/Configure.hxx.in
@@ -0,0 +1,31 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_Configure_hxx
+#define @KWSYS_NAMESPACE@_Configure_hxx
+
+/* Include C configuration. */
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+/* Whether wstring is available. */
+#define @KWSYS_NAMESPACE@_STL_HAS_WSTRING @KWSYS_STL_HAS_WSTRING@
+
+/* If building a C++ file in kwsys itself, give the source file
+ access to the macros without a configured namespace. */
+#if defined(KWSYS_NAMESPACE)
+# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# define kwsys @KWSYS_NAMESPACE@
+# endif
+# define KWSYS_NAME_IS_KWSYS @KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# define KWSYS_STL_HAS_WSTRING @KWSYS_NAMESPACE@_STL_HAS_WSTRING
+#endif
+
+#endif
diff --git a/Source/kwsys/Copyright.txt b/Source/kwsys/Copyright.txt
new file mode 100644
index 0000000..1549a7d
--- /dev/null
+++ b/Source/kwsys/Copyright.txt
@@ -0,0 +1,31 @@
+KWSys - Kitware System Library
+Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the names of Kitware, Inc., the Insight Software Consortium,
+ nor the names of their contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
new file mode 100644
index 0000000..c549792
--- /dev/null
+++ b/Source/kwsys/Directory.cxx
@@ -0,0 +1,260 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Directory.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.
+#if 0
+# include "Directory.hxx.in"
+# include "Configure.hxx.in"
+# include "Encoding.hxx.in"
+#endif
+
+#include <string>
+#include <vector>
+
+namespace KWSYS_NAMESPACE
+{
+
+//----------------------------------------------------------------------------
+class DirectoryInternals
+{
+public:
+ // Array of Files
+ std::vector<std::string> Files;
+
+ // Path to Open'ed directory
+ std::string Path;
+};
+
+//----------------------------------------------------------------------------
+Directory::Directory()
+{
+ this->Internal = new DirectoryInternals;
+}
+
+//----------------------------------------------------------------------------
+Directory::~Directory()
+{
+ delete this->Internal;
+}
+
+//----------------------------------------------------------------------------
+unsigned long Directory::GetNumberOfFiles() const
+{
+ return static_cast<unsigned long>(this->Internal->Files.size());
+}
+
+//----------------------------------------------------------------------------
+const char* Directory::GetFile(unsigned long dindex) const
+{
+ if ( dindex >= this->Internal->Files.size() )
+ {
+ return 0;
+ }
+ return this->Internal->Files[dindex].c_str();
+}
+
+//----------------------------------------------------------------------------
+const char* Directory::GetPath() const
+{
+ return this->Internal->Path.c_str();
+}
+
+//----------------------------------------------------------------------------
+void Directory::Clear()
+{
+ this->Internal->Path.resize(0);
+ this->Internal->Files.clear();
+}
+
+} // namespace KWSYS_NAMESPACE
+
+// First microsoft compilers
+
+#if defined(_MSC_VER) || defined(__WATCOMC__)
+#include <windows.h>
+#include <io.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+namespace KWSYS_NAMESPACE
+{
+
+bool Directory::Load(const std::string& name)
+{
+ this->Clear();
+#if _MSC_VER < 1300
+ long srchHandle;
+#else
+ intptr_t srchHandle;
+#endif
+ char* buf;
+ size_t n = name.size();
+ if ( *name.rbegin() == '/' || *name.rbegin() == '\\' )
+ {
+ buf = new char[n + 1 + 1];
+ sprintf(buf, "%s*", name.c_str());
+ }
+ else
+ {
+ // Make sure the slashes in the wildcard suffix are consistent with the
+ // rest of the path
+ buf = new char[n + 2 + 1];
+ if ( name.find('\\') != name.npos )
+ {
+ sprintf(buf, "%s\\*", name.c_str());
+ }
+ else
+ {
+ sprintf(buf, "%s/*", name.c_str());
+ }
+ }
+ struct _wfinddata_t data; // data of current file
+
+ // Now put them into the file array
+ srchHandle = _wfindfirst((wchar_t*)Encoding::ToWide(buf).c_str(), &data);
+ delete [] buf;
+
+ if ( srchHandle == -1 )
+ {
+ return 0;
+ }
+
+ // Loop through names
+ do
+ {
+ this->Internal->Files.push_back(Encoding::ToNarrow(data.name));
+ }
+ while ( _wfindnext(srchHandle, &data) != -1 );
+ this->Internal->Path = name;
+ return _findclose(srchHandle) != -1;
+}
+
+unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
+{
+#if _MSC_VER < 1300
+ long srchHandle;
+#else
+ intptr_t srchHandle;
+#endif
+ char* buf;
+ size_t n = name.size();
+ if ( *name.rbegin() == '/' )
+ {
+ buf = new char[n + 1 + 1];
+ sprintf(buf, "%s*", name.c_str());
+ }
+ else
+ {
+ buf = new char[n + 2 + 1];
+ sprintf(buf, "%s/*", name.c_str());
+ }
+ struct _wfinddata_t data; // data of current file
+
+ // Now put them into the file array
+ srchHandle = _wfindfirst((wchar_t*)Encoding::ToWide(buf).c_str(), &data);
+ delete [] buf;
+
+ if ( srchHandle == -1 )
+ {
+ return 0;
+ }
+
+ // Loop through names
+ unsigned long count = 0;
+ do
+ {
+ count++;
+ }
+ while ( _wfindnext(srchHandle, &data) != -1 );
+ _findclose(srchHandle);
+ return count;
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#else
+
+// Now the POSIX style directory access
+
+#include <sys/types.h>
+#include <dirent.h>
+
+// PGI with glibc has trouble with dirent and large file support:
+// http://www.pgroup.com/userforum/viewtopic.php?
+// p=1992&sid=f16167f51964f1a68fe5041b8eb213b6
+// Work around the problem by mapping dirent the same way as readdir.
+#if defined(__PGI) && defined(__GLIBC__)
+# define kwsys_dirent_readdir dirent
+# define kwsys_dirent_readdir64 dirent64
+# define kwsys_dirent kwsys_dirent_lookup(readdir)
+# define kwsys_dirent_lookup(x) kwsys_dirent_lookup_delay(x)
+# define kwsys_dirent_lookup_delay(x) kwsys_dirent_##x
+#else
+# define kwsys_dirent dirent
+#endif
+
+namespace KWSYS_NAMESPACE
+{
+
+bool Directory::Load(const std::string& name)
+{
+ this->Clear();
+
+ DIR* dir = opendir(name.c_str());
+
+ if (!dir)
+ {
+ return 0;
+ }
+
+ for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir) )
+ {
+ this->Internal->Files.push_back(d->d_name);
+ }
+ this->Internal->Path = name;
+ closedir(dir);
+ return 1;
+}
+
+unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
+{
+ DIR* dir = opendir(name.c_str());
+
+ if (!dir)
+ {
+ return 0;
+ }
+
+ unsigned long count = 0;
+ for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir) )
+ {
+ count++;
+ }
+ closedir(dir);
+ return count;
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#endif
diff --git a/Source/kwsys/Directory.hxx.in b/Source/kwsys/Directory.hxx.in
new file mode 100644
index 0000000..e68f337
--- /dev/null
+++ b/Source/kwsys/Directory.hxx.in
@@ -0,0 +1,81 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_Directory_hxx
+#define @KWSYS_NAMESPACE@_Directory_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+#include <string>
+
+namespace @KWSYS_NAMESPACE@
+{
+
+class DirectoryInternals;
+
+/** \class Directory
+ * \brief Portable directory/filename traversal.
+ *
+ * Directory provides a portable way of finding the names of the files
+ * in a system directory.
+ *
+ * Directory currently works with Windows and Unix operating systems.
+ */
+class @KWSYS_NAMESPACE@_EXPORT Directory
+{
+public:
+ Directory();
+ ~Directory();
+
+ /**
+ * Load the specified directory and load the names of the files
+ * in that directory. 0 is returned if the directory can not be
+ * opened, 1 if it is opened.
+ */
+ bool Load(const std::string&);
+
+ /**
+ * Return the number of files in the current directory.
+ */
+ unsigned long GetNumberOfFiles() const;
+
+ /**
+ * Return the number of files in the specified directory.
+ * A higher performance static method.
+ */
+ static unsigned long GetNumberOfFilesInDirectory(const std::string&);
+
+ /**
+ * Return the file at the given index, the indexing is 0 based
+ */
+ const char* GetFile(unsigned long) const;
+
+ /**
+ * Return the path to Open'ed directory
+ */
+ const char* GetPath() const;
+
+ /**
+ * Clear the internal structure. Used internally at beginning of Load(...)
+ * to clear the cache.
+ */
+ void Clear();
+
+private:
+ // Private implementation details.
+ DirectoryInternals* Internal;
+
+ Directory(const Directory&); // Not implemented.
+ void operator=(const Directory&); // Not implemented.
+}; // End Class: Directory
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/Source/kwsys/DynamicLoader.cxx b/Source/kwsys/DynamicLoader.cxx
new file mode 100644
index 0000000..1941d96
--- /dev/null
+++ b/Source/kwsys/DynamicLoader.cxx
@@ -0,0 +1,531 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(DynamicLoader.hxx)
+
+#include KWSYS_HEADER(Configure.hxx)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "DynamicLoader.hxx.in"
+# include "Configure.hxx.in"
+#endif
+
+// This file is actually 3 different implementations.
+// 1. HP machines which uses shl_load
+// 2. Mac OS X 10.2.x and earlier which uses NSLinkModule
+// 3. Windows which uses LoadLibrary
+// 4. Most unix systems (including Mac OS X 10.3 and later) which use dlopen
+// (default) Each part of the ifdef contains a complete implementation for
+// the static methods of DynamicLoader.
+
+// ---------------------------------------------------------------
+// 1. Implementation for HPUX machines
+#ifdef __hpux
+#include <errno.h>
+#include <dl.h>
+#define DYNAMICLOADER_DEFINED 1
+
+namespace KWSYS_NAMESPACE
+{
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const std::string& libname )
+{
+ return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+ if (!lib)
+ {
+ return 0;
+ }
+ return !shl_unload(lib);
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer
+DynamicLoader::GetSymbolAddress(DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+ void* addr;
+ int status;
+
+ /* TYPE_PROCEDURE Look for a function or procedure. (This used to be default)
+ * TYPE_DATA Look for a symbol in the data segment (for example, variables).
+ * TYPE_UNDEFINED Look for any symbol.
+ */
+ status = shl_findsym (&lib, sym.c_str(), TYPE_UNDEFINED, &addr);
+ void* result = (status < 0) ? (void*)0 : addr;
+
+ // Hack to cast pointer-to-data to pointer-to-function.
+ return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
+}
+
+const char* DynamicLoader::LastError()
+{
+ // TODO: Need implementation with errno/strerror
+ /* If successful, shl_findsym returns an integer (int) value zero. If
+ * shl_findsym cannot find sym, it returns -1 and sets errno to zero.
+ * If any other errors occur, shl_findsym returns -1 and sets errno to one
+ * of these values (defined in <errno.h>):
+ * ENOEXEC
+ * A format error was detected in the specified library.
+ * ENOSYM
+ * A symbol on which sym depends could not be found.
+ * EINVAL
+ * The specified handle is invalid.
+ */
+
+ if( errno == ENOEXEC
+ || errno == ENOSYM
+ || errno == EINVAL )
+ {
+ return strerror(errno);
+ }
+ // else
+ return 0;
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#endif //__hpux
+
+
+// ---------------------------------------------------------------
+// 2. Implementation for Mac OS X 10.2.x and earlier
+#ifdef __APPLE__
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1030
+#include <string.h> // for strlen
+#include <mach-o/dyld.h>
+#define DYNAMICLOADER_DEFINED 1
+
+namespace KWSYS_NAMESPACE
+{
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const std::string& libname )
+{
+ NSObjectFileImageReturnCode rc;
+ NSObjectFileImage image = 0;
+
+ rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image);
+ // rc == NSObjectFileImageInappropriateFile when trying to load a dylib file
+ if( rc != NSObjectFileImageSuccess )
+ {
+ return 0;
+ }
+ NSModule handle = NSLinkModule(image, libname.c_str(),
+ NSLINKMODULE_OPTION_BINDNOW|NSLINKMODULE_OPTION_RETURN_ON_ERROR);
+ NSDestroyObjectFileImage(image);
+ return handle;
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary( DynamicLoader::LibraryHandle lib)
+{
+ // NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED
+ // With this option the memory for the module is not deallocated
+ // allowing pointers into the module to still be valid.
+ // You should use this option instead if your code experience some problems
+ // reported against Panther 10.3.9 (fixed in Tiger 10.4.2 and up)
+ bool success = NSUnLinkModule(lib, NSUNLINKMODULE_OPTION_NONE);
+ return success;
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+ DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+ void *result=0;
+ // Need to prepend symbols with '_' on Apple-gcc compilers
+ size_t len = sym.size();
+ char *rsym = new char[len + 1 + 1];
+ strcpy(rsym, "_");
+ strcat(rsym+1, sym.c_str());
+
+ NSSymbol symbol = NSLookupSymbolInModule(lib, rsym);
+ if(symbol)
+ {
+ result = NSAddressOfSymbol(symbol);
+ }
+
+ delete[] rsym;
+ // Hack to cast pointer-to-data to pointer-to-function.
+ return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
+}
+
+//----------------------------------------------------------------------------
+const char* DynamicLoader::LastError()
+{
+ return 0;
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED < 1030
+#endif // __APPLE__
+
+// ---------------------------------------------------------------
+// 3. Implementation for Windows win32 code but not cygwin
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <windows.h>
+#define DYNAMICLOADER_DEFINED 1
+
+namespace KWSYS_NAMESPACE
+{
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const std::string& libname)
+{
+ 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;
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+ return (int)FreeLibrary(lib);
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+ DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+ // TODO: The calling convention affects the name of the symbol. We
+ // should have a tool to help get the symbol with the desired
+ // calling convention. Currently we assume cdecl.
+ //
+ // Borland:
+ // __cdecl = "_func" (default)
+ // __fastcall = "@_func"
+ // __stdcall = "func"
+ //
+ // Watcom:
+ // __cdecl = "_func"
+ // __fastcall = "@_func@X"
+ // __stdcall = "_func@X"
+ // __watcall = "func_" (default)
+ //
+ // MSVC:
+ // __cdecl = "func" (default)
+ // __fastcall = "@_func@X"
+ // __stdcall = "_func@X"
+ //
+ // Note that the "@X" part of the name above is the total size (in
+ // bytes) of the arguments on the stack.
+ void *result;
+#if defined(__BORLANDC__) || defined(__WATCOMC__)
+ // Need to prepend symbols with '_'
+ size_t len = sym.size();
+ char *rsym = new char[len + 1 + 1];
+ strcpy(rsym, "_");
+ strcat(rsym, sym.c_str());
+#else
+ const char *rsym = sym.c_str();
+#endif
+ result = (void*)GetProcAddress(lib, rsym);
+#if defined(__BORLANDC__) || defined(__WATCOMC__)
+ delete[] rsym;
+#endif
+ // Hack to cast pointer-to-data to pointer-to-function.
+#ifdef __WATCOMC__
+ return *(DynamicLoader::SymbolPointer*)(&result);
+#else
+ return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
+#endif
+}
+
+//----------------------------------------------------------------------------
+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
+ );
+
+ if(!lpMsgBuf)
+ {
+ return NULL;
+ }
+
+ static char* str = 0;
+ delete [] str;
+ str = strcpy(new char[strlen((char*)lpMsgBuf)+1], (char*)lpMsgBuf);
+ // Free the buffer.
+ LocalFree( lpMsgBuf );
+ return str;
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#endif //_WIN32
+
+// ---------------------------------------------------------------
+// 4. Implementation for BeOS
+#if defined __BEOS__
+
+#include <string.h> // for strerror()
+
+#include <be/kernel/image.h>
+#include <be/support/Errors.h>
+
+#define DYNAMICLOADER_DEFINED 1
+
+namespace KWSYS_NAMESPACE
+{
+
+static image_id last_dynamic_err = B_OK;
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const std::string& libname )
+{
+ // 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());
+ if (rc < 0)
+ {
+ last_dynamic_err = rc;
+ return 0;
+ }
+
+ return rc+1;
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+ if (!lib)
+ {
+ last_dynamic_err = B_BAD_VALUE;
+ return 0;
+ }
+ else
+ {
+ // The function dlclose() returns 0 on success, and non-zero on error.
+ status_t rc = unload_add_on(lib-1);
+ if (rc != B_OK)
+ {
+ last_dynamic_err = rc;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+ DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+ // Hack to cast pointer-to-data to pointer-to-function.
+ union
+ {
+ void* pvoid;
+ DynamicLoader::SymbolPointer psym;
+ } result;
+
+ result.psym = NULL;
+
+ if (!lib)
+ {
+ last_dynamic_err = B_BAD_VALUE;
+ }
+ else
+ {
+ // !!! FIXME: BeOS can do function-only lookups...does this ever
+ // !!! FIXME: actually _want_ a data symbol lookup, or was this union
+ // !!! FIXME: a leftover of dlsym()? (s/ANY/TEXT for functions only).
+ status_t rc = get_image_symbol(lib-1,sym.c_str(),B_SYMBOL_TYPE_ANY,&result.pvoid);
+ if (rc != B_OK)
+ {
+ last_dynamic_err = rc;
+ result.psym = NULL;
+ }
+ }
+ return result.psym;
+}
+
+//----------------------------------------------------------------------------
+const char* DynamicLoader::LastError()
+{
+ const char *retval = strerror(last_dynamic_err);
+ last_dynamic_err = B_OK;
+ return retval;
+}
+
+} // namespace KWSYS_NAMESPACE
+#endif
+
+// ---------------------------------------------------------------
+// 5. Implementation for systems without dynamic libs
+// __gnu_blrts__ is IBM BlueGene/L
+// __LIBCATAMOUNT__ is defined on Catamount on Cray compute nodes
+#if defined(__gnu_blrts__) || defined(__LIBCATAMOUNT__) || defined(__CRAYXT_COMPUTE_LINUX_TARGET)
+#include <string.h> // for strerror()
+#define DYNAMICLOADER_DEFINED 1
+
+namespace KWSYS_NAMESPACE
+{
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const std::string& libname )
+{
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+ if (!lib)
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+ DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+const char* DynamicLoader::LastError()
+ {
+ return "General error";
+ }
+
+} // namespace KWSYS_NAMESPACE
+#endif
+
+#ifdef __MINT__
+#define DYNAMICLOADER_DEFINED 1
+#define _GNU_SOURCE /* for program_invocation_name */
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <dld.h>
+
+namespace KWSYS_NAMESPACE
+{
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const std::string& libname )
+{
+ char *name = (char *)calloc(1, libname.size() + 1);
+ dld_init(program_invocation_name);
+ strncpy(name, libname.c_str(), libname.size());
+ dld_link(libname.c_str());
+ return (void *)name;
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+ dld_unlink_by_file((char *)lib, 0);
+ free(lib);
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+ DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+ // Hack to cast pointer-to-data to pointer-to-function.
+ union
+ {
+ void* pvoid;
+ DynamicLoader::SymbolPointer psym;
+ } result;
+ result.pvoid = dld_get_symbol(sym.c_str());
+ return result.psym;
+}
+
+//----------------------------------------------------------------------------
+const char* DynamicLoader::LastError()
+{
+ return dld_strerror(dld_errno);
+}
+
+} // namespace KWSYS_NAMESPACE
+#endif
+
+// ---------------------------------------------------------------
+// 6. Implementation for default UNIX machines.
+// if nothing has been defined then use this
+#ifndef DYNAMICLOADER_DEFINED
+#define DYNAMICLOADER_DEFINED 1
+// Setup for most unix machines
+#include <dlfcn.h>
+
+namespace KWSYS_NAMESPACE
+{
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const std::string& libname )
+{
+ return dlopen(libname.c_str(), RTLD_LAZY);
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+ if (lib)
+ {
+ // The function dlclose() returns 0 on success, and non-zero on error.
+ return !dlclose(lib);
+ }
+ // else
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+ DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+ // Hack to cast pointer-to-data to pointer-to-function.
+ union
+ {
+ void* pvoid;
+ DynamicLoader::SymbolPointer psym;
+ } result;
+ result.pvoid = dlsym(lib, sym.c_str());
+ return result.psym;
+}
+
+//----------------------------------------------------------------------------
+const char* DynamicLoader::LastError()
+{
+ return dlerror();
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#endif
diff --git a/Source/kwsys/DynamicLoader.hxx.in b/Source/kwsys/DynamicLoader.hxx.in
new file mode 100644
index 0000000..1e4a912
--- /dev/null
+++ b/Source/kwsys/DynamicLoader.hxx.in
@@ -0,0 +1,102 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_DynamicLoader_hxx
+#define @KWSYS_NAMESPACE@_DynamicLoader_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+#include <string>
+
+#if defined(__hpux)
+ #include <dl.h>
+#elif defined(_WIN32) && !defined(__CYGWIN__)
+ #include <windows.h>
+#elif defined(__APPLE__)
+ #include <AvailabilityMacros.h>
+ #if MAC_OS_X_VERSION_MAX_ALLOWED < 1030
+ #include <mach-o/dyld.h>
+ #endif
+#elif defined(__BEOS__)
+ #include <be/kernel/image.h>
+#endif
+
+namespace @KWSYS_NAMESPACE@
+{
+/** \class DynamicLoader
+ * \brief Portable loading of dynamic libraries or dll's.
+ *
+ * DynamicLoader provides a portable interface to loading dynamic
+ * libraries or dll's into a process.
+ *
+ * Directory currently works with Windows, Apple, HP-UX and Unix (POSIX)
+ * operating systems
+ *
+ * \warning dlopen on *nix system works the following way:
+ * If filename contains a slash ("/"), then it is interpreted as a (relative
+ * or absolute) pathname. Otherwise, the dynamic linker searches for the
+ * library as follows : see ld.so(8) for further details):
+ * Whereas this distinction does not exist on Win32. Therefore ideally you
+ * should be doing full path to garantee to have a consistent way of dealing
+ * with dynamic loading of shared library.
+ *
+ * \warning the Cygwin implementation do not use the Win32 HMODULE. Put extra
+ * condition so that we can include the correct declaration (POSIX)
+ */
+
+class @KWSYS_NAMESPACE@_EXPORT DynamicLoader
+{
+public:
+// Ugly stuff for library handles
+// They are different on several different OS's
+#if defined(__hpux)
+ typedef shl_t LibraryHandle;
+#elif defined(_WIN32) && !defined(__CYGWIN__)
+ typedef HMODULE LibraryHandle;
+#elif defined(__APPLE__)
+ #if MAC_OS_X_VERSION_MAX_ALLOWED < 1030
+ typedef NSModule LibraryHandle;
+ #else
+ typedef void* LibraryHandle;
+ #endif
+#elif defined(__BEOS__)
+ typedef image_id LibraryHandle;
+#else // POSIX
+ typedef void* LibraryHandle;
+#endif
+
+ // Return type from DynamicLoader::GetSymbolAddress.
+ typedef void (*SymbolPointer)();
+
+ /** Load a dynamic library into the current process.
+ * The returned LibraryHandle can be used to access the symbols in the
+ * library. */
+ static LibraryHandle OpenLibrary(const std::string&);
+
+ /** Attempt to detach a dynamic library from the
+ * process. A value of true is returned if it is sucessful. */
+ static int CloseLibrary(LibraryHandle);
+
+ /** Find the address of the symbol in the given library. */
+ static SymbolPointer GetSymbolAddress(LibraryHandle, const std::string&);
+
+ /** Return the default module prefix for the current platform. */
+ static const char* LibPrefix() { return "@KWSYS_DynamicLoader_PREFIX@"; }
+
+ /** Return the default module suffix for the current platform. */
+ static const char* LibExtension() { return "@KWSYS_DynamicLoader_SUFFIX@"; }
+
+ /** Return the last error produced from a calls made on this class. */
+ static const char* LastError();
+}; // End Class: DynamicLoader
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/Source/kwsys/Encoding.h.in b/Source/kwsys/Encoding.h.in
new file mode 100644
index 0000000..591c5a8
--- /dev/null
+++ b/Source/kwsys/Encoding.h.in
@@ -0,0 +1,79 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_Encoding_h
+#define @KWSYS_NAMESPACE@_Encoding_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+#include <wchar.h>
+
+/* Redefine all public interface symbol names to be in the proper
+ namespace. These macros are used internally to kwsys only, and are
+ not visible to user code. Use kwsysHeaderDump.pl to reproduce
+ these macros after making changes to the interface. */
+#if !defined(KWSYS_NAMESPACE)
+# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# define kwsysEncoding kwsys_ns(Encoding)
+# define kwsysEncoding_mbstowcs kwsys_ns(Encoding_mbstowcs)
+# define kwsysEncoding_DupToWide kwsys_ns(Encoding_DupToWide)
+# define kwsysEncoding_wcstombs kwsys_ns(Encoding_wcstombs)
+# define kwsysEncoding_DupToNarrow kwsys_ns(Encoding_DupToNarrow)
+#endif
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+
+/* Convert a narrow string to a wide string.
+ On Windows, UTF-8 is assumed, and on other platforms,
+ the current locale is assumed.
+ */
+kwsysEXPORT size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* src, size_t n);
+
+/* Convert a narrow string to a wide string.
+ This can return NULL if the conversion fails. */
+kwsysEXPORT wchar_t* kwsysEncoding_DupToWide(const char* src);
+
+
+/* Convert a wide string to a narrow string.
+ On Windows, UTF-8 is assumed, and on other platforms,
+ the current locale is assumed. */
+kwsysEXPORT size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* src, size_t n);
+
+/* Convert a wide string to a narrow string.
+ This can return NULL if the conversion fails. */
+kwsysEXPORT char* kwsysEncoding_DupToNarrow(const wchar_t* str);
+
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+ Otherwise, undefine them to keep the namespace clean. */
+#if !defined(KWSYS_NAMESPACE)
+# undef kwsys_ns
+# undef kwsysEXPORT
+# if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# undef kwsysEncoding
+# undef kwsysEncoding_mbstowcs
+# undef kwsysEncoding_DupToWide
+# undef kwsysEncoding_wcstombs
+# undef kwsysEncoding_DupToNarrow
+# endif
+#endif
+
+#endif
diff --git a/Source/kwsys/Encoding.hxx.in b/Source/kwsys/Encoding.hxx.in
new file mode 100644
index 0000000..87b1c21
--- /dev/null
+++ b/Source/kwsys/Encoding.hxx.in
@@ -0,0 +1,77 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_Encoding_hxx
+#define @KWSYS_NAMESPACE@_Encoding_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+#include <string>
+#include <vector>
+
+namespace @KWSYS_NAMESPACE@
+{
+class @KWSYS_NAMESPACE@_EXPORT Encoding
+{
+public:
+
+ // Container class for argc/argv.
+ class CommandLineArguments
+ {
+ public:
+ // On Windows, get the program command line arguments
+ // in this Encoding module's 8 bit encoding.
+ // On other platforms the given argc/argv is used, and
+ // to be consistent, should be the argc/argv from main().
+ static CommandLineArguments Main(int argc, char const* const* argv);
+
+ // Construct CommandLineArguments with the given
+ // argc/argv. It is assumed that the string is already
+ // in the encoding used by this module.
+ CommandLineArguments(int argc, char const* const* argv);
+
+ // Construct CommandLineArguments with the given
+ // argc and wide argv. This is useful if wmain() is used.
+ CommandLineArguments(int argc, wchar_t const* const* argv);
+ ~CommandLineArguments();
+ CommandLineArguments(const CommandLineArguments&);
+ CommandLineArguments& operator=(const CommandLineArguments&);
+
+ int argc() const;
+ char const* const* argv() const;
+
+ protected:
+ std::vector<char*> argv_;
+ };
+
+ /**
+ * Convert between char and wchar_t
+ */
+
+#if @KWSYS_NAMESPACE@_STL_HAS_WSTRING
+
+ // Convert a narrow string to a wide string.
+ // On Windows, UTF-8 is assumed, and on other platforms,
+ // the current locale is assumed.
+ static std::wstring ToWide(const std::string& str);
+ static std::wstring ToWide(const char* str);
+
+ // Convert a wide string to a narrow string.
+ // On Windows, UTF-8 is assumed, and on other platforms,
+ // the current locale is assumed.
+ static std::string ToNarrow(const std::wstring& str);
+ static std::string ToNarrow(const wchar_t* str);
+
+#endif // @KWSYS_NAMESPACE@_STL_HAS_WSTRING
+
+}; // class Encoding
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/Source/kwsys/EncodingC.c b/Source/kwsys/EncodingC.c
new file mode 100644
index 0000000..32b9bff
--- /dev/null
+++ b/Source/kwsys/EncodingC.c
@@ -0,0 +1,85 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Encoding.h)
+
+/* Work-around CMake dependency scanning limitation. This must
+ duplicate the above list of headers. */
+#if 0
+# include "Encoding.h.in"
+#endif
+
+#include <stdlib.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* str, size_t n)
+{
+ if(str == 0)
+ {
+ return (size_t)-1;
+ }
+#ifdef _WIN32
+ return MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0,
+ str, -1, dest, (int)n) - 1;
+#else
+ return mbstowcs(dest, str, n);
+#endif
+}
+
+wchar_t* kwsysEncoding_DupToWide(const char* str)
+{
+ wchar_t* ret = NULL;
+ size_t length = kwsysEncoding_mbstowcs(NULL, str, 0) + 1;
+ if(length > 0)
+ {
+ ret = (wchar_t*)malloc((length)*sizeof(wchar_t));
+ if(ret)
+ {
+ ret[0] = 0;
+ kwsysEncoding_mbstowcs(ret, str, length);
+ }
+ }
+ return ret;
+}
+
+size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* str, size_t n)
+{
+ if(str == 0)
+ {
+ return (size_t)-1;
+ }
+#ifdef _WIN32
+ return WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str, -1,
+ dest, (int)n, NULL, NULL) - 1;
+#else
+ return wcstombs(dest, str, n);
+#endif
+}
+
+char* kwsysEncoding_DupToNarrow(const wchar_t* str)
+{
+ char* ret = NULL;
+ size_t length = kwsysEncoding_wcstombs(0, str, 0) + 1;
+ if(length > 0)
+ {
+ ret = (char*)malloc(length);
+ if(ret)
+ {
+ ret[0] = 0;
+ kwsysEncoding_wcstombs(ret, str, length);
+ }
+ }
+ return ret;
+}
diff --git a/Source/kwsys/EncodingCXX.cxx b/Source/kwsys/EncodingCXX.cxx
new file mode 100644
index 0000000..597d4bd
--- /dev/null
+++ b/Source/kwsys/EncodingCXX.cxx
@@ -0,0 +1,185 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifdef __osf__
+# define _OSF_SOURCE
+# define _POSIX_C_SOURCE 199506L
+# define _XOPEN_SOURCE_EXTENDED
+#endif
+
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Encoding.hxx)
+#include KWSYS_HEADER(Encoding.h)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "Encoding.hxx.in"
+# include "Encoding.h.in"
+#endif
+
+#include <vector>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _MSC_VER
+# pragma warning (disable: 4786)
+#endif
+
+// Windows API.
+#if defined(_WIN32)
+# include <windows.h>
+# include <shellapi.h>
+#endif
+
+namespace KWSYS_NAMESPACE
+{
+
+Encoding::CommandLineArguments
+Encoding::CommandLineArguments::Main(int argc, char const* const* argv)
+{
+#ifdef _WIN32
+ (void) argc;
+ (void) argv;
+
+ int ac;
+ LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &ac);
+
+ std::vector<std::string> av1(ac);
+ std::vector<char const*> av2(ac);
+ for(int i=0; i<ac; i++)
+ {
+ av1[i] = ToNarrow(w_av[i]);
+ av2[i] = av1[i].c_str();
+ }
+ LocalFree(w_av);
+ return CommandLineArguments(ac, &av2[0]);
+#else
+ return CommandLineArguments(argc, argv);
+#endif
+}
+
+Encoding::CommandLineArguments::CommandLineArguments(int ac,
+ char const* const* av)
+{
+ this->argv_.resize(ac+1);
+ for(int i=0; i<ac; i++)
+ {
+ this->argv_[i] = strdup(av[i]);
+ }
+ this->argv_[ac] = 0;
+}
+
+Encoding::CommandLineArguments::CommandLineArguments(int ac,
+ wchar_t const* const* av)
+{
+ this->argv_.resize(ac+1);
+ for(int i=0; i<ac; i++)
+ {
+ this->argv_[i] = kwsysEncoding_DupToNarrow(av[i]);
+ }
+ this->argv_[ac] = 0;
+}
+
+Encoding::CommandLineArguments::~CommandLineArguments()
+{
+ for(size_t i=0; i<this->argv_.size(); i++)
+ {
+ free(argv_[i]);
+ }
+}
+
+Encoding::CommandLineArguments::
+ CommandLineArguments(const CommandLineArguments& other)
+{
+ this->argv_.resize(other.argv_.size());
+ for(size_t i=0; i<this->argv_.size(); i++)
+ {
+ this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : 0;
+ }
+}
+
+Encoding::CommandLineArguments&
+Encoding::CommandLineArguments::operator=(const CommandLineArguments& other)
+{
+ if(this != &other)
+ {
+ size_t i;
+ for(i=0; i<this->argv_.size(); i++)
+ {
+ free(this->argv_[i]);
+ }
+
+ this->argv_.resize(other.argv_.size());
+ for(i=0; i<this->argv_.size(); i++)
+ {
+ this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : 0;
+ }
+ }
+
+ return *this;
+}
+
+int Encoding::CommandLineArguments::argc() const
+{
+ return static_cast<int>(this->argv_.size() - 1);
+}
+
+char const* const* Encoding::CommandLineArguments::argv() const
+{
+ return &this->argv_[0];
+}
+
+#if KWSYS_STL_HAS_WSTRING
+
+std::wstring Encoding::ToWide(const std::string& str)
+{
+ return ToWide(str.c_str());
+}
+
+std::string Encoding::ToNarrow(const std::wstring& str)
+{
+ return ToNarrow(str.c_str());
+}
+
+std::wstring Encoding::ToWide(const char* cstr)
+{
+ std::wstring wstr;
+ size_t length = kwsysEncoding_mbstowcs(0, cstr, 0) + 1;
+ if(length > 0)
+ {
+ std::vector<wchar_t> wchars(length);
+ if(kwsysEncoding_mbstowcs(&wchars[0], cstr, length) > 0)
+ {
+ wstr = &wchars[0];
+ }
+ }
+ return wstr;
+}
+
+std::string Encoding::ToNarrow(const wchar_t* wcstr)
+{
+ std::string str;
+ size_t length = kwsysEncoding_wcstombs(0, wcstr, 0) + 1;
+ if(length > 0)
+ {
+ std::vector<char> chars(length);
+ if(kwsysEncoding_wcstombs(&chars[0], wcstr, length) > 0)
+ {
+ str = &chars[0];
+ }
+ }
+ return str;
+}
+#endif // KWSYS_STL_HAS_WSTRING
+
+} // namespace KWSYS_NAMESPACE
diff --git a/Source/kwsys/ExtraTest.cmake.in b/Source/kwsys/ExtraTest.cmake.in
new file mode 100644
index 0000000..e8c0a1c
--- /dev/null
+++ b/Source/kwsys/ExtraTest.cmake.in
@@ -0,0 +1 @@
+MESSAGE("*** This message is generated by message inside a file that is included in DartTestfile.txt ***")
diff --git a/Source/kwsys/FStream.cxx b/Source/kwsys/FStream.cxx
new file mode 100644
index 0000000..5a30997
--- /dev/null
+++ b/Source/kwsys/FStream.cxx
@@ -0,0 +1,78 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(FStream.hxx)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "FStream.hxx.in"
+#endif
+
+namespace KWSYS_NAMESPACE
+{
+namespace FStream
+{
+
+BOM ReadBOM(std::istream& in)
+{
+ if(!in.good())
+ {
+ return BOM_None;
+ }
+ unsigned long orig = in.tellg();
+ unsigned char bom[4];
+ in.read(reinterpret_cast<char*>(bom), 2);
+ if(!in.good())
+ {
+ in.clear();
+ in.seekg(orig);
+ return BOM_None;
+ }
+ if(bom[0] == 0xEF && bom[1] == 0xBB)
+ {
+ in.read(reinterpret_cast<char*>(bom+2), 1);
+ if(in.good() && bom[2] == 0xBF)
+ {
+ return BOM_UTF8;
+ }
+ }
+ else if(bom[0] == 0xFE && bom[1] == 0xFF)
+ {
+ return BOM_UTF16BE;
+ }
+ else if(bom[0] == 0x00 && bom[1] == 0x00)
+ {
+ in.read(reinterpret_cast<char*>(bom+2), 2);
+ if(in.good() && bom[2] == 0xFE && bom[3] == 0xFF)
+ {
+ return BOM_UTF32BE;
+ }
+ }
+ else if(bom[0] == 0xFF && bom[1] == 0xFE)
+ {
+ unsigned long p = in.tellg();
+ in.read(reinterpret_cast<char*>(bom+2), 2);
+ if(in.good() && bom[2] == 0x00 && bom[3] == 0x00)
+ {
+ return BOM_UTF32LE;
+ }
+ in.seekg(p);
+ return BOM_UTF16LE;
+ }
+ in.clear();
+ in.seekg(orig);
+ return BOM_None;
+}
+
+} // FStream namespace
+} //KWSYS_NAMESPACE
diff --git a/Source/kwsys/FStream.hxx.in b/Source/kwsys/FStream.hxx.in
new file mode 100644
index 0000000..681e4d8
--- /dev/null
+++ b/Source/kwsys/FStream.hxx.in
@@ -0,0 +1,194 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_FStream_hxx
+#define @KWSYS_NAMESPACE@_FStream_hxx
+
+#include <@KWSYS_NAMESPACE@/Encoding.hxx>
+#include <fstream>
+
+namespace @KWSYS_NAMESPACE@
+{
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+# if defined(_NOEXCEPT)
+# define @KWSYS_NAMESPACE@_FStream_NOEXCEPT _NOEXCEPT
+# else
+# define @KWSYS_NAMESPACE@_FStream_NOEXCEPT
+# endif
+ template<typename CharType,typename Traits>
+ class basic_filebuf : public std::basic_filebuf<CharType,Traits>
+ {
+ public:
+ typedef std::basic_filebuf<CharType,Traits> my_base_type;
+ basic_filebuf *open(char const *s,std::ios_base::openmode mode)
+ {
+ return static_cast<basic_filebuf*>(
+ my_base_type::open(Encoding::ToWide(s).c_str(), mode)
+ );
+ }
+ };
+
+ template<typename CharType,typename Traits = std::char_traits<CharType> >
+ class basic_ifstream : public std::basic_istream<CharType,Traits>
+ {
+ public:
+ typedef basic_filebuf<CharType,Traits> internal_buffer_type;
+ typedef std::basic_istream<CharType,Traits> internal_stream_type;
+
+ basic_ifstream() : internal_stream_type(new internal_buffer_type())
+ {
+ buf_ = static_cast<internal_buffer_type *>(internal_stream_type::rdbuf());
+ }
+ explicit basic_ifstream(char const *file_name,
+ std::ios_base::openmode mode = std::ios_base::in)
+ : internal_stream_type(new internal_buffer_type())
+ {
+ buf_ = static_cast<internal_buffer_type *>(internal_stream_type::rdbuf());
+ open(file_name,mode);
+ }
+ void open(char const *file_name,std::ios_base::openmode mode = std::ios_base::in)
+ {
+ if(!buf_->open(file_name,mode | std::ios_base::in))
+ {
+ this->setstate(std::ios_base::failbit);
+ }
+ else
+ {
+ this->clear();
+ }
+ }
+ bool is_open()
+ {
+ return buf_->is_open();
+ }
+ bool is_open() const
+ {
+ return buf_->is_open();
+ }
+ void close()
+ {
+ if(!buf_->close())
+ {
+ this->setstate(std::ios_base::failbit);
+ }
+ else
+ {
+ this->clear();
+ }
+ }
+
+ internal_buffer_type *rdbuf() const
+ {
+ return buf_;
+ }
+
+ ~basic_ifstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT
+ {
+ buf_->close();
+ delete buf_;
+ }
+
+ private:
+ internal_buffer_type* buf_;
+};
+
+template<typename CharType,typename Traits = std::char_traits<CharType> >
+class basic_ofstream : public std::basic_ostream<CharType,Traits>
+{
+ public:
+ typedef basic_filebuf<CharType,Traits> internal_buffer_type;
+ typedef std::basic_ostream<CharType,Traits> internal_stream_type;
+
+ basic_ofstream() : internal_stream_type(new internal_buffer_type())
+ {
+ buf_ = static_cast<internal_buffer_type *>(internal_stream_type::rdbuf());
+ }
+ explicit basic_ofstream(char const *file_name,std::ios_base::openmode mode = std::ios_base::out) :
+ internal_stream_type(new internal_buffer_type())
+ {
+ buf_ = static_cast<internal_buffer_type *>(internal_stream_type::rdbuf());
+ open(file_name,mode);
+ }
+ void open(char const *file_name,std::ios_base::openmode mode = std::ios_base::out)
+ {
+ if(!buf_->open(file_name,mode | std::ios_base::out))
+ {
+ this->setstate(std::ios_base::failbit);
+ }
+ else
+ {
+ this->clear();
+ }
+ }
+ bool is_open()
+ {
+ return buf_->is_open();
+ }
+ bool is_open() const
+ {
+ return buf_->is_open();
+ }
+ void close()
+ {
+ if(!buf_->close())
+ {
+ this->setstate(std::ios_base::failbit);
+ }
+ else
+ {
+ this->clear();
+ }
+ }
+
+ internal_buffer_type *rdbuf() const
+ {
+ return buf_.get();
+ }
+ ~basic_ofstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT
+ {
+ buf_->close();
+ delete buf_;
+ }
+
+ private:
+ internal_buffer_type* buf_;
+};
+
+ typedef basic_ifstream<char> ifstream;
+ typedef basic_ofstream<char> ofstream;
+
+# undef @KWSYS_NAMESPACE@_FStream_NOEXCEPT
+#else
+ using std::ofstream;
+ using std::ifstream;
+#endif
+
+ namespace FStream
+ {
+ enum BOM
+ {
+ BOM_None,
+ BOM_UTF8,
+ BOM_UTF16BE,
+ BOM_UTF16LE,
+ BOM_UTF32BE,
+ BOM_UTF32LE
+ };
+
+ // Read a BOM, if one exists.
+ // If a BOM exists, the stream is advanced to after the BOM.
+ // This function requires a seekable stream (but not a relative
+ // seekable stream).
+ BOM ReadBOM(std::istream& in);
+ }
+}
+
+#endif
diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
new file mode 100644
index 0000000..9d63459
--- /dev/null
+++ b/Source/kwsys/Glob.cxx
@@ -0,0 +1,559 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Glob.hxx)
+
+#include KWSYS_HEADER(Configure.hxx)
+
+#include KWSYS_HEADER(RegularExpression.hxx)
+#include KWSYS_HEADER(SystemTools.hxx)
+#include KWSYS_HEADER(Directory.hxx)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "Glob.hxx.in"
+# include "Directory.hxx.in"
+# include "Configure.hxx.in"
+# include "RegularExpression.hxx.in"
+# include "SystemTools.hxx.in"
+#endif
+
+#include <string>
+#include <vector>
+#include <algorithm>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+namespace KWSYS_NAMESPACE
+{
+#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
+// On Windows and apple, no difference between lower and upper case
+# define KWSYS_GLOB_CASE_INDEPENDENT
+#endif
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+// Handle network paths
+# define KWSYS_GLOB_SUPPORT_NETWORK_PATHS
+#endif
+
+//----------------------------------------------------------------------------
+class GlobInternals
+{
+public:
+ std::vector<std::string> Files;
+ std::vector<kwsys::RegularExpression> Expressions;
+};
+
+//----------------------------------------------------------------------------
+Glob::Glob()
+{
+ this->Internals = new GlobInternals;
+ this->Recurse = false;
+ this->Relative = "";
+
+ this->RecurseThroughSymlinks = true;
+ // RecurseThroughSymlinks is true by default for backwards compatibility,
+ // not because it's a good idea...
+ this->FollowedSymlinkCount = 0;
+
+ // Keep separate variables for directory listing for back compatibility
+ this->ListDirs = true;
+ this->RecurseListDirs = false;
+}
+
+//----------------------------------------------------------------------------
+Glob::~Glob()
+{
+ delete this->Internals;
+}
+
+//----------------------------------------------------------------------------
+std::vector<std::string>& Glob::GetFiles()
+{
+ return this->Internals->Files;
+}
+
+//----------------------------------------------------------------------------
+std::string Glob::PatternToRegex(const std::string& pattern,
+ bool require_whole_string,
+ bool preserve_case)
+{
+ // Incrementally build the regular expression from the pattern.
+ std::string regex = require_whole_string? "^" : "";
+ std::string::const_iterator pattern_first = pattern.begin();
+ std::string::const_iterator pattern_last = pattern.end();
+ for(std::string::const_iterator i = pattern_first;
+ i != pattern_last; ++i)
+ {
+ int c = *i;
+ if(c == '*')
+ {
+ // A '*' (not between brackets) matches any string.
+ // We modify this to not match slashes since the orignal glob
+ // pattern documentation was meant for matching file name
+ // components separated by slashes.
+ regex += "[^/]*";
+ }
+ else if(c == '?')
+ {
+ // A '?' (not between brackets) matches any single character.
+ // We modify this to not match slashes since the orignal glob
+ // pattern documentation was meant for matching file name
+ // components separated by slashes.
+ regex += "[^/]";
+ }
+ else if(c == '[')
+ {
+ // Parse out the bracket expression. It begins just after the
+ // opening character.
+ std::string::const_iterator bracket_first = i+1;
+ std::string::const_iterator bracket_last = bracket_first;
+
+ // The first character may be complementation '!' or '^'.
+ if(bracket_last != pattern_last &&
+ (*bracket_last == '!' || *bracket_last == '^'))
+ {
+ ++bracket_last;
+ }
+
+ // If the next character is a ']' it is included in the brackets
+ // because the bracket string may not be empty.
+ if(bracket_last != pattern_last && *bracket_last == ']')
+ {
+ ++bracket_last;
+ }
+
+ // Search for the closing ']'.
+ while(bracket_last != pattern_last && *bracket_last != ']')
+ {
+ ++bracket_last;
+ }
+
+ // Check whether we have a complete bracket string.
+ if(bracket_last == pattern_last)
+ {
+ // The bracket string did not end, so it was opened simply by
+ // a '[' that is supposed to be matched literally.
+ regex += "\\[";
+ }
+ else
+ {
+ // Convert the bracket string to its regex equivalent.
+ std::string::const_iterator k = bracket_first;
+
+ // Open the regex block.
+ regex += "[";
+
+ // A regex range complement uses '^' instead of '!'.
+ if(k != bracket_last && *k == '!')
+ {
+ regex += "^";
+ ++k;
+ }
+
+ // Convert the remaining characters.
+ for(; k != bracket_last; ++k)
+ {
+ // Backslashes must be escaped.
+ if(*k == '\\')
+ {
+ regex += "\\";
+ }
+
+ // Store this character.
+ regex += *k;
+ }
+
+ // Close the regex block.
+ regex += "]";
+
+ // Jump to the end of the bracket string.
+ i = bracket_last;
+ }
+ }
+ else
+ {
+ // A single character matches itself.
+ int ch = c;
+ if(!(('a' <= ch && ch <= 'z') ||
+ ('A' <= ch && ch <= 'Z') ||
+ ('0' <= ch && ch <= '9')))
+ {
+ // Escape the non-alphanumeric character.
+ regex += "\\";
+ }
+#if defined(KWSYS_GLOB_CASE_INDEPENDENT)
+ else
+ {
+ // On case-insensitive systems file names are converted to lower
+ // case before matching.
+ if(!preserve_case)
+ {
+ ch = tolower(ch);
+ }
+ }
+#endif
+ (void)preserve_case;
+ // Store the character.
+ regex.append(1, static_cast<char>(ch));
+ }
+ }
+
+ if(require_whole_string)
+ {
+ regex += "$";
+ }
+ return regex;
+}
+
+//----------------------------------------------------------------------------
+bool Glob::RecurseDirectory(std::string::size_type start,
+ const std::string& dir, GlobMessages* messages)
+{
+ kwsys::Directory d;
+ if ( !d.Load(dir) )
+ {
+ return true;
+ }
+ unsigned long cc;
+ std::string realname;
+ std::string fname;
+ for ( cc = 0; cc < d.GetNumberOfFiles(); cc ++ )
+ {
+ fname = d.GetFile(cc);
+ if ( fname == "." || fname == ".." )
+ {
+ continue;
+ }
+
+ if ( start == 0 )
+ {
+ realname = dir + fname;
+ }
+ else
+ {
+ realname = dir + "/" + fname;
+ }
+
+#if defined( KWSYS_GLOB_CASE_INDEPENDENT )
+ // On Windows and apple, no difference between lower and upper case
+ fname = kwsys::SystemTools::LowerCase(fname);
+#endif
+
+ bool isDir = kwsys::SystemTools::FileIsDirectory(realname);
+ bool isSymLink = kwsys::SystemTools::FileIsSymlink(realname);
+
+ if ( isDir && (!isSymLink || this->RecurseThroughSymlinks) )
+ {
+ if (isSymLink)
+ {
+ ++this->FollowedSymlinkCount;
+ std::string realPathErrorMessage;
+ std::string canonicalPath(SystemTools::GetRealPath(dir,
+ &realPathErrorMessage));
+
+ if(!realPathErrorMessage.empty())
+ {
+ if(messages)
+ {
+ messages->push_back(Message(
+ Glob::error, "Canonical path generation from path '"
+ + dir + "' failed! Reason: '" + realPathErrorMessage + "'"));
+ }
+ return false;
+ }
+
+ if(std::find(this->VisitedSymlinks.begin(),
+ this->VisitedSymlinks.end(),
+ canonicalPath) == this->VisitedSymlinks.end())
+ {
+ if(this->RecurseListDirs)
+ {
+ // symlinks are treated as directories
+ this->AddFile(this->Internals->Files, realname);
+ }
+
+ this->VisitedSymlinks.push_back(canonicalPath);
+ if(!this->RecurseDirectory(start+1, realname, messages))
+ {
+ this->VisitedSymlinks.pop_back();
+
+ return false;
+ }
+ this->VisitedSymlinks.pop_back();
+ }
+ // else we have already visited this symlink - prevent cyclic recursion
+ else if(messages)
+ {
+ std::string message;
+ for(std::vector<std::string>::const_iterator
+ pathIt = std::find(this->VisitedSymlinks.begin(),
+ this->VisitedSymlinks.end(),
+ canonicalPath);
+ pathIt != this->VisitedSymlinks.end(); ++pathIt)
+ {
+ message += *pathIt + "\n";
+ }
+ message += canonicalPath + "/" + fname;
+ messages->push_back(Message(Glob::cyclicRecursion, message));
+ }
+ }
+ else
+ {
+ if(this->RecurseListDirs)
+ {
+ this->AddFile(this->Internals->Files, realname);
+ }
+ if(!this->RecurseDirectory(start+1, realname, messages))
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ if ( !this->Internals->Expressions.empty() &&
+ this->Internals->Expressions.rbegin()->find(fname) )
+ {
+ this->AddFile(this->Internals->Files, realname);
+ }
+ }
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
+void Glob::ProcessDirectory(std::string::size_type start,
+ const std::string& dir, GlobMessages* messages)
+{
+ //std::cout << "ProcessDirectory: " << dir << std::endl;
+ bool last = ( start == this->Internals->Expressions.size()-1 );
+ if ( last && this->Recurse )
+ {
+ this->RecurseDirectory(start, dir, messages);
+ return;
+ }
+
+ if ( start >= this->Internals->Expressions.size() )
+ {
+ return;
+ }
+
+ kwsys::Directory d;
+ if ( !d.Load(dir) )
+ {
+ return;
+ }
+ unsigned long cc;
+ std::string realname;
+ std::string fname;
+ for ( cc = 0; cc < d.GetNumberOfFiles(); cc ++ )
+ {
+ fname = d.GetFile(cc);
+ if ( fname == "." || fname == ".." )
+ {
+ continue;
+ }
+
+ if ( start == 0 )
+ {
+ realname = dir + fname;
+ }
+ else
+ {
+ realname = dir + "/" + fname;
+ }
+
+#if defined(KWSYS_GLOB_CASE_INDEPENDENT)
+ // On case-insensitive file systems convert to lower case for matching.
+ fname = kwsys::SystemTools::LowerCase(fname);
+#endif
+
+ //std::cout << "Look at file: " << fname << std::endl;
+ //std::cout << "Match: "
+ // << this->Internals->TextExpressions[start].c_str() << std::endl;
+ //std::cout << "Real name: " << realname << std::endl;
+
+ if( (!last && !kwsys::SystemTools::FileIsDirectory(realname))
+ || (!this->ListDirs && last &&
+ kwsys::SystemTools::FileIsDirectory(realname)) )
+ {
+ continue;
+ }
+
+ if ( this->Internals->Expressions[start].find(fname) )
+ {
+ if ( last )
+ {
+ this->AddFile(this->Internals->Files, realname);
+ }
+ else
+ {
+ this->ProcessDirectory(start+1, realname, messages);
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+bool Glob::FindFiles(const std::string& inexpr, GlobMessages* messages)
+{
+ std::string cexpr;
+ std::string::size_type cc;
+ std::string expr = inexpr;
+
+ this->Internals->Expressions.clear();
+ this->Internals->Files.clear();
+
+ if ( !kwsys::SystemTools::FileIsFullPath(expr) )
+ {
+ expr = kwsys::SystemTools::GetCurrentWorkingDirectory();
+ expr += "/" + inexpr;
+ }
+ std::string fexpr = expr;
+
+ std::string::size_type skip = 0;
+ std::string::size_type last_slash = 0;
+ for ( cc = 0; cc < expr.size(); cc ++ )
+ {
+ if ( cc > 0 && expr[cc] == '/' && expr[cc-1] != '\\' )
+ {
+ last_slash = cc;
+ }
+ if ( cc > 0 &&
+ (expr[cc] == '[' || expr[cc] == '?' || expr[cc] == '*') &&
+ expr[cc-1] != '\\' )
+ {
+ break;
+ }
+ }
+ if ( last_slash > 0 )
+ {
+ //std::cout << "I can skip: " << fexpr.substr(0, last_slash)
+ // << std::endl;
+ skip = last_slash;
+ }
+ if ( skip == 0 )
+ {
+#if defined( KWSYS_GLOB_SUPPORT_NETWORK_PATHS )
+ // Handle network paths
+ if ( expr[0] == '/' && expr[1] == '/' )
+ {
+ int cnt = 0;
+ for ( cc = 2; cc < expr.size(); cc ++ )
+ {
+ if ( expr[cc] == '/' )
+ {
+ cnt ++;
+ if ( cnt == 2 )
+ {
+ break;
+ }
+ }
+ }
+ skip = int(cc + 1);
+ }
+ else
+#endif
+ // Handle drive letters on Windows
+ if ( expr[1] == ':' && expr[0] != '/' )
+ {
+ skip = 2;
+ }
+ }
+
+ if ( skip > 0 )
+ {
+ expr = expr.substr(skip);
+ }
+
+ cexpr = "";
+ for ( cc = 0; cc < expr.size(); cc ++ )
+ {
+ int ch = expr[cc];
+ if ( ch == '/' )
+ {
+ if ( !cexpr.empty() )
+ {
+ this->AddExpression(cexpr);
+ }
+ cexpr = "";
+ }
+ else
+ {
+ cexpr.append(1, static_cast<char>(ch));
+ }
+ }
+ if ( !cexpr.empty() )
+ {
+ this->AddExpression(cexpr);
+ }
+
+ // Handle network paths
+ if ( skip > 0 )
+ {
+ this->ProcessDirectory(0, fexpr.substr(0, skip) + "/", messages);
+ }
+ else
+ {
+ this->ProcessDirectory(0, "/", messages);
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+void Glob::AddExpression(const std::string& expr)
+{
+ this->Internals->Expressions.push_back(
+ kwsys::RegularExpression(
+ this->PatternToRegex(expr)));
+}
+
+//----------------------------------------------------------------------------
+void Glob::SetRelative(const char* dir)
+{
+ if ( !dir )
+ {
+ this->Relative = "";
+ return;
+ }
+ this->Relative = dir;
+}
+
+//----------------------------------------------------------------------------
+const char* Glob::GetRelative()
+{
+ if ( this->Relative.empty() )
+ {
+ return 0;
+ }
+ return this->Relative.c_str();
+}
+
+//----------------------------------------------------------------------------
+void Glob::AddFile(std::vector<std::string>& files, const std::string& file)
+{
+ if ( !this->Relative.empty() )
+ {
+ files.push_back(kwsys::SystemTools::RelativePath(this->Relative, file));
+ }
+ else
+ {
+ files.push_back(file);
+ }
+}
+
+} // namespace KWSYS_NAMESPACE
+
diff --git a/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in
new file mode 100644
index 0000000..ffee9ca
--- /dev/null
+++ b/Source/kwsys/Glob.hxx.in
@@ -0,0 +1,152 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_Glob_hxx
+#define @KWSYS_NAMESPACE@_Glob_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <string>
+#include <vector>
+
+namespace @KWSYS_NAMESPACE@
+{
+
+class GlobInternals;
+
+/** \class Glob
+ * \brief Portable globbing searches.
+ *
+ * Globbing expressions are much simpler than regular
+ * expressions. This class will search for files using
+ * globbing expressions.
+ *
+ * Finds all files that match a given globbing expression.
+ */
+class @KWSYS_NAMESPACE@_EXPORT Glob
+{
+public:
+ enum MessageType
+ {
+ error,
+ cyclicRecursion
+ };
+
+ struct Message
+ {
+ MessageType type;
+ std::string content;
+
+ Message(MessageType t, const std::string& c) :
+ type(t),
+ 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;
+ }
+ };
+
+ typedef std::vector<Message> GlobMessages;
+ typedef std::vector<Message>::iterator GlobMessagesIterator;
+public:
+ Glob();
+ ~Glob();
+
+ //! Find all files that match the pattern.
+ bool FindFiles(const std::string& inexpr,
+ GlobMessages* messages = 0);
+
+ //! Return the list of files that matched.
+ std::vector<std::string>& GetFiles();
+
+ //! Set recurse to true to match subdirectories.
+ void RecurseOn() { this->SetRecurse(true); }
+ void RecurseOff() { this->SetRecurse(false); }
+ void SetRecurse(bool i) { this->Recurse = i; }
+ bool GetRecurse() { return this->Recurse; }
+
+ //! Set recurse through symlinks to true if recursion should traverse the
+ // linked-to directories
+ void RecurseThroughSymlinksOn() { this->SetRecurseThroughSymlinks(true); }
+ void RecurseThroughSymlinksOff() { this->SetRecurseThroughSymlinks(false); }
+ void SetRecurseThroughSymlinks(bool i) { this->RecurseThroughSymlinks = i; }
+ bool GetRecurseThroughSymlinks() { return this->RecurseThroughSymlinks; }
+
+ //! Get the number of symlinks followed through recursion
+ unsigned int GetFollowedSymlinkCount() { return this->FollowedSymlinkCount; }
+
+ //! Set relative to true to only show relative path to files.
+ void SetRelative(const char* dir);
+ const char* GetRelative();
+
+ /** Convert the given globbing pattern to a regular expression.
+ There is no way to quote meta-characters. The
+ require_whole_string argument specifies whether the regex is
+ automatically surrounded by "^" and "$" to match the whole
+ string. This is on by default because patterns always match
+ whole strings, but may be disabled to support concatenating
+ expressions more easily (regex1|regex2|etc). */
+ static std::string PatternToRegex(const std::string& pattern,
+ bool require_whole_string = true,
+ bool preserve_case = false);
+
+ /** Getters and setters for enabling and disabling directory
+ listing in recursive and non recursive globbing mode.
+ If listing is enabled in recursive mode it also lists
+ directory symbolic links even if follow symlinks is enabled. */
+ void SetListDirs(bool list) { this->ListDirs=list; }
+ bool GetListDirs() const { return this->ListDirs; }
+ void SetRecurseListDirs(bool list) { this->RecurseListDirs=list; }
+ bool GetRecurseListDirs() const { return this->RecurseListDirs; }
+
+protected:
+ //! Process directory
+ void ProcessDirectory(std::string::size_type start,
+ const std::string& dir,
+ GlobMessages* messages);
+
+ //! Process last directory, but only when recurse flags is on. That is
+ // effectively like saying: /path/to/file/**/file
+ bool RecurseDirectory(std::string::size_type start,
+ const std::string& dir,
+ GlobMessages* messages);
+
+ //! Add regular expression
+ void AddExpression(const std::string& expr);
+
+ //! Add a file to the list
+ void AddFile(std::vector<std::string>& files, const std::string& file);
+
+ GlobInternals* Internals;
+ bool Recurse;
+ std::string Relative;
+ bool RecurseThroughSymlinks;
+ unsigned int FollowedSymlinkCount;
+ std::vector<std::string> VisitedSymlinks;
+ bool ListDirs;
+ bool RecurseListDirs;
+
+private:
+ Glob(const Glob&); // Not implemented.
+ void operator=(const Glob&); // Not implemented.
+};
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/Source/kwsys/IOStream.cxx b/Source/kwsys/IOStream.cxx
new file mode 100644
index 0000000..81c6a73
--- /dev/null
+++ b/Source/kwsys/IOStream.cxx
@@ -0,0 +1,250 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Configure.hxx)
+
+// Include the streams library.
+#include <iostream>
+#include KWSYS_HEADER(IOStream.hxx)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "Configure.hxx.in"
+# include "IOStream.hxx.in"
+#endif
+
+// Implement the rest of this file only if it is needed.
+#if KWSYS_IOS_NEED_OPERATORS_LL
+
+# include <stdio.h> // sscanf, sprintf
+# include <string.h> // memchr
+
+# if defined(_MAX_INT_DIG)
+# define KWSYS_IOS_INT64_MAX_DIG _MAX_INT_DIG
+# else
+# define KWSYS_IOS_INT64_MAX_DIG 32
+# endif
+
+namespace KWSYS_NAMESPACE
+{
+
+// Scan an input stream for an integer value.
+static int IOStreamScanStream(std::istream& is, char* buffer)
+{
+ // Prepare to write to buffer.
+ char* out = buffer;
+ char* end = buffer + KWSYS_IOS_INT64_MAX_DIG - 1;
+
+ // Look for leading sign.
+ if(is.peek() == '+') { *out++ = '+'; is.ignore(); }
+ else if(is.peek() == '-') { *out++ = '-'; is.ignore(); }
+
+ // Determine the base. If not specified in the stream, try to
+ // detect it from the input. A leading 0x means hex, and a leading
+ // 0 alone means octal.
+ int base = 0;
+ int flags = is.flags() & std::ios_base::basefield;
+ if(flags == std::ios_base::oct) { base = 8; }
+ else if(flags == std::ios_base::dec) { base = 10; }
+ else if(flags == std::ios_base::hex) { base = 16; }
+ bool foundDigit = false;
+ bool foundNonZero = false;
+ if(is.peek() == '0')
+ {
+ foundDigit = true;
+ is.ignore();
+ if((is.peek() == 'x' || is.peek() == 'X') && (base == 0 || base == 16))
+ {
+ base = 16;
+ foundDigit = false;
+ is.ignore();
+ }
+ else if (base == 0)
+ {
+ base = 8;
+ }
+ }
+
+ // Determine the range of digits allowed for this number.
+ const char* digits = "0123456789abcdefABCDEF";
+ int maxDigitIndex = 10;
+ if(base == 8)
+ {
+ maxDigitIndex = 8;
+ }
+ else if(base == 16)
+ {
+ maxDigitIndex = 10+6+6;
+ }
+
+ // Scan until an invalid digit is found.
+ for(;is.peek() != EOF; is.ignore())
+ {
+ if(memchr(digits, *out = (char)is.peek(), maxDigitIndex) != 0)
+ {
+ if((foundNonZero || *out != '0') && out < end)
+ {
+ ++out;
+ foundNonZero = true;
+ }
+ foundDigit = true;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // Correct the buffer contents for degenerate cases.
+ if(foundDigit && !foundNonZero)
+ {
+ *out++ = '0';
+ }
+ else if (!foundDigit)
+ {
+ out = buffer;
+ }
+
+ // Terminate the string in the buffer.
+ *out = '\0';
+
+ return base;
+}
+
+// Read an integer value from an input stream.
+template <class T>
+std::istream&
+IOStreamScanTemplate(std::istream& is, T& value, char type)
+{
+ int state = std::ios_base::goodbit;
+
+ // Skip leading whitespace.
+ std::istream::sentry okay(is);
+
+ if(okay)
+ {
+ try {
+ // Copy the string to a buffer and construct the format string.
+ char buffer[KWSYS_IOS_INT64_MAX_DIG];
+# if defined(_MSC_VER)
+ char format[] = "%I64_";
+ const int typeIndex = 4;
+# else
+ char format[] = "%ll_";
+ const int typeIndex = 3;
+# endif
+ switch(IOStreamScanStream(is, buffer))
+ {
+ case 8: format[typeIndex] = 'o'; break;
+ case 0: // Default to decimal if not told otherwise.
+ case 10: format[typeIndex] = type; break;
+ case 16: format[typeIndex] = 'x'; break;
+ };
+
+ // Use sscanf to parse the number from the buffer.
+ T result;
+ int success = (sscanf(buffer, format, &result) == 1)?1:0;
+
+ // Set flags for resulting state.
+ if(is.peek() == EOF) { state |= std::ios_base::eofbit; }
+ if(!success) { state |= std::ios_base::failbit; }
+ else { value = result; }
+ } catch(...) { state |= std::ios_base::badbit; }
+ }
+
+ is.setstate(std::ios_base::iostate(state));
+ return is;
+}
+
+// Print an integer value to an output stream.
+template <class T>
+std::ostream&
+IOStreamPrintTemplate(std::ostream& os, T value, char type)
+{
+ std::ostream::sentry okay(os);
+ if(okay)
+ {
+ try {
+ // Construct the format string.
+ char format[8];
+ char* f = format;
+ *f++ = '%';
+ if(os.flags() & std::ios_base::showpos) { *f++ = '+'; }
+ if(os.flags() & std::ios_base::showbase) { *f++ = '#'; }
+# if defined(_MSC_VER)
+ *f++ = 'I'; *f++ = '6'; *f++ = '4';
+# else
+ *f++ = 'l'; *f++ = 'l';
+# endif
+ long bflags = os.flags() & std::ios_base::basefield;
+ if(bflags == std::ios_base::oct) { *f++ = 'o'; }
+ else if(bflags != std::ios_base::hex) { *f++ = type; }
+ else if(os.flags() & std::ios_base::uppercase) { *f++ = 'X'; }
+ else { *f++ = 'x'; }
+ *f = '\0';
+
+ // Use sprintf to print to a buffer and then write the
+ // buffer to the stream.
+ char buffer[2*KWSYS_IOS_INT64_MAX_DIG];
+ sprintf(buffer, format, value);
+ os << buffer;
+ } catch(...) { os.clear(os.rdstate() | std::ios_base::badbit); }
+ }
+ return os;
+}
+
+# if !KWSYS_IOS_HAS_ISTREAM_LONG_LONG
+// Implement input stream operator for IOStreamSLL.
+std::istream& IOStreamScan(std::istream& is, IOStreamSLL& value)
+{
+ return IOStreamScanTemplate(is, value, 'd');
+}
+
+// Implement input stream operator for IOStreamULL.
+std::istream& IOStreamScan(std::istream& is, IOStreamULL& value)
+{
+ return IOStreamScanTemplate(is, value, 'u');
+}
+# endif
+
+# if !KWSYS_IOS_HAS_OSTREAM_LONG_LONG
+// Implement output stream operator for IOStreamSLL.
+std::ostream& IOStreamPrint(std::ostream& os, IOStreamSLL value)
+{
+ return IOStreamPrintTemplate(os, value, 'd');
+}
+
+// Implement output stream operator for IOStreamULL.
+std::ostream& IOStreamPrint(std::ostream& os, IOStreamULL value)
+{
+ return IOStreamPrintTemplate(os, value, 'u');
+}
+# endif
+
+} // namespace KWSYS_NAMESPACE
+
+#else
+
+namespace KWSYS_NAMESPACE
+{
+
+// Create one public symbol in this object file to avoid warnings from
+// archivers.
+void IOStreamSymbolToAvoidWarning();
+void IOStreamSymbolToAvoidWarning()
+{
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#endif // KWSYS_IOS_NEED_OPERATORS_LL
diff --git a/Source/kwsys/IOStream.hxx.in b/Source/kwsys/IOStream.hxx.in
new file mode 100644
index 0000000..c101909
--- /dev/null
+++ b/Source/kwsys/IOStream.hxx.in
@@ -0,0 +1,136 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_IOStream_hxx
+#define @KWSYS_NAMESPACE@_IOStream_hxx
+
+#include <iosfwd>
+
+/* Define these macros temporarily to keep the code readable. */
+#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+
+/* Whether istream supports long long. */
+#define @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG @KWSYS_IOS_HAS_ISTREAM_LONG_LONG@
+
+/* Whether ostream supports long long. */
+#define @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG @KWSYS_IOS_HAS_OSTREAM_LONG_LONG@
+
+/* Determine whether we need to define the streaming operators for
+ long long or __int64. */
+#if @KWSYS_USE_LONG_LONG@
+# if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG || \
+ !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG
+# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1
+ namespace @KWSYS_NAMESPACE@
+ {
+ typedef long long IOStreamSLL;
+ typedef unsigned long long IOStreamULL;
+ }
+# endif
+#elif defined(_MSC_VER) && _MSC_VER < 1300
+# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1
+ namespace @KWSYS_NAMESPACE@
+ {
+ typedef __int64 IOStreamSLL;
+ typedef unsigned __int64 IOStreamULL;
+ }
+#endif
+#if !defined(@KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL)
+# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 0
+#endif
+
+#if @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL
+# if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG
+
+/* Input stream operator implementation functions. */
+namespace @KWSYS_NAMESPACE@
+{
+kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamSLL&);
+kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamULL&);
+}
+
+/* Provide input stream operator for long long. */
+# if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_LONG_LONG) && \
+ !defined(KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED)
+# define KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED
+# define @KWSYS_NAMESPACE@_IOS_ISTREAM_LONG_LONG_DEFINED
+inline std::istream&
+operator>>(std::istream& is, @KWSYS_NAMESPACE@::IOStreamSLL& value)
+{
+ return @KWSYS_NAMESPACE@::IOStreamScan(is, value);
+}
+# endif
+
+/* Provide input stream operator for unsigned long long. */
+# if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_UNSIGNED_LONG_LONG) && \
+ !defined(KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED)
+# define KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED
+# define @KWSYS_NAMESPACE@_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED
+inline std::istream&
+operator>>(std::istream& is, @KWSYS_NAMESPACE@::IOStreamULL& value)
+{
+ return @KWSYS_NAMESPACE@::IOStreamScan(is, value);
+}
+# endif
+# endif /* !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG */
+
+# if !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG
+
+/* Output stream operator implementation functions. */
+namespace @KWSYS_NAMESPACE@
+{
+kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamSLL);
+kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamULL);
+}
+
+/* Provide output stream operator for long long. */
+# if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_LONG_LONG) && \
+ !defined(KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED)
+# define KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED
+# define @KWSYS_NAMESPACE@_IOS_OSTREAM_LONG_LONG_DEFINED
+inline std::ostream&
+operator<<(std::ostream& os, @KWSYS_NAMESPACE@::IOStreamSLL value)
+{
+ return @KWSYS_NAMESPACE@::IOStreamPrint(os, value);
+}
+# endif
+
+/* Provide output stream operator for unsigned long long. */
+# if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_UNSIGNED_LONG_LONG) && \
+ !defined(KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED)
+# define KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED
+# define @KWSYS_NAMESPACE@_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED
+inline std::ostream&
+operator<<(std::ostream& os, @KWSYS_NAMESPACE@::IOStreamULL value)
+{
+ return @KWSYS_NAMESPACE@::IOStreamPrint(os, value);
+}
+# endif
+# endif /* !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG */
+#endif /* @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL */
+
+/* Undefine temporary macros. */
+#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# undef kwsysEXPORT
+#endif
+
+/* If building a C++ file in kwsys itself, give the source file
+ access to the macros without a configured namespace. */
+#if defined(KWSYS_NAMESPACE)
+# define KWSYS_IOS_HAS_ISTREAM_LONG_LONG @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG
+# define KWSYS_IOS_HAS_OSTREAM_LONG_LONG @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG
+# define KWSYS_IOS_NEED_OPERATORS_LL @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL
+#endif
+
+#endif
+
diff --git a/Source/kwsys/MD5.c b/Source/kwsys/MD5.c
new file mode 100644
index 0000000..b75acb2
--- /dev/null
+++ b/Source/kwsys/MD5.c
@@ -0,0 +1,523 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(MD5.h)
+
+/* Work-around CMake dependency scanning limitation. This must
+ duplicate the above list of headers. */
+#if 0
+# include "MD5.h.in"
+#endif
+
+#include <stddef.h> /* size_t */
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* memcpy, strlen */
+
+/*--------------------------------------------------------------------------*/
+
+/* This MD5 implementation has been taken from a third party. Slight
+ modifications to the arrangement of the code have been made to put
+ it in a single source file instead of a separate header and
+ implementation file. */
+
+#if defined(__clang__) && !defined(__INTEL_COMPILER)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wcast-align"
+#endif
+
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+# define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+ md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ md5_word_t t;
+#if BYTE_ORDER > 0
+ /* Define storage only for big-endian CPUs. */
+ md5_word_t X[16];
+#else
+ /* Define storage for little-endian or both types of CPUs. */
+ md5_word_t xbuf[16];
+ const md5_word_t *X;
+#endif
+
+ {
+#if BYTE_ORDER == 0
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+#endif
+#if BYTE_ORDER == 0
+ else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const md5_byte_t *xp = data;
+ int i;
+
+# if BYTE_ORDER == 0
+ X = xbuf; /* (dynamic only) */
+# else
+# define xbuf X /* (static only) */
+# endif
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = (md5_word_t)(xp[0] + (xp[1] << 8) +
+ (xp[2] << 16) + (xp[3] << 24));
+ }
+#endif
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + (Ti);\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + (Ti);\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + (Ti);\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + (Ti);\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+/* Initialize the algorithm. */
+static void md5_init(md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+/* Append a string to the message. */
+static void md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes)
+{
+ const md5_byte_t *p = data;
+ size_t left = nbytes;
+ size_t offset = (pms->count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += (md5_word_t)(nbytes >> 29);
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+/* Finish the message and return the digest. */
+static void md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+ static const md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
+
+#if defined(__clang__) && !defined(__INTEL_COMPILER)
+# pragma clang diagnostic pop
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Wrap up the MD5 state in our opaque structure. */
+struct kwsysMD5_s
+{
+ md5_state_t md5_state;
+};
+
+/*--------------------------------------------------------------------------*/
+kwsysMD5* kwsysMD5_New(void)
+{
+ /* Allocate a process control structure. */
+ kwsysMD5* md5 = (kwsysMD5*)malloc(sizeof(kwsysMD5));
+ if(!md5)
+ {
+ return 0;
+ }
+ return md5;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysMD5_Delete(kwsysMD5* md5)
+{
+ /* Make sure we have an instance. */
+ if(!md5)
+ {
+ return;
+ }
+
+ /* Free memory. */
+ free(md5);
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysMD5_Initialize(kwsysMD5* md5)
+{
+ md5_init(&md5->md5_state);
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data, int length)
+{
+ size_t dlen;
+ if(length < 0)
+ {
+ dlen = strlen((char const*)data);
+ }
+ else
+ {
+ dlen = (size_t)length;
+ }
+ md5_append(&md5->md5_state, (md5_byte_t const*)data, dlen);
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysMD5_Finalize(kwsysMD5* md5, unsigned char digest[16])
+{
+ md5_finish(&md5->md5_state, (md5_byte_t*)digest);
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysMD5_FinalizeHex(kwsysMD5* md5, char buffer[32])
+{
+ unsigned char digest[16];
+ kwsysMD5_Finalize(md5, digest);
+ kwsysMD5_DigestToHex(digest, buffer);
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysMD5_DigestToHex(unsigned char const digest[16], char buffer[32])
+{
+ /* Map from 4-bit index to hexadecimal representation. */
+ static char const hex[16] =
+ {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+ /* Map each 4-bit block separately. */
+ char* out = buffer;
+ int i;
+ for(i=0; i < 16; ++i)
+ {
+ *out++ = hex[digest[i] >> 4];
+ *out++ = hex[digest[i] & 0xF];
+ }
+}
diff --git a/Source/kwsys/MD5.h.in b/Source/kwsys/MD5.h.in
new file mode 100644
index 0000000..3334431
--- /dev/null
+++ b/Source/kwsys/MD5.h.in
@@ -0,0 +1,107 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_MD5_h
+#define @KWSYS_NAMESPACE@_MD5_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+/* Redefine all public interface symbol names to be in the proper
+ namespace. These macros are used internally to kwsys only, and are
+ not visible to user code. Use kwsysHeaderDump.pl to reproduce
+ these macros after making changes to the interface. */
+#if !defined(KWSYS_NAMESPACE)
+# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# define kwsysMD5 kwsys_ns(MD5)
+# define kwsysMD5_s kwsys_ns(MD5_s)
+# define kwsysMD5_New kwsys_ns(MD5_New)
+# define kwsysMD5_Delete kwsys_ns(MD5_Delete)
+# define kwsysMD5_Initialize kwsys_ns(MD5_Initialize)
+# define kwsysMD5_Append kwsys_ns(MD5_Append)
+# define kwsysMD5_Finalize kwsys_ns(MD5_Finalize)
+# define kwsysMD5_FinalizeHex kwsys_ns(MD5_FinalizeHex)
+# define kwsysMD5_DigestToHex kwsys_ns(MD5_DigestToHex)
+#endif
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/**
+ * MD5 state data structure.
+ */
+typedef struct kwsysMD5_s kwsysMD5;
+
+/**
+ * Create a new MD5 instance. The returned instance is not initialized.
+ */
+kwsysEXPORT kwsysMD5* kwsysMD5_New(void);
+
+/**
+ * Delete an old MD5 instance.
+ */
+kwsysEXPORT void kwsysMD5_Delete(kwsysMD5* md5);
+
+/**
+ * Initialize a new MD5 digest.
+ */
+kwsysEXPORT void kwsysMD5_Initialize(kwsysMD5* md5);
+
+/**
+ * Append data to an MD5 digest. If the given length is negative,
+ * data will be read up to but not including a terminating null.
+ */
+kwsysEXPORT void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data,
+ int length);
+
+/**
+ * Finalize a MD5 digest and get the 16-byte hash value.
+ */
+kwsysEXPORT void kwsysMD5_Finalize(kwsysMD5* md5, unsigned char digest[16]);
+
+/**
+ * Finalize a MD5 digest and get the 32-bit hexadecimal representation.
+ */
+kwsysEXPORT void kwsysMD5_FinalizeHex(kwsysMD5* md5, char buffer[32]);
+
+/**
+ * Convert a MD5 digest 16-byte value to a 32-byte hexadecimal representation.
+ */
+kwsysEXPORT void kwsysMD5_DigestToHex(unsigned char const digest[16],
+ char buffer[32]);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+ Otherwise, undefine them to keep the namespace clean. */
+#if !defined(KWSYS_NAMESPACE)
+# undef kwsys_ns
+# undef kwsysEXPORT
+# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# undef kwsysMD5
+# undef kwsysMD5_s
+# undef kwsysMD5_New
+# undef kwsysMD5_Delete
+# undef kwsysMD5_Initialize
+# undef kwsysMD5_Append
+# undef kwsysMD5_Finalize
+# undef kwsysMD5_FinalizeHex
+# undef kwsysMD5_DigestToHex
+# endif
+#endif
+
+#endif
diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in
new file mode 100644
index 0000000..96563a2
--- /dev/null
+++ b/Source/kwsys/Process.h.in
@@ -0,0 +1,469 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_Process_h
+#define @KWSYS_NAMESPACE@_Process_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+/* Redefine all public interface symbol names to be in the proper
+ namespace. These macros are used internally to kwsys only, and are
+ not visible to user code. Use kwsysHeaderDump.pl to reproduce
+ these macros after making changes to the interface. */
+#if !defined(KWSYS_NAMESPACE)
+# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# define kwsysProcess kwsys_ns(Process)
+# define kwsysProcess_s kwsys_ns(Process_s)
+# define kwsysProcess_New kwsys_ns(Process_New)
+# define kwsysProcess_Delete kwsys_ns(Process_Delete)
+# define kwsysProcess_SetCommand kwsys_ns(Process_SetCommand)
+# define kwsysProcess_AddCommand kwsys_ns(Process_AddCommand)
+# define kwsysProcess_SetTimeout kwsys_ns(Process_SetTimeout)
+# define kwsysProcess_SetWorkingDirectory kwsys_ns(Process_SetWorkingDirectory)
+# define kwsysProcess_SetPipeFile kwsys_ns(Process_SetPipeFile)
+# define kwsysProcess_SetPipeNative kwsys_ns(Process_SetPipeNative)
+# define kwsysProcess_SetPipeShared kwsys_ns(Process_SetPipeShared)
+# define kwsysProcess_Option_Detach kwsys_ns(Process_Option_Detach)
+# define kwsysProcess_Option_HideWindow kwsys_ns(Process_Option_HideWindow)
+# define kwsysProcess_Option_MergeOutput kwsys_ns(Process_Option_MergeOutput)
+# define kwsysProcess_Option_Verbatim kwsys_ns(Process_Option_Verbatim)
+# define kwsysProcess_Option_CreateProcessGroup kwsys_ns(Process_Option_CreateProcessGroup)
+# define kwsysProcess_GetOption kwsys_ns(Process_GetOption)
+# define kwsysProcess_SetOption kwsys_ns(Process_SetOption)
+# define kwsysProcess_Option_e kwsys_ns(Process_Option_e)
+# define kwsysProcess_State_Starting kwsys_ns(Process_State_Starting)
+# define kwsysProcess_State_Error kwsys_ns(Process_State_Error)
+# define kwsysProcess_State_Exception kwsys_ns(Process_State_Exception)
+# define kwsysProcess_State_Executing kwsys_ns(Process_State_Executing)
+# define kwsysProcess_State_Exited kwsys_ns(Process_State_Exited)
+# define kwsysProcess_State_Expired kwsys_ns(Process_State_Expired)
+# define kwsysProcess_State_Killed kwsys_ns(Process_State_Killed)
+# define kwsysProcess_State_Disowned kwsys_ns(Process_State_Disowned)
+# define kwsysProcess_GetState kwsys_ns(Process_GetState)
+# define kwsysProcess_State_e kwsys_ns(Process_State_e)
+# define kwsysProcess_Exception_None kwsys_ns(Process_Exception_None)
+# define kwsysProcess_Exception_Fault kwsys_ns(Process_Exception_Fault)
+# define kwsysProcess_Exception_Illegal kwsys_ns(Process_Exception_Illegal)
+# define kwsysProcess_Exception_Interrupt kwsys_ns(Process_Exception_Interrupt)
+# define kwsysProcess_Exception_Numerical kwsys_ns(Process_Exception_Numerical)
+# define kwsysProcess_Exception_Other kwsys_ns(Process_Exception_Other)
+# define kwsysProcess_GetExitException kwsys_ns(Process_GetExitException)
+# define kwsysProcess_Exception_e kwsys_ns(Process_Exception_e)
+# define kwsysProcess_GetExitCode kwsys_ns(Process_GetExitCode)
+# define kwsysProcess_GetExitValue kwsys_ns(Process_GetExitValue)
+# define kwsysProcess_GetErrorString kwsys_ns(Process_GetErrorString)
+# define kwsysProcess_GetExceptionString kwsys_ns(Process_GetExceptionString)
+# define kwsysProcess_Execute kwsys_ns(Process_Execute)
+# define kwsysProcess_Disown kwsys_ns(Process_Disown)
+# define kwsysProcess_WaitForData kwsys_ns(Process_WaitForData)
+# define kwsysProcess_Pipes_e kwsys_ns(Process_Pipes_e)
+# define kwsysProcess_Pipe_None kwsys_ns(Process_Pipe_None)
+# define kwsysProcess_Pipe_STDIN kwsys_ns(Process_Pipe_STDIN)
+# define kwsysProcess_Pipe_STDOUT kwsys_ns(Process_Pipe_STDOUT)
+# define kwsysProcess_Pipe_STDERR kwsys_ns(Process_Pipe_STDERR)
+# define kwsysProcess_Pipe_Timeout kwsys_ns(Process_Pipe_Timeout)
+# define kwsysProcess_Pipe_Handle kwsys_ns(Process_Pipe_Handle)
+# define kwsysProcess_WaitForExit kwsys_ns(Process_WaitForExit)
+# define kwsysProcess_Interrupt kwsys_ns(Process_Interrupt)
+# define kwsysProcess_Kill kwsys_ns(Process_Kill)
+# define kwsysProcess_ResetStartTime kwsys_ns(Process_ResetStartTime)
+#endif
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/**
+ * Process control data structure.
+ */
+typedef struct kwsysProcess_s kwsysProcess;
+
+/* Platform-specific pipe handle type. */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+typedef void* kwsysProcess_Pipe_Handle;
+#else
+typedef int kwsysProcess_Pipe_Handle;
+#endif
+
+/**
+ * Create a new Process instance.
+ */
+kwsysEXPORT kwsysProcess* kwsysProcess_New(void);
+
+/**
+ * Delete an existing Process instance. If the instance is currently
+ * executing a process, this blocks until the process terminates.
+ */
+kwsysEXPORT void kwsysProcess_Delete(kwsysProcess* cp);
+
+/**
+ * Set the command line to be executed. Argument is an array of
+ * pointers to the command and each argument. The array must end with
+ * a NULL pointer. Any previous command lines are removed. Returns
+ * 1 for success and 0 otherwise.
+ */
+kwsysEXPORT int kwsysProcess_SetCommand(kwsysProcess* cp,
+ char const* const* command);
+
+/**
+ * Add a command line to be executed. Argument is an array of
+ * pointers to the command and each argument. The array must end with
+ * a NULL pointer. If this is not the first command added, its
+ * standard input will be connected to the standard output of the
+ * previous command. Returns 1 for success and 0 otherwise.
+ */
+kwsysEXPORT int kwsysProcess_AddCommand(kwsysProcess* cp,
+ char const* const* command);
+
+/**
+ * Set the timeout in seconds for the child process. The timeout
+ * period begins when the child is executed. If the child has not
+ * terminated when the timeout expires, it will be killed. A
+ * non-positive (<= 0) value will disable the timeout.
+ */
+kwsysEXPORT void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout);
+
+/**
+ * Set the working directory for the child process. The working
+ * directory can be absolute or relative to the current directory.
+ * Returns 1 for success and 0 for failure.
+ */
+kwsysEXPORT int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp,
+ const char* dir);
+
+/**
+ * Set the name of a file to be attached to the given pipe. Returns 1
+ * for success and 0 for failure.
+ */
+kwsysEXPORT int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe,
+ const char* file);
+
+/**
+ * Set whether the given pipe in the child is shared with the parent
+ * process. The default is no for Pipe_STDOUT and Pipe_STDERR and yes
+ * for Pipe_STDIN.
+ */
+kwsysEXPORT void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe,
+ int shared);
+
+/**
+ * Specify a platform-specific native pipe for use as one of the child
+ * interface pipes. The native pipe is specified by an array of two
+ * descriptors or handles. The first entry in the array (index 0)
+ * should be the read end of the pipe. The second entry in the array
+ * (index 1) should be the write end of the pipe. If a null pointer
+ * is given the option will be disabled.
+ *
+ * For Pipe_STDIN the native pipe is connected to the first child in
+ * the pipeline as its stdin. After the children are created the
+ * write end of the pipe will be closed in the child process and the
+ * read end will be closed in the parent process.
+ *
+ * For Pipe_STDOUT and Pipe_STDERR the pipe is connected to the last
+ * child as its stdout or stderr. After the children are created the
+ * write end of the pipe will be closed in the parent process and the
+ * read end will be closed in the child process.
+ */
+kwsysEXPORT void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe,
+ kwsysProcess_Pipe_Handle p[2]);
+
+/**
+ * Get/Set a possibly platform-specific option. Possible options are:
+ *
+ * kwsysProcess_Option_Detach = Whether to detach the process.
+ * 0 = No (default)
+ * 1 = Yes
+ *
+ * kwsysProcess_Option_HideWindow = Whether to hide window on Windows.
+ * 0 = No (default)
+ * 1 = Yes
+ *
+ * kwsysProcess_Option_MergeOutput = Whether to merge stdout/stderr.
+ * No content will be returned as stderr.
+ * Any actual stderr will be on stdout.
+ * 0 = No (default)
+ * 1 = Yes
+ *
+ * kwsysProcess_Option_Verbatim = Whether SetCommand and AddCommand
+ * should treat the first argument
+ * as a verbatim command line
+ * and ignore the rest of the arguments.
+ * 0 = No (default)
+ * 1 = Yes
+ *
+ * kwsysProcess_Option_CreateProcessGroup = Whether to place the process in a
+ * new process group. This is
+ * useful if you want to send Ctrl+C
+ * to the process. On UNIX, also
+ * places the process in a new
+ * session.
+ * 0 = No (default)
+ * 1 = Yes
+ */
+kwsysEXPORT int kwsysProcess_GetOption(kwsysProcess* cp, int optionId);
+kwsysEXPORT void kwsysProcess_SetOption(kwsysProcess* cp, int optionId,
+ int value);
+enum kwsysProcess_Option_e
+{
+ kwsysProcess_Option_HideWindow,
+ kwsysProcess_Option_Detach,
+ kwsysProcess_Option_MergeOutput,
+ kwsysProcess_Option_Verbatim,
+ kwsysProcess_Option_CreateProcessGroup
+};
+
+/**
+ * Get the current state of the Process instance. Possible states are:
+ *
+ * kwsysProcess_State_Starting = Execute has not yet been called.
+ * kwsysProcess_State_Error = Error administrating the child process.
+ * kwsysProcess_State_Exception = Child process exited abnormally.
+ * kwsysProcess_State_Executing = Child process is currently running.
+ * kwsysProcess_State_Exited = Child process exited normally.
+ * kwsysProcess_State_Expired = Child process's timeout expired.
+ * kwsysProcess_State_Killed = Child process terminated by Kill method.
+ * kwsysProcess_State_Disowned = Child is no longer managed by this object.
+ */
+kwsysEXPORT int kwsysProcess_GetState(kwsysProcess* cp);
+enum kwsysProcess_State_e
+{
+ kwsysProcess_State_Starting,
+ kwsysProcess_State_Error,
+ kwsysProcess_State_Exception,
+ kwsysProcess_State_Executing,
+ kwsysProcess_State_Exited,
+ kwsysProcess_State_Expired,
+ kwsysProcess_State_Killed,
+ kwsysProcess_State_Disowned
+};
+
+/**
+ * When GetState returns "Exception", this method returns a
+ * platform-independent description of the exceptional behavior that
+ * caused the child to terminate abnormally. Possible exceptions are:
+ *
+ * kwsysProcess_Exception_None = No exceptional behavior occurred.
+ * kwsysProcess_Exception_Fault = Child crashed with a memory fault.
+ * kwsysProcess_Exception_Illegal = Child crashed with an illegal instruction.
+ * kwsysProcess_Exception_Interrupt = Child was interrupted by user (Cntl-C/Break).
+ * kwsysProcess_Exception_Numerical = Child crashed with a numerical exception.
+ * kwsysProcess_Exception_Other = Child terminated for another reason.
+ */
+kwsysEXPORT int kwsysProcess_GetExitException(kwsysProcess* cp);
+enum kwsysProcess_Exception_e
+{
+ kwsysProcess_Exception_None,
+ kwsysProcess_Exception_Fault,
+ kwsysProcess_Exception_Illegal,
+ kwsysProcess_Exception_Interrupt,
+ kwsysProcess_Exception_Numerical,
+ kwsysProcess_Exception_Other
+};
+
+/**
+ * When GetState returns "Exited" or "Exception", this method returns
+ * the platform-specific raw exit code of the process. UNIX platforms
+ * should use WIFEXITED/WEXITSTATUS and WIFSIGNALED/WTERMSIG to access
+ * this value. Windows users should compare the value to the various
+ * EXCEPTION_* values.
+ *
+ * If GetState returns "Exited", use GetExitValue to get the
+ * platform-independent child return value.
+ */
+kwsysEXPORT int kwsysProcess_GetExitCode(kwsysProcess* cp);
+
+/**
+ * When GetState returns "Exited", this method returns the child's
+ * platform-independent exit code (such as the value returned by the
+ * child's main).
+ */
+kwsysEXPORT int kwsysProcess_GetExitValue(kwsysProcess* cp);
+
+/**
+ * When GetState returns "Error", this method returns a string
+ * describing the problem. Otherwise, it returns NULL.
+ */
+kwsysEXPORT const char* kwsysProcess_GetErrorString(kwsysProcess* cp);
+
+/**
+ * When GetState returns "Exception", this method returns a string
+ * describing the problem. Otherwise, it returns NULL.
+ */
+kwsysEXPORT const char* kwsysProcess_GetExceptionString(kwsysProcess* cp);
+
+/**
+ * Start executing the child process.
+ */
+kwsysEXPORT void kwsysProcess_Execute(kwsysProcess* cp);
+
+/**
+ * Stop management of a detached child process. This closes any pipes
+ * being read. If the child was not created with the
+ * kwsysProcess_Option_Detach option, this method does nothing. This
+ * is because disowning a non-detached process will cause the child
+ * exit signal to be left unhandled until this process exits.
+ */
+kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp);
+
+/**
+ * Block until data are available on a pipe, a timeout expires, or the
+ * child process terminates. Arguments are as follows:
+ *
+ * data = If data are read, the pointer to which this points is
+ * set to point to the data.
+ * length = If data are read, the integer to which this points is
+ * set to the length of the data read.
+ * timeout = Specifies the maximum time this call may block. Upon
+ * return after reading data, the time elapsed is subtracted
+ * from the timeout value. If this timeout expires, the
+ * value is set to 0. A NULL pointer passed for this argument
+ * indicates no timeout for the call. A negative or zero
+ * value passed for this argument may be used for polling
+ * and will always return immediately.
+ *
+ * Return value will be one of:
+ *
+ * Pipe_None = No more data will be available from the child process,
+ * ( == 0) or no process has been executed. WaitForExit should
+ * be called to wait for the process to terminate.
+ * Pipe_STDOUT = Data have been read from the child's stdout pipe.
+ * Pipe_STDERR = Data have been read from the child's stderr pipe.
+ * Pipe_Timeout = No data available within timeout specified for the
+ * call. Time elapsed has been subtracted from timeout
+ * argument.
+ */
+kwsysEXPORT int kwsysProcess_WaitForData(kwsysProcess* cp, char** data,
+ int* length, double* timeout);
+enum kwsysProcess_Pipes_e
+{
+ kwsysProcess_Pipe_None,
+ kwsysProcess_Pipe_STDIN,
+ kwsysProcess_Pipe_STDOUT,
+ kwsysProcess_Pipe_STDERR,
+ kwsysProcess_Pipe_Timeout=255
+};
+
+/**
+ * Block until the child process terminates or the given timeout
+ * expires. If no process is running, returns immediatly. The
+ * argument is:
+ *
+ * timeout = Specifies the maximum time this call may block. Upon
+ * returning due to child termination, the elapsed time
+ * is subtracted from the given value. A NULL pointer
+ * passed for this argument indicates no timeout for the
+ * call.
+ *
+ * Return value will be one of:
+ *
+ * 0 = Child did not terminate within timeout specified for
+ * the call. Time elapsed has been subtracted from timeout
+ * argument.
+ * 1 = Child has terminated or was not running.
+ */
+kwsysEXPORT int kwsysProcess_WaitForExit(kwsysProcess* cp, double* timeout);
+
+/**
+ * Interrupt the process group for the child process that is currently
+ * running by sending it the appropriate operating-system specific signal.
+ * The caller should call WaitForExit after this returns to wait for the
+ * child to terminate.
+ *
+ * WARNING: If you didn't specify kwsysProcess_Option_CreateProcessGroup,
+ * you will interrupt your own process group.
+ */
+kwsysEXPORT void kwsysProcess_Interrupt(kwsysProcess* cp);
+
+/**
+ * Forcefully terminate the child process that is currently running.
+ * The caller should call WaitForExit after this returns to wait for
+ * the child to terminate.
+ */
+kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
+
+/**
+ * Reset the start time of the child process to the current time.
+ */
+kwsysEXPORT void kwsysProcess_ResetStartTime(kwsysProcess* cp);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+ Otherwise, undefine them to keep the namespace clean. */
+#if !defined(KWSYS_NAMESPACE)
+# undef kwsys_ns
+# undef kwsysEXPORT
+# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# undef kwsysProcess
+# undef kwsysProcess_s
+# undef kwsysProcess_New
+# undef kwsysProcess_Delete
+# undef kwsysProcess_SetCommand
+# undef kwsysProcess_AddCommand
+# undef kwsysProcess_SetTimeout
+# undef kwsysProcess_SetWorkingDirectory
+# undef kwsysProcess_SetPipeFile
+# undef kwsysProcess_SetPipeNative
+# undef kwsysProcess_SetPipeShared
+# undef kwsysProcess_Option_Detach
+# undef kwsysProcess_Option_HideWindow
+# undef kwsysProcess_Option_MergeOutput
+# undef kwsysProcess_Option_Verbatim
+# undef kwsysProcess_Option_CreateProcessGroup
+# undef kwsysProcess_GetOption
+# undef kwsysProcess_SetOption
+# undef kwsysProcess_Option_e
+# undef kwsysProcess_State_Starting
+# undef kwsysProcess_State_Error
+# undef kwsysProcess_State_Exception
+# undef kwsysProcess_State_Executing
+# undef kwsysProcess_State_Exited
+# undef kwsysProcess_State_Expired
+# undef kwsysProcess_State_Killed
+# undef kwsysProcess_State_Disowned
+# undef kwsysProcess_GetState
+# undef kwsysProcess_State_e
+# undef kwsysProcess_Exception_None
+# undef kwsysProcess_Exception_Fault
+# undef kwsysProcess_Exception_Illegal
+# undef kwsysProcess_Exception_Interrupt
+# undef kwsysProcess_Exception_Numerical
+# undef kwsysProcess_Exception_Other
+# undef kwsysProcess_GetExitException
+# undef kwsysProcess_Exception_e
+# undef kwsysProcess_GetExitCode
+# undef kwsysProcess_GetExitValue
+# undef kwsysProcess_GetErrorString
+# undef kwsysProcess_GetExceptionString
+# undef kwsysProcess_Execute
+# undef kwsysProcess_Disown
+# undef kwsysProcess_WaitForData
+# undef kwsysProcess_Pipes_e
+# undef kwsysProcess_Pipe_None
+# undef kwsysProcess_Pipe_STDIN
+# undef kwsysProcess_Pipe_STDOUT
+# undef kwsysProcess_Pipe_STDERR
+# undef kwsysProcess_Pipe_Timeout
+# undef kwsysProcess_Pipe_Handle
+# undef kwsysProcess_WaitForExit
+# undef kwsysProcess_Interrupt
+# undef kwsysProcess_Kill
+# undef kwsysProcess_ResetStartTime
+# endif
+#endif
+
+#endif
diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c
new file mode 100644
index 0000000..b577982
--- /dev/null
+++ b/Source/kwsys/ProcessUNIX.c
@@ -0,0 +1,3071 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Process.h)
+#include KWSYS_HEADER(System.h)
+
+/* Work-around CMake dependency scanning limitation. This must
+ duplicate the above list of headers. */
+#if 0
+# include "Process.h.in"
+# include "System.h.in"
+#endif
+
+/*
+
+Implementation for UNIX
+
+On UNIX, a child process is forked to exec the program. Three output
+pipes are read by the parent process using a select call to block
+until data are ready. Two of the pipes are stdout and stderr for the
+child. The third is a special pipe populated by a signal handler to
+indicate that a child has terminated. This is used in conjunction
+with the timeout on the select call to implement a timeout for program
+even when it closes stdout and stderr and at the same time avoiding
+races.
+
+*/
+
+
+/*
+
+TODO:
+
+We cannot create the pipeline of processes in suspended states. How
+do we cleanup processes already started when one fails to load? Right
+now we are just killing them, which is probably not the right thing to
+do.
+
+*/
+
+#if defined(__CYGWIN__)
+/* Increase the file descriptor limit for select() before including
+ related system headers. (Default: 64) */
+# define FD_SETSIZE 16384
+#endif
+
+#include <stddef.h> /* ptrdiff_t */
+#include <stdio.h> /* snprintf */
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* strdup, strerror, memset */
+#include <sys/time.h> /* struct timeval */
+#include <sys/types.h> /* pid_t, fd_set */
+#include <sys/wait.h> /* waitpid */
+#include <sys/stat.h> /* open mode */
+#include <unistd.h> /* pipe, close, fork, execvp, select, _exit */
+#include <fcntl.h> /* fcntl */
+#include <errno.h> /* errno */
+#include <time.h> /* gettimeofday */
+#include <signal.h> /* sigaction */
+#include <dirent.h> /* DIR, dirent */
+#include <ctype.h> /* isspace */
+#include <assert.h> /* assert */
+
+#if defined(__VMS)
+# define KWSYSPE_VMS_NONBLOCK , O_NONBLOCK
+#else
+# define KWSYSPE_VMS_NONBLOCK
+#endif
+
+#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T
+typedef ptrdiff_t kwsysProcess_ptrdiff_t;
+#else
+typedef int kwsysProcess_ptrdiff_t;
+#endif
+
+#if defined(KWSYS_C_HAS_SSIZE_T) && KWSYS_C_HAS_SSIZE_T
+typedef ssize_t kwsysProcess_ssize_t;
+#else
+typedef int kwsysProcess_ssize_t;
+#endif
+
+#if defined(__BEOS__) && !defined(__ZETA__)
+/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */
+# include <be/kernel/OS.h>
+static inline void kwsysProcess_usleep(unsigned int msec)
+{
+ snooze(msec);
+}
+#else
+# define kwsysProcess_usleep usleep
+#endif
+
+/*
+ * BeOS's select() works like WinSock: it's for networking only, and
+ * doesn't work with Unix file handles...socket and file handles are
+ * different namespaces (the same descriptor means different things in
+ * each context!)
+ *
+ * So on Unix-like systems where select() is flakey, we'll set the
+ * pipes' file handles to be non-blocking and just poll them directly
+ * without select().
+ */
+#if !defined(__BEOS__) && !defined(__VMS) && !defined(__MINT__)
+# define KWSYSPE_USE_SELECT 1
+#endif
+
+/* Some platforms do not have siginfo on their signal handlers. */
+#if defined(SA_SIGINFO) && !defined(__BEOS__)
+# define KWSYSPE_USE_SIGINFO 1
+#endif
+
+/* The number of pipes for the child's output. The standard stdout
+ and stderr pipes are the first two. One more pipe is used to
+ detect when the child process has terminated. The third pipe is
+ not given to the child process, so it cannot close it until it
+ terminates. */
+#define KWSYSPE_PIPE_COUNT 3
+#define KWSYSPE_PIPE_STDOUT 0
+#define KWSYSPE_PIPE_STDERR 1
+#define KWSYSPE_PIPE_SIGNAL 2
+
+/* The maximum amount to read from a pipe at a time. */
+#define KWSYSPE_PIPE_BUFFER_SIZE 1024
+
+/* Keep track of times using a signed representation. Switch to the
+ native (possibly unsigned) representation only when calling native
+ functions. */
+typedef struct timeval kwsysProcessTimeNative;
+typedef struct kwsysProcessTime_s kwsysProcessTime;
+struct kwsysProcessTime_s
+{
+ long tv_sec;
+ long tv_usec;
+};
+
+typedef struct kwsysProcessCreateInformation_s
+{
+ int StdIn;
+ int StdOut;
+ int StdErr;
+ int ErrorPipe[2];
+} kwsysProcessCreateInformation;
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessVolatileFree(volatile void* p);
+static int kwsysProcessInitialize(kwsysProcess* cp);
+static void kwsysProcessCleanup(kwsysProcess* cp, int error);
+static void kwsysProcessCleanupDescriptor(int* pfd);
+static void kwsysProcessClosePipes(kwsysProcess* cp);
+static int kwsysProcessSetNonBlocking(int fd);
+static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
+ kwsysProcessCreateInformation* si);
+static void kwsysProcessDestroy(kwsysProcess* cp);
+static int kwsysProcessSetupOutputPipeFile(int* p, const char* name);
+static int kwsysProcessSetupOutputPipeNative(int* p, int des[2]);
+static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
+ kwsysProcessTime* timeoutTime);
+static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
+ double* userTimeout,
+ kwsysProcessTimeNative* timeoutLength,
+ int zeroIsExpired);
+static kwsysProcessTime kwsysProcessTimeGetCurrent(void);
+static double kwsysProcessTimeToDouble(kwsysProcessTime t);
+static kwsysProcessTime kwsysProcessTimeFromDouble(double d);
+static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2);
+static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2);
+static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime in2);
+static void kwsysProcessSetExitException(kwsysProcess* cp, int sig);
+static void kwsysProcessChildErrorExit(int errorPipe);
+static void kwsysProcessRestoreDefaultSignalHandlers(void);
+static pid_t kwsysProcessFork(kwsysProcess* cp,
+ kwsysProcessCreateInformation* si);
+static void kwsysProcessKill(pid_t process_id);
+#if defined(__VMS)
+static int kwsysProcessSetVMSFeature(const char* name, int value);
+#endif
+static int kwsysProcessesAdd(kwsysProcess* cp);
+static void kwsysProcessesRemove(kwsysProcess* cp);
+#if KWSYSPE_USE_SIGINFO
+static void kwsysProcessesSignalHandler(int signum, siginfo_t* info,
+ void* ucontext);
+#else
+static void kwsysProcessesSignalHandler(int signum);
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Structure containing data used to implement the child's execution. */
+struct kwsysProcess_s
+{
+ /* The command lines to execute. */
+ char*** Commands;
+ volatile int NumberOfCommands;
+
+ /* Descriptors for the read ends of the child's output pipes and
+ the signal pipe. */
+ int PipeReadEnds[KWSYSPE_PIPE_COUNT];
+
+ /* Descriptors for the child's ends of the pipes.
+ Used temporarily during process creation. */
+ int PipeChildStd[3];
+
+ /* Write descriptor for child termination signal pipe. */
+ int SignalPipe;
+
+ /* Buffer for pipe data. */
+ char PipeBuffer[KWSYSPE_PIPE_BUFFER_SIZE];
+
+ /* Process IDs returned by the calls to fork. Everything is volatile
+ because the signal handler accesses them. You must be very careful
+ when reaping PIDs or modifying this array to avoid race conditions. */
+ volatile pid_t* volatile ForkPIDs;
+
+ /* Flag for whether the children were terminated by a faild select. */
+ int SelectError;
+
+ /* The timeout length. */
+ double Timeout;
+
+ /* The working directory for the process. */
+ char* WorkingDirectory;
+
+ /* Whether to create the child as a detached process. */
+ int OptionDetach;
+
+ /* Whether the child was created as a detached process. */
+ int Detached;
+
+ /* Whether to treat command lines as verbatim. */
+ int Verbatim;
+
+ /* Whether to merge stdout/stderr of the child. */
+ int MergeOutput;
+
+ /* Whether to create the process in a new process group. */
+ volatile sig_atomic_t CreateProcessGroup;
+
+ /* Time at which the child started. Negative for no timeout. */
+ kwsysProcessTime StartTime;
+
+ /* Time at which the child will timeout. Negative for no timeout. */
+ kwsysProcessTime TimeoutTime;
+
+ /* Flag for whether the timeout expired. */
+ int TimeoutExpired;
+
+ /* The number of pipes left open during execution. */
+ int PipesLeft;
+
+#if KWSYSPE_USE_SELECT
+ /* File descriptor set for call to select. */
+ fd_set PipeSet;
+#endif
+
+ /* The number of children still executing. */
+ int CommandsLeft;
+
+ /* The current status of the child process. Must be atomic because
+ the signal handler checks this to avoid a race. */
+ volatile sig_atomic_t State;
+
+ /* The exceptional behavior that terminated the child process, if
+ * any. */
+ int ExitException;
+
+ /* The exit code of the child process. */
+ int ExitCode;
+
+ /* The exit value of the child process, if any. */
+ int ExitValue;
+
+ /* Whether the process was killed. */
+ volatile sig_atomic_t Killed;
+
+ /* Buffer for error message in case of failure. */
+ char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1];
+
+ /* Description for the ExitException. */
+ char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE+1];
+
+ /* The exit codes of each child process in the pipeline. */
+ int* CommandExitCodes;
+
+ /* Name of files to which stdin and stdout pipes are attached. */
+ char* PipeFileSTDIN;
+ char* PipeFileSTDOUT;
+ char* PipeFileSTDERR;
+
+ /* Whether each pipe is shared with the parent process. */
+ int PipeSharedSTDIN;
+ int PipeSharedSTDOUT;
+ int PipeSharedSTDERR;
+
+ /* Native pipes provided by the user. */
+ int PipeNativeSTDIN[2];
+ int PipeNativeSTDOUT[2];
+ int PipeNativeSTDERR[2];
+
+ /* The real working directory of this process. */
+ int RealWorkingDirectoryLength;
+ char* RealWorkingDirectory;
+};
+
+/*--------------------------------------------------------------------------*/
+kwsysProcess* kwsysProcess_New(void)
+{
+ /* Allocate a process control structure. */
+ kwsysProcess* cp = (kwsysProcess*)malloc(sizeof(kwsysProcess));
+ if(!cp)
+ {
+ return 0;
+ }
+ memset(cp, 0, sizeof(kwsysProcess));
+
+ /* Share stdin with the parent process by default. */
+ cp->PipeSharedSTDIN = 1;
+
+ /* No native pipes by default. */
+ cp->PipeNativeSTDIN[0] = -1;
+ cp->PipeNativeSTDIN[1] = -1;
+ cp->PipeNativeSTDOUT[0] = -1;
+ cp->PipeNativeSTDOUT[1] = -1;
+ cp->PipeNativeSTDERR[0] = -1;
+ cp->PipeNativeSTDERR[1] = -1;
+
+ /* Set initial status. */
+ cp->State = kwsysProcess_State_Starting;
+
+ return cp;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Delete(kwsysProcess* cp)
+{
+ /* Make sure we have an instance. */
+ if(!cp)
+ {
+ return;
+ }
+
+ /* If the process is executing, wait for it to finish. */
+ if(cp->State == kwsysProcess_State_Executing)
+ {
+ if(cp->Detached)
+ {
+ kwsysProcess_Disown(cp);
+ }
+ else
+ {
+ kwsysProcess_WaitForExit(cp, 0);
+ }
+ }
+
+ /* Free memory. */
+ kwsysProcess_SetCommand(cp, 0);
+ kwsysProcess_SetWorkingDirectory(cp, 0);
+ kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0);
+ kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0);
+ kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0);
+ if(cp->CommandExitCodes)
+ {
+ free(cp->CommandExitCodes);
+ }
+ free(cp);
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command)
+{
+ int i;
+ if(!cp)
+ {
+ return 0;
+ }
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ char** c = cp->Commands[i];
+ while(*c)
+ {
+ free(*c++);
+ }
+ free(cp->Commands[i]);
+ }
+ cp->NumberOfCommands = 0;
+ if(cp->Commands)
+ {
+ free(cp->Commands);
+ cp->Commands = 0;
+ }
+ if(command)
+ {
+ return kwsysProcess_AddCommand(cp, command);
+ }
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
+{
+ int newNumberOfCommands;
+ char*** newCommands;
+
+ /* Make sure we have a command to add. */
+ if(!cp || !command || !*command)
+ {
+ return 0;
+ }
+
+ /* Allocate a new array for command pointers. */
+ newNumberOfCommands = cp->NumberOfCommands + 1;
+ if(!(newCommands =
+ (char***)malloc(sizeof(char**) *(size_t)(newNumberOfCommands))))
+ {
+ /* Out of memory. */
+ return 0;
+ }
+
+ /* Copy any existing commands into the new array. */
+ {
+ int i;
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ newCommands[i] = cp->Commands[i];
+ }
+ }
+
+ /* Add the new command. */
+ if(cp->Verbatim)
+ {
+ /* In order to run the given command line verbatim we need to
+ parse it. */
+ newCommands[cp->NumberOfCommands] =
+ kwsysSystem_Parse_CommandForUnix(*command, 0);
+ if(!newCommands[cp->NumberOfCommands] ||
+ !newCommands[cp->NumberOfCommands][0])
+ {
+ /* Out of memory or no command parsed. */
+ free(newCommands);
+ return 0;
+ }
+ }
+ else
+ {
+ /* Copy each argument string individually. */
+ char const* const* c = command;
+ kwsysProcess_ptrdiff_t n = 0;
+ kwsysProcess_ptrdiff_t i = 0;
+ while(*c++);
+ n = c - command - 1;
+ newCommands[cp->NumberOfCommands] =
+ (char**)malloc((size_t)(n+1)*sizeof(char*));
+ if(!newCommands[cp->NumberOfCommands])
+ {
+ /* Out of memory. */
+ free(newCommands);
+ return 0;
+ }
+ for(i=0; i < n; ++i)
+ {
+ assert(command[i]); /* Quiet Clang scan-build. */
+ newCommands[cp->NumberOfCommands][i] = strdup(command[i]);
+ if(!newCommands[cp->NumberOfCommands][i])
+ {
+ break;
+ }
+ }
+ if(i < n)
+ {
+ /* Out of memory. */
+ for(;i > 0; --i)
+ {
+ free(newCommands[cp->NumberOfCommands][i-1]);
+ }
+ free(newCommands);
+ return 0;
+ }
+ newCommands[cp->NumberOfCommands][n] = 0;
+ }
+
+ /* Successfully allocated new command array. Free the old array. */
+ free(cp->Commands);
+ cp->Commands = newCommands;
+ cp->NumberOfCommands = newNumberOfCommands;
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout)
+{
+ if(!cp)
+ {
+ return;
+ }
+ cp->Timeout = timeout;
+ if(cp->Timeout < 0)
+ {
+ cp->Timeout = 0;
+ }
+ // Force recomputation of TimeoutTime.
+ cp->TimeoutTime.tv_sec = -1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
+{
+ if(!cp)
+ {
+ return 0;
+ }
+ if(cp->WorkingDirectory == dir)
+ {
+ return 1;
+ }
+ if(cp->WorkingDirectory && dir && strcmp(cp->WorkingDirectory, dir) == 0)
+ {
+ return 1;
+ }
+ if(cp->WorkingDirectory)
+ {
+ free(cp->WorkingDirectory);
+ cp->WorkingDirectory = 0;
+ }
+ if(dir)
+ {
+ cp->WorkingDirectory = (char*)malloc(strlen(dir) + 1);
+ if(!cp->WorkingDirectory)
+ {
+ return 0;
+ }
+ strcpy(cp->WorkingDirectory, dir);
+ }
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_SetPipeFile(kwsysProcess* cp, int prPipe, const char* file)
+{
+ char** pfile;
+ if(!cp)
+ {
+ return 0;
+ }
+ switch(prPipe)
+ {
+ case kwsysProcess_Pipe_STDIN: pfile = &cp->PipeFileSTDIN; break;
+ case kwsysProcess_Pipe_STDOUT: pfile = &cp->PipeFileSTDOUT; break;
+ case kwsysProcess_Pipe_STDERR: pfile = &cp->PipeFileSTDERR; break;
+ default: return 0;
+ }
+ if(*pfile)
+ {
+ free(*pfile);
+ *pfile = 0;
+ }
+ if(file)
+ {
+ *pfile = (char*)malloc(strlen(file)+1);
+ if(!*pfile)
+ {
+ return 0;
+ }
+ strcpy(*pfile, file);
+ }
+
+ /* If we are redirecting the pipe, do not share it or use a native
+ pipe. */
+ if(*pfile)
+ {
+ kwsysProcess_SetPipeNative(cp, prPipe, 0);
+ kwsysProcess_SetPipeShared(cp, prPipe, 0);
+ }
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetPipeShared(kwsysProcess* cp, int prPipe, int shared)
+{
+ if(!cp)
+ {
+ return;
+ }
+
+ switch(prPipe)
+ {
+ case kwsysProcess_Pipe_STDIN: cp->PipeSharedSTDIN = shared?1:0; break;
+ case kwsysProcess_Pipe_STDOUT: cp->PipeSharedSTDOUT = shared?1:0; break;
+ case kwsysProcess_Pipe_STDERR: cp->PipeSharedSTDERR = shared?1:0; break;
+ default: return;
+ }
+
+ /* If we are sharing the pipe, do not redirect it to a file or use a
+ native pipe. */
+ if(shared)
+ {
+ kwsysProcess_SetPipeFile(cp, prPipe, 0);
+ kwsysProcess_SetPipeNative(cp, prPipe, 0);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetPipeNative(kwsysProcess* cp, int prPipe, int p[2])
+{
+ int* pPipeNative = 0;
+
+ if(!cp)
+ {
+ return;
+ }
+
+ switch(prPipe)
+ {
+ case kwsysProcess_Pipe_STDIN: pPipeNative = cp->PipeNativeSTDIN; break;
+ case kwsysProcess_Pipe_STDOUT: pPipeNative = cp->PipeNativeSTDOUT; break;
+ case kwsysProcess_Pipe_STDERR: pPipeNative = cp->PipeNativeSTDERR; break;
+ default: return;
+ }
+
+ /* Copy the native pipe descriptors provided. */
+ if(p)
+ {
+ pPipeNative[0] = p[0];
+ pPipeNative[1] = p[1];
+ }
+ else
+ {
+ pPipeNative[0] = -1;
+ pPipeNative[1] = -1;
+ }
+
+ /* If we are using a native pipe, do not share it or redirect it to
+ a file. */
+ if(p)
+ {
+ kwsysProcess_SetPipeFile(cp, prPipe, 0);
+ kwsysProcess_SetPipeShared(cp, prPipe, 0);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
+{
+ if(!cp)
+ {
+ return 0;
+ }
+
+ switch(optionId)
+ {
+ case kwsysProcess_Option_Detach: return cp->OptionDetach;
+ case kwsysProcess_Option_MergeOutput: return cp->MergeOutput;
+ case kwsysProcess_Option_Verbatim: return cp->Verbatim;
+ case kwsysProcess_Option_CreateProcessGroup:
+ return cp->CreateProcessGroup;
+ default: return 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
+{
+ if(!cp)
+ {
+ return;
+ }
+
+ switch(optionId)
+ {
+ case kwsysProcess_Option_Detach: cp->OptionDetach = value; break;
+ case kwsysProcess_Option_MergeOutput: cp->MergeOutput = value; break;
+ case kwsysProcess_Option_Verbatim: cp->Verbatim = value; break;
+ case kwsysProcess_Option_CreateProcessGroup:
+ cp->CreateProcessGroup = value; break;
+ default: break;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetState(kwsysProcess* cp)
+{
+ return cp? cp->State : kwsysProcess_State_Error;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitException(kwsysProcess* cp)
+{
+ return cp? cp->ExitException : kwsysProcess_Exception_Other;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitCode(kwsysProcess* cp)
+{
+ return cp? cp->ExitCode : 0;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitValue(kwsysProcess* cp)
+{
+ return cp? cp->ExitValue : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
+{
+ if(!cp)
+ {
+ return "Process management structure could not be allocated";
+ }
+ else if(cp->State == kwsysProcess_State_Error)
+ {
+ return cp->ErrorMessage;
+ }
+ return "Success";
+}
+
+/*--------------------------------------------------------------------------*/
+const char* kwsysProcess_GetExceptionString(kwsysProcess* cp)
+{
+ if(!cp)
+ {
+ return "GetExceptionString called with NULL process management structure";
+ }
+ else if(cp->State == kwsysProcess_State_Exception)
+ {
+ return cp->ExitExceptionString;
+ }
+ return "No exception";
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Execute(kwsysProcess* cp)
+{
+ int i;
+
+ /* Do not execute a second copy simultaneously. */
+ if(!cp || cp->State == kwsysProcess_State_Executing)
+ {
+ return;
+ }
+
+ /* Make sure we have something to run. */
+ if(cp->NumberOfCommands < 1)
+ {
+ strcpy(cp->ErrorMessage, "No command");
+ cp->State = kwsysProcess_State_Error;
+ return;
+ }
+
+ /* Initialize the control structure for a new process. */
+ if(!kwsysProcessInitialize(cp))
+ {
+ strcpy(cp->ErrorMessage, "Out of memory");
+ cp->State = kwsysProcess_State_Error;
+ return;
+ }
+
+#if defined(__VMS)
+ /* Make sure pipes behave like streams on VMS. */
+ if(!kwsysProcessSetVMSFeature("DECC$STREAM_PIPE", 1))
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+#endif
+
+ /* Save the real working directory of this process and change to
+ the working directory for the child processes. This is needed
+ to make pipe file paths evaluate correctly. */
+ if(cp->WorkingDirectory)
+ {
+ int r;
+ if(!getcwd(cp->RealWorkingDirectory,
+ (size_t)(cp->RealWorkingDirectoryLength)))
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+
+ /* Some platforms specify that the chdir call may be
+ interrupted. Repeat the call until it finishes. */
+ while(((r = chdir(cp->WorkingDirectory)) < 0) && (errno == EINTR));
+ if(r < 0)
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+ }
+
+ /* If not running a detached child, add this object to the global
+ set of process objects that wish to be notified when a child
+ exits. */
+ if(!cp->OptionDetach)
+ {
+ if(!kwsysProcessesAdd(cp))
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+ }
+
+ /* Setup the stdin pipe for the first process. */
+ if(cp->PipeFileSTDIN)
+ {
+ /* Open a file for the child's stdin to read. */
+ cp->PipeChildStd[0] = open(cp->PipeFileSTDIN, O_RDONLY);
+ if(cp->PipeChildStd[0] < 0)
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+
+ /* Set close-on-exec flag on the pipe's end. */
+ if(fcntl(cp->PipeChildStd[0], F_SETFD, FD_CLOEXEC) < 0)
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+ }
+ else if(cp->PipeSharedSTDIN)
+ {
+ cp->PipeChildStd[0] = 0;
+ }
+ else if(cp->PipeNativeSTDIN[0] >= 0)
+ {
+ cp->PipeChildStd[0] = cp->PipeNativeSTDIN[0];
+
+ /* Set close-on-exec flag on the pipe's ends. The read end will
+ be dup2-ed into the stdin descriptor after the fork but before
+ the exec. */
+ if((fcntl(cp->PipeNativeSTDIN[0], F_SETFD, FD_CLOEXEC) < 0) ||
+ (fcntl(cp->PipeNativeSTDIN[1], F_SETFD, FD_CLOEXEC) < 0))
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+ }
+ else
+ {
+ cp->PipeChildStd[0] = -1;
+ }
+
+ /* Create the output pipe for the last process.
+ We always create this so the pipe can be passed to select even if
+ it will report closed immediately. */
+ {
+ /* Create the pipe. */
+ int p[2];
+ if(pipe(p KWSYSPE_VMS_NONBLOCK) < 0)
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+
+ /* Store the pipe. */
+ cp->PipeReadEnds[KWSYSPE_PIPE_STDOUT] = p[0];
+ cp->PipeChildStd[1] = p[1];
+
+ /* Set close-on-exec flag on the pipe's ends. */
+ if((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
+ (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0))
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+
+ /* Set to non-blocking in case select lies, or for the polling
+ implementation. */
+ if(!kwsysProcessSetNonBlocking(p[0]))
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+ }
+
+ if (cp->PipeFileSTDOUT)
+ {
+ /* Use a file for stdout. */
+ if(!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1],
+ cp->PipeFileSTDOUT))
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+ }
+ else if (cp->PipeSharedSTDOUT)
+ {
+ /* Use the parent stdout. */
+ kwsysProcessCleanupDescriptor(&cp->PipeChildStd[1]);
+ cp->PipeChildStd[1] = 1;
+ }
+ else if (cp->PipeNativeSTDOUT[1] >= 0)
+ {
+ /* Use the given descriptor for stdout. */
+ if(!kwsysProcessSetupOutputPipeNative(&cp->PipeChildStd[1],
+ cp->PipeNativeSTDOUT))
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+ }
+
+ /* Create stderr pipe to be shared by all processes in the pipeline.
+ We always create this so the pipe can be passed to select even if
+ it will report closed immediately. */
+ {
+ /* Create the pipe. */
+ int p[2];
+ if(pipe(p KWSYSPE_VMS_NONBLOCK) < 0)
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+
+ /* Store the pipe. */
+ cp->PipeReadEnds[KWSYSPE_PIPE_STDERR] = p[0];
+ cp->PipeChildStd[2] = p[1];
+
+ /* Set close-on-exec flag on the pipe's ends. */
+ if((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
+ (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0))
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+
+ /* Set to non-blocking in case select lies, or for the polling
+ implementation. */
+ if(!kwsysProcessSetNonBlocking(p[0]))
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+ }
+
+ if (cp->PipeFileSTDERR)
+ {
+ /* Use a file for stderr. */
+ if(!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2],
+ cp->PipeFileSTDERR))
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+ }
+ else if (cp->PipeSharedSTDERR)
+ {
+ /* Use the parent stderr. */
+ kwsysProcessCleanupDescriptor(&cp->PipeChildStd[2]);
+ cp->PipeChildStd[2] = 2;
+ }
+ else if (cp->PipeNativeSTDERR[1] >= 0)
+ {
+ /* Use the given handle for stderr. */
+ if(!kwsysProcessSetupOutputPipeNative(&cp->PipeChildStd[2],
+ cp->PipeNativeSTDERR))
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+ }
+
+ /* The timeout period starts now. */
+ cp->StartTime = kwsysProcessTimeGetCurrent();
+ cp->TimeoutTime.tv_sec = -1;
+ cp->TimeoutTime.tv_usec = -1;
+
+ /* Create the pipeline of processes. */
+ {
+ kwsysProcessCreateInformation si = {-1, -1, -1, {-1, -1}};
+ int nextStdIn = cp->PipeChildStd[0];
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ /* Setup the process's pipes. */
+ si.StdIn = nextStdIn;
+ if (i == cp->NumberOfCommands-1)
+ {
+ nextStdIn = -1;
+ si.StdOut = cp->PipeChildStd[1];
+ }
+ else
+ {
+ /* Create a pipe to sit between the children. */
+ int p[2] = {-1,-1};
+ if(pipe(p KWSYSPE_VMS_NONBLOCK) < 0)
+ {
+ if (nextStdIn != cp->PipeChildStd[0])
+ {
+ kwsysProcessCleanupDescriptor(&nextStdIn);
+ }
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+
+ /* Set close-on-exec flag on the pipe's ends. */
+ if((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
+ (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0))
+ {
+ close(p[0]);
+ close(p[1]);
+ if (nextStdIn != cp->PipeChildStd[0])
+ {
+ kwsysProcessCleanupDescriptor(&nextStdIn);
+ }
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+ nextStdIn = p[0];
+ si.StdOut = p[1];
+ }
+ si.StdErr = cp->MergeOutput? cp->PipeChildStd[1] : cp->PipeChildStd[2];
+
+ {
+ int res = kwsysProcessCreate(cp, i, &si);
+
+ /* Close our copies of pipes used between children. */
+ if (si.StdIn != cp->PipeChildStd[0])
+ {
+ kwsysProcessCleanupDescriptor(&si.StdIn);
+ }
+ if (si.StdOut != cp->PipeChildStd[1])
+ {
+ kwsysProcessCleanupDescriptor(&si.StdOut);
+ }
+ if (si.StdErr != cp->PipeChildStd[2] && !cp->MergeOutput)
+ {
+ kwsysProcessCleanupDescriptor(&si.StdErr);
+ }
+
+ if(!res)
+ {
+ kwsysProcessCleanupDescriptor(&si.ErrorPipe[0]);
+ kwsysProcessCleanupDescriptor(&si.ErrorPipe[1]);
+ if (nextStdIn != cp->PipeChildStd[0])
+ {
+ kwsysProcessCleanupDescriptor(&nextStdIn);
+ }
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+ }
+ }
+ }
+
+ /* The parent process does not need the child's pipe ends. */
+ for (i=0; i < 3; ++i)
+ {
+ kwsysProcessCleanupDescriptor(&cp->PipeChildStd[i]);
+ }
+
+ /* Restore the working directory. */
+ if(cp->RealWorkingDirectory)
+ {
+ /* Some platforms specify that the chdir call may be
+ interrupted. Repeat the call until it finishes. */
+ while((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR));
+ free(cp->RealWorkingDirectory);
+ cp->RealWorkingDirectory = 0;
+ }
+
+ /* All the pipes are now open. */
+ cp->PipesLeft = KWSYSPE_PIPE_COUNT;
+
+ /* The process has now started. */
+ cp->State = kwsysProcess_State_Executing;
+ cp->Detached = cp->OptionDetach;
+}
+
+/*--------------------------------------------------------------------------*/
+kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp)
+{
+ /* Make sure a detached child process is running. */
+ if(!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing ||
+ cp->TimeoutExpired || cp->Killed)
+ {
+ return;
+ }
+
+ /* Close all the pipes safely. */
+ kwsysProcessClosePipes(cp);
+
+ /* We will not wait for exit, so cleanup now. */
+ kwsysProcessCleanup(cp, 0);
+
+ /* The process has been disowned. */
+ cp->State = kwsysProcess_State_Disowned;
+}
+
+/*--------------------------------------------------------------------------*/
+typedef struct kwsysProcessWaitData_s
+{
+ int Expired;
+ int PipeId;
+ int User;
+ double* UserTimeout;
+ kwsysProcessTime TimeoutTime;
+} kwsysProcessWaitData;
+static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length,
+ kwsysProcessWaitData* wd);
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
+ double* userTimeout)
+{
+ kwsysProcessTime userStartTime = {0, 0};
+ kwsysProcessWaitData wd =
+ {
+ 0,
+ kwsysProcess_Pipe_None,
+ 0,
+ 0,
+ {0, 0}
+ };
+ wd.UserTimeout = userTimeout;
+ /* Make sure we are executing a process. */
+ if(!cp || cp->State != kwsysProcess_State_Executing || cp->Killed ||
+ cp->TimeoutExpired)
+ {
+ return kwsysProcess_Pipe_None;
+ }
+
+ /* Record the time at which user timeout period starts. */
+ if(userTimeout)
+ {
+ userStartTime = kwsysProcessTimeGetCurrent();
+ }
+
+ /* Calculate the time at which a timeout will expire, and whether it
+ is the user or process timeout. */
+ wd.User = kwsysProcessGetTimeoutTime(cp, userTimeout,
+ &wd.TimeoutTime);
+
+ /* Data can only be available when pipes are open. If the process
+ is not running, cp->PipesLeft will be 0. */
+ while(cp->PipesLeft > 0 &&
+ !kwsysProcessWaitForPipe(cp, data, length, &wd)) {}
+
+ /* Update the user timeout. */
+ if(userTimeout)
+ {
+ kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent();
+ kwsysProcessTime difference = kwsysProcessTimeSubtract(userEndTime,
+ userStartTime);
+ double d = kwsysProcessTimeToDouble(difference);
+ *userTimeout -= d;
+ if(*userTimeout < 0)
+ {
+ *userTimeout = 0;
+ }
+ }
+
+ /* Check what happened. */
+ if(wd.PipeId)
+ {
+ /* Data are ready on a pipe. */
+ return wd.PipeId;
+ }
+ else if(wd.Expired)
+ {
+ /* A timeout has expired. */
+ if(wd.User)
+ {
+ /* The user timeout has expired. It has no time left. */
+ return kwsysProcess_Pipe_Timeout;
+ }
+ else
+ {
+ /* The process timeout has expired. Kill the children now. */
+ kwsysProcess_Kill(cp);
+ cp->Killed = 0;
+ cp->TimeoutExpired = 1;
+ return kwsysProcess_Pipe_None;
+ }
+ }
+ else
+ {
+ /* No pipes are left open. */
+ return kwsysProcess_Pipe_None;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length,
+ kwsysProcessWaitData* wd)
+{
+ int i;
+ kwsysProcessTimeNative timeoutLength;
+
+#if KWSYSPE_USE_SELECT
+ int numReady = 0;
+ int max = -1;
+ kwsysProcessTimeNative* timeout = 0;
+
+ /* Check for any open pipes with data reported ready by the last
+ call to select. According to "man select_tut" we must deal
+ with all descriptors reported by a call to select before
+ passing them to another select call. */
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ if(cp->PipeReadEnds[i] >= 0 &&
+ FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet))
+ {
+ kwsysProcess_ssize_t n;
+
+ /* We are handling this pipe now. Remove it from the set. */
+ FD_CLR(cp->PipeReadEnds[i], &cp->PipeSet);
+
+ /* The pipe is ready to read without blocking. Keep trying to
+ read until the operation is not interrupted. */
+ while(((n = read(cp->PipeReadEnds[i], cp->PipeBuffer,
+ KWSYSPE_PIPE_BUFFER_SIZE)) < 0) && (errno == EINTR));
+ if(n > 0)
+ {
+ /* We have data on this pipe. */
+ if(i == KWSYSPE_PIPE_SIGNAL)
+ {
+ /* A child process has terminated. */
+ kwsysProcessDestroy(cp);
+ }
+ else if(data && length)
+ {
+ /* Report this data. */
+ *data = cp->PipeBuffer;
+ *length = (int)(n);
+ switch(i)
+ {
+ case KWSYSPE_PIPE_STDOUT:
+ wd->PipeId = kwsysProcess_Pipe_STDOUT; break;
+ case KWSYSPE_PIPE_STDERR:
+ wd->PipeId = kwsysProcess_Pipe_STDERR; break;
+ };
+ return 1;
+ }
+ }
+ else if(n < 0 && errno == EAGAIN)
+ {
+ /* No data are really ready. The select call lied. See the
+ "man select" page on Linux for cases when this occurs. */
+ }
+ else
+ {
+ /* We are done reading from this pipe. */
+ kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
+ --cp->PipesLeft;
+ }
+ }
+ }
+
+ /* If we have data, break early. */
+ if(wd->PipeId)
+ {
+ return 1;
+ }
+
+ /* Make sure the set is empty (it should always be empty here
+ anyway). */
+ FD_ZERO(&cp->PipeSet);
+
+ /* Setup a timeout if required. */
+ if(wd->TimeoutTime.tv_sec < 0)
+ {
+ timeout = 0;
+ }
+ else
+ {
+ timeout = &timeoutLength;
+ }
+ if(kwsysProcessGetTimeoutLeft(&wd->TimeoutTime,
+ wd->User?wd->UserTimeout:0,
+ &timeoutLength, 0))
+ {
+ /* Timeout has already expired. */
+ wd->Expired = 1;
+ return 1;
+ }
+
+ /* Add the pipe reading ends that are still open. */
+ max = -1;
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ if(cp->PipeReadEnds[i] >= 0)
+ {
+ FD_SET(cp->PipeReadEnds[i], &cp->PipeSet);
+ if(cp->PipeReadEnds[i] > max)
+ {
+ max = cp->PipeReadEnds[i];
+ }
+ }
+ }
+
+ /* Make sure we have a non-empty set. */
+ if(max < 0)
+ {
+ /* All pipes have closed. Child has terminated. */
+ return 1;
+ }
+
+ /* Run select to block until data are available. Repeat call
+ until it is not interrupted. */
+ while(((numReady = select(max+1, &cp->PipeSet, 0, 0, timeout)) < 0) &&
+ (errno == EINTR));
+
+ /* Check result of select. */
+ if(numReady == 0)
+ {
+ /* Select's timeout expired. */
+ wd->Expired = 1;
+ return 1;
+ }
+ else if(numReady < 0)
+ {
+ /* Select returned an error. Leave the error description in the
+ pipe buffer. */
+ strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
+
+ /* Kill the children now. */
+ kwsysProcess_Kill(cp);
+ cp->Killed = 0;
+ cp->SelectError = 1;
+ }
+
+ return 0;
+#else
+ /* Poll pipes for data since we do not have select. */
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ if(cp->PipeReadEnds[i] >= 0)
+ {
+ const int fd = cp->PipeReadEnds[i];
+ int n = read(fd, cp->PipeBuffer, KWSYSPE_PIPE_BUFFER_SIZE);
+ if(n > 0)
+ {
+ /* We have data on this pipe. */
+ if(i == KWSYSPE_PIPE_SIGNAL)
+ {
+ /* A child process has terminated. */
+ kwsysProcessDestroy(cp);
+ }
+ else if(data && length)
+ {
+ /* Report this data. */
+ *data = cp->PipeBuffer;
+ *length = n;
+ switch(i)
+ {
+ case KWSYSPE_PIPE_STDOUT:
+ wd->PipeId = kwsysProcess_Pipe_STDOUT; break;
+ case KWSYSPE_PIPE_STDERR:
+ wd->PipeId = kwsysProcess_Pipe_STDERR; break;
+ };
+ }
+ return 1;
+ }
+ else if (n == 0) /* EOF */
+ {
+ /* We are done reading from this pipe. */
+#if defined(__VMS)
+ if(!cp->CommandsLeft)
+#endif
+ {
+ kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
+ --cp->PipesLeft;
+ }
+ }
+ else if (n < 0) /* error */
+ {
+#if defined(__VMS)
+ if(!cp->CommandsLeft)
+ {
+ kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
+ --cp->PipesLeft;
+ }
+ else
+#endif
+ if((errno != EINTR) && (errno != EAGAIN))
+ {
+ strncpy(cp->ErrorMessage,strerror(errno),
+ KWSYSPE_PIPE_BUFFER_SIZE);
+ /* Kill the children now. */
+ kwsysProcess_Kill(cp);
+ cp->Killed = 0;
+ cp->SelectError = 1;
+ return 1;
+ }
+ }
+ }
+ }
+
+ /* If we have data, break early. */
+ if(wd->PipeId)
+ {
+ return 1;
+ }
+
+ if(kwsysProcessGetTimeoutLeft(&wd->TimeoutTime, wd->User?wd->UserTimeout:0,
+ &timeoutLength, 1))
+ {
+ /* Timeout has already expired. */
+ wd->Expired = 1;
+ return 1;
+ }
+
+ /* Sleep a little, try again. */
+ {
+ unsigned int msec = ((timeoutLength.tv_sec * 1000) +
+ (timeoutLength.tv_usec / 1000));
+ if (msec > 100000)
+ {
+ msec = 100000; /* do not sleep more than 100 milliseconds at a time */
+ }
+ kwsysProcess_usleep(msec);
+ }
+ return 0;
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
+{
+ int status = 0;
+ int prPipe = 0;
+
+ /* Make sure we are executing a process. */
+ if(!cp || cp->State != kwsysProcess_State_Executing)
+ {
+ return 1;
+ }
+
+ /* Wait for all the pipes to close. Ignore all data. */
+ while((prPipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0)
+ {
+ if(prPipe == kwsysProcess_Pipe_Timeout)
+ {
+ return 0;
+ }
+ }
+
+ /* Check if there was an error in one of the waitpid calls. */
+ if(cp->State == kwsysProcess_State_Error)
+ {
+ /* The error message is already in its buffer. Tell
+ kwsysProcessCleanup to not create it. */
+ kwsysProcessCleanup(cp, 0);
+ return 1;
+ }
+
+ /* Check whether the child reported an error invoking the process. */
+ if(cp->SelectError)
+ {
+ /* The error message is already in its buffer. Tell
+ kwsysProcessCleanup to not create it. */
+ kwsysProcessCleanup(cp, 0);
+ cp->State = kwsysProcess_State_Error;
+ return 1;
+ }
+
+ /* Use the status of the last process in the pipeline. */
+ status = cp->CommandExitCodes[cp->NumberOfCommands-1];
+
+ /* Determine the outcome. */
+ if(cp->Killed)
+ {
+ /* We killed the child. */
+ cp->State = kwsysProcess_State_Killed;
+ }
+ else if(cp->TimeoutExpired)
+ {
+ /* The timeout expired. */
+ cp->State = kwsysProcess_State_Expired;
+ }
+ else if(WIFEXITED(status))
+ {
+ /* The child exited normally. */
+ cp->State = kwsysProcess_State_Exited;
+ cp->ExitException = kwsysProcess_Exception_None;
+ cp->ExitCode = status;
+ cp->ExitValue = (int)WEXITSTATUS(status);
+ }
+ else if(WIFSIGNALED(status))
+ {
+ /* The child received an unhandled signal. */
+ cp->State = kwsysProcess_State_Exception;
+ cp->ExitCode = status;
+ kwsysProcessSetExitException(cp, (int)WTERMSIG(status));
+ }
+ else
+ {
+ /* Error getting the child return code. */
+ strcpy(cp->ErrorMessage, "Error getting child return code.");
+ cp->State = kwsysProcess_State_Error;
+ }
+
+ /* Normal cleanup. */
+ kwsysProcessCleanup(cp, 0);
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Interrupt(kwsysProcess* cp)
+{
+ int i;
+ /* Make sure we are executing a process. */
+ if(!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
+ cp->Killed)
+ {
+ return;
+ }
+
+ /* Interrupt the children. */
+ if (cp->CreateProcessGroup)
+ {
+ if(cp->ForkPIDs)
+ {
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ /* Make sure the PID is still valid. */
+ if(cp->ForkPIDs[i])
+ {
+ /* The user created a process group for this process. The group ID
+ is the process ID for the original process in the group. */
+ kill(-cp->ForkPIDs[i], SIGINT);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* No process group was created. Kill our own process group.
+ NOTE: While one could argue that we could call kill(cp->ForkPIDs[i],
+ SIGINT) as a way to still interrupt the process even though it's not in
+ a special group, this is not an option on Windows. Therefore, we kill
+ the current process group for consistency with Windows. */
+ kill(0, SIGINT);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Kill(kwsysProcess* cp)
+{
+ int i;
+
+ /* Make sure we are executing a process. */
+ if(!cp || cp->State != kwsysProcess_State_Executing)
+ {
+ return;
+ }
+
+ /* First close the child exit report pipe write end to avoid causing a
+ SIGPIPE when the child terminates and our signal handler tries to
+ report it after we have already closed the read end. */
+ kwsysProcessCleanupDescriptor(&cp->SignalPipe);
+
+#if !defined(__APPLE__)
+ /* Close all the pipe read ends. Do this before killing the
+ children because Cygwin has problems killing processes that are
+ blocking to wait for writing to their output pipes. */
+ kwsysProcessClosePipes(cp);
+#endif
+
+ /* Kill the children. */
+ cp->Killed = 1;
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ int status;
+ if(cp->ForkPIDs[i])
+ {
+ /* Kill the child. */
+ kwsysProcessKill(cp->ForkPIDs[i]);
+
+ /* Reap the child. Keep trying until the call is not
+ interrupted. */
+ while((waitpid(cp->ForkPIDs[i], &status, 0) < 0) && (errno == EINTR));
+ }
+ }
+
+#if defined(__APPLE__)
+ /* Close all the pipe read ends. Do this after killing the
+ children because OS X has problems closing pipe read ends whose
+ pipes are full and still have an open write end. */
+ kwsysProcessClosePipes(cp);
+#endif
+
+ cp->CommandsLeft = 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Call the free() function with a pointer to volatile without causing
+ compiler warnings. */
+static void kwsysProcessVolatileFree(volatile void* p)
+{
+ /* clang has made it impossible to free memory that points to volatile
+ without first using special pragmas to disable a warning... */
+#if defined(__clang__) && !defined(__INTEL_COMPILER)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wcast-qual"
+#endif
+ free((void*)p); /* The cast will silence most compilers, but not clang. */
+#if defined(__clang__) && !defined(__INTEL_COMPILER)
+# pragma clang diagnostic pop
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+/* Initialize a process control structure for kwsysProcess_Execute. */
+static int kwsysProcessInitialize(kwsysProcess* cp)
+{
+ int i;
+ volatile pid_t* oldForkPIDs;
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ cp->PipeReadEnds[i] = -1;
+ }
+ for(i=0; i < 3; ++i)
+ {
+ cp->PipeChildStd[i] = -1;
+ }
+ cp->SignalPipe = -1;
+ cp->SelectError = 0;
+ cp->StartTime.tv_sec = -1;
+ cp->StartTime.tv_usec = -1;
+ cp->TimeoutTime.tv_sec = -1;
+ cp->TimeoutTime.tv_usec = -1;
+ cp->TimeoutExpired = 0;
+ cp->PipesLeft = 0;
+ cp->CommandsLeft = 0;
+#if KWSYSPE_USE_SELECT
+ FD_ZERO(&cp->PipeSet);
+#endif
+ cp->State = kwsysProcess_State_Starting;
+ cp->Killed = 0;
+ cp->ExitException = kwsysProcess_Exception_None;
+ cp->ExitCode = 1;
+ cp->ExitValue = 1;
+ cp->ErrorMessage[0] = 0;
+ strcpy(cp->ExitExceptionString, "No exception");
+
+ oldForkPIDs = cp->ForkPIDs;
+ cp->ForkPIDs = (volatile pid_t*)malloc(
+ sizeof(volatile pid_t)*(size_t)(cp->NumberOfCommands));
+ if(oldForkPIDs)
+ {
+ kwsysProcessVolatileFree(oldForkPIDs);
+ }
+ if(!cp->ForkPIDs)
+ {
+ return 0;
+ }
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ cp->ForkPIDs[i] = 0; /* can't use memset due to volatile */
+ }
+
+ if(cp->CommandExitCodes)
+ {
+ free(cp->CommandExitCodes);
+ }
+ cp->CommandExitCodes = (int*)malloc(sizeof(int)*
+ (size_t)(cp->NumberOfCommands));
+ if(!cp->CommandExitCodes)
+ {
+ return 0;
+ }
+ memset(cp->CommandExitCodes, 0, sizeof(int)*(size_t)(cp->NumberOfCommands));
+
+ /* Allocate memory to save the real working directory. */
+ if ( cp->WorkingDirectory )
+ {
+#if defined(MAXPATHLEN)
+ cp->RealWorkingDirectoryLength = MAXPATHLEN;
+#elif defined(PATH_MAX)
+ cp->RealWorkingDirectoryLength = PATH_MAX;
+#else
+ cp->RealWorkingDirectoryLength = 4096;
+#endif
+ cp->RealWorkingDirectory =
+ (char*)malloc((size_t)(cp->RealWorkingDirectoryLength));
+ if(!cp->RealWorkingDirectory)
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Free all resources used by the given kwsysProcess instance that were
+ allocated by kwsysProcess_Execute. */
+static void kwsysProcessCleanup(kwsysProcess* cp, int error)
+{
+ int i;
+
+ if(error)
+ {
+ /* We are cleaning up due to an error. Report the error message
+ if one has not been provided already. */
+ if(cp->ErrorMessage[0] == 0)
+ {
+ strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
+ }
+
+ /* Set the error state. */
+ cp->State = kwsysProcess_State_Error;
+
+ /* Kill any children already started. */
+ if(cp->ForkPIDs)
+ {
+ int status;
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ if(cp->ForkPIDs[i])
+ {
+ /* Kill the child. */
+ kwsysProcessKill(cp->ForkPIDs[i]);
+
+ /* Reap the child. Keep trying until the call is not
+ interrupted. */
+ while((waitpid(cp->ForkPIDs[i], &status, 0) < 0) &&
+ (errno == EINTR));
+ }
+ }
+ }
+
+ /* Restore the working directory. */
+ if(cp->RealWorkingDirectory)
+ {
+ while((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR));
+ }
+ }
+
+ /* If not creating a detached child, remove this object from the
+ global set of process objects that wish to be notified when a
+ child exits. */
+ if(!cp->OptionDetach)
+ {
+ kwsysProcessesRemove(cp);
+ }
+
+ /* Free memory. */
+ if(cp->ForkPIDs)
+ {
+ kwsysProcessVolatileFree(cp->ForkPIDs);
+ cp->ForkPIDs = 0;
+ }
+ if(cp->RealWorkingDirectory)
+ {
+ free(cp->RealWorkingDirectory);
+ cp->RealWorkingDirectory = 0;
+ }
+
+ /* Close pipe handles. */
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
+ }
+ for(i=0; i < 3; ++i)
+ {
+ kwsysProcessCleanupDescriptor(&cp->PipeChildStd[i]);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Close the given file descriptor if it is open. Reset its value to -1. */
+static void kwsysProcessCleanupDescriptor(int* pfd)
+{
+ if(pfd && *pfd > 2)
+ {
+ /* Keep trying to close until it is not interrupted by a
+ * signal. */
+ while((close(*pfd) < 0) && (errno == EINTR));
+ *pfd = -1;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessClosePipes(kwsysProcess* cp)
+{
+ int i;
+
+ /* Close any pipes that are still open. */
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ if(cp->PipeReadEnds[i] >= 0)
+ {
+#if KWSYSPE_USE_SELECT
+ /* If the pipe was reported by the last call to select, we must
+ read from it. This is needed to satisfy the suggestions from
+ "man select_tut" and is not needed for the polling
+ implementation. Ignore the data. */
+ if(FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet))
+ {
+ /* We are handling this pipe now. Remove it from the set. */
+ FD_CLR(cp->PipeReadEnds[i], &cp->PipeSet);
+
+ /* The pipe is ready to read without blocking. Keep trying to
+ read until the operation is not interrupted. */
+ while((read(cp->PipeReadEnds[i], cp->PipeBuffer,
+ KWSYSPE_PIPE_BUFFER_SIZE) < 0) && (errno == EINTR));
+ }
+#endif
+
+ /* We are done reading from this pipe. */
+ kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
+ --cp->PipesLeft;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessSetNonBlocking(int fd)
+{
+ int flags = fcntl(fd, F_GETFL);
+ if(flags >= 0)
+ {
+ flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+ }
+ return flags >= 0;
+}
+
+/*--------------------------------------------------------------------------*/
+#if defined(__VMS)
+int decc$set_child_standard_streams(int fd1, int fd2, int fd3);
+#endif
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
+ kwsysProcessCreateInformation* si)
+{
+ sigset_t mask, old_mask;
+ int pgidPipe[2];
+ char tmp;
+ ssize_t readRes;
+
+ /* Create the error reporting pipe. */
+ if(pipe(si->ErrorPipe) < 0)
+ {
+ return 0;
+ }
+
+ /* Create a pipe for detecting that the child process has created a process
+ group and session. */
+ if(pipe(pgidPipe) < 0)
+ {
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+ return 0;
+ }
+
+ /* Set close-on-exec flag on the pipe's write end. */
+ if(fcntl(si->ErrorPipe[1], F_SETFD, FD_CLOEXEC) < 0 ||
+ fcntl(pgidPipe[1], F_SETFD, FD_CLOEXEC) < 0)
+ {
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[1]);
+ return 0;
+ }
+
+ /* Block SIGINT / SIGTERM while we start. The purpose is so that our signal
+ handler doesn't get called from the child process after the fork and
+ before the exec, and subsequently start kill()'ing PIDs from ForkPIDs. */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+ if(sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0)
+ {
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[1]);
+ return 0;
+ }
+
+ /* Fork off a child process. */
+#if defined(__VMS)
+ /* VMS needs vfork and execvp to be in the same function because
+ they use setjmp/longjmp to run the child startup code in the
+ parent! TODO: OptionDetach. Also
+ TODO: CreateProcessGroup. */
+ cp->ForkPIDs[prIndex] = vfork();
+#else
+ cp->ForkPIDs[prIndex] = kwsysProcessFork(cp, si);
+#endif
+ if(cp->ForkPIDs[prIndex] < 0)
+ {
+ sigprocmask(SIG_SETMASK, &old_mask, 0);
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[1]);
+ return 0;
+ }
+
+ if(cp->ForkPIDs[prIndex] == 0)
+ {
+#if defined(__VMS)
+ /* Specify standard pipes for child process. */
+ decc$set_child_standard_streams(si->StdIn, si->StdOut, si->StdErr);
+#else
+ /* Close the read end of the error reporting / process group
+ setup pipe. */
+ close(si->ErrorPipe[0]);
+ close(pgidPipe[0]);
+
+ /* Setup the stdin, stdout, and stderr pipes. */
+ if(si->StdIn > 0)
+ {
+ dup2(si->StdIn, 0);
+ }
+ else if(si->StdIn < 0)
+ {
+ close(0);
+ }
+ if(si->StdOut != 1)
+ {
+ dup2(si->StdOut, 1);
+ }
+ if(si->StdErr != 2)
+ {
+ dup2(si->StdErr, 2);
+ }
+
+ /* Clear the close-on-exec flag for stdin, stdout, and stderr.
+ All other pipe handles will be closed when exec succeeds. */
+ fcntl(0, F_SETFD, 0);
+ fcntl(1, F_SETFD, 0);
+ fcntl(2, F_SETFD, 0);
+
+ /* Restore all default signal handlers. */
+ kwsysProcessRestoreDefaultSignalHandlers();
+
+ /* Now that we have restored default signal handling and created the
+ process group, restore mask. */
+ sigprocmask(SIG_SETMASK, &old_mask, 0);
+
+ /* Create new process group. We use setsid instead of setpgid to avoid
+ the child getting hung up on signals like SIGTTOU. (In the real world,
+ this has been observed where "git svn" ends up calling the "resize"
+ program which opens /dev/tty. */
+ if(cp->CreateProcessGroup && setsid() < 0)
+ {
+ kwsysProcessChildErrorExit(si->ErrorPipe[1]);
+ }
+#endif
+
+ /* Execute the real process. If successful, this does not return. */
+ execvp(cp->Commands[prIndex][0], cp->Commands[prIndex]);
+ /* TODO: What does VMS do if the child fails to start? */
+ /* TODO: On VMS, how do we put the process in a new group? */
+
+ /* Failure. Report error to parent and terminate. */
+ kwsysProcessChildErrorExit(si->ErrorPipe[1]);
+ }
+
+#if defined(__VMS)
+ /* Restore the standard pipes of this process. */
+ decc$set_child_standard_streams(0, 1, 2);
+#endif
+
+ /* We are done with the error reporting pipe and process group setup pipe
+ write end. */
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[1]);
+
+ /* Make sure the child is in the process group before we proceed. This
+ avoids race conditions with calls to the kill function that we make for
+ signalling process groups. */
+ while((readRes = read(pgidPipe[0], &tmp, 1)) > 0);
+ if(readRes < 0)
+ {
+ sigprocmask(SIG_SETMASK, &old_mask, 0);
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+ return 0;
+ }
+ kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+
+ /* Unmask signals. */
+ if(sigprocmask(SIG_SETMASK, &old_mask, 0) < 0)
+ {
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+ return 0;
+ }
+
+ /* A child has been created. */
+ ++cp->CommandsLeft;
+
+ /* Block until the child's exec call succeeds and closes the error
+ pipe or writes data to the pipe to report an error. */
+ {
+ kwsysProcess_ssize_t total = 0;
+ kwsysProcess_ssize_t n = 1;
+ /* Read the entire error message up to the length of our buffer. */
+ while(total < KWSYSPE_PIPE_BUFFER_SIZE && n > 0)
+ {
+ /* Keep trying to read until the operation is not interrupted. */
+ while(((n = read(si->ErrorPipe[0], cp->ErrorMessage+total,
+ (size_t)(KWSYSPE_PIPE_BUFFER_SIZE-total))) < 0) &&
+ (errno == EINTR));
+ if(n > 0)
+ {
+ total += n;
+ }
+ }
+
+ /* We are done with the error reporting pipe read end. */
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+
+ if(total > 0)
+ {
+ /* The child failed to execute the process. */
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessDestroy(kwsysProcess* cp)
+{
+ /* A child process has terminated. Reap it if it is one handled by
+ this object. */
+ int i;
+ /* Temporarily disable signals that access ForkPIDs. We don't want them to
+ read a reaped PID, and writes to ForkPIDs are not atomic. */
+ sigset_t mask, old_mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+ if(sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0)
+ {
+ return;
+ }
+
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ if(cp->ForkPIDs[i])
+ {
+ int result;
+ while(((result = waitpid(cp->ForkPIDs[i],
+ &cp->CommandExitCodes[i], WNOHANG)) < 0) &&
+ (errno == EINTR));
+ if(result > 0)
+ {
+ /* This child has termianted. */
+ cp->ForkPIDs[i] = 0;
+ if(--cp->CommandsLeft == 0)
+ {
+ /* All children have terminated. Close the signal pipe
+ write end so that no more notifications are sent to this
+ object. */
+ kwsysProcessCleanupDescriptor(&cp->SignalPipe);
+
+ /* TODO: Once the children have terminated, switch
+ WaitForData to use a non-blocking read to get the
+ rest of the data from the pipe. This is needed when
+ grandchildren keep the output pipes open. */
+ }
+ }
+ else if(result < 0 && cp->State != kwsysProcess_State_Error)
+ {
+ /* Unexpected error. Report the first time this happens. */
+ strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
+ cp->State = kwsysProcess_State_Error;
+ }
+ }
+ }
+
+ /* Re-enable signals. */
+ sigprocmask(SIG_SETMASK, &old_mask, 0);
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessSetupOutputPipeFile(int* p, const char* name)
+{
+ int fout;
+ if(!name)
+ {
+ return 1;
+ }
+
+ /* Close the existing descriptor. */
+ kwsysProcessCleanupDescriptor(p);
+
+ /* Open a file for the pipe to write. */
+ if((fout = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
+ {
+ return 0;
+ }
+
+ /* Set close-on-exec flag on the pipe's end. */
+ if(fcntl(fout, F_SETFD, FD_CLOEXEC) < 0)
+ {
+ return 0;
+ }
+
+ /* Assign the replacement descriptor. */
+ *p = fout;
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessSetupOutputPipeNative(int* p, int des[2])
+{
+ /* Close the existing descriptor. */
+ kwsysProcessCleanupDescriptor(p);
+
+ /* Set close-on-exec flag on the pipe's ends. The proper end will
+ be dup2-ed into the standard descriptor number after fork but
+ before exec. */
+ if((fcntl(des[0], F_SETFD, FD_CLOEXEC) < 0) ||
+ (fcntl(des[1], F_SETFD, FD_CLOEXEC) < 0))
+ {
+ return 0;
+ }
+
+ /* Assign the replacement descriptor. */
+ *p = des[1];
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Get the time at which either the process or user timeout will
+ expire. Returns 1 if the user timeout is first, and 0 otherwise. */
+static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
+ kwsysProcessTime* timeoutTime)
+{
+ /* The first time this is called, we need to calculate the time at
+ which the child will timeout. */
+ if(cp->Timeout > 0 && cp->TimeoutTime.tv_sec < 0)
+ {
+ kwsysProcessTime length = kwsysProcessTimeFromDouble(cp->Timeout);
+ cp->TimeoutTime = kwsysProcessTimeAdd(cp->StartTime, length);
+ }
+
+ /* Start with process timeout. */
+ *timeoutTime = cp->TimeoutTime;
+
+ /* Check if the user timeout is earlier. */
+ if(userTimeout)
+ {
+ kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
+ kwsysProcessTime userTimeoutLength = kwsysProcessTimeFromDouble(*userTimeout);
+ kwsysProcessTime userTimeoutTime = kwsysProcessTimeAdd(currentTime,
+ userTimeoutLength);
+ if(timeoutTime->tv_sec < 0 ||
+ kwsysProcessTimeLess(userTimeoutTime, *timeoutTime))
+ {
+ *timeoutTime = userTimeoutTime;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Get the length of time before the given timeout time arrives.
+ Returns 1 if the time has already arrived, and 0 otherwise. */
+static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
+ double* userTimeout,
+ kwsysProcessTimeNative* timeoutLength,
+ int zeroIsExpired)
+{
+ if(timeoutTime->tv_sec < 0)
+ {
+ /* No timeout time has been requested. */
+ return 0;
+ }
+ else
+ {
+ /* Calculate the remaining time. */
+ kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
+ kwsysProcessTime timeLeft = kwsysProcessTimeSubtract(*timeoutTime,
+ currentTime);
+ if(timeLeft.tv_sec < 0 && userTimeout && *userTimeout <= 0)
+ {
+ /* Caller has explicitly requested a zero timeout. */
+ timeLeft.tv_sec = 0;
+ timeLeft.tv_usec = 0;
+ }
+
+ if(timeLeft.tv_sec < 0 ||
+ (timeLeft.tv_sec == 0 && timeLeft.tv_usec == 0 && zeroIsExpired))
+ {
+ /* Timeout has already expired. */
+ return 1;
+ }
+ else
+ {
+ /* There is some time left. */
+ timeoutLength->tv_sec = timeLeft.tv_sec;
+ timeoutLength->tv_usec = timeLeft.tv_usec;
+ return 0;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static kwsysProcessTime kwsysProcessTimeGetCurrent(void)
+{
+ kwsysProcessTime current;
+ kwsysProcessTimeNative current_native;
+ gettimeofday(&current_native, 0);
+ current.tv_sec = (long)current_native.tv_sec;
+ current.tv_usec = (long)current_native.tv_usec;
+ return current;
+}
+
+/*--------------------------------------------------------------------------*/
+static double kwsysProcessTimeToDouble(kwsysProcessTime t)
+{
+ return (double)t.tv_sec + (double)(t.tv_usec)*0.000001;
+}
+
+/*--------------------------------------------------------------------------*/
+static kwsysProcessTime kwsysProcessTimeFromDouble(double d)
+{
+ kwsysProcessTime t;
+ t.tv_sec = (long)d;
+ t.tv_usec = (long)((d-(double)(t.tv_sec))*1000000);
+ return t;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2)
+{
+ return ((in1.tv_sec < in2.tv_sec) ||
+ ((in1.tv_sec == in2.tv_sec) && (in1.tv_usec < in2.tv_usec)));
+}
+
+/*--------------------------------------------------------------------------*/
+static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2)
+{
+ kwsysProcessTime out;
+ out.tv_sec = in1.tv_sec + in2.tv_sec;
+ out.tv_usec = in1.tv_usec + in2.tv_usec;
+ if(out.tv_usec >= 1000000)
+ {
+ out.tv_usec -= 1000000;
+ out.tv_sec += 1;
+ }
+ return out;
+}
+
+/*--------------------------------------------------------------------------*/
+static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime in2)
+{
+ kwsysProcessTime out;
+ out.tv_sec = in1.tv_sec - in2.tv_sec;
+ out.tv_usec = in1.tv_usec - in2.tv_usec;
+ if(out.tv_usec < 0)
+ {
+ out.tv_usec += 1000000;
+ out.tv_sec -= 1;
+ }
+ return out;
+}
+
+/*--------------------------------------------------------------------------*/
+#define KWSYSPE_CASE(type, str) \
+ cp->ExitException = kwsysProcess_Exception_##type; \
+ strcpy(cp->ExitExceptionString, str)
+static void kwsysProcessSetExitException(kwsysProcess* cp, int sig)
+{
+ switch (sig)
+ {
+#ifdef SIGSEGV
+ case SIGSEGV: KWSYSPE_CASE(Fault, "Segmentation fault"); break;
+#endif
+#ifdef SIGBUS
+# if !defined(SIGSEGV) || SIGBUS != SIGSEGV
+ case SIGBUS: KWSYSPE_CASE(Fault, "Bus error"); break;
+# endif
+#endif
+#ifdef SIGFPE
+ case SIGFPE: KWSYSPE_CASE(Numerical, "Floating-point exception"); break;
+#endif
+#ifdef SIGILL
+ case SIGILL: KWSYSPE_CASE(Illegal, "Illegal instruction"); break;
+#endif
+#ifdef SIGINT
+ case SIGINT: KWSYSPE_CASE(Interrupt, "User interrupt"); break;
+#endif
+#ifdef SIGABRT
+ case SIGABRT: KWSYSPE_CASE(Other, "Child aborted"); break;
+#endif
+#ifdef SIGKILL
+ case SIGKILL: KWSYSPE_CASE(Other, "Child killed"); break;
+#endif
+#ifdef SIGTERM
+ case SIGTERM: KWSYSPE_CASE(Other, "Child terminated"); break;
+#endif
+#ifdef SIGHUP
+ case SIGHUP: KWSYSPE_CASE(Other, "SIGHUP"); break;
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT: KWSYSPE_CASE(Other, "SIGQUIT"); break;
+#endif
+#ifdef SIGTRAP
+ case SIGTRAP: KWSYSPE_CASE(Other, "SIGTRAP"); break;
+#endif
+#ifdef SIGIOT
+# if !defined(SIGABRT) || SIGIOT != SIGABRT
+ case SIGIOT: KWSYSPE_CASE(Other, "SIGIOT"); break;
+# endif
+#endif
+#ifdef SIGUSR1
+ case SIGUSR1: KWSYSPE_CASE(Other, "SIGUSR1"); break;
+#endif
+#ifdef SIGUSR2
+ case SIGUSR2: KWSYSPE_CASE(Other, "SIGUSR2"); break;
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE: KWSYSPE_CASE(Other, "SIGPIPE"); break;
+#endif
+#ifdef SIGALRM
+ case SIGALRM: KWSYSPE_CASE(Other, "SIGALRM"); break;
+#endif
+#ifdef SIGSTKFLT
+ case SIGSTKFLT: KWSYSPE_CASE(Other, "SIGSTKFLT"); break;
+#endif
+#ifdef SIGCHLD
+ case SIGCHLD: KWSYSPE_CASE(Other, "SIGCHLD"); break;
+#elif defined(SIGCLD)
+ case SIGCLD: KWSYSPE_CASE(Other, "SIGCLD"); break;
+#endif
+#ifdef SIGCONT
+ case SIGCONT: KWSYSPE_CASE(Other, "SIGCONT"); break;
+#endif
+#ifdef SIGSTOP
+ case SIGSTOP: KWSYSPE_CASE(Other, "SIGSTOP"); break;
+#endif
+#ifdef SIGTSTP
+ case SIGTSTP: KWSYSPE_CASE(Other, "SIGTSTP"); break;
+#endif
+#ifdef SIGTTIN
+ case SIGTTIN: KWSYSPE_CASE(Other, "SIGTTIN"); break;
+#endif
+#ifdef SIGTTOU
+ case SIGTTOU: KWSYSPE_CASE(Other, "SIGTTOU"); break;
+#endif
+#ifdef SIGURG
+ case SIGURG: KWSYSPE_CASE(Other, "SIGURG"); break;
+#endif
+#ifdef SIGXCPU
+ case SIGXCPU: KWSYSPE_CASE(Other, "SIGXCPU"); break;
+#endif
+#ifdef SIGXFSZ
+ case SIGXFSZ: KWSYSPE_CASE(Other, "SIGXFSZ"); break;
+#endif
+#ifdef SIGVTALRM
+ case SIGVTALRM: KWSYSPE_CASE(Other, "SIGVTALRM"); break;
+#endif
+#ifdef SIGPROF
+ case SIGPROF: KWSYSPE_CASE(Other, "SIGPROF"); break;
+#endif
+#ifdef SIGWINCH
+ case SIGWINCH: KWSYSPE_CASE(Other, "SIGWINCH"); break;
+#endif
+#ifdef SIGPOLL
+ case SIGPOLL: KWSYSPE_CASE(Other, "SIGPOLL"); break;
+#endif
+#ifdef SIGIO
+# if !defined(SIGPOLL) || SIGIO != SIGPOLL
+ case SIGIO: KWSYSPE_CASE(Other, "SIGIO"); break;
+# endif
+#endif
+#ifdef SIGPWR
+ case SIGPWR: KWSYSPE_CASE(Other, "SIGPWR"); break;
+#endif
+#ifdef SIGSYS
+ case SIGSYS: KWSYSPE_CASE(Other, "SIGSYS"); break;
+#endif
+#ifdef SIGUNUSED
+# if !defined(SIGSYS) || SIGUNUSED != SIGSYS
+ case SIGUNUSED: KWSYSPE_CASE(Other, "SIGUNUSED"); break;
+# endif
+#endif
+ default:
+ cp->ExitException = kwsysProcess_Exception_Other;
+ sprintf(cp->ExitExceptionString, "Signal %d", sig);
+ break;
+ }
+}
+#undef KWSYSPE_CASE
+
+/*--------------------------------------------------------------------------*/
+/* When the child process encounters an error before its program is
+ invoked, this is called to report the error to the parent and
+ exit. */
+static void kwsysProcessChildErrorExit(int errorPipe)
+{
+ /* Construct the error message. */
+ char buffer[KWSYSPE_PIPE_BUFFER_SIZE];
+ kwsysProcess_ssize_t result;
+ strncpy(buffer, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
+
+ /* Report the error to the parent through the special pipe. */
+ result=write(errorPipe, buffer, strlen(buffer));
+ (void)result;
+
+ /* Terminate without cleanup. */
+ _exit(1);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Restores all signal handlers to their default values. */
+static void kwsysProcessRestoreDefaultSignalHandlers(void)
+{
+ struct sigaction act;
+ memset(&act, 0, sizeof(struct sigaction));
+ act.sa_handler = SIG_DFL;
+#ifdef SIGHUP
+ sigaction(SIGHUP, &act, 0);
+#endif
+#ifdef SIGINT
+ sigaction(SIGINT, &act, 0);
+#endif
+#ifdef SIGQUIT
+ sigaction(SIGQUIT, &act, 0);
+#endif
+#ifdef SIGILL
+ sigaction(SIGILL, &act, 0);
+#endif
+#ifdef SIGTRAP
+ sigaction(SIGTRAP, &act, 0);
+#endif
+#ifdef SIGABRT
+ sigaction(SIGABRT, &act, 0);
+#endif
+#ifdef SIGIOT
+ sigaction(SIGIOT, &act, 0);
+#endif
+#ifdef SIGBUS
+ sigaction(SIGBUS, &act, 0);
+#endif
+#ifdef SIGFPE
+ sigaction(SIGFPE, &act, 0);
+#endif
+#ifdef SIGUSR1
+ sigaction(SIGUSR1, &act, 0);
+#endif
+#ifdef SIGSEGV
+ sigaction(SIGSEGV, &act, 0);
+#endif
+#ifdef SIGUSR2
+ sigaction(SIGUSR2, &act, 0);
+#endif
+#ifdef SIGPIPE
+ sigaction(SIGPIPE, &act, 0);
+#endif
+#ifdef SIGALRM
+ sigaction(SIGALRM, &act, 0);
+#endif
+#ifdef SIGTERM
+ sigaction(SIGTERM, &act, 0);
+#endif
+#ifdef SIGSTKFLT
+ sigaction(SIGSTKFLT, &act, 0);
+#endif
+#ifdef SIGCLD
+ sigaction(SIGCLD, &act, 0);
+#endif
+#ifdef SIGCHLD
+ sigaction(SIGCHLD, &act, 0);
+#endif
+#ifdef SIGCONT
+ sigaction(SIGCONT, &act, 0);
+#endif
+#ifdef SIGTSTP
+ sigaction(SIGTSTP, &act, 0);
+#endif
+#ifdef SIGTTIN
+ sigaction(SIGTTIN, &act, 0);
+#endif
+#ifdef SIGTTOU
+ sigaction(SIGTTOU, &act, 0);
+#endif
+#ifdef SIGURG
+ sigaction(SIGURG, &act, 0);
+#endif
+#ifdef SIGXCPU
+ sigaction(SIGXCPU, &act, 0);
+#endif
+#ifdef SIGXFSZ
+ sigaction(SIGXFSZ, &act, 0);
+#endif
+#ifdef SIGVTALRM
+ sigaction(SIGVTALRM, &act, 0);
+#endif
+#ifdef SIGPROF
+ sigaction(SIGPROF, &act, 0);
+#endif
+#ifdef SIGWINCH
+ sigaction(SIGWINCH, &act, 0);
+#endif
+#ifdef SIGPOLL
+ sigaction(SIGPOLL, &act, 0);
+#endif
+#ifdef SIGIO
+ sigaction(SIGIO, &act, 0);
+#endif
+#ifdef SIGPWR
+ sigaction(SIGPWR, &act, 0);
+#endif
+#ifdef SIGSYS
+ sigaction(SIGSYS, &act, 0);
+#endif
+#ifdef SIGUNUSED
+ sigaction(SIGUNUSED, &act, 0);
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessExit(void)
+{
+ _exit(0);
+}
+
+/*--------------------------------------------------------------------------*/
+#if !defined(__VMS)
+static pid_t kwsysProcessFork(kwsysProcess* cp,
+ kwsysProcessCreateInformation* si)
+{
+ /* Create a detached process if requested. */
+ if(cp->OptionDetach)
+ {
+ /* Create an intermediate process. */
+ pid_t middle_pid = fork();
+ if(middle_pid < 0)
+ {
+ /* Fork failed. Return as if we were not detaching. */
+ return middle_pid;
+ }
+ else if(middle_pid == 0)
+ {
+ /* This is the intermediate process. Create the real child. */
+ pid_t child_pid = fork();
+ if(child_pid == 0)
+ {
+ /* This is the real child process. There is nothing to do here. */
+ return 0;
+ }
+ else
+ {
+ /* Use the error pipe to report the pid to the real parent. */
+ while((write(si->ErrorPipe[1], &child_pid, sizeof(child_pid)) < 0) &&
+ (errno == EINTR));
+
+ /* Exit without cleanup. The parent holds all resources. */
+ kwsysProcessExit();
+ return 0; /* Never reached, but avoids SunCC warning. */
+ }
+ }
+ else
+ {
+ /* This is the original parent process. The intermediate
+ process will use the error pipe to report the pid of the
+ detached child. */
+ pid_t child_pid;
+ int status;
+ while((read(si->ErrorPipe[0], &child_pid, sizeof(child_pid)) < 0) &&
+ (errno == EINTR));
+
+ /* Wait for the intermediate process to exit and clean it up. */
+ while((waitpid(middle_pid, &status, 0) < 0) && (errno == EINTR));
+ return child_pid;
+ }
+ }
+ else
+ {
+ /* Not creating a detached process. Use normal fork. */
+ return fork();
+ }
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* We try to obtain process information by invoking the ps command.
+ Here we define the command to call on each platform and the
+ corresponding parsing format string. The parsing format should
+ have two integers to store: the pid and then the ppid. */
+#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) \
+ || defined(__OpenBSD__) || defined(__GLIBC__) || defined(__GNU__)
+# define KWSYSPE_PS_COMMAND "ps axo pid,ppid"
+# define KWSYSPE_PS_FORMAT "%d %d\n"
+#elif defined(__sun) && (defined(__SVR4) || defined(__svr4__)) /* Solaris */
+# define KWSYSPE_PS_COMMAND "ps -e -o pid,ppid"
+# define KWSYSPE_PS_FORMAT "%d %d\n"
+#elif defined(__hpux) || defined(__sun__) || defined(__sgi) || defined(_AIX) \
+ || defined(__sparc)
+# define KWSYSPE_PS_COMMAND "ps -ef"
+# define KWSYSPE_PS_FORMAT "%*s %d %d %*[^\n]\n"
+#elif defined(__QNX__)
+# define KWSYSPE_PS_COMMAND "ps -Af"
+# define KWSYSPE_PS_FORMAT "%*d %d %d %*[^\n]\n"
+#elif defined(__CYGWIN__)
+# define KWSYSPE_PS_COMMAND "ps aux"
+# define KWSYSPE_PS_FORMAT "%d %d %*[^\n]\n"
+#endif
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessKill(pid_t process_id)
+{
+#if defined(__linux__) || defined(__CYGWIN__)
+ DIR* procdir;
+#endif
+
+ /* Suspend the process to be sure it will not create more children. */
+ kill(process_id, SIGSTOP);
+
+#if defined(__CYGWIN__)
+ /* Some Cygwin versions seem to need help here. Give up our time slice
+ so that the child can process SIGSTOP before we send SIGKILL. */
+ usleep(1);
+#endif
+
+ /* Kill all children if we can find them. */
+#if defined(__linux__) || defined(__CYGWIN__)
+ /* First try using the /proc filesystem. */
+ if((procdir = opendir("/proc")) != NULL)
+ {
+#if defined(MAXPATHLEN)
+ char fname[MAXPATHLEN];
+#elif defined(PATH_MAX)
+ char fname[PATH_MAX];
+#else
+ char fname[4096];
+#endif
+ char buffer[KWSYSPE_PIPE_BUFFER_SIZE+1];
+ struct dirent* d;
+
+ /* Each process has a directory in /proc whose name is the pid.
+ Within this directory is a file called stat that has the
+ following format:
+
+ pid (command line) status ppid ...
+
+ We want to get the ppid for all processes. Those that have
+ process_id as their parent should be recursively killed. */
+ for(d = readdir(procdir); d; d = readdir(procdir))
+ {
+ int pid;
+ if(sscanf(d->d_name, "%d", &pid) == 1 && pid != 0)
+ {
+ struct stat finfo;
+ sprintf(fname, "/proc/%d/stat", pid);
+ if(stat(fname, &finfo) == 0)
+ {
+ FILE* f = fopen(fname, "r");
+ if(f)
+ {
+ size_t nread = fread(buffer, 1, KWSYSPE_PIPE_BUFFER_SIZE, f);
+ fclose(f);
+ buffer[nread] = '\0';
+ if(nread > 0)
+ {
+ const char* rparen = strrchr(buffer, ')');
+ int ppid;
+ if(rparen && (sscanf(rparen+1, "%*s %d", &ppid) == 1))
+ {
+ if(ppid == process_id)
+ {
+ /* Recursively kill this child and its children. */
+ kwsysProcessKill(pid);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ closedir(procdir);
+ }
+ else
+#endif
+ {
+#if defined(KWSYSPE_PS_COMMAND)
+ /* Try running "ps" to get the process information. */
+ FILE* ps = popen(KWSYSPE_PS_COMMAND, "r");
+
+ /* Make sure the process started and provided a valid header. */
+ if(ps && fscanf(ps, "%*[^\n]\n") != EOF)
+ {
+ /* Look for processes whose parent is the process being killed. */
+ int pid, ppid;
+ while(fscanf(ps, KWSYSPE_PS_FORMAT, &pid, &ppid) == 2)
+ {
+ if(ppid == process_id)
+ {
+ /* Recursively kill this child and its children. */
+ kwsysProcessKill(pid);
+ }
+ }
+ }
+
+ /* We are done with the ps process. */
+ if(ps)
+ {
+ pclose(ps);
+ }
+#endif
+ }
+
+ /* Kill the process. */
+ kill(process_id, SIGKILL);
+
+#if defined(__APPLE__)
+ /* On OS X 10.3 the above SIGSTOP occasionally prevents the SIGKILL
+ from working. Just in case, we resume the child and kill it
+ again. There is a small race condition in this obscure case. If
+ the child manages to fork again between these two signals, we
+ will not catch its children. */
+ kill(process_id, SIGCONT);
+ kill(process_id, SIGKILL);
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+#if defined(__VMS)
+int decc$feature_get_index(const char* name);
+int decc$feature_set_value(int index, int mode, int value);
+static int kwsysProcessSetVMSFeature(const char* name, int value)
+{
+ int i;
+ errno = 0;
+ i = decc$feature_get_index(name);
+ return i >= 0 && (decc$feature_set_value(i, 1, value) >= 0 || errno == 0);
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Global set of executing processes for use by the signal handler.
+ This global instance will be zero-initialized by the compiler. */
+typedef struct kwsysProcessInstances_s
+{
+ int Count;
+ int Size;
+ kwsysProcess** Processes;
+} kwsysProcessInstances;
+static kwsysProcessInstances kwsysProcesses;
+
+/* The old SIGCHLD / SIGINT / SIGTERM handlers. */
+static struct sigaction kwsysProcessesOldSigChldAction;
+static struct sigaction kwsysProcessesOldSigIntAction;
+static struct sigaction kwsysProcessesOldSigTermAction;
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessesUpdate(kwsysProcessInstances* newProcesses)
+{
+ /* Block signals while we update the set of pipes to check.
+ TODO: sigprocmask is undefined for threaded apps. See
+ pthread_sigmask. */
+ sigset_t newset;
+ sigset_t oldset;
+ sigemptyset(&newset);
+ sigaddset(&newset, SIGCHLD);
+ sigaddset(&newset, SIGINT);
+ sigaddset(&newset, SIGTERM);
+ sigprocmask(SIG_BLOCK, &newset, &oldset);
+
+ /* Store the new set in that seen by the signal handler. */
+ kwsysProcesses = *newProcesses;
+
+ /* Restore the signal mask to the previous setting. */
+ sigprocmask(SIG_SETMASK, &oldset, 0);
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessesAdd(kwsysProcess* cp)
+{
+ /* Create a pipe through which the signal handler can notify the
+ given process object that a child has exited. */
+ {
+ /* Create the pipe. */
+ int p[2];
+ if(pipe(p KWSYSPE_VMS_NONBLOCK) < 0)
+ {
+ return 0;
+ }
+
+ /* Store the pipes now to be sure they are cleaned up later. */
+ cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL] = p[0];
+ cp->SignalPipe = p[1];
+
+ /* Switch the pipe to non-blocking mode so that reading a byte can
+ be an atomic test-and-set. */
+ if(!kwsysProcessSetNonBlocking(p[0]) ||
+ !kwsysProcessSetNonBlocking(p[1]))
+ {
+ return 0;
+ }
+
+ /* The children do not need this pipe. Set close-on-exec flag on
+ the pipe's ends. */
+ if((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
+ (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0))
+ {
+ return 0;
+ }
+ }
+
+ /* Attempt to add the given signal pipe to the signal handler set. */
+ {
+
+ /* Make sure there is enough space for the new signal pipe. */
+ kwsysProcessInstances oldProcesses = kwsysProcesses;
+ kwsysProcessInstances newProcesses = oldProcesses;
+ if(oldProcesses.Count == oldProcesses.Size)
+ {
+ /* Start with enough space for a small number of process instances
+ and double the size each time more is needed. */
+ newProcesses.Size = oldProcesses.Size? oldProcesses.Size*2 : 4;
+
+ /* Try allocating the new block of memory. */
+ if((newProcesses.Processes = ((kwsysProcess**)
+ malloc((size_t)(newProcesses.Size)*
+ sizeof(kwsysProcess*)))))
+ {
+ /* Copy the old pipe set to the new memory. */
+ if(oldProcesses.Count > 0)
+ {
+ memcpy(newProcesses.Processes, oldProcesses.Processes,
+ ((size_t)(oldProcesses.Count) * sizeof(kwsysProcess*)));
+ }
+ }
+ else
+ {
+ /* Failed to allocate memory for the new signal pipe set. */
+ return 0;
+ }
+ }
+
+ /* Append the new signal pipe to the set. */
+ newProcesses.Processes[newProcesses.Count++] = cp;
+
+ /* Store the new set in that seen by the signal handler. */
+ kwsysProcessesUpdate(&newProcesses);
+
+ /* Free the original pipes if new ones were allocated. */
+ if(newProcesses.Processes != oldProcesses.Processes)
+ {
+ free(oldProcesses.Processes);
+ }
+
+ /* If this is the first process, enable the signal handler. */
+ if(newProcesses.Count == 1)
+ {
+ /* Install our handler for SIGCHLD. Repeat call until it is not
+ interrupted. */
+ struct sigaction newSigAction;
+ memset(&newSigAction, 0, sizeof(struct sigaction));
+#if KWSYSPE_USE_SIGINFO
+ newSigAction.sa_sigaction = kwsysProcessesSignalHandler;
+ newSigAction.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
+# ifdef SA_RESTART
+ newSigAction.sa_flags |= SA_RESTART;
+# endif
+#else
+ newSigAction.sa_handler = kwsysProcessesSignalHandler;
+ newSigAction.sa_flags = SA_NOCLDSTOP;
+#endif
+ sigemptyset(&newSigAction.sa_mask);
+ while((sigaction(SIGCHLD, &newSigAction,
+ &kwsysProcessesOldSigChldAction) < 0) &&
+ (errno == EINTR));
+
+ /* Install our handler for SIGINT / SIGTERM. Repeat call until
+ it is not interrupted. */
+ sigemptyset(&newSigAction.sa_mask);
+ sigaddset(&newSigAction.sa_mask, SIGTERM);
+ while((sigaction(SIGINT, &newSigAction,
+ &kwsysProcessesOldSigIntAction) < 0) &&
+ (errno == EINTR));
+
+ sigemptyset(&newSigAction.sa_mask);
+ sigaddset(&newSigAction.sa_mask, SIGINT);
+ while((sigaction(SIGTERM, &newSigAction,
+ &kwsysProcessesOldSigIntAction) < 0) &&
+ (errno == EINTR));
+ }
+ }
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessesRemove(kwsysProcess* cp)
+{
+ /* Attempt to remove the given signal pipe from the signal handler set. */
+ {
+ /* Find the given process in the set. */
+ kwsysProcessInstances newProcesses = kwsysProcesses;
+ int i;
+ for(i=0; i < newProcesses.Count; ++i)
+ {
+ if(newProcesses.Processes[i] == cp)
+ {
+ break;
+ }
+ }
+ if(i < newProcesses.Count)
+ {
+ /* Remove the process from the set. */
+ --newProcesses.Count;
+ for(; i < newProcesses.Count; ++i)
+ {
+ newProcesses.Processes[i] = newProcesses.Processes[i+1];
+ }
+
+ /* If this was the last process, disable the signal handler. */
+ if(newProcesses.Count == 0)
+ {
+ /* Restore the signal handlers. Repeat call until it is not
+ interrupted. */
+ while((sigaction(SIGCHLD, &kwsysProcessesOldSigChldAction, 0) < 0) &&
+ (errno == EINTR));
+ while((sigaction(SIGINT, &kwsysProcessesOldSigIntAction, 0) < 0) &&
+ (errno == EINTR));
+ while((sigaction(SIGTERM, &kwsysProcessesOldSigTermAction, 0) < 0) &&
+ (errno == EINTR));
+
+ /* Free the table of process pointers since it is now empty.
+ This is safe because the signal handler has been removed. */
+ newProcesses.Size = 0;
+ free(newProcesses.Processes);
+ newProcesses.Processes = 0;
+ }
+
+ /* Store the new set in that seen by the signal handler. */
+ kwsysProcessesUpdate(&newProcesses);
+ }
+ }
+
+ /* Close the pipe through which the signal handler may have notified
+ the given process object that a child has exited. */
+ kwsysProcessCleanupDescriptor(&cp->SignalPipe);
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessesSignalHandler(int signum
+#if KWSYSPE_USE_SIGINFO
+ , siginfo_t* info, void* ucontext
+#endif
+ )
+{
+ int i, j, procStatus, old_errno = errno;
+#if KWSYSPE_USE_SIGINFO
+ (void)info;
+ (void)ucontext;
+#endif
+
+ /* Signal all process objects that a child has terminated. */
+ switch(signum)
+ {
+ case SIGCHLD:
+ for(i=0; i < kwsysProcesses.Count; ++i)
+ {
+ /* Set the pipe in a signalled state. */
+ char buf = 1;
+ kwsysProcess* cp = kwsysProcesses.Processes[i];
+ kwsysProcess_ssize_t pipeStatus=
+ read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1);
+ (void)pipeStatus;
+ pipeStatus=write(cp->SignalPipe, &buf, 1);
+ (void)pipeStatus;
+ }
+ break;
+ case SIGINT:
+ case SIGTERM:
+ /* Signal child processes that are running in new process groups. */
+ for(i=0; i < kwsysProcesses.Count; ++i)
+ {
+ kwsysProcess* cp = kwsysProcesses.Processes[i];
+ /* Check Killed to avoid data race condition when killing.
+ Check State to avoid data race condition in kwsysProcessCleanup
+ when there is an error (it leaves a reaped PID). */
+ if(cp->CreateProcessGroup && !cp->Killed &&
+ cp->State != kwsysProcess_State_Error && cp->ForkPIDs)
+ {
+ for(j=0; j < cp->NumberOfCommands; ++j)
+ {
+ /* Make sure the PID is still valid. */
+ if(cp->ForkPIDs[j])
+ {
+ /* The user created a process group for this process. The group ID
+ is the process ID for the original process in the group. */
+ kill(-cp->ForkPIDs[j], SIGINT);
+ }
+ }
+ }
+ }
+
+ /* Wait for all processes to terminate. */
+ while(wait(&procStatus) >= 0 || errno != ECHILD)
+ {
+ }
+
+ /* Terminate the process, which is now in an inconsistent state
+ because we reaped all the PIDs that it may have been reaping
+ or may have reaped in the future. Reraise the signal so that
+ the proper exit code is returned. */
+ {
+ /* Install default signal handler. */
+ struct sigaction defSigAction;
+ sigset_t unblockSet;
+ memset(&defSigAction, 0, sizeof(defSigAction));
+ defSigAction.sa_handler = SIG_DFL;
+ sigemptyset(&defSigAction.sa_mask);
+ while((sigaction(signum, &defSigAction, 0) < 0) &&
+ (errno == EINTR));
+ /* Unmask the signal. */
+ sigemptyset(&unblockSet);
+ sigaddset(&unblockSet, signum);
+ sigprocmask(SIG_UNBLOCK, &unblockSet, 0);
+ /* Raise the signal again. */
+ raise(signum);
+ /* We shouldn't get here... but if we do... */
+ _exit(1);
+ }
+ /* break omitted to silence unreachable code clang compiler warning. */
+ }
+
+#if !KWSYSPE_USE_SIGINFO
+ /* Re-Install our handler. Repeat call until it is not interrupted. */
+ {
+ struct sigaction newSigAction;
+ struct sigaction &oldSigAction;
+ memset(&newSigAction, 0, sizeof(struct sigaction));
+ newSigChldAction.sa_handler = kwsysProcessesSignalHandler;
+ newSigChldAction.sa_flags = SA_NOCLDSTOP;
+ sigemptyset(&newSigAction.sa_mask);
+ switch(signum)
+ {
+ case SIGCHLD: oldSigAction = &kwsysProcessesOldSigChldAction; break;
+ case SIGINT:
+ sigaddset(&newSigAction.sa_mask, SIGTERM);
+ oldSigAction = &kwsysProcessesOldSigIntAction; break;
+ case SIGTERM:
+ sigaddset(&newSigAction.sa_mask, SIGINT);
+ oldSigAction = &kwsysProcessesOldSigTermAction; break;
+ default: return 0;
+ }
+ while((sigaction(signum, &newSigAction,
+ oldSigAction) < 0) &&
+ (errno == EINTR));
+ }
+#endif
+
+ errno = old_errno;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_ResetStartTime(kwsysProcess* cp)
+{
+ if(!cp)
+ {
+ return;
+ }
+ /* Reset start time. */
+ cp->StartTime = kwsysProcessTimeGetCurrent();
+}
diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
new file mode 100644
index 0000000..2b93e69
--- /dev/null
+++ b/Source/kwsys/ProcessWin32.c
@@ -0,0 +1,3030 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Process.h)
+#include KWSYS_HEADER(Encoding.h)
+
+/* Work-around CMake dependency scanning limitation. This must
+ duplicate the above list of headers. */
+#if 0
+# include "Process.h.in"
+# include "Encoding.h.in"
+#endif
+
+/*
+
+Implementation for Windows
+
+On windows, a thread is created to wait for data on each pipe. The
+threads are synchronized with the main thread to simulate the use of
+a UNIX-style select system call.
+
+*/
+
+#ifdef _MSC_VER
+#pragma warning (push, 1)
+#endif
+#include <windows.h> /* Windows API */
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#endif
+#include <string.h> /* strlen, strdup */
+#include <stdio.h> /* sprintf */
+#include <io.h> /* _unlink */
+#ifdef __WATCOMC__
+#define _unlink unlink
+#endif
+
+#ifndef _MAX_FNAME
+#define _MAX_FNAME 4096
+#endif
+#ifndef _MAX_PATH
+#define _MAX_PATH 4096
+#endif
+
+#ifdef _MSC_VER
+#pragma warning (pop)
+#pragma warning (disable: 4514)
+#pragma warning (disable: 4706)
+#endif
+
+#if defined(__BORLANDC__)
+# pragma warn -8004 /* assigned a value that is never used */
+# pragma warn -8060 /* Assignment inside if() condition. */
+#endif
+
+/* There are pipes for the process pipeline's stdout and stderr. */
+#define KWSYSPE_PIPE_COUNT 2
+#define KWSYSPE_PIPE_STDOUT 0
+#define KWSYSPE_PIPE_STDERR 1
+
+/* The maximum amount to read from a pipe at a time. */
+#define KWSYSPE_PIPE_BUFFER_SIZE 1024
+
+/* Debug output macro. */
+#if 0
+# define KWSYSPE_DEBUG(x) \
+( \
+ (void*)cp == (void*)0x00226DE0? \
+ ( \
+ fprintf(stderr, "%d/%p/%d ", (int)GetCurrentProcessId(), cp, __LINE__), \
+ fprintf x, \
+ fflush(stderr), \
+ 1 \
+ ) : (1) \
+)
+#else
+# define KWSYSPE_DEBUG(x) (void)1
+#endif
+
+typedef LARGE_INTEGER kwsysProcessTime;
+
+typedef struct kwsysProcessCreateInformation_s
+{
+ /* Windows child startup control data. */
+ STARTUPINFOW StartupInfo;
+
+ /* Original handles before making inherited duplicates. */
+ HANDLE hStdInput;
+ HANDLE hStdOutput;
+ HANDLE hStdError;
+} kwsysProcessCreateInformation;
+
+
+/*--------------------------------------------------------------------------*/
+typedef struct kwsysProcessPipeData_s kwsysProcessPipeData;
+static DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd);
+static void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp,
+ kwsysProcessPipeData* td);
+static DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd);
+static void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp,
+ kwsysProcessPipeData* td);
+static int kwsysProcessInitialize(kwsysProcess* cp);
+static DWORD kwsysProcessCreate(kwsysProcess* cp, int index,
+ kwsysProcessCreateInformation* si);
+static void kwsysProcessDestroy(kwsysProcess* cp, int event);
+static DWORD kwsysProcessSetupOutputPipeFile(PHANDLE handle,
+ const char* name);
+static void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle);
+static void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle);
+static void kwsysProcessCleanupHandle(PHANDLE h);
+static void kwsysProcessCleanup(kwsysProcess* cp, DWORD error);
+static void kwsysProcessCleanErrorMessage(kwsysProcess* cp);
+static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
+ kwsysProcessTime* timeoutTime);
+static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
+ double* userTimeout,
+ kwsysProcessTime* timeoutLength);
+static kwsysProcessTime kwsysProcessTimeGetCurrent(void);
+static DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t);
+static double kwsysProcessTimeToDouble(kwsysProcessTime t);
+static kwsysProcessTime kwsysProcessTimeFromDouble(double d);
+static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2);
+static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2);
+static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime in2);
+static void kwsysProcessSetExitException(kwsysProcess* cp, int code);
+static void kwsysProcessKillTree(int pid);
+static void kwsysProcessDisablePipeThreads(kwsysProcess* cp);
+static int kwsysProcessesInitialize(void);
+static int kwsysTryEnterCreateProcessSection(void);
+static void kwsysLeaveCreateProcessSection(void);
+static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessId,
+ int newProcessGroup);
+static void kwsysProcessesRemove(HANDLE hProcess);
+static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType);
+
+/*--------------------------------------------------------------------------*/
+/* A structure containing synchronization data for each thread. */
+typedef struct kwsysProcessPipeSync_s kwsysProcessPipeSync;
+struct kwsysProcessPipeSync_s
+{
+ /* Handle to the thread. */
+ HANDLE Thread;
+
+ /* Semaphore indicating to the thread that a process has started. */
+ HANDLE Ready;
+
+ /* Semaphore indicating to the thread that it should begin work. */
+ HANDLE Go;
+
+ /* Semaphore indicating thread has reset for another process. */
+ HANDLE Reset;
+};
+
+/*--------------------------------------------------------------------------*/
+/* A structure containing data for each pipe's threads. */
+struct kwsysProcessPipeData_s
+{
+ /* ------------- Data managed per instance of kwsysProcess ------------- */
+
+ /* Synchronization data for reading thread. */
+ kwsysProcessPipeSync Reader;
+
+ /* Synchronization data for waking thread. */
+ kwsysProcessPipeSync Waker;
+
+ /* Index of this pipe. */
+ int Index;
+
+ /* The kwsysProcess instance owning this pipe. */
+ kwsysProcess* Process;
+
+ /* ------------- Data managed per call to Execute ------------- */
+
+ /* Buffer for data read in this pipe's thread. */
+ char DataBuffer[KWSYSPE_PIPE_BUFFER_SIZE];
+
+ /* The length of the data stored in the buffer. */
+ DWORD DataLength;
+
+ /* Whether the pipe has been closed. */
+ int Closed;
+
+ /* Handle for the read end of this pipe. */
+ HANDLE Read;
+
+ /* Handle for the write end of this pipe. */
+ HANDLE Write;
+};
+
+/*--------------------------------------------------------------------------*/
+/* Structure containing data used to implement the child's execution. */
+struct kwsysProcess_s
+{
+ /* ------------- Data managed per instance of kwsysProcess ------------- */
+
+ /* The status of the process structure. */
+ int State;
+
+ /* The command lines to execute. */
+ wchar_t** Commands;
+ int NumberOfCommands;
+
+ /* The exit code of each command. */
+ DWORD* CommandExitCodes;
+
+ /* The working directory for the child process. */
+ wchar_t* WorkingDirectory;
+
+ /* Whether to create the child as a detached process. */
+ int OptionDetach;
+
+ /* Whether the child was created as a detached process. */
+ int Detached;
+
+ /* Whether to hide the child process's window. */
+ int HideWindow;
+
+ /* Whether to treat command lines as verbatim. */
+ int Verbatim;
+
+ /* Whether to merge stdout/stderr of the child. */
+ int MergeOutput;
+
+ /* Whether to create the process in a new process group. */
+ int CreateProcessGroup;
+
+ /* Mutex to protect the shared index used by threads to report data. */
+ HANDLE SharedIndexMutex;
+
+ /* Semaphore used by threads to signal data ready. */
+ HANDLE Full;
+
+ /* Whether we are currently deleting this kwsysProcess instance. */
+ int Deleting;
+
+ /* Data specific to each pipe and its thread. */
+ kwsysProcessPipeData Pipe[KWSYSPE_PIPE_COUNT];
+
+ /* Name of files to which stdin and stdout pipes are attached. */
+ char* PipeFileSTDIN;
+ char* PipeFileSTDOUT;
+ char* PipeFileSTDERR;
+
+ /* Whether each pipe is shared with the parent process. */
+ int PipeSharedSTDIN;
+ int PipeSharedSTDOUT;
+ int PipeSharedSTDERR;
+
+ /* Native pipes provided by the user. */
+ HANDLE PipeNativeSTDIN[2];
+ HANDLE PipeNativeSTDOUT[2];
+ HANDLE PipeNativeSTDERR[2];
+
+ /* ------------- Data managed per call to Execute ------------- */
+
+ /* The exceptional behavior that terminated the process, if any. */
+ int ExitException;
+
+ /* The process exit code. */
+ DWORD ExitCode;
+
+ /* The process return code, if any. */
+ int ExitValue;
+
+ /* Index of last pipe to report data, if any. */
+ int CurrentIndex;
+
+ /* Index shared by threads to report data. */
+ int SharedIndex;
+
+ /* The timeout length. */
+ double Timeout;
+
+ /* Time at which the child started. */
+ kwsysProcessTime StartTime;
+
+ /* Time at which the child will timeout. Negative for no timeout. */
+ kwsysProcessTime TimeoutTime;
+
+ /* Flag for whether the process was killed. */
+ int Killed;
+
+ /* Flag for whether the timeout expired. */
+ int TimeoutExpired;
+
+ /* Flag for whether the process has terminated. */
+ int Terminated;
+
+ /* The number of pipes still open during execution and while waiting
+ for pipes to close after process termination. */
+ int PipesLeft;
+
+ /* Buffer for error messages. */
+ char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1];
+
+ /* Description for the ExitException. */
+ char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE+1];
+
+ /* Windows process information data. */
+ PROCESS_INFORMATION* ProcessInformation;
+
+ /* Data and process termination events for which to wait. */
+ PHANDLE ProcessEvents;
+ int ProcessEventsLength;
+
+ /* Real working directory of our own process. */
+ DWORD RealWorkingDirectoryLength;
+ wchar_t* RealWorkingDirectory;
+
+ /* Own handles for the child's ends of the pipes in the parent process.
+ Used temporarily during process creation. */
+ HANDLE PipeChildStd[3];
+};
+
+/*--------------------------------------------------------------------------*/
+kwsysProcess* kwsysProcess_New(void)
+{
+ int i;
+
+ /* Process control structure. */
+ kwsysProcess* cp;
+
+ /* Windows version number data. */
+ OSVERSIONINFO osv;
+
+ /* Initialize list of processes before we get any farther. It's especially
+ important that the console Ctrl handler be added BEFORE starting the
+ first process. This prevents the risk of an orphaned process being
+ started by the main thread while the default Ctrl handler is in
+ progress. */
+ if(!kwsysProcessesInitialize())
+ {
+ return 0;
+ }
+
+ /* Allocate a process control structure. */
+ cp = (kwsysProcess*)malloc(sizeof(kwsysProcess));
+ if(!cp)
+ {
+ /* Could not allocate memory for the control structure. */
+ return 0;
+ }
+ ZeroMemory(cp, sizeof(*cp));
+
+ /* Share stdin with the parent process by default. */
+ cp->PipeSharedSTDIN = 1;
+
+ /* Set initial status. */
+ cp->State = kwsysProcess_State_Starting;
+
+ /* Choose a method of running the child based on version of
+ windows. */
+ ZeroMemory(&osv, sizeof(osv));
+ osv.dwOSVersionInfoSize = sizeof(osv);
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+# pragma warning (push)
+# ifdef __INTEL_COMPILER
+# pragma warning (disable:1478)
+# else
+# pragma warning (disable:4996)
+# endif
+#endif
+ GetVersionEx(&osv);
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+# pragma warning (pop)
+#endif
+ if(osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
+ {
+ /* Win9x no longer supported. */
+ kwsysProcess_Delete(cp);
+ return 0;
+ }
+
+ /* Initially no thread owns the mutex. Initialize semaphore to 1. */
+ if(!(cp->SharedIndexMutex = CreateSemaphore(0, 1, 1, 0)))
+ {
+ kwsysProcess_Delete(cp);
+ return 0;
+ }
+
+ /* Initially no data are available. Initialize semaphore to 0. */
+ if(!(cp->Full = CreateSemaphore(0, 0, 1, 0)))
+ {
+ kwsysProcess_Delete(cp);
+ return 0;
+ }
+
+ /* Create the thread to read each pipe. */
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ DWORD dummy=0;
+
+ /* Assign the thread its index. */
+ cp->Pipe[i].Index = i;
+
+ /* Give the thread a pointer back to the kwsysProcess instance. */
+ cp->Pipe[i].Process = cp;
+
+ /* No process is yet running. Initialize semaphore to 0. */
+ if(!(cp->Pipe[i].Reader.Ready = CreateSemaphore(0, 0, 1, 0)))
+ {
+ kwsysProcess_Delete(cp);
+ return 0;
+ }
+
+ /* The pipe is not yet reset. Initialize semaphore to 0. */
+ if(!(cp->Pipe[i].Reader.Reset = CreateSemaphore(0, 0, 1, 0)))
+ {
+ kwsysProcess_Delete(cp);
+ return 0;
+ }
+
+ /* The thread's buffer is initially empty. Initialize semaphore to 1. */
+ if(!(cp->Pipe[i].Reader.Go = CreateSemaphore(0, 1, 1, 0)))
+ {
+ kwsysProcess_Delete(cp);
+ return 0;
+ }
+
+ /* Create the reading thread. It will block immediately. The
+ thread will not make deeply nested calls, so we need only a
+ small stack. */
+ if(!(cp->Pipe[i].Reader.Thread = CreateThread(0, 1024,
+ kwsysProcessPipeThreadRead,
+ &cp->Pipe[i], 0, &dummy)))
+ {
+ kwsysProcess_Delete(cp);
+ return 0;
+ }
+
+ /* No process is yet running. Initialize semaphore to 0. */
+ if(!(cp->Pipe[i].Waker.Ready = CreateSemaphore(0, 0, 1, 0)))
+ {
+ kwsysProcess_Delete(cp);
+ return 0;
+ }
+
+ /* The pipe is not yet reset. Initialize semaphore to 0. */
+ if(!(cp->Pipe[i].Waker.Reset = CreateSemaphore(0, 0, 1, 0)))
+ {
+ kwsysProcess_Delete(cp);
+ return 0;
+ }
+
+ /* The waker should not wake immediately. Initialize semaphore to 0. */
+ if(!(cp->Pipe[i].Waker.Go = CreateSemaphore(0, 0, 1, 0)))
+ {
+ kwsysProcess_Delete(cp);
+ return 0;
+ }
+
+ /* Create the waking thread. It will block immediately. The
+ thread will not make deeply nested calls, so we need only a
+ small stack. */
+ if(!(cp->Pipe[i].Waker.Thread = CreateThread(0, 1024,
+ kwsysProcessPipeThreadWake,
+ &cp->Pipe[i], 0, &dummy)))
+ {
+ kwsysProcess_Delete(cp);
+ return 0;
+ }
+ }
+ for(i=0; i < 3; ++i)
+ {
+ cp->PipeChildStd[i] = INVALID_HANDLE_VALUE;
+ }
+
+ return cp;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Delete(kwsysProcess* cp)
+{
+ int i;
+
+ /* Make sure we have an instance. */
+ if(!cp)
+ {
+ return;
+ }
+
+ /* If the process is executing, wait for it to finish. */
+ if(cp->State == kwsysProcess_State_Executing)
+ {
+ if(cp->Detached)
+ {
+ kwsysProcess_Disown(cp);
+ }
+ else
+ {
+ kwsysProcess_WaitForExit(cp, 0);
+ }
+ }
+
+ /* We are deleting the kwsysProcess instance. */
+ cp->Deleting = 1;
+
+ /* Terminate each of the threads. */
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ /* Terminate this reading thread. */
+ if(cp->Pipe[i].Reader.Thread)
+ {
+ /* Signal the thread we are ready for it. It will terminate
+ immediately since Deleting is set. */
+ ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0);
+
+ /* Wait for the thread to exit. */
+ WaitForSingleObject(cp->Pipe[i].Reader.Thread, INFINITE);
+
+ /* Close the handle to the thread. */
+ kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Thread);
+ }
+
+ /* Terminate this waking thread. */
+ if(cp->Pipe[i].Waker.Thread)
+ {
+ /* Signal the thread we are ready for it. It will terminate
+ immediately since Deleting is set. */
+ ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0);
+
+ /* Wait for the thread to exit. */
+ WaitForSingleObject(cp->Pipe[i].Waker.Thread, INFINITE);
+
+ /* Close the handle to the thread. */
+ kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Thread);
+ }
+
+ /* Cleanup the pipe's semaphores. */
+ kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Ready);
+ kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Go);
+ kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Reset);
+ kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Ready);
+ kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Go);
+ kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Reset);
+ }
+
+ /* Close the shared semaphores. */
+ kwsysProcessCleanupHandle(&cp->SharedIndexMutex);
+ kwsysProcessCleanupHandle(&cp->Full);
+
+ /* Free memory. */
+ kwsysProcess_SetCommand(cp, 0);
+ kwsysProcess_SetWorkingDirectory(cp, 0);
+ kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0);
+ kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0);
+ kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0);
+ if(cp->CommandExitCodes)
+ {
+ free(cp->CommandExitCodes);
+ }
+ free(cp);
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command)
+{
+ int i;
+ if(!cp)
+ {
+ return 0;
+ }
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ free(cp->Commands[i]);
+ }
+ cp->NumberOfCommands = 0;
+ if(cp->Commands)
+ {
+ free(cp->Commands);
+ cp->Commands = 0;
+ }
+ if(command)
+ {
+ return kwsysProcess_AddCommand(cp, command);
+ }
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
+{
+ int newNumberOfCommands;
+ wchar_t** newCommands;
+
+ /* Make sure we have a command to add. */
+ if(!cp || !command || !*command)
+ {
+ return 0;
+ }
+
+
+ /* Allocate a new array for command pointers. */
+ newNumberOfCommands = cp->NumberOfCommands + 1;
+ if(!(newCommands = (wchar_t**)malloc(sizeof(wchar_t*) * newNumberOfCommands)))
+ {
+ /* Out of memory. */
+ return 0;
+ }
+
+ /* Copy any existing commands into the new array. */
+ {
+ int i;
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ newCommands[i] = cp->Commands[i];
+ }
+ }
+
+ if (cp->Verbatim)
+ {
+ /* Copy the verbatim command line into the buffer. */
+ newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(*command);
+ }
+ else
+ {
+ /* Encode the arguments so CommandLineToArgvW can decode
+ them from the command line string in the child. */
+ char buffer[32768]; /* CreateProcess max command-line length. */
+ char* end = buffer + sizeof(buffer);
+ char* out = buffer;
+ char const* const* a;
+ for (a = command; *a; ++a)
+ {
+ int quote = !**a; /* Quote the empty string. */
+ int slashes = 0;
+ char const* c;
+ if (a != command && out != end) { *out++ = ' '; }
+ for (c = *a; !quote && *c; ++c)
+ { quote = (*c == ' ' || *c == '\t'); }
+ if (quote && out != end) { *out++ = '"'; }
+ for (c = *a; *c; ++c)
+ {
+ if (*c == '\\')
+ {
+ ++slashes;
+ }
+ else
+ {
+ if (*c == '"')
+ {
+ // Add n+1 backslashes to total 2n+1 before internal '"'.
+ while(slashes-- >= 0 && out != end) { *out++ = '\\'; }
+ }
+ slashes = 0;
+ }
+ if (out != end) { *out++ = *c; }
+ }
+ if (quote)
+ {
+ // Add n backslashes to total 2n before ending '"'.
+ while (slashes-- > 0 && out != end) { *out++ = '\\'; }
+ if (out != end) { *out++ = '"'; }
+ }
+ }
+ if(out != end)
+ {
+ *out = '\0';
+ newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(buffer);
+ }
+ else
+ {
+ newCommands[cp->NumberOfCommands] = 0;
+ }
+ }
+ if (!newCommands[cp->NumberOfCommands])
+ {
+ /* Out of memory or command line too long. */
+ free(newCommands);
+ return 0;
+ }
+
+ /* Save the new array of commands. */
+ free(cp->Commands);
+ cp->Commands = newCommands;
+ cp->NumberOfCommands = newNumberOfCommands;
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout)
+{
+ if(!cp)
+ {
+ return;
+ }
+ cp->Timeout = timeout;
+ if(cp->Timeout < 0)
+ {
+ cp->Timeout = 0;
+ }
+ // Force recomputation of TimeoutTime.
+ cp->TimeoutTime.QuadPart = -1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
+{
+ if(!cp)
+ {
+ return 0;
+ }
+ if(cp->WorkingDirectory)
+ {
+ free(cp->WorkingDirectory);
+ cp->WorkingDirectory = 0;
+ }
+ if(dir && dir[0])
+ {
+ wchar_t* wdir = kwsysEncoding_DupToWide(dir);
+ /* We must convert the working directory to a full path. */
+ DWORD length = GetFullPathNameW(wdir, 0, 0, 0);
+ if(length > 0)
+ {
+ wchar_t* work_dir = malloc(length*sizeof(wchar_t));
+ if(!work_dir)
+ {
+ free(wdir);
+ return 0;
+ }
+ if(!GetFullPathNameW(wdir, length, work_dir, 0))
+ {
+ free(work_dir);
+ free(wdir);
+ return 0;
+ }
+ cp->WorkingDirectory = work_dir;
+ }
+ free(wdir);
+ }
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
+{
+ char** pfile;
+ if(!cp)
+ {
+ return 0;
+ }
+ switch(pipe)
+ {
+ case kwsysProcess_Pipe_STDIN: pfile = &cp->PipeFileSTDIN; break;
+ case kwsysProcess_Pipe_STDOUT: pfile = &cp->PipeFileSTDOUT; break;
+ case kwsysProcess_Pipe_STDERR: pfile = &cp->PipeFileSTDERR; break;
+ default: return 0;
+ }
+ if(*pfile)
+ {
+ free(*pfile);
+ *pfile = 0;
+ }
+ if(file)
+ {
+ *pfile = (char*)malloc(strlen(file)+1);
+ if(!*pfile)
+ {
+ return 0;
+ }
+ strcpy(*pfile, file);
+ }
+
+ /* If we are redirecting the pipe, do not share it or use a native
+ pipe. */
+ if(*pfile)
+ {
+ kwsysProcess_SetPipeNative(cp, pipe, 0);
+ kwsysProcess_SetPipeShared(cp, pipe, 0);
+ }
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared)
+{
+ if(!cp)
+ {
+ return;
+ }
+
+ switch(pipe)
+ {
+ case kwsysProcess_Pipe_STDIN: cp->PipeSharedSTDIN = shared?1:0; break;
+ case kwsysProcess_Pipe_STDOUT: cp->PipeSharedSTDOUT = shared?1:0; break;
+ case kwsysProcess_Pipe_STDERR: cp->PipeSharedSTDERR = shared?1:0; break;
+ default: return;
+ }
+
+ /* If we are sharing the pipe, do not redirect it to a file or use a
+ native pipe. */
+ if(shared)
+ {
+ kwsysProcess_SetPipeFile(cp, pipe, 0);
+ kwsysProcess_SetPipeNative(cp, pipe, 0);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, HANDLE p[2])
+{
+ HANDLE* pPipeNative = 0;
+
+ if(!cp)
+ {
+ return;
+ }
+
+ switch(pipe)
+ {
+ case kwsysProcess_Pipe_STDIN: pPipeNative = cp->PipeNativeSTDIN; break;
+ case kwsysProcess_Pipe_STDOUT: pPipeNative = cp->PipeNativeSTDOUT; break;
+ case kwsysProcess_Pipe_STDERR: pPipeNative = cp->PipeNativeSTDERR; break;
+ default: return;
+ }
+
+ /* Copy the native pipe handles provided. */
+ if(p)
+ {
+ pPipeNative[0] = p[0];
+ pPipeNative[1] = p[1];
+ }
+ else
+ {
+ pPipeNative[0] = 0;
+ pPipeNative[1] = 0;
+ }
+
+ /* If we are using a native pipe, do not share it or redirect it to
+ a file. */
+ if(p)
+ {
+ kwsysProcess_SetPipeFile(cp, pipe, 0);
+ kwsysProcess_SetPipeShared(cp, pipe, 0);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
+{
+ if(!cp)
+ {
+ return 0;
+ }
+
+ switch(optionId)
+ {
+ case kwsysProcess_Option_Detach: return cp->OptionDetach;
+ case kwsysProcess_Option_HideWindow: return cp->HideWindow;
+ case kwsysProcess_Option_MergeOutput: return cp->MergeOutput;
+ case kwsysProcess_Option_Verbatim: return cp->Verbatim;
+ case kwsysProcess_Option_CreateProcessGroup:
+ return cp->CreateProcessGroup;
+ default: return 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
+{
+ if(!cp)
+ {
+ return;
+ }
+
+ switch(optionId)
+ {
+ case kwsysProcess_Option_Detach: cp->OptionDetach = value; break;
+ case kwsysProcess_Option_HideWindow: cp->HideWindow = value; break;
+ case kwsysProcess_Option_MergeOutput: cp->MergeOutput = value; break;
+ case kwsysProcess_Option_Verbatim: cp->Verbatim = value; break;
+ case kwsysProcess_Option_CreateProcessGroup:
+ cp->CreateProcessGroup = value; break;
+ default: break;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetState(kwsysProcess* cp)
+{
+ return cp? cp->State : kwsysProcess_State_Error;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitException(kwsysProcess* cp)
+{
+ return cp? cp->ExitException : kwsysProcess_Exception_Other;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitValue(kwsysProcess* cp)
+{
+ return cp? cp->ExitValue : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitCode(kwsysProcess* cp)
+{
+ return cp? cp->ExitCode : 0;
+}
+
+/*--------------------------------------------------------------------------*/
+const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
+{
+ if(!cp)
+ {
+ return "Process management structure could not be allocated";
+ }
+ else if(cp->State == kwsysProcess_State_Error)
+ {
+ return cp->ErrorMessage;
+ }
+ return "Success";
+}
+
+/*--------------------------------------------------------------------------*/
+const char* kwsysProcess_GetExceptionString(kwsysProcess* cp)
+{
+ if(!cp)
+ {
+ return "GetExceptionString called with NULL process management structure";
+ }
+ else if(cp->State == kwsysProcess_State_Exception)
+ {
+ return cp->ExitExceptionString;
+ }
+ return "No exception";
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Execute(kwsysProcess* cp)
+{
+ int i;
+
+ /* Do not execute a second time. */
+ if(!cp || cp->State == kwsysProcess_State_Executing)
+ {
+ return;
+ }
+
+ /* Make sure we have something to run. */
+ if(cp->NumberOfCommands < 1)
+ {
+ strcpy(cp->ErrorMessage, "No command");
+ cp->State = kwsysProcess_State_Error;
+ return;
+ }
+
+ /* Initialize the control structure for a new process. */
+ if(!kwsysProcessInitialize(cp))
+ {
+ strcpy(cp->ErrorMessage, "Out of memory");
+ cp->State = kwsysProcess_State_Error;
+ return;
+ }
+
+ /* Save the real working directory of this process and change to
+ the working directory for the child processes. This is needed
+ to make pipe file paths evaluate correctly. */
+ if(cp->WorkingDirectory)
+ {
+ if(!GetCurrentDirectoryW(cp->RealWorkingDirectoryLength,
+ cp->RealWorkingDirectory))
+ {
+ kwsysProcessCleanup(cp, GetLastError());
+ return;
+ }
+ SetCurrentDirectoryW(cp->WorkingDirectory);
+ }
+
+
+ /* Setup the stdin pipe for the first process. */
+ if(cp->PipeFileSTDIN)
+ {
+ /* Create a handle to read a file for stdin. */
+ wchar_t* wstdin = kwsysEncoding_DupToWide(cp->PipeFileSTDIN);
+ DWORD error;
+ cp->PipeChildStd[0] =
+ CreateFileW(wstdin, GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ 0, OPEN_EXISTING, 0, 0);
+ error = GetLastError(); /* Check now in case free changes this. */
+ free(wstdin);
+ if(cp->PipeChildStd[0] == INVALID_HANDLE_VALUE)
+ {
+ kwsysProcessCleanup(cp, error);
+ return;
+ }
+ }
+ else if(cp->PipeSharedSTDIN)
+ {
+ /* Share this process's stdin with the child. */
+ kwsysProcessSetupSharedPipe(STD_INPUT_HANDLE, &cp->PipeChildStd[0]);
+ }
+ else if(cp->PipeNativeSTDIN[0])
+ {
+ /* Use the provided native pipe. */
+ kwsysProcessSetupPipeNative(cp->PipeNativeSTDIN[0], &cp->PipeChildStd[0]);
+ }
+ else
+ {
+ /* Explicitly give the child no stdin. */
+ cp->PipeChildStd[0] = INVALID_HANDLE_VALUE;
+ }
+
+ /* Create the output pipe for the last process.
+ We always create this so the pipe thread can run even if we
+ do not end up giving the write end to the child below. */
+ if(!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDOUT].Read,
+ &cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, 0, 0))
+ {
+ kwsysProcessCleanup(cp, GetLastError());
+ return;
+ }
+
+ if(cp->PipeFileSTDOUT)
+ {
+ /* Use a file for stdout. */
+ DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1],
+ cp->PipeFileSTDOUT);
+ if(error)
+ {
+ kwsysProcessCleanup(cp, error);
+ return;
+ }
+ }
+ else if(cp->PipeSharedSTDOUT)
+ {
+ /* Use the parent stdout. */
+ kwsysProcessSetupSharedPipe(STD_OUTPUT_HANDLE, &cp->PipeChildStd[1]);
+ }
+ else if(cp->PipeNativeSTDOUT[1])
+ {
+ /* Use the given handle for stdout. */
+ kwsysProcessSetupPipeNative(cp->PipeNativeSTDOUT[1], &cp->PipeChildStd[1]);
+ }
+ else
+ {
+ /* Use our pipe for stdout. Duplicate the handle since our waker
+ thread will use the original. Do not make it inherited yet. */
+ if(!DuplicateHandle(GetCurrentProcess(),
+ cp->Pipe[KWSYSPE_PIPE_STDOUT].Write,
+ GetCurrentProcess(), &cp->PipeChildStd[1],
+ 0, FALSE, DUPLICATE_SAME_ACCESS))
+ {
+ kwsysProcessCleanup(cp, GetLastError());
+ return;
+ }
+ }
+
+ /* Create stderr pipe to be shared by all processes in the pipeline.
+ We always create this so the pipe thread can run even if we do not
+ end up giving the write end to the child below. */
+ if(!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read,
+ &cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0))
+ {
+ kwsysProcessCleanup(cp, GetLastError());
+ return;
+ }
+
+ if(cp->PipeFileSTDERR)
+ {
+ /* Use a file for stderr. */
+ DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2],
+ cp->PipeFileSTDERR);
+ if(error)
+ {
+ kwsysProcessCleanup(cp, error);
+ return;
+ }
+ }
+ else if(cp->PipeSharedSTDERR)
+ {
+ /* Use the parent stderr. */
+ kwsysProcessSetupSharedPipe(STD_ERROR_HANDLE, &cp->PipeChildStd[2]);
+ }
+ else if(cp->PipeNativeSTDERR[1])
+ {
+ /* Use the given handle for stderr. */
+ kwsysProcessSetupPipeNative(cp->PipeNativeSTDERR[1], &cp->PipeChildStd[2]);
+ }
+ else
+ {
+ /* Use our pipe for stderr. Duplicate the handle since our waker
+ thread will use the original. Do not make it inherited yet. */
+ if(!DuplicateHandle(GetCurrentProcess(),
+ cp->Pipe[KWSYSPE_PIPE_STDERR].Write,
+ GetCurrentProcess(), &cp->PipeChildStd[2],
+ 0, FALSE, DUPLICATE_SAME_ACCESS))
+ {
+ kwsysProcessCleanup(cp, GetLastError());
+ return;
+ }
+ }
+
+ /* Create the pipeline of processes. */
+ {
+ /* Child startup control data. */
+ kwsysProcessCreateInformation si;
+ HANDLE nextStdInput = cp->PipeChildStd[0];
+
+ /* Initialize startup info data. */
+ ZeroMemory(&si, sizeof(si));
+ si.StartupInfo.cb = sizeof(si.StartupInfo);
+
+ /* Decide whether a child window should be shown. */
+ si.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
+ si.StartupInfo.wShowWindow =
+ (unsigned short)(cp->HideWindow?SW_HIDE:SW_SHOWDEFAULT);
+
+ /* Connect the child's output pipes to the threads. */
+ si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
+
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ /* Setup the process's pipes. */
+ si.hStdInput = nextStdInput;
+ if (i == cp->NumberOfCommands-1)
+ {
+ /* The last child gets the overall stdout. */
+ nextStdInput = INVALID_HANDLE_VALUE;
+ si.hStdOutput = cp->PipeChildStd[1];
+ }
+ else
+ {
+ /* Create a pipe to sit between the children. */
+ HANDLE p[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
+ if (!CreatePipe(&p[0], &p[1], 0, 0))
+ {
+ DWORD error = GetLastError();
+ if (nextStdInput != cp->PipeChildStd[0])
+ {
+ kwsysProcessCleanupHandle(&nextStdInput);
+ }
+ kwsysProcessCleanup(cp, error);
+ return;
+ }
+ nextStdInput = p[0];
+ si.hStdOutput = p[1];
+ }
+ si.hStdError = cp->MergeOutput? cp->PipeChildStd[1] : cp->PipeChildStd[2];
+
+ {
+ DWORD error = kwsysProcessCreate(cp, i, &si);
+
+ /* Close our copies of pipes used between children. */
+ if (si.hStdInput != cp->PipeChildStd[0])
+ {
+ kwsysProcessCleanupHandle(&si.hStdInput);
+ }
+ if (si.hStdOutput != cp->PipeChildStd[1])
+ {
+ kwsysProcessCleanupHandle(&si.hStdOutput);
+ }
+ if (si.hStdError != cp->PipeChildStd[2] && !cp->MergeOutput)
+ {
+ kwsysProcessCleanupHandle(&si.hStdError);
+ }
+ if (!error)
+ {
+ cp->ProcessEvents[i+1] = cp->ProcessInformation[i].hProcess;
+ }
+ else
+ {
+ if (nextStdInput != cp->PipeChildStd[0])
+ {
+ kwsysProcessCleanupHandle(&nextStdInput);
+ }
+ kwsysProcessCleanup(cp, error);
+ return;
+ }
+ }
+ }
+ }
+
+ /* The parent process does not need the child's pipe ends. */
+ for (i=0; i < 3; ++i)
+ {
+ kwsysProcessCleanupHandle(&cp->PipeChildStd[i]);
+ }
+
+ /* Restore the working directory. */
+ if(cp->RealWorkingDirectory)
+ {
+ SetCurrentDirectoryW(cp->RealWorkingDirectory);
+ free(cp->RealWorkingDirectory);
+ cp->RealWorkingDirectory = 0;
+ }
+
+ /* The timeout period starts now. */
+ cp->StartTime = kwsysProcessTimeGetCurrent();
+ cp->TimeoutTime = kwsysProcessTimeFromDouble(-1);
+
+ /* All processes in the pipeline have been started in suspended
+ mode. Resume them all now. */
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ ResumeThread(cp->ProcessInformation[i].hThread);
+ }
+
+ /* ---- It is no longer safe to call kwsysProcessCleanup. ----- */
+ /* Tell the pipe threads that a process has started. */
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0);
+ ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0);
+ }
+
+ /* We don't care about the children's main threads. */
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
+ }
+
+ /* No pipe has reported data. */
+ cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
+ cp->PipesLeft = KWSYSPE_PIPE_COUNT;
+
+ /* The process has now started. */
+ cp->State = kwsysProcess_State_Executing;
+ cp->Detached = cp->OptionDetach;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Disown(kwsysProcess* cp)
+{
+ int i;
+
+ /* Make sure we are executing a detached process. */
+ if(!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing ||
+ cp->TimeoutExpired || cp->Killed || cp->Terminated)
+ {
+ return;
+ }
+
+ /* Disable the reading threads. */
+ kwsysProcessDisablePipeThreads(cp);
+
+ /* Wait for all pipe threads to reset. */
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE);
+ WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE);
+ }
+
+ /* We will not wait for exit, so cleanup now. */
+ kwsysProcessCleanup(cp, 0);
+
+ /* The process has been disowned. */
+ cp->State = kwsysProcess_State_Disowned;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
+ double* userTimeout)
+{
+ kwsysProcessTime userStartTime;
+ kwsysProcessTime timeoutLength;
+ kwsysProcessTime timeoutTime;
+ DWORD timeout;
+ int user;
+ int done = 0;
+ int expired = 0;
+ int pipeId = kwsysProcess_Pipe_None;
+ DWORD w;
+
+ /* Make sure we are executing a process. */
+ if(!cp || cp->State != kwsysProcess_State_Executing || cp->Killed ||
+ cp->TimeoutExpired)
+ {
+ return kwsysProcess_Pipe_None;
+ }
+
+ /* Record the time at which user timeout period starts. */
+ userStartTime = kwsysProcessTimeGetCurrent();
+
+ /* Calculate the time at which a timeout will expire, and whether it
+ is the user or process timeout. */
+ user = kwsysProcessGetTimeoutTime(cp, userTimeout, &timeoutTime);
+
+ /* Loop until we have a reason to return. */
+ while(!done && cp->PipesLeft > 0)
+ {
+ /* If we previously got data from a thread, let it know we are
+ done with the data. */
+ if(cp->CurrentIndex < KWSYSPE_PIPE_COUNT)
+ {
+ KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex));
+ ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
+ cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
+ }
+
+ /* Setup a timeout if required. */
+ if(kwsysProcessGetTimeoutLeft(&timeoutTime, user?userTimeout:0,
+ &timeoutLength))
+ {
+ /* Timeout has already expired. */
+ expired = 1;
+ break;
+ }
+ if(timeoutTime.QuadPart < 0)
+ {
+ timeout = INFINITE;
+ }
+ else
+ {
+ timeout = kwsysProcessTimeToDWORD(timeoutLength);
+ }
+
+ /* Wait for a pipe's thread to signal or a process to terminate. */
+ w = WaitForMultipleObjects(cp->ProcessEventsLength, cp->ProcessEvents,
+ 0, timeout);
+ if(w == WAIT_TIMEOUT)
+ {
+ /* Timeout has expired. */
+ expired = 1;
+ done = 1;
+ }
+ else if(w == WAIT_OBJECT_0)
+ {
+ /* Save the index of the reporting thread and release the mutex.
+ The thread will block until we signal its Empty mutex. */
+ cp->CurrentIndex = cp->SharedIndex;
+ ReleaseSemaphore(cp->SharedIndexMutex, 1, 0);
+
+ /* Data are available or a pipe closed. */
+ if(cp->Pipe[cp->CurrentIndex].Closed)
+ {
+ /* The pipe closed at the write end. Close the read end and
+ inform the wakeup thread it is done with this process. */
+ kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read);
+ ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Waker.Go, 1, 0);
+ KWSYSPE_DEBUG((stderr, "wakeup %d\n", cp->CurrentIndex));
+ --cp->PipesLeft;
+ }
+ else if(data && length)
+ {
+ /* Report this data. */
+ *data = cp->Pipe[cp->CurrentIndex].DataBuffer;
+ *length = cp->Pipe[cp->CurrentIndex].DataLength;
+ switch(cp->CurrentIndex)
+ {
+ case KWSYSPE_PIPE_STDOUT:
+ pipeId = kwsysProcess_Pipe_STDOUT; break;
+ case KWSYSPE_PIPE_STDERR:
+ pipeId = kwsysProcess_Pipe_STDERR; break;
+ }
+ done = 1;
+ }
+ }
+ else
+ {
+ /* A process has terminated. */
+ kwsysProcessDestroy(cp, w-WAIT_OBJECT_0);
+ }
+ }
+
+ /* Update the user timeout. */
+ if(userTimeout)
+ {
+ kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent();
+ kwsysProcessTime difference = kwsysProcessTimeSubtract(userEndTime,
+ userStartTime);
+ double d = kwsysProcessTimeToDouble(difference);
+ *userTimeout -= d;
+ if(*userTimeout < 0)
+ {
+ *userTimeout = 0;
+ }
+ }
+
+ /* Check what happened. */
+ if(pipeId)
+ {
+ /* Data are ready on a pipe. */
+ return pipeId;
+ }
+ else if(expired)
+ {
+ /* A timeout has expired. */
+ if(user)
+ {
+ /* The user timeout has expired. It has no time left. */
+ return kwsysProcess_Pipe_Timeout;
+ }
+ else
+ {
+ /* The process timeout has expired. Kill the child now. */
+ KWSYSPE_DEBUG((stderr, "killing child because timeout expired\n"));
+ kwsysProcess_Kill(cp);
+ cp->TimeoutExpired = 1;
+ cp->Killed = 0;
+ return kwsysProcess_Pipe_None;
+ }
+ }
+ else
+ {
+ /* The children have terminated and no more data are available. */
+ return kwsysProcess_Pipe_None;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
+{
+ int i;
+ int pipe;
+
+ /* Make sure we are executing a process. */
+ if(!cp || cp->State != kwsysProcess_State_Executing)
+ {
+ return 1;
+ }
+
+ /* Wait for the process to terminate. Ignore all data. */
+ while((pipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0)
+ {
+ if(pipe == kwsysProcess_Pipe_Timeout)
+ {
+ /* The user timeout has expired. */
+ return 0;
+ }
+ }
+
+ KWSYSPE_DEBUG((stderr, "no more data\n"));
+
+ /* When the last pipe closes in WaitForData, the loop terminates
+ without releasing the pipe's thread. Release it now. */
+ if(cp->CurrentIndex < KWSYSPE_PIPE_COUNT)
+ {
+ KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex));
+ ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
+ cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
+ }
+
+ /* Wait for all pipe threads to reset. */
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ KWSYSPE_DEBUG((stderr, "waiting reader reset %d\n", i));
+ WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE);
+ KWSYSPE_DEBUG((stderr, "waiting waker reset %d\n", i));
+ WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE);
+ }
+
+ /* ---- It is now safe again to call kwsysProcessCleanup. ----- */
+ /* Close all the pipes. */
+ kwsysProcessCleanup(cp, 0);
+
+ /* Determine the outcome. */
+ if(cp->Killed)
+ {
+ /* We killed the child. */
+ cp->State = kwsysProcess_State_Killed;
+ }
+ else if(cp->TimeoutExpired)
+ {
+ /* The timeout expired. */
+ cp->State = kwsysProcess_State_Expired;
+ }
+ else
+ {
+ /* The children exited. Report the outcome of the last process. */
+ cp->ExitCode = cp->CommandExitCodes[cp->NumberOfCommands-1];
+ if((cp->ExitCode & 0xF0000000) == 0xC0000000)
+ {
+ /* Child terminated due to exceptional behavior. */
+ cp->State = kwsysProcess_State_Exception;
+ cp->ExitValue = 1;
+ kwsysProcessSetExitException(cp, cp->ExitCode);
+ }
+ else
+ {
+ /* Child exited without exception. */
+ cp->State = kwsysProcess_State_Exited;
+ cp->ExitException = kwsysProcess_Exception_None;
+ cp->ExitValue = cp->ExitCode;
+ }
+ }
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Interrupt(kwsysProcess* cp)
+{
+ int i;
+ /* Make sure we are executing a process. */
+ if(!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
+ cp->Killed)
+ {
+ KWSYSPE_DEBUG((stderr, "interrupt: child not executing\n"));
+ return;
+ }
+
+ /* Skip actually interrupting the child if it has already terminated. */
+ if(cp->Terminated)
+ {
+ KWSYSPE_DEBUG((stderr, "interrupt: child already terminated\n"));
+ return;
+ }
+
+ /* Interrupt the children. */
+ if (cp->CreateProcessGroup)
+ {
+ if(cp->ProcessInformation)
+ {
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ /* Make sure the process handle isn't closed (e.g. from disowning). */
+ if(cp->ProcessInformation[i].hProcess)
+ {
+ /* The user created a process group for this process. The group ID
+ is the process ID for the original process in the group. Note
+ that we have to use Ctrl+Break: Ctrl+C is not allowed for process
+ groups. */
+ GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
+ cp->ProcessInformation[i].dwProcessId);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* No process group was created. Kill our own process group... */
+ GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Kill(kwsysProcess* cp)
+{
+ int i;
+ /* Make sure we are executing a process. */
+ if(!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
+ cp->Killed)
+ {
+ KWSYSPE_DEBUG((stderr, "kill: child not executing\n"));
+ return;
+ }
+
+ /* Disable the reading threads. */
+ KWSYSPE_DEBUG((stderr, "kill: disabling pipe threads\n"));
+ kwsysProcessDisablePipeThreads(cp);
+
+ /* Skip actually killing the child if it has already terminated. */
+ if(cp->Terminated)
+ {
+ KWSYSPE_DEBUG((stderr, "kill: child already terminated\n"));
+ return;
+ }
+
+ /* Kill the children. */
+ cp->Killed = 1;
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId);
+ /* Remove from global list of processes and close handles. */
+ kwsysProcessesRemove(cp->ProcessInformation[i].hProcess);
+ kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
+ kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess);
+ }
+
+ /* We are killing the children and ignoring all data. Do not wait
+ for them to exit. */
+}
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ Function executed for each pipe's thread. Argument is a pointer to
+ the kwsysProcessPipeData instance for this thread.
+*/
+DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd)
+{
+ kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd;
+ kwsysProcess* cp = td->Process;
+
+ /* Wait for a process to be ready. */
+ while((WaitForSingleObject(td->Reader.Ready, INFINITE), !cp->Deleting))
+ {
+ /* Read output from the process for this thread's pipe. */
+ kwsysProcessPipeThreadReadPipe(cp, td);
+
+ /* Signal the main thread we have reset for a new process. */
+ ReleaseSemaphore(td->Reader.Reset, 1, 0);
+ }
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ Function called in each pipe's thread to handle data for one
+ execution of a subprocess.
+*/
+void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, kwsysProcessPipeData* td)
+{
+ /* Wait for space in the thread's buffer. */
+ while((KWSYSPE_DEBUG((stderr, "wait for read %d\n", td->Index)),
+ WaitForSingleObject(td->Reader.Go, INFINITE), !td->Closed))
+ {
+ KWSYSPE_DEBUG((stderr, "reading %d\n", td->Index));
+
+ /* Read data from the pipe. This may block until data are available. */
+ if(!ReadFile(td->Read, td->DataBuffer, KWSYSPE_PIPE_BUFFER_SIZE,
+ &td->DataLength, 0))
+ {
+ if(GetLastError() != ERROR_BROKEN_PIPE)
+ {
+ /* UNEXPECTED failure to read the pipe. */
+ }
+
+ /* The pipe closed. There are no more data to read. */
+ td->Closed = 1;
+ KWSYSPE_DEBUG((stderr, "read closed %d\n", td->Index));
+ }
+
+ KWSYSPE_DEBUG((stderr, "read %d\n", td->Index));
+
+ /* Wait for our turn to be handled by the main thread. */
+ WaitForSingleObject(cp->SharedIndexMutex, INFINITE);
+
+ KWSYSPE_DEBUG((stderr, "reporting read %d\n", td->Index));
+
+ /* Tell the main thread we have something to report. */
+ cp->SharedIndex = td->Index;
+ ReleaseSemaphore(cp->Full, 1, 0);
+ }
+
+ /* We were signalled to exit with our buffer empty. Reset the
+ mutex for a new process. */
+ KWSYSPE_DEBUG((stderr, "self releasing reader %d\n", td->Index));
+ ReleaseSemaphore(td->Reader.Go, 1, 0);
+}
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ Function executed for each pipe's thread. Argument is a pointer to
+ the kwsysProcessPipeData instance for this thread.
+*/
+DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd)
+{
+ kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd;
+ kwsysProcess* cp = td->Process;
+
+ /* Wait for a process to be ready. */
+ while((WaitForSingleObject(td->Waker.Ready, INFINITE), !cp->Deleting))
+ {
+ /* Wait for a possible wakeup. */
+ kwsysProcessPipeThreadWakePipe(cp, td);
+
+ /* Signal the main thread we have reset for a new process. */
+ ReleaseSemaphore(td->Waker.Reset, 1, 0);
+ }
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ Function called in each pipe's thread to handle reading thread
+ wakeup for one execution of a subprocess.
+*/
+void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp, kwsysProcessPipeData* td)
+{
+ (void)cp;
+
+ /* Wait for a possible wake command. */
+ KWSYSPE_DEBUG((stderr, "wait for wake %d\n", td->Index));
+ WaitForSingleObject(td->Waker.Go, INFINITE);
+ KWSYSPE_DEBUG((stderr, "waking %d\n", td->Index));
+
+ /* If the pipe is not closed, we need to wake up the reading thread. */
+ if(!td->Closed)
+ {
+ DWORD dummy;
+ KWSYSPE_DEBUG((stderr, "waker %d writing byte\n", td->Index));
+ WriteFile(td->Write, "", 1, &dummy, 0);
+ KWSYSPE_DEBUG((stderr, "waker %d wrote byte\n", td->Index));
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Initialize a process control structure for kwsysProcess_Execute. */
+int kwsysProcessInitialize(kwsysProcess* cp)
+{
+ /* Reset internal status flags. */
+ cp->TimeoutExpired = 0;
+ cp->Terminated = 0;
+ cp->Killed = 0;
+ cp->ExitException = kwsysProcess_Exception_None;
+ cp->ExitCode = 1;
+ cp->ExitValue = 1;
+
+ /* Reset error data. */
+ cp->ErrorMessage[0] = 0;
+ strcpy(cp->ExitExceptionString, "No exception");
+
+ /* Allocate process information for each process. */
+ cp->ProcessInformation =
+ (PROCESS_INFORMATION*)malloc(sizeof(PROCESS_INFORMATION) *
+ cp->NumberOfCommands);
+ if(!cp->ProcessInformation)
+ {
+ return 0;
+ }
+ ZeroMemory(cp->ProcessInformation,
+ sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands);
+ if(cp->CommandExitCodes)
+ {
+ free(cp->CommandExitCodes);
+ }
+ cp->CommandExitCodes = (DWORD*)malloc(sizeof(DWORD)*cp->NumberOfCommands);
+ if(!cp->CommandExitCodes)
+ {
+ return 0;
+ }
+ ZeroMemory(cp->CommandExitCodes, sizeof(DWORD)*cp->NumberOfCommands);
+
+ /* Allocate event wait array. The first event is cp->Full, the rest
+ are the process termination events. */
+ cp->ProcessEvents = (PHANDLE)malloc(sizeof(HANDLE)*(cp->NumberOfCommands+1));
+ if(!cp->ProcessEvents)
+ {
+ return 0;
+ }
+ ZeroMemory(cp->ProcessEvents, sizeof(HANDLE) * (cp->NumberOfCommands+1));
+ cp->ProcessEvents[0] = cp->Full;
+ cp->ProcessEventsLength = cp->NumberOfCommands+1;
+
+ /* Allocate space to save the real working directory of this process. */
+ if(cp->WorkingDirectory)
+ {
+ cp->RealWorkingDirectoryLength = GetCurrentDirectoryW(0, 0);
+ if(cp->RealWorkingDirectoryLength > 0)
+ {
+ cp->RealWorkingDirectory = malloc(cp->RealWorkingDirectoryLength * sizeof(wchar_t));
+ if(!cp->RealWorkingDirectory)
+ {
+ return 0;
+ }
+ }
+ }
+ {
+ int i;
+ for (i=0; i < 3; ++i)
+ {
+ cp->PipeChildStd[i] = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static DWORD kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn)
+{
+ DWORD flags;
+
+ /* Check whether the handle is valid for this process. */
+ if (in != INVALID_HANDLE_VALUE && GetHandleInformation(in, &flags))
+ {
+ /* Use the handle as-is if it is already inherited. */
+ if (flags & HANDLE_FLAG_INHERIT)
+ {
+ *out = in;
+ return ERROR_SUCCESS;
+ }
+
+ /* Create an inherited copy of this handle. */
+ if (DuplicateHandle(GetCurrentProcess(), in, GetCurrentProcess(), out,
+ 0, TRUE, DUPLICATE_SAME_ACCESS))
+ {
+ return ERROR_SUCCESS;
+ }
+ else
+ {
+ return GetLastError();
+ }
+ }
+ else
+ {
+ /* The given handle is not valid for this process. Some child
+ processes may break if they do not have a valid standard handle,
+ so open NUL to give to the child. */
+ SECURITY_ATTRIBUTES sa;
+ ZeroMemory(&sa, sizeof(sa));
+ sa.nLength = (DWORD)sizeof(sa);
+ sa.bInheritHandle = 1;
+ *out = CreateFileW(L"NUL",
+ (isStdIn ? GENERIC_READ :
+ (GENERIC_WRITE | FILE_READ_ATTRIBUTES)),
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ &sa, OPEN_EXISTING, 0, 0);
+ return (*out != INVALID_HANDLE_VALUE) ? ERROR_SUCCESS : GetLastError();
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+DWORD kwsysProcessCreate(kwsysProcess* cp, int index,
+ kwsysProcessCreateInformation* si)
+{
+ DWORD creationFlags;
+ DWORD error = ERROR_SUCCESS;
+
+ /* Check if we are currently exiting. */
+ if (!kwsysTryEnterCreateProcessSection())
+ {
+ /* The Ctrl handler is currently working on exiting our process. Rather
+ than return an error code, which could cause incorrect conclusions to be
+ reached by the caller, we simply hang. (For example, a CMake try_run
+ configure step might cause the project to configure wrong.) */
+ Sleep(INFINITE);
+ }
+
+ /* Create the child in a suspended state so we can wait until all
+ children have been created before running any one. */
+ creationFlags = CREATE_SUSPENDED;
+ if (cp->CreateProcessGroup)
+ {
+ creationFlags |= CREATE_NEW_PROCESS_GROUP;
+ }
+
+ /* Create inherited copies of the handles. */
+ (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdInput,
+ si->hStdInput, 1)) ||
+ (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdOutput,
+ si->hStdOutput, 0)) ||
+ (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdError,
+ si->hStdError, 0)) ||
+ /* Create the process. */
+ (!CreateProcessW(0, cp->Commands[index], 0, 0, TRUE, creationFlags, 0,
+ 0, &si->StartupInfo, &cp->ProcessInformation[index]) &&
+ (error = GetLastError()));
+
+ /* Close the inherited copies of the handles. */
+ if (si->StartupInfo.hStdInput != si->hStdInput)
+ {
+ kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput);
+ }
+ if (si->StartupInfo.hStdOutput != si->hStdOutput)
+ {
+ kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
+ }
+ if (si->StartupInfo.hStdError != si->hStdError)
+ {
+ kwsysProcessCleanupHandle(&si->StartupInfo.hStdError);
+ }
+
+ /* Add the process to the global list of processes. */
+ if (!error &&
+ !kwsysProcessesAdd(cp->ProcessInformation[index].hProcess,
+ cp->ProcessInformation[index].dwProcessId, cp->CreateProcessGroup))
+ {
+ /* This failed for some reason. Kill the suspended process. */
+ TerminateProcess(cp->ProcessInformation[index].hProcess, 1);
+ /* And clean up... */
+ kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess);
+ kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hThread);
+ strcpy(cp->ErrorMessage, "kwsysProcessesAdd function failed");
+ error = ERROR_NOT_ENOUGH_MEMORY; /* Most likely reason. */
+ }
+
+ /* If the console Ctrl handler is waiting for us, this will release it... */
+ kwsysLeaveCreateProcessSection();
+ return error;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcessDestroy(kwsysProcess* cp, int event)
+{
+ int i;
+ int index;
+
+ /* Find the process index for the termination event. */
+ for(index=0; index < cp->NumberOfCommands; ++index)
+ {
+ if(cp->ProcessInformation[index].hProcess == cp->ProcessEvents[event])
+ {
+ break;
+ }
+ }
+
+ /* Check the exit code of the process. */
+ GetExitCodeProcess(cp->ProcessInformation[index].hProcess,
+ &cp->CommandExitCodes[index]);
+
+ /* Remove from global list of processes. */
+ kwsysProcessesRemove(cp->ProcessInformation[index].hProcess);
+
+ /* Close the process handle for the terminated process. */
+ kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess);
+
+ /* Remove the process from the available events. */
+ cp->ProcessEventsLength -= 1;
+ for(i=event; i < cp->ProcessEventsLength; ++i)
+ {
+ cp->ProcessEvents[i] = cp->ProcessEvents[i+1];
+ }
+
+ /* Check if all processes have terminated. */
+ if(cp->ProcessEventsLength == 1)
+ {
+ cp->Terminated = 1;
+
+ /* Close our copies of the pipe write handles so the pipe threads
+ can detect end-of-data. */
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ /* TODO: If the child created its own child (our grandchild)
+ which inherited a copy of the pipe write-end then the pipe
+ may not close and we will still need the waker write pipe.
+ However we still want to be able to detect end-of-data in the
+ normal case. The reader thread will have to switch to using
+ PeekNamedPipe to read the last bit of data from the pipe
+ without blocking. This is equivalent to using a non-blocking
+ read on posix. */
+ KWSYSPE_DEBUG((stderr, "closing wakeup write %d\n", i));
+ kwsysProcessCleanupHandle(&cp->Pipe[i].Write);
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+DWORD kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
+{
+ HANDLE fout;
+ wchar_t* wname;
+ DWORD error;
+ if(!name)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /* Close the existing handle. */
+ kwsysProcessCleanupHandle(phandle);
+
+ /* Create a handle to write a file for the pipe. */
+ wname = kwsysEncoding_DupToWide(name);
+ fout = CreateFileW(wname, GENERIC_WRITE, FILE_SHARE_READ, 0,
+ CREATE_ALWAYS, 0, 0);
+ error = GetLastError();
+ free(wname);
+ if(fout == INVALID_HANDLE_VALUE)
+ {
+ return error;
+ }
+
+ /* Assign the replacement handle. */
+ *phandle = fout;
+ return ERROR_SUCCESS;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle)
+{
+ /* Close the existing handle. */
+ kwsysProcessCleanupHandle(handle);
+ /* Store the new standard handle. */
+ *handle = GetStdHandle(nStdHandle);
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle)
+{
+ /* Close the existing handle. */
+ kwsysProcessCleanupHandle(handle);
+ /* Store the new given handle. */
+ *handle = native;
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* Close the given handle if it is open. Reset its value to 0. */
+void kwsysProcessCleanupHandle(PHANDLE h)
+{
+ if(h && *h && *h != INVALID_HANDLE_VALUE &&
+ *h != GetStdHandle(STD_INPUT_HANDLE) &&
+ *h != GetStdHandle(STD_OUTPUT_HANDLE) &&
+ *h != GetStdHandle(STD_ERROR_HANDLE))
+ {
+ CloseHandle(*h);
+ *h = INVALID_HANDLE_VALUE;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* Close all handles created by kwsysProcess_Execute. */
+void kwsysProcessCleanup(kwsysProcess* cp, DWORD error)
+{
+ int i;
+ /* If this is an error case, report the error. */
+ if(error)
+ {
+ /* Construct an error message if one has not been provided already. */
+ if(cp->ErrorMessage[0] == 0)
+ {
+ /* Format the error message. */
+ wchar_t err_msg[KWSYSPE_PIPE_BUFFER_SIZE];
+ DWORD length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, 0, error,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ err_msg, KWSYSPE_PIPE_BUFFER_SIZE, 0);
+ if(length < 1)
+ {
+ /* FormatMessage failed. Use a default message. */
+ _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE,
+ "Process execution failed with error 0x%X. "
+ "FormatMessage failed with error 0x%X",
+ error, GetLastError());
+ }
+ if(!WideCharToMultiByte(CP_UTF8, 0, err_msg, -1, cp->ErrorMessage,
+ KWSYSPE_PIPE_BUFFER_SIZE, NULL, NULL))
+ {
+ /* WideCharToMultiByte failed. Use a default message. */
+ _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE,
+ "Process execution failed with error 0x%X. "
+ "WideCharToMultiByte failed with error 0x%X",
+ error, GetLastError());
+ }
+ }
+
+ /* Remove trailing period and newline, if any. */
+ kwsysProcessCleanErrorMessage(cp);
+
+ /* Set the error state. */
+ cp->State = kwsysProcess_State_Error;
+
+ /* Cleanup any processes already started in a suspended state. */
+ if(cp->ProcessInformation)
+ {
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ if(cp->ProcessInformation[i].hProcess)
+ {
+ TerminateProcess(cp->ProcessInformation[i].hProcess, 255);
+ WaitForSingleObject(cp->ProcessInformation[i].hProcess, INFINITE);
+ }
+ }
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ /* Remove from global list of processes and close handles. */
+ kwsysProcessesRemove(cp->ProcessInformation[i].hProcess);
+ kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
+ kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess);
+ }
+ }
+
+ /* Restore the working directory. */
+ if(cp->RealWorkingDirectory)
+ {
+ SetCurrentDirectoryW(cp->RealWorkingDirectory);
+ }
+ }
+
+ /* Free memory. */
+ if(cp->ProcessInformation)
+ {
+ free(cp->ProcessInformation);
+ cp->ProcessInformation = 0;
+ }
+ if(cp->ProcessEvents)
+ {
+ free(cp->ProcessEvents);
+ cp->ProcessEvents = 0;
+ }
+ if(cp->RealWorkingDirectory)
+ {
+ free(cp->RealWorkingDirectory);
+ cp->RealWorkingDirectory = 0;
+ }
+
+ /* Close each pipe. */
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ kwsysProcessCleanupHandle(&cp->Pipe[i].Write);
+ kwsysProcessCleanupHandle(&cp->Pipe[i].Read);
+ cp->Pipe[i].Closed = 0;
+ }
+ for(i=0; i < 3; ++i)
+ {
+ kwsysProcessCleanupHandle(&cp->PipeChildStd[i]);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcessCleanErrorMessage(kwsysProcess* cp)
+{
+ /* Remove trailing period and newline, if any. */
+ size_t length = strlen(cp->ErrorMessage);
+ if(cp->ErrorMessage[length-1] == '\n')
+ {
+ cp->ErrorMessage[length-1] = 0;
+ --length;
+ if(length > 0 && cp->ErrorMessage[length-1] == '\r')
+ {
+ cp->ErrorMessage[length-1] = 0;
+ --length;
+ }
+ }
+ if(length > 0 && cp->ErrorMessage[length-1] == '.')
+ {
+ cp->ErrorMessage[length-1] = 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Get the time at which either the process or user timeout will
+ expire. Returns 1 if the user timeout is first, and 0 otherwise. */
+int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
+ kwsysProcessTime* timeoutTime)
+{
+ /* The first time this is called, we need to calculate the time at
+ which the child will timeout. */
+ if(cp->Timeout && cp->TimeoutTime.QuadPart < 0)
+ {
+ kwsysProcessTime length = kwsysProcessTimeFromDouble(cp->Timeout);
+ cp->TimeoutTime = kwsysProcessTimeAdd(cp->StartTime, length);
+ }
+
+ /* Start with process timeout. */
+ *timeoutTime = cp->TimeoutTime;
+
+ /* Check if the user timeout is earlier. */
+ if(userTimeout)
+ {
+ kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
+ kwsysProcessTime userTimeoutLength = kwsysProcessTimeFromDouble(*userTimeout);
+ kwsysProcessTime userTimeoutTime = kwsysProcessTimeAdd(currentTime,
+ userTimeoutLength);
+ if(timeoutTime->QuadPart < 0 ||
+ kwsysProcessTimeLess(userTimeoutTime, *timeoutTime))
+ {
+ *timeoutTime = userTimeoutTime;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Get the length of time before the given timeout time arrives.
+ Returns 1 if the time has already arrived, and 0 otherwise. */
+int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
+ double* userTimeout,
+ kwsysProcessTime* timeoutLength)
+{
+ if(timeoutTime->QuadPart < 0)
+ {
+ /* No timeout time has been requested. */
+ return 0;
+ }
+ else
+ {
+ /* Calculate the remaining time. */
+ kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
+ *timeoutLength = kwsysProcessTimeSubtract(*timeoutTime, currentTime);
+
+ if(timeoutLength->QuadPart < 0 && userTimeout && *userTimeout <= 0)
+ {
+ /* Caller has explicitly requested a zero timeout. */
+ timeoutLength->QuadPart = 0;
+ }
+
+ if(timeoutLength->QuadPart < 0)
+ {
+ /* Timeout has already expired. */
+ return 1;
+ }
+ else
+ {
+ /* There is some time left. */
+ return 0;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+kwsysProcessTime kwsysProcessTimeGetCurrent()
+{
+ kwsysProcessTime current;
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+ current.LowPart = ft.dwLowDateTime;
+ current.HighPart = ft.dwHighDateTime;
+ return current;
+}
+
+/*--------------------------------------------------------------------------*/
+DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t)
+{
+ return (DWORD)(t.QuadPart * 0.0001);
+}
+
+/*--------------------------------------------------------------------------*/
+double kwsysProcessTimeToDouble(kwsysProcessTime t)
+{
+ return t.QuadPart * 0.0000001;
+}
+
+/*--------------------------------------------------------------------------*/
+kwsysProcessTime kwsysProcessTimeFromDouble(double d)
+{
+ kwsysProcessTime t;
+ t.QuadPart = (LONGLONG)(d*10000000);
+ return t;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2)
+{
+ return in1.QuadPart < in2.QuadPart;
+}
+
+/*--------------------------------------------------------------------------*/
+kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2)
+{
+ kwsysProcessTime out;
+ out.QuadPart = in1.QuadPart + in2.QuadPart;
+ return out;
+}
+
+/*--------------------------------------------------------------------------*/
+kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime in2)
+{
+ kwsysProcessTime out;
+ out.QuadPart = in1.QuadPart - in2.QuadPart;
+ return out;
+}
+
+/*--------------------------------------------------------------------------*/
+#define KWSYSPE_CASE(type, str) \
+ cp->ExitException = kwsysProcess_Exception_##type; \
+ strcpy(cp->ExitExceptionString, str)
+static void kwsysProcessSetExitException(kwsysProcess* cp, int code)
+{
+ switch (code)
+ {
+ case STATUS_CONTROL_C_EXIT:
+ KWSYSPE_CASE(Interrupt, "User interrupt"); break;
+
+ case STATUS_FLOAT_DENORMAL_OPERAND:
+ KWSYSPE_CASE(Numerical, "Floating-point exception (denormal operand)"); break;
+ case STATUS_FLOAT_DIVIDE_BY_ZERO:
+ KWSYSPE_CASE(Numerical, "Divide-by-zero"); break;
+ case STATUS_FLOAT_INEXACT_RESULT:
+ KWSYSPE_CASE(Numerical, "Floating-point exception (inexact result)"); break;
+ case STATUS_FLOAT_INVALID_OPERATION:
+ KWSYSPE_CASE(Numerical, "Invalid floating-point operation"); break;
+ case STATUS_FLOAT_OVERFLOW:
+ KWSYSPE_CASE(Numerical, "Floating-point overflow"); break;
+ case STATUS_FLOAT_STACK_CHECK:
+ KWSYSPE_CASE(Numerical, "Floating-point stack check failed"); break;
+ case STATUS_FLOAT_UNDERFLOW:
+ KWSYSPE_CASE(Numerical, "Floating-point underflow"); break;
+#ifdef STATUS_FLOAT_MULTIPLE_FAULTS
+ case STATUS_FLOAT_MULTIPLE_FAULTS:
+ KWSYSPE_CASE(Numerical, "Floating-point exception (multiple faults)"); break;
+#endif
+#ifdef STATUS_FLOAT_MULTIPLE_TRAPS
+ case STATUS_FLOAT_MULTIPLE_TRAPS:
+ KWSYSPE_CASE(Numerical, "Floating-point exception (multiple traps)"); break;
+#endif
+ case STATUS_INTEGER_DIVIDE_BY_ZERO:
+ KWSYSPE_CASE(Numerical, "Integer divide-by-zero"); break;
+ case STATUS_INTEGER_OVERFLOW:
+ KWSYSPE_CASE(Numerical, "Integer overflow"); break;
+
+ case STATUS_DATATYPE_MISALIGNMENT:
+ KWSYSPE_CASE(Fault, "Datatype misalignment"); break;
+ case STATUS_ACCESS_VIOLATION:
+ KWSYSPE_CASE(Fault, "Access violation"); break;
+ case STATUS_IN_PAGE_ERROR:
+ KWSYSPE_CASE(Fault, "In-page error"); break;
+ case STATUS_INVALID_HANDLE:
+ KWSYSPE_CASE(Fault, "Invalid hanlde"); break;
+ case STATUS_NONCONTINUABLE_EXCEPTION:
+ KWSYSPE_CASE(Fault, "Noncontinuable exception"); break;
+ case STATUS_INVALID_DISPOSITION:
+ KWSYSPE_CASE(Fault, "Invalid disposition"); break;
+ case STATUS_ARRAY_BOUNDS_EXCEEDED:
+ KWSYSPE_CASE(Fault, "Array bounds exceeded"); break;
+ case STATUS_STACK_OVERFLOW:
+ KWSYSPE_CASE(Fault, "Stack overflow"); break;
+
+ case STATUS_ILLEGAL_INSTRUCTION:
+ KWSYSPE_CASE(Illegal, "Illegal instruction"); break;
+ case STATUS_PRIVILEGED_INSTRUCTION:
+ KWSYSPE_CASE(Illegal, "Privileged instruction"); break;
+
+ case STATUS_NO_MEMORY:
+ default:
+ cp->ExitException = kwsysProcess_Exception_Other;
+ _snprintf(cp->ExitExceptionString, KWSYSPE_PIPE_BUFFER_SIZE, "Exit code 0x%x\n", code);
+ break;
+ }
+}
+#undef KWSYSPE_CASE
+
+typedef struct kwsysProcess_List_s kwsysProcess_List;
+static kwsysProcess_List* kwsysProcess_List_New(void);
+static void kwsysProcess_List_Delete(kwsysProcess_List* self);
+static int kwsysProcess_List_Update(kwsysProcess_List* self);
+static int kwsysProcess_List_NextProcess(kwsysProcess_List* self);
+static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self);
+static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self);
+
+/*--------------------------------------------------------------------------*/
+/* Windows NT 4 API definitions. */
+#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
+typedef LONG NTSTATUS;
+typedef LONG KPRIORITY;
+typedef struct _UNICODE_STRING UNICODE_STRING;
+struct _UNICODE_STRING
+{
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+};
+
+/* The process information structure. Declare only enough to get
+ process identifiers. The rest may be ignored because we use the
+ NextEntryDelta to move through an array of instances. */
+typedef struct _SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION;
+typedef SYSTEM_PROCESS_INFORMATION* PSYSTEM_PROCESS_INFORMATION;
+struct _SYSTEM_PROCESS_INFORMATION
+{
+ ULONG NextEntryDelta;
+ ULONG ThreadCount;
+ ULONG Reserved1[6];
+ LARGE_INTEGER CreateTime;
+ LARGE_INTEGER UserTime;
+ LARGE_INTEGER KernelTime;
+ UNICODE_STRING ProcessName;
+ KPRIORITY BasePriority;
+ ULONG ProcessId;
+ ULONG InheritedFromProcessId;
+};
+
+/*--------------------------------------------------------------------------*/
+/* Toolhelp32 API definitions. */
+#define TH32CS_SNAPPROCESS 0x00000002
+#if defined(_WIN64)
+typedef unsigned __int64 ProcessULONG_PTR;
+#else
+typedef unsigned long ProcessULONG_PTR;
+#endif
+typedef struct tagPROCESSENTRY32 PROCESSENTRY32;
+typedef PROCESSENTRY32* LPPROCESSENTRY32;
+struct tagPROCESSENTRY32
+{
+ DWORD dwSize;
+ DWORD cntUsage;
+ DWORD th32ProcessID;
+ ProcessULONG_PTR th32DefaultHeapID;
+ DWORD th32ModuleID;
+ DWORD cntThreads;
+ DWORD th32ParentProcessID;
+ LONG pcPriClassBase;
+ DWORD dwFlags;
+ char szExeFile[MAX_PATH];
+};
+
+/*--------------------------------------------------------------------------*/
+/* Windows API function types. */
+typedef HANDLE (WINAPI* CreateToolhelp32SnapshotType)(DWORD, DWORD);
+typedef BOOL (WINAPI* Process32FirstType)(HANDLE, LPPROCESSENTRY32);
+typedef BOOL (WINAPI* Process32NextType)(HANDLE, LPPROCESSENTRY32);
+typedef NTSTATUS (WINAPI* ZwQuerySystemInformationType)(ULONG, PVOID,
+ ULONG, PULONG);
+
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__New_NT4(kwsysProcess_List* self);
+static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self);
+static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self);
+static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self);
+static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self);
+static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self);
+static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self);
+static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self);
+static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self);
+static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self);
+static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self);
+static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self);
+
+struct kwsysProcess_List_s
+{
+ /* Implementation switches at runtime based on version of Windows. */
+ int NT4;
+
+ /* Implementation functions and data for NT 4. */
+ ZwQuerySystemInformationType P_ZwQuerySystemInformation;
+ char* Buffer;
+ int BufferSize;
+ PSYSTEM_PROCESS_INFORMATION CurrentInfo;
+
+ /* Implementation functions and data for other Windows versions. */
+ CreateToolhelp32SnapshotType P_CreateToolhelp32Snapshot;
+ Process32FirstType P_Process32First;
+ Process32NextType P_Process32Next;
+ HANDLE Snapshot;
+ PROCESSENTRY32 CurrentEntry;
+};
+
+/*--------------------------------------------------------------------------*/
+static kwsysProcess_List* kwsysProcess_List_New(void)
+{
+ OSVERSIONINFO osv;
+ kwsysProcess_List* self;
+
+ /* Allocate and initialize the list object. */
+ if(!(self = (kwsysProcess_List*)malloc(sizeof(kwsysProcess_List))))
+ {
+ return 0;
+ }
+ memset(self, 0, sizeof(*self));
+
+ /* Select an implementation. */
+ ZeroMemory(&osv, sizeof(osv));
+ osv.dwOSVersionInfoSize = sizeof(osv);
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+# pragma warning (push)
+# ifdef __INTEL_COMPILER
+# pragma warning (disable:1478)
+# else
+# pragma warning (disable:4996)
+# endif
+#endif
+ GetVersionEx(&osv);
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+# pragma warning (pop)
+#endif
+ self->NT4 = (osv.dwPlatformId == VER_PLATFORM_WIN32_NT &&
+ osv.dwMajorVersion < 5)? 1:0;
+
+ /* Initialize the selected implementation. */
+ if(!(self->NT4?
+ kwsysProcess_List__New_NT4(self) :
+ kwsysProcess_List__New_Snapshot(self)))
+ {
+ kwsysProcess_List_Delete(self);
+ return 0;
+ }
+
+ /* Update to the current set of processes. */
+ if(!kwsysProcess_List_Update(self))
+ {
+ kwsysProcess_List_Delete(self);
+ return 0;
+ }
+ return self;
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcess_List_Delete(kwsysProcess_List* self)
+{
+ if(self)
+ {
+ if(self->NT4)
+ {
+ kwsysProcess_List__Delete_NT4(self);
+ }
+ else
+ {
+ kwsysProcess_List__Delete_Snapshot(self);
+ }
+ free(self);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List_Update(kwsysProcess_List* self)
+{
+ return self? (self->NT4?
+ kwsysProcess_List__Update_NT4(self) :
+ kwsysProcess_List__Update_Snapshot(self)) : 0;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self)
+{
+ return self? (self->NT4?
+ kwsysProcess_List__GetProcessId_NT4(self) :
+ kwsysProcess_List__GetProcessId_Snapshot(self)) : -1;
+
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self)
+{
+ return self? (self->NT4?
+ kwsysProcess_List__GetParentId_NT4(self) :
+ kwsysProcess_List__GetParentId_Snapshot(self)) : -1;
+
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List_NextProcess(kwsysProcess_List* self)
+{
+ return (self? (self->NT4?
+ kwsysProcess_List__Next_NT4(self) :
+ kwsysProcess_List__Next_Snapshot(self)) : 0);
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__New_NT4(kwsysProcess_List* self)
+{
+ /* Get a handle to the NT runtime module that should already be
+ loaded in this program. This does not actually increment the
+ reference count to the module so we do not need to close the
+ handle. */
+ HMODULE hNT = GetModuleHandleW(L"ntdll.dll");
+ if(hNT)
+ {
+ /* Get pointers to the needed API functions. */
+ self->P_ZwQuerySystemInformation =
+ ((ZwQuerySystemInformationType)
+ GetProcAddress(hNT, "ZwQuerySystemInformation"));
+ }
+ if(!self->P_ZwQuerySystemInformation)
+ {
+ return 0;
+ }
+
+ /* Allocate an initial process information buffer. */
+ self->BufferSize = 32768;
+ self->Buffer = (char*)malloc(self->BufferSize);
+ return self->Buffer? 1:0;
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self)
+{
+ /* Free the process information buffer. */
+ if(self->Buffer)
+ {
+ free(self->Buffer);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self)
+{
+ self->CurrentInfo = 0;
+ for(;;)
+ {
+ /* Query number 5 is for system process list. */
+ NTSTATUS status =
+ self->P_ZwQuerySystemInformation(5, self->Buffer, self->BufferSize, 0);
+ if(status == STATUS_INFO_LENGTH_MISMATCH)
+ {
+ /* The query requires a bigger buffer. */
+ int newBufferSize = self->BufferSize * 2;
+ char* newBuffer = (char*)malloc(newBufferSize);
+ if(newBuffer)
+ {
+ free(self->Buffer);
+ self->Buffer = newBuffer;
+ self->BufferSize = newBufferSize;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else if(status >= 0)
+ {
+ /* The query succeeded. Initialize traversal of the process list. */
+ self->CurrentInfo = (PSYSTEM_PROCESS_INFORMATION)self->Buffer;
+ return 1;
+ }
+ else
+ {
+ /* The query failed. */
+ return 0;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self)
+{
+ if(self->CurrentInfo)
+ {
+ if(self->CurrentInfo->NextEntryDelta > 0)
+ {
+ self->CurrentInfo = ((PSYSTEM_PROCESS_INFORMATION)
+ ((char*)self->CurrentInfo +
+ self->CurrentInfo->NextEntryDelta));
+ return 1;
+ }
+ self->CurrentInfo = 0;
+ }
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self)
+{
+ return self->CurrentInfo? self->CurrentInfo->ProcessId : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self)
+{
+ return self->CurrentInfo? self->CurrentInfo->InheritedFromProcessId : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self)
+{
+ /* Get a handle to the Windows runtime module that should already be
+ loaded in this program. This does not actually increment the
+ reference count to the module so we do not need to close the
+ handle. */
+ HMODULE hKernel = GetModuleHandleW(L"kernel32.dll");
+ if(hKernel)
+ {
+ self->P_CreateToolhelp32Snapshot =
+ ((CreateToolhelp32SnapshotType)
+ GetProcAddress(hKernel, "CreateToolhelp32Snapshot"));
+ self->P_Process32First =
+ ((Process32FirstType)
+ GetProcAddress(hKernel, "Process32First"));
+ self->P_Process32Next =
+ ((Process32NextType)
+ GetProcAddress(hKernel, "Process32Next"));
+ }
+ return (self->P_CreateToolhelp32Snapshot &&
+ self->P_Process32First &&
+ self->P_Process32Next)? 1:0;
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self)
+{
+ if(self->Snapshot)
+ {
+ CloseHandle(self->Snapshot);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self)
+{
+ if(self->Snapshot)
+ {
+ CloseHandle(self->Snapshot);
+ }
+ if(!(self->Snapshot =
+ self->P_CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)))
+ {
+ return 0;
+ }
+ ZeroMemory(&self->CurrentEntry, sizeof(self->CurrentEntry));
+ self->CurrentEntry.dwSize = sizeof(self->CurrentEntry);
+ if(!self->P_Process32First(self->Snapshot, &self->CurrentEntry))
+ {
+ CloseHandle(self->Snapshot);
+ self->Snapshot = 0;
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self)
+{
+ if(self->Snapshot)
+ {
+ if(self->P_Process32Next(self->Snapshot, &self->CurrentEntry))
+ {
+ return 1;
+ }
+ CloseHandle(self->Snapshot);
+ self->Snapshot = 0;
+ }
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self)
+{
+ return self->Snapshot? self->CurrentEntry.th32ProcessID : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self)
+{
+ return self->Snapshot? self->CurrentEntry.th32ParentProcessID : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessKill(DWORD pid)
+{
+ HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, pid);
+ if(h)
+ {
+ TerminateProcess(h, 255);
+ WaitForSingleObject(h, INFINITE);
+ CloseHandle(h);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessKillTree(int pid)
+{
+ kwsysProcess_List* plist = kwsysProcess_List_New();
+ kwsysProcessKill(pid);
+ if(plist)
+ {
+ do
+ {
+ if(kwsysProcess_List_GetCurrentParentId(plist) == pid)
+ {
+ int ppid = kwsysProcess_List_GetCurrentProcessId(plist);
+ kwsysProcessKillTree(ppid);
+ }
+ } while(kwsysProcess_List_NextProcess(plist));
+ kwsysProcess_List_Delete(plist);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessDisablePipeThreads(kwsysProcess* cp)
+{
+ int i;
+
+ /* If data were just reported data, release the pipe's thread. */
+ if(cp->CurrentIndex < KWSYSPE_PIPE_COUNT)
+ {
+ KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex));
+ ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
+ cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
+ }
+
+ /* Wakeup all reading threads that are not on closed pipes. */
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ /* The wakeup threads will write one byte to the pipe write ends.
+ If there are no data in the pipe then this is enough to wakeup
+ the reading threads. If there are already data in the pipe
+ this may block. We cannot use PeekNamedPipe to check whether
+ there are data because an outside process might still be
+ writing data if we are disowning it. Also, PeekNamedPipe will
+ block if checking a pipe on which the reading thread is
+ currently calling ReadPipe. Therefore we need a separate
+ thread to call WriteFile. If it blocks, that is okay because
+ it will unblock when we close the read end and break the pipe
+ below. */
+ if(cp->Pipe[i].Read)
+ {
+ KWSYSPE_DEBUG((stderr, "releasing waker %d\n", i));
+ ReleaseSemaphore(cp->Pipe[i].Waker.Go, 1, 0);
+ }
+ }
+
+ /* Tell pipe threads to reset until we run another process. */
+ while(cp->PipesLeft > 0)
+ {
+ /* The waking threads will cause all reading threads to report.
+ Wait for the next one and save its index. */
+ KWSYSPE_DEBUG((stderr, "waiting for reader\n"));
+ WaitForSingleObject(cp->Full, INFINITE);
+ cp->CurrentIndex = cp->SharedIndex;
+ ReleaseSemaphore(cp->SharedIndexMutex, 1, 0);
+ KWSYSPE_DEBUG((stderr, "got reader %d\n", cp->CurrentIndex));
+
+ /* We are done reading this pipe. Close its read handle. */
+ cp->Pipe[cp->CurrentIndex].Closed = 1;
+ kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read);
+ --cp->PipesLeft;
+
+ /* Tell the reading thread we are done with the data. It will
+ reset immediately because the pipe is closed. */
+ ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Global set of executing processes for use by the Ctrl handler.
+ This global instance will be zero-initialized by the compiler.
+
+ Note that the console Ctrl handler runs on a background thread and so
+ everything it does must be thread safe. Here, we track the hProcess
+ HANDLEs directly instead of kwsysProcess instances, so that we don't have
+ to make kwsysProcess thread safe. */
+typedef struct kwsysProcessInstance_s
+{
+ HANDLE hProcess;
+ DWORD dwProcessId;
+ int NewProcessGroup; /* Whether the process was created in a new group. */
+} kwsysProcessInstance;
+
+typedef struct kwsysProcessInstances_s
+{
+ /* Whether we have initialized key fields below, like critical sections. */
+ int Initialized;
+
+ /* Ctrl handler runs on a different thread, so we must sync access. */
+ CRITICAL_SECTION Lock;
+
+ int Exiting;
+ size_t Count;
+ size_t Size;
+ kwsysProcessInstance* Processes;
+} kwsysProcessInstances;
+static kwsysProcessInstances kwsysProcesses;
+
+/*--------------------------------------------------------------------------*/
+/* Initialize critial section and set up console Ctrl handler. You MUST call
+ this before using any other kwsysProcesses* functions below. */
+static int kwsysProcessesInitialize(void)
+{
+ /* Initialize everything if not done already. */
+ if(!kwsysProcesses.Initialized)
+ {
+ InitializeCriticalSection(&kwsysProcesses.Lock);
+
+ /* Set up console ctrl handler. */
+ if(!SetConsoleCtrlHandler(kwsysCtrlHandler, TRUE))
+ {
+ return 0;
+ }
+
+ kwsysProcesses.Initialized = 1;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* The Ctrl handler waits on the global list of processes. To prevent an
+ orphaned process, do not create a new process if the Ctrl handler is
+ already running. Do so by using this function to check if it is ok to
+ create a process. */
+static int kwsysTryEnterCreateProcessSection(void)
+{
+ /* Enter main critical section; this means creating a process and the Ctrl
+ handler are mutually exclusive. */
+ EnterCriticalSection(&kwsysProcesses.Lock);
+ /* Indicate to the caller if they can create a process. */
+ if(kwsysProcesses.Exiting)
+ {
+ LeaveCriticalSection(&kwsysProcesses.Lock);
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Matching function on successful kwsysTryEnterCreateProcessSection return.
+ Make sure you called kwsysProcessesAdd if applicable before calling this.*/
+static void kwsysLeaveCreateProcessSection(void)
+{
+ LeaveCriticalSection(&kwsysProcesses.Lock);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Add new process to global process list. The Ctrl handler will wait for
+ the process to exit before it returns. Do not close the process handle
+ until after calling kwsysProcessesRemove. The newProcessGroup parameter
+ must be set if the process was created with CREATE_NEW_PROCESS_GROUP. */
+static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessid,
+ int newProcessGroup)
+{
+ if(!kwsysProcessesInitialize() || !hProcess ||
+ hProcess == INVALID_HANDLE_VALUE)
+ {
+ return 0;
+ }
+
+ /* Enter the critical section. */
+ EnterCriticalSection(&kwsysProcesses.Lock);
+
+ /* Make sure there is enough space for the new process handle. */
+ if(kwsysProcesses.Count == kwsysProcesses.Size)
+ {
+ size_t newSize;
+ kwsysProcessInstance *newArray;
+ /* Start with enough space for a small number of process handles
+ and double the size each time more is needed. */
+ newSize = kwsysProcesses.Size? kwsysProcesses.Size*2 : 4;
+
+ /* Try allocating the new block of memory. */
+ if(newArray = (kwsysProcessInstance*)malloc(
+ newSize*sizeof(kwsysProcessInstance)))
+ {
+ /* Copy the old process handles to the new memory. */
+ if(kwsysProcesses.Count > 0)
+ {
+ memcpy(newArray, kwsysProcesses.Processes,
+ kwsysProcesses.Count * sizeof(kwsysProcessInstance));
+ }
+ }
+ else
+ {
+ /* Failed to allocate memory for the new process handle set. */
+ LeaveCriticalSection(&kwsysProcesses.Lock);
+ return 0;
+ }
+
+ /* Free original array. */
+ free(kwsysProcesses.Processes);
+
+ /* Update original structure with new allocation. */
+ kwsysProcesses.Size = newSize;
+ kwsysProcesses.Processes = newArray;
+ }
+
+ /* Append the new process information to the set. */
+ kwsysProcesses.Processes[kwsysProcesses.Count].hProcess = hProcess;
+ kwsysProcesses.Processes[kwsysProcesses.Count].dwProcessId = dwProcessid;
+ kwsysProcesses.Processes[kwsysProcesses.Count++].NewProcessGroup =
+ newProcessGroup;
+
+ /* Leave critical section and return success. */
+ LeaveCriticalSection(&kwsysProcesses.Lock);
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Removes process to global process list. */
+static void kwsysProcessesRemove(HANDLE hProcess)
+{
+ size_t i;
+
+ if (!hProcess || hProcess == INVALID_HANDLE_VALUE)
+ {
+ return;
+ }
+
+ EnterCriticalSection(&kwsysProcesses.Lock);
+
+ /* Find the given process in the set. */
+ for(i=0; i < kwsysProcesses.Count; ++i)
+ {
+ if(kwsysProcesses.Processes[i].hProcess == hProcess)
+ {
+ break;
+ }
+ }
+ if(i < kwsysProcesses.Count)
+ {
+ /* Found it! Remove the process from the set. */
+ --kwsysProcesses.Count;
+ for(; i < kwsysProcesses.Count; ++i)
+ {
+ kwsysProcesses.Processes[i] = kwsysProcesses.Processes[i+1];
+ }
+
+ /* If this was the last process, free the array. */
+ if(kwsysProcesses.Count == 0)
+ {
+ kwsysProcesses.Size = 0;
+ free(kwsysProcesses.Processes);
+ kwsysProcesses.Processes = 0;
+ }
+ }
+
+ LeaveCriticalSection(&kwsysProcesses.Lock);
+}
+
+/*--------------------------------------------------------------------------*/
+static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType)
+{
+ size_t i;
+ (void)dwCtrlType;
+ /* Enter critical section. */
+ EnterCriticalSection(&kwsysProcesses.Lock);
+
+ /* Set flag indicating that we are exiting. */
+ kwsysProcesses.Exiting = 1;
+
+ /* If some of our processes were created in a new process group, we must
+ manually interrupt them. They won't otherwise receive a Ctrl+C/Break. */
+ for(i=0; i < kwsysProcesses.Count; ++i)
+ {
+ if(kwsysProcesses.Processes[i].NewProcessGroup)
+ {
+ DWORD groupId = kwsysProcesses.Processes[i].dwProcessId;
+ if(groupId)
+ {
+ GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, groupId);
+ }
+ }
+ }
+
+ /* Wait for each child process to exit. This is the key step that prevents
+ us from leaving several orphaned children processes running in the
+ background when the user presses Ctrl+C. */
+ for(i=0; i < kwsysProcesses.Count; ++i)
+ {
+ WaitForSingleObject(kwsysProcesses.Processes[i].hProcess, INFINITE);
+ }
+
+ /* Leave critical section. */
+ LeaveCriticalSection(&kwsysProcesses.Lock);
+
+ /* Continue on to default Ctrl handler (which calls ExitProcess). */
+ return FALSE;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_ResetStartTime(kwsysProcess* cp)
+{
+ if(!cp)
+ {
+ return;
+ }
+ /* Reset start time. */
+ cp->StartTime = kwsysProcessTimeGetCurrent();
+}
diff --git a/Source/kwsys/README.txt b/Source/kwsys/README.txt
new file mode 100644
index 0000000..b8191f7
--- /dev/null
+++ b/Source/kwsys/README.txt
@@ -0,0 +1,12 @@
+KWSys provides a platform-independent API to many common system
+features that are implemented differently on every platform. This
+library is intended to be shared among many projects, so it has a
+configurable namespace. Each project should configure KWSys to use a
+namespace unique to itself. See comments in CMakeLists.txt for
+details.
+
+You are probably reading this file in the source tree of a surrounding
+project. In that case, see "../README.kwsys" for details of using
+KWSys in your project.
+
+See CONTRIBUTING.rst for instructions to contribute KWSys changes.
diff --git a/Source/kwsys/RegularExpression.cxx b/Source/kwsys/RegularExpression.cxx
new file mode 100644
index 0000000..22593b4
--- /dev/null
+++ b/Source/kwsys/RegularExpression.cxx
@@ -0,0 +1,1244 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+//
+// Copyright (C) 1991 Texas Instruments Incorporated.
+//
+// Permission is granted to any individual or institution to use, copy, modify
+// and distribute this software, provided that this complete copyright and
+// permission notice is maintained, intact, in all copies and supporting
+// documentation.
+//
+// Texas Instruments Incorporated provides this software "as is" without
+// express or implied warranty.
+//
+//
+// Created: MNF 06/13/89 Initial Design and Implementation
+// Updated: LGO 08/09/89 Inherit from Generic
+// Updated: MBN 09/07/89 Added conditional exception handling
+// Updated: MBN 12/15/89 Sprinkled "const" qualifiers all over the place!
+// Updated: DLS 03/22/91 New lite version
+//
+
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(RegularExpression.hxx)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "RegularExpression.hxx.in"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+namespace KWSYS_NAMESPACE
+{
+
+// RegularExpression -- Copies the given regular expression.
+RegularExpression::RegularExpression (const RegularExpression& rxp) {
+ if ( !rxp.program )
+ {
+ this->program = 0;
+ return;
+ }
+ int ind;
+ this->progsize = rxp.progsize; // Copy regular expression size
+ this->program = new char[this->progsize]; // Allocate storage
+ for(ind=this->progsize; ind-- != 0;) // Copy regular expresion
+ this->program[ind] = rxp.program[ind];
+ this->startp[0] = rxp.startp[0]; // Copy pointers into last
+ this->endp[0] = rxp.endp[0]; // Successful "find" operation
+ this->regmust = rxp.regmust; // Copy field
+ if (rxp.regmust != 0) {
+ char* dum = rxp.program;
+ ind = 0;
+ while (dum != rxp.regmust) {
+ ++dum;
+ ++ind;
+ }
+ this->regmust = this->program + ind;
+ }
+ this->regstart = rxp.regstart; // Copy starting index
+ this->reganch = rxp.reganch; // Copy remaining private data
+ this->regmlen = rxp.regmlen; // Copy remaining private data
+}
+
+// operator= -- Copies the given regular expression.
+RegularExpression& RegularExpression::operator= (const RegularExpression& rxp)
+{
+ if(this == &rxp)
+ {
+ return *this;
+ }
+ if ( !rxp.program )
+ {
+ this->program = 0;
+ return *this;
+ }
+ int ind;
+ this->progsize = rxp.progsize; // Copy regular expression size
+ delete [] this->program;
+ this->program = new char[this->progsize]; // Allocate storage
+ for(ind=this->progsize; ind-- != 0;) // Copy regular expresion
+ this->program[ind] = rxp.program[ind];
+ this->startp[0] = rxp.startp[0]; // Copy pointers into last
+ this->endp[0] = rxp.endp[0]; // Successful "find" operation
+ this->regmust = rxp.regmust; // Copy field
+ if (rxp.regmust != 0) {
+ char* dum = rxp.program;
+ ind = 0;
+ while (dum != rxp.regmust) {
+ ++dum;
+ ++ind;
+ }
+ this->regmust = this->program + ind;
+ }
+ this->regstart = rxp.regstart; // Copy starting index
+ this->reganch = rxp.reganch; // Copy remaining private data
+ this->regmlen = rxp.regmlen; // Copy remaining private data
+
+ return *this;
+}
+
+// operator== -- Returns true if two regular expressions have the same
+// compiled program for pattern matching.
+bool RegularExpression::operator== (const RegularExpression& rxp) const {
+ if (this != &rxp) { // Same address?
+ int ind = this->progsize; // Get regular expression size
+ if (ind != rxp.progsize) // If different size regexp
+ return false; // Return failure
+ while(ind-- != 0) // Else while still characters
+ if(this->program[ind] != rxp.program[ind]) // If regexp are different
+ return false; // Return failure
+ }
+ return true; // Else same, return success
+}
+
+
+// deep_equal -- Returns true if have the same compiled regular expressions
+// and the same start and end pointers.
+
+bool RegularExpression::deep_equal (const RegularExpression& rxp) const {
+ int ind = this->progsize; // Get regular expression size
+ if (ind != rxp.progsize) // If different size regexp
+ return false; // Return failure
+ while(ind-- != 0) // Else while still characters
+ if(this->program[ind] != rxp.program[ind]) // If regexp are different
+ return false; // Return failure
+ return (this->startp[0] == rxp.startp[0] && // Else if same start/end ptrs,
+ this->endp[0] == rxp.endp[0]); // Return true
+}
+
+// The remaining code in this file is derived from the regular expression code
+// whose copyright statement appears below. It has been changed to work
+// with the class concepts of C++ and COOL.
+
+/*
+ * compile and find
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions. Serious changes in
+ * regular-expression syntax might require a total rethink.
+ */
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases. They are:
+ *
+ * regstart char that must begin a match; '\0' if none obvious
+ * reganch is the match anchored (at beginning-of-line only)?
+ * regmust string (pointer into program) that match must include, or NULL
+ * regmlen length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot. Regmust permits fast rejection
+ * of lines that cannot possibly match. The regmust tests are costly enough
+ * that compile() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup). Regmlen is
+ * supplied because the test in find() needs it and compile() is computing
+ * it anyway.
+ */
+
+/*
+ * Structure for regexp "program". This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology). Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand. "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives. (Here we
+ * have one of the subtle syntax dependencies: an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.) The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM. In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure: the tail of the branch connects
+ * to the thing following the set of BRANCHes.) The opcodes are:
+ */
+
+// definition number opnd? meaning
+#define END 0 // no End of program.
+#define BOL 1 // no Match "" at beginning of line.
+#define EOL 2 // no Match "" at end of line.
+#define ANY 3 // no Match any one character.
+#define ANYOF 4 // str Match any character in this string.
+#define ANYBUT 5 // str Match any character not in this
+ // string.
+#define BRANCH 6 // node Match this alternative, or the
+ // next...
+#define BACK 7 // no Match "", "next" ptr points backward.
+#define EXACTLY 8 // str Match this string.
+#define NOTHING 9 // no Match empty string.
+#define STAR 10 // node Match this (simple) thing 0 or more
+ // times.
+#define PLUS 11 // node Match this (simple) thing 1 or more
+ // times.
+#define OPEN 20 // no Mark this point in input as start of
+ // #n.
+// OPEN+1 is number 1, etc.
+#define CLOSE 30 // no Analogous to OPEN.
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH The set of branches constituting a single choice are hooked
+ * together with their "next" pointers, since precedence prevents
+ * anything being concatenated to any individual branch. The
+ * "next" pointer of the last BRANCH in a choice points to the
+ * thing following the whole choice. This is also where the
+ * final "next" pointer of each individual branch points; each
+ * branch starts with the operand node of a BRANCH node.
+ *
+ * BACK Normal "next" pointers all implicitly point forward; BACK
+ * exists to make loop structures possible.
+ *
+ * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
+ * BRANCH structures using BACK. Simple cases (one character
+ * per match) are implemented with STAR and PLUS for speed
+ * and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE ...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first. The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node. (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+
+#define OP(p) (*(p))
+#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+#define OPERAND(p) ((p) + 3)
+
+const unsigned char MAGIC = 0234;
+/*
+ * Utility definitions.
+ */
+
+#define UCHARAT(p) (reinterpret_cast<const unsigned char*>(p))[0]
+
+
+#define FAIL(m) { regerror(m); return(0); }
+#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
+#define META "^$.[()|?+*\\"
+
+
+/*
+ * Flags to be passed up and down.
+ */
+#define HASWIDTH 01 // Known never to match null string.
+#define SIMPLE 02 // Simple enough to be STAR/PLUS operand.
+#define SPSTART 04 // Starts with * or +.
+#define WORST 0 // Worst case.
+
+
+
+/////////////////////////////////////////////////////////////////////////
+//
+// COMPILE AND ASSOCIATED FUNCTIONS
+//
+/////////////////////////////////////////////////////////////////////////
+
+
+/*
+ * Global work variables for compile().
+ */
+static const char* regparse; // Input-scan pointer.
+static int regnpar; // () count.
+static char regdummy;
+static char* regcode; // Code-emit pointer; &regdummy = don't.
+static long regsize; // Code size.
+
+/*
+ * Forward declarations for compile()'s friends.
+ */
+// #ifndef static
+// #define static static
+// #endif
+static char* reg (int, int*);
+static char* regbranch (int*);
+static char* regpiece (int*);
+static char* regatom (int*);
+static char* regnode (char);
+static const char* regnext (const char*);
+static char* regnext (char*);
+static void regc (char);
+static void reginsert (char, char*);
+static void regtail (char*, const char*);
+static void regoptail (char*, const char*);
+
+#ifdef STRCSPN
+static int strcspn ();
+#endif
+
+
+
+/*
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code. So we cheat: we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it. (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+
+
+// compile -- compile a regular expression into internal code
+// for later pattern matching.
+
+bool RegularExpression::compile (const char* exp) {
+ const char* scan;
+ const char* longest;
+ size_t len;
+ int flags;
+
+ if (exp == 0) {
+ //RAISE Error, SYM(RegularExpression), SYM(No_Expr),
+ printf ("RegularExpression::compile(): No expression supplied.\n");
+ return false;
+ }
+
+ // First pass: determine size, legality.
+ regparse = exp;
+ regnpar = 1;
+ regsize = 0L;
+ regcode = &regdummy;
+ regc(static_cast<char>(MAGIC));
+ if(!reg(0, &flags))
+ {
+ printf ("RegularExpression::compile(): Error in compile.\n");
+ return false;
+ }
+ this->startp[0] = this->endp[0] = this->searchstring = 0;
+
+ // Small enough for pointer-storage convention?
+ if (regsize >= 32767L) { // Probably could be 65535L.
+ //RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big),
+ printf ("RegularExpression::compile(): Expression too big.\n");
+ return false;
+ }
+
+ // Allocate space.
+//#ifndef _WIN32
+ if (this->program != 0) delete [] this->program;
+//#endif
+ this->program = new char[regsize];
+ this->progsize = static_cast<int>(regsize);
+
+ if (this->program == 0) {
+ //RAISE Error, SYM(RegularExpression), SYM(Out_Of_Memory),
+ printf ("RegularExpression::compile(): Out of memory.\n");
+ return false;
+ }
+
+ // Second pass: emit code.
+ regparse = exp;
+ regnpar = 1;
+ regcode = this->program;
+ regc(static_cast<char>(MAGIC));
+ reg(0, &flags);
+
+ // Dig out information for optimizations.
+ this->regstart = '\0'; // Worst-case defaults.
+ this->reganch = 0;
+ this->regmust = 0;
+ this->regmlen = 0;
+ scan = this->program + 1; // First BRANCH.
+ if (OP(regnext(scan)) == END) { // Only one top-level choice.
+ scan = OPERAND(scan);
+
+ // Starting-point info.
+ if (OP(scan) == EXACTLY)
+ this->regstart = *OPERAND(scan);
+ else if (OP(scan) == BOL)
+ this->reganch++;
+
+ //
+ // If there's something expensive in the r.e., find the longest
+ // literal string that must appear and make it the regmust. Resolve
+ // ties in favor of later strings, since the regstart check works
+ // with the beginning of the r.e. and avoiding duplication
+ // strengthens checking. Not a strong reason, but sufficient in the
+ // absence of others.
+ //
+ if (flags & SPSTART) {
+ longest = 0;
+ len = 0;
+ for (; scan != 0; scan = regnext(scan))
+ if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
+ longest = OPERAND(scan);
+ len = strlen(OPERAND(scan));
+ }
+ this->regmust = longest;
+ this->regmlen = len;
+ }
+ }
+ return true;
+}
+
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char* reg (int paren, int *flagp) {
+ char* ret;
+ char* br;
+ char* ender;
+ int parno =0;
+ int flags;
+
+ *flagp = HASWIDTH; // Tentatively.
+
+ // Make an OPEN node, if parenthesized.
+ if (paren) {
+ if (regnpar >= RegularExpression::NSUBEXP) {
+ //RAISE Error, SYM(RegularExpression), SYM(Too_Many_Parens),
+ printf ("RegularExpression::compile(): Too many parentheses.\n");
+ return 0;
+ }
+ parno = regnpar;
+ regnpar++;
+ ret = regnode(static_cast<char>(OPEN + parno));
+ }
+ else
+ ret = 0;
+
+ // Pick up the branches, linking them together.
+ br = regbranch(&flags);
+ if (br == 0)
+ return (0);
+ if (ret != 0)
+ regtail(ret, br); // OPEN -> first.
+ else
+ ret = br;
+ if (!(flags & HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags & SPSTART;
+ while (*regparse == '|') {
+ regparse++;
+ br = regbranch(&flags);
+ if (br == 0)
+ return (0);
+ regtail(ret, br); // BRANCH -> BRANCH.
+ if (!(flags & HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags & SPSTART;
+ }
+
+ // Make a closing node, and hook it on the end.
+ ender = regnode(static_cast<char>((paren) ? CLOSE + parno : END));
+ regtail(ret, ender);
+
+ // Hook the tails of the branches to the closing node.
+ for (br = ret; br != 0; br = regnext(br))
+ regoptail(br, ender);
+
+ // Check for proper termination.
+ if (paren && *regparse++ != ')') {
+ //RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens),
+ printf ("RegularExpression::compile(): Unmatched parentheses.\n");
+ return 0;
+ }
+ else if (!paren && *regparse != '\0') {
+ if (*regparse == ')') {
+ //RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens),
+ printf ("RegularExpression::compile(): Unmatched parentheses.\n");
+ return 0;
+ }
+ else {
+ //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+ printf ("RegularExpression::compile(): Internal error.\n");
+ return 0;
+ }
+ // NOTREACHED
+ }
+ return (ret);
+}
+
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char* regbranch (int *flagp) {
+ char* ret;
+ char* chain;
+ char* latest;
+ int flags;
+
+ *flagp = WORST; // Tentatively.
+
+ ret = regnode(BRANCH);
+ chain = 0;
+ while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
+ latest = regpiece(&flags);
+ if (latest == 0)
+ return (0);
+ *flagp |= flags & HASWIDTH;
+ if (chain == 0) // First piece.
+ *flagp |= flags & SPSTART;
+ else
+ regtail(chain, latest);
+ chain = latest;
+ }
+ if (chain == 0) // Loop ran zero times.
+ regnode(NOTHING);
+
+ return (ret);
+}
+
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized: they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static char* regpiece (int *flagp) {
+ char* ret;
+ char op;
+ char* next;
+ int flags;
+
+ ret = regatom(&flags);
+ if (ret == 0)
+ return (0);
+
+ op = *regparse;
+ if (!ISMULT(op)) {
+ *flagp = flags;
+ return (ret);
+ }
+
+ if (!(flags & HASWIDTH) && op != '?') {
+ //RAISE Error, SYM(RegularExpression), SYM(Empty_Operand),
+ printf ("RegularExpression::compile() : *+ operand could be empty.\n");
+ return 0;
+ }
+ *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH);
+
+ if (op == '*' && (flags & SIMPLE))
+ reginsert(STAR, ret);
+ else if (op == '*') {
+ // Emit x* as (x&|), where & means "self".
+ reginsert(BRANCH, ret); // Either x
+ regoptail(ret, regnode(BACK)); // and loop
+ regoptail(ret, ret); // back
+ regtail(ret, regnode(BRANCH)); // or
+ regtail(ret, regnode(NOTHING)); // null.
+ }
+ else if (op == '+' && (flags & SIMPLE))
+ reginsert(PLUS, ret);
+ else if (op == '+') {
+ // Emit x+ as x(&|), where & means "self".
+ next = regnode(BRANCH); // Either
+ regtail(ret, next);
+ regtail(regnode(BACK), ret); // loop back
+ regtail(next, regnode(BRANCH)); // or
+ regtail(ret, regnode(NOTHING)); // null.
+ }
+ else if (op == '?') {
+ // Emit x? as (x|)
+ reginsert(BRANCH, ret); // Either x
+ regtail(ret, regnode(BRANCH)); // or
+ next = regnode(NOTHING);// null.
+ regtail(ret, next);
+ regoptail(ret, next);
+ }
+ regparse++;
+ if (ISMULT(*regparse)) {
+ //RAISE Error, SYM(RegularExpression), SYM(Nested_Operand),
+ printf ("RegularExpression::compile(): Nested *?+.\n");
+ return 0;
+ }
+ return (ret);
+}
+
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization: gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run. Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static char* regatom (int *flagp) {
+ char* ret;
+ int flags;
+
+ *flagp = WORST; // Tentatively.
+
+ switch (*regparse++) {
+ case '^':
+ ret = regnode(BOL);
+ break;
+ case '$':
+ ret = regnode(EOL);
+ break;
+ case '.':
+ ret = regnode(ANY);
+ *flagp |= HASWIDTH | SIMPLE;
+ break;
+ case '[':{
+ int rxpclass;
+ int rxpclassend;
+
+ if (*regparse == '^') { // Complement of range.
+ ret = regnode(ANYBUT);
+ regparse++;
+ }
+ else
+ ret = regnode(ANYOF);
+ if (*regparse == ']' || *regparse == '-')
+ regc(*regparse++);
+ while (*regparse != '\0' && *regparse != ']') {
+ if (*regparse == '-') {
+ regparse++;
+ if (*regparse == ']' || *regparse == '\0')
+ regc('-');
+ else {
+ rxpclass = UCHARAT(regparse - 2) + 1;
+ rxpclassend = UCHARAT(regparse);
+ if (rxpclass > rxpclassend + 1) {
+ //RAISE Error, SYM(RegularExpression), SYM(Invalid_Range),
+ printf ("RegularExpression::compile(): Invalid range in [].\n");
+ return 0;
+ }
+ for (; rxpclass <= rxpclassend; rxpclass++)
+ regc(static_cast<char>(rxpclass));
+ regparse++;
+ }
+ }
+ else
+ regc(*regparse++);
+ }
+ regc('\0');
+ if (*regparse != ']') {
+ //RAISE Error, SYM(RegularExpression), SYM(Unmatched_Bracket),
+ printf ("RegularExpression::compile(): Unmatched [].\n");
+ return 0;
+ }
+ regparse++;
+ *flagp |= HASWIDTH | SIMPLE;
+ }
+ break;
+ case '(':
+ ret = reg(1, &flags);
+ if (ret == 0)
+ return (0);
+ *flagp |= flags & (HASWIDTH | SPSTART);
+ break;
+ case '\0':
+ case '|':
+ case ')':
+ //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+ printf ("RegularExpression::compile(): Internal error.\n"); // Never here
+ return 0;
+ case '?':
+ case '+':
+ case '*':
+ //RAISE Error, SYM(RegularExpression), SYM(No_Operand),
+ printf ("RegularExpression::compile(): ?+* follows nothing.\n");
+ return 0;
+ case '\\':
+ if (*regparse == '\0') {
+ //RAISE Error, SYM(RegularExpression), SYM(Trailing_Backslash),
+ printf ("RegularExpression::compile(): Trailing backslash.\n");
+ return 0;
+ }
+ ret = regnode(EXACTLY);
+ regc(*regparse++);
+ regc('\0');
+ *flagp |= HASWIDTH | SIMPLE;
+ break;
+ default:{
+ int len;
+ char ender;
+
+ regparse--;
+ len = int(strcspn(regparse, META));
+ if (len <= 0) {
+ //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+ printf ("RegularExpression::compile(): Internal error.\n");
+ return 0;
+ }
+ ender = *(regparse + len);
+ if (len > 1 && ISMULT(ender))
+ len--; // Back off clear of ?+* operand.
+ *flagp |= HASWIDTH;
+ if (len == 1)
+ *flagp |= SIMPLE;
+ ret = regnode(EXACTLY);
+ while (len > 0) {
+ regc(*regparse++);
+ len--;
+ }
+ regc('\0');
+ }
+ break;
+ }
+ return (ret);
+}
+
+
+/*
+ - regnode - emit a node
+ Location.
+ */
+static char* regnode (char op) {
+ char* ret;
+ char* ptr;
+
+ ret = regcode;
+ if (ret == &regdummy) {
+ regsize += 3;
+ return (ret);
+ }
+
+ ptr = ret;
+ *ptr++ = op;
+ *ptr++ = '\0'; // Null "next" pointer.
+ *ptr++ = '\0';
+ regcode = ptr;
+
+ return (ret);
+}
+
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void regc (char b) {
+ if (regcode != &regdummy)
+ *regcode++ = b;
+ else
+ regsize++;
+}
+
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void reginsert (char op, char* opnd) {
+ char* src;
+ char* dst;
+ char* place;
+
+ if (regcode == &regdummy) {
+ regsize += 3;
+ return;
+ }
+
+ src = regcode;
+ regcode += 3;
+ dst = regcode;
+ while (src > opnd)
+ *--dst = *--src;
+
+ place = opnd; // Op node, where operand used to be.
+ *place++ = op;
+ *place++ = '\0';
+ *place = '\0';
+}
+
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void regtail (char* p, const char* val) {
+ char* scan;
+ char* temp;
+ int offset;
+
+ if (p == &regdummy)
+ return;
+
+ // Find last node.
+ scan = p;
+ for (;;) {
+ temp = regnext(scan);
+ if (temp == 0)
+ break;
+ scan = temp;
+ }
+
+ if (OP(scan) == BACK)
+ offset = int(scan - val);
+ else
+ offset = int(val - scan);
+ *(scan + 1) = static_cast<char>((offset >> 8) & 0377);
+ *(scan + 2) = static_cast<char>(offset & 0377);
+}
+
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+static void regoptail (char* p, const char* val) {
+ // "Operandless" and "op != BRANCH" are synonymous in practice.
+ if (p == 0 || p == &regdummy || OP(p) != BRANCH)
+ return;
+ regtail(OPERAND(p), val);
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// find and friends
+//
+////////////////////////////////////////////////////////////////////////
+
+
+/*
+ * Global work variables for find().
+ */
+static const char* reginput; // String-input pointer.
+static const char* regbol; // Beginning of input, for ^ check.
+static const char* *regstartp; // Pointer to startp array.
+static const char* *regendp; // Ditto for endp.
+
+/*
+ * Forwards.
+ */
+static int regtry (const char*, const char* *,
+ const char* *, const char*);
+static int regmatch (const char*);
+static int regrepeat (const char*);
+
+#ifdef DEBUG
+int regnarrate = 0;
+void regdump ();
+static char* regprop ();
+#endif
+
+// find -- Matches the regular expression to the given string.
+// Returns true if found, and sets start and end indexes accordingly.
+
+bool RegularExpression::find (const char* string) {
+ const char* s;
+
+ this->searchstring = string;
+
+ if (!this->program)
+ {
+ return false;
+ }
+
+ // Check validity of program.
+ if (UCHARAT(this->program) != MAGIC) {
+ //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+ printf ("RegularExpression::find(): Compiled regular expression corrupted.\n");
+ return 0;
+ }
+
+ // If there is a "must appear" string, look for it.
+ if (this->regmust != 0) {
+ s = string;
+ while ((s = strchr(s, this->regmust[0])) != 0) {
+ if (strncmp(s, this->regmust, this->regmlen) == 0)
+ break; // Found it.
+ s++;
+ }
+ if (s == 0) // Not present.
+ return (0);
+ }
+
+ // Mark beginning of line for ^ .
+ regbol = string;
+
+ // Simplest case: anchored match need be tried only once.
+ if (this->reganch)
+ return (regtry(string, this->startp, this->endp, this->program) != 0);
+
+ // Messy cases: unanchored match.
+ s = string;
+ if (this->regstart != '\0')
+ // We know what char it must start with.
+ while ((s = strchr(s, this->regstart)) != 0) {
+ if (regtry(s, this->startp, this->endp, this->program))
+ return (1);
+ s++;
+
+ }
+ else
+ // We don't -- general case.
+ do {
+ if (regtry(s, this->startp, this->endp, this->program))
+ return (1);
+ } while (*s++ != '\0');
+
+ // Failure.
+ return (0);
+}
+
+
+/*
+ - regtry - try match at specific point
+ 0 failure, 1 success
+ */
+static int regtry (const char* string, const char* *start,
+ const char* *end, const char* prog) {
+ int i;
+ const char* *sp1;
+ const char* *ep;
+
+ reginput = string;
+ regstartp = start;
+ regendp = end;
+
+ sp1 = start;
+ ep = end;
+ for (i = RegularExpression::NSUBEXP; i > 0; i--) {
+ *sp1++ = 0;
+ *ep++ = 0;
+ }
+ if (regmatch(prog + 1)) {
+ start[0] = string;
+ end[0] = reginput;
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple: check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly. In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ * 0 failure, 1 success
+ */
+static int regmatch (const char* prog) {
+ const char* scan; // Current node.
+ const char* next; // Next node.
+
+ scan = prog;
+
+ while (scan != 0) {
+
+ next = regnext(scan);
+
+ switch (OP(scan)) {
+ case BOL:
+ if (reginput != regbol)
+ return (0);
+ break;
+ case EOL:
+ if (*reginput != '\0')
+ return (0);
+ break;
+ case ANY:
+ if (*reginput == '\0')
+ return (0);
+ reginput++;
+ break;
+ case EXACTLY:{
+ size_t len;
+ const char* opnd;
+
+ opnd = OPERAND(scan);
+ // Inline the first character, for speed.
+ if (*opnd != *reginput)
+ return (0);
+ len = strlen(opnd);
+ if (len > 1 && strncmp(opnd, reginput, len) != 0)
+ return (0);
+ reginput += len;
+ }
+ break;
+ case ANYOF:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == 0)
+ return (0);
+ reginput++;
+ break;
+ case ANYBUT:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != 0)
+ return (0);
+ reginput++;
+ break;
+ case NOTHING:
+ break;
+ case BACK:
+ break;
+ case OPEN + 1:
+ case OPEN + 2:
+ case OPEN + 3:
+ case OPEN + 4:
+ case OPEN + 5:
+ case OPEN + 6:
+ case OPEN + 7:
+ case OPEN + 8:
+ case OPEN + 9:{
+ int no;
+ const char* save;
+
+ no = OP(scan) - OPEN;
+ save = reginput;
+
+ if (regmatch(next)) {
+
+ //
+ // Don't set startp if some later invocation of the
+ // same parentheses already has.
+ //
+ if (regstartp[no] == 0)
+ regstartp[no] = save;
+ return (1);
+ }
+ else
+ return (0);
+ }
+// break;
+ case CLOSE + 1:
+ case CLOSE + 2:
+ case CLOSE + 3:
+ case CLOSE + 4:
+ case CLOSE + 5:
+ case CLOSE + 6:
+ case CLOSE + 7:
+ case CLOSE + 8:
+ case CLOSE + 9:{
+ int no;
+ const char* save;
+
+ no = OP(scan) - CLOSE;
+ save = reginput;
+
+ if (regmatch(next)) {
+
+ //
+ // Don't set endp if some later invocation of the
+ // same parentheses already has.
+ //
+ if (regendp[no] == 0)
+ regendp[no] = save;
+ return (1);
+ }
+ else
+ return (0);
+ }
+// break;
+ case BRANCH:{
+
+ const char* save;
+
+ if (OP(next) != BRANCH) // No choice.
+ next = OPERAND(scan); // Avoid recursion.
+ else {
+ do {
+ save = reginput;
+ if (regmatch(OPERAND(scan)))
+ return (1);
+ reginput = save;
+ scan = regnext(scan);
+ } while (scan != 0 && OP(scan) == BRANCH);
+ return (0);
+ // NOTREACHED
+ }
+ }
+ break;
+ case STAR:
+ case PLUS:{
+ char nextch;
+ int no;
+ const char* save;
+ int min_no;
+
+ //
+ // Lookahead to avoid useless match attempts when we know
+ // what character comes next.
+ //
+ nextch = '\0';
+ if (OP(next) == EXACTLY)
+ nextch = *OPERAND(next);
+ min_no = (OP(scan) == STAR) ? 0 : 1;
+ save = reginput;
+ no = regrepeat(OPERAND(scan));
+ while (no >= min_no) {
+ // If it could work, try it.
+ if (nextch == '\0' || *reginput == nextch)
+ if (regmatch(next))
+ return (1);
+ // Couldn't or didn't -- back up.
+ no--;
+ reginput = save + no;
+ }
+ return (0);
+ }
+// break;
+ case END:
+ return (1); // Success!
+
+ default:
+ //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+ printf ("RegularExpression::find(): Internal error -- memory corrupted.\n");
+ return 0;
+ }
+ scan = next;
+ }
+
+ //
+ // We get here only if there's trouble -- normally "case END" is the
+ // terminating point.
+ //
+ //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+ printf ("RegularExpression::find(): Internal error -- corrupted pointers.\n");
+ return (0);
+}
+
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int regrepeat (const char* p) {
+ int count = 0;
+ const char* scan;
+ const char* opnd;
+
+ scan = reginput;
+ opnd = OPERAND(p);
+ switch (OP(p)) {
+ case ANY:
+ count = int(strlen(scan));
+ scan += count;
+ break;
+ case EXACTLY:
+ while (*opnd == *scan) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYOF:
+ while (*scan != '\0' && strchr(opnd, *scan) != 0) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYBUT:
+ while (*scan != '\0' && strchr(opnd, *scan) == 0) {
+ count++;
+ scan++;
+ }
+ break;
+ default: // Oh dear. Called inappropriately.
+ //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+ printf ("cm RegularExpression::find(): Internal error.\n");
+ return 0;
+ }
+ reginput = scan;
+ return (count);
+}
+
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static const char* regnext (const char* p) {
+ int offset;
+
+ if (p == &regdummy)
+ return (0);
+
+ offset = NEXT(p);
+ if (offset == 0)
+ return (0);
+
+ if (OP(p) == BACK)
+ return (p - offset);
+ else
+ return (p + offset);
+}
+
+static char* regnext (char* p) {
+ int offset;
+
+ if (p == &regdummy)
+ return (0);
+
+ offset = NEXT(p);
+ if (offset == 0)
+ return (0);
+
+ if (OP(p) == BACK)
+ return (p - offset);
+ else
+ return (p + offset);
+}
+
+} // namespace KWSYS_NAMESPACE
diff --git a/Source/kwsys/RegularExpression.hxx.in b/Source/kwsys/RegularExpression.hxx.in
new file mode 100644
index 0000000..0bb700f
--- /dev/null
+++ b/Source/kwsys/RegularExpression.hxx.in
@@ -0,0 +1,443 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+// Original Copyright notice:
+// Copyright (C) 1991 Texas Instruments Incorporated.
+//
+// Permission is granted to any individual or institution to use, copy, modify,
+// and distribute this software, provided that this complete copyright and
+// permission notice is maintained, intact, in all copies and supporting
+// documentation.
+//
+// Texas Instruments Incorporated provides this software "as is" without
+// express or implied warranty.
+//
+// Created: MNF 06/13/89 Initial Design and Implementation
+// Updated: LGO 08/09/89 Inherit from Generic
+// Updated: MBN 09/07/89 Added conditional exception handling
+// Updated: MBN 12/15/89 Sprinkled "const" qualifiers all over the place!
+// Updated: DLS 03/22/91 New lite version
+//
+
+#ifndef @KWSYS_NAMESPACE@_RegularExpression_hxx
+#define @KWSYS_NAMESPACE@_RegularExpression_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <string>
+
+/* Disable useless Borland warnings. KWSys tries not to force things
+ on its includers, but there is no choice here. */
+#if defined(__BORLANDC__)
+# pragma warn -8027 /* function not inlined. */
+#endif
+
+namespace @KWSYS_NAMESPACE@
+{
+
+/** \class RegularExpression
+ * \brief Implements pattern matching with regular expressions.
+ *
+ * This is the header file for the regular expression class. An object of
+ * this class contains a regular expression, in a special "compiled" format.
+ * This compiled format consists of several slots all kept as the objects
+ * private data. The RegularExpression class provides a convenient way to
+ * represent regular expressions. It makes it easy to search for the same
+ * regular expression in many different strings without having to compile a
+ * string to regular expression format more than necessary.
+ *
+ * This class implements pattern matching via regular expressions.
+ * A regular expression allows a programmer to specify complex
+ * patterns that can be searched for and matched against the
+ * character string of a string object. In its simplest form, a
+ * regular expression is a sequence of characters used to
+ * search for exact character matches. However, many times the
+ * exact sequence to be found is not known, or only a match at
+ * the beginning or end of a string is desired. The RegularExpression regu-
+ * lar expression class implements regular expression pattern
+ * matching as is found and implemented in many UNIX commands
+ * and utilities.
+ *
+ * Example: The perl code
+ *
+ * $filename =~ m"([a-z]+)\.cc";
+ * print $1;
+ *
+ * Is written as follows in C++
+ *
+ * RegularExpression re("([a-z]+)\\.cc");
+ * re.find(filename);
+ * cerr << re.match(1);
+ *
+ *
+ * The regular expression class provides a convenient mechanism
+ * for specifying and manipulating regular expressions. The
+ * regular expression object allows specification of such pat-
+ * terns by using the following regular expression metacharac-
+ * ters:
+ *
+ * ^ Matches at beginning of a line
+ *
+ * $ Matches at end of a line
+ *
+ * . Matches any single character
+ *
+ * [ ] Matches any character(s) inside the brackets
+ *
+ * [^ ] Matches any character(s) not inside the brackets
+ *
+ * - Matches any character in range on either side of a dash
+ *
+ * * Matches preceding pattern zero or more times
+ *
+ * + Matches preceding pattern one or more times
+ *
+ * ? Matches preceding pattern zero or once only
+ *
+ * () Saves a matched expression and uses it in a later match
+ *
+ * Note that more than one of these metacharacters can be used
+ * in a single regular expression in order to create complex
+ * search patterns. For example, the pattern [^ab1-9] says to
+ * match any character sequence that does not begin with the
+ * characters "ab" followed by numbers in the series one
+ * through nine.
+ *
+ * There are three constructors for RegularExpression. One just creates an
+ * empty RegularExpression object. Another creates a RegularExpression
+ * object and initializes it with a regular expression that is given in the
+ * form of a char*. The third takes a reference to a RegularExpression
+ * object as an argument and creates an object initialized with the
+ * information from the given RegularExpression object.
+ *
+ * The find member function finds the first occurence of the regualr
+ * expression of that object in the string given to find as an argument. Find
+ * returns a boolean, and if true, mutates the private data appropriately.
+ * Find sets pointers to the beginning and end of the thing last found, they
+ * are pointers into the actual string that was searched. The start and end
+ * member functions return indicies into the searched string that correspond
+ * to the beginning and end pointers respectively. The compile member
+ * function takes a char* and puts the compiled version of the char* argument
+ * into the object's private data fields. The == and != operators only check
+ * the to see if the compiled regular expression is the same, and the
+ * deep_equal functions also checks to see if the start and end pointers are
+ * the same. The is_valid function returns false if program is set to NULL,
+ * (i.e. there is no valid compiled exression). The set_invalid function sets
+ * the program to NULL (Warning: this deletes the compiled expression). The
+ * following examples may help clarify regular expression usage:
+ *
+ * * The regular expression "^hello" matches a "hello" only at the
+ * beginning of a line. It would match "hello there" but not "hi,
+ * hello there".
+ *
+ * * The regular expression "long$" matches a "long" only at the end
+ * of a line. It would match "so long\0", but not "long ago".
+ *
+ * * The regular expression "t..t..g" will match anything that has a
+ * "t" then any two characters, another "t", any two characters and
+ * then a "g". It will match "testing", or "test again" but would
+ * not match "toasting"
+ *
+ * * The regular expression "[1-9ab]" matches any number one through
+ * nine, and the characters "a" and "b". It would match "hello 1"
+ * or "begin", but would not match "no-match".
+ *
+ * * The regular expression "[^1-9ab]" matches any character that is
+ * not a number one through nine, or an "a" or "b". It would NOT
+ * match "hello 1" or "begin", but would match "no-match".
+ *
+ * * The regular expression "br* " matches something that begins with
+ * a "b", is followed by zero or more "r"s, and ends in a space. It
+ * would match "brrrrr ", and "b ", but would not match "brrh ".
+ *
+ * * The regular expression "br+ " matches something that begins with
+ * a "b", is followed by one or more "r"s, and ends in a space. It
+ * would match "brrrrr ", and "br ", but would not match "b " or
+ * "brrh ".
+ *
+ * * The regular expression "br? " matches something that begins with
+ * a "b", is followed by zero or one "r"s, and ends in a space. It
+ * would match "br ", and "b ", but would not match "brrrr " or
+ * "brrh ".
+ *
+ * * The regular expression "(..p)b" matches something ending with pb
+ * and beginning with whatever the two characters before the first p
+ * encounterd in the line were. It would find "repb" in "rep drepa
+ * qrepb". The regular expression "(..p)a" would find "repa qrepb"
+ * in "rep drepa qrepb"
+ *
+ * * The regular expression "d(..p)" matches something ending with p,
+ * beginning with d, and having two characters in between that are
+ * the same as the two characters before the first p encounterd in
+ * the line. It would match "drepa qrepb" in "rep drepa qrepb".
+ *
+ */
+class @KWSYS_NAMESPACE@_EXPORT RegularExpression
+{
+public:
+ /**
+ * Instantiate RegularExpression with program=NULL.
+ */
+ inline RegularExpression ();
+
+ /**
+ * Instantiate RegularExpression with compiled char*.
+ */
+ inline RegularExpression (char const*);
+
+ /**
+ * Instantiate RegularExpression as a copy of another regular expression.
+ */
+ RegularExpression (RegularExpression const&);
+
+ /**
+ * Instantiate RegularExpression with compiled string.
+ */
+ inline RegularExpression (std::string const&);
+
+ /**
+ * Destructor.
+ */
+ inline ~RegularExpression();
+
+ /**
+ * Compile a regular expression into internal code
+ * for later pattern matching.
+ */
+ bool compile (char const*);
+
+ /**
+ * Compile a regular expression into internal code
+ * for later pattern matching.
+ */
+ inline bool compile (std::string const&);
+
+ /**
+ * Matches the regular expression to the given string.
+ * Returns true if found, and sets start and end indexes accordingly.
+ */
+ bool find (char const*);
+
+ /**
+ * Matches the regular expression to the given std string.
+ * Returns true if found, and sets start and end indexes accordingly.
+ */
+ inline bool find (std::string const&);
+
+ /**
+ * Index to start of first find.
+ */
+ inline std::string::size_type start() const;
+
+ /**
+ * Index to end of first find.
+ */
+ inline std::string::size_type end() const;
+
+ /**
+ * Copy the given regular expression.
+ */
+ RegularExpression& operator= (const RegularExpression& rxp);
+
+ /**
+ * Returns true if two regular expressions have the same
+ * compiled program for pattern matching.
+ */
+ bool operator== (RegularExpression const&) const;
+
+ /**
+ * Returns true if two regular expressions have different
+ * compiled program for pattern matching.
+ */
+ inline bool operator!= (RegularExpression const&) const;
+
+ /**
+ * Returns true if have the same compiled regular expressions
+ * and the same start and end pointers.
+ */
+ bool deep_equal (RegularExpression const&) const;
+
+ /**
+ * True if the compiled regexp is valid.
+ */
+ inline bool is_valid() const;
+
+ /**
+ * Marks the regular expression as invalid.
+ */
+ inline void set_invalid();
+
+ /**
+ * Destructor.
+ */
+ // awf added
+ std::string::size_type start(int n) const;
+ std::string::size_type end(int n) const;
+ std::string match(int n) const;
+
+ enum { NSUBEXP = 10 };
+private:
+ const char* startp[NSUBEXP];
+ const char* endp[NSUBEXP];
+ char regstart; // Internal use only
+ char reganch; // Internal use only
+ const char* regmust; // Internal use only
+ std::string::size_type regmlen; // Internal use only
+ char* program;
+ int progsize;
+ const char* searchstring;
+};
+
+/**
+ * Create an empty regular expression.
+ */
+inline RegularExpression::RegularExpression ()
+{
+ this->program = 0;
+}
+
+/**
+ * Creates a regular expression from string s, and
+ * compiles s.
+ */
+inline RegularExpression::RegularExpression (const char* s)
+{
+ this->program = 0;
+ if ( s )
+ {
+ this->compile(s);
+ }
+}
+
+/**
+ * Creates a regular expression from string s, and
+ * compiles s.
+ */
+inline RegularExpression::RegularExpression (const std::string& s)
+{
+ this->program = 0;
+ this->compile(s);
+}
+
+/**
+ * Destroys and frees space allocated for the regular expression.
+ */
+inline RegularExpression::~RegularExpression ()
+{
+//#ifndef _WIN32
+ delete [] this->program;
+//#endif
+}
+
+/**
+ * Compile a regular expression into internal code
+ * for later pattern matching.
+ */
+inline bool RegularExpression::compile (std::string const& s)
+{
+ return this->compile(s.c_str());
+}
+
+/**
+ * Matches the regular expression to the given std string.
+ * Returns true if found, and sets start and end indexes accordingly.
+ */
+inline bool RegularExpression::find (std::string const& s)
+{
+ return this->find(s.c_str());
+}
+
+/**
+ * Set the start position for the regular expression.
+ */
+inline std::string::size_type RegularExpression::start () const
+{
+ return static_cast<std::string::size_type>(
+ this->startp[0] - searchstring);
+}
+
+
+/**
+ * Returns the start/end index of the last item found.
+ */
+inline std::string::size_type RegularExpression::end () const
+{
+ return static_cast<std::string::size_type>(
+ this->endp[0] - searchstring);
+}
+
+/**
+ * Returns true if two regular expressions have different
+ * compiled program for pattern matching.
+ */
+inline bool RegularExpression::operator!= (const RegularExpression& r) const
+{
+ return(!(*this == r));
+}
+
+/**
+ * Returns true if a valid regular expression is compiled
+ * and ready for pattern matching.
+ */
+inline bool RegularExpression::is_valid () const
+{
+ return (this->program != 0);
+}
+
+
+inline void RegularExpression::set_invalid ()
+{
+//#ifndef _WIN32
+ delete [] this->program;
+//#endif
+ this->program = 0;
+}
+
+/**
+ * Return start index of nth submatch. start(0) is the start of the full match.
+ */
+inline std::string::size_type RegularExpression::start(int n) const
+{
+ return static_cast<std::string::size_type>(
+ this->startp[n] - searchstring);
+}
+
+
+/**
+ * Return end index of nth submatch. end(0) is the end of the full match.
+ */
+inline std::string::size_type RegularExpression::end(int n) const
+{
+ return static_cast<std::string::size_type>(
+ this->endp[n] - searchstring);
+}
+
+/**
+ * Return nth submatch as a string.
+ */
+inline std::string RegularExpression::match(int n) const
+{
+ if (this->startp[n]==0)
+ {
+ return std::string("");
+ }
+ else
+ {
+ return std::string(this->startp[n],
+ static_cast<std::string::size_type>(
+ this->endp[n] - this->startp[n]));
+ }
+}
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/Source/kwsys/SharedForward.h.in b/Source/kwsys/SharedForward.h.in
new file mode 100644
index 0000000..f80ef84
--- /dev/null
+++ b/Source/kwsys/SharedForward.h.in
@@ -0,0 +1,944 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_SharedForward_h
+#define @KWSYS_NAMESPACE@_SharedForward_h
+
+/*
+ This header is used to create a forwarding executable sets up the
+ shared library search path and replaces itself with a real
+ executable. This is useful when creating installations on UNIX with
+ shared libraries that will run from any install directory. Typical
+ usage:
+
+ #if defined(CMAKE_INTDIR)
+ # define CONFIG_DIR_PRE CMAKE_INTDIR "/"
+ # define CONFIG_DIR_POST "/" CMAKE_INTDIR
+ #else
+ # define CONFIG_DIR_PRE ""
+ # define CONFIG_DIR_POST ""
+ #endif
+ #define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD "/path/to/foo-build/bin"
+ #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD "." CONFIG_DIR_POST
+ #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL "../lib/foo-1.2"
+ #define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD CONFIG_DIR_PRE "foo-real"
+ #define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL "../lib/foo-1.2/foo-real"
+ #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND "--command"
+ #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT "--print"
+ #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD "--ldd"
+ #if defined(CMAKE_INTDIR)
+ # define @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME CMAKE_INTDIR
+ #endif
+ #include <@KWSYS_NAMESPACE@/SharedForward.h>
+ int main(int argc, char** argv)
+ {
+ return @KWSYS_NAMESPACE@_shared_forward_to_real(argc, argv);
+ }
+
+ Specify search and executable paths relative to the forwarding
+ executable location or as full paths. Include no trailing slash.
+ In the case of a multi-configuration build, when CMAKE_INTDIR is
+ defined, the DIR_BUILD setting should point at the directory above
+ the executable (the one containing the per-configuration
+ subdirectory specified by CMAKE_INTDIR). Then PATH_BUILD entries
+ and EXE_BUILD should be specified relative to this location and use
+ CMAKE_INTDIR as necessary. In the above example imagine appending
+ the PATH_BUILD or EXE_BUILD setting to the DIR_BUILD setting. The
+ result should form a valid path with per-configuration subdirectory.
+
+ Additional paths may be specified in the PATH_BUILD and PATH_INSTALL
+ variables by using comma-separated strings. For example:
+
+ #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD \
+ "." CONFIG_DIR_POST, "/path/to/bar-build" CONFIG_DIR_POST
+ #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL \
+ "../lib/foo-1.2", "../lib/bar-4.5"
+
+ See the comments below for specific explanations of each macro.
+*/
+
+/* Disable -Wcast-qual warnings since they are too hard to fix in a
+ cross-platform way. */
+#if defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wcast-qual")
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wcast-qual"
+# endif
+#endif
+
+#if defined(__BORLANDC__) && !defined(__cplusplus)
+ /* Code has no effect; raised by winnt.h in C (not C++) when ignoring an
+ unused parameter using "(param)" syntax (i.e. no cast to void). */
+# pragma warn -8019
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+/* Full path to the directory in which this executable is built. Do
+ not include a trailing slash. */
+#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD)
+# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD"
+#endif
+#if !defined(KWSYS_SHARED_FORWARD_DIR_BUILD)
+# define KWSYS_SHARED_FORWARD_DIR_BUILD @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD
+#endif
+
+/* Library search path for build tree. */
+#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD)
+# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD"
+#endif
+#if !defined(KWSYS_SHARED_FORWARD_PATH_BUILD)
+# define KWSYS_SHARED_FORWARD_PATH_BUILD @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD
+#endif
+
+/* Library search path for install tree. */
+#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL)
+# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL"
+#endif
+#if !defined(KWSYS_SHARED_FORWARD_PATH_INSTALL)
+# define KWSYS_SHARED_FORWARD_PATH_INSTALL @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL
+#endif
+
+/* The real executable to which to forward in the build tree. */
+#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD)
+# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD"
+#endif
+#if !defined(KWSYS_SHARED_FORWARD_EXE_BUILD)
+# define KWSYS_SHARED_FORWARD_EXE_BUILD @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD
+#endif
+
+/* The real executable to which to forward in the install tree. */
+#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL)
+# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL"
+#endif
+#if !defined(KWSYS_SHARED_FORWARD_EXE_INSTALL)
+# define KWSYS_SHARED_FORWARD_EXE_INSTALL @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL
+#endif
+
+/* The configuration name with which this executable was built (Debug/Release). */
+#if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME)
+# define KWSYS_SHARED_FORWARD_CONFIG_NAME @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME
+#else
+# undef KWSYS_SHARED_FORWARD_CONFIG_NAME
+#endif
+
+/* Create command line option to replace executable. */
+#if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND)
+# if !defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND)
+# define KWSYS_SHARED_FORWARD_OPTION_COMMAND @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND
+# endif
+#else
+# undef KWSYS_SHARED_FORWARD_OPTION_COMMAND
+#endif
+
+/* Create command line option to print environment setting and exit. */
+#if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT)
+# if !defined(KWSYS_SHARED_FORWARD_OPTION_PRINT)
+# define KWSYS_SHARED_FORWARD_OPTION_PRINT @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT
+# endif
+#else
+# undef KWSYS_SHARED_FORWARD_OPTION_PRINT
+#endif
+
+/* Create command line option to run ldd or equivalent. */
+#if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD)
+# if !defined(KWSYS_SHARED_FORWARD_OPTION_LDD)
+# define KWSYS_SHARED_FORWARD_OPTION_LDD @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD
+# endif
+#else
+# undef KWSYS_SHARED_FORWARD_OPTION_LDD
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Include needed system headers. */
+
+#include <stddef.h> /* size_t */
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <io.h>
+# include <windows.h>
+# include <process.h>
+# define KWSYS_SHARED_FORWARD_ESCAPE_ARGV /* re-escape argv for execvp */
+#else
+# include <unistd.h>
+# include <sys/stat.h>
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Configuration for this platform. */
+
+/* The path separator for this platform. */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# define KWSYS_SHARED_FORWARD_PATH_SEP ';'
+# define KWSYS_SHARED_FORWARD_PATH_SLASH '\\'
+#else
+# define KWSYS_SHARED_FORWARD_PATH_SEP ':'
+# define KWSYS_SHARED_FORWARD_PATH_SLASH '/'
+#endif
+static const char kwsys_shared_forward_path_sep[2] = {KWSYS_SHARED_FORWARD_PATH_SEP, 0};
+static const char kwsys_shared_forward_path_slash[2] = {KWSYS_SHARED_FORWARD_PATH_SLASH, 0};
+
+/* The maximum length of a file name. */
+#if defined(PATH_MAX)
+# define KWSYS_SHARED_FORWARD_MAXPATH PATH_MAX
+#elif defined(MAXPATHLEN)
+# define KWSYS_SHARED_FORWARD_MAXPATH MAXPATHLEN
+#else
+# define KWSYS_SHARED_FORWARD_MAXPATH 16384
+#endif
+
+/* Select the environment variable holding the shared library runtime
+ search path for this platform and build configuration. Also select
+ ldd command equivalent. */
+
+/* Linux */
+#if defined(__linux)
+# define KWSYS_SHARED_FORWARD_LDD "ldd"
+# define KWSYS_SHARED_FORWARD_LDD_N 1
+# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+
+/* FreeBSD */
+#elif defined(__FreeBSD__)
+# define KWSYS_SHARED_FORWARD_LDD "ldd"
+# define KWSYS_SHARED_FORWARD_LDD_N 1
+# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+
+/* OpenBSD */
+#elif defined(__OpenBSD__)
+# define KWSYS_SHARED_FORWARD_LDD "ldd"
+# define KWSYS_SHARED_FORWARD_LDD_N 1
+# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+
+/* OSX */
+#elif defined(__APPLE__)
+# define KWSYS_SHARED_FORWARD_LDD "otool", "-L"
+# define KWSYS_SHARED_FORWARD_LDD_N 2
+# define KWSYS_SHARED_FORWARD_LDPATH "DYLD_LIBRARY_PATH"
+
+/* AIX */
+#elif defined(_AIX)
+# define KWSYS_SHARED_FORWARD_LDD "dump", "-H"
+# define KWSYS_SHARED_FORWARD_LDD_N 2
+# define KWSYS_SHARED_FORWARD_LDPATH "LIBPATH"
+
+/* SUN */
+#elif defined(__sun)
+# define KWSYS_SHARED_FORWARD_LDD "ldd"
+# define KWSYS_SHARED_FORWARD_LDD_N 1
+# include <sys/isa_defs.h>
+# if defined(_ILP32)
+# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+# elif defined(_LP64)
+# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH_64"
+# endif
+
+/* HP-UX */
+#elif defined(__hpux)
+# define KWSYS_SHARED_FORWARD_LDD "chatr"
+# define KWSYS_SHARED_FORWARD_LDD_N 1
+# if defined(__LP64__)
+# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+# else
+# define KWSYS_SHARED_FORWARD_LDPATH "SHLIB_PATH"
+# endif
+
+/* SGI MIPS */
+#elif defined(__sgi) && defined(_MIPS_SIM)
+# define KWSYS_SHARED_FORWARD_LDD "ldd"
+# define KWSYS_SHARED_FORWARD_LDD_N 1
+# if _MIPS_SIM == _ABIO32
+# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+# elif _MIPS_SIM == _ABIN32
+# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARYN32_PATH"
+# elif _MIPS_SIM == _ABI64
+# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY64_PATH"
+# endif
+
+/* Cygwin */
+#elif defined(__CYGWIN__)
+# define KWSYS_SHARED_FORWARD_LDD "cygcheck" /* TODO: cygwin 1.7 has ldd */
+# define KWSYS_SHARED_FORWARD_LDD_N 1
+# define KWSYS_SHARED_FORWARD_LDPATH "PATH"
+
+/* Windows */
+#elif defined(_WIN32)
+# define KWSYS_SHARED_FORWARD_LDPATH "PATH"
+
+/* Guess on this unknown system. */
+#else
+# define KWSYS_SHARED_FORWARD_LDD "ldd"
+# define KWSYS_SHARED_FORWARD_LDD_N 1
+# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+#endif
+
+#ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV
+/*--------------------------------------------------------------------------*/
+typedef struct kwsys_sf_arg_info_s
+{
+ const char* arg;
+ int size;
+ int quote;
+} kwsys_sf_arg_info;
+
+/*--------------------------------------------------------------------------*/
+static kwsys_sf_arg_info kwsys_sf_get_arg_info(const char* in)
+{
+ /* Initialize information. */
+ kwsys_sf_arg_info info;
+
+ /* String iterator. */
+ const char* c;
+
+ /* Keep track of how many backslashes have been encountered in a row. */
+ int windows_backslashes = 0;
+
+ /* Start with the length of the original argument, plus one for
+ either a terminating null or a separating space. */
+ info.arg = in;
+ info.size = (int)strlen(in) + 1;
+ info.quote = 0;
+
+ /* Scan the string for characters that require escaping or quoting. */
+ for(c=in; *c; ++c)
+ {
+ /* Check whether this character needs quotes. */
+ if(strchr(" \t?'#&<>|^", *c))
+ {
+ info.quote = 1;
+ }
+
+ /* On Windows only backslashes and double-quotes need escaping. */
+ if(*c == '\\')
+ {
+ /* Found a backslash. It may need to be escaped later. */
+ ++windows_backslashes;
+ }
+ else if(*c == '"')
+ {
+ /* Found a double-quote. We need to escape it and all
+ immediately preceding backslashes. */
+ info.size += windows_backslashes + 1;
+ windows_backslashes = 0;
+ }
+ else
+ {
+ /* Found another character. This eliminates the possibility
+ that any immediately preceding backslashes will be
+ escaped. */
+ windows_backslashes = 0;
+ }
+ }
+
+ /* Check whether the argument needs surrounding quotes. */
+ if(info.quote)
+ {
+ /* Surrounding quotes are needed. Allocate space for them. */
+ info.size += 2;
+
+ /* We must escape all ending backslashes when quoting on windows. */
+ info.size += windows_backslashes;
+ }
+
+ return info;
+}
+
+/*--------------------------------------------------------------------------*/
+static char* kwsys_sf_get_arg(kwsys_sf_arg_info info, char* out)
+{
+ /* String iterator. */
+ const char* c;
+
+ /* Keep track of how many backslashes have been encountered in a row. */
+ int windows_backslashes = 0;
+
+ /* Whether the argument must be quoted. */
+ if(info.quote)
+ {
+ /* Add the opening quote for this argument. */
+ *out++ = '"';
+ }
+
+ /* Scan the string for characters that require escaping or quoting. */
+ for(c=info.arg; *c; ++c)
+ {
+ /* On Windows only backslashes and double-quotes need escaping. */
+ if(*c == '\\')
+ {
+ /* Found a backslash. It may need to be escaped later. */
+ ++windows_backslashes;
+ }
+ else if(*c == '"')
+ {
+ /* Found a double-quote. Escape all immediately preceding
+ backslashes. */
+ while(windows_backslashes > 0)
+ {
+ --windows_backslashes;
+ *out++ = '\\';
+ }
+
+ /* Add the backslash to escape the double-quote. */
+ *out++ = '\\';
+ }
+ else
+ {
+ /* We encountered a normal character. This eliminates any
+ escaping needed for preceding backslashes. */
+ windows_backslashes = 0;
+ }
+
+ /* Store this character. */
+ *out++ = *c;
+ }
+
+ if(info.quote)
+ {
+ /* Add enough backslashes to escape any trailing ones. */
+ while(windows_backslashes > 0)
+ {
+ --windows_backslashes;
+ *out++ = '\\';
+ }
+
+ /* Add the closing quote for this argument. */
+ *out++ = '"';
+ }
+
+ /* Store a terminating null without incrementing. */
+ *out = 0;
+
+ return out;
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Function to convert a logical or relative path to a physical full path. */
+static int kwsys_shared_forward_realpath(const char* in_path, char* out_path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ /* Implementation for Windows. */
+ DWORD n = GetFullPathNameA(in_path, KWSYS_SHARED_FORWARD_MAXPATH,
+ out_path, 0);
+ return n > 0 && n <= KWSYS_SHARED_FORWARD_MAXPATH;
+#else
+ /* Implementation for UNIX. */
+ return realpath(in_path, out_path) != 0;
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsys_shared_forward_samepath(const char* file1, const char* file2)
+{
+#if defined(_WIN32)
+ int result = 0;
+ HANDLE h1 = CreateFileA(file1, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ HANDLE h2 = CreateFileA(file2, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if(h1 != INVALID_HANDLE_VALUE && h2 != INVALID_HANDLE_VALUE)
+ {
+ BY_HANDLE_FILE_INFORMATION fi1;
+ BY_HANDLE_FILE_INFORMATION fi2;
+ GetFileInformationByHandle(h1, &fi1);
+ GetFileInformationByHandle(h2, &fi2);
+ result = (fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber &&
+ fi1.nFileIndexHigh == fi2.nFileIndexHigh &&
+ fi1.nFileIndexLow == fi2.nFileIndexLow);
+ }
+ CloseHandle(h1);
+ CloseHandle(h2);
+ return result;
+#else
+ struct stat fs1, fs2;
+ return (stat(file1, &fs1) == 0 && stat(file2, &fs2) == 0 &&
+ memcmp(&fs2.st_dev, &fs1.st_dev, sizeof(fs1.st_dev)) == 0 &&
+ memcmp(&fs2.st_ino, &fs1.st_ino, sizeof(fs1.st_ino)) == 0 &&
+ fs2.st_size == fs1.st_size);
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to report a system error message. */
+static void kwsys_shared_forward_strerror(char* message)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ /* Implementation for Windows. */
+ DWORD original = GetLastError();
+ DWORD length = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, 0, original,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ message, KWSYS_SHARED_FORWARD_MAXPATH, 0);
+ if(length < 1 || length > KWSYS_SHARED_FORWARD_MAXPATH)
+ {
+ /* FormatMessage failed. Use a default message. */
+ _snprintf(message, KWSYS_SHARED_FORWARD_MAXPATH,
+ "Error 0x%X (FormatMessage failed with error 0x%X)",
+ original, GetLastError());
+ }
+#else
+ /* Implementation for UNIX. */
+ strcpy(message, strerror(errno));
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+/* Functions to execute a child process. */
+static void kwsys_shared_forward_execvp(const char* cmd,
+ char const* const* argv)
+{
+#ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV
+ /* Count the number of arguments. */
+ int argc = 0;
+ {
+ char const* const* argvc;
+ for(argvc = argv; *argvc; ++argvc,++argc) {}
+ }
+
+ /* Create the escaped arguments. */
+ {
+ char** nargv = (char**)malloc((argc+1) * sizeof(char*));
+ int i;
+ for(i=0; i < argc; ++i)
+ {
+ kwsys_sf_arg_info info = kwsys_sf_get_arg_info(argv[i]);
+ nargv[i] = (char*)malloc(info.size);
+ kwsys_sf_get_arg(info, nargv[i]);
+ }
+ nargv[argc] = 0;
+
+ /* Replace the command line to be used. */
+ argv = (char const* const*)nargv;
+ }
+#endif
+
+ /* Invoke the child process. */
+#if defined(_MSC_VER)
+ _execvp(cmd, argv);
+#elif defined(__MINGW32__) && !defined(__MINGW64__)
+ execvp(cmd, argv);
+#else
+ execvp(cmd, (char* const*)argv);
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to get the directory containing the given file or directory. */
+static void kwsys_shared_forward_dirname(const char* begin, char* result)
+{
+ /* Find the location of the last slash. */
+ int last_slash_index = -1;
+ const char* end = begin + strlen(begin);
+ for(;begin <= end && last_slash_index < 0; --end)
+ {
+ if(*end == '/' || *end == '\\')
+ {
+ last_slash_index = (int)(end-begin);
+ }
+ }
+
+ /* Handle each case of the index of the last slash. */
+ if(last_slash_index < 0)
+ {
+ /* No slashes. */
+ strcpy(result, ".");
+ }
+ else if(last_slash_index == 0)
+ {
+ /* Only one leading slash. */
+ strcpy(result, kwsys_shared_forward_path_slash);
+ }
+#if defined(_WIN32)
+ else if(last_slash_index == 2 && begin[1] == ':')
+ {
+ /* Only one leading drive letter and slash. */
+ strncpy(result, begin, (size_t)last_slash_index);
+ result[last_slash_index] = KWSYS_SHARED_FORWARD_PATH_SLASH;
+ result[last_slash_index+1] = 0;
+ }
+#endif
+ else
+ {
+ /* A non-leading slash. */
+ strncpy(result, begin, (size_t)last_slash_index);
+ result[last_slash_index] = 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to check if a file exists and is executable. */
+static int kwsys_shared_forward_is_executable(const char* f)
+{
+#if defined(_MSC_VER)
+# define KWSYS_SHARED_FORWARD_ACCESS _access
+#else
+# define KWSYS_SHARED_FORWARD_ACCESS access
+#endif
+#if defined(X_OK)
+# define KWSYS_SHARED_FORWARD_ACCESS_OK X_OK
+#else
+# define KWSYS_SHARED_FORWARD_ACCESS_OK 04
+#endif
+ if(KWSYS_SHARED_FORWARD_ACCESS(f, KWSYS_SHARED_FORWARD_ACCESS_OK) == 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to locate the executable currently running. */
+static int kwsys_shared_forward_self_path(const char* argv0, char* result)
+{
+ /* Check whether argv0 has a slash. */
+ int has_slash = 0;
+ const char* p = argv0;
+ for(;*p && !has_slash; ++p)
+ {
+ if(*p == '/' || *p == '\\')
+ {
+ has_slash = 1;
+ }
+ }
+
+ if(has_slash)
+ {
+ /* There is a slash. Use the dirname of the given location. */
+ kwsys_shared_forward_dirname(argv0, result);
+ return 1;
+ }
+ else
+ {
+ /* There is no slash. Search the PATH for the executable. */
+ const char* path = getenv("PATH");
+ const char* begin = path;
+ const char* end = begin + (begin?strlen(begin):0);
+ const char* first = begin;
+ while(first != end)
+ {
+ /* Store the end of this path entry. */
+ const char* last;
+
+ /* Skip all path separators. */
+ for(;*first && *first == KWSYS_SHARED_FORWARD_PATH_SEP; ++first);
+
+ /* Find the next separator. */
+ for(last = first;*last && *last != KWSYS_SHARED_FORWARD_PATH_SEP; ++last);
+
+ /* If we got a non-empty directory, look for the executable there. */
+ if(first < last)
+ {
+ /* Determine the length without trailing slash. */
+ size_t length = (size_t)(last-first);
+ if(*(last-1) == '/' || *(last-1) == '\\')
+ {
+ --length;
+ }
+
+ /* Construct the name of the executable in this location. */
+ strncpy(result, first, length);
+ result[length] = KWSYS_SHARED_FORWARD_PATH_SLASH;
+ strcpy(result+(length)+1, argv0);
+
+ /* Check if it exists and is executable. */
+ if(kwsys_shared_forward_is_executable(result))
+ {
+ /* Found it. */
+ result[length] = 0;
+ return 1;
+ }
+ }
+
+ /* Move to the next directory in the path. */
+ first = last;
+ }
+ }
+
+ /* We could not find the executable. */
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to convert a specified path to a full path. If it is not
+ already full, it is taken relative to the self path. */
+static int kwsys_shared_forward_fullpath(const char* self_path,
+ const char* in_path,
+ char* result,
+ const char* desc)
+{
+ /* Check the specified path type. */
+ if(in_path[0] == '/')
+ {
+ /* Already a full path. */
+ strcpy(result, in_path);
+ }
+#if defined(_WIN32)
+ else if(in_path[0] && in_path[1] == ':')
+ {
+ /* Already a full path. */
+ strcpy(result, in_path);
+ }
+#endif
+ else
+ {
+ /* Relative to self path. */
+ char temp_path[KWSYS_SHARED_FORWARD_MAXPATH];
+ strcpy(temp_path, self_path);
+ strcat(temp_path, kwsys_shared_forward_path_slash);
+ strcat(temp_path, in_path);
+ if(!kwsys_shared_forward_realpath(temp_path, result))
+ {
+ if(desc)
+ {
+ char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH];
+ kwsys_shared_forward_strerror(msgbuf);
+ fprintf(stderr, "Error converting %s \"%s\" to real path: %s\n",
+ desc, temp_path, msgbuf);
+ }
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to compute the library search path and executable name
+ based on the self path. */
+static int kwsys_shared_forward_get_settings(const char* self_path,
+ char* ldpath, char* exe)
+{
+ /* Possible search paths. */
+ static const char* search_path_build[] = {KWSYS_SHARED_FORWARD_PATH_BUILD, 0};
+ static const char* search_path_install[] = {KWSYS_SHARED_FORWARD_PATH_INSTALL, 0};
+
+ /* Chosen paths. */
+ const char** search_path;
+ const char* exe_path;
+
+ /* Get the real name of the build and self paths. */
+#if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME)
+ char build_path[] = KWSYS_SHARED_FORWARD_DIR_BUILD "/" KWSYS_SHARED_FORWARD_CONFIG_NAME;
+ char self_path_logical[KWSYS_SHARED_FORWARD_MAXPATH];
+#else
+ char build_path[] = KWSYS_SHARED_FORWARD_DIR_BUILD;
+ const char* self_path_logical = self_path;
+#endif
+ char build_path_real[KWSYS_SHARED_FORWARD_MAXPATH];
+ char self_path_real[KWSYS_SHARED_FORWARD_MAXPATH];
+ if(!kwsys_shared_forward_realpath(self_path, self_path_real))
+ {
+ char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH];
+ kwsys_shared_forward_strerror(msgbuf);
+ fprintf(stderr, "Error converting self path \"%s\" to real path: %s\n",
+ self_path, msgbuf);
+ return 0;
+ }
+
+ /* Check whether we are running in the build tree or an install tree. */
+ if(kwsys_shared_forward_realpath(build_path, build_path_real) &&
+ kwsys_shared_forward_samepath(self_path_real, build_path_real))
+ {
+ /* Running in build tree. Use the build path and exe. */
+ search_path = search_path_build;
+#if defined(_WIN32)
+ exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD ".exe";
+#else
+ exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD;
+#endif
+
+#if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME)
+ /* Remove the configuration directory from self_path. */
+ kwsys_shared_forward_dirname(self_path, self_path_logical);
+#endif
+ }
+ else
+ {
+ /* Running in install tree. Use the install path and exe. */
+ search_path = search_path_install;
+#if defined(_WIN32)
+ exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL ".exe";
+#else
+ exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL;
+#endif
+
+#if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME)
+ /* Use the original self path directory. */
+ strcpy(self_path_logical, self_path);
+#endif
+ }
+
+ /* Construct the runtime search path. */
+ {
+ const char** dir;
+ for(dir = search_path; *dir; ++dir)
+ {
+ /* Add separator between path components. */
+ if(dir != search_path)
+ {
+ strcat(ldpath, kwsys_shared_forward_path_sep);
+ }
+
+ /* Add this path component. */
+ if(!kwsys_shared_forward_fullpath(self_path_logical, *dir,
+ ldpath+strlen(ldpath),
+ "runtime path entry"))
+ {
+ return 0;
+ }
+ }
+ }
+
+ /* Construct the executable location. */
+ if(!kwsys_shared_forward_fullpath(self_path_logical, exe_path, exe,
+ "executable file"))
+ {
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to print why execution of a command line failed. */
+static void kwsys_shared_forward_print_failure(char const* const* argv)
+{
+ char msg[KWSYS_SHARED_FORWARD_MAXPATH];
+ char const* const* arg = argv;
+ kwsys_shared_forward_strerror(msg);
+ fprintf(stderr, "Error running");
+ for(; *arg; ++arg)
+ {
+ fprintf(stderr, " \"%s\"", *arg);
+ }
+ fprintf(stderr, ": %s\n", msg);
+}
+
+/* Static storage space to store the updated environment variable. */
+static char kwsys_shared_forward_ldpath[65535] = KWSYS_SHARED_FORWARD_LDPATH "=";
+
+/*--------------------------------------------------------------------------*/
+/* Main driver function to be called from main. */
+static int @KWSYS_NAMESPACE@_shared_forward_to_real(int argc, char** argv_in)
+{
+ char const** argv = (char const**)argv_in;
+ /* Get the directory containing this executable. */
+ char self_path[KWSYS_SHARED_FORWARD_MAXPATH];
+ if(kwsys_shared_forward_self_path(argv[0], self_path))
+ {
+ /* Found this executable. Use it to get the library directory. */
+ char exe[KWSYS_SHARED_FORWARD_MAXPATH];
+ if(kwsys_shared_forward_get_settings(self_path,
+ kwsys_shared_forward_ldpath, exe))
+ {
+ /* Append the old runtime search path. */
+ const char* old_ldpath = getenv(KWSYS_SHARED_FORWARD_LDPATH);
+ if(old_ldpath)
+ {
+ strcat(kwsys_shared_forward_ldpath, kwsys_shared_forward_path_sep);
+ strcat(kwsys_shared_forward_ldpath, old_ldpath);
+ }
+
+ /* Store the environment variable. */
+ putenv(kwsys_shared_forward_ldpath);
+
+#if defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND)
+ /* Look for the command line replacement option. */
+ if(argc > 1 && strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_COMMAND) == 0)
+ {
+ if(argc > 2)
+ {
+ /* Use the command line given. */
+ strcpy(exe, argv[2]);
+ argv += 2;
+ argc -= 2;
+ }
+ else
+ {
+ /* The option was not given an executable. */
+ fprintf(stderr, "Option " KWSYS_SHARED_FORWARD_OPTION_COMMAND
+ " must be followed by a command line.\n");
+ return 1;
+ }
+ }
+#endif
+
+#if defined(KWSYS_SHARED_FORWARD_OPTION_PRINT)
+ /* Look for the print command line option. */
+ if(argc > 1 && strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_PRINT) == 0)
+ {
+ fprintf(stdout, "%s\n", kwsys_shared_forward_ldpath);
+ fprintf(stdout, "%s\n", exe);
+ return 0;
+ }
+#endif
+
+#if defined(KWSYS_SHARED_FORWARD_OPTION_LDD)
+ /* Look for the ldd command line option. */
+ if(argc > 1 && strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_LDD) == 0)
+ {
+# if defined(KWSYS_SHARED_FORWARD_LDD)
+ /* Use the named ldd-like executable and arguments. */
+ char const* ldd_argv[] = {KWSYS_SHARED_FORWARD_LDD, 0, 0};
+ ldd_argv[KWSYS_SHARED_FORWARD_LDD_N] = exe;
+ kwsys_shared_forward_execvp(ldd_argv[0], ldd_argv);
+
+ /* Report why execution failed. */
+ kwsys_shared_forward_print_failure(ldd_argv);
+ return 1;
+# else
+ /* We have no ldd-like executable available on this platform. */
+ fprintf(stderr, "No ldd-like tool is known to this executable.\n");
+ return 1;
+# endif
+ }
+#endif
+
+ /* Replace this process with the real executable. */
+ argv[0] = exe;
+ kwsys_shared_forward_execvp(argv[0], argv);
+
+ /* Report why execution failed. */
+ kwsys_shared_forward_print_failure(argv);
+ }
+ else
+ {
+ /* Could not convert self path to the library directory. */
+ }
+ }
+ else
+ {
+ /* Could not find this executable. */
+ fprintf(stderr, "Error locating executable \"%s\".\n", argv[0]);
+ }
+
+ /* Avoid unused argument warning. */
+ (void)argc;
+
+ /* Exit with failure. */
+ return 1;
+}
+
+/* Restore warning stack. */
+#if defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wcast-qual")
+# pragma clang diagnostic pop
+# endif
+#endif
+
+#else
+# error "@KWSYS_NAMESPACE@/SharedForward.h should be included only once."
+#endif
diff --git a/Source/kwsys/String.c b/Source/kwsys/String.c
new file mode 100644
index 0000000..ed4a6c5
--- /dev/null
+++ b/Source/kwsys/String.c
@@ -0,0 +1,115 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifdef KWSYS_STRING_C
+/*
+All code in this source file is conditionally compiled to work-around
+template definition auto-search on VMS. Other source files in this
+directory that use the stl string cause the compiler to load this
+source to try to get the definition of the string template. This
+condition blocks the compiler from seeing the symbols defined here.
+*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(String.h)
+
+/* Work-around CMake dependency scanning limitation. This must
+ duplicate the above list of headers. */
+#if 0
+# include "String.h.in"
+#endif
+
+/* Select an implementation for strcasecmp. */
+#if defined(_MSC_VER)
+# define KWSYS_STRING_USE_STRICMP
+# include <string.h>
+#elif defined(__GNUC__)
+# define KWSYS_STRING_USE_STRCASECMP
+# include <strings.h>
+#else
+/* Table to convert upper case letters to lower case and leave all
+ other characters alone. */
+static char kwsysString_strcasecmp_tolower[] =
+{
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+ '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
+ '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+ '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+#endif
+
+/*--------------------------------------------------------------------------*/
+int kwsysString_strcasecmp(const char* lhs, const char* rhs)
+{
+#if defined(KWSYS_STRING_USE_STRICMP)
+ return _stricmp(lhs, rhs);
+#elif defined(KWSYS_STRING_USE_STRCASECMP)
+ return strcasecmp(lhs, rhs);
+#else
+ const char* const lower = kwsysString_strcasecmp_tolower;
+ unsigned char const* us1 = (unsigned char const*)lhs;
+ unsigned char const* us2 = (unsigned char const*)rhs;
+ int result;
+ while((result = lower[*us1] - lower[*us2++], result == 0) && *us1++)
+ {
+ }
+ return result;
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysString_strncasecmp(const char* lhs, const char* rhs, size_t n)
+{
+#if defined(KWSYS_STRING_USE_STRICMP)
+ return _strnicmp(lhs, rhs, n);
+#elif defined(KWSYS_STRING_USE_STRCASECMP)
+ return strncasecmp(lhs, rhs, n);
+#else
+ const char* const lower = kwsysString_strcasecmp_tolower;
+ unsigned char const* us1 = (unsigned char const*)lhs;
+ unsigned char const* us2 = (unsigned char const*)rhs;
+ int result = 0;
+ while(n && (result = lower[*us1] - lower[*us2++], result == 0) && *us1++)
+ {
+ --n;
+ }
+ return result;
+#endif
+}
+
+#endif /* KWSYS_STRING_C */
diff --git a/Source/kwsys/String.h.in b/Source/kwsys/String.h.in
new file mode 100644
index 0000000..f5bab6e
--- /dev/null
+++ b/Source/kwsys/String.h.in
@@ -0,0 +1,67 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_String_h
+#define @KWSYS_NAMESPACE@_String_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+#include <stddef.h> /* size_t */
+
+/* Redefine all public interface symbol names to be in the proper
+ namespace. These macros are used internally to kwsys only, and are
+ not visible to user code. Use kwsysHeaderDump.pl to reproduce
+ these macros after making changes to the interface. */
+#if !defined(KWSYS_NAMESPACE)
+# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# define kwsysString_strcasecmp kwsys_ns(String_strcasecmp)
+# define kwsysString_strncasecmp kwsys_ns(String_strncasecmp)
+#endif
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/**
+ * Compare two strings ignoring the case of the characters. The
+ * integer returned is negative, zero, or positive if the first string
+ * is found to be less than, equal to, or greater than the second
+ * string, respectively.
+ */
+kwsysEXPORT int kwsysString_strcasecmp(const char* lhs, const char* rhs);
+
+/**
+ * Identical to String_strcasecmp except that only the first n
+ * characters are considered.
+ */
+kwsysEXPORT int kwsysString_strncasecmp(const char* lhs, const char* rhs,
+ size_t n);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+ Otherwise, undefine them to keep the namespace clean. */
+#if !defined(KWSYS_NAMESPACE)
+# undef kwsys_ns
+# undef kwsysEXPORT
+# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# undef kwsysString_strcasecmp
+# undef kwsysString_strncasecmp
+# endif
+#endif
+
+#endif
diff --git a/Source/kwsys/String.hxx.in b/Source/kwsys/String.hxx.in
new file mode 100644
index 0000000..2e9aedb
--- /dev/null
+++ b/Source/kwsys/String.hxx.in
@@ -0,0 +1,65 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_String_hxx
+#define @KWSYS_NAMESPACE@_String_hxx
+
+#include <string>
+
+namespace @KWSYS_NAMESPACE@
+{
+
+/** \class String
+ * \brief Short-name version of the STL basic_string class template.
+ *
+ * The standard library "string" type is actually a typedef for
+ * "basic_string<..long argument list..>". This string class is
+ * simply a subclass of this type with the same interface so that the
+ * name is shorter in debugging symbols and error messages.
+ */
+class String: public std::string
+{
+ /** The original string type. */
+ typedef std::string stl_string;
+
+public:
+
+ /** String member types. */
+ typedef stl_string::value_type value_type;
+ typedef stl_string::pointer pointer;
+ typedef stl_string::reference reference;
+ typedef stl_string::const_reference const_reference;
+ typedef stl_string::size_type size_type;
+ typedef stl_string::difference_type difference_type;
+ typedef stl_string::iterator iterator;
+ typedef stl_string::const_iterator const_iterator;
+ typedef stl_string::reverse_iterator reverse_iterator;
+ typedef stl_string::const_reverse_iterator const_reverse_iterator;
+
+ /** String constructors. */
+ String(): stl_string() {}
+ String(const value_type* s): stl_string(s) {}
+ String(const value_type* s, size_type n): stl_string(s, n) {}
+ String(const stl_string& s, size_type pos=0, size_type n=npos):
+ stl_string(s, pos, n) {}
+}; // End Class: String
+
+#if defined(__WATCOMC__)
+inline bool operator<(String const& l, String const& r)
+ {
+ return (static_cast<std::string const&>(l) <
+ static_cast<std::string const&>(r));
+ }
+#endif
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/Source/kwsys/System.c b/Source/kwsys/System.c
new file mode 100644
index 0000000..ccc7e81
--- /dev/null
+++ b/Source/kwsys/System.c
@@ -0,0 +1,301 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(System.h)
+
+/* Work-around CMake dependency scanning limitation. This must
+ duplicate the above list of headers. */
+#if 0
+# include "System.h.in"
+#endif
+
+#include <stddef.h> /* ptrdiff_t */
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* memcpy */
+#include <ctype.h> /* isspace */
+
+#include <stdio.h>
+
+#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T
+typedef ptrdiff_t kwsysSystem_ptrdiff_t;
+#else
+typedef int kwsysSystem_ptrdiff_t;
+#endif
+
+/*--------------------------------------------------------------------------*/
+static int kwsysSystem__AppendByte(char* local,
+ char** begin, char** end,
+ int* size, char c)
+{
+ /* Allocate space for the character. */
+ if((*end - *begin) >= *size)
+ {
+ kwsysSystem_ptrdiff_t length = *end - *begin;
+ char* newBuffer = (char*)malloc((size_t)(*size*2));
+ if(!newBuffer)
+ {
+ return 0;
+ }
+ memcpy(newBuffer, *begin, (size_t)(length)*sizeof(char));
+ if(*begin != local)
+ {
+ free(*begin);
+ }
+ *begin = newBuffer;
+ *end = *begin + length;
+ *size *= 2;
+ }
+
+ /* Store the character. */
+ *(*end)++ = c;
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysSystem__AppendArgument(char** local,
+ char*** begin, char*** end,
+ int* size,
+ char* arg_local,
+ char** arg_begin, char** arg_end,
+ int* arg_size)
+{
+ /* Append a null-terminator to the argument string. */
+ if(!kwsysSystem__AppendByte(arg_local, arg_begin, arg_end, arg_size, '\0'))
+ {
+ return 0;
+ }
+
+ /* Allocate space for the argument pointer. */
+ if((*end - *begin) >= *size)
+ {
+ kwsysSystem_ptrdiff_t length = *end - *begin;
+ char** newPointers = (char**)malloc((size_t)(*size)*2*sizeof(char*));
+ if(!newPointers)
+ {
+ return 0;
+ }
+ memcpy(newPointers, *begin, (size_t)(length)*sizeof(char*));
+ if(*begin != local)
+ {
+ free(*begin);
+ }
+ *begin = newPointers;
+ *end = *begin + length;
+ *size *= 2;
+ }
+
+ /* Allocate space for the argument string. */
+ **end = (char*)malloc((size_t)(*arg_end - *arg_begin));
+ if(!**end)
+ {
+ return 0;
+ }
+
+ /* Store the argument in the command array. */
+ memcpy(**end, *arg_begin,(size_t)(*arg_end - *arg_begin));
+ ++(*end);
+
+ /* Reset the argument to be empty. */
+ *arg_end = *arg_begin;
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+#define KWSYSPE_LOCAL_BYTE_COUNT 1024
+#define KWSYSPE_LOCAL_ARGS_COUNT 32
+static char** kwsysSystem__ParseUnixCommand(const char* command, int flags)
+{
+ /* Create a buffer for argument pointers during parsing. */
+ char* local_pointers[KWSYSPE_LOCAL_ARGS_COUNT];
+ int pointers_size = KWSYSPE_LOCAL_ARGS_COUNT;
+ char** pointer_begin = local_pointers;
+ char** pointer_end = pointer_begin;
+
+ /* Create a buffer for argument strings during parsing. */
+ char local_buffer[KWSYSPE_LOCAL_BYTE_COUNT];
+ int buffer_size = KWSYSPE_LOCAL_BYTE_COUNT;
+ char* buffer_begin = local_buffer;
+ char* buffer_end = buffer_begin;
+
+ /* Parse the command string. Try to behave like a UNIX shell. */
+ char** newCommand = 0;
+ const char* c = command;
+ int in_argument = 0;
+ int in_escape = 0;
+ int in_single = 0;
+ int in_double = 0;
+ int failed = 0;
+ for(;*c; ++c)
+ {
+ if(in_escape)
+ {
+ /* This character is escaped so do no special handling. */
+ if(!in_argument)
+ {
+ in_argument = 1;
+ }
+ if(!kwsysSystem__AppendByte(local_buffer, &buffer_begin,
+ &buffer_end, &buffer_size, *c))
+ {
+ failed = 1;
+ break;
+ }
+ in_escape = 0;
+ }
+ else if(*c == '\\')
+ {
+ /* The next character should be escaped. */
+ in_escape = 1;
+ }
+ else if(*c == '\'' && !in_double)
+ {
+ /* Enter or exit single-quote state. */
+ if(in_single)
+ {
+ in_single = 0;
+ }
+ else
+ {
+ in_single = 1;
+ if(!in_argument)
+ {
+ in_argument = 1;
+ }
+ }
+ }
+ else if(*c == '"' && !in_single)
+ {
+ /* Enter or exit double-quote state. */
+ if(in_double)
+ {
+ in_double = 0;
+ }
+ else
+ {
+ in_double = 1;
+ if(!in_argument)
+ {
+ in_argument = 1;
+ }
+ }
+ }
+ else if(isspace((unsigned char) *c))
+ {
+ if(in_argument)
+ {
+ if(in_single || in_double)
+ {
+ /* This space belongs to a quoted argument. */
+ if(!kwsysSystem__AppendByte(local_buffer, &buffer_begin,
+ &buffer_end, &buffer_size, *c))
+ {
+ failed = 1;
+ break;
+ }
+ }
+ else
+ {
+ /* This argument has been terminated by whitespace. */
+ if(!kwsysSystem__AppendArgument(local_pointers, &pointer_begin,
+ &pointer_end, &pointers_size,
+ local_buffer, &buffer_begin,
+ &buffer_end, &buffer_size))
+ {
+ failed = 1;
+ break;
+ }
+ in_argument = 0;
+ }
+ }
+ }
+ else
+ {
+ /* This character belong to an argument. */
+ if(!in_argument)
+ {
+ in_argument = 1;
+ }
+ if(!kwsysSystem__AppendByte(local_buffer, &buffer_begin,
+ &buffer_end, &buffer_size, *c))
+ {
+ failed = 1;
+ break;
+ }
+ }
+ }
+
+ /* Finish the last argument. */
+ if(in_argument)
+ {
+ if(!kwsysSystem__AppendArgument(local_pointers, &pointer_begin,
+ &pointer_end, &pointers_size,
+ local_buffer, &buffer_begin,
+ &buffer_end, &buffer_size))
+ {
+ failed = 1;
+ }
+ }
+
+ /* If we still have memory allocate space for the new command
+ buffer. */
+ if(!failed)
+ {
+ kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin;
+ newCommand = (char**)malloc((size_t)(n+1)*sizeof(char*));
+ }
+
+ if(newCommand)
+ {
+ /* Copy the arguments into the new command buffer. */
+ kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin;
+ memcpy(newCommand, pointer_begin, sizeof(char*)*(size_t)(n));
+ newCommand[n] = 0;
+ }
+ else
+ {
+ /* Free arguments already allocated. */
+ while(pointer_end != pointer_begin)
+ {
+ free(*(--pointer_end));
+ }
+ }
+
+ /* Free temporary buffers. */
+ if(pointer_begin != local_pointers)
+ {
+ free(pointer_begin);
+ }
+ if(buffer_begin != local_buffer)
+ {
+ free(buffer_begin);
+ }
+
+ /* The flags argument is currently unused. */
+ (void)flags;
+
+ /* Return the final command buffer. */
+ return newCommand;
+}
+
+/*--------------------------------------------------------------------------*/
+char** kwsysSystem_Parse_CommandForUnix(const char* command, int flags)
+{
+ /* Validate the flags. */
+ if(flags != 0)
+ {
+ return 0;
+ }
+
+ /* Forward to our internal implementation. */
+ return kwsysSystem__ParseUnixCommand(command, flags);
+}
diff --git a/Source/kwsys/System.h.in b/Source/kwsys/System.h.in
new file mode 100644
index 0000000..3f3d3f4
--- /dev/null
+++ b/Source/kwsys/System.h.in
@@ -0,0 +1,69 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_System_h
+#define @KWSYS_NAMESPACE@_System_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+/* Redefine all public interface symbol names to be in the proper
+ namespace. These macros are used internally to kwsys only, and are
+ not visible to user code. Use kwsysHeaderDump.pl to reproduce
+ these macros after making changes to the interface. */
+#if !defined(KWSYS_NAMESPACE)
+# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# define kwsysSystem_Parse_CommandForUnix kwsys_ns(System_Parse_CommandForUnix)
+#endif
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/**
+ * Parse a unix-style command line string into separate arguments.
+ *
+ * On success, returns a pointer to an array of pointers to individual
+ * argument strings. Each string is null-terminated and the last
+ * entry in the array is a NULL pointer (just like argv). It is the
+ * caller's responsibility to free() the strings and the array of
+ * pointers to them.
+ *
+ * On failure, returns NULL. Failure occurs only on invalid flags or
+ * when memory cannot be allocated; never due to content of the input
+ * string. Missing close-quotes are treated as if the necessary
+ * closing quote appears.
+ *
+ * By default single- and double-quoted arguments are supported, and
+ * any character may be escaped by a backslash. The flags argument is
+ * reserved for future use, and must be zero (or the call will fail).
+ */
+kwsysEXPORT char** kwsysSystem_Parse_CommandForUnix(const char* command,
+ int flags);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+ Otherwise, undefine them to keep the namespace clean. */
+#if !defined(KWSYS_NAMESPACE)
+# undef kwsys_ns
+# undef kwsysEXPORT
+# if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# undef kwsysSystem_Parse_CommandForUnix
+# endif
+#endif
+
+#endif
diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx
new file mode 100644
index 0000000..81fb2f9
--- /dev/null
+++ b/Source/kwsys/SystemInformation.cxx
@@ -0,0 +1,5489 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#if defined(_WIN32)
+# define NOMINMAX // use our min,max
+# if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300)
+# define _WIN32_WINNT 0x0501
+# endif
+# include <winsock.h> // WSADATA, include before sys/types.h
+#endif
+
+#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
+# define _GNU_SOURCE
+#endif
+
+// TODO:
+// We need an alternative implementation for many functions in this file
+// when USE_ASM_INSTRUCTIONS gets defined as 0.
+//
+// Consider using these on Win32/Win64 for some of them:
+//
+// IsProcessorFeaturePresent
+// http://msdn.microsoft.com/en-us/library/ms724482(VS.85).aspx
+//
+// GetProcessMemoryInfo
+// http://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx
+
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(SystemInformation.hxx)
+#include KWSYS_HEADER(Process.h)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "SystemInformation.hxx.in"
+# include "Process.h.in"
+#endif
+
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#if defined(_WIN32)
+# include <windows.h>
+# if defined(_MSC_VER) && _MSC_VER >= 1800
+# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+# endif
+# include <errno.h>
+# if defined(KWSYS_SYS_HAS_PSAPI)
+# include <psapi.h>
+# endif
+# if !defined(siginfo_t)
+typedef int siginfo_t;
+# endif
+#else
+# include <sys/types.h>
+# include <sys/time.h>
+# include <sys/utsname.h> // int uname(struct utsname *buf);
+# include <sys/resource.h> // getrlimit
+# include <unistd.h>
+# include <signal.h>
+# include <fcntl.h>
+# include <errno.h> // extern int errno;
+#endif
+
+#if defined (__CYGWIN__) && !defined(_WIN32)
+# include <windows.h>
+# undef _WIN32
+#endif
+
+#ifdef __FreeBSD__
+# include <sys/sysctl.h>
+# include <fenv.h>
+# include <sys/socket.h>
+# include <netdb.h>
+# include <netinet/in.h>
+# if defined(KWSYS_SYS_HAS_IFADDRS_H)
+# include <ifaddrs.h>
+# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
+# endif
+#endif
+
+#if defined(__OpenBSD__) || defined(__NetBSD__)
+# include <sys/param.h>
+# include <sys/sysctl.h>
+#endif
+
+#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H)
+# include <machine/cpu.h>
+#endif
+
+#if defined(__DragonFly__)
+# include <sys/sysctl.h>
+#endif
+
+#ifdef __APPLE__
+# include <sys/sysctl.h>
+# include <mach/vm_statistics.h>
+# include <mach/host_info.h>
+# include <mach/mach.h>
+# include <mach/mach_types.h>
+# include <fenv.h>
+# include <sys/socket.h>
+# include <netdb.h>
+# include <netinet/in.h>
+# if defined(KWSYS_SYS_HAS_IFADDRS_H)
+# include <ifaddrs.h>
+# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
+# endif
+# if !(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0 >= 1050)
+# undef KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE
+# endif
+#endif
+
+#ifdef __linux
+# include <fenv.h>
+# include <sys/socket.h>
+# include <netdb.h>
+# include <netinet/in.h>
+# if defined(KWSYS_SYS_HAS_IFADDRS_H)
+# include <ifaddrs.h>
+# if !defined(__LSB_VERSION__) /* LSB has no getifaddrs */
+# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
+# endif
+# endif
+# if defined(KWSYS_CXX_HAS_RLIMIT64)
+typedef struct rlimit64 ResourceLimitType;
+# define GetResourceLimit getrlimit64
+# else
+typedef struct rlimit ResourceLimitType;
+# define GetResourceLimit getrlimit
+# endif
+#elif defined( __hpux )
+# include <sys/param.h>
+# include <sys/pstat.h>
+# if defined(KWSYS_SYS_HAS_MPCTL_H)
+# include <sys/mpctl.h>
+# endif
+#endif
+
+#ifdef __HAIKU__
+# include <OS.h>
+#endif
+
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
+# include <execinfo.h>
+# if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
+# include <cxxabi.h>
+# endif
+# if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
+# include <dlfcn.h>
+# endif
+#else
+# undef KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE
+# undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP
+#endif
+
+#include <memory.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h> // int isdigit(int c);
+
+#if defined(KWSYS_USE_LONG_LONG)
+# if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG)
+# define iostreamLongLong(x) (x)
+# else
+# define iostreamLongLong(x) ((long)(x))
+# endif
+#elif defined(KWSYS_USE___INT64)
+# if defined(KWSYS_IOS_HAS_OSTREAM___INT64)
+# define iostreamLongLong(x) (x)
+# else
+# define iostreamLongLong(x) ((long)(x))
+# endif
+#else
+# error "No Long Long"
+#endif
+
+#if defined(KWSYS_CXX_HAS_ATOLL)
+# define atoLongLong atoll
+#else
+# if defined(KWSYS_CXX_HAS__ATOI64)
+# define atoLongLong _atoi64
+# elif defined(KWSYS_CXX_HAS_ATOL)
+# define atoLongLong atol
+# else
+# define atoLongLong atoi
+# endif
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) && !defined(__clang__)
+#define USE_ASM_INSTRUCTIONS 1
+#else
+#define USE_ASM_INSTRUCTIONS 0
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__)
+#include <intrin.h>
+#define USE_CPUID_INTRINSICS 1
+#else
+#define USE_CPUID_INTRINSICS 0
+#endif
+
+#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS || defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
+# define USE_CPUID 1
+#else
+# define USE_CPUID 0
+#endif
+
+#if USE_CPUID
+
+#define CPUID_AWARE_COMPILER
+
+/**
+ * call CPUID instruction
+ *
+ * Will return false if the instruction failed.
+ */
+static bool call_cpuid(int select, int result[4])
+{
+#if USE_CPUID_INTRINSICS
+ __cpuid(result, select);
+ return true;
+#else
+ int tmp[4];
+#if defined(_MSC_VER)
+ // Use SEH to determine CPUID presence
+ __try {
+ _asm {
+#ifdef CPUID_AWARE_COMPILER
+ ; we must push/pop the registers <<CPUID>> writes to, as the
+ ; optimiser does not know about <<CPUID>>, and so does not expect
+ ; these registers to change.
+ push eax
+ push ebx
+ push ecx
+ push edx
+#endif
+ ; <<CPUID>>
+ mov eax, select
+#ifdef CPUID_AWARE_COMPILER
+ cpuid
+#else
+ _asm _emit 0x0f
+ _asm _emit 0xa2
+#endif
+ mov tmp[0 * TYPE int], eax
+ mov tmp[1 * TYPE int], ebx
+ mov tmp[2 * TYPE int], ecx
+ mov tmp[3 * TYPE int], edx
+
+#ifdef CPUID_AWARE_COMPILER
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+#endif
+ }
+ }
+ __except(1)
+ {
+ return false;
+ }
+
+ memcpy(result, tmp, sizeof(tmp));
+#elif defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
+ unsigned int a, b, c, d;
+ __asm {
+ mov EAX, select;
+ cpuid
+ mov a, EAX;
+ mov b, EBX;
+ mov c, ECX;
+ mov d, EDX;
+ }
+
+ result[0] = a;
+ result[1] = b;
+ result[2] = c;
+ result[3] = d;
+#endif
+
+ // The cpuid instruction succeeded.
+ return true;
+#endif
+}
+#endif
+
+
+namespace KWSYS_NAMESPACE
+{
+template<typename T>
+T min(T a, T b){ return a<b ? a : b; }
+
+extern "C" { typedef void (*SigAction)(int,siginfo_t*,void*); }
+
+// Define SystemInformationImplementation class
+typedef void (*DELAY_FUNC)(unsigned int uiMS);
+
+class SystemInformationImplementation
+{
+public:
+ typedef SystemInformation::LongLong LongLong;
+ SystemInformationImplementation ();
+ ~SystemInformationImplementation ();
+
+ const char * GetVendorString();
+ const char * GetVendorID();
+ std::string GetTypeID();
+ std::string GetFamilyID();
+ std::string GetModelID();
+ std::string GetModelName();
+ std::string GetSteppingCode();
+ const char * GetExtendedProcessorName();
+ const char * GetProcessorSerialNumber();
+ int GetProcessorCacheSize();
+ unsigned int GetLogicalProcessorsPerPhysical();
+ float GetProcessorClockFrequency();
+ int GetProcessorAPICID();
+ int GetProcessorCacheXSize(long int);
+ bool DoesCPUSupportFeature(long int);
+
+ const char * GetOSName();
+ const char * GetHostname();
+ int GetFullyQualifiedDomainName(std::string &fqdn);
+ const char * GetOSRelease();
+ const char * GetOSVersion();
+ const char * GetOSPlatform();
+
+ bool Is64Bits();
+
+ unsigned int GetNumberOfLogicalCPU(); // per physical cpu
+ unsigned int GetNumberOfPhysicalCPU();
+
+ bool DoesCPUSupportCPUID();
+
+ // Retrieve memory information in megabyte.
+ size_t GetTotalVirtualMemory();
+ size_t GetAvailableVirtualMemory();
+ size_t GetTotalPhysicalMemory();
+ size_t GetAvailablePhysicalMemory();
+
+ LongLong GetProcessId();
+
+ // Retrieve memory information in kib
+ LongLong GetHostMemoryTotal();
+ LongLong GetHostMemoryAvailable(const char *envVarName);
+ LongLong GetHostMemoryUsed();
+
+ LongLong GetProcMemoryAvailable(
+ const char *hostLimitEnvVarName,
+ const char *procLimitEnvVarName);
+ LongLong GetProcMemoryUsed();
+
+ double GetLoadAverage();
+
+ // enable/disable stack trace signal handler.
+ static
+ void SetStackTraceOnError(int enable);
+
+ // get current stack
+ static
+ std::string GetProgramStack(int firstFrame, int wholePath);
+
+ /** Run the different checks */
+ void RunCPUCheck();
+ void RunOSCheck();
+ void RunMemoryCheck();
+
+public:
+ typedef struct tagID
+ {
+ int Type;
+ int Family;
+ int Model;
+ int Revision;
+ int ExtendedFamily;
+ int ExtendedModel;
+ std::string ProcessorName;
+ std::string Vendor;
+ std::string SerialNumber;
+ std::string ModelName;
+ } ID;
+
+ typedef struct tagCPUPowerManagement
+ {
+ bool HasVoltageID;
+ bool HasFrequencyID;
+ bool HasTempSenseDiode;
+ } CPUPowerManagement;
+
+ typedef struct tagCPUExtendedFeatures
+ {
+ bool Has3DNow;
+ bool Has3DNowPlus;
+ bool SupportsMP;
+ bool HasMMXPlus;
+ bool HasSSEMMX;
+ bool SupportsHyperthreading;
+ unsigned int LogicalProcessorsPerPhysical;
+ int APIC_ID;
+ CPUPowerManagement PowerManagement;
+ } CPUExtendedFeatures;
+
+ typedef struct CPUtagFeatures
+ {
+ bool HasFPU;
+ bool HasTSC;
+ bool HasMMX;
+ bool HasSSE;
+ bool HasSSEFP;
+ bool HasSSE2;
+ bool HasIA64;
+ bool HasAPIC;
+ bool HasCMOV;
+ bool HasMTRR;
+ bool HasACPI;
+ bool HasSerial;
+ bool HasThermal;
+ int CPUSpeed;
+ int L1CacheSize;
+ int L2CacheSize;
+ int L3CacheSize;
+ CPUExtendedFeatures ExtendedFeatures;
+ } CPUFeatures;
+
+ enum Manufacturer
+ {
+ AMD, Intel, NSC, UMC, Cyrix, NexGen, IDT, Rise, Transmeta, Sun, IBM,
+ Motorola, HP, UnknownManufacturer
+ };
+
+protected:
+ // For windows
+ bool RetrieveCPUFeatures();
+ bool RetrieveCPUIdentity();
+ bool RetrieveCPUCacheDetails();
+ bool RetrieveClassicalCPUCacheDetails();
+ bool RetrieveCPUClockSpeed();
+ bool RetrieveClassicalCPUClockSpeed();
+ bool RetrieveCPUExtendedLevelSupport(int);
+ bool RetrieveExtendedCPUFeatures();
+ bool RetrieveProcessorSerialNumber();
+ bool RetrieveCPUPowerManagement();
+ bool RetrieveClassicalCPUIdentity();
+ bool RetrieveExtendedCPUIdentity();
+
+ // Processor information
+ Manufacturer ChipManufacturer;
+ CPUFeatures Features;
+ ID ChipID;
+ float CPUSpeedInMHz;
+ unsigned int NumberOfLogicalCPU;
+ unsigned int NumberOfPhysicalCPU;
+
+ int CPUCount(); // For windows
+ unsigned char LogicalCPUPerPhysicalCPU();
+ unsigned char GetAPICId(); // For windows
+ bool IsHyperThreadingSupported();
+ static LongLong GetCyclesDifference(DELAY_FUNC, unsigned int); // For windows
+
+ // For Linux and Cygwin, /proc/cpuinfo formats are slightly different
+ bool RetreiveInformationFromCpuInfoFile();
+ std::string ExtractValueFromCpuInfoFile(std::string buffer,
+ const char* word, size_t init=0);
+
+ bool QueryLinuxMemory();
+ bool QueryCygwinMemory();
+
+ static void Delay (unsigned int);
+ static void DelayOverhead (unsigned int);
+
+ void FindManufacturer(const std::string &family = "");
+
+ // For Mac
+ bool ParseSysCtl();
+ int CallSwVers(const char *arg, std::string &ver);
+ void TrimNewline(std::string&);
+ std::string ExtractValueFromSysCtl(const char* word);
+ std::string SysCtlBuffer;
+
+ // For Solaris
+ bool QuerySolarisMemory();
+ bool QuerySolarisProcessor();
+ std::string ParseValueFromKStat(const char* arguments);
+ std::string RunProcess(std::vector<const char*> args);
+
+ //For Haiku OS
+ bool QueryHaikuInfo();
+
+ //For QNX
+ bool QueryQNXMemory();
+ bool QueryQNXProcessor();
+
+ //For OpenBSD, FreeBSD, NetBSD, DragonFly
+ bool QueryBSDMemory();
+ bool QueryBSDProcessor();
+
+ //For HP-UX
+ bool QueryHPUXMemory();
+ bool QueryHPUXProcessor();
+
+ //For Microsoft Windows
+ bool QueryWindowsMemory();
+
+ //For AIX
+ bool QueryAIXMemory();
+
+ bool QueryProcessorBySysconf();
+ bool QueryProcessor();
+
+ // Evaluate the memory information.
+ bool QueryMemoryBySysconf();
+ bool QueryMemory();
+ size_t TotalVirtualMemory;
+ size_t AvailableVirtualMemory;
+ size_t TotalPhysicalMemory;
+ size_t AvailablePhysicalMemory;
+
+ size_t CurrentPositionInFile;
+
+ // Operating System information
+ bool QueryOSInformation();
+ std::string OSName;
+ std::string Hostname;
+ std::string OSRelease;
+ std::string OSVersion;
+ std::string OSPlatform;
+};
+
+
+SystemInformation::SystemInformation()
+{
+ this->Implementation = new SystemInformationImplementation;
+}
+
+SystemInformation::~SystemInformation()
+{
+ delete this->Implementation;
+}
+
+const char * SystemInformation::GetVendorString()
+{
+ return this->Implementation->GetVendorString();
+}
+
+const char * SystemInformation::GetVendorID()
+{
+ return this->Implementation->GetVendorID();
+}
+
+std::string SystemInformation::GetTypeID()
+{
+ return this->Implementation->GetTypeID();
+}
+
+std::string SystemInformation::GetFamilyID()
+{
+ return this->Implementation->GetFamilyID();
+}
+
+std::string SystemInformation::GetModelID()
+{
+ return this->Implementation->GetModelID();
+}
+
+std::string SystemInformation::GetModelName()
+{
+ return this->Implementation->GetModelName();
+}
+
+std::string SystemInformation::GetSteppingCode()
+{
+ return this->Implementation->GetSteppingCode();
+}
+
+const char * SystemInformation::GetExtendedProcessorName()
+{
+ return this->Implementation->GetExtendedProcessorName();
+}
+
+const char * SystemInformation::GetProcessorSerialNumber()
+{
+ return this->Implementation->GetProcessorSerialNumber();
+}
+
+int SystemInformation::GetProcessorCacheSize()
+{
+ return this->Implementation->GetProcessorCacheSize();
+}
+
+unsigned int SystemInformation::GetLogicalProcessorsPerPhysical()
+{
+ return this->Implementation->GetLogicalProcessorsPerPhysical();
+}
+
+float SystemInformation::GetProcessorClockFrequency()
+{
+ return this->Implementation->GetProcessorClockFrequency();
+}
+
+int SystemInformation::GetProcessorAPICID()
+{
+ return this->Implementation->GetProcessorAPICID();
+}
+
+int SystemInformation::GetProcessorCacheXSize(long int l)
+{
+ return this->Implementation->GetProcessorCacheXSize(l);
+}
+
+bool SystemInformation::DoesCPUSupportFeature(long int i)
+{
+ return this->Implementation->DoesCPUSupportFeature(i);
+}
+
+std::string SystemInformation::GetCPUDescription()
+{
+ std::ostringstream oss;
+ oss
+ << this->GetNumberOfPhysicalCPU()
+ << " core ";
+ if (this->GetModelName().empty())
+ {
+ oss
+ << this->GetProcessorClockFrequency()
+ << " MHz "
+ << this->GetVendorString()
+ << " "
+ << this->GetExtendedProcessorName();
+ }
+ else
+ {
+ oss << this->GetModelName();
+ }
+
+ // remove extra spaces
+ std::string tmp=oss.str();
+ size_t pos;
+ while( (pos=tmp.find(" "))!=std::string::npos)
+ {
+ tmp.replace(pos,2," ");
+ }
+
+ return tmp;
+}
+
+const char * SystemInformation::GetOSName()
+{
+ return this->Implementation->GetOSName();
+}
+
+const char * SystemInformation::GetHostname()
+{
+ return this->Implementation->GetHostname();
+}
+
+std::string SystemInformation::GetFullyQualifiedDomainName()
+{
+ std::string fqdn;
+ this->Implementation->GetFullyQualifiedDomainName(fqdn);
+ return fqdn;
+}
+
+const char * SystemInformation::GetOSRelease()
+{
+ return this->Implementation->GetOSRelease();
+}
+
+const char * SystemInformation::GetOSVersion()
+{
+ return this->Implementation->GetOSVersion();
+}
+
+const char * SystemInformation::GetOSPlatform()
+{
+ return this->Implementation->GetOSPlatform();
+}
+
+int SystemInformation::GetOSIsWindows()
+{
+#if defined(_WIN32)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+int SystemInformation::GetOSIsLinux()
+{
+#if defined(__linux)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+int SystemInformation::GetOSIsApple()
+{
+#if defined(__APPLE__)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+std::string SystemInformation::GetOSDescription()
+{
+ std::ostringstream oss;
+ oss
+ << this->GetOSName()
+ << " "
+ << this->GetOSRelease()
+ << " "
+ << this->GetOSVersion();
+
+ return oss.str();
+}
+
+bool SystemInformation::Is64Bits()
+{
+ return this->Implementation->Is64Bits();
+}
+
+unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu
+{
+ return this->Implementation->GetNumberOfLogicalCPU();
+}
+
+unsigned int SystemInformation::GetNumberOfPhysicalCPU()
+{
+ return this->Implementation->GetNumberOfPhysicalCPU();
+}
+
+bool SystemInformation::DoesCPUSupportCPUID()
+{
+ return this->Implementation->DoesCPUSupportCPUID();
+}
+
+// Retrieve memory information in megabyte.
+size_t SystemInformation::GetTotalVirtualMemory()
+{
+ return this->Implementation->GetTotalVirtualMemory();
+}
+
+size_t SystemInformation::GetAvailableVirtualMemory()
+{
+ return this->Implementation->GetAvailableVirtualMemory();
+}
+
+size_t SystemInformation::GetTotalPhysicalMemory()
+{
+ return this->Implementation->GetTotalPhysicalMemory();
+}
+
+size_t SystemInformation::GetAvailablePhysicalMemory()
+{
+ return this->Implementation->GetAvailablePhysicalMemory();
+}
+
+std::string SystemInformation::GetMemoryDescription(
+ const char *hostLimitEnvVarName,
+ const char *procLimitEnvVarName)
+{
+ std::ostringstream oss;
+ oss
+ << "Host Total: "
+ << iostreamLongLong(this->GetHostMemoryTotal())
+ << " KiB, Host Available: "
+ << iostreamLongLong(this->GetHostMemoryAvailable(hostLimitEnvVarName))
+ << " KiB, Process Available: "
+ << iostreamLongLong(
+ this->GetProcMemoryAvailable(hostLimitEnvVarName,procLimitEnvVarName))
+ << " KiB";
+ return oss.str();
+}
+
+// host memory info in units of KiB.
+SystemInformation::LongLong SystemInformation::GetHostMemoryTotal()
+{
+ return this->Implementation->GetHostMemoryTotal();
+}
+
+SystemInformation::LongLong
+SystemInformation::GetHostMemoryAvailable(const char *hostLimitEnvVarName)
+{
+ return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName);
+}
+
+SystemInformation::LongLong SystemInformation::GetHostMemoryUsed()
+{
+ return this->Implementation->GetHostMemoryUsed();
+}
+
+// process memory info in units of KiB.
+SystemInformation::LongLong
+SystemInformation::GetProcMemoryAvailable(
+ const char *hostLimitEnvVarName,
+ const char *procLimitEnvVarName)
+{
+ return this->Implementation->GetProcMemoryAvailable(
+ hostLimitEnvVarName,
+ procLimitEnvVarName);
+}
+
+SystemInformation::LongLong SystemInformation::GetProcMemoryUsed()
+{
+ return this->Implementation->GetProcMemoryUsed();
+}
+
+double SystemInformation::GetLoadAverage()
+{
+ return this->Implementation->GetLoadAverage();
+}
+
+SystemInformation::LongLong SystemInformation::GetProcessId()
+{
+ return this->Implementation->GetProcessId();
+}
+
+void SystemInformation::SetStackTraceOnError(int enable)
+{
+ SystemInformationImplementation::SetStackTraceOnError(enable);
+}
+
+std::string SystemInformation::GetProgramStack(int firstFrame, int wholePath)
+{
+ return SystemInformationImplementation::GetProgramStack(firstFrame, wholePath);
+}
+
+/** Run the different checks */
+void SystemInformation::RunCPUCheck()
+{
+ this->Implementation->RunCPUCheck();
+}
+
+void SystemInformation::RunOSCheck()
+{
+ this->Implementation->RunOSCheck();
+}
+
+void SystemInformation::RunMemoryCheck()
+{
+ this->Implementation->RunMemoryCheck();
+}
+
+
+// --------------------------------------------------------------
+// SystemInformationImplementation starts here
+
+#define STORE_TLBCACHE_INFO(x,y) x = (x < (y)) ? (y) : x
+#define TLBCACHE_INFO_UNITS (15)
+#define CLASSICAL_CPU_FREQ_LOOP 10000000
+#define RDTSC_INSTRUCTION _asm _emit 0x0f _asm _emit 0x31
+
+#define MMX_FEATURE 0x00000001
+#define MMX_PLUS_FEATURE 0x00000002
+#define SSE_FEATURE 0x00000004
+#define SSE2_FEATURE 0x00000008
+#define AMD_3DNOW_FEATURE 0x00000010
+#define AMD_3DNOW_PLUS_FEATURE 0x00000020
+#define IA64_FEATURE 0x00000040
+#define MP_CAPABLE 0x00000080
+#define HYPERTHREAD_FEATURE 0x00000100
+#define SERIALNUMBER_FEATURE 0x00000200
+#define APIC_FEATURE 0x00000400
+#define SSE_FP_FEATURE 0x00000800
+#define SSE_MMX_FEATURE 0x00001000
+#define CMOV_FEATURE 0x00002000
+#define MTRR_FEATURE 0x00004000
+#define L1CACHE_FEATURE 0x00008000
+#define L2CACHE_FEATURE 0x00010000
+#define L3CACHE_FEATURE 0x00020000
+#define ACPI_FEATURE 0x00040000
+#define THERMALMONITOR_FEATURE 0x00080000
+#define TEMPSENSEDIODE_FEATURE 0x00100000
+#define FREQUENCYID_FEATURE 0x00200000
+#define VOLTAGEID_FREQUENCY 0x00400000
+
+// Status Flag
+#define HT_NOT_CAPABLE 0
+#define HT_ENABLED 1
+#define HT_DISABLED 2
+#define HT_SUPPORTED_NOT_ENABLED 3
+#define HT_CANNOT_DETECT 4
+
+// EDX[28] Bit 28 is set if HT is supported
+#define HT_BIT 0x10000000
+
+// EAX[11:8] Bit 8-11 contains family processor ID.
+#define FAMILY_ID 0x0F00
+#define PENTIUM4_ID 0x0F00
+// EAX[23:20] Bit 20-23 contains extended family processor ID
+#define EXT_FAMILY_ID 0x0F00000
+// EBX[23:16] Bit 16-23 in ebx contains the number of logical
+#define NUM_LOGICAL_BITS 0x00FF0000
+// processors per physical processor when execute cpuid with
+// eax set to 1
+// EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique
+#define INITIAL_APIC_ID_BITS 0xFF000000
+// initial APIC ID for the processor this code is running on.
+// Default value = 0xff if HT is not supported
+
+// Hide implementation details in an anonymous namespace.
+namespace {
+// *****************************************************************************
+#if defined(__linux) || defined(__APPLE__)
+int LoadLines(
+ FILE *file,
+ std::vector<std::string> &lines)
+{
+ // Load each line in the given file into a the vector.
+ int nRead=0;
+ const int bufSize=1024;
+ char buf[bufSize]={'\0'};
+ while (!feof(file) && !ferror(file))
+ {
+ errno=0;
+ if (fgets(buf,bufSize,file) == 0)
+ {
+ if (ferror(file) && (errno==EINTR))
+ {
+ clearerr(file);
+ }
+ continue;
+ }
+ char *pBuf=buf;
+ while(*pBuf)
+ {
+ if (*pBuf=='\n') *pBuf='\0';
+ pBuf+=1;
+ }
+ lines.push_back(buf);
+ ++nRead;
+ }
+ if (ferror(file))
+ {
+ return 0;
+ }
+ return nRead;
+}
+
+# if defined(__linux)
+// *****************************************************************************
+int LoadLines(
+ const char *fileName,
+ std::vector<std::string> &lines)
+{
+ FILE *file=fopen(fileName,"r");
+ if (file==0)
+ {
+ return 0;
+ }
+ int nRead=LoadLines(file,lines);
+ fclose(file);
+ return nRead;
+}
+# endif
+
+// ****************************************************************************
+template<typename T>
+int NameValue(
+ std::vector<std::string> &lines,
+ std::string name, T &value)
+{
+ size_t nLines=lines.size();
+ for (size_t i=0; i<nLines; ++i)
+ {
+ size_t at=lines[i].find(name);
+ if (at==std::string::npos)
+ {
+ continue;
+ }
+ std::istringstream is(lines[i].substr(at+name.size()));
+ is >> value;
+ return 0;
+ }
+ return -1;
+}
+#endif
+
+#if defined(__linux)
+// ****************************************************************************
+template<typename T>
+int GetFieldsFromFile(
+ const char *fileName,
+ const char **fieldNames,
+ T *values)
+{
+ std::vector<std::string> fields;
+ if (!LoadLines(fileName,fields))
+ {
+ return -1;
+ }
+ int i=0;
+ while (fieldNames[i]!=NULL)
+ {
+ int ierr=NameValue(fields,fieldNames[i],values[i]);
+ if (ierr)
+ {
+ return -(i+2);
+ }
+ i+=1;
+ }
+ return 0;
+}
+
+// ****************************************************************************
+template<typename T>
+int GetFieldFromFile(
+ const char *fileName,
+ const char *fieldName,
+ T &value)
+{
+ const char *fieldNames[2]={fieldName,NULL};
+ T values[1]={T(0)};
+ int ierr=GetFieldsFromFile(fileName,fieldNames,values);
+ if (ierr)
+ {
+ return ierr;
+ }
+ value=values[0];
+ return 0;
+}
+#endif
+
+// ****************************************************************************
+#if defined(__APPLE__)
+template<typename T>
+int GetFieldsFromCommand(
+ const char *command,
+ const char **fieldNames,
+ T *values)
+{
+ FILE *file=popen(command,"r");
+ if (file==0)
+ {
+ return -1;
+ }
+ std::vector<std::string> fields;
+ int nl=LoadLines(file,fields);
+ pclose(file);
+ if (nl==0)
+ {
+ return -1;
+ }
+ int i=0;
+ while (fieldNames[i]!=NULL)
+ {
+ int ierr=NameValue(fields,fieldNames[i],values[i]);
+ if (ierr)
+ {
+ return -(i+2);
+ }
+ i+=1;
+ }
+ return 0;
+}
+#endif
+
+// ****************************************************************************
+#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
+void StacktraceSignalHandler(
+ int sigNo,
+ siginfo_t *sigInfo,
+ void * /*sigContext*/)
+{
+#if defined(__linux) || defined(__APPLE__)
+ std::ostringstream oss;
+ oss
+ << std::endl
+ << "=========================================================" << std::endl
+ << "Process id " << getpid() << " ";
+ switch (sigNo)
+ {
+ case SIGINT:
+ oss << "Caught SIGINT";
+ break;
+
+ case SIGTERM:
+ oss << "Caught SIGTERM";
+ break;
+
+ case SIGABRT:
+ oss << "Caught SIGABRT";
+ break;
+
+ case SIGFPE:
+ oss
+ << "Caught SIGFPE at "
+ << (sigInfo->si_addr==0?"0x":"")
+ << sigInfo->si_addr
+ << " ";
+ switch (sigInfo->si_code)
+ {
+# if defined(FPE_INTDIV)
+ case FPE_INTDIV:
+ oss << "integer division by zero";
+ break;
+# endif
+
+# if defined(FPE_INTOVF)
+ case FPE_INTOVF:
+ oss << "integer overflow";
+ break;
+# endif
+
+ case FPE_FLTDIV:
+ oss << "floating point divide by zero";
+ break;
+
+ case FPE_FLTOVF:
+ oss << "floating point overflow";
+ break;
+
+ case FPE_FLTUND:
+ oss << "floating point underflow";
+ break;
+
+ case FPE_FLTRES:
+ oss << "floating point inexact result";
+ break;
+
+ case FPE_FLTINV:
+ oss << "floating point invalid operation";
+ break;
+
+#if defined(FPE_FLTSUB)
+ case FPE_FLTSUB:
+ oss << "floating point subscript out of range";
+ break;
+#endif
+
+ default:
+ oss << "code " << sigInfo->si_code;
+ break;
+ }
+ break;
+
+ case SIGSEGV:
+ oss
+ << "Caught SIGSEGV at "
+ << (sigInfo->si_addr==0?"0x":"")
+ << sigInfo->si_addr
+ << " ";
+ switch (sigInfo->si_code)
+ {
+ case SEGV_MAPERR:
+ oss << "address not mapped to object";
+ break;
+
+ case SEGV_ACCERR:
+ oss << "invalid permission for mapped object";
+ break;
+
+ default:
+ oss << "code " << sigInfo->si_code;
+ break;
+ }
+ break;
+
+ case SIGBUS:
+ oss
+ << "Caught SIGBUS at "
+ << (sigInfo->si_addr==0?"0x":"")
+ << sigInfo->si_addr
+ << " ";
+ switch (sigInfo->si_code)
+ {
+ case BUS_ADRALN:
+ oss << "invalid address alignment";
+ break;
+
+# if defined(BUS_ADRERR)
+ case BUS_ADRERR:
+ oss << "nonexistent physical address";
+ break;
+# endif
+
+# if defined(BUS_OBJERR)
+ case BUS_OBJERR:
+ oss << "object-specific hardware error";
+ break;
+# endif
+
+# if defined(BUS_MCEERR_AR)
+ case BUS_MCEERR_AR:
+ oss << "Hardware memory error consumed on a machine check; action required.";
+ break;
+# endif
+
+# if defined(BUS_MCEERR_AO)
+ case BUS_MCEERR_AO:
+ oss << "Hardware memory error detected in process but not consumed; action optional.";
+ break;
+# endif
+
+ default:
+ oss << "code " << sigInfo->si_code;
+ break;
+ }
+ break;
+
+ case SIGILL:
+ oss
+ << "Caught SIGILL at "
+ << (sigInfo->si_addr==0?"0x":"")
+ << sigInfo->si_addr
+ << " ";
+ switch (sigInfo->si_code)
+ {
+ case ILL_ILLOPC:
+ oss << "illegal opcode";
+ break;
+
+# if defined(ILL_ILLOPN)
+ case ILL_ILLOPN:
+ oss << "illegal operand";
+ break;
+# endif
+
+# if defined(ILL_ILLADR)
+ case ILL_ILLADR:
+ oss << "illegal addressing mode.";
+ break;
+# endif
+
+ case ILL_ILLTRP:
+ oss << "illegal trap";
+ break;
+
+ case ILL_PRVOPC:
+ oss << "privileged opcode";
+ break;
+
+# if defined(ILL_PRVREG)
+ case ILL_PRVREG:
+ oss << "privileged register";
+ break;
+# endif
+
+# if defined(ILL_COPROC)
+ case ILL_COPROC:
+ oss << "co-processor error";
+ break;
+# endif
+
+# if defined(ILL_BADSTK)
+ case ILL_BADSTK:
+ oss << "internal stack error";
+ break;
+# endif
+
+ default:
+ oss << "code " << sigInfo->si_code;
+ break;
+ }
+ break;
+
+ default:
+ oss << "Caught " << sigNo << " code " << sigInfo->si_code;
+ break;
+ }
+ oss
+ << std::endl
+ << "Program Stack:" << std::endl
+ << SystemInformationImplementation::GetProgramStack(2,0)
+ << "=========================================================" << std::endl;
+ std::cerr << oss.str() << std::endl;
+
+ // restore the previously registered handlers
+ // and abort
+ SystemInformationImplementation::SetStackTraceOnError(0);
+ abort();
+#else
+ // avoid warning C4100
+ (void)sigNo;
+ (void)sigInfo;
+#endif
+}
+#endif
+
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
+#define safes(_arg)((_arg)?(_arg):"???")
+
+// Description:
+// A container for symbol properties. Each instance
+// must be Initialized.
+class SymbolProperties
+{
+public:
+ SymbolProperties();
+
+ // Description:
+ // The SymbolProperties instance must be initialized by
+ // passing a stack address.
+ void Initialize(void *address);
+
+ // Description:
+ // Get the symbol's stack address.
+ void *GetAddress() const { return this->Address; }
+
+ // Description:
+ // If not set paths will be removed. eg, from a binary
+ // or source file.
+ void SetReportPath(int rp){ this->ReportPath=rp; }
+
+ // Description:
+ // Set/Get the name of the binary file that the symbol
+ // is found in.
+ void SetBinary(const char *binary)
+ { this->Binary=safes(binary); }
+
+ std::string GetBinary() const;
+
+ // Description:
+ // Set the name of the function that the symbol is found in.
+ // If c++ demangling is supported it will be demangled.
+ void SetFunction(const char *function)
+ { this->Function=this->Demangle(function); }
+
+ std::string GetFunction() const
+ { return this->Function; }
+
+ // Description:
+ // Set/Get the name of the source file where the symbol
+ // is defined.
+ void SetSourceFile(const char *sourcefile)
+ { this->SourceFile=safes(sourcefile); }
+
+ std::string GetSourceFile() const
+ { return this->GetFileName(this->SourceFile); }
+
+ // Description:
+ // Set/Get the line number where the symbol is defined
+ void SetLineNumber(long linenumber){ this->LineNumber=linenumber; }
+ long GetLineNumber() const { return this->LineNumber; }
+
+ // Description:
+ // Set the address where the biinary image is mapped
+ // into memory.
+ void SetBinaryBaseAddress(void *address)
+ { this->BinaryBaseAddress=address; }
+
+private:
+ void *GetRealAddress() const
+ { return (void*)((char*)this->Address-(char*)this->BinaryBaseAddress); }
+
+ std::string GetFileName(const std::string &path) const;
+ std::string Demangle(const char *symbol) const;
+
+private:
+ std::string Binary;
+ void *BinaryBaseAddress;
+ void *Address;
+ std::string SourceFile;
+ std::string Function;
+ long LineNumber;
+ int ReportPath;
+};
+
+// --------------------------------------------------------------------------
+std::ostream &operator<<(
+ std::ostream &os,
+ const SymbolProperties &sp)
+{
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
+ os
+ << std::hex << sp.GetAddress() << " : "
+ << sp.GetFunction()
+ << " [(" << sp.GetBinary() << ") "
+ << sp.GetSourceFile() << ":"
+ << std::dec << sp.GetLineNumber() << "]";
+#elif defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
+ void *addr = sp.GetAddress();
+ char **syminfo = backtrace_symbols(&addr,1);
+ os << safes(syminfo[0]);
+ free(syminfo);
+#else
+ (void)os;
+ (void)sp;
+#endif
+ return os;
+}
+
+// --------------------------------------------------------------------------
+SymbolProperties::SymbolProperties()
+{
+ // not using an initializer list
+ // to avoid some PGI compiler warnings
+ this->SetBinary("???");
+ this->SetBinaryBaseAddress(NULL);
+ this->Address = NULL;
+ this->SetSourceFile("???");
+ this->SetFunction("???");
+ this->SetLineNumber(-1);
+ this->SetReportPath(0);
+ // avoid PGI compiler warnings
+ this->GetRealAddress();
+ this->GetFunction();
+ this->GetSourceFile();
+ this->GetLineNumber();
+}
+
+// --------------------------------------------------------------------------
+std::string SymbolProperties::GetFileName(const std::string &path) const
+{
+ std::string file(path);
+ if (!this->ReportPath)
+ {
+ size_t at = file.rfind("/");
+ if (at!=std::string::npos)
+ {
+ file = file.substr(at+1,std::string::npos);
+ }
+ }
+ return file;
+}
+
+// --------------------------------------------------------------------------
+std::string SymbolProperties::GetBinary() const
+{
+// only linux has proc fs
+#if defined(__linux__)
+ if (this->Binary=="/proc/self/exe")
+ {
+ std::string binary;
+ char buf[1024]={'\0'};
+ ssize_t ll=0;
+ if ((ll=readlink("/proc/self/exe",buf,1024))>0)
+ {
+ buf[ll]='\0';
+ binary=buf;
+ }
+ else
+ {
+ binary="/proc/self/exe";
+ }
+ return this->GetFileName(binary);
+ }
+#endif
+ return this->GetFileName(this->Binary);
+}
+
+// --------------------------------------------------------------------------
+std::string SymbolProperties::Demangle(const char *symbol) const
+{
+ std::string result = safes(symbol);
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
+ int status = 0;
+ size_t bufferLen = 1024;
+ char *buffer = (char*)malloc(1024);
+ char *demangledSymbol =
+ abi::__cxa_demangle(symbol, buffer, &bufferLen, &status);
+ if (!status)
+ {
+ result = demangledSymbol;
+ }
+ free(buffer);
+#else
+ (void)symbol;
+#endif
+ return result;
+}
+
+// --------------------------------------------------------------------------
+void SymbolProperties::Initialize(void *address)
+{
+ this->Address = address;
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
+ // first fallback option can demangle c++ functions
+ Dl_info info;
+ int ierr=dladdr(this->Address,&info);
+ if (ierr && info.dli_sname && info.dli_saddr)
+ {
+ this->SetBinary(info.dli_fname);
+ this->SetFunction(info.dli_sname);
+ }
+#else
+ // second fallback use builtin backtrace_symbols
+ // to decode the bactrace.
+#endif
+}
+#endif // don't define this class if we're not using it
+
+// --------------------------------------------------------------------------
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes
+#endif
+#if defined(_MSC_VER) && _MSC_VER < 1310
+# undef KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes
+#endif
+#if defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes)
+double calculateCPULoad(unsigned __int64 idleTicks,
+ unsigned __int64 totalTicks)
+{
+ static double previousLoad = -0.0;
+ static unsigned __int64 previousIdleTicks = 0;
+ static unsigned __int64 previousTotalTicks = 0;
+
+ unsigned __int64 const idleTicksSinceLastTime =
+ idleTicks - previousIdleTicks;
+ unsigned __int64 const totalTicksSinceLastTime =
+ totalTicks - previousTotalTicks;
+
+ double load;
+ if (previousTotalTicks == 0 || totalTicksSinceLastTime == 0)
+ {
+ // No new information. Use previous result.
+ load = previousLoad;
+ }
+ else
+ {
+ // Calculate load since last time.
+ load = 1.0 - double(idleTicksSinceLastTime) / totalTicksSinceLastTime;
+
+ // Smooth if possible.
+ if (previousLoad > 0)
+ {
+ load = 0.25 * load + 0.75 * previousLoad;
+ }
+ }
+
+ previousLoad = load;
+ previousIdleTicks = idleTicks;
+ previousTotalTicks = totalTicks;
+
+ return load;
+}
+
+unsigned __int64 fileTimeToUInt64(FILETIME const& ft)
+{
+ LARGE_INTEGER out;
+ out.HighPart = ft.dwHighDateTime;
+ out.LowPart = ft.dwLowDateTime;
+ return out.QuadPart;
+}
+#endif
+
+} // anonymous namespace
+
+
+SystemInformationImplementation::SystemInformationImplementation()
+{
+ this->TotalVirtualMemory = 0;
+ this->AvailableVirtualMemory = 0;
+ this->TotalPhysicalMemory = 0;
+ this->AvailablePhysicalMemory = 0;
+ this->CurrentPositionInFile = 0;
+ this->ChipManufacturer = UnknownManufacturer;
+ memset(&this->Features, 0, sizeof(CPUFeatures));
+ this->ChipID.Type = 0;
+ this->ChipID.Family = 0;
+ this->ChipID.Model = 0;
+ this->ChipID.Revision = 0;
+ this->ChipID.ExtendedFamily = 0;
+ this->ChipID.ExtendedModel = 0;
+ this->CPUSpeedInMHz = 0;
+ this->NumberOfLogicalCPU = 0;
+ this->NumberOfPhysicalCPU = 0;
+ this->OSName = "";
+ this->Hostname = "";
+ this->OSRelease = "";
+ this->OSVersion = "";
+ this->OSPlatform = "";
+}
+
+SystemInformationImplementation::~SystemInformationImplementation()
+{
+}
+
+void SystemInformationImplementation::RunCPUCheck()
+{
+#ifdef _WIN32
+ // Check to see if this processor supports CPUID.
+ bool supportsCPUID = DoesCPUSupportCPUID();
+
+ if (supportsCPUID)
+ {
+ // Retrieve the CPU details.
+ RetrieveCPUIdentity();
+ this->FindManufacturer();
+ RetrieveCPUFeatures();
+ }
+
+ // These two may be called without support for the CPUID instruction.
+ // (But if the instruction is there, they should be called *after*
+ // the above call to RetrieveCPUIdentity... that's why the two if
+ // blocks exist with the same "if (supportsCPUID)" logic...
+ //
+ if (!RetrieveCPUClockSpeed())
+ {
+ RetrieveClassicalCPUClockSpeed();
+ }
+
+ if (supportsCPUID)
+ {
+ // Retrieve cache information.
+ if (!RetrieveCPUCacheDetails())
+ {
+ RetrieveClassicalCPUCacheDetails();
+ }
+
+ // Retrieve the extended CPU details.
+ if (!RetrieveExtendedCPUIdentity())
+ {
+ RetrieveClassicalCPUIdentity();
+ }
+
+ RetrieveExtendedCPUFeatures();
+ RetrieveCPUPowerManagement();
+
+ // Now attempt to retrieve the serial number (if possible).
+ RetrieveProcessorSerialNumber();
+ }
+
+ this->CPUCount();
+
+#elif defined(__APPLE__)
+ this->ParseSysCtl();
+#elif defined (__SVR4) && defined (__sun)
+ this->QuerySolarisProcessor();
+#elif defined(__HAIKU__)
+ this->QueryHaikuInfo();
+#elif defined(__QNX__)
+ this->QueryQNXProcessor();
+#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
+ this->QueryBSDProcessor();
+#elif defined(__hpux)
+ this->QueryHPUXProcessor();
+#elif defined(__linux) || defined(__CYGWIN__)
+ this->RetreiveInformationFromCpuInfoFile();
+#else
+ this->QueryProcessor();
+#endif
+}
+
+void SystemInformationImplementation::RunOSCheck()
+{
+ this->QueryOSInformation();
+}
+
+void SystemInformationImplementation::RunMemoryCheck()
+{
+#if defined(__APPLE__)
+ this->ParseSysCtl();
+#elif defined (__SVR4) && defined (__sun)
+ this->QuerySolarisMemory();
+#elif defined(__HAIKU__)
+ this->QueryHaikuInfo();
+#elif defined(__QNX__)
+ this->QueryQNXMemory();
+#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
+ this->QueryBSDMemory();
+#elif defined(__CYGWIN__)
+ this->QueryCygwinMemory();
+#elif defined(_WIN32)
+ this->QueryWindowsMemory();
+#elif defined(__hpux)
+ this->QueryHPUXMemory();
+#elif defined(__linux)
+ this->QueryLinuxMemory();
+#elif defined(_AIX)
+ this->QueryAIXMemory();
+#else
+ this->QueryMemory();
+#endif
+}
+
+/** Get the vendor string */
+const char * SystemInformationImplementation::GetVendorString()
+{
+ return this->ChipID.Vendor.c_str();
+}
+
+/** Get the OS Name */
+const char * SystemInformationImplementation::GetOSName()
+{
+ return this->OSName.c_str();
+}
+
+/** Get the hostname */
+const char* SystemInformationImplementation::GetHostname()
+{
+ if (this->Hostname.empty())
+ {
+ this->Hostname="localhost";
+#if defined(_WIN32)
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ char name[255];
+ wVersionRequested = MAKEWORD(2,0);
+ if ( WSAStartup( wVersionRequested, &wsaData ) == 0 )
+ {
+ gethostname(name,sizeof(name));
+ WSACleanup( );
+ }
+ this->Hostname = name;
+#else
+ struct utsname unameInfo;
+ int errorFlag = uname(&unameInfo);
+ if(errorFlag == 0)
+ {
+ this->Hostname = unameInfo.nodename;
+ }
+#endif
+ }
+ return this->Hostname.c_str();
+}
+
+/** Get the FQDN */
+int SystemInformationImplementation::GetFullyQualifiedDomainName(
+ std::string &fqdn)
+{
+ // in the event of absolute failure return localhost.
+ fqdn="localhost";
+
+#if defined(_WIN32)
+ int ierr;
+ // TODO - a more robust implementation for windows, see comments
+ // in unix implementation.
+ WSADATA wsaData;
+ WORD ver=MAKEWORD(2,0);
+ ierr=WSAStartup(ver,&wsaData);
+ if (ierr)
+ {
+ return -1;
+ }
+
+ char base[256]={'\0'};
+ ierr=gethostname(base,256);
+ if (ierr)
+ {
+ WSACleanup();
+ return -2;
+ }
+ fqdn=base;
+
+ HOSTENT *hent=gethostbyname(base);
+ if (hent)
+ {
+ fqdn=hent->h_name;
+ }
+
+ WSACleanup();
+ return 0;
+
+#elif defined(KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN)
+ // gethostname typical returns an alias for loopback interface
+ // we want the fully qualified domain name. Because there are
+ // any number of interfaces on this system we look for the
+ // first of these that contains the name returned by gethostname
+ // and is longer. failing that we return gethostname and indicate
+ // with a failure code. Return of a failure code is not necessarilly
+ // an indication of an error. for instance gethostname may return
+ // the fully qualified domain name, or there may not be one if the
+ // system lives on a private network such as in the case of a cluster
+ // node.
+
+ int ierr=0;
+ char base[NI_MAXHOST];
+ ierr=gethostname(base,NI_MAXHOST);
+ if (ierr)
+ {
+ return -1;
+ }
+ size_t baseSize=strlen(base);
+ fqdn=base;
+
+ struct ifaddrs *ifas;
+ struct ifaddrs *ifa;
+ ierr=getifaddrs(&ifas);
+ if (ierr)
+ {
+ return -2;
+ }
+
+ for (ifa=ifas; ifa!=NULL; ifa=ifa->ifa_next)
+ {
+ int fam = ifa->ifa_addr? ifa->ifa_addr->sa_family : -1;
+ if ((fam==AF_INET) || (fam==AF_INET6))
+ {
+ char host[NI_MAXHOST]={'\0'};
+
+ const size_t addrlen
+ = (fam==AF_INET?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6));
+
+ ierr=getnameinfo(
+ ifa->ifa_addr,
+ static_cast<socklen_t>(addrlen),
+ host,
+ NI_MAXHOST,
+ NULL,
+ 0,
+ NI_NAMEREQD);
+ if (ierr)
+ {
+ // don't report the failure now since we may succeed on another
+ // interface. If all attempts fail then return the failure code.
+ ierr=-3;
+ continue;
+ }
+
+ std::string candidate=host;
+ if ((candidate.find(base)!=std::string::npos) && baseSize<candidate.size())
+ {
+ // success, stop now.
+ ierr=0;
+ fqdn=candidate;
+ break;
+ }
+ }
+ }
+ freeifaddrs(ifas);
+
+ return ierr;
+#else
+ /* TODO: Implement on more platforms. */
+ fqdn=this->GetHostname();
+ return -1;
+#endif
+}
+
+/** Get the OS release */
+const char* SystemInformationImplementation::GetOSRelease()
+{
+ return this->OSRelease.c_str();
+}
+
+/** Get the OS version */
+const char* SystemInformationImplementation::GetOSVersion()
+{
+ return this->OSVersion.c_str();
+}
+
+/** Get the OS platform */
+const char* SystemInformationImplementation::GetOSPlatform()
+{
+ return this->OSPlatform.c_str();
+}
+
+/** Get the vendor ID */
+const char * SystemInformationImplementation::GetVendorID()
+{
+ // Return the vendor ID.
+ switch (this->ChipManufacturer)
+ {
+ case Intel:
+ return "Intel Corporation";
+ case AMD:
+ return "Advanced Micro Devices";
+ case NSC:
+ return "National Semiconductor";
+ case Cyrix:
+ return "Cyrix Corp., VIA Inc.";
+ case NexGen:
+ return "NexGen Inc., Advanced Micro Devices";
+ case IDT:
+ return "IDT\\Centaur, Via Inc.";
+ case UMC:
+ return "United Microelectronics Corp.";
+ case Rise:
+ return "Rise";
+ case Transmeta:
+ return "Transmeta";
+ case Sun:
+ return "Sun Microelectronics";
+ case IBM:
+ return "IBM";
+ case Motorola:
+ return "Motorola";
+ case HP:
+ return "Hewlett-Packard";
+ case UnknownManufacturer:
+ default:
+ return "Unknown Manufacturer";
+ }
+}
+
+/** Return the type ID of the CPU */
+std::string SystemInformationImplementation::GetTypeID()
+{
+ std::ostringstream str;
+ str << this->ChipID.Type;
+ return str.str();
+}
+
+/** Return the family of the CPU present */
+std::string SystemInformationImplementation::GetFamilyID()
+{
+ std::ostringstream str;
+ str << this->ChipID.Family;
+ return str.str();
+}
+
+// Return the model of CPU present */
+std::string SystemInformationImplementation::GetModelID()
+{
+ std::ostringstream str;
+ str << this->ChipID.Model;
+ return str.str();
+}
+
+// Return the model name of CPU present */
+std::string SystemInformationImplementation::GetModelName()
+{
+ return this->ChipID.ModelName;
+}
+
+/** Return the stepping code of the CPU present. */
+std::string SystemInformationImplementation::GetSteppingCode()
+{
+ std::ostringstream str;
+ str << this->ChipID.Revision;
+ return str.str();
+}
+
+/** Return the stepping code of the CPU present. */
+const char * SystemInformationImplementation::GetExtendedProcessorName()
+{
+ return this->ChipID.ProcessorName.c_str();
+}
+
+/** Return the serial number of the processor
+ * in hexadecimal: xxxx-xxxx-xxxx-xxxx-xxxx-xxxx. */
+const char * SystemInformationImplementation::GetProcessorSerialNumber()
+{
+ return this->ChipID.SerialNumber.c_str();
+}
+
+/** Return the logical processors per physical */
+unsigned int SystemInformationImplementation::GetLogicalProcessorsPerPhysical()
+{
+ return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical;
+}
+
+/** Return the processor clock frequency. */
+float SystemInformationImplementation::GetProcessorClockFrequency()
+{
+ return this->CPUSpeedInMHz;
+}
+
+/** Return the APIC ID. */
+int SystemInformationImplementation::GetProcessorAPICID()
+{
+ return this->Features.ExtendedFeatures.APIC_ID;
+}
+
+/** Return the L1 cache size. */
+int SystemInformationImplementation::GetProcessorCacheSize()
+{
+ return this->Features.L1CacheSize;
+}
+
+/** Return the chosen cache size. */
+int SystemInformationImplementation::GetProcessorCacheXSize(long int dwCacheID)
+{
+ switch (dwCacheID)
+ {
+ case L1CACHE_FEATURE:
+ return this->Features.L1CacheSize;
+ case L2CACHE_FEATURE:
+ return this->Features.L2CacheSize;
+ case L3CACHE_FEATURE:
+ return this->Features.L3CacheSize;
+ }
+ return -1;
+}
+
+
+bool SystemInformationImplementation::DoesCPUSupportFeature(long int dwFeature)
+{
+ bool bHasFeature = false;
+
+ // Check for MMX instructions.
+ if (((dwFeature & MMX_FEATURE) != 0) && this->Features.HasMMX) bHasFeature = true;
+
+ // Check for MMX+ instructions.
+ if (((dwFeature & MMX_PLUS_FEATURE) != 0) && this->Features.ExtendedFeatures.HasMMXPlus) bHasFeature = true;
+
+ // Check for SSE FP instructions.
+ if (((dwFeature & SSE_FEATURE) != 0) && this->Features.HasSSE) bHasFeature = true;
+
+ // Check for SSE FP instructions.
+ if (((dwFeature & SSE_FP_FEATURE) != 0) && this->Features.HasSSEFP) bHasFeature = true;
+
+ // Check for SSE MMX instructions.
+ if (((dwFeature & SSE_MMX_FEATURE) != 0) && this->Features.ExtendedFeatures.HasSSEMMX) bHasFeature = true;
+
+ // Check for SSE2 instructions.
+ if (((dwFeature & SSE2_FEATURE) != 0) && this->Features.HasSSE2) bHasFeature = true;
+
+ // Check for 3DNow! instructions.
+ if (((dwFeature & AMD_3DNOW_FEATURE) != 0) && this->Features.ExtendedFeatures.Has3DNow) bHasFeature = true;
+
+ // Check for 3DNow+ instructions.
+ if (((dwFeature & AMD_3DNOW_PLUS_FEATURE) != 0) && this->Features.ExtendedFeatures.Has3DNowPlus) bHasFeature = true;
+
+ // Check for IA64 instructions.
+ if (((dwFeature & IA64_FEATURE) != 0) && this->Features.HasIA64) bHasFeature = true;
+
+ // Check for MP capable.
+ if (((dwFeature & MP_CAPABLE) != 0) && this->Features.ExtendedFeatures.SupportsMP) bHasFeature = true;
+
+ // Check for a serial number for the processor.
+ if (((dwFeature & SERIALNUMBER_FEATURE) != 0) && this->Features.HasSerial) bHasFeature = true;
+
+ // Check for a local APIC in the processor.
+ if (((dwFeature & APIC_FEATURE) != 0) && this->Features.HasAPIC) bHasFeature = true;
+
+ // Check for CMOV instructions.
+ if (((dwFeature & CMOV_FEATURE) != 0) && this->Features.HasCMOV) bHasFeature = true;
+
+ // Check for MTRR instructions.
+ if (((dwFeature & MTRR_FEATURE) != 0) && this->Features.HasMTRR) bHasFeature = true;
+
+ // Check for L1 cache size.
+ if (((dwFeature & L1CACHE_FEATURE) != 0) && (this->Features.L1CacheSize != -1)) bHasFeature = true;
+
+ // Check for L2 cache size.
+ if (((dwFeature & L2CACHE_FEATURE) != 0) && (this->Features.L2CacheSize != -1)) bHasFeature = true;
+
+ // Check for L3 cache size.
+ if (((dwFeature & L3CACHE_FEATURE) != 0) && (this->Features.L3CacheSize != -1)) bHasFeature = true;
+
+ // Check for ACPI capability.
+ if (((dwFeature & ACPI_FEATURE) != 0) && this->Features.HasACPI) bHasFeature = true;
+
+ // Check for thermal monitor support.
+ if (((dwFeature & THERMALMONITOR_FEATURE) != 0) && this->Features.HasThermal) bHasFeature = true;
+
+ // Check for temperature sensing diode support.
+ if (((dwFeature & TEMPSENSEDIODE_FEATURE) != 0) && this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode) bHasFeature = true;
+
+ // Check for frequency ID support.
+ if (((dwFeature & FREQUENCYID_FEATURE) != 0) && this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID) bHasFeature = true;
+
+ // Check for voltage ID support.
+ if (((dwFeature & VOLTAGEID_FREQUENCY) != 0) && this->Features.ExtendedFeatures.PowerManagement.HasVoltageID) bHasFeature = true;
+
+ return bHasFeature;
+}
+
+
+void SystemInformationImplementation::Delay(unsigned int uiMS)
+{
+#ifdef _WIN32
+ LARGE_INTEGER Frequency, StartCounter, EndCounter;
+ __int64 x;
+
+ // Get the frequency of the high performance counter.
+ if (!QueryPerformanceFrequency (&Frequency)) return;
+ x = Frequency.QuadPart / 1000 * uiMS;
+
+ // Get the starting position of the counter.
+ QueryPerformanceCounter (&StartCounter);
+
+ do {
+ // Get the ending position of the counter.
+ QueryPerformanceCounter (&EndCounter);
+ } while (EndCounter.QuadPart - StartCounter.QuadPart < x);
+#endif
+ (void)uiMS;
+}
+
+
+bool SystemInformationImplementation::DoesCPUSupportCPUID()
+{
+#if USE_CPUID
+ int dummy[4] = { 0, 0, 0, 0 };
+
+#if USE_ASM_INSTRUCTIONS
+ return call_cpuid(0, dummy);
+#else
+ call_cpuid(0, dummy);
+ return dummy[0] || dummy[1] || dummy[2] || dummy[3];
+#endif
+#else
+ // Assume no cpuid instruction.
+ return false;
+#endif
+}
+
+
+bool SystemInformationImplementation::RetrieveCPUFeatures()
+{
+#if USE_CPUID
+ int cpuinfo[4] = { 0, 0, 0, 0 };
+
+ if (!call_cpuid(1, cpuinfo))
+ {
+ return false;
+ }
+
+ // Retrieve the features of CPU present.
+ this->Features.HasFPU = ((cpuinfo[3] & 0x00000001) != 0); // FPU Present --> Bit 0
+ this->Features.HasTSC = ((cpuinfo[3] & 0x00000010) != 0); // TSC Present --> Bit 4
+ this->Features.HasAPIC = ((cpuinfo[3] & 0x00000200) != 0); // APIC Present --> Bit 9
+ this->Features.HasMTRR = ((cpuinfo[3] & 0x00001000) != 0); // MTRR Present --> Bit 12
+ this->Features.HasCMOV = ((cpuinfo[3] & 0x00008000) != 0); // CMOV Present --> Bit 15
+ this->Features.HasSerial = ((cpuinfo[3] & 0x00040000) != 0); // Serial Present --> Bit 18
+ this->Features.HasACPI = ((cpuinfo[3] & 0x00400000) != 0); // ACPI Capable --> Bit 22
+ this->Features.HasMMX = ((cpuinfo[3] & 0x00800000) != 0); // MMX Present --> Bit 23
+ this->Features.HasSSE = ((cpuinfo[3] & 0x02000000) != 0); // SSE Present --> Bit 25
+ this->Features.HasSSE2 = ((cpuinfo[3] & 0x04000000) != 0); // SSE2 Present --> Bit 26
+ this->Features.HasThermal = ((cpuinfo[3] & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29
+ this->Features.HasIA64 = ((cpuinfo[3] & 0x40000000) != 0); // IA64 Present --> Bit 30
+
+#if USE_ASM_INSTRUCTIONS
+ // Retrieve extended SSE capabilities if SSE is available.
+ if (this->Features.HasSSE) {
+
+ // Attempt to __try some SSE FP instructions.
+ __try
+ {
+ // Perform: orps xmm0, xmm0
+ _asm
+ {
+ _emit 0x0f
+ _emit 0x56
+ _emit 0xc0
+ }
+
+ // SSE FP capable processor.
+ this->Features.HasSSEFP = true;
+ }
+ __except(1)
+ {
+ // bad instruction - processor or OS cannot handle SSE FP.
+ this->Features.HasSSEFP = false;
+ }
+ }
+ else
+ {
+ // Set the advanced SSE capabilities to not available.
+ this->Features.HasSSEFP = false;
+ }
+#else
+ this->Features.HasSSEFP = false;
+#endif
+
+ // Retrieve Intel specific extended features.
+ if (this->ChipManufacturer == Intel)
+ {
+ this->Features.ExtendedFeatures.SupportsHyperthreading = ((cpuinfo[3] & 0x10000000) != 0); // Intel specific: Hyperthreading --> Bit 28
+ this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = (this->Features.ExtendedFeatures.SupportsHyperthreading) ? ((cpuinfo[1] & 0x00FF0000) >> 16) : 1;
+
+ if ((this->Features.ExtendedFeatures.SupportsHyperthreading) && (this->Features.HasAPIC))
+ {
+ // Retrieve APIC information if there is one present.
+ this->Features.ExtendedFeatures.APIC_ID = ((cpuinfo[1] & 0xFF000000) >> 24);
+ }
+ }
+
+ return true;
+
+#else
+ return false;
+#endif
+}
+
+
+/** Find the manufacturer given the vendor id */
+void SystemInformationImplementation::FindManufacturer(const std::string& family)
+{
+ if (this->ChipID.Vendor == "GenuineIntel") this->ChipManufacturer = Intel; // Intel Corp.
+ else if (this->ChipID.Vendor == "UMC UMC UMC ") this->ChipManufacturer = UMC; // United Microelectronics Corp.
+ else if (this->ChipID.Vendor == "AuthenticAMD") 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 == "CyrixInstead") this->ChipManufacturer = Cyrix; // Cyrix Corp., VIA Inc.
+ else if (this->ChipID.Vendor == "NexGenDriven") this->ChipManufacturer = NexGen; // NexGen Inc. (now AMD)
+ else if (this->ChipID.Vendor == "CentaurHauls") this->ChipManufacturer = IDT; // IDT/Centaur (now VIA)
+ else if (this->ChipID.Vendor == "RiseRiseRise") this->ChipManufacturer = Rise; // Rise
+ else if (this->ChipID.Vendor == "GenuineTMx86") this->ChipManufacturer = Transmeta; // Transmeta
+ else if (this->ChipID.Vendor == "TransmetaCPU") this->ChipManufacturer = Transmeta; // Transmeta
+ else if (this->ChipID.Vendor == "Geode By NSC") this->ChipManufacturer = NSC; // National Semiconductor
+ else if (this->ChipID.Vendor == "Sun") this->ChipManufacturer = Sun; // Sun Microelectronics
+ else if (this->ChipID.Vendor == "IBM") this->ChipManufacturer = IBM; // IBM Microelectronics
+ else if (this->ChipID.Vendor == "Hewlett-Packard") this->ChipManufacturer = HP; // Hewlett-Packard
+ else if (this->ChipID.Vendor == "Motorola") this->ChipManufacturer = Motorola; // Motorola Microelectronics
+ else if (family.substr(0, 7) == "PA-RISC") this->ChipManufacturer = HP; // Hewlett-Packard
+ else this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer
+}
+
+
+/** */
+bool SystemInformationImplementation::RetrieveCPUIdentity()
+{
+#if USE_CPUID
+ int localCPUVendor[4];
+ int localCPUSignature[4];
+
+ if (!call_cpuid(0, localCPUVendor))
+ {
+ return false;
+ }
+ if (!call_cpuid(1, localCPUSignature))
+ {
+ return false;
+ }
+
+ // Process the returned information.
+ // ; eax = 0 --> eax: maximum value of CPUID instruction.
+ // ; ebx: part 1 of 3; CPU signature.
+ // ; edx: part 2 of 3; CPU signature.
+ // ; ecx: part 3 of 3; CPU signature.
+ char vbuf[13];
+ memcpy (&(vbuf[0]), &(localCPUVendor[1]), sizeof (int));
+ memcpy (&(vbuf[4]), &(localCPUVendor[3]), sizeof (int));
+ memcpy (&(vbuf[8]), &(localCPUVendor[2]), sizeof (int));
+ vbuf[12] = '\0';
+ this->ChipID.Vendor = vbuf;
+
+ // Retrieve the family of CPU present.
+ // ; eax = 1 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type, bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision
+ // ; ebx: 31..24 - default APIC ID, 23..16 - logical processor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID
+ // ; edx: CPU feature flags
+ this->ChipID.ExtendedFamily = ((localCPUSignature[0] & 0x0FF00000) >> 20); // Bits 27..20 Used
+ this->ChipID.ExtendedModel = ((localCPUSignature[0] & 0x000F0000) >> 16); // Bits 19..16 Used
+ this->ChipID.Type = ((localCPUSignature[0] & 0x0000F000) >> 12); // Bits 15..12 Used
+ this->ChipID.Family = ((localCPUSignature[0] & 0x00000F00) >> 8); // Bits 11..8 Used
+ this->ChipID.Model = ((localCPUSignature[0] & 0x000000F0) >> 4); // Bits 7..4 Used
+ this->ChipID.Revision = ((localCPUSignature[0] & 0x0000000F) >> 0); // Bits 3..0 Used
+
+ return true;
+
+#else
+ return false;
+#endif
+}
+
+
+/** */
+bool SystemInformationImplementation::RetrieveCPUCacheDetails()
+{
+#if USE_CPUID
+ int L1Cache[4] = { 0, 0, 0, 0 };
+ int L2Cache[4] = { 0, 0, 0, 0 };
+
+ // Check to see if what we are about to do is supported...
+ if (RetrieveCPUExtendedLevelSupport (0x80000005))
+ {
+ if (!call_cpuid(0x80000005, L1Cache))
+ {
+ return false;
+ }
+ // Save the L1 data cache size (in KB) from ecx: bits 31..24 as well as data cache size from edx: bits 31..24.
+ this->Features.L1CacheSize = ((L1Cache[2] & 0xFF000000) >> 24);
+ this->Features.L1CacheSize += ((L1Cache[3] & 0xFF000000) >> 24);
+ }
+ else
+ {
+ // Store -1 to indicate the cache could not be queried.
+ this->Features.L1CacheSize = -1;
+ }
+
+ // Check to see if what we are about to do is supported...
+ if (RetrieveCPUExtendedLevelSupport (0x80000006))
+ {
+ if (!call_cpuid(0x80000006, L2Cache))
+ {
+ return false;
+ }
+ // Save the L2 unified cache size (in KB) from ecx: bits 31..16.
+ this->Features.L2CacheSize = ((L2Cache[2] & 0xFFFF0000) >> 16);
+ }
+ else
+ {
+ // Store -1 to indicate the cache could not be queried.
+ this->Features.L2CacheSize = -1;
+ }
+
+ // Define L3 as being not present as we cannot test for it.
+ this->Features.L3CacheSize = -1;
+
+#endif
+
+ // Return failure if we cannot detect either cache with this method.
+ return ((this->Features.L1CacheSize == -1) && (this->Features.L2CacheSize == -1)) ? false : true;
+}
+
+
+/** */
+bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails()
+{
+#if USE_CPUID
+ int TLBCode = -1, TLBData = -1, L1Code = -1, L1Data = -1, L1Trace = -1, L2Unified = -1, L3Unified = -1;
+ int TLBCacheData[4] = { 0, 0, 0, 0 };
+ int TLBPassCounter = 0;
+ int TLBCacheUnit = 0;
+
+
+ do {
+ if (!call_cpuid(2, TLBCacheData))
+ {
+ return false;
+ }
+
+ int bob = ((TLBCacheData[0] & 0x00FF0000) >> 16);
+ (void)bob;
+ // Process the returned TLB and cache information.
+ for (int nCounter = 0; nCounter < TLBCACHE_INFO_UNITS; nCounter ++)
+ {
+ // First of all - decide which unit we are dealing with.
+ switch (nCounter)
+ {
+ // eax: bits 8..15 : bits 16..23 : bits 24..31
+ case 0: TLBCacheUnit = ((TLBCacheData[0] & 0x0000FF00) >> 8); break;
+ case 1: TLBCacheUnit = ((TLBCacheData[0] & 0x00FF0000) >> 16); break;
+ case 2: TLBCacheUnit = ((TLBCacheData[0] & 0xFF000000) >> 24); break;
+
+ // ebx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
+ case 3: TLBCacheUnit = ((TLBCacheData[1] & 0x000000FF) >> 0); break;
+ case 4: TLBCacheUnit = ((TLBCacheData[1] & 0x0000FF00) >> 8); break;
+ case 5: TLBCacheUnit = ((TLBCacheData[1] & 0x00FF0000) >> 16); break;
+ case 6: TLBCacheUnit = ((TLBCacheData[1] & 0xFF000000) >> 24); break;
+
+ // ecx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
+ case 7: TLBCacheUnit = ((TLBCacheData[2] & 0x000000FF) >> 0); break;
+ case 8: TLBCacheUnit = ((TLBCacheData[2] & 0x0000FF00) >> 8); break;
+ case 9: TLBCacheUnit = ((TLBCacheData[2] & 0x00FF0000) >> 16); break;
+ case 10: TLBCacheUnit = ((TLBCacheData[2] & 0xFF000000) >> 24); break;
+
+ // edx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
+ case 11: TLBCacheUnit = ((TLBCacheData[3] & 0x000000FF) >> 0); break;
+ case 12: TLBCacheUnit = ((TLBCacheData[3] & 0x0000FF00) >> 8); break;
+ case 13: TLBCacheUnit = ((TLBCacheData[3] & 0x00FF0000) >> 16); break;
+ case 14: TLBCacheUnit = ((TLBCacheData[3] & 0xFF000000) >> 24); break;
+
+ // Default case - an error has occurred.
+ default: return false;
+ }
+
+ // Now process the resulting unit to see what it means....
+ switch (TLBCacheUnit)
+ {
+ case 0x00: break;
+ case 0x01: STORE_TLBCACHE_INFO (TLBCode, 4); break;
+ case 0x02: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
+ case 0x03: STORE_TLBCACHE_INFO (TLBData, 4); break;
+ case 0x04: STORE_TLBCACHE_INFO (TLBData, 4096); break;
+ case 0x06: STORE_TLBCACHE_INFO (L1Code, 8); break;
+ case 0x08: STORE_TLBCACHE_INFO (L1Code, 16); break;
+ case 0x0a: STORE_TLBCACHE_INFO (L1Data, 8); break;
+ case 0x0c: STORE_TLBCACHE_INFO (L1Data, 16); break;
+ case 0x10: STORE_TLBCACHE_INFO (L1Data, 16); break; // <-- FIXME: IA-64 Only
+ case 0x15: STORE_TLBCACHE_INFO (L1Code, 16); break; // <-- FIXME: IA-64 Only
+ case 0x1a: STORE_TLBCACHE_INFO (L2Unified, 96); break; // <-- FIXME: IA-64 Only
+ case 0x22: STORE_TLBCACHE_INFO (L3Unified, 512); break;
+ case 0x23: STORE_TLBCACHE_INFO (L3Unified, 1024); break;
+ case 0x25: STORE_TLBCACHE_INFO (L3Unified, 2048); break;
+ case 0x29: STORE_TLBCACHE_INFO (L3Unified, 4096); break;
+ case 0x39: STORE_TLBCACHE_INFO (L2Unified, 128); break;
+ case 0x3c: STORE_TLBCACHE_INFO (L2Unified, 256); break;
+ case 0x40: STORE_TLBCACHE_INFO (L2Unified, 0); break; // <-- FIXME: No integrated L2 cache (P6 core) or L3 cache (P4 core).
+ case 0x41: STORE_TLBCACHE_INFO (L2Unified, 128); break;
+ case 0x42: STORE_TLBCACHE_INFO (L2Unified, 256); break;
+ case 0x43: STORE_TLBCACHE_INFO (L2Unified, 512); break;
+ case 0x44: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
+ case 0x45: STORE_TLBCACHE_INFO (L2Unified, 2048); break;
+ case 0x50: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
+ case 0x51: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
+ case 0x52: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
+ case 0x5b: STORE_TLBCACHE_INFO (TLBData, 4096); break;
+ case 0x5c: STORE_TLBCACHE_INFO (TLBData, 4096); break;
+ case 0x5d: STORE_TLBCACHE_INFO (TLBData, 4096); break;
+ case 0x66: STORE_TLBCACHE_INFO (L1Data, 8); break;
+ case 0x67: STORE_TLBCACHE_INFO (L1Data, 16); break;
+ case 0x68: STORE_TLBCACHE_INFO (L1Data, 32); break;
+ case 0x70: STORE_TLBCACHE_INFO (L1Trace, 12); break;
+ case 0x71: STORE_TLBCACHE_INFO (L1Trace, 16); break;
+ case 0x72: STORE_TLBCACHE_INFO (L1Trace, 32); break;
+ case 0x77: STORE_TLBCACHE_INFO (L1Code, 16); break; // <-- FIXME: IA-64 Only
+ case 0x79: STORE_TLBCACHE_INFO (L2Unified, 128); break;
+ case 0x7a: STORE_TLBCACHE_INFO (L2Unified, 256); break;
+ case 0x7b: STORE_TLBCACHE_INFO (L2Unified, 512); break;
+ case 0x7c: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
+ case 0x7e: STORE_TLBCACHE_INFO (L2Unified, 256); break;
+ case 0x81: STORE_TLBCACHE_INFO (L2Unified, 128); break;
+ case 0x82: STORE_TLBCACHE_INFO (L2Unified, 256); break;
+ case 0x83: STORE_TLBCACHE_INFO (L2Unified, 512); break;
+ case 0x84: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
+ case 0x85: STORE_TLBCACHE_INFO (L2Unified, 2048); break;
+ case 0x88: STORE_TLBCACHE_INFO (L3Unified, 2048); break; // <-- FIXME: IA-64 Only
+ case 0x89: STORE_TLBCACHE_INFO (L3Unified, 4096); break; // <-- FIXME: IA-64 Only
+ case 0x8a: STORE_TLBCACHE_INFO (L3Unified, 8192); break; // <-- FIXME: IA-64 Only
+ case 0x8d: STORE_TLBCACHE_INFO (L3Unified, 3096); break; // <-- FIXME: IA-64 Only
+ case 0x90: STORE_TLBCACHE_INFO (TLBCode, 262144); break; // <-- FIXME: IA-64 Only
+ case 0x96: STORE_TLBCACHE_INFO (TLBCode, 262144); break; // <-- FIXME: IA-64 Only
+ case 0x9b: STORE_TLBCACHE_INFO (TLBCode, 262144); break; // <-- FIXME: IA-64 Only
+
+ // Default case - an error has occurred.
+ default: return false;
+ }
+ }
+
+ // Increment the TLB pass counter.
+ TLBPassCounter ++;
+ } while ((TLBCacheData[0] & 0x000000FF) > TLBPassCounter);
+
+ // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
+ if ((L1Code == -1) && (L1Data == -1) && (L1Trace == -1))
+ {
+ this->Features.L1CacheSize = -1;
+ }
+ else if ((L1Code == -1) && (L1Data == -1) && (L1Trace != -1))
+ {
+ this->Features.L1CacheSize = L1Trace;
+ }
+ else if ((L1Code != -1) && (L1Data == -1))
+ {
+ this->Features.L1CacheSize = L1Code;
+ }
+ else if ((L1Code == -1) && (L1Data != -1))
+ {
+ this->Features.L1CacheSize = L1Data;
+ }
+ else if ((L1Code != -1) && (L1Data != -1))
+ {
+ this->Features.L1CacheSize = L1Code + L1Data;
+ }
+ else
+ {
+ this->Features.L1CacheSize = -1;
+ }
+
+ // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
+ if (L2Unified == -1)
+ {
+ this->Features.L2CacheSize = -1;
+ }
+ else
+ {
+ this->Features.L2CacheSize = L2Unified;
+ }
+
+ // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
+ if (L3Unified == -1)
+ {
+ this->Features.L3CacheSize = -1;
+ }
+ else
+ {
+ this->Features.L3CacheSize = L3Unified;
+ }
+
+ return true;
+
+#else
+ return false;
+#endif
+}
+
+
+/** */
+bool SystemInformationImplementation::RetrieveCPUClockSpeed()
+{
+ bool retrieved = false;
+
+#if defined(_WIN32)
+ unsigned int uiRepetitions = 1;
+ unsigned int uiMSecPerRepetition = 50;
+ __int64 i64Total = 0;
+ __int64 i64Overhead = 0;
+
+ // Check if the TSC implementation works at all
+ if (this->Features.HasTSC &&
+ GetCyclesDifference(SystemInformationImplementation::Delay,
+ uiMSecPerRepetition) > 0)
+ {
+ for (unsigned int nCounter = 0; nCounter < uiRepetitions; nCounter ++)
+ {
+ i64Total += GetCyclesDifference (SystemInformationImplementation::Delay,
+ uiMSecPerRepetition);
+ i64Overhead +=
+ GetCyclesDifference (SystemInformationImplementation::DelayOverhead,
+ uiMSecPerRepetition);
+ }
+
+ // Calculate the MHz speed.
+ i64Total -= i64Overhead;
+ i64Total /= uiRepetitions;
+ i64Total /= uiMSecPerRepetition;
+ i64Total /= 1000;
+
+ // Save the CPU speed.
+ this->CPUSpeedInMHz = (float) i64Total;
+
+ retrieved = true;
+ }
+
+ // If RDTSC is not supported, we fallback to trying to read this value
+ // from the registry:
+ if (!retrieved)
+ {
+ HKEY hKey = NULL;
+ LONG err = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0,
+ KEY_READ, &hKey);
+
+ if (ERROR_SUCCESS == err)
+ {
+ DWORD dwType = 0;
+ DWORD data = 0;
+ DWORD dwSize = sizeof(DWORD);
+
+ err = RegQueryValueExW(hKey, L"~MHz", 0,
+ &dwType, (LPBYTE) &data, &dwSize);
+
+ if (ERROR_SUCCESS == err)
+ {
+ this->CPUSpeedInMHz = (float) data;
+ retrieved = true;
+ }
+
+ RegCloseKey(hKey);
+ hKey = NULL;
+ }
+ }
+#endif
+
+ return retrieved;
+}
+
+
+/** */
+bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed()
+{
+#if USE_ASM_INSTRUCTIONS
+ LARGE_INTEGER liStart, liEnd, liCountsPerSecond;
+ double dFrequency, dDifference;
+
+ // Attempt to get a starting tick count.
+ QueryPerformanceCounter (&liStart);
+
+ __try
+ {
+ _asm
+ {
+ mov eax, 0x80000000
+ mov ebx, CLASSICAL_CPU_FREQ_LOOP
+ Timer_Loop:
+ bsf ecx,eax
+ dec ebx
+ jnz Timer_Loop
+ }
+ }
+ __except(1)
+ {
+ return false;
+ }
+
+ // Attempt to get a starting tick count.
+ QueryPerformanceCounter (&liEnd);
+
+ // Get the difference... NB: This is in seconds....
+ QueryPerformanceFrequency (&liCountsPerSecond);
+ dDifference = (((double) liEnd.QuadPart - (double) liStart.QuadPart) / (double) liCountsPerSecond.QuadPart);
+
+ // Calculate the clock speed.
+ if (this->ChipID.Family == 3)
+ {
+ // 80386 processors.... Loop time is 115 cycles!
+ dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 115) / dDifference) / 1000000);
+ }
+ else if (this->ChipID.Family == 4)
+ {
+ // 80486 processors.... Loop time is 47 cycles!
+ dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 47) / dDifference) / 1000000);
+ }
+ else if (this->ChipID.Family == 5)
+ {
+ // Pentium processors.... Loop time is 43 cycles!
+ dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 43) / dDifference) / 1000000);
+ }
+
+ // Save the clock speed.
+ this->Features.CPUSpeed = (int) dFrequency;
+
+ return true;
+
+#else
+ return false;
+#endif
+}
+
+
+/** */
+bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport(int CPULevelToCheck)
+{
+ int cpuinfo[4] = { 0, 0, 0, 0 };
+
+ // The extended CPUID is supported by various vendors starting with the following CPU models:
+ //
+ // Manufacturer & Chip Name | Family Model Revision
+ //
+ // AMD K6, K6-2 | 5 6 x
+ // Cyrix GXm, Cyrix III "Joshua" | 5 4 x
+ // IDT C6-2 | 5 8 x
+ // VIA Cyrix III | 6 5 x
+ // Transmeta Crusoe | 5 x x
+ // Intel Pentium 4 | f x x
+ //
+
+ // We check to see if a supported processor is present...
+ if (this->ChipManufacturer == AMD)
+ {
+ if (this->ChipID.Family < 5) return false;
+ if ((this->ChipID.Family == 5) && (this->ChipID.Model < 6)) return false;
+ }
+ else if (this->ChipManufacturer == Cyrix)
+ {
+ if (this->ChipID.Family < 5) return false;
+ if ((this->ChipID.Family == 5) && (this->ChipID.Model < 4)) return false;
+ if ((this->ChipID.Family == 6) && (this->ChipID.Model < 5)) return false;
+ }
+ else if (this->ChipManufacturer == IDT)
+ {
+ if (this->ChipID.Family < 5) return false;
+ if ((this->ChipID.Family == 5) && (this->ChipID.Model < 8)) return false;
+ }
+ else if (this->ChipManufacturer == Transmeta)
+ {
+ if (this->ChipID.Family < 5) return false;
+ }
+ else if (this->ChipManufacturer == Intel)
+ {
+ if (this->ChipID.Family < 0xf)
+ {
+ return false;
+ }
+ }
+
+#if USE_CPUID
+ if (!call_cpuid(0x80000000, cpuinfo))
+ {
+ return false;
+ }
+#endif
+
+ // Now we have to check the level wanted vs level returned...
+ int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF);
+ int nLevelReturn = (cpuinfo[0] & 0x7FFFFFFF);
+
+ // Check to see if the level provided is supported...
+ if (nLevelWanted > nLevelReturn)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+/** */
+bool SystemInformationImplementation::RetrieveExtendedCPUFeatures()
+{
+
+ // Check that we are not using an Intel processor as it does not support this.
+ if (this->ChipManufacturer == Intel)
+ {
+ return false;
+ }
+
+ // Check to see if what we are about to do is supported...
+ if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000001)))
+ {
+ return false;
+ }
+
+#if USE_CPUID
+ int localCPUExtendedFeatures[4] = { 0, 0, 0, 0 };
+
+ if (!call_cpuid(0x80000001, localCPUExtendedFeatures))
+ {
+ return false;
+ }
+
+ // Retrieve the extended features of CPU present.
+ this->Features.ExtendedFeatures.Has3DNow = ((localCPUExtendedFeatures[3] & 0x80000000) != 0); // 3DNow Present --> Bit 31.
+ this->Features.ExtendedFeatures.Has3DNowPlus = ((localCPUExtendedFeatures[3] & 0x40000000) != 0); // 3DNow+ Present -- > Bit 30.
+ this->Features.ExtendedFeatures.HasSSEMMX = ((localCPUExtendedFeatures[3] & 0x00400000) != 0); // SSE MMX Present --> Bit 22.
+ this->Features.ExtendedFeatures.SupportsMP = ((localCPUExtendedFeatures[3] & 0x00080000) != 0); // MP Capable -- > Bit 19.
+
+ // Retrieve AMD specific extended features.
+ if (this->ChipManufacturer == AMD)
+ {
+ this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures[3] & 0x00400000) != 0); // AMD specific: MMX-SSE --> Bit 22
+ }
+
+ // Retrieve Cyrix specific extended features.
+ if (this->ChipManufacturer == Cyrix)
+ {
+ this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures[3] & 0x01000000) != 0); // Cyrix specific: Extended MMX --> Bit 24
+ }
+
+ return true;
+
+#else
+ return false;
+#endif
+}
+
+
+/** */
+bool SystemInformationImplementation::RetrieveProcessorSerialNumber()
+{
+ // Check to see if the processor supports the processor serial number.
+ if (!this->Features.HasSerial)
+ {
+ return false;
+ }
+
+#if USE_CPUID
+ int SerialNumber[4];
+
+ if (!call_cpuid(3, SerialNumber))
+ {
+ return false;
+ }
+
+ // Process the returned information.
+ // ; eax = 3 --> ebx: top 32 bits are the processor signature bits --> NB: Transmeta only ?!?
+ // ; ecx: middle 32 bits are the processor signature bits
+ // ; edx: bottom 32 bits are the processor signature bits
+ char sn[128];
+ sprintf (sn, "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x",
+ ((SerialNumber[1] & 0xff000000) >> 24),
+ ((SerialNumber[1] & 0x00ff0000) >> 16),
+ ((SerialNumber[1] & 0x0000ff00) >> 8),
+ ((SerialNumber[1] & 0x000000ff) >> 0),
+ ((SerialNumber[2] & 0xff000000) >> 24),
+ ((SerialNumber[2] & 0x00ff0000) >> 16),
+ ((SerialNumber[2] & 0x0000ff00) >> 8),
+ ((SerialNumber[2] & 0x000000ff) >> 0),
+ ((SerialNumber[3] & 0xff000000) >> 24),
+ ((SerialNumber[3] & 0x00ff0000) >> 16),
+ ((SerialNumber[3] & 0x0000ff00) >> 8),
+ ((SerialNumber[3] & 0x000000ff) >> 0));
+ this->ChipID.SerialNumber = sn;
+ return true;
+
+#else
+ return false;
+#endif
+}
+
+
+/** */
+bool SystemInformationImplementation::RetrieveCPUPowerManagement()
+{
+ // Check to see if what we are about to do is supported...
+ if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000007)))
+ {
+ this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = false;
+ this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = false;
+ this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = false;
+ return false;
+ }
+
+#if USE_CPUID
+ int localCPUPowerManagement[4] = { 0, 0, 0, 0 };
+
+ if (!call_cpuid(0x80000007, localCPUPowerManagement))
+ {
+ return false;
+ }
+
+ // Check for the power management capabilities of the CPU.
+ this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = ((localCPUPowerManagement[3] & 0x00000001) != 0);
+ this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = ((localCPUPowerManagement[3] & 0x00000002) != 0);
+ this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = ((localCPUPowerManagement[3] & 0x00000004) != 0);
+
+ return true;
+
+#else
+ return false;
+#endif
+}
+
+#if USE_CPUID
+// Used only in USE_CPUID implementation below.
+static void SystemInformationStripLeadingSpace(std::string& str)
+{
+ // Because some manufacturers have leading white space - we have to post-process the name.
+ std::string::size_type pos = str.find_first_not_of(" ");
+ if(pos != std::string::npos)
+ {
+ str = str.substr(pos);
+ }
+}
+#endif
+
+/** */
+bool SystemInformationImplementation::RetrieveExtendedCPUIdentity()
+{
+ // Check to see if what we are about to do is supported...
+ if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000002)))
+ return false;
+ if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000003)))
+ return false;
+ if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000004)))
+ return false;
+
+#if USE_CPUID
+ int CPUExtendedIdentity[12];
+
+ if (!call_cpuid(0x80000002, CPUExtendedIdentity))
+ {
+ return false;
+ }
+ if (!call_cpuid(0x80000003, CPUExtendedIdentity + 4))
+ {
+ return false;
+ }
+ if (!call_cpuid(0x80000004, CPUExtendedIdentity + 8))
+ {
+ return false;
+ }
+
+ // Process the returned information.
+ char nbuf[49];
+ memcpy (&(nbuf[0]), &(CPUExtendedIdentity[0]), sizeof (int));
+ memcpy (&(nbuf[4]), &(CPUExtendedIdentity[1]), sizeof (int));
+ memcpy (&(nbuf[8]), &(CPUExtendedIdentity[2]), sizeof (int));
+ memcpy (&(nbuf[12]), &(CPUExtendedIdentity[3]), sizeof (int));
+ memcpy (&(nbuf[16]), &(CPUExtendedIdentity[4]), sizeof (int));
+ memcpy (&(nbuf[20]), &(CPUExtendedIdentity[5]), sizeof (int));
+ memcpy (&(nbuf[24]), &(CPUExtendedIdentity[6]), sizeof (int));
+ memcpy (&(nbuf[28]), &(CPUExtendedIdentity[7]), sizeof (int));
+ memcpy (&(nbuf[32]), &(CPUExtendedIdentity[8]), sizeof (int));
+ memcpy (&(nbuf[36]), &(CPUExtendedIdentity[9]), sizeof (int));
+ memcpy (&(nbuf[40]), &(CPUExtendedIdentity[10]), sizeof (int));
+ memcpy (&(nbuf[44]), &(CPUExtendedIdentity[11]), sizeof (int));
+ nbuf[48] = '\0';
+ this->ChipID.ProcessorName = nbuf;
+ this->ChipID.ModelName = nbuf;
+
+ // Because some manufacturers have leading white space - we have to post-process the name.
+ SystemInformationStripLeadingSpace(this->ChipID.ProcessorName);
+ return true;
+#else
+ return false;
+#endif
+}
+
+
+/** */
+bool SystemInformationImplementation::RetrieveClassicalCPUIdentity()
+{
+ // Start by decided which manufacturer we are using....
+ switch (this->ChipManufacturer)
+ {
+ case Intel:
+ // Check the family / model / revision to determine the CPU ID.
+ switch (this->ChipID.Family) {
+ case 3:
+ this->ChipID.ProcessorName = "Newer i80386 family";
+ break;
+ case 4:
+ switch (this->ChipID.Model) {
+ case 0: this->ChipID.ProcessorName = "i80486DX-25/33"; break;
+ case 1: this->ChipID.ProcessorName = "i80486DX-50"; break;
+ case 2: this->ChipID.ProcessorName = "i80486SX"; break;
+ case 3: this->ChipID.ProcessorName = "i80486DX2"; break;
+ case 4: this->ChipID.ProcessorName = "i80486SL"; break;
+ case 5: this->ChipID.ProcessorName = "i80486SX2"; break;
+ case 7: this->ChipID.ProcessorName = "i80486DX2 WriteBack"; break;
+ case 8: this->ChipID.ProcessorName = "i80486DX4"; break;
+ case 9: this->ChipID.ProcessorName = "i80486DX4 WriteBack"; break;
+ default: this->ChipID.ProcessorName = "Unknown 80486 family"; return false;
+ }
+ break;
+ case 5:
+ switch (this->ChipID.Model)
+ {
+ case 0: this->ChipID.ProcessorName = "P5 A-Step"; break;
+ case 1: this->ChipID.ProcessorName = "P5"; break;
+ case 2: this->ChipID.ProcessorName = "P54C"; break;
+ case 3: this->ChipID.ProcessorName = "P24T OverDrive"; break;
+ case 4: this->ChipID.ProcessorName = "P55C"; break;
+ case 7: this->ChipID.ProcessorName = "P54C"; break;
+ case 8: this->ChipID.ProcessorName = "P55C (0.25micron)"; break;
+ default: this->ChipID.ProcessorName = "Unknown Pentium family"; return false;
+ }
+ break;
+ case 6:
+ switch (this->ChipID.Model)
+ {
+ case 0: this->ChipID.ProcessorName = "P6 A-Step"; break;
+ case 1: this->ChipID.ProcessorName = "P6"; break;
+ case 3: this->ChipID.ProcessorName = "Pentium II (0.28 micron)"; break;
+ case 5: this->ChipID.ProcessorName = "Pentium II (0.25 micron)"; break;
+ case 6: this->ChipID.ProcessorName = "Pentium II With On-Die L2 Cache"; break;
+ case 7: this->ChipID.ProcessorName = "Pentium III (0.25 micron)"; break;
+ case 8: this->ChipID.ProcessorName = "Pentium III (0.18 micron) With 256 KB On-Die L2 Cache "; break;
+ case 0xa: this->ChipID.ProcessorName = "Pentium III (0.18 micron) With 1 Or 2 MB On-Die L2 Cache "; break;
+ case 0xb: this->ChipID.ProcessorName = "Pentium III (0.13 micron) With 256 Or 512 KB On-Die L2 Cache "; break;
+ case 23: this->ChipID.ProcessorName = "Intel(R) Core(TM)2 Duo CPU T9500 @ 2.60GHz"; break;
+ default: this->ChipID.ProcessorName = "Unknown P6 family"; return false;
+ }
+ break;
+ case 7:
+ this->ChipID.ProcessorName = "Intel Merced (IA-64)";
+ break;
+ case 0xf:
+ // Check the extended family bits...
+ switch (this->ChipID.ExtendedFamily)
+ {
+ case 0:
+ switch (this->ChipID.Model)
+ {
+ case 0: this->ChipID.ProcessorName = "Pentium IV (0.18 micron)"; break;
+ case 1: this->ChipID.ProcessorName = "Pentium IV (0.18 micron)"; break;
+ case 2: this->ChipID.ProcessorName = "Pentium IV (0.13 micron)"; break;
+ default: this->ChipID.ProcessorName = "Unknown Pentium 4 family"; return false;
+ }
+ break;
+ case 1:
+ this->ChipID.ProcessorName = "Intel McKinley (IA-64)";
+ break;
+ default:
+ this->ChipID.ProcessorName = "Pentium";
+ }
+ break;
+ default:
+ this->ChipID.ProcessorName = "Unknown Intel family";
+ return false;
+ }
+ break;
+
+ case AMD:
+ // Check the family / model / revision to determine the CPU ID.
+ switch (this->ChipID.Family)
+ {
+ case 4:
+ switch (this->ChipID.Model)
+ {
+ case 3: this->ChipID.ProcessorName = "80486DX2"; break;
+ case 7: this->ChipID.ProcessorName = "80486DX2 WriteBack"; break;
+ case 8: this->ChipID.ProcessorName = "80486DX4"; break;
+ case 9: this->ChipID.ProcessorName = "80486DX4 WriteBack"; break;
+ case 0xe: this->ChipID.ProcessorName = "5x86"; break;
+ case 0xf: this->ChipID.ProcessorName = "5x86WB"; break;
+ default: this->ChipID.ProcessorName = "Unknown 80486 family"; return false;
+ }
+ break;
+ case 5:
+ switch (this->ChipID.Model)
+ {
+ case 0: this->ChipID.ProcessorName = "SSA5 (PR75, PR90 = PR100)"; break;
+ case 1: this->ChipID.ProcessorName = "5k86 (PR120 = PR133)"; break;
+ case 2: this->ChipID.ProcessorName = "5k86 (PR166)"; break;
+ case 3: this->ChipID.ProcessorName = "5k86 (PR200)"; break;
+ case 6: this->ChipID.ProcessorName = "K6 (0.30 micron)"; break;
+ case 7: this->ChipID.ProcessorName = "K6 (0.25 micron)"; break;
+ case 8: this->ChipID.ProcessorName = "K6-2"; break;
+ case 9: this->ChipID.ProcessorName = "K6-III"; break;
+ case 0xd: this->ChipID.ProcessorName = "K6-2+ or K6-III+ (0.18 micron)"; break;
+ default: this->ChipID.ProcessorName = "Unknown 80586 family"; return false;
+ }
+ break;
+ case 6:
+ switch (this->ChipID.Model)
+ {
+ case 1: this->ChipID.ProcessorName = "Athlon- (0.25 micron)"; break;
+ case 2: this->ChipID.ProcessorName = "Athlon- (0.18 micron)"; break;
+ case 3: this->ChipID.ProcessorName = "Duron- (SF core)"; break;
+ case 4: this->ChipID.ProcessorName = "Athlon- (Thunderbird core)"; break;
+ case 6: this->ChipID.ProcessorName = "Athlon- (Palomino core)"; break;
+ case 7: this->ChipID.ProcessorName = "Duron- (Morgan core)"; break;
+ case 8:
+ if (this->Features.ExtendedFeatures.SupportsMP)
+ this->ChipID.ProcessorName = "Athlon - MP (Thoroughbred core)";
+ else this->ChipID.ProcessorName = "Athlon - XP (Thoroughbred core)";
+ break;
+ default: this->ChipID.ProcessorName = "Unknown K7 family"; return false;
+ }
+ break;
+ default:
+ this->ChipID.ProcessorName = "Unknown AMD family";
+ return false;
+ }
+ break;
+
+ case Transmeta:
+ switch (this->ChipID.Family)
+ {
+ case 5:
+ switch (this->ChipID.Model)
+ {
+ case 4: this->ChipID.ProcessorName = "Crusoe TM3x00 and TM5x00"; break;
+ default: this->ChipID.ProcessorName = "Unknown Crusoe family"; return false;
+ }
+ break;
+ default:
+ this->ChipID.ProcessorName = "Unknown Transmeta family";
+ return false;
+ }
+ break;
+
+ case Rise:
+ switch (this->ChipID.Family)
+ {
+ case 5:
+ switch (this->ChipID.Model)
+ {
+ case 0: this->ChipID.ProcessorName = "mP6 (0.25 micron)"; break;
+ case 2: this->ChipID.ProcessorName = "mP6 (0.18 micron)"; break;
+ default: this->ChipID.ProcessorName = "Unknown Rise family"; return false;
+ }
+ break;
+ default:
+ this->ChipID.ProcessorName = "Unknown Rise family";
+ return false;
+ }
+ break;
+
+ case UMC:
+ switch (this->ChipID.Family)
+ {
+ case 4:
+ switch (this->ChipID.Model)
+ {
+ case 1: this->ChipID.ProcessorName = "U5D"; break;
+ case 2: this->ChipID.ProcessorName = "U5S"; break;
+ default: this->ChipID.ProcessorName = "Unknown UMC family"; return false;
+ }
+ break;
+ default:
+ this->ChipID.ProcessorName = "Unknown UMC family";
+ return false;
+ }
+ break;
+
+ case IDT:
+ switch (this->ChipID.Family)
+ {
+ case 5:
+ switch (this->ChipID.Model)
+ {
+ case 4: this->ChipID.ProcessorName = "C6"; break;
+ case 8: this->ChipID.ProcessorName = "C2"; break;
+ case 9: this->ChipID.ProcessorName = "C3"; break;
+ default: this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; return false;
+ }
+ break;
+ case 6:
+ switch (this->ChipID.Model)
+ {
+ case 6: this->ChipID.ProcessorName = "VIA Cyrix III - Samuel"; break;
+ default: this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; return false;
+ }
+ break;
+ default:
+ this->ChipID.ProcessorName = "Unknown IDT\\Centaur family";
+ return false;
+ }
+ break;
+
+ case Cyrix:
+ switch (this->ChipID.Family)
+ {
+ case 4:
+ switch (this->ChipID.Model)
+ {
+ case 4: this->ChipID.ProcessorName = "MediaGX GX = GXm"; break;
+ case 9: this->ChipID.ProcessorName = "5x86"; break;
+ default: this->ChipID.ProcessorName = "Unknown Cx5x86 family"; return false;
+ }
+ break;
+ case 5:
+ switch (this->ChipID.Model)
+ {
+ case 2: this->ChipID.ProcessorName = "Cx6x86"; break;
+ case 4: this->ChipID.ProcessorName = "MediaGX GXm"; break;
+ default: this->ChipID.ProcessorName = "Unknown Cx6x86 family"; return false;
+ }
+ break;
+ case 6:
+ switch (this->ChipID.Model)
+ {
+ case 0: this->ChipID.ProcessorName = "6x86MX"; break;
+ case 5: this->ChipID.ProcessorName = "Cyrix M2 Core"; break;
+ case 6: this->ChipID.ProcessorName = "WinChip C5A Core"; break;
+ case 7: this->ChipID.ProcessorName = "WinChip C5B\\C5C Core"; break;
+ case 8: this->ChipID.ProcessorName = "WinChip C5C-T Core"; break;
+ default: this->ChipID.ProcessorName = "Unknown 6x86MX\\Cyrix III family"; return false;
+ }
+ break;
+ default:
+ this->ChipID.ProcessorName = "Unknown Cyrix family";
+ return false;
+ }
+ break;
+
+ case NexGen:
+ switch (this->ChipID.Family)
+ {
+ case 5:
+ switch (this->ChipID.Model)
+ {
+ case 0: this->ChipID.ProcessorName = "Nx586 or Nx586FPU"; break;
+ default: this->ChipID.ProcessorName = "Unknown NexGen family"; return false;
+ }
+ break;
+ default:
+ this->ChipID.ProcessorName = "Unknown NexGen family";
+ return false;
+ }
+ break;
+
+ case NSC:
+ this->ChipID.ProcessorName = "Cx486SLC \\ DLC \\ Cx486S A-Step";
+ break;
+
+ case Sun:
+ case IBM:
+ case Motorola:
+ case HP:
+ case UnknownManufacturer:
+ default:
+ this->ChipID.ProcessorName = "Unknown family"; // We cannot identify the processor.
+ return false;
+ }
+
+ return true;
+}
+
+
+/** Extract a value from the CPUInfo file */
+std::string SystemInformationImplementation::ExtractValueFromCpuInfoFile(std::string buffer,const char* word,size_t init)
+{
+ size_t pos = buffer.find(word,init);
+ if(pos != buffer.npos)
+ {
+ this->CurrentPositionInFile = pos;
+ pos = buffer.find(":",pos);
+ size_t pos2 = buffer.find("\n",pos);
+ if(pos!=buffer.npos && pos2!=buffer.npos)
+ {
+ // It may happen that the beginning matches, but this is still not the requested key.
+ // An example is looking for "cpu" when "cpu family" comes first. So we check that
+ // we have only spaces from here to pos, otherwise we search again.
+ for(size_t i=this->CurrentPositionInFile+strlen(word); i < pos; ++i)
+ {
+ if(buffer[i] != ' ' && buffer[i] != '\t')
+ {
+ return this->ExtractValueFromCpuInfoFile(buffer, word, pos2);
+ }
+ }
+ return buffer.substr(pos+2,pos2-pos-2);
+ }
+ }
+ this->CurrentPositionInFile = buffer.npos;
+ return "";
+}
+
+/** Query for the cpu status */
+bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile()
+{
+ this->NumberOfLogicalCPU = 0;
+ this->NumberOfPhysicalCPU = 0;
+ std::string buffer;
+
+ FILE *fd = fopen("/proc/cpuinfo", "r" );
+ if ( !fd )
+ {
+ std::cout << "Problem opening /proc/cpuinfo" << std::endl;
+ return false;
+ }
+
+ size_t fileSize = 0;
+ while(!feof(fd))
+ {
+ buffer += static_cast<char>(fgetc(fd));
+ fileSize++;
+ }
+ fclose( fd );
+ buffer.resize(fileSize-2);
+ // Number of logical CPUs (combination of multiple processors, multi-core
+ // and hyperthreading)
+ size_t pos = buffer.find("processor\t");
+ while(pos != buffer.npos)
+ {
+ this->NumberOfLogicalCPU++;
+ pos = buffer.find("processor\t",pos+1);
+ }
+
+#ifdef __linux
+ // Find the largest physical id.
+ int maxId = -1;
+ std::string idc =
+ this->ExtractValueFromCpuInfoFile(buffer,"physical id");
+ while(this->CurrentPositionInFile != buffer.npos)
+ {
+ int id = atoi(idc.c_str());
+ if(id > maxId)
+ {
+ maxId=id;
+ }
+ idc = this->ExtractValueFromCpuInfoFile(buffer,"physical id",
+ this->CurrentPositionInFile+1);
+ }
+ // Physical ids returned by Linux don't distinguish cores.
+ // We want to record the total number of cores in this->NumberOfPhysicalCPU
+ // (checking only the first proc)
+ std::string cores =
+ this->ExtractValueFromCpuInfoFile(buffer,"cpu cores");
+ int numberOfCoresPerCPU=atoi(cores.c_str());
+ if (maxId > 0)
+ {
+ this->NumberOfPhysicalCPU=static_cast<unsigned int>(
+ numberOfCoresPerCPU*(maxId+1));
+ }
+ else
+ {
+ // Linux Sparc: get cpu count
+ this->NumberOfPhysicalCPU=
+ atoi(this->ExtractValueFromCpuInfoFile(buffer,"ncpus active").c_str());
+ }
+
+#else // __CYGWIN__
+ // does not have "physical id" entries, neither "cpu cores"
+ // this has to be fixed for hyper-threading.
+ std::string cpucount =
+ this->ExtractValueFromCpuInfoFile(buffer,"cpu count");
+ this->NumberOfPhysicalCPU=
+ this->NumberOfLogicalCPU = atoi(cpucount.c_str());
+#endif
+ // gotta have one, and if this is 0 then we get a / by 0n
+ // better to have a bad answer than a crash
+ if(this->NumberOfPhysicalCPU <= 0)
+ {
+ this->NumberOfPhysicalCPU = 1;
+ }
+ // LogicalProcessorsPerPhysical>1 => hyperthreading.
+ this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical=
+ this->NumberOfLogicalCPU/this->NumberOfPhysicalCPU;
+
+ // CPU speed (checking only the first processor)
+ std::string CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer,"cpu MHz");
+ if(!CPUSpeed.empty())
+ {
+ this->CPUSpeedInMHz = static_cast<float>(atof(CPUSpeed.c_str()));
+ }
+#ifdef __linux
+ else
+ {
+ // Linux Sparc: CPU speed is in Hz and encoded in hexadecimal
+ CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer,"Cpu0ClkTck");
+ this->CPUSpeedInMHz = static_cast<float>(
+ strtoull(CPUSpeed.c_str(),0,16))/1000000.0f;
+ }
+#endif
+
+ // Chip family
+ std::string familyStr =
+ this->ExtractValueFromCpuInfoFile(buffer,"cpu family");
+ if(familyStr.empty())
+ {
+ familyStr = this->ExtractValueFromCpuInfoFile(buffer,"CPU architecture");
+ }
+ this->ChipID.Family = atoi(familyStr.c_str());
+
+ // Chip Vendor
+ this->ChipID.Vendor = this->ExtractValueFromCpuInfoFile(buffer,"vendor_id");
+ this->FindManufacturer(familyStr);
+
+ // second try for setting family
+ if (this->ChipID.Family == 0 && this->ChipManufacturer == HP)
+ {
+ if (familyStr == "PA-RISC 1.1a")
+ this->ChipID.Family = 0x11a;
+ else if (familyStr == "PA-RISC 2.0")
+ this->ChipID.Family = 0x200;
+ // If you really get CMake to work on a machine not belonging to
+ // any of those families I owe you a dinner if you get it to
+ // contribute nightly builds regularly.
+ }
+
+ // Chip Model
+ this->ChipID.Model = atoi(this->ExtractValueFromCpuInfoFile(buffer,"model").c_str());
+ if(!this->RetrieveClassicalCPUIdentity())
+ {
+ // Some platforms (e.g. PA-RISC) tell us their CPU name here.
+ // Note: x86 does not.
+ std::string cpuname = this->ExtractValueFromCpuInfoFile(buffer,"cpu");
+ if(!cpuname.empty())
+ {
+ this->ChipID.ProcessorName = cpuname;
+ }
+ }
+
+ // Chip revision
+ std::string cpurev = this->ExtractValueFromCpuInfoFile(buffer,"stepping");
+ if(cpurev.empty())
+ {
+ cpurev = this->ExtractValueFromCpuInfoFile(buffer,"CPU revision");
+ }
+ this->ChipID.Revision = atoi(cpurev.c_str());
+
+ // Chip Model Name
+ this->ChipID.ModelName = this->ExtractValueFromCpuInfoFile(buffer,"model name").c_str();
+
+ // L1 Cache size
+ // Different architectures may show different names for the caches.
+ // Sum up everything we find.
+ std::vector<const char*> cachename;
+ cachename.clear();
+
+ cachename.push_back("cache size"); // e.g. x86
+ cachename.push_back("I-cache"); // e.g. PA-RISC
+ cachename.push_back("D-cache"); // e.g. PA-RISC
+
+ this->Features.L1CacheSize = 0;
+ for (size_t index = 0; index < cachename.size(); index ++)
+ {
+ std::string cacheSize = this->ExtractValueFromCpuInfoFile(buffer,cachename[index]);
+ if (!cacheSize.empty())
+ {
+ pos = cacheSize.find(" KB");
+ if(pos!=cacheSize.npos)
+ {
+ cacheSize = cacheSize.substr(0,pos);
+ }
+ this->Features.L1CacheSize += atoi(cacheSize.c_str());
+ }
+ }
+
+ // processor feature flags (probably x86 specific)
+ std::string cpuflags = this->ExtractValueFromCpuInfoFile(buffer,"flags");
+ if(!cpurev.empty())
+ {
+ // now we can match every flags as space + flag + space
+ cpuflags = " " + cpuflags + " ";
+ if ((cpuflags.find(" fpu ")!=std::string::npos))
+ {
+ this->Features.HasFPU = true;
+ }
+ if ((cpuflags.find(" tsc ")!=std::string::npos))
+ {
+ this->Features.HasTSC = true;
+ }
+ if ((cpuflags.find(" mmx ")!=std::string::npos))
+ {
+ this->Features.HasMMX = true;
+ }
+ if ((cpuflags.find(" sse ")!=std::string::npos))
+ {
+ this->Features.HasSSE = true;
+ }
+ if ((cpuflags.find(" sse2 ")!=std::string::npos))
+ {
+ this->Features.HasSSE2 = true;
+ }
+ if ((cpuflags.find(" apic ")!=std::string::npos))
+ {
+ this->Features.HasAPIC = true;
+ }
+ if ((cpuflags.find(" cmov ")!=std::string::npos))
+ {
+ this->Features.HasCMOV = true;
+ }
+ if ((cpuflags.find(" mtrr ")!=std::string::npos))
+ {
+ this->Features.HasMTRR = true;
+ }
+ if ((cpuflags.find(" acpi ")!=std::string::npos))
+ {
+ this->Features.HasACPI = true;
+ }
+ if ((cpuflags.find(" 3dnow ")!=std::string::npos))
+ {
+ this->Features.ExtendedFeatures.Has3DNow = true;
+ }
+ }
+
+ return true;
+}
+
+bool SystemInformationImplementation::QueryProcessorBySysconf()
+{
+#if defined(_SC_NPROC_ONLN) && !defined(_SC_NPROCESSORS_ONLN)
+// IRIX names this slightly different
+# define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
+#endif
+
+#ifdef _SC_NPROCESSORS_ONLN
+ long c = sysconf(_SC_NPROCESSORS_ONLN);
+ if (c <= 0)
+ {
+ return false;
+ }
+
+ this->NumberOfPhysicalCPU = static_cast<unsigned int>(c);
+ this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryProcessor()
+{
+ return this->QueryProcessorBySysconf();
+}
+
+/**
+Get total system RAM in units of KiB.
+*/
+SystemInformation::LongLong
+SystemInformationImplementation::GetHostMemoryTotal()
+{
+#if defined(_WIN32)
+# if defined(_MSC_VER) && _MSC_VER < 1300
+ MEMORYSTATUS stat;
+ stat.dwLength = sizeof(stat);
+ GlobalMemoryStatus(&stat);
+ return stat.dwTotalPhys/1024;
+# else
+ MEMORYSTATUSEX statex;
+ statex.dwLength=sizeof(statex);
+ GlobalMemoryStatusEx(&statex);
+ return statex.ullTotalPhys/1024;
+# endif
+#elif defined(__linux)
+ SystemInformation::LongLong memTotal=0;
+ int ierr=GetFieldFromFile("/proc/meminfo","MemTotal:",memTotal);
+ if (ierr)
+ {
+ return -1;
+ }
+ return memTotal;
+#elif defined(__APPLE__)
+ uint64_t mem;
+ size_t len = sizeof(mem);
+ int ierr=sysctlbyname("hw.memsize", &mem, &len, NULL, 0);
+ if (ierr)
+ {
+ return -1;
+ }
+ return mem/1024;
+#else
+ return 0;
+#endif
+}
+
+/**
+Get total system RAM in units of KiB. This may differ from the
+host total if a host-wide resource limit is applied.
+*/
+SystemInformation::LongLong
+SystemInformationImplementation::GetHostMemoryAvailable(const char *hostLimitEnvVarName)
+{
+ SystemInformation::LongLong memTotal=this->GetHostMemoryTotal();
+
+ // the following mechanism is provided for systems that
+ // apply resource limits across groups of processes.
+ // this is of use on certain SMP systems (eg. SGI UV)
+ // where the host has a large amount of ram but a given user's
+ // access to it is severly restricted. The system will
+ // apply a limit across a set of processes. Units are in KiB.
+ if (hostLimitEnvVarName)
+ {
+ const char *hostLimitEnvVarValue=getenv(hostLimitEnvVarName);
+ if (hostLimitEnvVarValue)
+ {
+ SystemInformation::LongLong hostLimit=atoLongLong(hostLimitEnvVarValue);
+ if (hostLimit>0)
+ {
+ memTotal=min(hostLimit,memTotal);
+ }
+ }
+ }
+
+ return memTotal;
+}
+
+/**
+Get total system RAM in units of KiB. This may differ from the
+host total if a per-process resource limit is applied.
+*/
+SystemInformation::LongLong
+SystemInformationImplementation::GetProcMemoryAvailable(
+ const char *hostLimitEnvVarName,
+ const char *procLimitEnvVarName)
+{
+ SystemInformation::LongLong memAvail
+ = this->GetHostMemoryAvailable(hostLimitEnvVarName);
+
+ // the following mechanism is provide for systems where rlimits
+ // are not employed. Units are in KiB.
+ if (procLimitEnvVarName)
+ {
+ const char *procLimitEnvVarValue=getenv(procLimitEnvVarName);
+ if (procLimitEnvVarValue)
+ {
+ SystemInformation::LongLong procLimit=atoLongLong(procLimitEnvVarValue);
+ if (procLimit>0)
+ {
+ memAvail=min(procLimit,memAvail);
+ }
+ }
+ }
+
+#if defined(__linux)
+ int ierr;
+ ResourceLimitType rlim;
+ ierr=GetResourceLimit(RLIMIT_DATA,&rlim);
+ if ((ierr==0) && (rlim.rlim_cur != RLIM_INFINITY))
+ {
+ memAvail=min((SystemInformation::LongLong)rlim.rlim_cur/1024,memAvail);
+ }
+
+ ierr=GetResourceLimit(RLIMIT_AS,&rlim);
+ if ((ierr==0) && (rlim.rlim_cur != RLIM_INFINITY))
+ {
+ memAvail=min((SystemInformation::LongLong)rlim.rlim_cur/1024,memAvail);
+ }
+#elif defined(__APPLE__)
+ struct rlimit rlim;
+ int ierr;
+ ierr=getrlimit(RLIMIT_DATA,&rlim);
+ if ((ierr==0) && (rlim.rlim_cur != RLIM_INFINITY))
+ {
+ memAvail=min((SystemInformation::LongLong)rlim.rlim_cur/1024,memAvail);
+ }
+
+ ierr=getrlimit(RLIMIT_RSS,&rlim);
+ if ((ierr==0) && (rlim.rlim_cur != RLIM_INFINITY))
+ {
+ memAvail=min((SystemInformation::LongLong)rlim.rlim_cur/1024,memAvail);
+ }
+#endif
+
+ return memAvail;
+}
+
+/**
+Get RAM used by all processes in the host, in units of KiB.
+*/
+SystemInformation::LongLong
+SystemInformationImplementation::GetHostMemoryUsed()
+{
+#if defined(_WIN32)
+# if defined(_MSC_VER) && _MSC_VER < 1300
+ MEMORYSTATUS stat;
+ stat.dwLength = sizeof(stat);
+ GlobalMemoryStatus(&stat);
+ return (stat.dwTotalPhys - stat.dwAvailPhys)/1024;
+# else
+ MEMORYSTATUSEX statex;
+ statex.dwLength=sizeof(statex);
+ GlobalMemoryStatusEx(&statex);
+ return (statex.ullTotalPhys - statex.ullAvailPhys)/1024;
+# endif
+#elif defined(__linux)
+ // First try to use MemAvailable, but it only works on newer kernels
+ const char *names2[3]={"MemTotal:","MemAvailable:",NULL};
+ SystemInformation::LongLong values2[2]={SystemInformation::LongLong(0)};
+ int ierr=GetFieldsFromFile("/proc/meminfo",names2,values2);
+ if (ierr)
+ {
+ const char *names4[5]={"MemTotal:","MemFree:","Buffers:","Cached:",NULL};
+ SystemInformation::LongLong values4[4]={SystemInformation::LongLong(0)};
+ ierr=GetFieldsFromFile("/proc/meminfo",names4,values4);
+ if(ierr)
+ {
+ return ierr;
+ }
+ SystemInformation::LongLong &memTotal=values4[0];
+ SystemInformation::LongLong &memFree=values4[1];
+ SystemInformation::LongLong &memBuffers=values4[2];
+ SystemInformation::LongLong &memCached=values4[3];
+ return memTotal - memFree - memBuffers - memCached;
+ }
+ SystemInformation::LongLong &memTotal=values2[0];
+ SystemInformation::LongLong &memAvail=values2[1];
+ return memTotal - memAvail;
+#elif defined(__APPLE__)
+ SystemInformation::LongLong psz=getpagesize();
+ if (psz<1)
+ {
+ return -1;
+ }
+ const char *names[3]={"Pages wired down:","Pages active:",NULL};
+ SystemInformation::LongLong values[2]={SystemInformation::LongLong(0)};
+ int ierr=GetFieldsFromCommand("vm_stat", names, values);
+ if (ierr)
+ {
+ return -1;
+ }
+ SystemInformation::LongLong &vmWired=values[0];
+ SystemInformation::LongLong &vmActive=values[1];
+ return ((vmActive+vmWired)*psz)/1024;
+#else
+ return 0;
+#endif
+}
+
+/**
+Get system RAM used by the process associated with the given
+process id in units of KiB.
+*/
+SystemInformation::LongLong
+SystemInformationImplementation::GetProcMemoryUsed()
+{
+#if defined(_WIN32) && defined(KWSYS_SYS_HAS_PSAPI)
+ long pid=GetCurrentProcessId();
+ HANDLE hProc;
+ hProc=OpenProcess(
+ PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
+ false,
+ pid);
+ if (hProc==0)
+ {
+ return -1;
+ }
+ PROCESS_MEMORY_COUNTERS pmc;
+ int ok=GetProcessMemoryInfo(hProc,&pmc,sizeof(pmc));
+ CloseHandle(hProc);
+ if (!ok)
+ {
+ return -2;
+ }
+ return pmc.WorkingSetSize/1024;
+#elif defined(__linux)
+ SystemInformation::LongLong memUsed=0;
+ int ierr=GetFieldFromFile("/proc/self/status","VmRSS:",memUsed);
+ if (ierr)
+ {
+ return -1;
+ }
+ return memUsed;
+#elif defined(__APPLE__)
+ SystemInformation::LongLong memUsed=0;
+ pid_t pid=getpid();
+ std::ostringstream oss;
+ oss << "ps -o rss= -p " << pid;
+ FILE *file=popen(oss.str().c_str(),"r");
+ if (file==0)
+ {
+ return -1;
+ }
+ oss.str("");
+ while (!feof(file) && !ferror(file))
+ {
+ char buf[256]={'\0'};
+ errno=0;
+ size_t nRead=fread(buf,1,256,file);
+ if (ferror(file) && (errno==EINTR))
+ {
+ clearerr(file);
+ }
+ if (nRead) oss << buf;
+ }
+ int ierr=ferror(file);
+ pclose(file);
+ if (ierr)
+ {
+ return -2;
+ }
+ std::istringstream iss(oss.str());
+ iss >> memUsed;
+ return memUsed;
+#else
+ return 0;
+#endif
+}
+
+double SystemInformationImplementation::GetLoadAverage()
+{
+#if defined(KWSYS_CXX_HAS_GETLOADAVG)
+ double loadavg[3] = { 0.0, 0.0, 0.0 };
+ if (getloadavg(loadavg, 3) > 0)
+ {
+ return loadavg[0];
+ }
+ return -0.0;
+#elif defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes)
+ // Old windows.h headers do not provide GetSystemTimes.
+ typedef BOOL (WINAPI *GetSystemTimesType)(LPFILETIME, LPFILETIME,
+ LPFILETIME);
+ static GetSystemTimesType pGetSystemTimes =
+ (GetSystemTimesType)GetProcAddress(GetModuleHandleW(L"kernel32"),
+ "GetSystemTimes");
+ FILETIME idleTime, kernelTime, userTime;
+ if (pGetSystemTimes && pGetSystemTimes(&idleTime, &kernelTime, &userTime))
+ {
+ unsigned __int64 const idleTicks =
+ fileTimeToUInt64(idleTime);
+ unsigned __int64 const totalTicks =
+ fileTimeToUInt64(kernelTime) + fileTimeToUInt64(userTime);
+ return calculateCPULoad(idleTicks, totalTicks) * GetNumberOfPhysicalCPU();
+ }
+ return -0.0;
+#else
+ // Not implemented on this platform.
+ return -0.0;
+#endif
+}
+
+/**
+Get the process id of the running process.
+*/
+SystemInformation::LongLong
+SystemInformationImplementation::GetProcessId()
+{
+#if defined(_WIN32)
+ return GetCurrentProcessId();
+#elif defined(__linux) || defined(__APPLE__)
+ return getpid();
+#else
+ return -1;
+#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"
+#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
+ ;
+
+ std::ostringstream oss;
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
+ void *stackSymbols[256];
+ int nFrames=backtrace(stackSymbols,256);
+ for (int i=firstFrame; i<nFrames; ++i)
+ {
+ SymbolProperties symProps;
+ symProps.SetReportPath(wholePath);
+ symProps.Initialize(stackSymbols[i]);
+ oss << symProps << std::endl;
+ }
+#else
+ (void)firstFrame;
+ (void)wholePath;
+#endif
+ programStack += oss.str();
+
+ return programStack;
+}
+
+
+/**
+when set print stack trace in response to common signals.
+*/
+void SystemInformationImplementation::SetStackTraceOnError(int enable)
+{
+#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
+ static int saOrigValid=0;
+ static struct sigaction saABRTOrig;
+ static struct sigaction saSEGVOrig;
+ static struct sigaction saTERMOrig;
+ static struct sigaction saINTOrig;
+ static struct sigaction saILLOrig;
+ static struct sigaction saBUSOrig;
+ static struct sigaction saFPEOrig;
+
+
+ if (enable && !saOrigValid)
+ {
+ // save the current actions
+ sigaction(SIGABRT,0,&saABRTOrig);
+ sigaction(SIGSEGV,0,&saSEGVOrig);
+ sigaction(SIGTERM,0,&saTERMOrig);
+ sigaction(SIGINT,0,&saINTOrig);
+ sigaction(SIGILL,0,&saILLOrig);
+ sigaction(SIGBUS,0,&saBUSOrig);
+ sigaction(SIGFPE,0,&saFPEOrig);
+
+ // enable read, disable write
+ saOrigValid=1;
+
+ // install ours
+ struct sigaction sa;
+ sa.sa_sigaction=(SigAction)StacktraceSignalHandler;
+ sa.sa_flags=SA_SIGINFO|SA_RESETHAND;
+# ifdef SA_RESTART
+ sa.sa_flags|=SA_RESTART;
+# endif
+ sigemptyset(&sa.sa_mask);
+
+ sigaction(SIGABRT,&sa,0);
+ sigaction(SIGSEGV,&sa,0);
+ sigaction(SIGTERM,&sa,0);
+ sigaction(SIGINT,&sa,0);
+ sigaction(SIGILL,&sa,0);
+ sigaction(SIGBUS,&sa,0);
+ sigaction(SIGFPE,&sa,0);
+ }
+ else
+ if (!enable && saOrigValid)
+ {
+ // restore previous actions
+ sigaction(SIGABRT,&saABRTOrig,0);
+ sigaction(SIGSEGV,&saSEGVOrig,0);
+ sigaction(SIGTERM,&saTERMOrig,0);
+ sigaction(SIGINT,&saINTOrig,0);
+ sigaction(SIGILL,&saILLOrig,0);
+ sigaction(SIGBUS,&saBUSOrig,0);
+ sigaction(SIGFPE,&saFPEOrig,0);
+
+ // enable write, disable read
+ saOrigValid=0;
+ }
+#else
+ // avoid warning C4100
+ (void)enable;
+#endif
+}
+
+bool SystemInformationImplementation::QueryWindowsMemory()
+{
+#if defined(_WIN32)
+# if defined(_MSC_VER) && _MSC_VER < 1300
+ MEMORYSTATUS ms;
+ unsigned long tv, tp, av, ap;
+ ms.dwLength = sizeof(ms);
+ GlobalMemoryStatus(&ms);
+# define MEM_VAL(value) dw##value
+# else
+ MEMORYSTATUSEX ms;
+ DWORDLONG tv, tp, av, ap;
+ ms.dwLength = sizeof(ms);
+ if (0 == GlobalMemoryStatusEx(&ms))
+ {
+ return 0;
+ }
+# define MEM_VAL(value) ull##value
+# endif
+ tv = ms.MEM_VAL(TotalPageFile);
+ tp = ms.MEM_VAL(TotalPhys);
+ av = ms.MEM_VAL(AvailPageFile);
+ ap = ms.MEM_VAL(AvailPhys);
+ this->TotalVirtualMemory = tv>>10>>10;
+ this->TotalPhysicalMemory = tp>>10>>10;
+ this->AvailableVirtualMemory = av>>10>>10;
+ this->AvailablePhysicalMemory = ap>>10>>10;
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryLinuxMemory()
+{
+#if defined(__linux)
+ unsigned long tv=0;
+ unsigned long tp=0;
+ unsigned long av=0;
+ unsigned long ap=0;
+
+ char buffer[1024]; // for reading lines
+
+ int linuxMajor = 0;
+ int linuxMinor = 0;
+
+ // Find the Linux kernel version first
+ struct utsname unameInfo;
+ int errorFlag = uname(&unameInfo);
+ if( errorFlag!=0 )
+ {
+ std::cout << "Problem calling uname(): " << strerror(errno) << std::endl;
+ return false;
+ }
+
+ if( strlen(unameInfo.release)>=3 )
+ {
+ // release looks like "2.6.3-15mdk-i686-up-4GB"
+ char majorChar=unameInfo.release[0];
+ char minorChar=unameInfo.release[2];
+
+ if( isdigit(majorChar) )
+ {
+ linuxMajor=majorChar-'0';
+ }
+
+ if( isdigit(minorChar) )
+ {
+ linuxMinor=minorChar-'0';
+ }
+ }
+
+ FILE *fd = fopen("/proc/meminfo", "r" );
+ if ( !fd )
+ {
+ std::cout << "Problem opening /proc/meminfo" << std::endl;
+ return false;
+ }
+
+ if( linuxMajor>=3 || ( (linuxMajor>=2) && (linuxMinor>=6) ) )
+ {
+ // new /proc/meminfo format since kernel 2.6.x
+ // Rigorously, this test should check from the developping version 2.5.x
+ // that introduced the new format...
+
+ enum { mMemTotal, mMemFree, mBuffers, mCached, mSwapTotal, mSwapFree };
+ const char* format[6] =
+ { "MemTotal:%lu kB", "MemFree:%lu kB", "Buffers:%lu kB",
+ "Cached:%lu kB", "SwapTotal:%lu kB", "SwapFree:%lu kB" };
+ bool have[6] = { false, false, false, false, false, false };
+ unsigned long value[6];
+ int count = 0;
+ while(fgets(buffer, static_cast<int>(sizeof(buffer)), fd))
+ {
+ for(int i=0; i < 6; ++i)
+ {
+ if(!have[i] && sscanf(buffer, format[i], &value[i]) == 1)
+ {
+ have[i] = true;
+ ++count;
+ }
+ }
+ }
+ if(count == 6)
+ {
+ this->TotalPhysicalMemory = value[mMemTotal] / 1024;
+ this->AvailablePhysicalMemory =
+ (value[mMemFree] + value[mBuffers] + value[mCached]) / 1024;
+ this->TotalVirtualMemory = value[mSwapTotal] / 1024;
+ this->AvailableVirtualMemory = value[mSwapFree] / 1024;
+ }
+ else
+ {
+ std::cout << "Problem parsing /proc/meminfo" << std::endl;
+ fclose(fd);
+ return false;
+ }
+ }
+ else
+ {
+ // /proc/meminfo format for kernel older than 2.6.x
+
+ unsigned long temp;
+ unsigned long cachedMem;
+ unsigned long buffersMem;
+ // Skip "total: used:..."
+ char *r=fgets(buffer, static_cast<int>(sizeof(buffer)), fd);
+ int status=0;
+ if(r==buffer)
+ {
+ status+=fscanf(fd, "Mem: %lu %lu %lu %lu %lu %lu\n",
+ &tp, &temp, &ap, &temp, &buffersMem, &cachedMem);
+ }
+ if(status==6)
+ {
+ status+=fscanf(fd, "Swap: %lu %lu %lu\n", &tv, &temp, &av);
+ }
+ if(status==9)
+ {
+ this->TotalVirtualMemory = tv>>10>>10;
+ this->TotalPhysicalMemory = tp>>10>>10;
+ this->AvailableVirtualMemory = av>>10>>10;
+ this->AvailablePhysicalMemory = (ap+buffersMem+cachedMem)>>10>>10;
+ }
+ else
+ {
+ std::cout << "Problem parsing /proc/meminfo" << std::endl;
+ fclose(fd);
+ return false;
+ }
+ }
+ fclose( fd );
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryCygwinMemory()
+{
+#ifdef __CYGWIN__
+ // _SC_PAGE_SIZE does return the mmap() granularity on Cygwin,
+ // see http://cygwin.com/ml/cygwin/2006-06/msg00350.html
+ // Therefore just use 4096 as the page size of Windows.
+ long m = sysconf(_SC_PHYS_PAGES);
+ if (m < 0)
+ {
+ return false;
+ }
+ this->TotalPhysicalMemory = m >> 8;
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryAIXMemory()
+{
+#if defined(_AIX) && defined(_SC_AIX_REALMEM)
+ long c = sysconf(_SC_AIX_REALMEM);
+ if (c <= 0)
+ {
+ return false;
+ }
+
+ this->TotalPhysicalMemory = c / 1024;
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryMemoryBySysconf()
+{
+#if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
+ // Assume the mmap() granularity as returned by _SC_PAGESIZE is also
+ // the system page size. The only known system where this isn't true
+ // is Cygwin.
+ long p = sysconf(_SC_PHYS_PAGES);
+ long m = sysconf(_SC_PAGESIZE);
+
+ if (p < 0 || m < 0)
+ {
+ return false;
+ }
+
+ // assume pagesize is a power of 2 and smaller 1 MiB
+ size_t pagediv = (1024 * 1024 / m);
+
+ this->TotalPhysicalMemory = p;
+ this->TotalPhysicalMemory /= pagediv;
+
+#if defined(_SC_AVPHYS_PAGES)
+ p = sysconf(_SC_AVPHYS_PAGES);
+ if (p < 0)
+ {
+ return false;
+ }
+
+ this->AvailablePhysicalMemory = p;
+ this->AvailablePhysicalMemory /= pagediv;
+#endif
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+/** Query for the memory status */
+bool SystemInformationImplementation::QueryMemory()
+{
+ return this->QueryMemoryBySysconf();
+}
+
+/** */
+size_t SystemInformationImplementation::GetTotalVirtualMemory()
+{
+ return this->TotalVirtualMemory;
+}
+
+/** */
+size_t SystemInformationImplementation::GetAvailableVirtualMemory()
+{
+ return this->AvailableVirtualMemory;
+}
+
+size_t SystemInformationImplementation::GetTotalPhysicalMemory()
+{
+ return this->TotalPhysicalMemory;
+}
+
+/** */
+size_t SystemInformationImplementation::GetAvailablePhysicalMemory()
+{
+ return this->AvailablePhysicalMemory;
+}
+
+/** Get Cycle differences */
+SystemInformation::LongLong
+SystemInformationImplementation::GetCyclesDifference (DELAY_FUNC DelayFunction,
+ unsigned int uiParameter)
+{
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+ unsigned __int64 stamp1, stamp2;
+
+ stamp1 = __rdtsc();
+ DelayFunction(uiParameter);
+ stamp2 = __rdtsc();
+
+ return stamp2 - stamp1;
+#elif USE_ASM_INSTRUCTIONS
+
+ unsigned int edx1, eax1;
+ unsigned int edx2, eax2;
+
+ // Calculate the frequency of the CPU instructions.
+ __try {
+ _asm {
+ push uiParameter ; push parameter param
+ mov ebx, DelayFunction ; store func in ebx
+
+ RDTSC_INSTRUCTION
+
+ mov esi, eax ; esi = eax
+ mov edi, edx ; edi = edx
+
+ call ebx ; call the delay functions
+
+ RDTSC_INSTRUCTION
+
+ pop ebx
+
+ mov edx2, edx ; edx2 = edx
+ mov eax2, eax ; eax2 = eax
+
+ mov edx1, edi ; edx2 = edi
+ mov eax1, esi ; eax2 = esi
+ }
+ }
+ __except(1)
+ {
+ return -1;
+ }
+
+ return ((((__int64) edx2 << 32) + eax2) - (((__int64) edx1 << 32) + eax1));
+
+#else
+ (void)DelayFunction;
+ (void)uiParameter;
+ return -1;
+#endif
+}
+
+
+/** Compute the delay overhead */
+void SystemInformationImplementation::DelayOverhead(unsigned int uiMS)
+{
+#if defined(_WIN32)
+ LARGE_INTEGER Frequency, StartCounter, EndCounter;
+ __int64 x;
+
+ // Get the frequency of the high performance counter.
+ if(!QueryPerformanceFrequency (&Frequency))
+ {
+ return;
+ }
+ x = Frequency.QuadPart / 1000 * uiMS;
+
+ // Get the starting position of the counter.
+ QueryPerformanceCounter (&StartCounter);
+
+ do {
+ // Get the ending position of the counter.
+ QueryPerformanceCounter (&EndCounter);
+ } while (EndCounter.QuadPart - StartCounter.QuadPart == x);
+#endif
+ (void)uiMS;
+}
+
+/** Return the number of logical CPU per physical CPUs Works only for windows */
+unsigned char SystemInformationImplementation::LogicalCPUPerPhysicalCPU(void)
+{
+#ifdef __APPLE__
+ size_t len = 4;
+ int cores_per_package = 0;
+ int err = sysctlbyname("machdep.cpu.cores_per_package", &cores_per_package, &len, NULL, 0);
+ if (err != 0)
+ {
+ return 1; // That name was not found, default to 1
+ }
+ return static_cast<unsigned char>(cores_per_package);
+#else
+ int Regs[4] = { 0, 0, 0, 0 };
+#if USE_CPUID
+ if (!this->IsHyperThreadingSupported())
+ {
+ return static_cast<unsigned char>(1); // HT not supported
+ }
+ call_cpuid(1, Regs);
+#endif
+ return static_cast<unsigned char> ((Regs[1] & NUM_LOGICAL_BITS) >> 16);
+#endif
+}
+
+
+/** Works only for windows */
+bool SystemInformationImplementation::IsHyperThreadingSupported()
+{
+ if (this->Features.ExtendedFeatures.SupportsHyperthreading)
+ {
+ return true;
+ }
+
+#if USE_CPUID
+ int Regs[4] = { 0, 0, 0, 0 },
+ VendorId[4] = { 0, 0, 0, 0 };
+ // Get vendor id string
+ if (!call_cpuid(0, VendorId))
+ {
+ return false;
+ }
+ // eax contains family processor type
+ // edx has info about the availability of hyper-Threading
+ if (!call_cpuid(1, Regs))
+ {
+ return false;
+ }
+
+ if (((Regs[0] & FAMILY_ID) == PENTIUM4_ID) || (Regs[0] & EXT_FAMILY_ID))
+ {
+ if (VendorId[1] == 0x756e6547) // 'uneG'
+ {
+ if (VendorId[3] == 0x49656e69) // 'Ieni'
+ {
+ if (VendorId[2] == 0x6c65746e) // 'letn'
+ {
+ // Genuine Intel with hyper-Threading technology
+ this->Features.ExtendedFeatures.SupportsHyperthreading = ((Regs[3] & HT_BIT) != 0);
+ return this->Features.ExtendedFeatures.SupportsHyperthreading;
+ }
+ }
+ }
+ }
+#endif
+
+ return 0; // Not genuine Intel processor
+}
+
+
+/** Return the APIC Id. Works only for windows. */
+unsigned char SystemInformationImplementation::GetAPICId()
+{
+ int Regs[4] = { 0, 0, 0, 0 };
+
+#if USE_CPUID
+ if (!this->IsHyperThreadingSupported())
+ {
+ return static_cast<unsigned char>(-1); // HT not supported
+ } // Logical processor = 1
+ call_cpuid(1, Regs);
+#endif
+
+ return static_cast<unsigned char>((Regs[1] & INITIAL_APIC_ID_BITS) >> 24);
+}
+
+
+/** Count the number of CPUs. Works only on windows. */
+int SystemInformationImplementation::CPUCount()
+{
+#if defined(_WIN32)
+ unsigned char StatusFlag = 0;
+ SYSTEM_INFO info;
+
+ this->NumberOfPhysicalCPU = 0;
+ this->NumberOfLogicalCPU = 0;
+ info.dwNumberOfProcessors = 0;
+ GetSystemInfo (&info);
+
+ // Number of physical processors in a non-Intel system
+ // or in a 32-bit Intel system with Hyper-Threading technology disabled
+ this->NumberOfPhysicalCPU = (unsigned char) info.dwNumberOfProcessors;
+
+ if (this->IsHyperThreadingSupported())
+ {
+ unsigned char HT_Enabled = 0;
+ this->NumberOfLogicalCPU = this->LogicalCPUPerPhysicalCPU();
+ if (this->NumberOfLogicalCPU >= 1) // >1 Doesn't mean HT is enabled in the BIOS
+ {
+ HANDLE hCurrentProcessHandle;
+#ifndef _WIN64
+# define DWORD_PTR DWORD
+#endif
+ DWORD_PTR dwProcessAffinity;
+ DWORD_PTR dwSystemAffinity;
+ DWORD dwAffinityMask;
+
+ // Calculate the appropriate shifts and mask based on the
+ // number of logical processors.
+ unsigned int i = 1;
+ unsigned char PHY_ID_MASK = 0xFF;
+ //unsigned char PHY_ID_SHIFT = 0;
+
+ while (i < this->NumberOfLogicalCPU)
+ {
+ i *= 2;
+ PHY_ID_MASK <<= 1;
+ // PHY_ID_SHIFT++;
+ }
+
+ hCurrentProcessHandle = GetCurrentProcess();
+ GetProcessAffinityMask(hCurrentProcessHandle, &dwProcessAffinity,
+ &dwSystemAffinity);
+
+ // Check if available process affinity mask is equal to the
+ // available system affinity mask
+ if (dwProcessAffinity != dwSystemAffinity)
+ {
+ StatusFlag = HT_CANNOT_DETECT;
+ this->NumberOfPhysicalCPU = (unsigned char)-1;
+ return StatusFlag;
+ }
+
+ dwAffinityMask = 1;
+ while (dwAffinityMask != 0 && dwAffinityMask <= dwProcessAffinity)
+ {
+ // Check if this CPU is available
+ if (dwAffinityMask & dwProcessAffinity)
+ {
+ if (SetProcessAffinityMask(hCurrentProcessHandle,
+ dwAffinityMask))
+ {
+ unsigned char APIC_ID, LOG_ID;
+ Sleep(0); // Give OS time to switch CPU
+
+ APIC_ID = GetAPICId();
+ LOG_ID = APIC_ID & ~PHY_ID_MASK;
+
+ if (LOG_ID != 0)
+ {
+ HT_Enabled = 1;
+ }
+ }
+ }
+ dwAffinityMask = dwAffinityMask << 1;
+ }
+ // Reset the processor affinity
+ SetProcessAffinityMask(hCurrentProcessHandle, dwProcessAffinity);
+
+ if (this->NumberOfLogicalCPU == 1) // Normal P4 : HT is disabled in hardware
+ {
+ StatusFlag = HT_DISABLED;
+ }
+ else
+ {
+ if (HT_Enabled)
+ {
+ // Total physical processors in a Hyper-Threading enabled system.
+ this->NumberOfPhysicalCPU /= (this->NumberOfLogicalCPU);
+ StatusFlag = HT_ENABLED;
+ }
+ else
+ {
+ StatusFlag = HT_SUPPORTED_NOT_ENABLED;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Processors do not have Hyper-Threading technology
+ StatusFlag = HT_NOT_CAPABLE;
+ this->NumberOfLogicalCPU = 1;
+ }
+ return StatusFlag;
+#else
+ return 0;
+#endif
+}
+
+
+/** Return the number of logical CPUs on the system */
+unsigned int SystemInformationImplementation::GetNumberOfLogicalCPU()
+{
+ return this->NumberOfLogicalCPU;
+}
+
+
+/** Return the number of physical CPUs on the system */
+unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU()
+{
+ return this->NumberOfPhysicalCPU;
+}
+
+
+/** For Mac use sysctlbyname calls to find system info */
+bool SystemInformationImplementation::ParseSysCtl()
+{
+#if defined(__APPLE__)
+ char retBuf[128];
+ int err = 0;
+ uint64_t value = 0;
+ size_t len = sizeof(value);
+ sysctlbyname("hw.memsize", &value, &len, NULL, 0);
+ this->TotalPhysicalMemory = static_cast< size_t >( value/1048576 );
+
+ // Parse values for Mac
+ this->AvailablePhysicalMemory = 0;
+ vm_statistics_data_t vmstat;
+ mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+ if ( host_statistics(mach_host_self(), HOST_VM_INFO,
+ (host_info_t) &vmstat, &count) == KERN_SUCCESS )
+ {
+ len = sizeof(value);
+ err = sysctlbyname("hw.pagesize", &value, &len, NULL, 0);
+ int64_t available_memory = vmstat.free_count * value;
+ this->AvailablePhysicalMemory = static_cast< size_t >( available_memory / 1048576 );
+ }
+
+#ifdef VM_SWAPUSAGE
+ // Virtual memory.
+ int mib[2] = { CTL_VM, VM_SWAPUSAGE };
+ size_t miblen = sizeof(mib) / sizeof(mib[0]);
+ struct xsw_usage swap;
+ len = sizeof(swap);
+ err = sysctl(mib, miblen, &swap, &len, NULL, 0);
+ if (err == 0)
+ {
+ this->AvailableVirtualMemory = static_cast< size_t >( swap.xsu_avail/1048576 );
+ this->TotalVirtualMemory = static_cast< size_t >( swap.xsu_total/1048576 );
+ }
+#else
+ this->AvailableVirtualMemory = 0;
+ this->TotalVirtualMemory = 0;
+#endif
+
+// CPU Info
+ len = sizeof(this->NumberOfPhysicalCPU);
+ sysctlbyname("hw.physicalcpu", &this->NumberOfPhysicalCPU, &len, NULL, 0);
+ len = sizeof(this->NumberOfLogicalCPU);
+ sysctlbyname("hw.logicalcpu", &this->NumberOfLogicalCPU, &len, NULL, 0);
+ this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical =
+ this->LogicalCPUPerPhysicalCPU();
+
+ len = sizeof(value);
+ sysctlbyname("hw.cpufrequency", &value, &len, NULL, 0);
+ this->CPUSpeedInMHz = static_cast< float >( value )/ 1000000;
+
+
+ // Chip family
+ len = sizeof(this->ChipID.Family);
+ //Seems only the intel chips will have this name so if this fails it is
+ //probably a PPC machine
+ err = sysctlbyname("machdep.cpu.family",
+ &this->ChipID.Family, &len, NULL, 0);
+ if (err != 0) // Go back to names we know but are less descriptive
+ {
+ this->ChipID.Family = 0;
+ ::memset(retBuf, 0, 128);
+ len = 32;
+ err = sysctlbyname("hw.machine", &retBuf, &len, NULL, 0);
+ std::string machineBuf(retBuf);
+ if (machineBuf.find_first_of("Power") != std::string::npos)
+ {
+ this->ChipID.Vendor = "IBM";
+ len = sizeof(this->ChipID.Family);
+ err = sysctlbyname("hw.cputype", &this->ChipID.Family, &len, NULL, 0);
+ len = sizeof(this->ChipID.Model);
+ err = sysctlbyname("hw.cpusubtype", &this->ChipID.Model, &len, NULL, 0);
+ this->FindManufacturer();
+ }
+ }
+ else // Should be an Intel Chip.
+ {
+ len = sizeof(this->ChipID.Family);
+ err =
+ sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, NULL, 0);
+
+ ::memset(retBuf, 0, 128);
+ len = 128;
+ err = sysctlbyname("machdep.cpu.vendor", retBuf, &len, NULL, 0);
+ // Chip Vendor
+ this->ChipID.Vendor = retBuf;
+ this->FindManufacturer();
+
+ // Chip Model
+ len = sizeof(value);
+ err = sysctlbyname("machdep.cpu.model", &value, &len, NULL, 0);
+ this->ChipID.Model = static_cast< int >( value );
+
+ // Chip Stepping
+ len = sizeof(value);
+ value = 0;
+ err = sysctlbyname("machdep.cpu.stepping", &value, &len, NULL, 0);
+ if (!err)
+ {
+ this->ChipID.Revision = static_cast< int >( value );
+ }
+
+ // feature string
+ char *buf = 0;
+ size_t allocSize = 128;
+
+ err = 0;
+ len = 0;
+
+ // sysctlbyname() will return with err==0 && len==0 if the buffer is too small
+ while (err == 0 && len == 0)
+ {
+ delete[] buf;
+ allocSize *= 2;
+ buf = new char[allocSize];
+ if (!buf)
+ {
+ break;
+ }
+ buf[0] = ' ';
+ len = allocSize - 2; // keep space for leading and trailing space
+ err = sysctlbyname("machdep.cpu.features", buf + 1, &len, NULL, 0);
+ }
+ if (!err && buf && len)
+ {
+ // now we can match every flags as space + flag + space
+ buf[len + 1] = ' ';
+ std::string cpuflags(buf, len + 2);
+
+ if ((cpuflags.find(" FPU ")!=std::string::npos))
+ {
+ this->Features.HasFPU = true;
+ }
+ if ((cpuflags.find(" TSC ")!=std::string::npos))
+ {
+ this->Features.HasTSC = true;
+ }
+ if ((cpuflags.find(" MMX ")!=std::string::npos))
+ {
+ this->Features.HasMMX = true;
+ }
+ if ((cpuflags.find(" SSE ")!=std::string::npos))
+ {
+ this->Features.HasSSE = true;
+ }
+ if ((cpuflags.find(" SSE2 ")!=std::string::npos))
+ {
+ this->Features.HasSSE2 = true;
+ }
+ if ((cpuflags.find(" APIC ")!=std::string::npos))
+ {
+ this->Features.HasAPIC = true;
+ }
+ if ((cpuflags.find(" CMOV ")!=std::string::npos))
+ {
+ this->Features.HasCMOV = true;
+ }
+ if ((cpuflags.find(" MTRR ")!=std::string::npos))
+ {
+ this->Features.HasMTRR = true;
+ }
+ if ((cpuflags.find(" ACPI ")!=std::string::npos))
+ {
+ this->Features.HasACPI = true;
+ }
+ }
+ delete[] buf;
+ }
+
+ // brand string
+ ::memset(retBuf, 0, sizeof(retBuf));
+ len = sizeof(retBuf);
+ err = sysctlbyname("machdep.cpu.brand_string", retBuf, &len, NULL, 0);
+ if (!err)
+ {
+ this->ChipID.ProcessorName = retBuf;
+ this->ChipID.ModelName = retBuf;
+ }
+
+ // Cache size
+ len = sizeof(value);
+ err = sysctlbyname("hw.l1icachesize", &value, &len, NULL, 0);
+ this->Features.L1CacheSize = static_cast< int >( value );
+ len = sizeof(value);
+ err = sysctlbyname("hw.l2cachesize", &value, &len, NULL, 0);
+ this->Features.L2CacheSize = static_cast< int >( value );
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+
+/** Extract a value from sysctl command */
+std::string SystemInformationImplementation::ExtractValueFromSysCtl(const char* word)
+{
+ size_t pos = this->SysCtlBuffer.find(word);
+ if(pos != this->SysCtlBuffer.npos)
+ {
+ pos = this->SysCtlBuffer.find(": ",pos);
+ size_t pos2 = this->SysCtlBuffer.find("\n",pos);
+ if(pos!=this->SysCtlBuffer.npos && pos2!=this->SysCtlBuffer.npos)
+ {
+ return this->SysCtlBuffer.substr(pos+2,pos2-pos-2);
+ }
+ }
+ return "";
+}
+
+
+/** Run a given process */
+std::string SystemInformationImplementation::RunProcess(std::vector<const char*> args)
+{
+ std::string buffer = "";
+
+ // Run the application
+ kwsysProcess* gp = kwsysProcess_New();
+ kwsysProcess_SetCommand(gp, &*args.begin());
+ kwsysProcess_SetOption(gp,kwsysProcess_Option_HideWindow,1);
+
+ kwsysProcess_Execute(gp);
+
+ char* data = NULL;
+ int length;
+ double timeout = 255;
+ int pipe; // pipe id as returned by kwsysProcess_WaitForData()
+
+ while( ( static_cast<void>(pipe = kwsysProcess_WaitForData(gp,&data,&length,&timeout)),
+ (pipe == kwsysProcess_Pipe_STDOUT || pipe == kwsysProcess_Pipe_STDERR) ) ) // wait for 1s
+ {
+ buffer.append(data, length);
+ }
+ kwsysProcess_WaitForExit(gp, 0);
+
+ int result = 0;
+ switch(kwsysProcess_GetState(gp))
+ {
+ case kwsysProcess_State_Exited:
+ {
+ result = kwsysProcess_GetExitValue(gp);
+ } break;
+ case kwsysProcess_State_Error:
+ {
+ std::cerr << "Error: Could not run " << args[0] << ":\n";
+ std::cerr << kwsysProcess_GetErrorString(gp) << "\n";
+ } break;
+ case kwsysProcess_State_Exception:
+ {
+ std::cerr << "Error: " << args[0]
+ << " terminated with an exception: "
+ << kwsysProcess_GetExceptionString(gp) << "\n";
+ } break;
+ case kwsysProcess_State_Starting:
+ case kwsysProcess_State_Executing:
+ case kwsysProcess_State_Expired:
+ case kwsysProcess_State_Killed:
+ {
+ // Should not get here.
+ std::cerr << "Unexpected ending state after running " << args[0]
+ << std::endl;
+ } break;
+ }
+ kwsysProcess_Delete(gp);
+ if(result)
+ {
+ std::cerr << "Error " << args[0] << " returned :" << result << "\n";
+ }
+ return buffer;
+}
+
+
+std::string SystemInformationImplementation::ParseValueFromKStat(const char* arguments)
+{
+ std::vector<const char*> args;
+ args.clear();
+ args.push_back("kstat");
+ args.push_back("-p");
+
+ std::string command = arguments;
+ size_t start = command.npos;
+ size_t pos = command.find(' ',0);
+ while(pos!=command.npos)
+ {
+ bool inQuotes = false;
+ // Check if we are between quotes
+ size_t b0 = command.find('"',0);
+ size_t b1 = command.find('"',b0+1);
+ while(b0 != command.npos && b1 != command.npos && b1>b0)
+ {
+ if(pos>b0 && pos<b1)
+ {
+ inQuotes = true;
+ break;
+ }
+ b0 = command.find('"',b1+1);
+ b1 = command.find('"',b0+1);
+ }
+
+ if(!inQuotes)
+ {
+ std::string arg = command.substr(start+1,pos-start-1);
+
+ // Remove the quotes if any
+ size_t quotes = arg.find('"');
+ while(quotes != arg.npos)
+ {
+ arg.erase(quotes,1);
+ quotes = arg.find('"');
+ }
+ args.push_back(arg.c_str());
+ start = pos;
+ }
+ pos = command.find(' ',pos+1);
+ }
+ std::string lastArg = command.substr(start+1,command.size()-start-1);
+ args.push_back(lastArg.c_str());
+
+ args.push_back(0);
+
+ std::string buffer = this->RunProcess(args);
+
+ std::string value = "";
+ for(size_t i=buffer.size()-1;i>0;i--)
+ {
+ if(buffer[i] == ' ' || buffer[i] == '\t')
+ {
+ break;
+ }
+ if(buffer[i] != '\n' && buffer[i] != '\r')
+ {
+ std::string val = value;
+ value = buffer[i];
+ value += val;
+ }
+ }
+ return value;
+}
+
+/** Querying for system information from Solaris */
+bool SystemInformationImplementation::QuerySolarisMemory()
+{
+#if defined (__SVR4) && defined (__sun)
+ // Solaris allows querying this value by sysconf, but if this is
+ // a 32 bit process on a 64 bit host the returned memory will be
+ // limited to 4GiB. So if this is a 32 bit process or if the sysconf
+ // method fails use the kstat interface.
+#if SIZEOF_VOID_P == 8
+ if (this->QueryMemoryBySysconf())
+ {
+ return true;
+ }
+#endif
+
+ char* tail;
+ unsigned long totalMemory =
+ strtoul(this->ParseValueFromKStat("-s physmem").c_str(),&tail,0);
+ this->TotalPhysicalMemory = totalMemory/128;
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool SystemInformationImplementation::QuerySolarisProcessor()
+{
+ if (!this->QueryProcessorBySysconf())
+ {
+ return false;
+ }
+
+ // Parse values
+ this->CPUSpeedInMHz = static_cast<float>(atoi(this->ParseValueFromKStat("-s clock_MHz").c_str()));
+
+ // Chip family
+ this->ChipID.Family = 0;
+
+ // Chip Model
+ this->ChipID.ProcessorName = this->ParseValueFromKStat("-s cpu_type");
+ this->ChipID.Model = 0;
+
+ // Chip Vendor
+ if (this->ChipID.ProcessorName != "i386")
+ {
+ this->ChipID.Vendor = "Sun";
+ this->FindManufacturer();
+ }
+
+ return true;
+}
+
+
+/** Querying for system information from Haiku OS */
+bool SystemInformationImplementation::QueryHaikuInfo()
+{
+#if defined(__HAIKU__)
+
+ // CPU count
+ system_info info;
+ get_system_info(&info);
+ this->NumberOfPhysicalCPU = info.cpu_count;
+
+ // CPU speed
+ uint32 topologyNodeCount = 0;
+ cpu_topology_node_info* topology = 0;
+ get_cpu_topology_info(0, &topologyNodeCount);
+ if (topologyNodeCount != 0)
+ topology = new cpu_topology_node_info[topologyNodeCount];
+ get_cpu_topology_info(topology, &topologyNodeCount);
+
+ for (uint32 i = 0; i < topologyNodeCount; i++) {
+ if (topology[i].type == B_TOPOLOGY_CORE) {
+ this->CPUSpeedInMHz = topology[i].data.core.default_frequency /
+ 1000000.0f;
+ break;
+ }
+ }
+
+ delete[] topology;
+
+ // Physical Memory
+ this->TotalPhysicalMemory = (info.max_pages * B_PAGE_SIZE) / (1024 * 1024) ;
+ this->AvailablePhysicalMemory = this->TotalPhysicalMemory -
+ ((info.used_pages * B_PAGE_SIZE) / (1024 * 1024));
+
+
+ // NOTE: get_system_info_etc is currently a private call so just set to 0
+ // until it becomes public
+ this->TotalVirtualMemory = 0;
+ this->AvailableVirtualMemory = 0;
+
+ // Retrieve cpuid_info union for cpu 0
+ cpuid_info cpu_info;
+ get_cpuid(&cpu_info, 0, 0);
+
+ // Chip Vendor
+ // Use a temporary buffer so that we can add NULL termination to the string
+ char vbuf[13];
+ strncpy(vbuf, cpu_info.eax_0.vendor_id, 12);
+ vbuf[12] = '\0';
+ this->ChipID.Vendor = vbuf;
+
+ this->FindManufacturer();
+
+ // Retrieve cpuid_info union for cpu 0 this time using a register value of 1
+ get_cpuid(&cpu_info, 1, 0);
+
+ this->NumberOfLogicalCPU = cpu_info.eax_1.logical_cpus;
+
+ // Chip type
+ this->ChipID.Type = cpu_info.eax_1.type;
+
+ // Chip family
+ this->ChipID.Family = cpu_info.eax_1.family;
+
+ // Chip Model
+ this->ChipID.Model = cpu_info.eax_1.model;
+
+ // Chip Revision
+ this->ChipID.Revision = cpu_info.eax_1.stepping;
+
+ // Chip Extended Family
+ this->ChipID.ExtendedFamily = cpu_info.eax_1.extended_family;
+
+ // Chip Extended Model
+ this->ChipID.ExtendedModel = cpu_info.eax_1.extended_model;
+
+ // Get ChipID.ProcessorName from other information already gathered
+ this->RetrieveClassicalCPUIdentity();
+
+ // Cache size
+ this->Features.L1CacheSize = 0;
+ this->Features.L2CacheSize = 0;
+
+ return true;
+
+#else
+ return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryQNXMemory()
+{
+#if defined(__QNX__)
+ std::string buffer;
+ std::vector<const char*> args;
+ args.clear();
+
+ args.push_back("showmem");
+ args.push_back("-S");
+ args.push_back(0);
+ buffer = this->RunProcess(args);
+ args.clear();
+
+ size_t pos = buffer.find("System RAM:");
+ if (pos == buffer.npos)
+ return false;
+ pos = buffer.find(":", pos);
+ size_t pos2 = buffer.find("M (", pos);
+ if (pos2 == buffer.npos)
+ return false;
+
+ pos++;
+ while (buffer[pos] == ' ')
+ pos++;
+
+ this->TotalPhysicalMemory = atoi(buffer.substr(pos, pos2 - pos).c_str());
+ return true;
+#endif
+ return false;
+}
+
+bool SystemInformationImplementation::QueryBSDMemory()
+{
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
+ int ctrl[2] = { CTL_HW, HW_PHYSMEM };
+#if defined(HW_PHYSMEM64)
+ int64_t k;
+ ctrl[1] = HW_PHYSMEM64;
+#else
+ int k;
+#endif
+ size_t sz = sizeof(k);
+
+ if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0)
+ {
+ return false;
+ }
+
+ this->TotalPhysicalMemory = k>>10>>10;
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryQNXProcessor()
+{
+#if defined(__QNX__)
+ // the output on my QNX 6.4.1 looks like this:
+ // Processor1: 686 Pentium II Stepping 3 2175MHz FPU
+ std::string buffer;
+ std::vector<const char*> args;
+ args.clear();
+
+ args.push_back("pidin");
+ args.push_back("info");
+ args.push_back(0);
+ buffer = this->RunProcess(args);
+ args.clear();
+
+ size_t pos = buffer.find("Processor1:");
+ if (pos == buffer.npos)
+ return false;
+
+ size_t pos2 = buffer.find("MHz", pos);
+ if (pos2 == buffer.npos)
+ return false;
+
+ size_t pos3 = pos2;
+ while (buffer[pos3] != ' ')
+ --pos3;
+
+ this->CPUSpeedInMHz = atoi(buffer.substr(pos3 + 1, pos2 - pos3 - 1).c_str());
+
+ pos2 = buffer.find(" Stepping", pos);
+ if (pos2 != buffer.npos)
+ {
+ pos2 = buffer.find(" ", pos2 + 1);
+ if (pos2 != buffer.npos && pos2 < pos3)
+ {
+ this->ChipID.Revision = atoi(buffer.substr(pos2 + 1, pos3 - pos2).c_str());
+ }
+ }
+
+ this->NumberOfPhysicalCPU = 0;
+ do
+ {
+ pos = buffer.find("\nProcessor", pos + 1);
+ ++this->NumberOfPhysicalCPU;
+ } while (pos != buffer.npos);
+ this->NumberOfLogicalCPU = 1;
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryBSDProcessor()
+{
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
+ int k;
+ size_t sz = sizeof(k);
+ int ctrl[2] = { CTL_HW, HW_NCPU };
+
+ if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0)
+ {
+ return false;
+ }
+
+ this->NumberOfPhysicalCPU = k;
+ this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
+
+#if defined(HW_CPUSPEED)
+ ctrl[1] = HW_CPUSPEED;
+
+ if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0)
+ {
+ return false;
+ }
+
+ this->CPUSpeedInMHz = (float) k;
+#endif
+
+#if defined(CPU_SSE)
+ ctrl[0] = CTL_MACHDEP;
+ ctrl[1] = CPU_SSE;
+
+ if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0)
+ {
+ return false;
+ }
+
+ this->Features.HasSSE = (k > 0);
+#endif
+
+#if defined(CPU_SSE2)
+ ctrl[0] = CTL_MACHDEP;
+ ctrl[1] = CPU_SSE2;
+
+ if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0)
+ {
+ return false;
+ }
+
+ this->Features.HasSSE2 = (k > 0);
+#endif
+
+#if defined(CPU_CPUVENDOR)
+ ctrl[0] = CTL_MACHDEP;
+ ctrl[1] = CPU_CPUVENDOR;
+ char vbuf[25];
+ ::memset(vbuf, 0, sizeof(vbuf));
+ sz = sizeof(vbuf) - 1;
+ if (sysctl(ctrl, 2, vbuf, &sz, NULL, 0) != 0)
+ {
+ return false;
+ }
+
+ this->ChipID.Vendor = vbuf;
+ this->FindManufacturer();
+#endif
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryHPUXMemory()
+{
+#if defined(__hpux)
+ unsigned long tv=0;
+ unsigned long tp=0;
+ unsigned long av=0;
+ unsigned long ap=0;
+ struct pst_static pst;
+ struct pst_dynamic pdy;
+
+ unsigned long ps = 0;
+ if (pstat_getstatic(&pst, sizeof(pst), (size_t) 1, 0) == -1)
+ {
+ return false;
+ }
+
+ ps = pst.page_size;
+ tp = pst.physical_memory *ps;
+ tv = (pst.physical_memory + pst.pst_maxmem) * ps;
+ if (pstat_getdynamic(&pdy, sizeof(pdy), (size_t) 1, 0) == -1)
+ {
+ return false;
+ }
+
+ ap = tp - pdy.psd_rm * ps;
+ av = tv - pdy.psd_vm;
+ this->TotalVirtualMemory = tv>>10>>10;
+ this->TotalPhysicalMemory = tp>>10>>10;
+ this->AvailableVirtualMemory = av>>10>>10;
+ this->AvailablePhysicalMemory = ap>>10>>10;
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryHPUXProcessor()
+{
+#if defined(__hpux)
+# if defined(KWSYS_SYS_HAS_MPCTL_H)
+ int c = mpctl(MPC_GETNUMSPUS_SYS, 0, 0);
+ if (c <= 0)
+ {
+ return false;
+ }
+
+ this->NumberOfPhysicalCPU = c;
+ this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
+
+ long t = sysconf(_SC_CPU_VERSION);
+
+ if (t == -1)
+ {
+ return false;
+ }
+
+ switch (t)
+ {
+ case CPU_PA_RISC1_0:
+ this->ChipID.Vendor = "Hewlett-Packard";
+ this->ChipID.Family = 0x100;
+ break;
+ case CPU_PA_RISC1_1:
+ this->ChipID.Vendor = "Hewlett-Packard";
+ this->ChipID.Family = 0x110;
+ break;
+ case CPU_PA_RISC2_0:
+ this->ChipID.Vendor = "Hewlett-Packard";
+ this->ChipID.Family = 0x200;
+ break;
+# if defined(CPU_HP_INTEL_EM_1_0) || defined(CPU_IA64_ARCHREV_0)
+# ifdef CPU_HP_INTEL_EM_1_0
+ case CPU_HP_INTEL_EM_1_0:
+# endif
+# ifdef CPU_IA64_ARCHREV_0
+ case CPU_IA64_ARCHREV_0:
+# endif
+ this->ChipID.Vendor = "GenuineIntel";
+ this->Features.HasIA64 = true;
+ break;
+# endif
+ default:
+ return false;
+ }
+
+ this->FindManufacturer();
+
+ return true;
+# else
+ return false;
+# endif
+#else
+ return false;
+#endif
+}
+
+/** Query the operating system information */
+bool SystemInformationImplementation::QueryOSInformation()
+{
+#if defined(_WIN32)
+
+ this->OSName = "Windows";
+
+ OSVERSIONINFOEXW osvi;
+ BOOL bIsWindows64Bit;
+ BOOL bOsVersionInfoEx;
+ char operatingSystem[256];
+
+ // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
+ ZeroMemory (&osvi, sizeof (OSVERSIONINFOEXW));
+ osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW);
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+# pragma warning (push)
+# ifdef __INTEL_COMPILER
+# pragma warning (disable:1478)
+# else
+# pragma warning (disable:4996)
+# endif
+#endif
+ bOsVersionInfoEx = GetVersionExW ((OSVERSIONINFOW*)&osvi);
+ if (!bOsVersionInfoEx)
+ {
+ osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOW);
+ if (!GetVersionExW((OSVERSIONINFOW*)&osvi))
+ {
+ return false;
+ }
+ }
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+# pragma warning (pop)
+#endif
+
+ switch (osvi.dwPlatformId)
+ {
+ case VER_PLATFORM_WIN32_NT:
+ // Test for the product.
+ if (osvi.dwMajorVersion <= 4)
+ {
+ this->OSRelease = "NT";
+ }
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
+ {
+ this->OSRelease = "2000";
+ }
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
+ {
+ this->OSRelease = "XP";
+ }
+ // XP Professional x64
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
+ {
+ this->OSRelease = "XP";
+ }
+#ifdef VER_NT_WORKSTATION
+ // Test for product type.
+ if (bOsVersionInfoEx)
+ {
+ if (osvi.wProductType == VER_NT_WORKSTATION)
+ {
+ if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
+ {
+ this->OSRelease = "Vista";
+ }
+ if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1)
+ {
+ this->OSRelease = "7";
+ }
+// VER_SUITE_PERSONAL may not be defined
+#ifdef VER_SUITE_PERSONAL
+ else
+ {
+ if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
+ {
+ this->OSRelease += " Personal";
+ }
+ else
+ {
+ this->OSRelease += " Professional";
+ }
+ }
+#endif
+ }
+ else if (osvi.wProductType == VER_NT_SERVER)
+ {
+ // Check for .NET Server instead of Windows XP.
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
+ {
+ this->OSRelease = ".NET";
+ }
+
+ // Continue with the type detection.
+ if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
+ {
+ this->OSRelease += " DataCenter Server";
+ }
+ else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
+ {
+ this->OSRelease += " Advanced Server";
+ }
+ else
+ {
+ this->OSRelease += " Server";
+ }
+ }
+
+ sprintf (operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
+ this->OSVersion = operatingSystem;
+ }
+ else
+#endif // VER_NT_WORKSTATION
+ {
+ HKEY hKey;
+ wchar_t szProductType[80];
+ DWORD dwBufLen;
+
+ // Query the registry to retrieve information.
+ RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_QUERY_VALUE, &hKey);
+ RegQueryValueExW(hKey, L"ProductType", NULL, NULL, (LPBYTE) szProductType, &dwBufLen);
+ RegCloseKey (hKey);
+
+ if (lstrcmpiW(L"WINNT", szProductType) == 0)
+ {
+ this->OSRelease += " Professional";
+ }
+ if (lstrcmpiW(L"LANMANNT", szProductType) == 0)
+ {
+ // Decide between Windows 2000 Advanced Server and Windows .NET Enterprise Server.
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
+ {
+ this->OSRelease += " Standard Server";
+ }
+ else
+ {
+ this->OSRelease += " Server";
+ }
+ }
+ if (lstrcmpiW(L"SERVERNT", szProductType) == 0)
+ {
+ // Decide between Windows 2000 Advanced Server and Windows .NET Enterprise Server.
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
+ {
+ this->OSRelease += " Enterprise Server";
+ }
+ else
+ {
+ this->OSRelease += " Advanced Server";
+ }
+ }
+ }
+
+ // Display version, service pack (if any), and build number.
+ if (osvi.dwMajorVersion <= 4)
+ {
+ // NB: NT 4.0 and earlier.
+ sprintf (operatingSystem, "version %ld.%ld %ls (Build %ld)",
+ osvi.dwMajorVersion,
+ osvi.dwMinorVersion,
+ osvi.szCSDVersion,
+ osvi.dwBuildNumber & 0xFFFF);
+ this->OSVersion = operatingSystem;
+ }
+ else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
+ {
+ // Windows XP and .NET server.
+ typedef BOOL (CALLBACK* LPFNPROC) (HANDLE, BOOL *);
+ HINSTANCE hKernelDLL;
+ LPFNPROC DLLProc;
+
+ // Load the Kernel32 DLL.
+ hKernelDLL = LoadLibraryW(L"kernel32");
+ if (hKernelDLL != NULL) {
+ // Only XP and .NET Server support IsWOW64Process so... Load dynamically!
+ DLLProc = (LPFNPROC) GetProcAddress (hKernelDLL, "IsWow64Process");
+
+ // If the function address is valid, call the function.
+ if (DLLProc != NULL) (DLLProc) (GetCurrentProcess (), &bIsWindows64Bit);
+ else bIsWindows64Bit = false;
+
+ // Free the DLL module.
+ FreeLibrary (hKernelDLL);
+ }
+ }
+ else
+ {
+ // Windows 2000 and everything else.
+ sprintf (operatingSystem,"%ls (Build %ld)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
+ this->OSVersion = operatingSystem;
+ }
+ break;
+
+ case VER_PLATFORM_WIN32_WINDOWS:
+ // Test for the product.
+ if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
+ {
+ this->OSRelease = "95";
+ if(osvi.szCSDVersion[1] == 'C')
+ {
+ this->OSRelease += "OSR 2.5";
+ }
+ else if(osvi.szCSDVersion[1] == 'B')
+ {
+ this->OSRelease += "OSR 2";
+ }
+ }
+
+ if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
+ {
+ this->OSRelease = "98";
+ if (osvi.szCSDVersion[1] == 'A' )
+ {
+ this->OSRelease += "SE";
+ }
+ }
+
+ if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
+ {
+ this->OSRelease = "Me";
+ }
+ break;
+
+ case VER_PLATFORM_WIN32s:
+ this->OSRelease = "Win32s";
+ break;
+
+ default:
+ this->OSRelease = "Unknown";
+ break;
+ }
+
+ // Get the hostname
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ char name[255];
+ wVersionRequested = MAKEWORD(2,0);
+
+ if ( WSAStartup( wVersionRequested, &wsaData ) == 0 )
+ {
+ gethostname(name,sizeof(name));
+ WSACleanup( );
+ }
+ this->Hostname = name;
+
+ const char* arch = getenv("PROCESSOR_ARCHITECTURE");
+ if(arch)
+ {
+ this->OSPlatform = arch;
+ }
+
+#else
+
+ struct utsname unameInfo;
+ int errorFlag = uname(&unameInfo);
+ if(errorFlag == 0)
+ {
+ this->OSName = unameInfo.sysname;
+ this->Hostname = unameInfo.nodename;
+ this->OSRelease = unameInfo.release;
+ this->OSVersion = unameInfo.version;
+ this->OSPlatform = unameInfo.machine;
+ }
+
+#ifdef __APPLE__
+ this->OSName="Unknown Apple OS";
+ this->OSRelease="Unknown product version";
+ this->OSVersion="Unknown build version";
+
+ this->CallSwVers("-productName",this->OSName);
+ this->CallSwVers("-productVersion",this->OSRelease);
+ this->CallSwVers("-buildVersion",this->OSVersion);
+#endif
+
+#endif
+
+ return true;
+}
+
+int SystemInformationImplementation::CallSwVers(
+ const char *arg,
+ std::string &ver)
+{
+#ifdef __APPLE__
+ std::vector<const char*> args;
+ args.push_back("sw_vers");
+ args.push_back(arg);
+ args.push_back(0);
+ ver = this->RunProcess(args);
+ this->TrimNewline(ver);
+#else
+ // avoid C4100
+ (void)arg;
+ (void)ver;
+#endif
+ return 0;
+}
+
+void SystemInformationImplementation::TrimNewline(std::string& output)
+{
+ // remove \r
+ std::string::size_type pos=0;
+ while((pos = output.find("\r", pos)) != std::string::npos)
+ {
+ output.erase(pos);
+ }
+
+ // remove \n
+ pos = 0;
+ while((pos = output.find("\n", pos)) != std::string::npos)
+ {
+ output.erase(pos);
+ }
+}
+
+
+/** Return true if the machine is 64 bits */
+bool SystemInformationImplementation::Is64Bits()
+{
+ return (sizeof(void*) == 8);
+}
+
+
+} // namespace @KWSYS_NAMESPACE@
diff --git a/Source/kwsys/SystemInformation.hxx.in b/Source/kwsys/SystemInformation.hxx.in
new file mode 100644
index 0000000..7c45388
--- /dev/null
+++ b/Source/kwsys/SystemInformation.hxx.in
@@ -0,0 +1,152 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_SystemInformation_h
+#define @KWSYS_NAMESPACE@_SystemInformation_h
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+#include <stddef.h> /* size_t */
+#include <string>
+
+namespace @KWSYS_NAMESPACE@
+{
+
+// forward declare the implementation class
+class SystemInformationImplementation;
+
+class @KWSYS_NAMESPACE@_EXPORT SystemInformation
+{
+#if @KWSYS_USE_LONG_LONG@
+ typedef long long LongLong;
+#elif @KWSYS_USE___INT64@
+ typedef __int64 LongLong;
+#else
+# error "No Long Long"
+#endif
+ friend class SystemInformationImplementation;
+ SystemInformationImplementation* Implementation;
+public:
+
+ SystemInformation ();
+ ~SystemInformation ();
+
+ const char * GetVendorString();
+ const char * GetVendorID();
+ std::string GetTypeID();
+ std::string GetFamilyID();
+ std::string GetModelID();
+ std::string GetModelName();
+ std::string GetSteppingCode();
+ const char * GetExtendedProcessorName();
+ const char * GetProcessorSerialNumber();
+ int GetProcessorCacheSize();
+ unsigned int GetLogicalProcessorsPerPhysical();
+ float GetProcessorClockFrequency();
+ int GetProcessorAPICID();
+ int GetProcessorCacheXSize(long int);
+ bool DoesCPUSupportFeature(long int);
+
+ // returns an informative general description of the cpu
+ // on this system.
+ std::string GetCPUDescription();
+
+ const char * GetHostname();
+ std::string GetFullyQualifiedDomainName();
+
+ const char * GetOSName();
+ const char * GetOSRelease();
+ const char * GetOSVersion();
+ const char * GetOSPlatform();
+
+ int GetOSIsWindows();
+ int GetOSIsLinux();
+ int GetOSIsApple();
+
+ // returns an informative general description of the os
+ // on this system.
+ std::string GetOSDescription();
+
+ bool Is64Bits();
+
+ unsigned int GetNumberOfLogicalCPU(); // per physical cpu
+ unsigned int GetNumberOfPhysicalCPU();
+
+ bool DoesCPUSupportCPUID();
+
+ // Retrieve id of the current running process
+ LongLong GetProcessId();
+
+ // Retrieve memory information in megabyte.
+ size_t GetTotalVirtualMemory();
+ size_t GetAvailableVirtualMemory();
+ size_t GetTotalPhysicalMemory();
+ size_t GetAvailablePhysicalMemory();
+
+ // returns an informative general description if the installed and
+ // available ram on this system. See the GetHostMmeoryTotal, and
+ // Get{Host,Proc}MemoryAvailable methods for more information.
+ std::string GetMemoryDescription(
+ const char *hostLimitEnvVarName=NULL,
+ const char *procLimitEnvVarName=NULL);
+
+ // Retrieve amount of physical memory installed on the system in KiB
+ // units.
+ LongLong GetHostMemoryTotal();
+
+ // Get total system RAM in units of KiB available colectivley to all
+ // processes in a process group. An example of a process group
+ // are the processes comprising an mpi program which is running in
+ // parallel. The amount of memory reported may differ from the host
+ // total if a host wide resource limit is applied. Such reource limits
+ // are reported to us via an applicaiton specified environment variable.
+ LongLong GetHostMemoryAvailable(const char *hostLimitEnvVarName=NULL);
+
+ // Get total system RAM in units of KiB available to this process.
+ // This may differ from the host available if a per-process resource
+ // limit is applied. per-process memory limits are applied on unix
+ // system via rlimit API. Resource limits that are not imposed via
+ // rlimit API may be reported to us via an application specified
+ // environment variable.
+ LongLong GetProcMemoryAvailable(
+ const char *hostLimitEnvVarName=NULL,
+ const char *procLimitEnvVarName=NULL);
+
+ // Get the system RAM used by all processes on the host, in units of KiB.
+ LongLong GetHostMemoryUsed();
+
+ // Get system RAM used by this process id in units of KiB.
+ LongLong GetProcMemoryUsed();
+
+ // Return the load average of the machine or -0.0 if it cannot
+ // be determined.
+ double GetLoadAverage();
+
+ // enable/disable stack trace signal handler. In order to
+ // produce an informative stack trace the application should
+ // be dynamically linked and compiled with debug symbols.
+ static
+ void SetStackTraceOnError(int enable);
+
+ // format and return the current program stack in a string. In
+ // order to produce an informative stack trace the application
+ // should be dynamically linked and compiled with debug symbols.
+ static
+ std::string GetProgramStack(int firstFrame, int wholePath);
+
+ /** Run the different checks */
+ void RunCPUCheck();
+ void RunOSCheck();
+ void RunMemoryCheck();
+};
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
new file mode 100644
index 0000000..c6e668d
--- /dev/null
+++ b/Source/kwsys/SystemTools.cxx
@@ -0,0 +1,5521 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifdef __osf__
+# define _OSF_SOURCE
+# define _POSIX_C_SOURCE 199506L
+# define _XOPEN_SOURCE_EXTENDED
+#endif
+
+#if defined(_WIN32) && (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__MINGW32__))
+# define KWSYS_WINDOWS_DIRS
+#else
+# if defined(__SUNPRO_CC)
+# include <fcntl.h>
+# endif
+#endif
+
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(RegularExpression.hxx)
+#include KWSYS_HEADER(SystemTools.hxx)
+#include KWSYS_HEADER(Directory.hxx)
+#include KWSYS_HEADER(FStream.hxx)
+#include KWSYS_HEADER(Encoding.hxx)
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <set>
+#include <vector>
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "RegularExpression.hxx.in"
+# include "SystemTools.hxx.in"
+# include "Directory.hxx.in"
+# include "FStream.hxx.in"
+# include "Encoding.hxx.in"
+#endif
+
+#ifdef _MSC_VER
+# pragma warning (disable: 4786)
+#endif
+
+#if defined(__sgi) && !defined(__GNUC__)
+# pragma set woff 1375 /* base class destructor not virtual */
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#ifdef __QNX__
+# include <malloc.h> /* for malloc/free on QNX */
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#ifdef _MSC_VER
+# define umask _umask // Note this is still umask on Borland
+#endif
+
+// support for realpath call
+#ifndef _WIN32
+#include <sys/time.h>
+#include <utime.h>
+#include <limits.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <pwd.h>
+#ifndef __VMS
+#include <sys/param.h>
+#include <termios.h>
+#endif
+#include <signal.h> /* sigprocmask */
+#endif
+
+// Windows API.
+#if defined(_WIN32)
+# include <windows.h>
+# include <winioctl.h>
+# ifndef INVALID_FILE_ATTRIBUTES
+# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+# endif
+# if defined(_MSC_VER) && _MSC_VER >= 1800
+# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+# endif
+#elif defined (__CYGWIN__)
+# include <windows.h>
+# undef _WIN32
+#endif
+
+#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
+extern char **environ;
+#endif
+
+#ifdef __CYGWIN__
+# include <sys/cygwin.h>
+#endif
+
+// getpwnam doesn't exist on Windows and Cray Xt3/Catamount
+// same for TIOCGWINSZ
+#if defined(_WIN32) || defined (__LIBCATAMOUNT__)
+# undef HAVE_GETPWNAM
+# undef HAVE_TTY_INFO
+#else
+# define HAVE_GETPWNAM 1
+# define HAVE_TTY_INFO 1
+#endif
+
+#define VTK_URL_PROTOCOL_REGEX "([a-zA-Z0-9]*)://(.*)"
+#define VTK_URL_REGEX "([a-zA-Z0-9]*)://(([A-Za-z0-9]+)(:([^:@]+))?@)?([^:@/]+)(:([0-9]+))?/(.+)?"
+
+#ifdef _MSC_VER
+#include <sys/utime.h>
+#else
+#include <utime.h>
+#endif
+
+
+// This is a hack to prevent warnings about these functions being
+// declared but not referenced.
+#if defined(__sgi) && !defined(__GNUC__)
+# include <sys/termios.h>
+namespace KWSYS_NAMESPACE
+{
+class SystemToolsHack
+{
+public:
+ enum
+ {
+ Ref1 = sizeof(cfgetospeed(0)),
+ Ref2 = sizeof(cfgetispeed(0)),
+ Ref3 = sizeof(tcgetattr(0, 0)),
+ Ref4 = sizeof(tcsetattr(0, 0, 0)),
+ Ref5 = sizeof(cfsetospeed(0,0)),
+ Ref6 = sizeof(cfsetispeed(0,0))
+ };
+};
+}
+#endif
+
+#if defined(_WIN32) && (defined(_MSC_VER) || defined(__WATCOMC__) ||defined(__BORLANDC__) || defined(__MINGW32__))
+#include <io.h>
+#include <direct.h>
+#define _unlink unlink
+#endif
+
+/* The maximum length of a file name. */
+#if defined(PATH_MAX)
+# define KWSYS_SYSTEMTOOLS_MAXPATH PATH_MAX
+#elif defined(MAXPATHLEN)
+# define KWSYS_SYSTEMTOOLS_MAXPATH MAXPATHLEN
+#else
+# define KWSYS_SYSTEMTOOLS_MAXPATH 16384
+#endif
+#if defined(__WATCOMC__)
+#include <direct.h>
+#define _mkdir mkdir
+#define _rmdir rmdir
+#define _getcwd getcwd
+#define _chdir chdir
+#endif
+
+#if defined(__BEOS__) && !defined(__ZETA__)
+#include <be/kernel/OS.h>
+#include <be/storage/Path.h>
+
+// BeOS 5 doesn't have usleep(), but it has snooze(), which is identical.
+static inline void usleep(unsigned int msec)
+{
+ ::snooze(msec);
+}
+
+// BeOS 5 also doesn't have realpath(), but its C++ API offers something close.
+static inline char *realpath(const char *path, char *resolved_path)
+{
+ const size_t maxlen = KWSYS_SYSTEMTOOLS_MAXPATH;
+ snprintf(resolved_path, maxlen, "%s", path);
+ BPath normalized(resolved_path, NULL, true);
+ const char *resolved = normalized.Path();
+ if (resolved != NULL) // NULL == No such file.
+ {
+ if (snprintf(resolved_path, maxlen, "%s", resolved) < maxlen)
+ {
+ return resolved_path;
+ }
+ }
+ return NULL; // something went wrong.
+}
+#endif
+
+#ifdef _WIN32
+static time_t windows_filetime_to_posix_time(const FILETIME& ft)
+{
+ LARGE_INTEGER date;
+ date.HighPart = ft.dwHighDateTime;
+ date.LowPart = ft.dwLowDateTime;
+
+ // removes the diff between 1970 and 1601
+ date.QuadPart -= ((LONGLONG)(369 * 365 + 89) * 24 * 3600 * 10000000);
+
+ // converts back from 100-nanoseconds to seconds
+ return date.QuadPart / 10000000;
+}
+#endif
+
+#ifdef KWSYS_WINDOWS_DIRS
+#include <wctype.h>
+
+inline int Mkdir(const std::string& dir)
+{
+ return _wmkdir(
+ KWSYS_NAMESPACE::SystemTools::ConvertToWindowsExtendedPath(dir).c_str());
+}
+inline int Rmdir(const std::string& dir)
+{
+ return _wrmdir(
+ KWSYS_NAMESPACE::SystemTools::ConvertToWindowsExtendedPath(dir).c_str());
+}
+inline const char* Getcwd(char* buf, unsigned int len)
+{
+ std::vector<wchar_t> w_buf(len);
+ if(_wgetcwd(&w_buf[0], len))
+ {
+ // make sure the drive letter is capital
+ if(wcslen(&w_buf[0]) > 1 && w_buf[1] == L':')
+ {
+ w_buf[0] = towupper(w_buf[0]);
+ }
+ std::string tmp = KWSYS_NAMESPACE::Encoding::ToNarrow(&w_buf[0]);
+ strcpy(buf, tmp.c_str());
+ return buf;
+ }
+ return 0;
+}
+inline int Chdir(const std::string& dir)
+{
+ #if defined(__BORLANDC__)
+ return chdir(dir.c_str());
+ #else
+ return _wchdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str());
+ #endif
+}
+inline void Realpath(const std::string& path,
+ std::string& resolved_path,
+ std::string* errorMessage = 0)
+{
+ std::wstring tmp = KWSYS_NAMESPACE::Encoding::ToWide(path);
+ wchar_t *ptemp;
+ wchar_t fullpath[MAX_PATH];
+ DWORD bufferLen = GetFullPathNameW(tmp.c_str(),
+ sizeof(fullpath) / sizeof(fullpath[0]),
+ fullpath, &ptemp);
+ if( bufferLen < sizeof(fullpath)/sizeof(fullpath[0]) )
+ {
+ resolved_path = KWSYS_NAMESPACE::Encoding::ToNarrow(fullpath);
+ KWSYS_NAMESPACE::SystemTools::ConvertToUnixSlashes(resolved_path);
+ }
+ else if(errorMessage)
+ {
+ if(bufferLen)
+ {
+ *errorMessage = "Destination path buffer size too small.";
+ }
+ else if(unsigned int errorId = GetLastError())
+ {
+ LPSTR message = NULL;
+ DWORD size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
+ | FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, errorId,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&message, 0, NULL);
+ *errorMessage = std::string(message, size);
+ LocalFree(message);
+ }
+ else
+ {
+ *errorMessage = "Unknown error.";
+ }
+
+ resolved_path = "";
+ }
+ else
+ {
+ resolved_path = path;
+ }
+}
+#else
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+inline int Mkdir(const std::string& dir)
+{
+ return mkdir(dir.c_str(), 00777);
+}
+inline int Rmdir(const std::string& dir)
+{
+ return rmdir(dir.c_str());
+}
+inline const char* Getcwd(char* buf, unsigned int len)
+{
+ return getcwd(buf, len);
+}
+
+inline int Chdir(const std::string& dir)
+{
+ return chdir(dir.c_str());
+}
+inline void Realpath(const std::string& path,
+ std::string& resolved_path,
+ std::string* errorMessage = 0)
+{
+ char resolved_name[KWSYS_SYSTEMTOOLS_MAXPATH];
+
+ errno = 0;
+ char *ret = realpath(path.c_str(), resolved_name);
+ if(ret)
+ {
+ resolved_path = ret;
+ }
+ else if(errorMessage)
+ {
+ if(errno)
+ {
+ *errorMessage = strerror(errno);
+ }
+ else
+ {
+ *errorMessage = "Unknown error.";
+ }
+
+ resolved_path = "";
+ }
+ else
+ {
+ // if path resolution fails, return what was passed in
+ resolved_path = path;
+ }
+}
+#endif
+
+#if !defined(_WIN32) && defined(__COMO__)
+// Hack for como strict mode to avoid defining _SVID_SOURCE or _BSD_SOURCE.
+extern "C"
+{
+extern FILE *popen (__const char *__command, __const char *__modes) __THROW;
+extern int pclose (FILE *__stream) __THROW;
+extern char *realpath (__const char *__restrict __name,
+ char *__restrict __resolved) __THROW;
+extern char *strdup (__const char *__s) __THROW;
+extern int putenv (char *__string) __THROW;
+}
+#endif
+
+namespace KWSYS_NAMESPACE
+{
+
+double SystemTools::GetTime(void)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+ return (429.4967296*ft.dwHighDateTime
+ + 0.0000001*ft.dwLowDateTime
+ - 11644473600.0);
+#else
+ struct timeval t;
+ gettimeofday(&t, 0);
+ return 1.0*double(t.tv_sec) + 0.000001*double(t.tv_usec);
+#endif
+}
+
+class SystemToolsTranslationMap :
+ public std::map<std::string,std::string>
+{
+};
+
+#ifdef _WIN32
+struct SystemToolsPathCaseCmp
+{
+ bool operator()(std::string const& l, std::string const& r) const
+ {
+# ifdef _MSC_VER
+ return _stricmp(l.c_str(), r.c_str()) < 0;
+# elif defined(__GNUC__)
+ return strcasecmp(l.c_str(), r.c_str()) < 0;
+# else
+ return SystemTools::Strucmp(l.c_str(), r.c_str()) < 0;
+# endif
+ }
+};
+
+class SystemToolsPathCaseMap:
+ public std::map<std::string, std::string,
+ SystemToolsPathCaseCmp> {};
+#endif
+
+// adds the elements of the env variable path to the arg passed in
+void SystemTools::GetPath(std::vector<std::string>& path, const char* env)
+{
+ size_t const old_size = path.size();
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ const char pathSep = ';';
+#else
+ const char pathSep = ':';
+#endif
+ if(!env)
+ {
+ env = "PATH";
+ }
+ const char* cpathEnv = SystemTools::GetEnv(env);
+ if ( !cpathEnv )
+ {
+ return;
+ }
+
+ std::string pathEnv = cpathEnv;
+
+ // A hack to make the below algorithm work.
+ if(!pathEnv.empty() && *pathEnv.rbegin() != pathSep)
+ {
+ pathEnv += pathSep;
+ }
+ std::string::size_type start =0;
+ bool done = false;
+ while(!done)
+ {
+ std::string::size_type endpos = pathEnv.find(pathSep, start);
+ if(endpos != std::string::npos)
+ {
+ path.push_back(pathEnv.substr(start, endpos-start));
+ start = endpos+1;
+ }
+ else
+ {
+ done = true;
+ }
+ }
+ for(std::vector<std::string>::iterator i = path.begin() + old_size;
+ i != path.end(); ++i)
+ {
+ SystemTools::ConvertToUnixSlashes(*i);
+ }
+}
+
+const char* SystemTools::GetEnv(const char* key)
+{
+ return getenv(key);
+}
+
+const char* SystemTools::GetEnv(const std::string& key)
+{
+ return SystemTools::GetEnv(key.c_str());
+}
+
+bool SystemTools::GetEnv(const char* key, std::string& result)
+{
+ const char* v = getenv(key);
+ if(v)
+ {
+ result = v;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool SystemTools::GetEnv(const std::string& key, std::string& result)
+{
+ return SystemTools::GetEnv(key.c_str(), result);
+}
+
+//----------------------------------------------------------------------------
+
+#if defined(__CYGWIN__) || defined(__GLIBC__)
+# define KWSYS_PUTENV_NAME /* putenv("A") removes A. */
+#elif defined(_WIN32)
+# define KWSYS_PUTENV_EMPTY /* putenv("A=") removes A. */
+#endif
+
+#if KWSYS_CXX_HAS_UNSETENV
+/* unsetenv("A") removes A from the environment.
+ On older platforms it returns void instead of int. */
+static int kwsysUnPutEnv(const std::string& env)
+{
+ size_t pos = env.find('=');
+ if(pos != env.npos)
+ {
+ std::string name = env.substr(0, pos);
+ unsetenv(name.c_str());
+ }
+ else
+ {
+ unsetenv(env.c_str());
+ }
+ return 0;
+}
+
+#elif defined(KWSYS_PUTENV_EMPTY) || defined(KWSYS_PUTENV_NAME)
+/* putenv("A=") or putenv("A") removes A from the environment. */
+static int kwsysUnPutEnv(const std::string& env)
+{
+ int err = 0;
+ size_t pos = env.find('=');
+ size_t const len = pos == env.npos ? env.size() : pos;
+# ifdef KWSYS_PUTENV_EMPTY
+ size_t const sz = len + 2;
+# else
+ size_t const sz = len + 1;
+# endif
+ char local_buf[256];
+ char* buf = sz > sizeof(local_buf) ? (char*)malloc(sz) : local_buf;
+ if(!buf)
+ {
+ return -1;
+ }
+ strncpy(buf, env.c_str(), len);
+# ifdef KWSYS_PUTENV_EMPTY
+ buf[len] = '=';
+ buf[len+1] = 0;
+ if(putenv(buf) < 0)
+ {
+ err = errno;
+ }
+# else
+ buf[len] = 0;
+ if(putenv(buf) < 0 && errno != EINVAL)
+ {
+ err = errno;
+ }
+# endif
+ if(buf != local_buf)
+ {
+ free(buf);
+ }
+ if(err)
+ {
+ errno = err;
+ return -1;
+ }
+ return 0;
+}
+
+#else
+/* Manipulate the "environ" global directly. */
+static int kwsysUnPutEnv(const std::string& env)
+{
+ size_t pos = env.find('=');
+ size_t const len = pos == env.npos ? env.size() : pos;
+ int in = 0;
+ int out = 0;
+ while(environ[in])
+ {
+ if(strlen(environ[in]) > len &&
+ environ[in][len] == '=' &&
+ strncmp(env.c_str(), environ[in], len) == 0)
+ {
+ ++in;
+ }
+ else
+ {
+ environ[out++] = environ[in++];
+ }
+ }
+ while(out < in)
+ {
+ environ[out++] = 0;
+ }
+ return 0;
+}
+#endif
+
+//----------------------------------------------------------------------------
+
+#if KWSYS_CXX_HAS_SETENV
+
+/* setenv("A", "B", 1) will set A=B in the environment and makes its
+ own copies of the strings. */
+bool SystemTools::PutEnv(const std::string& env)
+{
+ size_t pos = env.find('=');
+ if(pos != env.npos)
+ {
+ std::string name = env.substr(0, pos);
+ return setenv(name.c_str(), env.c_str() + pos + 1, 1) == 0;
+ }
+ else
+ {
+ return kwsysUnPutEnv(env) == 0;
+ }
+}
+
+bool SystemTools::UnPutEnv(const std::string& env)
+{
+ return kwsysUnPutEnv(env) == 0;
+}
+
+#else
+
+/* putenv("A=B") will set A=B in the environment. Most putenv implementations
+ put their argument directly in the environment. They never free the memory
+ on program exit. Keep an active set of pointers to memory we allocate and
+ pass to putenv, one per environment key. At program exit remove any
+ environment values that may still reference memory we allocated. Then free
+ the memory. This will not affect any environment values we never set. */
+
+# ifdef __INTEL_COMPILER
+# pragma warning disable 444 /* base has non-virtual destructor */
+# endif
+
+/* Order by environment key only (VAR from VAR=VALUE). */
+struct kwsysEnvCompare
+{
+ bool operator() (const char* l, const char* r) const
+ {
+ const char* leq = strchr(l, '=');
+ const char* req = strchr(r, '=');
+ size_t llen = leq? (leq-l) : strlen(l);
+ size_t rlen = req? (req-r) : strlen(r);
+ if(llen == rlen)
+ {
+ return strncmp(l,r,llen) < 0;
+ }
+ else
+ {
+ return strcmp(l,r) < 0;
+ }
+ }
+};
+
+class kwsysEnv: public std::set<const char*, kwsysEnvCompare>
+{
+ class Free
+ {
+ const char* Env;
+ public:
+ Free(const char* env): Env(env) {}
+ ~Free() { free(const_cast<char*>(this->Env)); }
+ };
+public:
+ typedef std::set<const char*, kwsysEnvCompare> derived;
+ ~kwsysEnv()
+ {
+ for(derived::iterator i = this->begin(); i != this->end(); ++i)
+ {
+ kwsysUnPutEnv(*i);
+ free(const_cast<char*>(*i));
+ }
+ }
+ const char* Release(const char* env)
+ {
+ const char* old = 0;
+ derived::iterator i = this->find(env);
+ if(i != this->end())
+ {
+ old = *i;
+ this->erase(i);
+ }
+ return old;
+ }
+ bool Put(const char* env)
+ {
+ Free oldEnv(this->Release(env));
+ static_cast<void>(oldEnv);
+ char* newEnv = strdup(env);
+ this->insert(newEnv);
+ return putenv(newEnv) == 0;
+ }
+ bool UnPut(const char* env)
+ {
+ Free oldEnv(this->Release(env));
+ static_cast<void>(oldEnv);
+ return kwsysUnPutEnv(env) == 0;
+ }
+};
+
+static kwsysEnv kwsysEnvInstance;
+
+bool SystemTools::PutEnv(const std::string& env)
+{
+ return kwsysEnvInstance.Put(env.c_str());
+}
+
+bool SystemTools::UnPutEnv(const std::string& env)
+{
+ return kwsysEnvInstance.UnPut(env.c_str());
+}
+
+#endif
+
+//----------------------------------------------------------------------------
+
+const char* SystemTools::GetExecutableExtension()
+{
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(__VMS)
+ return ".exe";
+#else
+ return "";
+#endif
+}
+
+FILE* SystemTools::Fopen(const std::string& file, const char* mode)
+{
+#ifdef _WIN32
+ return _wfopen(SystemTools::ConvertToWindowsExtendedPath(file).c_str(),
+ Encoding::ToWide(mode).c_str());
+#else
+ return fopen(file.c_str(), mode);
+#endif
+}
+
+bool SystemTools::MakeDirectory(const char* path)
+{
+ if(!path)
+ {
+ return false;
+ }
+ return SystemTools::MakeDirectory(std::string(path));
+}
+
+bool SystemTools::MakeDirectory(const std::string& path)
+{
+ if(SystemTools::FileExists(path))
+ {
+ return SystemTools::FileIsDirectory(path);
+ }
+ if(path.empty())
+ {
+ return false;
+ }
+ std::string dir = path;
+ SystemTools::ConvertToUnixSlashes(dir);
+
+ std::string::size_type pos = 0;
+ std::string topdir;
+ while((pos = dir.find('/', pos)) != std::string::npos)
+ {
+ topdir = dir.substr(0, pos);
+ Mkdir(topdir);
+ pos++;
+ }
+ topdir = dir;
+ if(Mkdir(topdir) != 0)
+ {
+ // There is a bug in the Borland Run time library which makes MKDIR
+ // return EACCES when it should return EEXISTS
+ // if it is some other error besides directory exists
+ // then return false
+ if( (errno != EEXIST)
+#ifdef __BORLANDC__
+ && (errno != EACCES)
+#endif
+ )
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+// replace replace with with as many times as it shows up in source.
+// write the result into source.
+void SystemTools::ReplaceString(std::string& source,
+ const std::string& replace,
+ const std::string& with)
+{
+ // do while hangs if replaceSize is 0
+ if (replace.empty())
+ {
+ return;
+ }
+
+ SystemTools::ReplaceString(source, replace.c_str(), replace.size(), with);
+}
+
+void SystemTools::ReplaceString(std::string& source,
+ const char* replace,
+ const char* with)
+{
+ // do while hangs if replaceSize is 0
+ if (!*replace)
+ {
+ return;
+ }
+
+ SystemTools::ReplaceString(source, replace, strlen(replace), with ? with : "");
+}
+
+void SystemTools::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));
+
+ // get out quick if string is not found
+ if (!searchPos)
+ {
+ return;
+ }
+
+ // perform replacements until done
+ char *orig = strdup(src);
+ char *currentPos = orig;
+ searchPos = searchPos - src + orig;
+
+ // initialize the result
+ source.erase(source.begin(),source.end());
+ do
+ {
+ *searchPos = '\0';
+ source += currentPos;
+ currentPos = searchPos + replaceSize;
+ // replace
+ source += with;
+ searchPos = strstr(currentPos,replace);
+ }
+ while (searchPos);
+
+ // copy any trailing text
+ source += currentPos;
+ free(orig);
+}
+
+#if defined(KEY_WOW64_32KEY) && defined(KEY_WOW64_64KEY)
+# define KWSYS_ST_KEY_WOW64_32KEY KEY_WOW64_32KEY
+# define KWSYS_ST_KEY_WOW64_64KEY KEY_WOW64_64KEY
+#else
+# define KWSYS_ST_KEY_WOW64_32KEY 0x0200
+# define KWSYS_ST_KEY_WOW64_64KEY 0x0100
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+static bool SystemToolsParseRegistryKey(const std::string& key,
+ HKEY& primaryKey,
+ std::string& second,
+ std::string& valuename)
+{
+ std::string primary = key;
+
+ size_t start = primary.find('\\');
+ if (start == std::string::npos)
+ {
+ return false;
+ }
+
+ size_t valuenamepos = primary.find(';');
+ if (valuenamepos != std::string::npos)
+ {
+ valuename = primary.substr(valuenamepos+1);
+ }
+
+ second = primary.substr(start+1, valuenamepos-start-1);
+ primary = primary.substr(0, start);
+
+ if (primary == "HKEY_CURRENT_USER")
+ {
+ primaryKey = HKEY_CURRENT_USER;
+ }
+ if (primary == "HKEY_CURRENT_CONFIG")
+ {
+ primaryKey = HKEY_CURRENT_CONFIG;
+ }
+ if (primary == "HKEY_CLASSES_ROOT")
+ {
+ primaryKey = HKEY_CLASSES_ROOT;
+ }
+ if (primary == "HKEY_LOCAL_MACHINE")
+ {
+ primaryKey = HKEY_LOCAL_MACHINE;
+ }
+ if (primary == "HKEY_USERS")
+ {
+ primaryKey = HKEY_USERS;
+ }
+
+ return true;
+}
+
+static DWORD SystemToolsMakeRegistryMode(DWORD mode,
+ SystemTools::KeyWOW64 view)
+{
+ // only add the modes when on a system that supports Wow64.
+ static FARPROC wow64p = GetProcAddress(GetModuleHandleW(L"kernel32"),
+ "IsWow64Process");
+ if(wow64p == NULL)
+ {
+ return mode;
+ }
+
+ if(view == SystemTools::KeyWOW64_32)
+ {
+ return mode | KWSYS_ST_KEY_WOW64_32KEY;
+ }
+ else if(view == SystemTools::KeyWOW64_64)
+ {
+ return mode | KWSYS_ST_KEY_WOW64_64KEY;
+ }
+ return mode;
+}
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool
+SystemTools::GetRegistrySubKeys(const std::string& key,
+ std::vector<std::string>& subkeys,
+ KeyWOW64 view)
+{
+ HKEY primaryKey = HKEY_CURRENT_USER;
+ std::string second;
+ std::string valuename;
+ if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename))
+ {
+ return false;
+ }
+
+ HKEY hKey;
+ if(RegOpenKeyExW(primaryKey,
+ Encoding::ToWide(second).c_str(),
+ 0,
+ SystemToolsMakeRegistryMode(KEY_READ, view),
+ &hKey) != ERROR_SUCCESS)
+ {
+ return false;
+ }
+ else
+ {
+ wchar_t name[1024];
+ DWORD dwNameSize = sizeof(name)/sizeof(name[0]);
+
+ DWORD i = 0;
+ while (RegEnumKeyW(hKey, i, name, dwNameSize) == ERROR_SUCCESS)
+ {
+ subkeys.push_back(Encoding::ToNarrow(name));
+ ++i;
+ }
+
+ RegCloseKey(hKey);
+ }
+
+ return true;
+}
+#else
+bool SystemTools::GetRegistrySubKeys(const std::string&,
+ std::vector<std::string>&,
+ KeyWOW64)
+{
+ return false;
+}
+#endif
+
+// Read a registry value.
+// Example :
+// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
+// => will return the data of the "default" value of the key
+// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
+// => will return the data of the "Root" value of the key
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::ReadRegistryValue(const std::string& key, std::string &value,
+ KeyWOW64 view)
+{
+ bool valueset = false;
+ HKEY primaryKey = HKEY_CURRENT_USER;
+ std::string second;
+ std::string valuename;
+ if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename))
+ {
+ return false;
+ }
+
+ HKEY hKey;
+ if(RegOpenKeyExW(primaryKey,
+ Encoding::ToWide(second).c_str(),
+ 0,
+ SystemToolsMakeRegistryMode(KEY_READ, view),
+ &hKey) != ERROR_SUCCESS)
+ {
+ return false;
+ }
+ else
+ {
+ DWORD dwType, dwSize;
+ dwSize = 1023;
+ wchar_t data[1024];
+ if(RegQueryValueExW(hKey,
+ Encoding::ToWide(valuename).c_str(),
+ NULL,
+ &dwType,
+ (BYTE *)data,
+ &dwSize) == ERROR_SUCCESS)
+ {
+ if (dwType == REG_SZ)
+ {
+ value = Encoding::ToNarrow(data);
+ valueset = true;
+ }
+ else if (dwType == REG_EXPAND_SZ)
+ {
+ wchar_t expanded[1024];
+ DWORD dwExpandedSize = sizeof(expanded)/sizeof(expanded[0]);
+ if(ExpandEnvironmentStringsW(data, expanded,
+ dwExpandedSize))
+ {
+ value = Encoding::ToNarrow(expanded);
+ valueset = true;
+ }
+ }
+ }
+
+ RegCloseKey(hKey);
+ }
+
+ return valueset;
+}
+#else
+bool SystemTools::ReadRegistryValue(const std::string&, std::string &,
+ KeyWOW64)
+{
+ return false;
+}
+#endif
+
+
+// Write a registry value.
+// Example :
+// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
+// => will set the data of the "default" value of the key
+// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
+// => will set the data of the "Root" value of the key
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::WriteRegistryValue(const std::string& key,
+ const std::string& value,
+ KeyWOW64 view)
+{
+ HKEY primaryKey = HKEY_CURRENT_USER;
+ std::string second;
+ std::string valuename;
+ if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename))
+ {
+ return false;
+ }
+
+ HKEY hKey;
+ DWORD dwDummy;
+ wchar_t lpClass[] = L"";
+ if(RegCreateKeyExW(primaryKey,
+ Encoding::ToWide(second).c_str(),
+ 0,
+ lpClass,
+ REG_OPTION_NON_VOLATILE,
+ SystemToolsMakeRegistryMode(KEY_WRITE, view),
+ NULL,
+ &hKey,
+ &dwDummy) != ERROR_SUCCESS)
+ {
+ return false;
+ }
+
+ std::wstring wvalue = Encoding::ToWide(value);
+ if(RegSetValueExW(hKey,
+ Encoding::ToWide(valuename).c_str(),
+ 0,
+ REG_SZ,
+ (CONST BYTE *)wvalue.c_str(),
+ (DWORD)(sizeof(wchar_t) * (wvalue.size() + 1))) == ERROR_SUCCESS)
+ {
+ return true;
+ }
+ return false;
+}
+#else
+bool SystemTools::WriteRegistryValue(const std::string&, const std::string&, KeyWOW64)
+{
+ return false;
+}
+#endif
+
+// Delete a registry value.
+// Example :
+// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
+// => will delete the data of the "default" value of the key
+// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
+// => will delete the data of the "Root" value of the key
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::DeleteRegistryValue(const std::string& key, KeyWOW64 view)
+{
+ HKEY primaryKey = HKEY_CURRENT_USER;
+ std::string second;
+ std::string valuename;
+ if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename))
+ {
+ return false;
+ }
+
+ HKEY hKey;
+ if(RegOpenKeyExW(primaryKey,
+ Encoding::ToWide(second).c_str(),
+ 0,
+ SystemToolsMakeRegistryMode(KEY_WRITE, view),
+ &hKey) != ERROR_SUCCESS)
+ {
+ return false;
+ }
+ else
+ {
+ if(RegDeleteValue(hKey,
+ (LPTSTR)valuename.c_str()) == ERROR_SUCCESS)
+ {
+ RegCloseKey(hKey);
+ return true;
+ }
+ }
+ return false;
+}
+#else
+bool SystemTools::DeleteRegistryValue(const std::string&, KeyWOW64)
+{
+ return false;
+}
+#endif
+
+bool SystemTools::SameFile(const std::string& file1, const std::string& file2)
+{
+#ifdef _WIN32
+ HANDLE hFile1, hFile2;
+
+ hFile1 = CreateFileW( Encoding::ToWide(file1).c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL
+ );
+ hFile2 = CreateFileW( Encoding::ToWide(file2).c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL
+ );
+ if( hFile1 == INVALID_HANDLE_VALUE || hFile2 == INVALID_HANDLE_VALUE)
+ {
+ if(hFile1 != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(hFile1);
+ }
+ if(hFile2 != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(hFile2);
+ }
+ return false;
+ }
+
+ BY_HANDLE_FILE_INFORMATION fiBuf1;
+ BY_HANDLE_FILE_INFORMATION fiBuf2;
+ GetFileInformationByHandle( hFile1, &fiBuf1 );
+ GetFileInformationByHandle( hFile2, &fiBuf2 );
+ CloseHandle(hFile1);
+ CloseHandle(hFile2);
+ return (fiBuf1.dwVolumeSerialNumber == fiBuf2.dwVolumeSerialNumber &&
+ fiBuf1.nFileIndexHigh == fiBuf2.nFileIndexHigh &&
+ fiBuf1.nFileIndexLow == fiBuf2.nFileIndexLow);
+#else
+ struct stat fileStat1, fileStat2;
+ if (stat(file1.c_str(), &fileStat1) == 0 && stat(file2.c_str(), &fileStat2) == 0)
+ {
+ // see if the files are the same file
+ // check the device inode and size
+ if(memcmp(&fileStat2.st_dev, &fileStat1.st_dev, sizeof(fileStat1.st_dev)) == 0 &&
+ memcmp(&fileStat2.st_ino, &fileStat1.st_ino, sizeof(fileStat1.st_ino)) == 0 &&
+ fileStat2.st_size == fileStat1.st_size
+ )
+ {
+ return true;
+ }
+ }
+ return false;
+#endif
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::FileExists(const char* filename)
+{
+ if(!filename)
+ {
+ return false;
+ }
+ return SystemTools::FileExists(std::string(filename));
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::FileExists(const std::string& filename)
+{
+ if(filename.empty())
+ {
+ return false;
+ }
+#if defined(__CYGWIN__)
+ // Convert filename to native windows path if possible.
+ char winpath[MAX_PATH];
+ if(SystemTools::PathCygwinToWin32(filename.c_str(), winpath))
+ {
+ return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES);
+ }
+ return access(filename.c_str(), R_OK) == 0;
+#elif defined(_WIN32)
+ return (GetFileAttributesW(
+ SystemTools::ConvertToWindowsExtendedPath(filename).c_str())
+ != INVALID_FILE_ATTRIBUTES);
+#else
+ return access(filename.c_str(), R_OK) == 0;
+#endif
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::FileExists(const char* filename, bool isFile)
+{
+ if(!filename)
+ {
+ return false;
+ }
+ return SystemTools::FileExists(std::string(filename), isFile);
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::FileExists(const std::string& filename, bool isFile)
+{
+ if(SystemTools::FileExists(filename))
+ {
+ // If isFile is set return not FileIsDirectory,
+ // so this will only be true if it is a file
+ return !isFile || !SystemTools::FileIsDirectory(filename);
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::TestFileAccess(const char* filename,
+ TestFilePermissions permissions)
+{
+ if(!filename)
+ {
+ return false;
+ }
+ return SystemTools::TestFileAccess(std::string(filename),
+ permissions);
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::TestFileAccess(const std::string& filename,
+ TestFilePermissions permissions)
+{
+ if(filename.empty())
+ {
+ return false;
+ }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // If execute set, change to read permission (all files on Windows
+ // are executable if they are readable). The CRT will always fail
+ // if you pass an execute bit.
+ if(permissions & TEST_FILE_EXECUTE)
+ {
+ permissions &= ~TEST_FILE_EXECUTE;
+ permissions |= TEST_FILE_READ;
+ }
+ return _waccess(
+ SystemTools::ConvertToWindowsExtendedPath(filename).c_str(),
+ permissions) == 0;
+#else
+ return access(filename.c_str(), permissions) == 0;
+#endif
+}
+
+//----------------------------------------------------------------------------
+#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);
+ }
+ 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);
+ }
+ return win32_path[0] != 0;
+}
+#endif
+
+bool SystemTools::Touch(const std::string& filename, bool create)
+{
+ if (!SystemTools::FileExists(filename))
+ {
+ if(create)
+ {
+ FILE* file = Fopen(filename, "a+b");
+ if(file)
+ {
+ fclose(file);
+ return true;
+ }
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ HANDLE h = CreateFileW(
+ SystemTools::ConvertToWindowsExtendedPath(filename).c_str(),
+ FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_WRITE, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, 0);
+ if(!h)
+ {
+ return false;
+ }
+ FILETIME mtime;
+ GetSystemTimeAsFileTime(&mtime);
+ if(!SetFileTime(h, 0, 0, &mtime))
+ {
+ CloseHandle(h);
+ return false;
+ }
+ CloseHandle(h);
+#elif KWSYS_CXX_HAS_UTIMENSAT
+ struct timespec times[2] = {{0,UTIME_OMIT},{0,UTIME_NOW}};
+ if(utimensat(AT_FDCWD, filename.c_str(), times, 0) < 0)
+ {
+ return false;
+ }
+#else
+ struct stat st;
+ if(stat(filename.c_str(), &st) < 0)
+ {
+ return false;
+ }
+ struct timeval mtime;
+ gettimeofday(&mtime, 0);
+# if KWSYS_CXX_HAS_UTIMES
+ struct timeval atime;
+# if KWSYS_CXX_STAT_HAS_ST_MTIM
+ atime.tv_sec = st.st_atim.tv_sec;
+ atime.tv_usec = st.st_atim.tv_nsec/1000;
+# elif KWSYS_CXX_STAT_HAS_ST_MTIMESPEC
+ atime.tv_sec = st.st_atimespec.tv_sec;
+ atime.tv_usec = st.st_atimespec.tv_nsec/1000;
+# else
+ atime.tv_sec = st.st_atime;
+ atime.tv_usec = 0;
+# endif
+ struct timeval times[2] = { atime, mtime };
+ if(utimes(filename.c_str(), times) < 0)
+ {
+ return false;
+ }
+# else
+ struct utimbuf times = {st.st_atime, mtime.tv_sec};
+ if(utime(filename.c_str(), &times) < 0)
+ {
+ return false;
+ }
+# endif
+#endif
+ return true;
+}
+
+bool SystemTools::FileTimeCompare(const std::string& f1,
+ const std::string& f2,
+ int* result)
+{
+ // Default to same time.
+ *result = 0;
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ // POSIX version. Use stat function to get file modification time.
+ struct stat s1;
+ if(stat(f1.c_str(), &s1) != 0)
+ {
+ return false;
+ }
+ struct stat s2;
+ if(stat(f2.c_str(), &s2) != 0)
+ {
+ return false;
+ }
+# if KWSYS_CXX_STAT_HAS_ST_MTIM
+ // Compare using nanosecond resolution.
+ if(s1.st_mtim.tv_sec < s2.st_mtim.tv_sec)
+ {
+ *result = -1;
+ }
+ else if(s1.st_mtim.tv_sec > s2.st_mtim.tv_sec)
+ {
+ *result = 1;
+ }
+ else if(s1.st_mtim.tv_nsec < s2.st_mtim.tv_nsec)
+ {
+ *result = -1;
+ }
+ else if(s1.st_mtim.tv_nsec > s2.st_mtim.tv_nsec)
+ {
+ *result = 1;
+ }
+# elif KWSYS_CXX_STAT_HAS_ST_MTIMESPEC
+ // Compare using nanosecond resolution.
+ if(s1.st_mtimespec.tv_sec < s2.st_mtimespec.tv_sec)
+ {
+ *result = -1;
+ }
+ else if(s1.st_mtimespec.tv_sec > s2.st_mtimespec.tv_sec)
+ {
+ *result = 1;
+ }
+ else if(s1.st_mtimespec.tv_nsec < s2.st_mtimespec.tv_nsec)
+ {
+ *result = -1;
+ }
+ else if(s1.st_mtimespec.tv_nsec > s2.st_mtimespec.tv_nsec)
+ {
+ *result = 1;
+ }
+# else
+ // Compare using 1 second resolution.
+ if(s1.st_mtime < s2.st_mtime)
+ {
+ *result = -1;
+ }
+ else if(s1.st_mtime > s2.st_mtime)
+ {
+ *result = 1;
+ }
+# endif
+#else
+ // Windows version. Get the modification time from extended file attributes.
+ WIN32_FILE_ATTRIBUTE_DATA f1d;
+ WIN32_FILE_ATTRIBUTE_DATA f2d;
+ if(!GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(f1).c_str(),
+ GetFileExInfoStandard, &f1d))
+ {
+ return false;
+ }
+ if(!GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(f2).c_str(),
+ GetFileExInfoStandard, &f2d))
+ {
+ return false;
+ }
+
+ // Compare the file times using resolution provided by system call.
+ *result = (int)CompareFileTime(&f1d.ftLastWriteTime, &f2d.ftLastWriteTime);
+#endif
+ return true;
+}
+
+
+// Return a capitalized string (i.e the first letter is uppercased, all other
+// are lowercased)
+std::string SystemTools::Capitalized(const std::string& s)
+{
+ std::string n;
+ if(s.empty())
+ {
+ return n;
+ }
+ n.resize(s.size());
+ n[0] = static_cast<std::string::value_type>(toupper(s[0]));
+ for (size_t i = 1; i < s.size(); i++)
+ {
+ n[i] = static_cast<std::string::value_type>(tolower(s[i]));
+ }
+ return n;
+}
+
+// Return capitalized words
+std::string SystemTools::CapitalizedWords(const std::string& s)
+{
+ std::string n(s);
+ for (size_t i = 0; i < s.size(); i++)
+ {
+#if defined(_MSC_VER) && defined (_MT) && defined (_DEBUG)
+ // MS has an assert that will fail if s[i] < 0; setting
+ // LC_CTYPE using setlocale() does *not* help. Painful.
+ if ((int)s[i] >= 0 && isalpha(s[i]) &&
+ (i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1]))))
+#else
+ if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1])))
+#endif
+ {
+ n[i] = static_cast<std::string::value_type>(toupper(s[i]));
+ }
+ }
+ return n;
+}
+
+// Return uncapitalized words
+std::string SystemTools::UnCapitalizedWords(const std::string& s)
+{
+ std::string n(s);
+ for (size_t i = 0; i < s.size(); i++)
+ {
+#if defined(_MSC_VER) && defined (_MT) && defined (_DEBUG)
+ // MS has an assert that will fail if s[i] < 0; setting
+ // LC_CTYPE using setlocale() does *not* help. Painful.
+ if ((int)s[i] >= 0 && isalpha(s[i]) &&
+ (i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1]))))
+#else
+ if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1])))
+#endif
+ {
+ n[i] = static_cast<std::string::value_type>(tolower(s[i]));
+ }
+ }
+ return n;
+}
+
+// only works for words with at least two letters
+std::string SystemTools::AddSpaceBetweenCapitalizedWords(
+ const std::string& s)
+{
+ std::string n;
+ if (!s.empty())
+ {
+ n.reserve(s.size());
+ n += s[0];
+ for (size_t i = 1; i < s.size(); i++)
+ {
+ if (isupper(s[i]) && !isspace(s[i - 1]) && !isupper(s[i - 1]))
+ {
+ n += ' ';
+ }
+ n += s[i];
+ }
+ }
+ return n;
+}
+
+char* SystemTools::AppendStrings(const char* str1, const char* str2)
+{
+ if (!str1)
+ {
+ return SystemTools::DuplicateString(str2);
+ }
+ if (!str2)
+ {
+ return SystemTools::DuplicateString(str1);
+ }
+ size_t len1 = strlen(str1);
+ char *newstr = new char[len1 + strlen(str2) + 1];
+ if (!newstr)
+ {
+ return 0;
+ }
+ strcpy(newstr, str1);
+ strcat(newstr + len1, str2);
+ return newstr;
+}
+
+char* SystemTools::AppendStrings(
+ const char* str1, const char* str2, const char* str3)
+{
+ if (!str1)
+ {
+ return SystemTools::AppendStrings(str2, str3);
+ }
+ if (!str2)
+ {
+ return SystemTools::AppendStrings(str1, str3);
+ }
+ if (!str3)
+ {
+ return SystemTools::AppendStrings(str1, str2);
+ }
+
+ size_t len1 = strlen(str1), len2 = strlen(str2);
+ char *newstr = new char[len1 + len2 + strlen(str3) + 1];
+ if (!newstr)
+ {
+ return 0;
+ }
+ strcpy(newstr, str1);
+ strcat(newstr + len1, str2);
+ strcat(newstr + len1 + len2, str3);
+ return newstr;
+}
+
+// Return a lower case string
+std::string SystemTools::LowerCase(const std::string& s)
+{
+ std::string n;
+ n.resize(s.size());
+ for (size_t i = 0; i < s.size(); i++)
+ {
+ n[i] = static_cast<std::string::value_type>(tolower(s[i]));
+ }
+ return n;
+}
+
+// Return a lower case string
+std::string SystemTools::UpperCase(const std::string& s)
+{
+ std::string n;
+ n.resize(s.size());
+ for (size_t i = 0; i < s.size(); i++)
+ {
+ n[i] = static_cast<std::string::value_type>(toupper(s[i]));
+ }
+ return n;
+}
+
+// Count char in string
+size_t SystemTools::CountChar(const char* str, char c)
+{
+ size_t count = 0;
+
+ if (str)
+ {
+ while (*str)
+ {
+ if (*str == c)
+ {
+ ++count;
+ }
+ ++str;
+ }
+ }
+ return count;
+}
+
+// Remove chars in string
+char* SystemTools::RemoveChars(const char* str, const char *toremove)
+{
+ if (!str)
+ {
+ return NULL;
+ }
+ char *clean_str = new char [strlen(str) + 1];
+ char *ptr = clean_str;
+ while (*str)
+ {
+ const char *str2 = toremove;
+ while (*str2 && *str != *str2)
+ {
+ ++str2;
+ }
+ if (!*str2)
+ {
+ *ptr++ = *str;
+ }
+ ++str;
+ }
+ *ptr = '\0';
+ return clean_str;
+}
+
+// Remove chars in string
+char* SystemTools::RemoveCharsButUpperHex(const char* str)
+{
+ if (!str)
+ {
+ return 0;
+ }
+ char *clean_str = new char [strlen(str) + 1];
+ char *ptr = clean_str;
+ while (*str)
+ {
+ if ((*str >= '0' && *str <= '9') || (*str >= 'A' && *str <= 'F'))
+ {
+ *ptr++ = *str;
+ }
+ ++str;
+ }
+ *ptr = '\0';
+ return clean_str;
+}
+
+// Replace chars in string
+char* SystemTools::ReplaceChars(char* str, const char *toreplace, char replacement)
+{
+ if (str)
+ {
+ char *ptr = str;
+ while (*ptr)
+ {
+ const char *ptr2 = toreplace;
+ while (*ptr2)
+ {
+ if (*ptr == *ptr2)
+ {
+ *ptr = replacement;
+ }
+ ++ptr2;
+ }
+ ++ptr;
+ }
+ }
+ return str;
+}
+
+// Returns if string starts with another string
+bool SystemTools::StringStartsWith(const char* str1, const char* str2)
+{
+ if (!str1 || !str2)
+ {
+ return false;
+ }
+ size_t len1 = strlen(str1), len2 = strlen(str2);
+ return len1 >= len2 && !strncmp(str1, str2, len2) ? true : false;
+}
+
+// Returns if string starts with another string
+bool SystemTools::StringStartsWith(const std::string& str1, const char* str2)
+{
+ if (!str2)
+ {
+ return false;
+ }
+ size_t len1 = str1.size(), len2 = strlen(str2);
+ return len1 >= len2 && !strncmp(str1.c_str(), str2, len2) ? true : false;
+}
+
+// Returns if string ends with another string
+bool SystemTools::StringEndsWith(const char* str1, const char* str2)
+{
+ if (!str1 || !str2)
+ {
+ return false;
+ }
+ size_t len1 = strlen(str1), len2 = strlen(str2);
+ return len1 >= len2 && !strncmp(str1 + (len1 - len2), str2, len2) ? true : false;
+}
+
+// Returns if string ends with another string
+bool SystemTools::StringEndsWith(const std::string& str1, const char* str2)
+{
+ if (!str2)
+ {
+ return false;
+ }
+ size_t len1 = str1.size(), len2 = strlen(str2);
+ return len1 >= len2 && !strncmp(str1.c_str() + (len1 - len2), str2, len2) ? true : false;
+}
+
+// Returns a pointer to the last occurence of str2 in str1
+const char* SystemTools::FindLastString(const char* str1, const char* str2)
+{
+ if (!str1 || !str2)
+ {
+ return NULL;
+ }
+
+ size_t len1 = strlen(str1), len2 = strlen(str2);
+ if (len1 >= len2)
+ {
+ const char *ptr = str1 + len1 - len2;
+ do
+ {
+ if (!strncmp(ptr, str2, len2))
+ {
+ return ptr;
+ }
+ } while (ptr-- != str1);
+ }
+
+ return NULL;
+}
+
+// Duplicate string
+char* SystemTools::DuplicateString(const char* str)
+{
+ if (str)
+ {
+ char *newstr = new char [strlen(str) + 1];
+ return strcpy(newstr, str);
+ }
+ return NULL;
+}
+
+// Return a cropped string
+std::string SystemTools::CropString(const std::string& s,
+ size_t max_len)
+{
+ if (!s.size() || max_len == 0 || max_len >= s.size())
+ {
+ return s;
+ }
+
+ std::string n;
+ n.reserve(max_len);
+
+ size_t middle = max_len / 2;
+
+ n += s.substr(0, middle);
+ n += s.substr(s.size() - (max_len - middle), std::string::npos);
+
+ if (max_len > 2)
+ {
+ n[middle] = '.';
+ if (max_len > 3)
+ {
+ n[middle - 1] = '.';
+ if (max_len > 4)
+ {
+ n[middle + 1] = '.';
+ }
+ }
+ }
+
+ return n;
+}
+
+//----------------------------------------------------------------------------
+std::vector<kwsys::String> SystemTools::SplitString(const std::string& p, char sep, bool isPath)
+{
+ std::string path = p;
+ std::vector<kwsys::String> paths;
+ if(path.empty())
+ {
+ return paths;
+ }
+ if(isPath && path[0] == '/')
+ {
+ path.erase(path.begin());
+ paths.push_back("/");
+ }
+ std::string::size_type pos1 = 0;
+ std::string::size_type pos2 = path.find(sep, pos1+1);
+ while(pos2 != std::string::npos)
+ {
+ paths.push_back(path.substr(pos1, pos2-pos1));
+ pos1 = pos2+1;
+ pos2 = path.find(sep, pos1+1);
+ }
+ paths.push_back(path.substr(pos1, pos2-pos1));
+
+ return paths;
+}
+
+//----------------------------------------------------------------------------
+int SystemTools::EstimateFormatLength(const char *format, va_list ap)
+{
+ if (!format)
+ {
+ return 0;
+ }
+
+ // Quick-hack attempt at estimating the length of the string.
+ // Should never under-estimate.
+
+ // Start with the length of the format string itself.
+
+ size_t length = strlen(format);
+
+ // Increase the length for every argument in the format.
+
+ const char* cur = format;
+ while(*cur)
+ {
+ if(*cur++ == '%')
+ {
+ // Skip "%%" since it doesn't correspond to a va_arg.
+ if(*cur != '%')
+ {
+ while(!int(isalpha(*cur)))
+ {
+ ++cur;
+ }
+ switch (*cur)
+ {
+ case 's':
+ {
+ // Check the length of the string.
+ char* s = va_arg(ap, char*);
+ if(s)
+ {
+ length += strlen(s);
+ }
+ } break;
+ case 'e':
+ case 'f':
+ case 'g':
+ {
+ // Assume the argument contributes no more than 64 characters.
+ length += 64;
+
+ // Eat the argument.
+ static_cast<void>(va_arg(ap, double));
+ } break;
+ default:
+ {
+ // Assume the argument contributes no more than 64 characters.
+ length += 64;
+
+ // Eat the argument.
+ static_cast<void>(va_arg(ap, int));
+ } break;
+ }
+ }
+
+ // Move past the characters just tested.
+ ++cur;
+ }
+ }
+
+ return static_cast<int>(length);
+}
+
+std::string SystemTools::EscapeChars(
+ const char *str,
+ const char *chars_to_escape,
+ char escape_char)
+{
+ std::string n;
+ if (str)
+ {
+ if (!chars_to_escape || !*chars_to_escape)
+ {
+ n.append(str);
+ }
+ else
+ {
+ n.reserve(strlen(str));
+ while (*str)
+ {
+ const char *ptr = chars_to_escape;
+ while (*ptr)
+ {
+ if (*str == *ptr)
+ {
+ n += escape_char;
+ break;
+ }
+ ++ptr;
+ }
+ n += *str;
+ ++str;
+ }
+ }
+ }
+ return n;
+}
+
+#ifdef __VMS
+static void ConvertVMSToUnix(std::string& path)
+{
+ std::string::size_type rootEnd = path.find(":[");
+ std::string::size_type pathEnd = path.find("]");
+ if(rootEnd != path.npos)
+ {
+ std::string root = path.substr(0, rootEnd);
+ std::string pathPart = path.substr(rootEnd+2, pathEnd - rootEnd-2);
+ const char* pathCString = pathPart.c_str();
+ const char* pos0 = pathCString;
+ for (std::string::size_type pos = 0; *pos0; ++ pos )
+ {
+ if ( *pos0 == '.' )
+ {
+ pathPart[pos] = '/';
+ }
+ pos0 ++;
+ }
+ path = "/"+ root + "/" + pathPart;
+ }
+}
+#endif
+
+// convert windows slashes to unix slashes
+void SystemTools::ConvertToUnixSlashes(std::string& path)
+{
+ const char* pathCString = path.c_str();
+ bool hasDoubleSlash = false;
+#ifdef __VMS
+ ConvertVMSToUnix(path);
+#else
+ const char* pos0 = pathCString;
+ const char* pos1 = pathCString+1;
+ for (std::string::size_type pos = 0; *pos0; ++ pos )
+ {
+ // make sure we don't convert an escaped space to a unix slash
+ if ( *pos0 == '\\' && *pos1 != ' ' )
+ {
+ path[pos] = '/';
+ }
+
+ // Also, reuse the loop to check for slash followed by another slash
+ if (*pos1 == '/' && *(pos1+1) == '/' && !hasDoubleSlash)
+ {
+#ifdef _WIN32
+ // However, on windows if the first characters are both slashes,
+ // then keep them that way, so that network paths can be handled.
+ if ( pos > 0)
+ {
+ hasDoubleSlash = true;
+ }
+#else
+ hasDoubleSlash = true;
+#endif
+ }
+
+ pos0 ++;
+ pos1 ++;
+ }
+
+ if ( hasDoubleSlash )
+ {
+ SystemTools::ReplaceString(path, "//", "/");
+ }
+#endif
+ // remove any trailing slash
+ if(!path.empty())
+ {
+ // if there is a tilda ~ then replace it with HOME
+ pathCString = path.c_str();
+ if(pathCString[0] == '~' && (pathCString[1] == '/' || pathCString[1] == '\0'))
+ {
+ const char* homeEnv = SystemTools::GetEnv("HOME");
+ if (homeEnv)
+ {
+ path.replace(0,1,homeEnv);
+ }
+ }
+#ifdef HAVE_GETPWNAM
+ else if(pathCString[0] == '~')
+ {
+ std::string::size_type idx = path.find_first_of("/\0");
+ std::string user = path.substr(1, idx-1);
+ passwd* pw = getpwnam(user.c_str());
+ if(pw)
+ {
+ path.replace(0, idx, pw->pw_dir);
+ }
+ }
+#endif
+ // remove trailing slash if the path is more than
+ // a single /
+ pathCString = path.c_str();
+ size_t size = path.size();
+ if(size > 1 && *path.rbegin() == '/')
+ {
+ // if it is c:/ then do not remove the trailing slash
+ if(!((size == 3 && pathCString[1] == ':')))
+ {
+ path.resize(size - 1);
+ }
+ }
+ }
+}
+
+#ifdef _WIN32
+// Convert local paths to UNC style paths
+std::wstring
+SystemTools::ConvertToWindowsExtendedPath(const std::string &source)
+{
+ std::wstring wsource = Encoding::ToWide(source);
+
+ // Resolve any relative paths
+ DWORD wfull_len;
+
+ /* The +3 is a workaround for a bug in some versions of GetFullPathNameW that
+ * won't return a large enough buffer size if the input is too small */
+ wfull_len = GetFullPathNameW(wsource.c_str(), 0, NULL, NULL) + 3;
+ std::vector<wchar_t> wfull(wfull_len);
+ GetFullPathNameW(wsource.c_str(), wfull_len, &wfull[0], NULL);
+
+ /* This should get the correct size without any extra padding from the
+ * previous size workaround. */
+ wfull_len = static_cast<DWORD>(wcslen(&wfull[0]));
+
+ if(wfull_len >= 2 && isalpha(wfull[0]) && wfull[1] == L':')
+ { /* C:\Foo\bar\FooBar.txt */
+ return L"\\\\?\\" + std::wstring(&wfull[0]);
+ }
+ else if(wfull_len >= 2 && wfull[0] == L'\\' && wfull[1] == L'\\')
+ { /* Starts with \\ */
+ if(wfull_len >= 4 && wfull[2] == L'?' && wfull[3] == L'\\')
+ { /* Starts with \\?\ */
+ if(wfull_len >= 8 && wfull[4] == L'U' && wfull[5] == L'N' &&
+ wfull[6] == L'C' && wfull[7] == L'\\')
+ { /* \\?\UNC\Foo\bar\FooBar.txt */
+ return std::wstring(&wfull[0]);
+ }
+ else if(wfull_len >= 6 && isalpha(wfull[4]) && wfull[5] == L':')
+ { /* \\?\C:\Foo\bar\FooBar.txt */
+ return std::wstring(&wfull[0]);
+ }
+ else if(wfull_len >= 5)
+ { /* \\?\Foo\bar\FooBar.txt */
+ return L"\\\\?\\UNC\\" + std::wstring(&wfull[4]);
+ }
+ }
+ else if(wfull_len >= 4 && wfull[2] == L'.' && wfull[3] == L'\\')
+ { /* Starts with \\.\ a device name */
+ if(wfull_len >= 6 && isalpha(wfull[4]) && wfull[5] == L':')
+ { /* \\.\C:\Foo\bar\FooBar.txt */
+ return L"\\\\?\\" + std::wstring(&wfull[4]);
+ }
+ else if(wfull_len >= 5)
+ { /* \\.\Foo\bar\ Device name is left unchanged */
+ return std::wstring(&wfull[0]);
+ }
+ }
+ else if(wfull_len >= 3)
+ { /* \\Foo\bar\FooBar.txt */
+ return L"\\\\?\\UNC\\" + std::wstring(&wfull[2]);
+ }
+ }
+
+ // If this case has been reached, then the path is invalid. Leave it
+ // unchanged
+ return Encoding::ToWide(source);
+}
+#endif
+
+// change // to /, and escape any spaces in the path
+std::string SystemTools::ConvertToUnixOutputPath(const std::string& path)
+{
+ std::string ret = path;
+
+ // remove // except at the beginning might be a cygwin drive
+ std::string::size_type pos=1;
+ while((pos = ret.find("//", pos)) != std::string::npos)
+ {
+ ret.erase(pos, 1);
+ }
+ // escape spaces and () in the path
+ if(ret.find_first_of(" ") != std::string::npos)
+ {
+ std::string result = "";
+ char lastch = 1;
+ for(const char* ch = ret.c_str(); *ch != '\0'; ++ch)
+ {
+ // if it is already escaped then don't try to escape it again
+ if((*ch == ' ') && lastch != '\\')
+ {
+ result += '\\';
+ }
+ result += *ch;
+ lastch = *ch;
+ }
+ ret = result;
+ }
+ return ret;
+}
+
+std::string SystemTools::ConvertToOutputPath(const std::string& path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ return SystemTools::ConvertToWindowsOutputPath(path);
+#else
+ return SystemTools::ConvertToUnixOutputPath(path);
+#endif
+}
+
+// remove double slashes not at the start
+std::string SystemTools::ConvertToWindowsOutputPath(const std::string& path)
+{
+ std::string ret;
+ // make it big enough for all of path and double quotes
+ ret.reserve(path.size()+3);
+ // put path into the string
+ ret = path;
+ std::string::size_type pos = 0;
+ // first convert all of the slashes
+ while((pos = ret.find('/', pos)) != std::string::npos)
+ {
+ ret[pos] = '\\';
+ pos++;
+ }
+ // check for really small paths
+ if(ret.size() < 2)
+ {
+ return ret;
+ }
+ // now clean up a bit and remove double slashes
+ // Only if it is not the first position in the path which is a network
+ // path on windows
+ pos = 1; // start at position 1
+ if(ret[0] == '\"')
+ {
+ pos = 2; // if the string is already quoted then start at 2
+ if(ret.size() < 3)
+ {
+ return ret;
+ }
+ }
+ while((pos = ret.find("\\\\", pos)) != std::string::npos)
+ {
+ ret.erase(pos, 1);
+ }
+ // now double quote the path if it has spaces in it
+ // and is not already double quoted
+ if(ret.find(' ') != std::string::npos
+ && ret[0] != '\"')
+ {
+ ret.insert(static_cast<std::string::size_type>(0),
+ static_cast<std::string::size_type>(1), '\"');
+ ret.append(1, '\"');
+ }
+ return ret;
+}
+
+bool SystemTools::CopyFileIfDifferent(const std::string& source,
+ const std::string& destination)
+{
+ // special check for a destination that is a directory
+ // FilesDiffer does not handle file to directory compare
+ if(SystemTools::FileIsDirectory(destination))
+ {
+ std::string new_destination = destination;
+ SystemTools::ConvertToUnixSlashes(new_destination);
+ new_destination += '/';
+ std::string source_name = source;
+ new_destination += SystemTools::GetFilenameName(source_name);
+ if(SystemTools::FilesDiffer(source, new_destination))
+ {
+ return SystemTools::CopyFileAlways(source, destination);
+ }
+ else
+ {
+ // the files are the same so the copy is done return
+ // true
+ return true;
+ }
+ }
+ // source and destination are files so do a copy if they
+ // are different
+ if(SystemTools::FilesDiffer(source, destination))
+ {
+ return SystemTools::CopyFileAlways(source, destination);
+ }
+ // at this point the files must be the same so return true
+ return true;
+}
+
+#define KWSYS_ST_BUFFER 4096
+
+bool SystemTools::FilesDiffer(const std::string& source,
+ const std::string& destination)
+{
+
+#if defined(_WIN32)
+ WIN32_FILE_ATTRIBUTE_DATA statSource;
+ if (GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(source).c_str(),
+ GetFileExInfoStandard,
+ &statSource) == 0)
+ {
+ return true;
+ }
+
+ WIN32_FILE_ATTRIBUTE_DATA statDestination;
+ if (GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(destination).c_str(),
+ GetFileExInfoStandard,
+ &statDestination) == 0)
+ {
+ return true;
+ }
+
+ if(statSource.nFileSizeHigh != statDestination.nFileSizeHigh ||
+ statSource.nFileSizeLow != statDestination.nFileSizeLow)
+ {
+ return true;
+ }
+
+ if(statSource.nFileSizeHigh == 0 && statSource.nFileSizeLow == 0)
+ {
+ return false;
+ }
+ off_t nleft = ((__int64)statSource.nFileSizeHigh << 32) +
+ statSource.nFileSizeLow;
+
+#else
+
+ struct stat statSource;
+ if (stat(source.c_str(), &statSource) != 0)
+ {
+ return true;
+ }
+
+ struct stat statDestination;
+ if (stat(destination.c_str(), &statDestination) != 0)
+ {
+ return true;
+ }
+
+ if(statSource.st_size != statDestination.st_size)
+ {
+ return true;
+ }
+
+ if(statSource.st_size == 0)
+ {
+ return false;
+ }
+ off_t nleft = statSource.st_size;
+#endif
+
+#if defined(_WIN32)
+ kwsys::ifstream finSource(source.c_str(),
+ (std::ios::binary |
+ std::ios::in));
+ kwsys::ifstream finDestination(destination.c_str(),
+ (std::ios::binary |
+ std::ios::in));
+#else
+ kwsys::ifstream finSource(source.c_str());
+ kwsys::ifstream finDestination(destination.c_str());
+#endif
+ if(!finSource || !finDestination)
+ {
+ return true;
+ }
+
+ // Compare the files a block at a time.
+ char source_buf[KWSYS_ST_BUFFER];
+ char dest_buf[KWSYS_ST_BUFFER];
+ while(nleft > 0)
+ {
+ // Read a block from each file.
+ std::streamsize nnext = (nleft > KWSYS_ST_BUFFER)? KWSYS_ST_BUFFER : static_cast<std::streamsize>(nleft);
+ finSource.read(source_buf, nnext);
+ finDestination.read(dest_buf, nnext);
+
+ // If either failed to read assume they are different.
+ if(static_cast<std::streamsize>(finSource.gcount()) != nnext ||
+ static_cast<std::streamsize>(finDestination.gcount()) != nnext)
+ {
+ return true;
+ }
+
+ // If this block differs the file differs.
+ if(memcmp(static_cast<const void*>(source_buf),
+ static_cast<const void*>(dest_buf),
+ static_cast<size_t>(nnext)) != 0)
+ {
+ return true;
+ }
+
+ // Update the byte count remaining.
+ nleft -= nnext;
+ }
+
+ // No differences found.
+ return false;
+}
+
+
+//----------------------------------------------------------------------------
+/**
+ * Copy a file named by "source" to the file named by "destination".
+ */
+bool SystemTools::CopyFileAlways(const std::string& source, const std::string& destination)
+{
+ // If files are the same do not copy
+ if ( SystemTools::SameFile(source, destination) )
+ {
+ return true;
+ }
+ mode_t perm = 0;
+ bool perms = SystemTools::GetPermissions(source, perm);
+ std::string real_destination = destination;
+
+ if(SystemTools::FileIsDirectory(source))
+ {
+ SystemTools::MakeDirectory(destination);
+ }
+ else
+ {
+ const int bufferSize = 4096;
+ char buffer[bufferSize];
+
+ // If destination is a directory, try to create a file with the same
+ // name as the source in that directory.
+
+ std::string destination_dir;
+ if(SystemTools::FileIsDirectory(destination))
+ {
+ destination_dir = real_destination;
+ SystemTools::ConvertToUnixSlashes(real_destination);
+ real_destination += '/';
+ std::string source_name = source;
+ real_destination += SystemTools::GetFilenameName(source_name);
+ }
+ else
+ {
+ destination_dir = SystemTools::GetFilenamePath(destination);
+ }
+
+ // Create destination directory
+
+ SystemTools::MakeDirectory(destination_dir);
+
+ // Open files
+#if defined(_WIN32)
+ kwsys::ifstream fin(Encoding::ToNarrow(
+ SystemTools::ConvertToWindowsExtendedPath(source)).c_str(),
+ std::ios::in | std::ios::binary);
+#else
+ kwsys::ifstream fin(source.c_str(),
+ std::ios::in | std::ios::binary);
+#endif
+ if(!fin)
+ {
+ return false;
+ }
+
+ // try and remove the destination file so that read only destination files
+ // can be written to.
+ // If the remove fails continue so that files in read only directories
+ // that do not allow file removal can be modified.
+ SystemTools::RemoveFile(real_destination);
+
+#if defined(_WIN32)
+ kwsys::ofstream fout(Encoding::ToNarrow(
+ SystemTools::ConvertToWindowsExtendedPath(real_destination)).c_str(),
+ std::ios::out | std::ios::trunc | std::ios::binary);
+#else
+ kwsys::ofstream fout(real_destination.c_str(),
+ std::ios::out | std::ios::trunc | std::ios::binary);
+#endif
+ if(!fout)
+ {
+ return false;
+ }
+
+ // This copy loop is very sensitive on certain platforms with
+ // slightly broken stream libraries (like HPUX). Normally, it is
+ // incorrect to not check the error condition on the fin.read()
+ // before using the data, but the fin.gcount() will be zero if an
+ // error occurred. Therefore, the loop should be safe everywhere.
+ while(fin)
+ {
+ fin.read(buffer, bufferSize);
+ if(fin.gcount())
+ {
+ fout.write(buffer, fin.gcount());
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // Make sure the operating system has finished writing the file
+ // before closing it. This will ensure the file is finished before
+ // the check below.
+ fout.flush();
+
+ fin.close();
+ fout.close();
+
+ if(!fout)
+ {
+ return false;
+ }
+ }
+ if ( perms )
+ {
+ if ( !SystemTools::SetPermissions(real_destination, perm) )
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::CopyAFile(const std::string& source, const std::string& destination,
+ bool always)
+{
+ if(always)
+ {
+ return SystemTools::CopyFileAlways(source, destination);
+ }
+ else
+ {
+ return SystemTools::CopyFileIfDifferent(source, destination);
+ }
+}
+
+/**
+ * Copy a directory content from "source" directory to the directory named by
+ * "destination".
+ */
+bool SystemTools::CopyADirectory(const std::string& source, const std::string& destination,
+ bool always)
+{
+ Directory dir;
+#ifdef _WIN32
+ dir.Load(Encoding::ToNarrow(
+ SystemTools::ConvertToWindowsExtendedPath(source)));
+#else
+ dir.Load(source);
+#endif
+ size_t fileNum;
+ if ( !SystemTools::MakeDirectory(destination) )
+ {
+ return false;
+ }
+ for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum)
+ {
+ if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)),".") &&
+ strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)),".."))
+ {
+ std::string fullPath = source;
+ fullPath += "/";
+ fullPath += dir.GetFile(static_cast<unsigned long>(fileNum));
+ if(SystemTools::FileIsDirectory(fullPath))
+ {
+ std::string fullDestPath = destination;
+ fullDestPath += "/";
+ fullDestPath += dir.GetFile(static_cast<unsigned long>(fileNum));
+ if (!SystemTools::CopyADirectory(fullPath,
+ fullDestPath,
+ always))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if(!SystemTools::CopyAFile(fullPath, destination, always))
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+
+// return size of file; also returns zero if no file exists
+unsigned long SystemTools::FileLength(const std::string& filename)
+{
+ unsigned long length = 0;
+#ifdef _WIN32
+ WIN32_FILE_ATTRIBUTE_DATA fs;
+ if (GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(filename).c_str(),
+ GetFileExInfoStandard, &fs) != 0)
+ {
+ /* To support the full 64-bit file size, use fs.nFileSizeHigh
+ * and fs.nFileSizeLow to construct the 64 bit size
+
+ length = ((__int64)fs.nFileSizeHigh << 32) + fs.nFileSizeLow;
+ */
+ length = static_cast<unsigned long>(fs.nFileSizeLow);
+ }
+#else
+ struct stat fs;
+ if (stat(filename.c_str(), &fs) == 0)
+ {
+ length = static_cast<unsigned long>(fs.st_size);
+ }
+#endif
+ return length;
+}
+
+int SystemTools::Strucmp(const char *s1, const char *s2)
+{
+ // lifted from Graphvis http://www.graphviz.org
+ while ((*s1 != '\0')
+ && (tolower(*s1) == tolower(*s2)))
+ {
+ s1++;
+ s2++;
+ }
+
+ return tolower(*s1) - tolower(*s2);
+}
+
+// return file's modified time
+long int SystemTools::ModifiedTime(const std::string& filename)
+{
+ long int mt = 0;
+#ifdef _WIN32
+ WIN32_FILE_ATTRIBUTE_DATA fs;
+ if (GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(filename).c_str(),
+ GetFileExInfoStandard,
+ &fs) != 0)
+ {
+ mt = windows_filetime_to_posix_time(fs.ftLastWriteTime);
+ }
+#else
+ struct stat fs;
+ if (stat(filename.c_str(), &fs) == 0)
+ {
+ mt = static_cast<long int>(fs.st_mtime);
+ }
+#endif
+ return mt;
+}
+
+// return file's creation time
+long int SystemTools::CreationTime(const std::string& filename)
+{
+ long int ct = 0;
+#ifdef _WIN32
+ WIN32_FILE_ATTRIBUTE_DATA fs;
+ if (GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(filename).c_str(),
+ GetFileExInfoStandard,
+ &fs) != 0)
+ {
+ ct = windows_filetime_to_posix_time(fs.ftCreationTime);
+ }
+#else
+ struct stat fs;
+ if (stat(filename.c_str(), &fs) == 0)
+ {
+ ct = fs.st_ctime >= 0 ? static_cast<long int>(fs.st_ctime) : 0;
+ }
+#endif
+ return ct;
+}
+
+bool SystemTools::ConvertDateMacroString(const char *str, time_t *tmt)
+{
+ if (!str || !tmt || strlen(str) > 11)
+ {
+ return false;
+ }
+
+ struct tm tmt2;
+
+ // __DATE__
+ // The compilation date of the current source file. The date is a string
+ // literal of the form Mmm dd yyyy. The month name Mmm is the same as for
+ // dates generated by the library function asctime declared in TIME.H.
+
+ // index: 012345678901
+ // format: Mmm dd yyyy
+ // example: Dec 19 2003
+
+ static char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+ char buffer[12];
+ strcpy(buffer, str);
+
+ buffer[3] = 0;
+ char *ptr = strstr(month_names, buffer);
+ if (!ptr)
+ {
+ return false;
+ }
+
+ int month = static_cast<int>((ptr - month_names) / 3);
+ int day = atoi(buffer + 4);
+ int year = atoi(buffer + 7);
+
+ tmt2.tm_isdst = -1;
+ tmt2.tm_hour = 0;
+ tmt2.tm_min = 0;
+ tmt2.tm_sec = 0;
+ tmt2.tm_wday = 0;
+ tmt2.tm_yday = 0;
+ tmt2.tm_mday = day;
+ tmt2.tm_mon = month;
+ tmt2.tm_year = year - 1900;
+
+ *tmt = mktime(&tmt2);
+ return true;
+}
+
+bool SystemTools::ConvertTimeStampMacroString(const char *str, time_t *tmt)
+{
+ if (!str || !tmt || strlen(str) > 26)
+ {
+ return false;
+ }
+
+ struct tm tmt2;
+
+ // __TIMESTAMP__
+ // The date and time of the last modification of the current source file,
+ // expressed as a string literal in the form Ddd Mmm Date hh:mm:ss yyyy,
+ /// where Ddd is the abbreviated day of the week and Date is an integer
+ // from 1 to 31.
+
+ // index: 0123456789
+ // 0123456789
+ // 0123456789
+ // format: Ddd Mmm Date hh:mm:ss yyyy
+ // example: Fri Dec 19 14:34:58 2003
+
+ static char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+ char buffer[27];
+ strcpy(buffer, str);
+
+ buffer[7] = 0;
+ char *ptr = strstr(month_names, buffer + 4);
+ if (!ptr)
+ {
+ return false;
+ }
+
+ int month = static_cast<int>((ptr - month_names) / 3);
+ int day = atoi(buffer + 8);
+ int hour = atoi(buffer + 11);
+ int min = atoi(buffer + 14);
+ int sec = atoi(buffer + 17);
+ int year = atoi(buffer + 20);
+
+ tmt2.tm_isdst = -1;
+ tmt2.tm_hour = hour;
+ tmt2.tm_min = min;
+ tmt2.tm_sec = sec;
+ tmt2.tm_wday = 0;
+ tmt2.tm_yday = 0;
+ tmt2.tm_mday = day;
+ tmt2.tm_mon = month;
+ tmt2.tm_year = year - 1900;
+
+ *tmt = mktime(&tmt2);
+ return true;
+}
+
+std::string SystemTools::GetLastSystemError()
+{
+ int e = errno;
+ return strerror(e);
+}
+
+#ifdef _WIN32
+
+static bool IsJunction(const std::wstring& source)
+{
+#ifdef FSCTL_GET_REPARSE_POINT
+ const DWORD JUNCTION_ATTRS = FILE_ATTRIBUTE_DIRECTORY |
+ FILE_ATTRIBUTE_REPARSE_POINT;
+ DWORD attrs = GetFileAttributesW(source.c_str());
+ if (attrs == INVALID_FILE_ATTRIBUTES)
+ {
+ return false;
+ }
+ if ((attrs & JUNCTION_ATTRS) != JUNCTION_ATTRS)
+ {
+ return false;
+ }
+
+ // Adjust privileges so that we can succefully open junction points.
+ HANDLE token;
+ TOKEN_PRIVILEGES privs;
+ OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token);
+ LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &privs.Privileges[0].Luid);
+ privs.PrivilegeCount = 1;
+ privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ AdjustTokenPrivileges(token, FALSE, &privs, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
+ CloseHandle(token);
+
+ HANDLE dir = CreateFileW(source.c_str(), GENERIC_READ,
+ 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (dir == INVALID_HANDLE_VALUE)
+ {
+ return false;
+ }
+
+ // Query whether this is a reparse point or not.
+ BYTE buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ REPARSE_GUID_DATA_BUFFER *reparse_buffer =
+ (REPARSE_GUID_DATA_BUFFER*) buffer;
+ DWORD sentinel;
+
+ BOOL success = DeviceIoControl(
+ dir, FSCTL_GET_REPARSE_POINT,
+ NULL, 0,
+ reparse_buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
+ &sentinel, NULL);
+
+ CloseHandle(dir);
+
+ return (success && (reparse_buffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT));
+#else
+ return false;
+#endif
+}
+
+static bool DeleteJunction(const std::wstring& source)
+{
+#ifdef FSCTL_DELETE_REPARSE_POINT
+ // Adjust privileges so that we can succefully open junction points as
+ // read/write.
+ HANDLE token;
+ TOKEN_PRIVILEGES privs;
+ OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token);
+ LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &privs.Privileges[0].Luid);
+ privs.PrivilegeCount = 1;
+ privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ AdjustTokenPrivileges(token, FALSE, &privs, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
+ CloseHandle(token);
+
+ HANDLE dir = CreateFileW(source.c_str(), GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (dir == INVALID_HANDLE_VALUE)
+ {
+ return false;
+ }
+
+ // Set up the structure so that we can delete the junction.
+ std::vector<BYTE> buffer(REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, 0);
+ REPARSE_GUID_DATA_BUFFER *reparse_buffer =
+ (REPARSE_GUID_DATA_BUFFER*) &buffer[0];
+ DWORD sentinel;
+
+ reparse_buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+
+ BOOL success = DeviceIoControl(
+ dir, FSCTL_DELETE_REPARSE_POINT,
+ reparse_buffer, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE,
+ NULL, 0,
+ &sentinel, NULL);
+
+ CloseHandle(dir);
+
+ return !!success;
+#else
+ return false;
+#endif
+}
+
+#endif
+
+bool SystemTools::RemoveFile(const std::string& source)
+{
+#ifdef _WIN32
+ std::wstring const& ws =
+ SystemTools::ConvertToWindowsExtendedPath(source);
+ if (DeleteFileW(ws.c_str()))
+ {
+ return true;
+ }
+ DWORD err = GetLastError();
+ if (err == ERROR_FILE_NOT_FOUND ||
+ err == ERROR_PATH_NOT_FOUND)
+ {
+ return true;
+ }
+ if (err != ERROR_ACCESS_DENIED)
+ {
+ return false;
+ }
+ /* The file may be read-only. Try adding write permission. */
+ mode_t mode;
+ if (!SystemTools::GetPermissions(source, mode) ||
+ !SystemTools::SetPermissions(source, S_IWRITE))
+ {
+ SetLastError(err);
+ return false;
+ }
+ if (IsJunction(ws) && DeleteJunction(ws))
+ {
+ return true;
+ }
+ if (DeleteFileW(ws.c_str()) ||
+ GetLastError() == ERROR_FILE_NOT_FOUND ||
+ GetLastError() == ERROR_PATH_NOT_FOUND)
+ {
+ return true;
+ }
+ /* Try to restore the original permissions. */
+ SystemTools::SetPermissions(source, mode);
+ SetLastError(err);
+ return false;
+#else
+ return unlink(source.c_str()) == 0 || errno == ENOENT;
+#endif
+}
+
+bool SystemTools::RemoveADirectory(const std::string& source)
+{
+ // Add write permission to the directory so we can modify its
+ // content to remove files and directories from it.
+ mode_t mode;
+ if(SystemTools::GetPermissions(source, mode))
+ {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ mode |= S_IWRITE;
+#else
+ mode |= S_IWUSR;
+#endif
+ SystemTools::SetPermissions(source, mode);
+ }
+
+ Directory dir;
+#ifdef _WIN32
+ dir.Load(Encoding::ToNarrow(
+ SystemTools::ConvertToWindowsExtendedPath(source)));
+#else
+ dir.Load(source);
+#endif
+ size_t fileNum;
+ for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum)
+ {
+ if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)),".") &&
+ strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)),".."))
+ {
+ std::string fullPath = source;
+ fullPath += "/";
+ fullPath += dir.GetFile(static_cast<unsigned long>(fileNum));
+ if(SystemTools::FileIsDirectory(fullPath) &&
+ !SystemTools::FileIsSymlink(fullPath))
+ {
+ if (!SystemTools::RemoveADirectory(fullPath))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if(!SystemTools::RemoveFile(fullPath))
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ return (Rmdir(source) == 0);
+}
+
+/**
+ */
+size_t SystemTools::GetMaximumFilePathLength()
+{
+ return KWSYS_SYSTEMTOOLS_MAXPATH;
+}
+
+/**
+ * Find the file the given name. Searches the given path and then
+ * 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)
+{
+ // Add the system search path to our path first
+ std::vector<std::string> path;
+ if (!no_system_path)
+ {
+ SystemTools::GetPath(path, "CMAKE_FILE_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);
+ }
+ }
+ // 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 += "/";
+ }
+ }
+ }
+ // now look for the file
+ std::string tryPath;
+ for(std::vector<std::string>::const_iterator p = path.begin();
+ p != path.end(); ++p)
+ {
+ tryPath = *p;
+ tryPath += name;
+ if(SystemTools::FileExists(tryPath))
+ {
+ return tryPath;
+ }
+ }
+ // Couldn't find the file.
+ return "";
+}
+
+/**
+ * Find the file the given name. Searches the given path and then
+ * the system search path. Returns the full path to the file if it is
+ * found. Otherwise, the empty string is returned.
+ */
+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);
+ if(!tryPath.empty() && !SystemTools::FileIsDirectory(tryPath))
+ {
+ return SystemTools::CollapseFullPath(tryPath);
+ }
+ // Couldn't find the file.
+ return "";
+}
+
+/**
+ * Find the directory the given name. Searches the given path and then
+ * the system search path. Returns the full path to the directory if it is
+ * found. Otherwise, the empty string is returned.
+ */
+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);
+ if(!tryPath.empty() && SystemTools::FileIsDirectory(tryPath))
+ {
+ return SystemTools::CollapseFullPath(tryPath);
+ }
+ // Couldn't find the file.
+ return "";
+}
+
+/**
+ * Find the executable with the given name. Searches the given path and then
+ * the system search path. Returns the full path to the executable if it is
+ * found. Otherwise, the empty string is returned.
+ */
+std::string SystemTools::FindProgram(
+ const char* nameIn,
+ const std::vector<std::string>& userPaths,
+ bool no_system_path)
+{
+ if(!nameIn || !*nameIn)
+ {
+ return "";
+ }
+ return SystemTools::FindProgram(std::string(nameIn), userPaths, no_system_path);
+}
+
+std::string SystemTools::FindProgram(
+ const std::string& name,
+ const std::vector<std::string>& userPaths,
+ bool no_system_path)
+{
+ std::string tryPath;
+
+#if defined (_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+ std::vector<std::string> extensions;
+ // check to see if the name already has a .xxx at
+ // 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");
+
+ // first try with extensions if the os supports them
+ for(std::vector<std::string>::iterator i =
+ extensions.begin(); i != extensions.end(); ++i)
+ {
+ tryPath = name;
+ tryPath += *i;
+ if(SystemTools::FileExists(tryPath, true))
+ {
+ return SystemTools::CollapseFullPath(tryPath);
+ }
+ }
+ }
+#endif
+
+ // now try just the name
+ if(SystemTools::FileExists(name, true))
+ {
+ return SystemTools::CollapseFullPath(name);
+ }
+ // now construct the path
+ std::vector<std::string> path;
+ // Add the system search path to our path.
+ if (!no_system_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);
+ }
+ }
+ // 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 += "/";
+ }
+ }
+ }
+ // Try each path
+ for(std::vector<std::string>::iterator p = path.begin();
+ p != path.end(); ++p)
+ {
+#ifdef _WIN32
+ // Remove double quotes from the path on windows
+ 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;
+ tryPath += name;
+ tryPath += *ext;
+ if(SystemTools::FileExists(tryPath, true))
+ {
+ return SystemTools::CollapseFullPath(tryPath);
+ }
+ }
+#endif
+ // now try it without them
+ tryPath = *p;
+ tryPath += name;
+ if(SystemTools::FileExists(tryPath, true))
+ {
+ return SystemTools::CollapseFullPath(tryPath);
+ }
+ }
+ // Couldn't find the program.
+ return "";
+}
+
+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)
+ {
+ // Try to find the program.
+ std::string result = SystemTools::FindProgram(*it,
+ path,
+ noSystemPath);
+ if ( !result.empty() )
+ {
+ return result;
+ }
+ }
+ return "";
+}
+
+/**
+ * Find the library with the given name. Searches the given path and then
+ * the system search path. Returns the full path to the library if it is
+ * found. Otherwise, the empty string is returned.
+ */
+std::string SystemTools
+::FindLibrary(const std::string& name,
+ const std::vector<std::string>& userPaths)
+{
+ // See if the executable exists as written.
+ if(SystemTools::FileExists(name, true))
+ {
+ return SystemTools::CollapseFullPath(name);
+ }
+
+ // Add the system search path to our path.
+ 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);
+ }
+ }
+ // 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 += "/";
+ }
+ }
+ }
+ std::string tryPath;
+ for(std::vector<std::string>::const_iterator p = path.begin();
+ p != path.end(); ++p)
+ {
+#if defined(__APPLE__)
+ tryPath = *p;
+ tryPath += name;
+ tryPath += ".framework";
+ if(SystemTools::FileIsDirectory(tryPath))
+ {
+ return SystemTools::CollapseFullPath(tryPath);
+ }
+#endif
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
+ tryPath = *p;
+ tryPath += name;
+ tryPath += ".lib";
+ if(SystemTools::FileExists(tryPath, true))
+ {
+ return SystemTools::CollapseFullPath(tryPath);
+ }
+#else
+ tryPath = *p;
+ tryPath += "lib";
+ tryPath += name;
+ tryPath += ".so";
+ if(SystemTools::FileExists(tryPath, true))
+ {
+ return SystemTools::CollapseFullPath(tryPath);
+ }
+ tryPath = *p;
+ tryPath += "lib";
+ tryPath += name;
+ tryPath += ".a";
+ if(SystemTools::FileExists(tryPath, true))
+ {
+ return SystemTools::CollapseFullPath(tryPath);
+ }
+ tryPath = *p;
+ tryPath += "lib";
+ tryPath += name;
+ tryPath += ".sl";
+ if(SystemTools::FileExists(tryPath, true))
+ {
+ return SystemTools::CollapseFullPath(tryPath);
+ }
+ tryPath = *p;
+ tryPath += "lib";
+ tryPath += name;
+ tryPath += ".dylib";
+ if(SystemTools::FileExists(tryPath, true))
+ {
+ return SystemTools::CollapseFullPath(tryPath);
+ }
+ tryPath = *p;
+ tryPath += "lib";
+ tryPath += name;
+ tryPath += ".dll";
+ if(SystemTools::FileExists(tryPath, true))
+ {
+ return SystemTools::CollapseFullPath(tryPath);
+ }
+#endif
+ }
+
+ // Couldn't find the library.
+ return "";
+}
+
+std::string SystemTools::GetRealPath(const std::string& path,
+ std::string* errorMessage)
+{
+ std::string ret;
+ Realpath(path, ret, errorMessage);
+ return ret;
+}
+
+bool SystemTools::FileIsDirectory(const std::string& inName)
+{
+ if (inName.empty())
+ {
+ return false;
+ }
+ size_t length = inName.size();
+ const char* name = inName.c_str();
+
+ // Remove any trailing slash from the name except in a root component.
+ char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH];
+ std::string string_buffer;
+ size_t last = length-1;
+ if(last > 0 && (name[last] == '/' || name[last] == '\\')
+ && strcmp(name, "/") != 0 && name[last-1] != ':')
+ {
+ if (last < sizeof(local_buffer))
+ {
+ memcpy(local_buffer, name, last);
+ local_buffer[last] = '\0';
+ name = local_buffer;
+ }
+ else
+ {
+ string_buffer.append(name, last);
+ name = string_buffer.c_str();
+ }
+ }
+
+ // Now check the file node type.
+#if defined( _WIN32 )
+ DWORD attr = GetFileAttributesW(
+ SystemTools::ConvertToWindowsExtendedPath(name).c_str());
+ if (attr != INVALID_FILE_ATTRIBUTES)
+ {
+ return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
+#else
+ struct stat fs;
+ if(stat(name, &fs) == 0)
+ {
+ return S_ISDIR(fs.st_mode);
+#endif
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool SystemTools::FileIsSymlink(const std::string& name)
+{
+#if defined( _WIN32 )
+ DWORD attr = GetFileAttributesW(
+ SystemTools::ConvertToWindowsExtendedPath(name).c_str());
+ if (attr != INVALID_FILE_ATTRIBUTES)
+ {
+ return (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
+ }
+ else
+ {
+ return false;
+ }
+#else
+ struct stat fs;
+ if(lstat(name.c_str(), &fs) == 0)
+ {
+ return S_ISLNK(fs.st_mode);
+ }
+ else
+ {
+ return false;
+ }
+#endif
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::CreateSymlink(const std::string&, const std::string&)
+{
+ return false;
+}
+#else
+bool SystemTools::CreateSymlink(const std::string& origName, const std::string& newName)
+{
+ return symlink(origName.c_str(), newName.c_str()) >= 0;
+}
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::ReadSymlink(const std::string&, std::string&)
+{
+ return false;
+}
+#else
+bool SystemTools::ReadSymlink(const std::string& newName,
+ std::string& origName)
+{
+ char buf[KWSYS_SYSTEMTOOLS_MAXPATH+1];
+ int count =
+ static_cast<int>(readlink(newName.c_str(), buf, KWSYS_SYSTEMTOOLS_MAXPATH));
+ if(count >= 0)
+ {
+ // Add null-terminator.
+ buf[count] = 0;
+ origName = buf;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+#endif
+
+int SystemTools::ChangeDirectory(const std::string& dir)
+{
+ return Chdir(dir);
+}
+
+std::string SystemTools::GetCurrentWorkingDirectory(bool collapse)
+{
+ char buf[2048];
+ const char* cwd = Getcwd(buf, 2048);
+ std::string path;
+ if ( cwd )
+ {
+ path = cwd;
+ }
+ if(collapse)
+ {
+ return SystemTools::CollapseFullPath(path);
+ }
+ return path;
+}
+
+std::string SystemTools::GetProgramPath(const std::string& in_name)
+{
+ std::string dir, file;
+ SystemTools::SplitProgramPath(in_name, dir, file);
+ return dir;
+}
+
+bool SystemTools::SplitProgramPath(const std::string& in_name,
+ std::string& dir,
+ std::string& file,
+ bool)
+{
+ dir = in_name;
+ file = "";
+ SystemTools::ConvertToUnixSlashes(dir);
+
+ if(!SystemTools::FileIsDirectory(dir))
+ {
+ std::string::size_type slashPos = dir.rfind("/");
+ if(slashPos != std::string::npos)
+ {
+ file = dir.substr(slashPos+1);
+ dir = dir.substr(0, slashPos);
+ }
+ else
+ {
+ file = dir;
+ dir = "";
+ }
+ }
+ if(!(dir.empty()) && !SystemTools::FileIsDirectory(dir))
+ {
+ std::string oldDir = in_name;
+ SystemTools::ConvertToUnixSlashes(oldDir);
+ dir = in_name;
+ return false;
+ }
+ return true;
+}
+
+bool SystemTools::FindProgramPath(const char* argv0,
+ std::string& pathOut,
+ std::string& errorMsg,
+ const char* exeName,
+ const char* buildDir,
+ const char* installPrefix )
+{
+ std::vector<std::string> failures;
+ std::string self = argv0 ? argv0 : "";
+ failures.push_back(self);
+ SystemTools::ConvertToUnixSlashes(self);
+ self = SystemTools::FindProgram(self);
+ if(!SystemTools::FileExists(self))
+ {
+ if(buildDir)
+ {
+ std::string intdir = ".";
+#ifdef CMAKE_INTDIR
+ intdir = CMAKE_INTDIR;
+#endif
+ self = buildDir;
+ self += "/bin/";
+ self += intdir;
+ self += "/";
+ self += exeName;
+ self += SystemTools::GetExecutableExtension();
+ }
+ }
+ if(installPrefix)
+ {
+ if(!SystemTools::FileExists(self))
+ {
+ failures.push_back(self);
+ self = installPrefix;
+ self += "/bin/";
+ self += exeName;
+ }
+ }
+ if(!SystemTools::FileExists(self))
+ {
+ failures.push_back(self);
+ std::ostringstream msg;
+ msg << "Can not find the command line program ";
+ if (exeName)
+ {
+ msg << exeName;
+ }
+ msg << "\n";
+ if (argv0)
+ {
+ 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";
+ }
+ errorMsg = msg.str();
+ return false;
+ }
+ pathOut = self;
+ return true;
+}
+
+
+std::string SystemTools::CollapseFullPath(const std::string& in_relative)
+{
+ return SystemTools::CollapseFullPath(in_relative, 0);
+}
+
+void SystemTools::AddTranslationPath(const std::string& a, const std::string& b)
+{
+ std::string path_a = a;
+ std::string path_b = b;
+ SystemTools::ConvertToUnixSlashes(path_a);
+ SystemTools::ConvertToUnixSlashes(path_b);
+ // First check this is a directory path, since we don't want the table to
+ // grow too fat
+ if( SystemTools::FileIsDirectory( path_a ) )
+ {
+ // Make sure the path is a full path and does not contain no '..'
+ // Ken--the following code is incorrect. .. can be in a valid path
+ // for example /home/martink/MyHubba...Hubba/Src
+ 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() != '/')
+ {
+ path_a += '/';
+ }
+ if(!path_b.empty() && *path_b.rbegin() != '/')
+ {
+ path_b += '/';
+ }
+ if( !(path_a == path_b) )
+ {
+ SystemTools::TranslationMap->insert(
+ SystemToolsTranslationMap::value_type(path_a, path_b));
+ }
+ }
+ }
+}
+
+void SystemTools::AddKeepPath(const std::string& dir)
+{
+ std::string cdir;
+ Realpath(SystemTools::CollapseFullPath(dir).c_str(), cdir);
+ SystemTools::AddTranslationPath(cdir, dir);
+}
+
+void SystemTools::CheckTranslationPath(std::string & path)
+{
+ // Do not translate paths that are too short to have meaningful
+ // translations.
+ if(path.size() < 2)
+ {
+ return;
+ }
+
+ // 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 += "/";
+
+ // 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 )
+ {
+ // 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);
+ }
+ }
+
+ // Remove the trailing slash we added before.
+ path.erase(path.end()-1, path.end());
+}
+
+static void
+SystemToolsAppendComponents(
+ std::vector<std::string>& out_components,
+ std::vector<std::string>::const_iterator first,
+ std::vector<std::string>::const_iterator last)
+{
+ static const std::string up = "..";
+ static const std::string cur = ".";
+ for(std::vector<std::string>::const_iterator i = first;
+ i != last; ++i)
+ {
+ if(*i == up)
+ {
+ if(out_components.size() > 1)
+ {
+ out_components.resize(out_components.size()-1);
+ }
+ }
+ else if(!i->empty() && *i != cur)
+ {
+ out_components.push_back(*i);
+ }
+ }
+}
+
+std::string SystemTools::CollapseFullPath(const std::string& in_path,
+ const char* in_base)
+{
+ // Collect the output path components.
+ std::vector<std::string> out_components;
+
+ // Split the input path components.
+ std::vector<std::string> path_components;
+ SystemTools::SplitPath(in_path, path_components);
+
+ // If the input path is relative, start with a base path.
+ if(path_components[0].length() == 0)
+ {
+ std::vector<std::string> base_components;
+ if(in_base)
+ {
+ // Use the given base path.
+ SystemTools::SplitPath(in_base, base_components);
+ }
+ else
+ {
+ // Use the current working directory as a base path.
+ char buf[2048];
+ if(const char* cwd = Getcwd(buf, 2048))
+ {
+ SystemTools::SplitPath(cwd, base_components);
+ }
+ else
+ {
+ base_components.push_back("");
+ }
+ }
+
+ // Append base path components to the output path.
+ out_components.push_back(base_components[0]);
+ SystemToolsAppendComponents(out_components,
+ base_components.begin()+1,
+ base_components.end());
+ }
+
+ // Append input path components to the output path.
+ SystemToolsAppendComponents(out_components,
+ path_components.begin(),
+ path_components.end());
+
+ // Transform the path back to a string.
+ std::string newPath = SystemTools::JoinPath(out_components);
+
+ // 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
+ // from what I can see it created a mapping from the collapsed path, to be
+ // replaced by the input path, which almost completely does the opposite of
+ // this function, the only thing preventing this from happening a lot is
+ // that if the in_path has a .. in it, then it is not added to the
+ // translation table. So for most calls this either does nothing due to the
+ // .. or it adds a translation between identical paths as nothing was
+ // collapsed, so I am going to try to comment it out, and see what hits the
+ // fan, hopefully quickly.
+ // Commented out line below:
+ //SystemTools::AddTranslationPath(newPath, in_path);
+
+ SystemTools::CheckTranslationPath(newPath);
+#ifdef _WIN32
+ newPath = SystemTools::GetActualCaseForPath(newPath);
+ SystemTools::ConvertToUnixSlashes(newPath);
+#endif
+ // Return the reconstructed path.
+ return newPath;
+}
+
+std::string SystemTools::CollapseFullPath(const std::string& in_path,
+ const std::string& in_base)
+{
+ // Collect the output path components.
+ std::vector<std::string> out_components;
+
+ // Split the input path components.
+ std::vector<std::string> path_components;
+ SystemTools::SplitPath(in_path, path_components);
+
+ // If the input path is relative, start with a base path.
+ if(path_components[0].length() == 0)
+ {
+ std::vector<std::string> base_components;
+ // Use the given base path.
+ SystemTools::SplitPath(in_base, base_components);
+
+ // Append base path components to the output path.
+ out_components.push_back(base_components[0]);
+ SystemToolsAppendComponents(out_components,
+ base_components.begin()+1,
+ base_components.end());
+ }
+
+ // Append input path components to the output path.
+ SystemToolsAppendComponents(out_components,
+ path_components.begin(),
+ path_components.end());
+
+ // Transform the path back to a string.
+ std::string newPath = SystemTools::JoinPath(out_components);
+
+ // 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
+ // from what I can see it created a mapping from the collapsed path, to be
+ // replaced by the input path, which almost completely does the opposite of
+ // this function, the only thing preventing this from happening a lot is
+ // that if the in_path has a .. in it, then it is not added to the
+ // translation table. So for most calls this either does nothing due to the
+ // .. or it adds a translation between identical paths as nothing was
+ // collapsed, so I am going to try to comment it out, and see what hits the
+ // fan, hopefully quickly.
+ // Commented out line below:
+ //SystemTools::AddTranslationPath(newPath, in_path);
+
+ SystemTools::CheckTranslationPath(newPath);
+#ifdef _WIN32
+ newPath = SystemTools::GetActualCaseForPath(newPath);
+ SystemTools::ConvertToUnixSlashes(newPath);
+#endif
+ // Return the reconstructed path.
+ return newPath;
+}
+
+// compute the relative path from here to there
+std::string SystemTools::RelativePath(const std::string& local, const std::string& remote)
+{
+ if(!SystemTools::FileIsFullPath(local))
+ {
+ return "";
+ }
+ if(!SystemTools::FileIsFullPath(remote))
+ {
+ return "";
+ }
+
+ std::string l = SystemTools::CollapseFullPath(local);
+ std::string r = SystemTools::CollapseFullPath(remote);
+
+ // split up both paths into arrays of strings using / as a separator
+ std::vector<kwsys::String> localSplit = SystemTools::SplitString(l, '/', true);
+ std::vector<kwsys::String> remoteSplit = SystemTools::SplitString(r, '/', true);
+ std::vector<kwsys::String> commonPath; // store shared parts of path in this array
+ std::vector<kwsys::String> finalPath; // store the final relative path here
+ // count up how many matching directory names there are from the start
+ unsigned int sameCount = 0;
+ while(
+ ((sameCount <= (localSplit.size()-1)) && (sameCount <= (remoteSplit.size()-1)))
+ &&
+// for windows and apple do a case insensitive string compare
+#if defined(_WIN32) || defined(__APPLE__)
+ SystemTools::Strucmp(localSplit[sameCount].c_str(),
+ remoteSplit[sameCount].c_str()) == 0
+#else
+ localSplit[sameCount] == remoteSplit[sameCount]
+#endif
+ )
+ {
+ // put the common parts of the path into the commonPath array
+ commonPath.push_back(localSplit[sameCount]);
+ // erase the common parts of the path from the original path arrays
+ localSplit[sameCount] = "";
+ remoteSplit[sameCount] = "";
+ sameCount++;
+ }
+
+ // If there is nothing in common at all then just return the full
+ // path. This is the case only on windows when the paths have
+ // different drive letters. On unix two full paths always at least
+ // have the root "/" in common so we will return a relative path
+ // that passes through the root directory.
+ if(sameCount == 0)
+ {
+ return remote;
+ }
+
+ // 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 each entry that is not common in the remote path add it
+ // to the final path.
+ for(std::vector<String>::iterator vit = remoteSplit.begin();
+ vit != remoteSplit.end(); ++vit)
+ {
+ if(!vit->empty())
+ {
+ finalPath.push_back(*vit);
+ }
+ }
+ 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<String>::iterator vit1 = finalPath.begin();
+ vit1 != finalPath.end(); ++vit1)
+ {
+ if(!relativePath.empty() && *relativePath.rbegin() != '/')
+ {
+ relativePath += "/";
+ }
+ relativePath += *vit1;
+ }
+ return relativePath;
+}
+
+#ifdef _WIN32
+static int GetCasePathName(const std::string & pathIn,
+ std::string & casePath)
+{
+ std::vector<std::string> path_components;
+ SystemTools::SplitPath(pathIn, path_components);
+ if(path_components[0].empty()) // First component always exists.
+ {
+ // Relative paths cannot be converted.
+ casePath = "";
+ return 0;
+ }
+
+ // 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 = "/";
+ }
+
+ for(; idx < path_components.size(); idx++)
+ {
+ casePath += sep;
+ sep = "/";
+ std::string test_str = casePath;
+ test_str += path_components[idx];
+
+ // 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)
+ {
+ casePath = "";
+ return 0;
+ }
+
+ WIN32_FIND_DATAW findData;
+ HANDLE hFind = ::FindFirstFileW(Encoding::ToWide(test_str).c_str(),
+ &findData);
+ if (INVALID_HANDLE_VALUE != hFind)
+ {
+ casePath += Encoding::ToNarrow(findData.cFileName);
+ ::FindClose(hFind);
+ }
+ else
+ {
+ casePath = "";
+ return 0;
+ }
+ }
+ return (int)casePath.size();
+}
+#endif
+
+
+//----------------------------------------------------------------------------
+std::string SystemTools::GetActualCaseForPath(const std::string& p)
+{
+#ifndef _WIN32
+ return p;
+#else
+ // 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;
+ int len = GetCasePathName(p, casePath);
+ if(len == 0 || len > MAX_PATH+1)
+ {
+ return p;
+ }
+ (*SystemTools::PathCaseMap)[p] = casePath;
+ return casePath;
+#endif
+}
+
+//----------------------------------------------------------------------------
+const char* SystemTools::SplitPathRootComponent(const std::string& p,
+ std::string* root)
+{
+ // Identify the root component.
+ const char* c = p.c_str();
+ if((c[0] == '/' && c[1] == '/') || (c[0] == '\\' && c[1] == '\\'))
+ {
+ // Network path.
+ if(root)
+ {
+ *root = "//";
+ }
+ c += 2;
+ }
+ else if(c[0] == '/' || c[0] == '\\')
+ {
+ // Unix path (or Windows path w/out drive letter).
+ if(root)
+ {
+ *root = "/";
+ }
+ c += 1;
+ }
+ else if(c[0] && c[1] == ':' && (c[2] == '/' || c[2] == '\\'))
+ {
+ // Windows path.
+ if(root)
+ {
+ (*root) = "_:/";
+ (*root)[0] = c[0];
+ }
+ c += 3;
+ }
+ else if(c[0] && c[1] == ':')
+ {
+ // Path relative to a windows drive working directory.
+ if(root)
+ {
+ (*root) = "_:";
+ (*root)[0] = c[0];
+ }
+ c += 2;
+ }
+ else if(c[0] == '~')
+ {
+ // Home directory. The returned root should always have a
+ // trailing slash so that appending components as
+ // c[0]c[1]/c[2]/... works. The remaining path returned should
+ // skip the first slash if it exists:
+ //
+ // "~" : root = "~/" , return ""
+ // "~/ : root = "~/" , return ""
+ // "~/x : root = "~/" , return "x"
+ // "~u" : root = "~u/", return ""
+ // "~u/" : root = "~u/", return ""
+ // "~u/x" : root = "~u/", return "x"
+ size_t n = 1;
+ while(c[n] && c[n] != '/')
+ {
+ ++n;
+ }
+ if(root)
+ {
+ root->assign(c, n);
+ *root += '/';
+ }
+ if(c[n] == '/')
+ {
+ ++n;
+ }
+ c += n;
+ }
+ else
+ {
+ // Relative path.
+ if(root)
+ {
+ *root = "";
+ }
+ }
+
+ // Return the remaining path.
+ return c;
+}
+
+//----------------------------------------------------------------------------
+void SystemTools::SplitPath(const std::string& p,
+ std::vector<std::string>& components,
+ bool expand_home_dir)
+{
+ const char* c;
+ components.clear();
+
+ // Identify the root component.
+ {
+ std::string root;
+ c = SystemTools::SplitPathRootComponent(p, &root);
+
+ // Expand home directory references if requested.
+ if(expand_home_dir && !root.empty() && root[0] == '~')
+ {
+ std::string homedir;
+ root = root.substr(0, root.size()-1);
+ if(root.size() == 1)
+ {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if(const char* userp = getenv("USERPROFILE"))
+ {
+ homedir = userp;
+ }
+ else
+#endif
+ if(const char* h = getenv("HOME"))
+ {
+ homedir = h;
+ }
+ }
+#ifdef HAVE_GETPWNAM
+ else if(passwd* pw = getpwnam(root.c_str()+1))
+ {
+ if(pw->pw_dir)
+ {
+ homedir = pw->pw_dir;
+ }
+ }
+#endif
+ if(!homedir.empty() && (*homedir.rbegin() == '/' ||
+ *homedir.rbegin() == '\\'))
+ {
+ homedir.resize(homedir.size() - 1);
+ }
+ SystemTools::SplitPath(homedir, components);
+ }
+ else
+ {
+ components.push_back(root);
+ }
+ }
+
+ // Parse the remaining components.
+ const char* first = c;
+ const char* last = first;
+ for(;*last; ++last)
+ {
+ if(*last == '/' || *last == '\\')
+ {
+ // End of a component. Save it.
+ components.push_back(std::string(first, last));
+ first = last+1;
+ }
+ }
+
+ // Save the last component unless there were no components.
+ if(last != c)
+ {
+ components.push_back(std::string(first, last));
+ }
+}
+
+//----------------------------------------------------------------------------
+std::string
+SystemTools::JoinPath(const std::vector<std::string>& components)
+{
+ return SystemTools::JoinPath(components.begin(), components.end());
+}
+
+//----------------------------------------------------------------------------
+std::string
+SystemTools
+::JoinPath(std::vector<std::string>::const_iterator first,
+ std::vector<std::string>::const_iterator last)
+{
+ // 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)
+ {
+ len += 1 + i->size();
+ }
+ result.reserve(len);
+
+ // The first two components do not add a slash.
+ if(first != last)
+ {
+ result.append(*first++);
+ }
+ if(first != last)
+ {
+ result.append(*first++);
+ }
+
+ // All remaining components are always separated with a slash.
+ while(first != last)
+ {
+ result.append("/");
+ result.append((*first++));
+ }
+
+ // Return the concatenated result.
+ return result;
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::ComparePath(const std::string& c1, const std::string& c2)
+{
+#if defined(_WIN32) || defined(__APPLE__)
+# ifdef _MSC_VER
+ return _stricmp(c1.c_str(), c2.c_str()) == 0;
+# elif defined(__APPLE__) || defined(__GNUC__)
+ return strcasecmp(c1.c_str(), c2.c_str()) == 0;
+#else
+ return SystemTools::Strucmp(c1.c_str(), c2.c_str()) == 0;
+# endif
+#else
+ return c1 == c2;
+#endif
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::Split(const std::string& str, std::vector<std::string>& lines, char separator)
+{
+ std::string data(str);
+ std::string::size_type lpos = 0;
+ while(lpos < data.length())
+ {
+ std::string::size_type rpos = data.find_first_of(separator, lpos);
+ if(rpos == std::string::npos)
+ {
+ // Line ends at end of string without a newline.
+ lines.push_back(data.substr(lpos));
+ return false;
+ }
+ else
+ {
+ // Line ends in a "\n", remove the character.
+ lines.push_back(data.substr(lpos, rpos-lpos));
+ }
+ lpos = rpos+1;
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::Split(const std::string& str, std::vector<std::string>& lines)
+{
+ std::string data(str);
+ std::string::size_type lpos = 0;
+ while(lpos < data.length())
+ {
+ std::string::size_type rpos = data.find_first_of("\n", lpos);
+ if(rpos == std::string::npos)
+ {
+ // Line ends at end of string without a newline.
+ lines.push_back(data.substr(lpos));
+ return false;
+ }
+ if((rpos > lpos) && (data[rpos-1] == '\r'))
+ {
+ // Line ends in a "\r\n" pair, remove both characters.
+ lines.push_back(data.substr(lpos, (rpos-1)-lpos));
+ }
+ else
+ {
+ // Line ends in a "\n", remove the character.
+ lines.push_back(data.substr(lpos, rpos-lpos));
+ }
+ lpos = rpos+1;
+ }
+ return true;
+}
+
+/**
+ * Return path of a full filename (no trailing slashes).
+ * Warning: returned path is converted to Unix slashes format.
+ */
+std::string SystemTools::GetFilenamePath(const std::string& filename)
+{
+ std::string fn = filename;
+ SystemTools::ConvertToUnixSlashes(fn);
+
+ std::string::size_type slash_pos = fn.rfind("/");
+ if(slash_pos != std::string::npos)
+ {
+ std::string ret = fn.substr(0, slash_pos);
+ if(ret.size() == 2 && ret[1] == ':')
+ {
+ return ret + '/';
+ }
+ if(ret.empty())
+ {
+ return "/";
+ }
+ return ret;
+ }
+ else
+ {
+ return "";
+ }
+}
+
+
+/**
+ * Return file name of a full filename (i.e. file name without path).
+ */
+std::string SystemTools::GetFilenameName(const std::string& filename)
+{
+#if defined(_WIN32)
+ std::string::size_type slash_pos = filename.find_last_of("/\\");
+#else
+ std::string::size_type slash_pos = filename.rfind('/');
+#endif
+ if(slash_pos != std::string::npos)
+ {
+ return filename.substr(slash_pos + 1);
+ }
+ else
+ {
+ return filename;
+ }
+}
+
+
+/**
+ * Return file extension of a full filename (dot included).
+ * Warning: this is the longest extension (for example: .tar.gz)
+ */
+std::string SystemTools::GetFilenameExtension(const std::string& filename)
+{
+ std::string name = SystemTools::GetFilenameName(filename);
+ std::string::size_type dot_pos = name.find('.');
+ if(dot_pos != std::string::npos)
+ {
+ return name.substr(dot_pos);
+ }
+ else
+ {
+ return "";
+ }
+}
+
+/**
+ * Return file extension of a full filename (dot included).
+ * Warning: this is the shortest extension (for example: .gz of .tar.gz)
+ */
+std::string SystemTools::GetFilenameLastExtension(const std::string& filename)
+{
+ std::string name = SystemTools::GetFilenameName(filename);
+ std::string::size_type dot_pos = name.rfind('.');
+ if(dot_pos != std::string::npos)
+ {
+ return name.substr(dot_pos);
+ }
+ else
+ {
+ return "";
+ }
+}
+
+/**
+ * Return file name without extension of a full filename (i.e. without path).
+ * Warning: it considers the longest extension (for example: .tar.gz)
+ */
+std::string SystemTools::GetFilenameWithoutExtension(const std::string& filename)
+{
+ std::string name = SystemTools::GetFilenameName(filename);
+ std::string::size_type dot_pos = name.find('.');
+ if(dot_pos != std::string::npos)
+ {
+ return name.substr(0, dot_pos);
+ }
+ else
+ {
+ return name;
+ }
+}
+
+
+/**
+ * Return file name without extension of a full filename (i.e. without path).
+ * Warning: it considers the last extension (for example: removes .gz
+ * from .tar.gz)
+ */
+std::string
+SystemTools::GetFilenameWithoutLastExtension(const std::string& filename)
+{
+ std::string name = SystemTools::GetFilenameName(filename);
+ std::string::size_type dot_pos = name.rfind('.');
+ if(dot_pos != std::string::npos)
+ {
+ return name.substr(0, dot_pos);
+ }
+ else
+ {
+ return name;
+ }
+}
+
+bool SystemTools::FileHasSignature(const char *filename,
+ const char *signature,
+ long offset)
+{
+ if (!filename || !signature)
+ {
+ return false;
+ }
+
+ FILE *fp = Fopen(filename, "rb");
+ if (!fp)
+ {
+ return false;
+ }
+
+ fseek(fp, offset, SEEK_SET);
+
+ bool res = false;
+ size_t signature_len = strlen(signature);
+ char *buffer = new char [signature_len];
+
+ if (fread(buffer, 1, signature_len, fp) == signature_len)
+ {
+ res = (!strncmp(buffer, signature, signature_len) ? true : false);
+ }
+
+ delete [] buffer;
+
+ fclose(fp);
+ return res;
+}
+
+SystemTools::FileTypeEnum
+SystemTools::DetectFileType(const char *filename,
+ unsigned long length,
+ double percent_bin)
+{
+ if (!filename || percent_bin < 0)
+ {
+ return SystemTools::FileTypeUnknown;
+ }
+
+ if (SystemTools::FileIsDirectory(filename))
+ {
+ return SystemTools::FileTypeUnknown;
+ }
+
+ FILE *fp = Fopen(filename, "rb");
+ if (!fp)
+ {
+ return SystemTools::FileTypeUnknown;
+ }
+
+ // Allocate buffer and read bytes
+
+ unsigned char *buffer = new unsigned char [length];
+ size_t read_length = fread(buffer, 1, length, fp);
+ fclose(fp);
+ if (read_length == 0)
+ {
+ delete [] buffer;
+ return SystemTools::FileTypeUnknown;
+ }
+
+ // Loop over contents and count
+
+ size_t text_count = 0;
+
+ const unsigned char *ptr = buffer;
+ const unsigned char *buffer_end = buffer + read_length;
+
+ while (ptr != buffer_end)
+ {
+ if ((*ptr >= 0x20 && *ptr <= 0x7F) ||
+ *ptr == '\n' ||
+ *ptr == '\r' ||
+ *ptr == '\t')
+ {
+ text_count++;
+ }
+ ptr++;
+ }
+
+ delete [] buffer;
+
+ double current_percent_bin =
+ (static_cast<double>(read_length - text_count) /
+ static_cast<double>(read_length));
+
+ if (current_percent_bin >= percent_bin)
+ {
+ return SystemTools::FileTypeBinary;
+ }
+
+ return SystemTools::FileTypeText;
+}
+
+bool SystemTools::LocateFileInDir(const char *filename,
+ const char *dir,
+ std::string& filename_found,
+ int try_filename_dirs)
+{
+ if (!filename || !dir)
+ {
+ return false;
+ }
+
+ // Get the basename of 'filename'
+
+ std::string filename_base = SystemTools::GetFilenameName(filename);
+
+ // Check if 'dir' is really a directory
+ // If win32 and matches something like C:, accept it as a dir
+
+ std::string real_dir;
+ if (!SystemTools::FileIsDirectory(dir))
+ {
+#if defined( _WIN32 )
+ size_t dir_len = strlen(dir);
+ if (dir_len < 2 || dir[dir_len - 1] != ':')
+ {
+#endif
+ real_dir = SystemTools::GetFilenamePath(dir);
+ dir = real_dir.c_str();
+#if defined( _WIN32 )
+ }
+#endif
+ }
+
+ // Try to find the file in 'dir'
+
+ bool res = false;
+ if (!filename_base.empty() && dir)
+ {
+ size_t dir_len = strlen(dir);
+ int need_slash =
+ (dir_len && dir[dir_len - 1] != '/' && dir[dir_len - 1] != '\\');
+
+ std::string temp = dir;
+ if (need_slash)
+ {
+ temp += "/";
+ }
+ temp += filename_base;
+
+ if (SystemTools::FileExists(temp))
+ {
+ res = true;
+ filename_found = temp;
+ }
+
+ // If not found, we can try harder by appending part of the file to
+ // to the directory to look inside.
+ // Example: if we were looking for /foo/bar/yo.txt in /d1/d2, then
+ // try to find yo.txt in /d1/d2/bar, then /d1/d2/foo/bar, etc.
+
+ else if (try_filename_dirs)
+ {
+ std::string filename_dir(filename);
+ std::string filename_dir_base;
+ std::string filename_dir_bases;
+ do
+ {
+ 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() == ':')
+#else
+ if (filename_dir_base.empty())
+#endif
+ {
+ break;
+ }
+
+ filename_dir_bases = filename_dir_base + "/" + filename_dir_bases;
+
+ temp = dir;
+ if (need_slash)
+ {
+ temp += "/";
+ }
+ temp += filename_dir_bases;
+
+ res = SystemTools::LocateFileInDir(
+ filename_base.c_str(), temp.c_str(), filename_found, 0);
+
+ } while (!res && !filename_dir_base.empty());
+ }
+ }
+
+ return res;
+}
+
+bool SystemTools::FileIsFullPath(const std::string& in_name)
+{
+ return SystemTools::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);
+}
+
+bool SystemTools::FileIsFullPath(const char* in_name, size_t len)
+{
+#if defined(_WIN32) || defined(__CYGWIN__)
+ // On Windows, the name must be at least two characters long.
+ if(len < 2)
+ {
+ return false;
+ }
+ if(in_name[1] == ':')
+ {
+ return true;
+ }
+ if(in_name[0] == '\\')
+ {
+ return true;
+ }
+#else
+ // On UNIX, the name must be at least one character long.
+ if(len < 1)
+ {
+ return false;
+ }
+#endif
+#if !defined(_WIN32)
+ if(in_name[0] == '~')
+ {
+ return true;
+ }
+#endif
+ // On UNIX, the name must begin in a '/'.
+ // On Windows, if the name begins in a '/', then it is a full
+ // network path.
+ if(in_name[0] == '/')
+ {
+ return true;
+ }
+ return false;
+}
+
+bool SystemTools::GetShortPath(const std::string& path, std::string& shortPath)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ 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() == '"')
+ {
+ tempPath = path.substr(1, path.length()-2);
+ }
+
+ std::wstring wtempPath = Encoding::ToWide(tempPath);
+ DWORD ret = GetShortPathNameW(wtempPath.c_str(), NULL, 0);
+ std::vector<wchar_t> buffer(ret);
+ ret = GetShortPathNameW(wtempPath.c_str(),
+ &buffer[0], static_cast<DWORD>(buffer.size()));
+
+ if (ret == 0)
+ {
+ return false;
+ }
+ else
+ {
+ shortPath = Encoding::ToNarrow(&buffer[0]);
+ return true;
+ }
+#else
+ shortPath = path;
+ return true;
+#endif
+}
+
+void SystemTools::SplitProgramFromArgs(const std::string& path,
+ std::string& program, std::string& args)
+{
+ // see if this is a full path to a program
+ // if so then set program to path and args to nothing
+ if(SystemTools::FileExists(path))
+ {
+ program = path;
+ args = "";
+ return;
+ }
+ // Try to find the program in the path, note the program
+ // may have spaces in its name so we have to look for it
+ std::vector<std::string> e;
+ std::string findProg = SystemTools::FindProgram(path, e);
+ if(!findProg.empty())
+ {
+ program = findProg;
+ args = "";
+ return;
+ }
+
+ // Now try and peel off space separated chunks from the end of the string
+ // so the largest path possible is found allowing for spaces in the path
+ std::string dir = path;
+ std::string::size_type spacePos = dir.rfind(' ');
+ while(spacePos != std::string::npos)
+ {
+ std::string tryProg = dir.substr(0, spacePos);
+ // See if the file exists
+ if(SystemTools::FileExists(tryProg))
+ {
+ program = tryProg;
+ // remove trailing spaces from program
+ std::string::size_type pos = program.size()-1;
+ while(program[pos] == ' ')
+ {
+ program.erase(pos);
+ pos--;
+ }
+ args = dir.substr(spacePos, dir.size()-spacePos);
+ return;
+ }
+ // Now try and find the program in the path
+ findProg = SystemTools::FindProgram(tryProg, e);
+ if(!findProg.empty())
+ {
+ program = findProg;
+ // remove trailing spaces from program
+ std::string::size_type pos = program.size()-1;
+ while(program[pos] == ' ')
+ {
+ program.erase(pos);
+ pos--;
+ }
+ args = dir.substr(spacePos, dir.size()-spacePos);
+ return;
+ }
+ // move past the space for the next search
+ spacePos--;
+ spacePos = dir.rfind(' ', spacePos);
+ }
+
+ program = "";
+ args = "";
+}
+
+std::string SystemTools::GetCurrentDateTime(const char* format)
+{
+ char buf[1024];
+ time_t t;
+ time(&t);
+ strftime(buf, sizeof(buf), format, localtime(&t));
+ return std::string(buf);
+}
+
+std::string SystemTools::MakeCidentifier(const std::string& s)
+{
+ std::string str(s);
+ if (str.find_first_of("0123456789") == 0)
+ {
+ str = "_" + str;
+ }
+
+ std::string permited_chars("_"
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789");
+ std::string::size_type pos = 0;
+ while ((pos = str.find_first_not_of(permited_chars, pos)) != std::string::npos)
+ {
+ str[pos] = '_';
+ }
+ return str;
+}
+
+// Due to a buggy stream library on the HP and another on Mac OS X, we
+// need this very carefully written version of getline. Returns true
+// if any data were read before the end-of-file was reached.
+bool SystemTools::GetLineFromStream(std::istream& is,
+ std::string& line,
+ bool* has_newline /* = 0 */,
+ long sizeLimit /* = -1 */)
+{
+ const int bufferSize = 1024;
+ char buffer[bufferSize];
+ bool haveData = false;
+ bool haveNewline = false;
+
+ // Start with an empty line.
+ line = "";
+
+ long leftToRead = sizeLimit;
+
+ // Early short circuit return if stream is no good. Just return
+ // false and the empty line. (Probably means caller tried to
+ // create a file stream with a non-existent file name...)
+ //
+ if(!is)
+ {
+ if(has_newline)
+ {
+ *has_newline = false;
+ }
+ return false;
+ }
+
+ // If no characters are read from the stream, the end of file has
+ // been reached. Clear the fail bit just before reading.
+ while(!haveNewline &&
+ leftToRead != 0 &&
+ (static_cast<void>(is.clear(is.rdstate() & ~std::ios::failbit)),
+ static_cast<void>(is.getline(buffer, bufferSize)),
+ is.gcount() > 0))
+ {
+ // We have read at least one byte.
+ haveData = true;
+
+ // If newline character was read the gcount includes the character
+ // but the buffer does not: the end of line has been reached.
+ size_t length = strlen(buffer);
+ if(length < static_cast<size_t>(is.gcount()))
+ {
+ haveNewline = true;
+ }
+
+ // Avoid storing a carriage return character.
+ if(length > 0 && buffer[length-1] == '\r')
+ {
+ buffer[length-1] = 0;
+ }
+
+ // if we read too much then truncate the buffer
+ if (leftToRead > 0)
+ {
+ if (static_cast<long>(length) > leftToRead)
+ {
+ buffer[leftToRead-1] = 0;
+ leftToRead = 0;
+ }
+ else
+ {
+ leftToRead -= static_cast<long>(length);
+ }
+ }
+
+ // Append the data read to the line.
+ line.append(buffer);
+ }
+
+ // Return the results.
+ if(has_newline)
+ {
+ *has_newline = haveNewline;
+ }
+ return haveData;
+}
+
+int SystemTools::GetTerminalWidth()
+{
+ int width = -1;
+#ifdef HAVE_TTY_INFO
+ struct winsize ws;
+ char *columns; /* Unix98 environment variable */
+ if(ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col>0 && ws.ws_row>0)
+ {
+ width = ws.ws_col;
+ }
+ if(!isatty(STDOUT_FILENO))
+ {
+ width = -1;
+ }
+ columns = getenv("COLUMNS");
+ if(columns && *columns)
+ {
+ long t;
+ char *endptr;
+ t = strtol(columns, &endptr, 0);
+ if(endptr && !*endptr && (t>0) && (t<1000))
+ {
+ width = static_cast<int>(t);
+ }
+ }
+ if ( width < 9 )
+ {
+ width = -1;
+ }
+#endif
+ return width;
+}
+
+bool SystemTools::GetPermissions(const char* file, mode_t& mode)
+{
+ if ( !file )
+ {
+ return false;
+ }
+ return SystemTools::GetPermissions(std::string(file), mode);
+}
+
+bool SystemTools::GetPermissions(const std::string& file, mode_t& mode)
+{
+#if defined(_WIN32)
+ DWORD attr = GetFileAttributesW(
+ SystemTools::ConvertToWindowsExtendedPath(file).c_str());
+ if(attr == INVALID_FILE_ATTRIBUTES)
+ {
+ return false;
+ }
+ if((attr & FILE_ATTRIBUTE_READONLY) != 0)
+ {
+ mode = (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6));
+ }
+ else
+ {
+ mode = (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6)) |
+ (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6));
+ }
+ if((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ {
+ mode |= S_IFDIR | (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6));
+ }
+ else
+ {
+ mode |= S_IFREG;
+ }
+ size_t dotPos = file.rfind('.');
+ const char* ext = dotPos == file.npos ? 0 : (file.c_str() + dotPos);
+ if(ext && (Strucmp(ext, ".exe") == 0 ||
+ Strucmp(ext, ".com") == 0 ||
+ Strucmp(ext, ".cmd") == 0 ||
+ Strucmp(ext, ".bat") == 0))
+ {
+ mode |= (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6));
+ }
+#else
+ struct stat st;
+ if ( stat(file.c_str(), &st) < 0 )
+ {
+ return false;
+ }
+ mode = st.st_mode;
+#endif
+ return true;
+}
+
+bool SystemTools::SetPermissions(const char* file,
+ mode_t mode,
+ bool honor_umask)
+{
+ if ( !file )
+ {
+ return false;
+ }
+ return SystemTools::SetPermissions(
+ std::string(file), mode, honor_umask);
+}
+
+bool SystemTools::SetPermissions(const std::string& file,
+ mode_t mode,
+ bool honor_umask)
+{
+ // TEMPORARY / TODO: After FileExists calls lstat() instead of
+ // access(), change this call to FileExists instead of
+ // TestFileAccess so that we don't follow symlinks.
+ if ( !SystemTools::TestFileAccess(file, TEST_FILE_OK) )
+ {
+ return false;
+ }
+ if (honor_umask)
+ {
+ mode_t currentMask = umask(0);
+ umask(currentMask);
+ mode &= ~currentMask;
+ }
+#ifdef _WIN32
+ if ( _wchmod(SystemTools::ConvertToWindowsExtendedPath(file).c_str(),
+ mode) < 0 )
+#else
+ if ( chmod(file.c_str(), mode) < 0 )
+#endif
+ {
+ return false;
+ }
+
+ return true;
+}
+
+std::string SystemTools::GetParentDirectory(const std::string& fileOrDir)
+{
+ return SystemTools::GetFilenamePath(fileOrDir);
+}
+
+bool SystemTools::IsSubDirectory(const std::string& cSubdir, const std::string& cDir)
+{
+ if(cDir.empty())
+ {
+ return false;
+ }
+ std::string subdir = cSubdir;
+ std::string dir = cDir;
+ SystemTools::ConvertToUnixSlashes(subdir);
+ SystemTools::ConvertToUnixSlashes(dir);
+ if(subdir.size() > dir.size() && subdir[dir.size()] == '/')
+ {
+ std::string s = subdir.substr(0, dir.size());
+ return SystemTools::ComparePath(s, dir);
+ }
+ return false;
+}
+
+void SystemTools::Delay(unsigned int msec)
+{
+#ifdef _WIN32
+ Sleep(msec);
+#else
+ // The sleep function gives 1 second resolution and the usleep
+ // function gives 1e-6 second resolution but on some platforms has a
+ // maximum sleep time of 1 second. This could be re-implemented to
+ // use select with masked signals or pselect to mask signals
+ // atomically. If select is given empty sets and zero as the max
+ // file descriptor but a non-zero timeout it can be used to block
+ // for a precise amount of time.
+ if(msec >= 1000)
+ {
+ sleep(msec / 1000);
+ usleep((msec % 1000) * 1000);
+ }
+ else
+ {
+ usleep(msec * 1000);
+ }
+#endif
+}
+
+std::string SystemTools::GetOperatingSystemNameAndVersion()
+{
+ std::string res;
+
+#ifdef _WIN32
+ char buffer[256];
+
+ OSVERSIONINFOEXA osvi;
+ BOOL bOsVersionInfoEx;
+
+ ZeroMemory(&osvi, sizeof(osvi));
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+# pragma warning (push)
+# ifdef __INTEL_COMPILER
+# pragma warning (disable:1478)
+# else
+# pragma warning (disable:4996)
+# endif
+#endif
+ bOsVersionInfoEx = GetVersionExA((OSVERSIONINFOA *)&osvi);
+ if (!bOsVersionInfoEx)
+ {
+ return 0;
+ }
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+# pragma warning (pop)
+#endif
+
+ switch (osvi.dwPlatformId)
+ {
+ // Test for the Windows NT product family.
+
+ case VER_PLATFORM_WIN32_NT:
+
+ // Test for the specific product family.
+ if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0)
+ {
+ if (osvi.wProductType == VER_NT_WORKSTATION)
+ {
+ res += "Microsoft Windows 10";
+ }
+ else
+ {
+ res += "Microsoft Windows Server 2016 family";
+ }
+ }
+
+ if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3)
+ {
+ if (osvi.wProductType == VER_NT_WORKSTATION)
+ {
+ res += "Microsoft Windows 8.1";
+ }
+ else
+ {
+ res += "Microsoft Windows Server 2012 R2 family";
+ }
+ }
+
+ if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2)
+ {
+ if (osvi.wProductType == VER_NT_WORKSTATION)
+ {
+ res += "Microsoft Windows 8";
+ }
+ else
+ {
+ res += "Microsoft Windows Server 2012 family";
+ }
+ }
+
+ if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1)
+ {
+ if (osvi.wProductType == VER_NT_WORKSTATION)
+ {
+ res += "Microsoft Windows 7";
+ }
+ else
+ {
+ res += "Microsoft Windows Server 2008 R2 family";
+ }
+ }
+
+ if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
+ {
+ if (osvi.wProductType == VER_NT_WORKSTATION)
+ {
+ res += "Microsoft Windows Vista";
+ }
+ else
+ {
+ res += "Microsoft Windows Server 2008 family";
+ }
+ }
+
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
+ {
+ res += "Microsoft Windows Server 2003 family";
+ }
+
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
+ {
+ res += "Microsoft Windows XP";
+ }
+
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
+ {
+ res += "Microsoft Windows 2000";
+ }
+
+ if (osvi.dwMajorVersion <= 4)
+ {
+ res += "Microsoft Windows NT";
+ }
+
+ // Test for specific product on Windows NT 4.0 SP6 and later.
+
+ if (bOsVersionInfoEx)
+ {
+ // Test for the workstation type.
+
+ if (osvi.wProductType == VER_NT_WORKSTATION)
+ {
+ if (osvi.dwMajorVersion == 4)
+ {
+ res += " Workstation 4.0";
+ }
+ else if (osvi.dwMajorVersion == 5)
+ {
+ if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
+ {
+ res += " Home Edition";
+ }
+ else
+ {
+ res += " Professional";
+ }
+ }
+ }
+
+ // Test for the server type.
+
+ else if (osvi.wProductType == VER_NT_SERVER)
+ {
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
+ {
+ if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
+ {
+ res += " Datacenter Edition";
+ }
+ else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
+ {
+ res += " Enterprise Edition";
+ }
+ else if (osvi.wSuiteMask == VER_SUITE_BLADE)
+ {
+ res += " Web Edition";
+ }
+ else
+ {
+ res += " Standard Edition";
+ }
+ }
+
+ else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
+ {
+ if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
+ {
+ res += " Datacenter Server";
+ }
+ else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
+ {
+ res += " Advanced Server";
+ }
+ else
+ {
+ res += " Server";
+ }
+ }
+
+ else if (osvi.dwMajorVersion <= 4) // Windows NT 4.0
+ {
+ if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
+ {
+ res += " Server 4.0, Enterprise Edition";
+ }
+ else
+ {
+ res += " Server 4.0";
+ }
+ }
+ }
+ }
+
+ // Test for specific product on Windows NT 4.0 SP5 and earlier
+
+ else
+ {
+ HKEY hKey;
+ #define BUFSIZE 80
+ wchar_t szProductType[BUFSIZE];
+ DWORD dwBufLen=BUFSIZE;
+ LONG lRet;
+
+ lRet = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
+ 0, KEY_QUERY_VALUE, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ {
+ return 0;
+ }
+
+ lRet = RegQueryValueExW(hKey, L"ProductType", NULL, NULL,
+ (LPBYTE) szProductType, &dwBufLen);
+
+ if ((lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE))
+ {
+ return 0;
+ }
+
+ RegCloseKey(hKey);
+
+ if (lstrcmpiW(L"WINNT", szProductType) == 0)
+ {
+ res += " Workstation";
+ }
+ if (lstrcmpiW(L"LANMANNT", szProductType) == 0)
+ {
+ res += " Server";
+ }
+ if (lstrcmpiW(L"SERVERNT", szProductType) == 0)
+ {
+ res += " Advanced Server";
+ }
+
+ res += " ";
+ sprintf(buffer, "%ld", osvi.dwMajorVersion);
+ res += buffer;
+ res += ".";
+ sprintf(buffer, "%ld", osvi.dwMinorVersion);
+ res += buffer;
+ }
+
+ // Display service pack (if any) and build number.
+
+ if (osvi.dwMajorVersion == 4 &&
+ lstrcmpiA(osvi.szCSDVersion, "Service Pack 6") == 0)
+ {
+ HKEY hKey;
+ LONG lRet;
+
+ // Test for SP6 versus SP6a.
+
+ lRet = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009",
+ 0, KEY_QUERY_VALUE, &hKey);
+
+ if (lRet == ERROR_SUCCESS)
+ {
+ res += " Service Pack 6a (Build ";
+ sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF);
+ res += buffer;
+ res += ")";
+ }
+ else // Windows NT 4.0 prior to SP6a
+ {
+ res += " ";
+ res += osvi.szCSDVersion;
+ res += " (Build ";
+ sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF);
+ res += buffer;
+ res += ")";
+ }
+
+ RegCloseKey(hKey);
+ }
+ else // Windows NT 3.51 and earlier or Windows 2000 and later
+ {
+ res += " ";
+ res += osvi.szCSDVersion;
+ res += " (Build ";
+ sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF);
+ res += buffer;
+ res += ")";
+ }
+
+ break;
+
+ // Test for the Windows 95 product family.
+
+ case VER_PLATFORM_WIN32_WINDOWS:
+
+ if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
+ {
+ res += "Microsoft Windows 95";
+ if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B')
+ {
+ res += " OSR2";
+ }
+ }
+
+ if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
+ {
+ res += "Microsoft Windows 98";
+ if (osvi.szCSDVersion[1] == 'A')
+ {
+ res += " SE";
+ }
+ }
+
+ if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
+ {
+ res += "Microsoft Windows Millennium Edition";
+ }
+ break;
+
+ case VER_PLATFORM_WIN32s:
+
+ res += "Microsoft Win32s";
+ break;
+ }
+#endif
+
+ return res;
+}
+
+// ----------------------------------------------------------------------
+bool SystemTools::ParseURLProtocol( const std::string& URL,
+ std::string& protocol,
+ std::string& dataglom )
+{
+ // match 0 entire url
+ // match 1 protocol
+ // match 2 dataglom following protocol://
+ kwsys::RegularExpression urlRe( VTK_URL_PROTOCOL_REGEX );
+
+ if ( ! urlRe.find( URL ) ) return false;
+
+ protocol = urlRe.match( 1 );
+ dataglom = urlRe.match( 2 );
+
+ return true;
+}
+
+// ----------------------------------------------------------------------
+bool SystemTools::ParseURL( const std::string& URL,
+ std::string& protocol,
+ std::string& username,
+ std::string& password,
+ std::string& hostname,
+ std::string& dataport,
+ std::string& database )
+{
+ kwsys::RegularExpression urlRe( VTK_URL_REGEX );
+ if ( ! urlRe.find( URL ) ) return false;
+
+ // match 0 URL
+ // match 1 protocol
+ // match 2 mangled user
+ // match 3 username
+ // match 4 mangled password
+ // match 5 password
+ // match 6 hostname
+ // match 7 mangled port
+ // match 8 dataport
+ // match 9 database name
+
+ protocol = urlRe.match( 1 );
+ username = urlRe.match( 3 );
+ password = urlRe.match( 5 );
+ hostname = urlRe.match( 6 );
+ dataport = urlRe.match( 8 );
+ database = urlRe.match( 9 );
+
+ return true;
+}
+
+// ----------------------------------------------------------------------
+// These must NOT be initialized. Default initialization to zero is
+// necessary.
+static unsigned int SystemToolsManagerCount;
+SystemToolsTranslationMap *SystemTools::TranslationMap;
+#ifdef _WIN32
+SystemToolsPathCaseMap *SystemTools::PathCaseMap;
+#endif
+#ifdef __CYGWIN__
+SystemToolsTranslationMap *SystemTools::Cyg2Win32Map;
+#endif
+
+// SystemToolsManager manages the SystemTools singleton.
+// SystemToolsManager should be included in any translation unit
+// that will use SystemTools or that implements the singleton
+// pattern. It makes sure that the SystemTools singleton is created
+// before and destroyed after all other singletons in CMake.
+
+SystemToolsManager::SystemToolsManager()
+{
+ if(++SystemToolsManagerCount == 1)
+ {
+ SystemTools::ClassInitialize();
+ }
+}
+
+SystemToolsManager::~SystemToolsManager()
+{
+ if(--SystemToolsManagerCount == 0)
+ {
+ SystemTools::ClassFinalize();
+ }
+}
+
+#if defined(__VMS)
+// On VMS we configure the run time C library to be more UNIX like.
+// http://h71000.www7.hp.com/doc/732final/5763/5763pro_004.html
+extern "C" int decc$feature_get_index(char *name);
+extern "C" int decc$feature_set_value(int index, int mode, int value);
+static int SetVMSFeature(char* name, int value)
+{
+ int i;
+ errno = 0;
+ i = decc$feature_get_index(name);
+ return i >= 0 && (decc$feature_set_value(i, 1, value) >= 0 || errno == 0);
+}
+#endif
+
+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;
+#endif
+#ifdef __CYGWIN__
+ SystemTools::Cyg2Win32Map = new SystemToolsTranslationMap;
+#endif
+
+ // 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__)
+ // The tmp path is frequently a logical path so always keep it:
+ SystemTools::AddKeepPath("/tmp/");
+
+ // If the current working directory is a logical path then keep the
+ // logical name.
+ if(const char* pwd = getenv("PWD"))
+ {
+ char buf[2048];
+ if(const char* cwd = Getcwd(buf, 2048))
+ {
+ // The current working directory may be a logical path. Find
+ // the shortest logical path that still produces the correct
+ // physical path.
+ std::string cwd_changed;
+ std::string pwd_changed;
+
+ // Test progressively shorter logical-to-physical mappings.
+ std::string pwd_str = pwd;
+ std::string cwd_str = cwd;
+ std::string pwd_path;
+ Realpath(pwd, pwd_path);
+ while(cwd_str == pwd_path && cwd_str != pwd_str)
+ {
+ // The current pair of paths is a working logical mapping.
+ cwd_changed = cwd_str;
+ pwd_changed = pwd_str;
+
+ // Strip off one directory level and see if the logical
+ // mapping still works.
+ pwd_str = SystemTools::GetFilenamePath(pwd_str);
+ cwd_str = SystemTools::GetFilenamePath(cwd_str);
+ Realpath(pwd_str.c_str(), pwd_path);
+ }
+
+ // Add the translation to keep the logical path name.
+ if(!cwd_changed.empty() && !pwd_changed.empty())
+ {
+ SystemTools::AddTranslationPath(cwd_changed,
+ pwd_changed);
+ }
+ }
+ }
+#endif
+}
+
+void SystemTools::ClassFinalize()
+{
+ delete SystemTools::TranslationMap;
+#ifdef _WIN32
+ delete SystemTools::PathCaseMap;
+#endif
+#ifdef __CYGWIN__
+ delete SystemTools::Cyg2Win32Map;
+#endif
+}
+
+
+} // namespace KWSYS_NAMESPACE
+
+#if defined(_MSC_VER) && defined(_DEBUG)
+# include <crtdbg.h>
+# include <stdio.h>
+# include <stdlib.h>
+namespace KWSYS_NAMESPACE
+{
+
+static int SystemToolsDebugReport(int, char* message, int*)
+{
+ fprintf(stderr, "%s", message);
+ fflush(stderr);
+ return 1; // no further reporting required
+}
+
+void SystemTools::EnableMSVCDebugHook()
+{
+ if (getenv("DART_TEST_FROM_DART") ||
+ getenv("DASHBOARD_TEST_FROM_CTEST"))
+ {
+ _CrtSetReportHook(SystemToolsDebugReport);
+ }
+}
+
+} // namespace KWSYS_NAMESPACE
+#else
+namespace KWSYS_NAMESPACE
+{
+void SystemTools::EnableMSVCDebugHook() {}
+} // namespace KWSYS_NAMESPACE
+#endif
diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
new file mode 100644
index 0000000..bba5a5c
--- /dev/null
+++ b/Source/kwsys/SystemTools.hxx.in
@@ -0,0 +1,1001 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_SystemTools_hxx
+#define @KWSYS_NAMESPACE@_SystemTools_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+#include <map>
+
+#include <@KWSYS_NAMESPACE@/String.hxx>
+
+#include <sys/types.h>
+#if !defined(_WIN32) || defined(__CYGWIN__)
+# include <unistd.h> // For access permissions for use with access()
+#endif
+
+// Required for va_list
+#include <stdarg.h>
+// Required for FILE*
+#include <stdio.h>
+#if !defined(va_list)
+// Some compilers move va_list into the std namespace and there is no way to
+// tell that this has been done. Playing with things being included before or
+// after stdarg.h does not solve things because we do not have control over
+// what the user does. This hack solves this problem by moving va_list to our
+// own namespace that is local for kwsys.
+namespace std {} // Required for platforms that do not have std namespace
+namespace @KWSYS_NAMESPACE@_VA_LIST
+{
+ using namespace std;
+ typedef va_list hack_va_list;
+}
+namespace @KWSYS_NAMESPACE@
+{
+ typedef @KWSYS_NAMESPACE@_VA_LIST::hack_va_list va_list;
+}
+#endif // va_list
+
+namespace @KWSYS_NAMESPACE@
+{
+
+class SystemToolsTranslationMap;
+class SystemToolsPathCaseMap;
+
+/** \class SystemToolsManager
+ * \brief Use to make sure SystemTools is initialized before it is used
+ * and is the last static object destroyed
+ */
+class @KWSYS_NAMESPACE@_EXPORT SystemToolsManager
+{
+public:
+ SystemToolsManager();
+ ~SystemToolsManager();
+};
+
+// This instance will show up in any translation unit that uses
+// SystemTools. It will make sure SystemTools is initialized
+// before it is used and is the last static object destroyed.
+static SystemToolsManager SystemToolsManagerInstance;
+
+// Flags for use with TestFileAccess. Use a typedef in case any operating
+// system in the future needs a special type. These are flags that may be
+// combined using the | operator.
+typedef int TestFilePermissions;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // On Windows (VC and Borland), no system header defines these constants...
+ static const TestFilePermissions TEST_FILE_OK = 0;
+ static const TestFilePermissions TEST_FILE_READ = 4;
+ static const TestFilePermissions TEST_FILE_WRITE = 2;
+ static const TestFilePermissions TEST_FILE_EXECUTE = 1;
+#else
+ // Standard POSIX constants
+ static const TestFilePermissions TEST_FILE_OK = F_OK;
+ static const TestFilePermissions TEST_FILE_READ = R_OK;
+ static const TestFilePermissions TEST_FILE_WRITE = W_OK;
+ static const TestFilePermissions TEST_FILE_EXECUTE = X_OK;
+#endif
+
+/** \class SystemTools
+ * \brief A collection of useful platform-independent system functions.
+ */
+class @KWSYS_NAMESPACE@_EXPORT SystemTools
+{
+public:
+
+ /** -----------------------------------------------------------------
+ * String Manipulation Routines
+ * -----------------------------------------------------------------
+ */
+
+ /**
+ * Replace symbols in str that are not valid in C identifiers as
+ * defined by the 1999 standard, ie. anything except [A-Za-z0-9_].
+ * They are replaced with `_' and if the first character is a digit
+ * then an underscore is prepended. Note that this can produce
+ * identifiers that the standard reserves (_[A-Z].* and __.*).
+ */
+ static std::string MakeCidentifier(const std::string& s);
+
+ static std::string MakeCindentifier(const std::string& s)
+ {
+ return MakeCidentifier(s);
+ }
+
+ /**
+ * Replace replace all occurences of the string in the source string.
+ */
+ static void ReplaceString(std::string& source,
+ const char* replace,
+ const char* with);
+ static void ReplaceString(std::string& source,
+ const std::string& replace,
+ const std::string& with);
+
+ /**
+ * Return a capitalized string (i.e the first letter is uppercased,
+ * all other are lowercased).
+ */
+ static std::string Capitalized(const std::string&);
+
+ /**
+ * Return a 'capitalized words' string (i.e the first letter of each word
+ * is uppercased all other are left untouched though).
+ */
+ static std::string CapitalizedWords(const std::string&);
+
+ /**
+ * Return a 'uncapitalized words' string (i.e the first letter of each word
+ * is lowercased all other are left untouched though).
+ */
+ static std::string UnCapitalizedWords(const std::string&);
+
+ /**
+ * Return a lower case string
+ */
+ static std::string LowerCase(const std::string&);
+
+ /**
+ * Return a lower case string
+ */
+ static std::string UpperCase(const std::string&);
+
+ /**
+ * Count char in string
+ */
+ static size_t CountChar(const char* str, char c);
+
+ /**
+ * Remove some characters from a string.
+ * Return a pointer to the new resulting string (allocated with 'new')
+ */
+ static char* RemoveChars(const char* str, const char *toremove);
+
+ /**
+ * Remove remove all but 0->9, A->F characters from a string.
+ * Return a pointer to the new resulting string (allocated with 'new')
+ */
+ static char* RemoveCharsButUpperHex(const char* str);
+
+ /**
+ * Replace some characters by another character in a string (in-place)
+ * Return a pointer to string
+ */
+ static char* ReplaceChars(char* str, const char *toreplace,char replacement);
+
+ /**
+ * Returns true if str1 starts (respectively ends) with str2
+ */
+ static bool StringStartsWith(const char* str1, const char* str2);
+ static bool StringStartsWith(const std::string& str1, const char* str2);
+ static bool StringEndsWith(const char* str1, const char* str2);
+ static bool StringEndsWith(const std::string& str1, const char* str2);
+
+ /**
+ * Returns a pointer to the last occurence of str2 in str1
+ */
+ static const char* FindLastString(const char* str1, const char* str2);
+
+ /**
+ * Make a duplicate of the string similar to the strdup C function
+ * but use new to create the 'new' string, so one can use
+ * 'delete' to remove it. Returns 0 if the input is empty.
+ */
+ static char* DuplicateString(const char* str);
+
+ /**
+ * Return the string cropped to a given length by removing chars in the
+ * center of the string and replacing them with an ellipsis (...)
+ */
+ static std::string CropString(const std::string&,size_t max_len);
+
+ /** split a path by separator into an array of strings, default is /.
+ If isPath is true then the string is treated like a path and if
+ s starts with a / then the first element of the returned array will
+ be /, so /foo/bar will be [/, foo, bar]
+ */
+ static std::vector<String> SplitString(const std::string& s, char separator = '/',
+ bool isPath = false);
+ /**
+ * Perform a case-independent string comparison
+ */
+ static int Strucmp(const char *s1, const char *s2);
+
+ /**
+ * Convert a string in __DATE__ or __TIMESTAMP__ format into a time_t.
+ * Return false on error, true on success
+ */
+ static bool ConvertDateMacroString(const char *str, time_t *tmt);
+ static bool ConvertTimeStampMacroString(const char *str, time_t *tmt);
+
+ /**
+ * Split a string on its newlines into multiple lines
+ * Return false only if the last line stored had no newline
+ */
+ static bool Split(const std::string& s, std::vector<std::string>& l);
+ static bool Split(const std::string& s, std::vector<std::string>& l, char separator);
+
+ /**
+ * Return string with space added between capitalized words
+ * (i.e. EatMyShorts becomes Eat My Shorts )
+ * (note that IEatShorts becomes IEat Shorts)
+ */
+ static std::string AddSpaceBetweenCapitalizedWords(
+ const std::string&);
+
+ /**
+ * Append two or more strings and produce new one.
+ * Programmer must 'delete []' the resulting string, which was allocated
+ * with 'new'.
+ * Return 0 if inputs are empty or there was an error
+ */
+ static char* AppendStrings(
+ const char* str1, const char* str2);
+ static char* AppendStrings(
+ const char* str1, const char* str2, const char* str3);
+
+ /**
+ * Estimate the length of the string that will be produced
+ * from printing the given format string and arguments. The
+ * returned length will always be at least as large as the string
+ * that will result from printing.
+ * WARNING: since va_arg is called to iterate of the argument list,
+ * you will not be able to use this 'ap' anymore from the beginning.
+ * It's up to you to call va_end though.
+ */
+ static int EstimateFormatLength(const char *format, va_list ap);
+
+ /**
+ * Escape specific characters in 'str'.
+ */
+ static std::string EscapeChars(
+ const char *str, const char *chars_to_escape, char escape_char = '\\');
+
+ /** -----------------------------------------------------------------
+ * Filename Manipulation Routines
+ * -----------------------------------------------------------------
+ */
+
+ /**
+ * Replace Windows file system slashes with Unix-style slashes.
+ */
+ static void ConvertToUnixSlashes(std::string& path);
+
+#ifdef _WIN32
+ /**
+ * Convert the path to an extended length path to avoid MAX_PATH length
+ * limitations on Windows. If the input is a local path the result will be
+ * prefixed with \\?\; if the input is instead a network path, the result
+ * will be prefixed with \\?\UNC\. All output will also be converted to
+ * absolute paths with Windows-style backslashes.
+ **/
+ static std::wstring ConvertToWindowsExtendedPath(const std::string&);
+#endif
+
+ /**
+ * For windows this calls ConvertToWindowsOutputPath and for unix
+ * it calls ConvertToUnixOutputPath
+ */
+ static std::string ConvertToOutputPath(const std::string&);
+
+ /**
+ * Convert the path to a string that can be used in a unix makefile.
+ * double slashes are removed, and spaces are escaped.
+ */
+ static std::string ConvertToUnixOutputPath(const std::string&);
+
+ /**
+ * Convert the path to string that can be used in a windows project or
+ * makefile. Double slashes are removed if they are not at the start of
+ * the string, the slashes are converted to windows style backslashes, and
+ * if there are spaces in the string it is double quoted.
+ */
+ static std::string ConvertToWindowsOutputPath(const std::string&);
+
+ /**
+ * Return true if a file exists in the current directory.
+ * If isFile = true, then make sure the file is a file and
+ * not a directory. If isFile = false, then return true
+ * if it is a file or a directory. Note that the file will
+ * also be checked for read access. (Currently, this check
+ * for read access is only done on POSIX systems.)
+ */
+ static bool FileExists(const char* filename, bool isFile);
+ static bool FileExists(const std::string& filename, bool isFile);
+ static bool FileExists(const char* filename);
+ static bool FileExists(const std::string& filename);
+
+ /**
+ * Test if a file exists and can be accessed with the requested
+ * permissions. Symbolic links are followed. Returns true if
+ * the access test was successful.
+ *
+ * On POSIX systems (including Cygwin), this maps to the access
+ * function. On Windows systems, all existing files are
+ * considered readable, and writable files are considered to
+ * have the read-only file attribute cleared.
+ */
+ static bool TestFileAccess(const char* filename,
+ TestFilePermissions permissions);
+ static bool TestFileAccess(const std::string& filename,
+ TestFilePermissions permissions);
+
+ /**
+ * Converts Cygwin path to Win32 path. Uses dictionary container for
+ * caching and calls to cygwin_conv_to_win32_path from Cygwin dll
+ * for actual translation. Returns true on success, else false.
+ */
+#ifdef __CYGWIN__
+ static bool PathCygwinToWin32(const char *path, char *win32_path);
+#endif
+
+ /**
+ * Return file length
+ */
+ static unsigned long FileLength(const std::string& filename);
+
+ /**
+ Change the modification time or create a file
+ */
+ static bool Touch(const std::string& filename, bool create);
+
+ /**
+ * 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.
+ */
+ static bool FileTimeCompare(const std::string& f1,
+ const std::string& f2,
+ int* result);
+
+ /**
+ * Get the file extension (including ".") needed for an executable
+ * on the current platform ("" for unix, ".exe" for Windows).
+ */
+ static const char* GetExecutableExtension();
+
+ /**
+ * Given a path that exists on a windows machine, return the
+ * actuall case of the path as it was created. If the file
+ * does not exist path is returned unchanged. This does nothing
+ * on unix but return path.
+ */
+ static std::string GetActualCaseForPath(const std::string& path);
+
+ /**
+ * Given the path to a program executable, get the directory part of
+ * the path with the file stripped off. If there is no directory
+ * part, the empty string is returned.
+ */
+ static std::string GetProgramPath(const std::string&);
+ static bool SplitProgramPath(const std::string& in_name,
+ std::string& dir,
+ std::string& file,
+ bool errorReport = true);
+
+ /**
+ * Given argv[0] for a unix program find the full path to a running
+ * executable. argv0 can be null for windows WinMain programs
+ * in this case GetModuleFileName will be used to find the path
+ * to the running executable. If argv0 is not a full path,
+ * then this will try to find the full path. If the path is not
+ * found false is returned, if found true is returned. An error
+ * message of the attempted paths is stored in errorMsg.
+ * exeName is the name of the executable.
+ * buildDir is a possibly null path to the build directory.
+ * installPrefix is a possibly null pointer to the install directory.
+ */
+ static bool FindProgramPath(const char* argv0,
+ std::string& pathOut,
+ std::string& errorMsg,
+ const char* exeName = 0,
+ const char* buildDir = 0,
+ const char* installPrefix = 0);
+
+ /**
+ * Given a path to a file or directory, convert it to a full path.
+ * This collapses away relative paths relative to the cwd argument
+ * (which defaults to the current working directory). The full path
+ * is returned.
+ */
+ static std::string CollapseFullPath(const std::string& in_relative);
+ static std::string CollapseFullPath(const std::string& in_relative,
+ const char* in_base);
+ static std::string CollapseFullPath(const std::string& in_relative,
+ const std::string& in_base);
+
+ /**
+ * Get the real path for a given path, removing all symlinks. In
+ * the event of an error (non-existent path, permissions issue,
+ * etc.) the original path is returned if errorMessage pointer is
+ * NULL. Otherwise empty string is returned and errorMessage
+ * contains error description.
+ */
+ static std::string GetRealPath(const std::string& path,
+ std::string* errorMessage = 0);
+
+ /**
+ * Split a path name into its root component and the rest of the
+ * path. The root component is one of the following:
+ * "/" = UNIX full path
+ * "c:/" = Windows full path (can be any drive letter)
+ * "c:" = Windows drive-letter relative path (can be any drive letter)
+ * "//" = Network path
+ * "~/" = Home path for current user
+ * "~u/" = Home path for user 'u'
+ * "" = Relative path
+ *
+ * A pointer to the rest of the path after the root component is
+ * returned. The root component is stored in the "root" string if
+ * given.
+ */
+ static const char* SplitPathRootComponent(const std::string& p,
+ std::string* root=0);
+
+ /**
+ * Split a path name into its basic components. The first component
+ * always exists and is the root returned by SplitPathRootComponent.
+ * The remaining components form the path. If there is a trailing
+ * slash then the last component is the empty string. The
+ * components can be recombined as "c[0]c[1]/c[2]/.../c[n]" to
+ * produce the original path. Home directory references are
+ * automatically expanded if expand_home_dir is true and this
+ * platform supports them.
+ */
+ static void SplitPath(const std::string& p,
+ std::vector<std::string>& components,
+ bool expand_home_dir = true);
+
+ /**
+ * Join components of a path name into a single string. See
+ * SplitPath for the format of the components.
+ */
+ static std::string JoinPath(
+ const std::vector<std::string>& components);
+ static std::string JoinPath(
+ std::vector<std::string>::const_iterator first,
+ std::vector<std::string>::const_iterator last);
+
+ /**
+ * Compare a path or components of a path.
+ */
+ static bool ComparePath(const std::string& c1, const std::string& c2);
+
+
+ /**
+ * Return path of a full filename (no trailing slashes)
+ */
+ static std::string GetFilenamePath(const std::string&);
+
+ /**
+ * Return file name of a full filename (i.e. file name without path)
+ */
+ static std::string GetFilenameName(const std::string&);
+
+ /**
+ * Split a program from its arguments and handle spaces in the paths
+ */
+ static void SplitProgramFromArgs(
+ const std::string& path,
+ std::string& program, std::string& args);
+
+ /**
+ * Return longest file extension of a full filename (dot included)
+ */
+ static std::string GetFilenameExtension(const std::string&);
+
+ /**
+ * Return shortest file extension of a full filename (dot included)
+ */
+ static std::string GetFilenameLastExtension(
+ const std::string& filename);
+
+ /**
+ * Return file name without extension of a full filename
+ */
+ static std::string GetFilenameWithoutExtension(
+ const std::string&);
+
+ /**
+ * Return file name without its last (shortest) extension
+ */
+ static std::string GetFilenameWithoutLastExtension(
+ const std::string&);
+
+ /**
+ * Return whether the path represents a full path (not relative)
+ */
+ static bool FileIsFullPath(const std::string&);
+ static bool FileIsFullPath(const char*);
+
+ /**
+ * For windows return the short path for the given path,
+ * Unix just a pass through
+ */
+ static bool GetShortPath(const std::string& path, std::string& result);
+
+ /**
+ * Read line from file. Make sure to get everything. Due to a buggy stream
+ * library on the HP and another on Mac OS X, we need this very carefully
+ * written version of getline. Returns true if any data were read before the
+ * end-of-file was reached. If the has_newline argument is specified, it will
+ * be true when the line read had a newline character.
+ */
+ static bool GetLineFromStream(std::istream& istr,
+ std::string& line,
+ bool* has_newline=0,
+ long sizeLimit=-1);
+
+ /**
+ * Get the parent directory of the directory or file
+ */
+ static std::string GetParentDirectory(const std::string& fileOrDir);
+
+ /**
+ * Check if the given file or directory is in subdirectory of dir
+ */
+ static bool IsSubDirectory(const std::string& fileOrDir, const std::string& dir);
+
+ /** -----------------------------------------------------------------
+ * File Manipulation Routines
+ * -----------------------------------------------------------------
+ */
+
+ /**
+ * Open a file considering unicode.
+ */
+ static FILE* Fopen(const std::string& file, const char* mode);
+
+ /**
+ * Make a new directory if it is not there. This function
+ * can make a full path even if none of the directories existed
+ * prior to calling this function.
+ */
+ static bool MakeDirectory(const char* path);
+ static bool MakeDirectory(const std::string& path);
+
+ /**
+ * Copy the source file to the destination file only
+ * if the two files differ.
+ */
+ static bool CopyFileIfDifferent(const std::string& source,
+ const std::string& destination);
+
+ /**
+ * Compare the contents of two files. Return true if different
+ */
+ static bool FilesDiffer(const std::string& source, const std::string& destination);
+
+ /**
+ * Return true if the two files are the same file
+ */
+ static bool SameFile(const std::string& file1, const std::string& file2);
+
+ /**
+ * Copy a file.
+ */
+ static bool CopyFileAlways(const std::string& source, const std::string& destination);
+
+ /**
+ * Copy a file. If the "always" argument is true the file is always
+ * copied. If it is false, the file is copied only if it is new or
+ * has changed.
+ */
+ static bool CopyAFile(const std::string& source, const std::string& destination,
+ bool always = true);
+
+ /**
+ * Copy content directory to another directory with all files and
+ * subdirectories. If the "always" argument is true all files are
+ * always copied. If it is false, only files that have changed or
+ * are new are copied.
+ */
+ static bool CopyADirectory(const std::string& source, const std::string& destination,
+ bool always = true);
+
+ /**
+ * Remove a file
+ */
+ static bool RemoveFile(const std::string& source);
+
+ /**
+ * Remove a directory
+ */
+ static bool RemoveADirectory(const std::string& source);
+
+ /**
+ * Get the maximum full file path length
+ */
+ static size_t GetMaximumFilePathLength();
+
+ /**
+ * Find a file in the system PATH, with optional extra paths
+ */
+ static std::string FindFile(
+ const std::string& name,
+ const std::vector<std::string>& path =
+ std::vector<std::string>(),
+ bool no_system_path = false);
+
+ /**
+ * Find a directory in the system PATH, with optional extra paths
+ */
+ static std::string FindDirectory(
+ const std::string& name,
+ const std::vector<std::string>& path =
+ std::vector<std::string>(),
+ bool no_system_path = false);
+
+ /**
+ * Find an executable in the system PATH, with optional extra paths
+ */
+ static std::string FindProgram(
+ const char* name,
+ const std::vector<std::string>& path =
+ std::vector<std::string>(),
+ bool no_system_path = false);
+ static std::string FindProgram(
+ const std::string& name,
+ const std::vector<std::string>& path =
+ std::vector<std::string>(),
+ bool no_system_path = false);
+ static std::string FindProgram(
+ const std::vector<std::string>& names,
+ const std::vector<std::string>& path =
+ std::vector<std::string>(),
+ bool no_system_path = false);
+
+ /**
+ * Find a library in the system PATH, with optional extra paths
+ */
+ static std::string FindLibrary(
+ const std::string& name,
+ const std::vector<std::string>& path);
+
+ /**
+ * Return true if the file is a directory
+ */
+ static bool FileIsDirectory(const std::string& name);
+
+ /**
+ * Return true if the file is a symlink
+ */
+ static bool FileIsSymlink(const std::string& name);
+
+ /**
+ * Return true if the file has a given signature (first set of bytes)
+ */
+ static bool FileHasSignature(
+ const char* filename, const char *signature, long offset = 0);
+
+ /**
+ * Attempt to detect and return the type of a file.
+ * Up to 'length' bytes are read from the file, if more than 'percent_bin' %
+ * of the bytes are non-textual elements, the file is considered binary,
+ * otherwise textual. Textual elements are bytes in the ASCII [0x20, 0x7E]
+ * range, but also \\n, \\r, \\t.
+ * The algorithm is simplistic, and should probably check for usual file
+ * extensions, 'magic' signature, unicode, etc.
+ */
+ enum FileTypeEnum
+ {
+ FileTypeUnknown,
+ FileTypeBinary,
+ FileTypeText
+ };
+ static SystemTools::FileTypeEnum DetectFileType(
+ const char* filename,
+ unsigned long length = 256,
+ double percent_bin = 0.05);
+
+ /**
+ * Create a symbolic link if the platform supports it. Returns whether
+ * creation succeeded.
+ */
+ static bool CreateSymlink(const std::string& origName, const std::string& newName);
+
+ /**
+ * Read the contents of a symbolic link. Returns whether reading
+ * succeeded.
+ */
+ static bool ReadSymlink(const std::string& newName, std::string& origName);
+
+ /**
+ * Try to locate the file 'filename' in the directory 'dir'.
+ * If 'filename' is a fully qualified filename, the basename of the file is
+ * used to check for its existence in 'dir'.
+ * If 'dir' is not a directory, GetFilenamePath() is called on 'dir' to
+ * get its directory first (thus, you can pass a filename as 'dir', as
+ * a convenience).
+ * 'filename_found' is assigned the fully qualified name/path of the file
+ * if it is found (not touched otherwise).
+ * If 'try_filename_dirs' is true, try to find the file using the
+ * components of its path, i.e. if we are looking for c:/foo/bar/bill.txt,
+ * first look for bill.txt in 'dir', then in 'dir'/bar, then in 'dir'/foo/bar
+ * etc.
+ * Return true if the file was found, false otherwise.
+ */
+ static bool LocateFileInDir(const char *filename,
+ const char *dir,
+ std::string& filename_found,
+ int try_filename_dirs = 0);
+
+ /** compute the relative path from local to remote. local must
+ be a directory. remote can be a file or a directory.
+ Both remote and local must be full paths. Basically, if
+ you are in directory local and you want to access the file in remote
+ what is the relative path to do that. For example:
+ /a/b/c/d to /a/b/c1/d1 -> ../../c1/d1
+ from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp
+ */
+ static std::string RelativePath(const std::string& local, const std::string& remote);
+
+ /**
+ * Return file's modified time
+ */
+ static long int ModifiedTime(const std::string& filename);
+
+ /**
+ * Return file's creation time (Win32: works only for NTFS, not FAT)
+ */
+ static long int CreationTime(const std::string& filename);
+
+ /**
+ * Visual C++ does not define mode_t (note that Borland does, however).
+ */
+ #if defined( _MSC_VER )
+ typedef unsigned short mode_t;
+ #endif
+
+ /**
+ * Get and set permissions of the file. If honor_umask is set, the umask
+ * is queried and applied to the given permissions. Returns false if
+ * failure.
+ *
+ * WARNING: A non-thread-safe method is currently used to get the umask
+ * if a honor_umask parameter is set to true.
+ */
+ static bool GetPermissions(const char* file, mode_t& mode);
+ static bool GetPermissions(const std::string& file, mode_t& mode);
+ static bool SetPermissions(const char* file, mode_t mode, bool honor_umask = false);
+ static bool SetPermissions(const std::string& file, mode_t mode, bool honor_umask = false);
+
+ /** -----------------------------------------------------------------
+ * Time Manipulation Routines
+ * -----------------------------------------------------------------
+ */
+
+ /** Get current time in seconds since Posix Epoch (Jan 1, 1970). */
+ static double GetTime();
+
+ /**
+ * Get current date/time
+ */
+ static std::string GetCurrentDateTime(const char* format);
+
+ /** -----------------------------------------------------------------
+ * Registry Manipulation Routines
+ * -----------------------------------------------------------------
+ */
+
+ /**
+ * Specify access to the 32-bit or 64-bit application view of
+ * registry values. The default is to match the currently running
+ * binary type.
+ */
+ enum KeyWOW64 { KeyWOW64_Default, KeyWOW64_32, KeyWOW64_64 };
+
+ /**
+ * Get a list of subkeys.
+ */
+ static bool GetRegistrySubKeys(const std::string& key,
+ std::vector<std::string>& subkeys,
+ KeyWOW64 view = KeyWOW64_Default);
+
+ /**
+ * Read a registry value
+ */
+ static bool ReadRegistryValue(const std::string& key, std::string &value,
+ KeyWOW64 view = KeyWOW64_Default);
+
+ /**
+ * Write a registry value
+ */
+ static bool WriteRegistryValue(const std::string& key, const std::string& value,
+ KeyWOW64 view = KeyWOW64_Default);
+
+ /**
+ * Delete a registry value
+ */
+ static bool DeleteRegistryValue(const std::string& key,
+ KeyWOW64 view = KeyWOW64_Default);
+
+ /** -----------------------------------------------------------------
+ * Environment Manipulation Routines
+ * -----------------------------------------------------------------
+ */
+
+ /**
+ * Add the paths from the environment variable PATH to the
+ * string vector passed in. If env is set then the value
+ * of env will be used instead of PATH.
+ */
+ static void GetPath(std::vector<std::string>& path,
+ const char* env=0);
+
+ /**
+ * Read an environment variable
+ */
+ static const char* GetEnv(const char* key);
+ static const char* GetEnv(const std::string& key);
+ static bool GetEnv(const char* key, std::string& result);
+ static bool GetEnv(const std::string& key, std::string& result);
+
+ /** Put a string into the environment
+ of the form var=value */
+ static bool PutEnv(const std::string& env);
+
+ /** Remove a string from the environment.
+ Input is of the form "var" or "var=value" (value is ignored). */
+ static bool UnPutEnv(const std::string& env);
+
+ /**
+ * Get current working directory CWD
+ */
+ static std::string GetCurrentWorkingDirectory(bool collapse =true);
+
+ /**
+ * Change directory to the directory specified
+ */
+ static int ChangeDirectory(const std::string& dir);
+
+ /**
+ * Get the result of strerror(errno)
+ */
+ static std::string GetLastSystemError();
+
+ /**
+ * When building DEBUG with MSVC, this enables a hook that prevents
+ * error dialogs from popping up if the program is being run from
+ * DART.
+ */
+ static void EnableMSVCDebugHook();
+
+ /**
+ * Get the width of the terminal window. The code may or may not work, so
+ * make sure you have some resonable defaults prepared if the code returns
+ * some bogus size.
+ */
+ static int GetTerminalWidth();
+
+ /**
+ * Add an entry in the path translation table.
+ */
+ static void AddTranslationPath(const std::string& dir, const std::string& refdir);
+
+ /**
+ * If dir is different after CollapseFullPath is called,
+ * Then insert it into the path translation table
+ */
+ static void AddKeepPath(const std::string& dir);
+
+ /**
+ * Update path by going through the Path Translation table;
+ */
+ static void CheckTranslationPath(std::string & path);
+
+ /**
+ * Delay the execution for a specified amount of time specified
+ * in miliseconds
+ */
+ static void Delay(unsigned int msec);
+
+ /**
+ * Get the operating system name and version
+ * This is implemented for Win32 only for the moment
+ */
+ static std::string GetOperatingSystemNameAndVersion();
+
+ /** -----------------------------------------------------------------
+ * URL Manipulation Routines
+ * -----------------------------------------------------------------
+ */
+
+ /**
+ * Parse a character string :
+ * protocol://dataglom
+ * and fill protocol as appropriate.
+ * Return false if the URL does not have the required form, true otherwise.
+ */
+ static bool ParseURLProtocol( const std::string& URL,
+ std::string& protocol,
+ std::string& dataglom );
+
+ /**
+ * Parse a string (a URL without protocol prefix) with the form:
+ * protocol://[[username[':'password]'@']hostname[':'dataport]]'/'[datapath]
+ * and fill protocol, username, password, hostname, dataport, and datapath
+ * when values are found.
+ * Return true if the string matches the format; false otherwise.
+ */
+ static bool ParseURL( const std::string& URL,
+ std::string& protocol,
+ std::string& username,
+ std::string& password,
+ std::string& hostname,
+ std::string& dataport,
+ std::string& datapath );
+
+private:
+ /**
+ * Allocate the stl map that serve as the Path Translation table.
+ */
+ static void ClassInitialize();
+
+ /**
+ * Deallocate the stl map that serve as the Path Translation table.
+ */
+ static void ClassFinalize();
+
+ /**
+ * This method prevents warning on SGI
+ */
+ SystemToolsManager* GetSystemToolsManager()
+ {
+ 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);
+
+
+ /**
+ * 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 SystemToolsPathCaseMap *PathCaseMap;
+#endif
+#ifdef __CYGWIN__
+ static SystemToolsTranslationMap *Cyg2Win32Map;
+#endif
+ friend class SystemToolsManager;
+};
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/Source/kwsys/Terminal.c b/Source/kwsys/Terminal.c
new file mode 100644
index 0000000..a8abb6c
--- /dev/null
+++ b/Source/kwsys/Terminal.c
@@ -0,0 +1,445 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Terminal.h)
+
+/* Work-around CMake dependency scanning limitation. This must
+ duplicate the above list of headers. */
+#if 0
+# include "Terminal.h.in"
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Configure support for this platform. */
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define KWSYS_TERMINAL_SUPPORT_CONSOLE
+#endif
+#if !defined(_WIN32)
+# define KWSYS_TERMINAL_ISATTY_WORKS
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Include needed system APIs. */
+
+#include <stdlib.h> /* getenv */
+#include <string.h> /* strcmp */
+#include <stdarg.h> /* va_list */
+
+#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
+# include <windows.h> /* SetConsoleTextAttribute */
+# include <io.h> /* _get_osfhandle */
+#endif
+
+#if defined(KWSYS_TERMINAL_ISATTY_WORKS)
+# include <unistd.h> /* isatty */
+#else
+# include <sys/stat.h> /* fstat */
+#endif
+
+/*--------------------------------------------------------------------------*/
+static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100,
+ int default_tty);
+static void kwsysTerminalSetVT100Color(FILE* stream, int color);
+#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
+static HANDLE kwsysTerminalGetStreamHandle(FILE* stream);
+static void kwsysTerminalSetConsoleColor(HANDLE hOut,
+ CONSOLE_SCREEN_BUFFER_INFO* hOutInfo,
+ FILE* stream,
+ int color);
+#endif
+
+/*--------------------------------------------------------------------------*/
+void kwsysTerminal_cfprintf(int color, FILE* stream, const char* format, ...)
+{
+ /* Setup the stream with the given color if possible. */
+ int pipeIsConsole = 0;
+ int pipeIsVT100 = 0;
+ int default_vt100 = color & kwsysTerminal_Color_AssumeVT100;
+ int default_tty = color & kwsysTerminal_Color_AssumeTTY;
+#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
+ CONSOLE_SCREEN_BUFFER_INFO hOutInfo;
+ HANDLE hOut = kwsysTerminalGetStreamHandle(stream);
+ if(GetConsoleScreenBufferInfo(hOut, &hOutInfo))
+ {
+ pipeIsConsole = 1;
+ kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream, color);
+ }
+#endif
+ if(!pipeIsConsole && kwsysTerminalStreamIsVT100(stream,
+ default_vt100, default_tty))
+ {
+ pipeIsVT100 = 1;
+ kwsysTerminalSetVT100Color(stream, color);
+ }
+
+ /* Format the text into the stream. */
+ {
+ va_list var_args;
+ va_start(var_args, format);
+ vfprintf(stream, format, var_args);
+ va_end(var_args);
+ }
+
+ /* Restore the normal color state for the stream. */
+#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
+ if(pipeIsConsole)
+ {
+ kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream,
+ kwsysTerminal_Color_Normal);
+ }
+#endif
+ if(pipeIsVT100)
+ {
+ kwsysTerminalSetVT100Color(stream, kwsysTerminal_Color_Normal);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Detect cases when a stream is definitely not interactive. */
+#if !defined(KWSYS_TERMINAL_ISATTY_WORKS)
+static int kwsysTerminalStreamIsNotInteractive(FILE* stream)
+{
+ /* The given stream is definitely not interactive if it is a regular
+ file. */
+ struct stat stream_stat;
+ if(fstat(fileno(stream), &stream_stat) == 0)
+ {
+ if(stream_stat.st_mode & S_IFREG)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* List of terminal names known to support VT100 color escape sequences. */
+static const char* kwsysTerminalVT100Names[] =
+{
+ "Eterm",
+ "ansi",
+ "color-xterm",
+ "con132x25",
+ "con132x30",
+ "con132x43",
+ "con132x60",
+ "con80x25",
+ "con80x28",
+ "con80x30",
+ "con80x43",
+ "con80x50",
+ "con80x60",
+ "cons25",
+ "console",
+ "cygwin",
+ "dtterm",
+ "eterm-color",
+ "gnome",
+ "gnome-256color",
+ "konsole",
+ "konsole-256color",
+ "kterm",
+ "linux",
+ "msys",
+ "linux-c",
+ "mach-color",
+ "mlterm",
+ "putty",
+ "putty-256color",
+ "rxvt",
+ "rxvt-256color",
+ "rxvt-cygwin",
+ "rxvt-cygwin-native",
+ "rxvt-unicode",
+ "rxvt-unicode-256color",
+ "screen",
+ "screen-256color",
+ "screen-256color-bce",
+ "screen-bce",
+ "screen-w",
+ "screen.linux",
+ "vt100",
+ "xterm",
+ "xterm-16color",
+ "xterm-256color",
+ "xterm-88color",
+ "xterm-color",
+ "xterm-debian",
+ "xterm-termite",
+ 0
+};
+
+/*--------------------------------------------------------------------------*/
+/* Detect whether a stream is displayed in a VT100-compatible terminal. */
+static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100,
+ int default_tty)
+{
+ /* Force color according to http://bixense.com/clicolors/ convention. */
+ {
+ const char* clicolor_force = getenv("CLICOLOR_FORCE");
+ if (clicolor_force && *clicolor_force && strcmp(clicolor_force, "0") != 0)
+ {
+ return 1;
+ }
+ }
+
+ /* If running inside emacs the terminal is not VT100. Some emacs
+ seem to claim the TERM is xterm even though they do not support
+ VT100 escapes. */
+ {
+ const char* emacs = getenv("EMACS");
+ if(emacs && *emacs == 't')
+ {
+ return 0;
+ }
+ }
+
+ /* Check for a valid terminal. */
+ if(!default_vt100)
+ {
+ const char** t = 0;
+ const char* term = getenv("TERM");
+ if(term)
+ {
+ for(t = kwsysTerminalVT100Names; *t && strcmp(term, *t) != 0; ++t) {}
+ }
+ if(!(t && *t))
+ {
+ return 0;
+ }
+ }
+
+#if defined(KWSYS_TERMINAL_ISATTY_WORKS)
+ /* Make sure the stream is a tty. */
+ (void)default_tty;
+ return isatty(fileno(stream))? 1:0;
+#else
+ /* Check for cases in which the stream is definitely not a tty. */
+ if(kwsysTerminalStreamIsNotInteractive(stream))
+ {
+ return 0;
+ }
+
+ /* Use the provided default for whether this is a tty. */
+ return default_tty;
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+/* VT100 escape sequence strings. */
+#define KWSYS_TERMINAL_VT100_NORMAL "\33[0m"
+#define KWSYS_TERMINAL_VT100_BOLD "\33[1m"
+#define KWSYS_TERMINAL_VT100_UNDERLINE "\33[4m"
+#define KWSYS_TERMINAL_VT100_BLINK "\33[5m"
+#define KWSYS_TERMINAL_VT100_INVERSE "\33[7m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_BLACK "\33[30m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_RED "\33[31m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_GREEN "\33[32m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_YELLOW "\33[33m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_BLUE "\33[34m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_MAGENTA "\33[35m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_CYAN "\33[36m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_WHITE "\33[37m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_BLACK "\33[40m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_RED "\33[41m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_GREEN "\33[42m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_YELLOW "\33[43m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_BLUE "\33[44m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_MAGENTA "\33[45m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_CYAN "\33[46m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_WHITE "\33[47m"
+
+/*--------------------------------------------------------------------------*/
+/* Write VT100 escape sequences to the stream for the given color. */
+static void kwsysTerminalSetVT100Color(FILE* stream, int color)
+{
+ if(color == kwsysTerminal_Color_Normal)
+ {
+ fprintf(stream, KWSYS_TERMINAL_VT100_NORMAL);
+ return;
+ }
+
+ switch(color & kwsysTerminal_Color_ForegroundMask)
+ {
+ case kwsysTerminal_Color_Normal:
+ fprintf(stream, KWSYS_TERMINAL_VT100_NORMAL);
+ break;
+ case kwsysTerminal_Color_ForegroundBlack:
+ fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_BLACK);
+ break;
+ case kwsysTerminal_Color_ForegroundRed:
+ fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_RED);
+ break;
+ case kwsysTerminal_Color_ForegroundGreen:
+ fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_GREEN);
+ break;
+ case kwsysTerminal_Color_ForegroundYellow:
+ fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_YELLOW);
+ break;
+ case kwsysTerminal_Color_ForegroundBlue:
+ fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_BLUE);
+ break;
+ case kwsysTerminal_Color_ForegroundMagenta:
+ fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_MAGENTA);
+ break;
+ case kwsysTerminal_Color_ForegroundCyan:
+ fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_CYAN);
+ break;
+ case kwsysTerminal_Color_ForegroundWhite:
+ fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_WHITE);
+ break;
+ }
+ switch(color & kwsysTerminal_Color_BackgroundMask)
+ {
+ case kwsysTerminal_Color_BackgroundBlack:
+ fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_BLACK);
+ break;
+ case kwsysTerminal_Color_BackgroundRed:
+ fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_RED);
+ break;
+ case kwsysTerminal_Color_BackgroundGreen:
+ fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_GREEN);
+ break;
+ case kwsysTerminal_Color_BackgroundYellow:
+ fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_YELLOW);
+ break;
+ case kwsysTerminal_Color_BackgroundBlue:
+ fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_BLUE);
+ break;
+ case kwsysTerminal_Color_BackgroundMagenta:
+ fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_MAGENTA);
+ break;
+ case kwsysTerminal_Color_BackgroundCyan:
+ fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_CYAN);
+ break;
+ case kwsysTerminal_Color_BackgroundWhite:
+ fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_WHITE);
+ break;
+ }
+ if(color & kwsysTerminal_Color_ForegroundBold)
+ {
+ fprintf(stream, KWSYS_TERMINAL_VT100_BOLD);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
+
+# define KWSYS_TERMINAL_MASK_FOREGROUND \
+ (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY)
+# define KWSYS_TERMINAL_MASK_BACKGROUND \
+ (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
+
+/* Get the Windows handle for a FILE stream. */
+static HANDLE kwsysTerminalGetStreamHandle(FILE* stream)
+{
+ /* Get the C-library file descriptor from the stream. */
+ int fd = fileno(stream);
+
+# if defined(__CYGWIN__)
+ /* Cygwin seems to have an extra pipe level. If the file descriptor
+ corresponds to stdout or stderr then obtain the matching windows
+ handle directly. */
+ if(fd == fileno(stdout))
+ {
+ return GetStdHandle(STD_OUTPUT_HANDLE);
+ }
+ else if(fd == fileno(stderr))
+ {
+ return GetStdHandle(STD_ERROR_HANDLE);
+ }
+# endif
+
+ /* Get the underlying Windows handle for the descriptor. */
+ return (HANDLE)_get_osfhandle(fd);
+}
+
+/* Set color attributes in a Windows console. */
+static void kwsysTerminalSetConsoleColor(HANDLE hOut,
+ CONSOLE_SCREEN_BUFFER_INFO* hOutInfo,
+ FILE* stream,
+ int color)
+{
+ WORD attributes = 0;
+ switch(color & kwsysTerminal_Color_ForegroundMask)
+ {
+ case kwsysTerminal_Color_Normal:
+ attributes |= hOutInfo->wAttributes & KWSYS_TERMINAL_MASK_FOREGROUND;
+ break;
+ case kwsysTerminal_Color_ForegroundBlack:
+ attributes |= 0;
+ break;
+ case kwsysTerminal_Color_ForegroundRed:
+ attributes |= FOREGROUND_RED;
+ break;
+ case kwsysTerminal_Color_ForegroundGreen:
+ attributes |= FOREGROUND_GREEN;
+ break;
+ case kwsysTerminal_Color_ForegroundYellow:
+ attributes |= FOREGROUND_RED | FOREGROUND_GREEN;
+ break;
+ case kwsysTerminal_Color_ForegroundBlue:
+ attributes |= FOREGROUND_BLUE;
+ break;
+ case kwsysTerminal_Color_ForegroundMagenta:
+ attributes |= FOREGROUND_RED | FOREGROUND_BLUE;
+ break;
+ case kwsysTerminal_Color_ForegroundCyan:
+ attributes |= FOREGROUND_BLUE | FOREGROUND_GREEN;
+ break;
+ case kwsysTerminal_Color_ForegroundWhite:
+ attributes |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
+ break;
+ }
+ switch(color & kwsysTerminal_Color_BackgroundMask)
+ {
+ case kwsysTerminal_Color_Normal:
+ attributes |= hOutInfo->wAttributes & KWSYS_TERMINAL_MASK_BACKGROUND;
+ break;
+ case kwsysTerminal_Color_BackgroundBlack:
+ attributes |= 0;
+ break;
+ case kwsysTerminal_Color_BackgroundRed:
+ attributes |= BACKGROUND_RED;
+ break;
+ case kwsysTerminal_Color_BackgroundGreen:
+ attributes |= BACKGROUND_GREEN;
+ break;
+ case kwsysTerminal_Color_BackgroundYellow:
+ attributes |= BACKGROUND_RED | BACKGROUND_GREEN;
+ break;
+ case kwsysTerminal_Color_BackgroundBlue:
+ attributes |= BACKGROUND_BLUE;
+ break;
+ case kwsysTerminal_Color_BackgroundMagenta:
+ attributes |= BACKGROUND_RED | BACKGROUND_BLUE;
+ break;
+ case kwsysTerminal_Color_BackgroundCyan:
+ attributes |= BACKGROUND_BLUE | BACKGROUND_GREEN;
+ break;
+ case kwsysTerminal_Color_BackgroundWhite:
+ attributes |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
+ break;
+ }
+ if(color & kwsysTerminal_Color_ForegroundBold)
+ {
+ attributes |= FOREGROUND_INTENSITY;
+ }
+ if(color & kwsysTerminal_Color_BackgroundBold)
+ {
+ attributes |= BACKGROUND_INTENSITY;
+ }
+ fflush(stream);
+ SetConsoleTextAttribute(hOut, attributes);
+}
+#endif
diff --git a/Source/kwsys/Terminal.h.in b/Source/kwsys/Terminal.h.in
new file mode 100644
index 0000000..108cba0
--- /dev/null
+++ b/Source/kwsys/Terminal.h.in
@@ -0,0 +1,159 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_Terminal_h
+#define @KWSYS_NAMESPACE@_Terminal_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+#include <stdio.h> /* For file stream type FILE. */
+
+/* Redefine all public interface symbol names to be in the proper
+ namespace. These macros are used internally to kwsys only, and are
+ not visible to user code. Use kwsysHeaderDump.pl to reproduce
+ these macros after making changes to the interface. */
+#if !defined(KWSYS_NAMESPACE)
+# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# define kwsysTerminal_cfprintf kwsys_ns(Terminal_cfprintf)
+# define kwsysTerminal_Color_e kwsys_ns(Terminal_Color_e)
+# define kwsysTerminal_Color_Normal kwsys_ns(Terminal_Color_Normal)
+# define kwsysTerminal_Color_ForegroundBlack kwsys_ns(Terminal_Color_ForegroundBlack)
+# define kwsysTerminal_Color_ForegroundRed kwsys_ns(Terminal_Color_ForegroundRed)
+# define kwsysTerminal_Color_ForegroundGreen kwsys_ns(Terminal_Color_ForegroundGreen)
+# define kwsysTerminal_Color_ForegroundYellow kwsys_ns(Terminal_Color_ForegroundYellow)
+# define kwsysTerminal_Color_ForegroundBlue kwsys_ns(Terminal_Color_ForegroundBlue)
+# define kwsysTerminal_Color_ForegroundMagenta kwsys_ns(Terminal_Color_ForegroundMagenta)
+# define kwsysTerminal_Color_ForegroundCyan kwsys_ns(Terminal_Color_ForegroundCyan)
+# define kwsysTerminal_Color_ForegroundWhite kwsys_ns(Terminal_Color_ForegroundWhite)
+# define kwsysTerminal_Color_ForegroundMask kwsys_ns(Terminal_Color_ForegroundMask)
+# define kwsysTerminal_Color_BackgroundBlack kwsys_ns(Terminal_Color_BackgroundBlack)
+# define kwsysTerminal_Color_BackgroundRed kwsys_ns(Terminal_Color_BackgroundRed)
+# define kwsysTerminal_Color_BackgroundGreen kwsys_ns(Terminal_Color_BackgroundGreen)
+# define kwsysTerminal_Color_BackgroundYellow kwsys_ns(Terminal_Color_BackgroundYellow)
+# define kwsysTerminal_Color_BackgroundBlue kwsys_ns(Terminal_Color_BackgroundBlue)
+# define kwsysTerminal_Color_BackgroundMagenta kwsys_ns(Terminal_Color_BackgroundMagenta)
+# define kwsysTerminal_Color_BackgroundCyan kwsys_ns(Terminal_Color_BackgroundCyan)
+# define kwsysTerminal_Color_BackgroundWhite kwsys_ns(Terminal_Color_BackgroundWhite)
+# define kwsysTerminal_Color_BackgroundMask kwsys_ns(Terminal_Color_BackgroundMask)
+# define kwsysTerminal_Color_ForegroundBold kwsys_ns(Terminal_Color_ForegroundBold)
+# define kwsysTerminal_Color_BackgroundBold kwsys_ns(Terminal_Color_BackgroundBold)
+# define kwsysTerminal_Color_AssumeTTY kwsys_ns(Terminal_Color_AssumeTTY)
+# define kwsysTerminal_Color_AssumeVT100 kwsys_ns(Terminal_Color_AssumeVT100)
+# define kwsysTerminal_Color_AttributeMask kwsys_ns(Terminal_Color_AttributeMask)
+#endif
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/**
+ * Write colored and formatted text to a stream. Color is used only
+ * for streams supporting it. The color specification is constructed
+ * by bitwise-OR-ing enumeration values. At most one foreground and
+ * one background value may be given.
+ *
+ * Whether the a stream supports color is usually automatically
+ * detected, but with two exceptions:
+ *
+ * - When the stream is displayed in a terminal supporting VT100
+ * color but using an intermediate pipe for communication the
+ * detection of a tty fails. (This typically occurs for a shell
+ * running in an rxvt terminal in MSYS.) If the caller knows this
+ * to be the case, the attribute Color_AssumeTTY may be included in
+ * the color specification.
+ *
+ * - When the stream is displayed in a terminal whose TERM
+ * environment variable is not set or is set to a value that is not
+ * known to support VT100 colors. If the caller knows this to be
+ * the case, the attribute Color_AssumeVT100 may be included in the
+ * color specification.
+ */
+kwsysEXPORT void kwsysTerminal_cfprintf(int color, FILE* stream,
+ const char* format, ...);
+enum kwsysTerminal_Color_e
+{
+ /* Normal Text */
+ kwsysTerminal_Color_Normal = 0,
+
+ /* Foreground Color */
+ kwsysTerminal_Color_ForegroundBlack = 0x1,
+ kwsysTerminal_Color_ForegroundRed = 0x2,
+ kwsysTerminal_Color_ForegroundGreen = 0x3,
+ kwsysTerminal_Color_ForegroundYellow = 0x4,
+ kwsysTerminal_Color_ForegroundBlue = 0x5,
+ kwsysTerminal_Color_ForegroundMagenta = 0x6,
+ kwsysTerminal_Color_ForegroundCyan = 0x7,
+ kwsysTerminal_Color_ForegroundWhite = 0x8,
+ kwsysTerminal_Color_ForegroundMask = 0xF,
+
+ /* Background Color */
+ kwsysTerminal_Color_BackgroundBlack = 0x10,
+ kwsysTerminal_Color_BackgroundRed = 0x20,
+ kwsysTerminal_Color_BackgroundGreen = 0x30,
+ kwsysTerminal_Color_BackgroundYellow = 0x40,
+ kwsysTerminal_Color_BackgroundBlue = 0x50,
+ kwsysTerminal_Color_BackgroundMagenta = 0x60,
+ kwsysTerminal_Color_BackgroundCyan = 0x70,
+ kwsysTerminal_Color_BackgroundWhite = 0x80,
+ kwsysTerminal_Color_BackgroundMask = 0xF0,
+
+ /* Attributes */
+ kwsysTerminal_Color_ForegroundBold = 0x100,
+ kwsysTerminal_Color_BackgroundBold = 0x200,
+ kwsysTerminal_Color_AssumeTTY = 0x400,
+ kwsysTerminal_Color_AssumeVT100 = 0x800,
+ kwsysTerminal_Color_AttributeMask = 0xF00
+};
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+ Otherwise, undefine them to keep the namespace clean. */
+#if !defined(KWSYS_NAMESPACE)
+# undef kwsys_ns
+# undef kwsysEXPORT
+# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# undef kwsysTerminal_cfprintf
+# undef kwsysTerminal_Color_e
+# undef kwsysTerminal_Color_Normal
+# undef kwsysTerminal_Color_ForegroundBlack
+# undef kwsysTerminal_Color_ForegroundRed
+# undef kwsysTerminal_Color_ForegroundGreen
+# undef kwsysTerminal_Color_ForegroundYellow
+# undef kwsysTerminal_Color_ForegroundBlue
+# undef kwsysTerminal_Color_ForegroundMagenta
+# undef kwsysTerminal_Color_ForegroundCyan
+# undef kwsysTerminal_Color_ForegroundWhite
+# undef kwsysTerminal_Color_ForegroundMask
+# undef kwsysTerminal_Color_BackgroundBlack
+# undef kwsysTerminal_Color_BackgroundRed
+# undef kwsysTerminal_Color_BackgroundGreen
+# undef kwsysTerminal_Color_BackgroundYellow
+# undef kwsysTerminal_Color_BackgroundBlue
+# undef kwsysTerminal_Color_BackgroundMagenta
+# undef kwsysTerminal_Color_BackgroundCyan
+# undef kwsysTerminal_Color_BackgroundWhite
+# undef kwsysTerminal_Color_BackgroundMask
+# undef kwsysTerminal_Color_ForegroundBold
+# undef kwsysTerminal_Color_BackgroundBold
+# undef kwsysTerminal_Color_AssumeTTY
+# undef kwsysTerminal_Color_AssumeVT100
+# undef kwsysTerminal_Color_AttributeMask
+# endif
+#endif
+
+#endif
diff --git a/Source/kwsys/hash_fun.hxx.in b/Source/kwsys/hash_fun.hxx.in
new file mode 100644
index 0000000..4872b51
--- /dev/null
+++ b/Source/kwsys/hash_fun.hxx.in
@@ -0,0 +1,149 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+#ifndef @KWSYS_NAMESPACE@_hash_fun_hxx
+#define @KWSYS_NAMESPACE@_hash_fun_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+#include <stddef.h> // size_t
+#include <string>
+
+namespace @KWSYS_NAMESPACE@
+{
+
+template <class _Key> struct hash { };
+
+inline size_t _stl_hash_string(const char* __s)
+{
+ unsigned long __h = 0;
+ for ( ; *__s; ++__s)
+ __h = 5*__h + *__s;
+
+ return size_t(__h);
+}
+
+template <>
+struct hash<char*> {
+ size_t operator()(const char* __s) const { return _stl_hash_string(__s); }
+};
+
+template <>
+struct hash<const char*> {
+ size_t operator()(const char* __s) const { return _stl_hash_string(__s); }
+};
+
+template <>
+ struct hash<std::string> {
+ size_t operator()(const std::string & __s) const { return _stl_hash_string(__s.c_str()); }
+};
+
+#if !defined(__BORLANDC__)
+template <>
+ struct hash<const std::string> {
+ size_t operator()(const std::string & __s) const { return _stl_hash_string(__s.c_str()); }
+};
+#endif
+
+template <>
+struct hash<char> {
+ size_t operator()(char __x) const { return __x; }
+};
+
+template <>
+struct hash<unsigned char> {
+ size_t operator()(unsigned char __x) const { return __x; }
+};
+
+template <>
+struct hash<signed char> {
+ size_t operator()(unsigned char __x) const { return __x; }
+};
+
+template <>
+struct hash<short> {
+ size_t operator()(short __x) const { return __x; }
+};
+
+template <>
+struct hash<unsigned short> {
+ size_t operator()(unsigned short __x) const { return __x; }
+};
+
+template <>
+struct hash<int> {
+ size_t operator()(int __x) const { return __x; }
+};
+
+template <>
+struct hash<unsigned int> {
+ size_t operator()(unsigned int __x) const { return __x; }
+};
+
+template <>
+struct hash<long> {
+ size_t operator()(long __x) const { return __x; }
+};
+
+template <>
+struct hash<unsigned long> {
+ size_t operator()(unsigned long __x) const { return __x; }
+};
+
+// use long long or __int64
+#if @KWSYS_USE_LONG_LONG@
+template <>
+struct hash<long long> {
+ size_t operator()(long long __x) const { return __x; }
+};
+
+template <>
+struct hash<unsigned long long> {
+ size_t operator()(unsigned long long __x) const { return __x; }
+};
+#elif @KWSYS_USE___INT64@
+template <>
+struct hash<__int64> {
+ size_t operator()(__int64 __x) const { return __x; }
+};
+template <>
+struct hash<unsigned __int64> {
+ size_t operator()(unsigned __int64 __x) const { return __x; }
+};
+#endif // use long long or __int64
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/Source/kwsys/hash_map.hxx.in b/Source/kwsys/hash_map.hxx.in
new file mode 100644
index 0000000..60c7086
--- /dev/null
+++ b/Source/kwsys/hash_map.hxx.in
@@ -0,0 +1,375 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+#ifndef @KWSYS_NAMESPACE@_hash_map_hxx
+#define @KWSYS_NAMESPACE@_hash_map_hxx
+
+#include <@KWSYS_NAMESPACE@/hashtable.hxx>
+#include <@KWSYS_NAMESPACE@/hash_fun.hxx>
+#include <functional> // equal_to
+
+#if defined(_MSC_VER)
+# pragma warning (push)
+# pragma warning (disable:4284)
+# pragma warning (disable:4786)
+#endif
+
+#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+# pragma set woff 1174
+# pragma set woff 1375
+#endif
+
+namespace @KWSYS_NAMESPACE@
+{
+
+// select1st is an extension: it is not part of the standard.
+template <class T1, class T2>
+struct hash_select1st:
+ public std::unary_function<std::pair<T1, T2>, T1>
+{
+ const T1& operator()(const std::pair<T1, T2>& __x) const
+ { return __x.first; }
+};
+
+// Forward declaration of equality operator; needed for friend declaration.
+
+template <class _Key, class _Tp,
+ class _HashFcn = hash<_Key>,
+ class _EqualKey = std::equal_to<_Key>,
+ class _Alloc = std::allocator<char> >
+class hash_map;
+
+template <class _Key, class _Tp, class _HashFn, class _EqKey, class _Alloc>
+bool operator==(const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&,
+ const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&);
+
+template <class _Key, class _Tp, class _HashFcn, class _EqualKey,
+ class _Alloc>
+class hash_map
+{
+private:
+ typedef hashtable<std::pair<const _Key,_Tp>,_Key,_HashFcn,
+ hash_select1st<const _Key,_Tp>,_EqualKey,_Alloc> _Ht;
+ _Ht _M_ht;
+
+public:
+ typedef typename _Ht::key_type key_type;
+ typedef _Tp data_type;
+ typedef _Tp mapped_type;
+ typedef typename _Ht::value_type value_type;
+ typedef typename _Ht::hasher hasher;
+ typedef typename _Ht::key_equal key_equal;
+
+ typedef typename _Ht::size_type size_type;
+ typedef typename _Ht::difference_type difference_type;
+ typedef typename _Ht::pointer pointer;
+ typedef typename _Ht::const_pointer const_pointer;
+ typedef typename _Ht::reference reference;
+ typedef typename _Ht::const_reference const_reference;
+
+ typedef typename _Ht::iterator iterator;
+ typedef typename _Ht::const_iterator const_iterator;
+
+ typedef typename _Ht::allocator_type allocator_type;
+
+ hasher hash_funct() const { return _M_ht.hash_funct(); }
+ key_equal key_eq() const { return _M_ht.key_eq(); }
+ allocator_type get_allocator() const { return _M_ht.get_allocator(); }
+
+public:
+ hash_map() : _M_ht(100, hasher(), key_equal(), allocator_type()) {}
+ explicit hash_map(size_type __n)
+ : _M_ht(__n, hasher(), key_equal(), allocator_type()) {}
+ hash_map(size_type __n, const hasher& __hf)
+ : _M_ht(__n, __hf, key_equal(), allocator_type()) {}
+ hash_map(size_type __n, const hasher& __hf, const key_equal& __eql,
+ const allocator_type& __a = allocator_type())
+ : _M_ht(__n, __hf, __eql, __a) {}
+
+ template <class _InputIterator>
+ hash_map(_InputIterator __f, _InputIterator __l)
+ : _M_ht(100, hasher(), key_equal(), allocator_type())
+ { _M_ht.insert_unique(__f, __l); }
+ template <class _InputIterator>
+ hash_map(_InputIterator __f, _InputIterator __l, size_type __n)
+ : _M_ht(__n, hasher(), key_equal(), allocator_type())
+ { _M_ht.insert_unique(__f, __l); }
+ template <class _InputIterator>
+ hash_map(_InputIterator __f, _InputIterator __l, size_type __n,
+ const hasher& __hf)
+ : _M_ht(__n, __hf, key_equal(), allocator_type())
+ { _M_ht.insert_unique(__f, __l); }
+ template <class _InputIterator>
+ hash_map(_InputIterator __f, _InputIterator __l, size_type __n,
+ const hasher& __hf, const key_equal& __eql,
+ const allocator_type& __a = allocator_type())
+ : _M_ht(__n, __hf, __eql, __a)
+ { _M_ht.insert_unique(__f, __l); }
+
+public:
+ size_type size() const { return _M_ht.size(); }
+ size_type max_size() const { return _M_ht.max_size(); }
+ bool empty() const { return _M_ht.empty(); }
+ void swap(hash_map& __hs) { _M_ht.swap(__hs._M_ht); }
+
+ friend bool operator==<>(const hash_map&,
+ const hash_map&);
+
+ iterator begin() { return _M_ht.begin(); }
+ iterator end() { return _M_ht.end(); }
+ const_iterator begin() const { return _M_ht.begin(); }
+ const_iterator end() const { return _M_ht.end(); }
+
+public:
+ std::pair<iterator,bool> insert(const value_type& __obj)
+ { return _M_ht.insert_unique(__obj); }
+ template <class _InputIterator>
+ void insert(_InputIterator __f, _InputIterator __l)
+ { _M_ht.insert_unique(__f,__l); }
+ std::pair<iterator,bool> insert_noresize(const value_type& __obj)
+ { return _M_ht.insert_unique_noresize(__obj); }
+
+ iterator find(const key_type& __key) { return _M_ht.find(__key); }
+ const_iterator find(const key_type& __key) const
+ { return _M_ht.find(__key); }
+
+ _Tp& operator[](const key_type& __key) {
+ return _M_ht.find_or_insert(value_type(__key, _Tp())).second;
+ }
+
+ size_type count(const key_type& __key) const { return _M_ht.count(__key); }
+
+ std::pair<iterator, iterator> equal_range(const key_type& __key)
+ { return _M_ht.equal_range(__key); }
+ std::pair<const_iterator, const_iterator>
+ equal_range(const key_type& __key) const
+ { return _M_ht.equal_range(__key); }
+
+ size_type erase(const key_type& __key) {return _M_ht.erase(__key); }
+ void erase(iterator __it) { _M_ht.erase(__it); }
+ void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }
+ void clear() { _M_ht.clear(); }
+
+ void resize(size_type __hint) { _M_ht.resize(__hint); }
+ size_type bucket_count() const { return _M_ht.bucket_count(); }
+ size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }
+ size_type elems_in_bucket(size_type __n) const
+ { return _M_ht.elems_in_bucket(__n); }
+};
+
+template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc>
+bool
+operator==(const hash_map<_Key,_Tp,_HashFcn,_EqlKey,_Alloc>& __hm1,
+ const hash_map<_Key,_Tp,_HashFcn,_EqlKey,_Alloc>& __hm2)
+{
+ return __hm1._M_ht == __hm2._M_ht;
+}
+
+template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc>
+inline bool
+operator!=(const hash_map<_Key,_Tp,_HashFcn,_EqlKey,_Alloc>& __hm1,
+ const hash_map<_Key,_Tp,_HashFcn,_EqlKey,_Alloc>& __hm2) {
+ return !(__hm1 == __hm2);
+}
+
+template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc>
+inline void
+swap(hash_map<_Key,_Tp,_HashFcn,_EqlKey,_Alloc>& __hm1,
+ hash_map<_Key,_Tp,_HashFcn,_EqlKey,_Alloc>& __hm2)
+{
+ __hm1.swap(__hm2);
+}
+
+// Forward declaration of equality operator; needed for friend declaration.
+
+template <class _Key, class _Tp,
+ class _HashFcn = hash<_Key>,
+ class _EqualKey = std::equal_to<_Key>,
+ class _Alloc = std::allocator<char> >
+class hash_multimap;
+
+template <class _Key, class _Tp, class _HF, class _EqKey, class _Alloc>
+bool
+operator==(const hash_multimap<_Key,_Tp,_HF,_EqKey,_Alloc>& __hm1,
+ const hash_multimap<_Key,_Tp,_HF,_EqKey,_Alloc>& __hm2);
+
+template <class _Key, class _Tp, class _HashFcn, class _EqualKey,
+ class _Alloc>
+class hash_multimap
+{
+private:
+ typedef hashtable<std::pair<const _Key, _Tp>, _Key, _HashFcn,
+ hash_select1st<const _Key, _Tp>, _EqualKey, _Alloc>
+ _Ht;
+ _Ht _M_ht;
+
+public:
+ typedef typename _Ht::key_type key_type;
+ typedef _Tp data_type;
+ typedef _Tp mapped_type;
+ typedef typename _Ht::value_type value_type;
+ typedef typename _Ht::hasher hasher;
+ typedef typename _Ht::key_equal key_equal;
+
+ typedef typename _Ht::size_type size_type;
+ typedef typename _Ht::difference_type difference_type;
+ typedef typename _Ht::pointer pointer;
+ typedef typename _Ht::const_pointer const_pointer;
+ typedef typename _Ht::reference reference;
+ typedef typename _Ht::const_reference const_reference;
+
+ typedef typename _Ht::iterator iterator;
+ typedef typename _Ht::const_iterator const_iterator;
+
+ typedef typename _Ht::allocator_type allocator_type;
+
+ hasher hash_funct() const { return _M_ht.hash_funct(); }
+ key_equal key_eq() const { return _M_ht.key_eq(); }
+ allocator_type get_allocator() const { return _M_ht.get_allocator(); }
+
+public:
+ hash_multimap() : _M_ht(100, hasher(), key_equal(), allocator_type()) {}
+ explicit hash_multimap(size_type __n)
+ : _M_ht(__n, hasher(), key_equal(), allocator_type()) {}
+ hash_multimap(size_type __n, const hasher& __hf)
+ : _M_ht(__n, __hf, key_equal(), allocator_type()) {}
+ hash_multimap(size_type __n, const hasher& __hf, const key_equal& __eql,
+ const allocator_type& __a = allocator_type())
+ : _M_ht(__n, __hf, __eql, __a) {}
+
+ template <class _InputIterator>
+ hash_multimap(_InputIterator __f, _InputIterator __l)
+ : _M_ht(100, hasher(), key_equal(), allocator_type())
+ { _M_ht.insert_equal(__f, __l); }
+ template <class _InputIterator>
+ hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n)
+ : _M_ht(__n, hasher(), key_equal(), allocator_type())
+ { _M_ht.insert_equal(__f, __l); }
+ template <class _InputIterator>
+ hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n,
+ const hasher& __hf)
+ : _M_ht(__n, __hf, key_equal(), allocator_type())
+ { _M_ht.insert_equal(__f, __l); }
+ template <class _InputIterator>
+ hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n,
+ const hasher& __hf, const key_equal& __eql,
+ const allocator_type& __a = allocator_type())
+ : _M_ht(__n, __hf, __eql, __a)
+ { _M_ht.insert_equal(__f, __l); }
+
+public:
+ size_type size() const { return _M_ht.size(); }
+ size_type max_size() const { return _M_ht.max_size(); }
+ bool empty() const { return _M_ht.empty(); }
+ void swap(hash_multimap& __hs) { _M_ht.swap(__hs._M_ht); }
+
+ friend bool operator==<>(const hash_multimap&,
+ const hash_multimap&);
+
+ iterator begin() { return _M_ht.begin(); }
+ iterator end() { return _M_ht.end(); }
+ const_iterator begin() const { return _M_ht.begin(); }
+ const_iterator end() const { return _M_ht.end(); }
+
+public:
+ iterator insert(const value_type& __obj)
+ { return _M_ht.insert_equal(__obj); }
+ template <class _InputIterator>
+ void insert(_InputIterator __f, _InputIterator __l)
+ { _M_ht.insert_equal(__f,__l); }
+ iterator insert_noresize(const value_type& __obj)
+ { return _M_ht.insert_equal_noresize(__obj); }
+
+ iterator find(const key_type& __key) { return _M_ht.find(__key); }
+ const_iterator find(const key_type& __key) const
+ { return _M_ht.find(__key); }
+
+ size_type count(const key_type& __key) const { return _M_ht.count(__key); }
+
+ std::pair<iterator, iterator> equal_range(const key_type& __key)
+ { return _M_ht.equal_range(__key); }
+ std::pair<const_iterator, const_iterator>
+ equal_range(const key_type& __key) const
+ { return _M_ht.equal_range(__key); }
+
+ size_type erase(const key_type& __key) {return _M_ht.erase(__key); }
+ void erase(iterator __it) { _M_ht.erase(__it); }
+ void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }
+ void clear() { _M_ht.clear(); }
+
+public:
+ void resize(size_type __hint) { _M_ht.resize(__hint); }
+ size_type bucket_count() const { return _M_ht.bucket_count(); }
+ size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }
+ size_type elems_in_bucket(size_type __n) const
+ { return _M_ht.elems_in_bucket(__n); }
+};
+
+template <class _Key, class _Tp, class _HF, class _EqKey, class _Alloc>
+bool
+operator==(const hash_multimap<_Key,_Tp,_HF,_EqKey,_Alloc>& __hm1,
+ const hash_multimap<_Key,_Tp,_HF,_EqKey,_Alloc>& __hm2)
+{
+ return __hm1._M_ht == __hm2._M_ht;
+}
+
+template <class _Key, class _Tp, class _HF, class _EqKey, class _Alloc>
+inline bool
+operator!=(const hash_multimap<_Key,_Tp,_HF,_EqKey,_Alloc>& __hm1,
+ const hash_multimap<_Key,_Tp,_HF,_EqKey,_Alloc>& __hm2) {
+ return !(__hm1 == __hm2);
+}
+
+template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc>
+inline void
+swap(hash_multimap<_Key,_Tp,_HashFcn,_EqlKey,_Alloc>& __hm1,
+ hash_multimap<_Key,_Tp,_HashFcn,_EqlKey,_Alloc>& __hm2)
+{
+ __hm1.swap(__hm2);
+}
+
+} // namespace @KWSYS_NAMESPACE@
+
+#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+# pragma reset woff 1174
+# pragma reset woff 1375
+#endif
+
+#if defined(_MSC_VER)
+# pragma warning (pop)
+#endif
+
+#endif
diff --git a/Source/kwsys/hash_set.hxx.in b/Source/kwsys/hash_set.hxx.in
new file mode 100644
index 0000000..c314979
--- /dev/null
+++ b/Source/kwsys/hash_set.hxx.in
@@ -0,0 +1,359 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+#ifndef @KWSYS_NAMESPACE@_hash_set_hxx
+#define @KWSYS_NAMESPACE@_hash_set_hxx
+
+#include <@KWSYS_NAMESPACE@/hashtable.hxx>
+#include <@KWSYS_NAMESPACE@/hash_fun.hxx>
+#include <functional> // equal_to
+
+#if defined(_MSC_VER)
+# pragma warning (push)
+# pragma warning (disable:4284)
+# pragma warning (disable:4786)
+#endif
+
+#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+# pragma set woff 1174
+# pragma set woff 1375
+#endif
+
+namespace @KWSYS_NAMESPACE@
+{
+
+// identity is an extension: it is not part of the standard.
+template <class _Tp>
+struct _Identity : public std::unary_function<_Tp,_Tp>
+{
+ const _Tp& operator()(const _Tp& __x) const { return __x; }
+};
+
+// Forward declaration of equality operator; needed for friend declaration.
+
+template <class _Value,
+ class _HashFcn = hash<_Value>,
+ class _EqualKey = std::equal_to<_Value>,
+ class _Alloc = std::allocator<char> >
+class hash_set;
+
+template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
+bool
+operator==(const hash_set<_Value,_HashFcn,_EqualKey,_Alloc>& __hs1,
+ const hash_set<_Value,_HashFcn,_EqualKey,_Alloc>& __hs2);
+
+template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
+class hash_set
+{
+private:
+ typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>,
+ _EqualKey, _Alloc> _Ht;
+ _Ht _M_ht;
+
+public:
+ typedef typename _Ht::key_type key_type;
+ typedef typename _Ht::value_type value_type;
+ typedef typename _Ht::hasher hasher;
+ typedef typename _Ht::key_equal key_equal;
+
+ typedef typename _Ht::size_type size_type;
+ typedef typename _Ht::difference_type difference_type;
+ typedef typename _Ht::const_pointer pointer;
+ typedef typename _Ht::const_pointer const_pointer;
+ typedef typename _Ht::const_reference reference;
+ typedef typename _Ht::const_reference const_reference;
+
+ typedef typename _Ht::const_iterator iterator;
+ typedef typename _Ht::const_iterator const_iterator;
+
+ typedef typename _Ht::allocator_type allocator_type;
+
+ hasher hash_funct() const { return _M_ht.hash_funct(); }
+ key_equal key_eq() const { return _M_ht.key_eq(); }
+ allocator_type get_allocator() const { return _M_ht.get_allocator(); }
+
+public:
+ hash_set()
+ : _M_ht(100, hasher(), key_equal(), allocator_type()) {}
+ explicit hash_set(size_type __n)
+ : _M_ht(__n, hasher(), key_equal(), allocator_type()) {}
+ hash_set(size_type __n, const hasher& __hf)
+ : _M_ht(__n, __hf, key_equal(), allocator_type()) {}
+ hash_set(size_type __n, const hasher& __hf, const key_equal& __eql,
+ const allocator_type& __a = allocator_type())
+ : _M_ht(__n, __hf, __eql, __a) {}
+
+ template <class _InputIterator>
+ hash_set(_InputIterator __f, _InputIterator __l)
+ : _M_ht(100, hasher(), key_equal(), allocator_type())
+ { _M_ht.insert_unique(__f, __l); }
+ template <class _InputIterator>
+ hash_set(_InputIterator __f, _InputIterator __l, size_type __n)
+ : _M_ht(__n, hasher(), key_equal(), allocator_type())
+ { _M_ht.insert_unique(__f, __l); }
+ template <class _InputIterator>
+ hash_set(_InputIterator __f, _InputIterator __l, size_type __n,
+ const hasher& __hf)
+ : _M_ht(__n, __hf, key_equal(), allocator_type())
+ { _M_ht.insert_unique(__f, __l); }
+ template <class _InputIterator>
+ hash_set(_InputIterator __f, _InputIterator __l, size_type __n,
+ const hasher& __hf, const key_equal& __eql,
+ const allocator_type& __a = allocator_type())
+ : _M_ht(__n, __hf, __eql, __a)
+ { _M_ht.insert_unique(__f, __l); }
+
+public:
+ size_type size() const { return _M_ht.size(); }
+ size_type max_size() const { return _M_ht.max_size(); }
+ bool empty() const { return _M_ht.empty(); }
+ void swap(hash_set& __hs) { _M_ht.swap(__hs._M_ht); }
+
+ friend bool operator==<>(const hash_set&,
+ const hash_set&);
+
+ iterator begin() const { return _M_ht.begin(); }
+ iterator end() const { return _M_ht.end(); }
+
+public:
+ std::pair<iterator, bool> insert(const value_type& __obj)
+ {
+ typedef typename _Ht::iterator _Ht_iterator;
+ std::pair<_Ht_iterator, bool> __p = _M_ht.insert_unique(__obj);
+ return std::pair<iterator,bool>(__p.first, __p.second);
+ }
+ template <class _InputIterator>
+ void insert(_InputIterator __f, _InputIterator __l)
+ { _M_ht.insert_unique(__f,__l); }
+ std::pair<iterator, bool> insert_noresize(const value_type& __obj)
+ {
+ typedef typename _Ht::iterator _Ht_iterator;
+ std::pair<_Ht_iterator, bool> __p =
+ _M_ht.insert_unique_noresize(__obj);
+ return std::pair<iterator, bool>(__p.first, __p.second);
+ }
+
+ iterator find(const key_type& __key) const { return _M_ht.find(__key); }
+
+ size_type count(const key_type& __key) const { return _M_ht.count(__key); }
+
+ std::pair<iterator, iterator> equal_range(const key_type& __key) const
+ { return _M_ht.equal_range(__key); }
+
+ size_type erase(const key_type& __key) {return _M_ht.erase(__key); }
+ void erase(iterator __it) { _M_ht.erase(__it); }
+ void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }
+ void clear() { _M_ht.clear(); }
+
+public:
+ void resize(size_type __hint) { _M_ht.resize(__hint); }
+ size_type bucket_count() const { return _M_ht.bucket_count(); }
+ size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }
+ size_type elems_in_bucket(size_type __n) const
+ { return _M_ht.elems_in_bucket(__n); }
+};
+
+template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
+bool
+operator==(const hash_set<_Value,_HashFcn,_EqualKey,_Alloc>& __hs1,
+ const hash_set<_Value,_HashFcn,_EqualKey,_Alloc>& __hs2)
+{
+ return __hs1._M_ht == __hs2._M_ht;
+}
+
+template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
+inline bool
+operator!=(const hash_set<_Value,_HashFcn,_EqualKey,_Alloc>& __hs1,
+ const hash_set<_Value,_HashFcn,_EqualKey,_Alloc>& __hs2) {
+ return !(__hs1 == __hs2);
+}
+
+template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
+inline void
+swap(hash_set<_Val,_HashFcn,_EqualKey,_Alloc>& __hs1,
+ hash_set<_Val,_HashFcn,_EqualKey,_Alloc>& __hs2)
+{
+ __hs1.swap(__hs2);
+}
+
+template <class _Value,
+ class _HashFcn = hash<_Value>,
+ class _EqualKey = std::equal_to<_Value>,
+ class _Alloc = std::allocator<char> >
+class hash_multiset;
+
+template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
+bool
+operator==(const hash_multiset<_Val,_HashFcn,_EqualKey,_Alloc>& __hs1,
+ const hash_multiset<_Val,_HashFcn,_EqualKey,_Alloc>& __hs2);
+
+
+template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
+class hash_multiset
+{
+private:
+ typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>,
+ _EqualKey, _Alloc> _Ht;
+ _Ht _M_ht;
+
+public:
+ typedef typename _Ht::key_type key_type;
+ typedef typename _Ht::value_type value_type;
+ typedef typename _Ht::hasher hasher;
+ typedef typename _Ht::key_equal key_equal;
+
+ typedef typename _Ht::size_type size_type;
+ typedef typename _Ht::difference_type difference_type;
+ typedef typename _Ht::const_pointer pointer;
+ typedef typename _Ht::const_pointer const_pointer;
+ typedef typename _Ht::const_reference reference;
+ typedef typename _Ht::const_reference const_reference;
+
+ typedef typename _Ht::const_iterator iterator;
+ typedef typename _Ht::const_iterator const_iterator;
+
+ typedef typename _Ht::allocator_type allocator_type;
+
+ hasher hash_funct() const { return _M_ht.hash_funct(); }
+ key_equal key_eq() const { return _M_ht.key_eq(); }
+ allocator_type get_allocator() const { return _M_ht.get_allocator(); }
+
+public:
+ hash_multiset()
+ : _M_ht(100, hasher(), key_equal(), allocator_type()) {}
+ explicit hash_multiset(size_type __n)
+ : _M_ht(__n, hasher(), key_equal(), allocator_type()) {}
+ hash_multiset(size_type __n, const hasher& __hf)
+ : _M_ht(__n, __hf, key_equal(), allocator_type()) {}
+ hash_multiset(size_type __n, const hasher& __hf, const key_equal& __eql,
+ const allocator_type& __a = allocator_type())
+ : _M_ht(__n, __hf, __eql, __a) {}
+
+ template <class _InputIterator>
+ hash_multiset(_InputIterator __f, _InputIterator __l)
+ : _M_ht(100, hasher(), key_equal(), allocator_type())
+ { _M_ht.insert_equal(__f, __l); }
+ template <class _InputIterator>
+ hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n)
+ : _M_ht(__n, hasher(), key_equal(), allocator_type())
+ { _M_ht.insert_equal(__f, __l); }
+ template <class _InputIterator>
+ hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n,
+ const hasher& __hf)
+ : _M_ht(__n, __hf, key_equal(), allocator_type())
+ { _M_ht.insert_equal(__f, __l); }
+ template <class _InputIterator>
+ hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n,
+ const hasher& __hf, const key_equal& __eql,
+ const allocator_type& __a = allocator_type())
+ : _M_ht(__n, __hf, __eql, __a)
+ { _M_ht.insert_equal(__f, __l); }
+
+public:
+ size_type size() const { return _M_ht.size(); }
+ size_type max_size() const { return _M_ht.max_size(); }
+ bool empty() const { return _M_ht.empty(); }
+ void swap(hash_multiset& hs) { _M_ht.swap(hs._M_ht); }
+
+ friend bool operator==<>(const hash_multiset&,
+ const hash_multiset&);
+
+ iterator begin() const { return _M_ht.begin(); }
+ iterator end() const { return _M_ht.end(); }
+
+public:
+ iterator insert(const value_type& __obj)
+ { return _M_ht.insert_equal(__obj); }
+ template <class _InputIterator>
+ void insert(_InputIterator __f, _InputIterator __l)
+ { _M_ht.insert_equal(__f,__l); }
+ iterator insert_noresize(const value_type& __obj)
+ { return _M_ht.insert_equal_noresize(__obj); }
+
+ iterator find(const key_type& __key) const { return _M_ht.find(__key); }
+
+ size_type count(const key_type& __key) const { return _M_ht.count(__key); }
+
+ std::pair<iterator, iterator> equal_range(const key_type& __key) const
+ { return _M_ht.equal_range(__key); }
+
+ size_type erase(const key_type& __key) {return _M_ht.erase(__key); }
+ void erase(iterator __it) { _M_ht.erase(__it); }
+ void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }
+ void clear() { _M_ht.clear(); }
+
+public:
+ void resize(size_type __hint) { _M_ht.resize(__hint); }
+ size_type bucket_count() const { return _M_ht.bucket_count(); }
+ size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }
+ size_type elems_in_bucket(size_type __n) const
+ { return _M_ht.elems_in_bucket(__n); }
+};
+
+template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
+bool
+operator==(const hash_multiset<_Val,_HashFcn,_EqualKey,_Alloc>& __hs1,
+ const hash_multiset<_Val,_HashFcn,_EqualKey,_Alloc>& __hs2)
+{
+ return __hs1._M_ht == __hs2._M_ht;
+}
+
+template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
+inline bool
+operator!=(const hash_multiset<_Val,_HashFcn,_EqualKey,_Alloc>& __hs1,
+ const hash_multiset<_Val,_HashFcn,_EqualKey,_Alloc>& __hs2) {
+ return !(__hs1 == __hs2);
+}
+
+template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
+inline void
+swap(hash_multiset<_Val,_HashFcn,_EqualKey,_Alloc>& __hs1,
+ hash_multiset<_Val,_HashFcn,_EqualKey,_Alloc>& __hs2) {
+ __hs1.swap(__hs2);
+}
+
+} // namespace @KWSYS_NAMESPACE@
+
+#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+# pragma reset woff 1174
+# pragma reset woff 1375
+#endif
+
+#if defined(_MSC_VER)
+# pragma warning (pop)
+#endif
+
+#endif
diff --git a/Source/kwsys/hashtable.hxx.in b/Source/kwsys/hashtable.hxx.in
new file mode 100644
index 0000000..9a20226
--- /dev/null
+++ b/Source/kwsys/hashtable.hxx.in
@@ -0,0 +1,997 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+#ifdef __BORLANDC__
+# pragma warn -8027 /* 'for' not inlined. */
+# pragma warn -8026 /* 'exception' not inlined. */
+#endif
+
+#ifndef @KWSYS_NAMESPACE@_hashtable_hxx
+#define @KWSYS_NAMESPACE@_hashtable_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <stddef.h> // size_t
+#include <algorithm> // lower_bound
+#include <functional> // unary_function
+#include <iterator> // iterator_traits
+#include <memory> // allocator
+#include <utility> // pair
+#include <vector> // vector
+
+#if defined(_MSC_VER)
+# pragma warning (push)
+# pragma warning (disable:4284)
+# pragma warning (disable:4786)
+# pragma warning (disable:4512) /* no assignment operator for class */
+#endif
+#if defined(__sgi) && !defined(__GNUC__)
+# pragma set woff 3970 /* pointer to int conversion */ 3321 3968
+#endif
+
+// In C++11, clang will warn about using dynamic exception specifications
+// as they are deprecated. But as this class is trying to faithfully
+// mimic unordered_set and unordered_map, we want to keep the 'throw()'
+// decorations below. So we suppress the warning.
+#if defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wdeprecated")
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated"
+# endif
+#endif
+
+namespace @KWSYS_NAMESPACE@
+{
+
+template <class _Val>
+struct _Hashtable_node
+{
+ _Hashtable_node* _M_next;
+ _Val _M_val;
+ void public_method_to_quiet_warning_about_all_methods_private();
+private:
+ void operator=(_Hashtable_node<_Val> const&); // poison node assignment
+};
+
+template <class _Val, class _Key, class _HashFcn,
+ class _ExtractKey, class _EqualKey,
+ class _Alloc = std::allocator<char> >
+class hashtable;
+
+template <class _Val, class _Key, class _HashFcn,
+ class _ExtractKey, class _EqualKey, class _Alloc>
+struct _Hashtable_iterator;
+
+template <class _Val, class _Key, class _HashFcn,
+ class _ExtractKey, class _EqualKey, class _Alloc>
+struct _Hashtable_const_iterator;
+
+template <class _Val, class _Key, class _HashFcn,
+ class _ExtractKey, class _EqualKey, class _Alloc>
+struct _Hashtable_iterator {
+ typedef hashtable<_Val,_Key,_HashFcn,_ExtractKey,_EqualKey,_Alloc>
+ _Hashtable;
+ typedef _Hashtable_iterator<_Val, _Key, _HashFcn,
+ _ExtractKey, _EqualKey, _Alloc>
+ iterator;
+ typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn,
+ _ExtractKey, _EqualKey, _Alloc>
+ const_iterator;
+ typedef _Hashtable_node<_Val> _Node;
+
+ typedef std::forward_iterator_tag iterator_category;
+ typedef _Val value_type;
+ typedef ptrdiff_t difference_type;
+ typedef size_t size_type;
+ typedef _Val& reference;
+ typedef _Val* pointer;
+
+ _Node* _M_cur;
+ _Hashtable* _M_ht;
+
+ _Hashtable_iterator(_Node* __n, _Hashtable* __tab)
+ : _M_cur(__n), _M_ht(__tab) {}
+ _Hashtable_iterator() {}
+ reference operator*() const { return _M_cur->_M_val; }
+ pointer operator->() const { return &(operator*()); }
+ iterator& operator++();
+ iterator operator++(int);
+ bool operator==(const iterator& __it) const
+ { return _M_cur == __it._M_cur; }
+ bool operator!=(const iterator& __it) const
+ { return _M_cur != __it._M_cur; }
+};
+
+
+template <class _Val, class _Key, class _HashFcn,
+ class _ExtractKey, class _EqualKey, class _Alloc>
+struct _Hashtable_const_iterator {
+ typedef hashtable<_Val,_Key,_HashFcn,_ExtractKey,_EqualKey,_Alloc>
+ _Hashtable;
+ typedef _Hashtable_iterator<_Val,_Key,_HashFcn,
+ _ExtractKey,_EqualKey,_Alloc>
+ iterator;
+ typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn,
+ _ExtractKey, _EqualKey, _Alloc>
+ const_iterator;
+ typedef _Hashtable_node<_Val> _Node;
+
+ typedef std::forward_iterator_tag iterator_category;
+ typedef _Val value_type;
+ typedef ptrdiff_t difference_type;
+ typedef size_t size_type;
+ typedef const _Val& reference;
+ typedef const _Val* pointer;
+
+ const _Node* _M_cur;
+ const _Hashtable* _M_ht;
+
+ _Hashtable_const_iterator(const _Node* __n, const _Hashtable* __tab)
+ : _M_cur(__n), _M_ht(__tab) {}
+ _Hashtable_const_iterator() {}
+ _Hashtable_const_iterator(const iterator& __it)
+ : _M_cur(__it._M_cur), _M_ht(__it._M_ht) {}
+ reference operator*() const { return _M_cur->_M_val; }
+ pointer operator->() const { return &(operator*()); }
+ const_iterator& operator++();
+ const_iterator operator++(int);
+ bool operator==(const const_iterator& __it) const
+ { return _M_cur == __it._M_cur; }
+ bool operator!=(const const_iterator& __it) const
+ { return _M_cur != __it._M_cur; }
+};
+
+// Note: assumes long is at least 32 bits.
+enum { _stl_num_primes = 31 };
+
+// create a function with a static local to that function that returns
+// the static
+static inline const unsigned long* get_stl_prime_list() {
+
+static const unsigned long _stl_prime_list[_stl_num_primes] =
+{
+ 5ul, 11ul, 23ul,
+ 53ul, 97ul, 193ul, 389ul, 769ul,
+ 1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
+ 49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
+ 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
+ 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
+ 1610612741ul, 3221225473ul, 4294967291ul
+};
+
+return &_stl_prime_list[0]; }
+
+static inline size_t _stl_next_prime(size_t __n)
+{
+ const unsigned long* __first = get_stl_prime_list();
+ const unsigned long* __last = get_stl_prime_list() + (int)_stl_num_primes;
+ const unsigned long* pos = std::lower_bound(__first, __last, __n);
+ return pos == __last ? *(__last - 1) : *pos;
+}
+
+// Forward declaration of operator==.
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+class hashtable;
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+bool operator==(const hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>& __ht1,
+ const hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>& __ht2);
+
+// Hashtables handle allocators a bit differently than other containers
+// do. If we're using standard-conforming allocators, then a hashtable
+// unconditionally has a member variable to hold its allocator, even if
+// it so happens that all instances of the allocator type are identical.
+// This is because, for hashtables, this extra storage is negligible.
+// Additionally, a base class wouldn't serve any other purposes; it
+// wouldn't, for example, simplify the exception-handling code.
+
+template <class _Val, class _Key, class _HashFcn,
+ class _ExtractKey, class _EqualKey, class _Alloc>
+class hashtable {
+public:
+ typedef _Key key_type;
+ typedef _Val value_type;
+ typedef _HashFcn hasher;
+ typedef _EqualKey key_equal;
+
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+
+ hasher hash_funct() const { return _M_hash; }
+ key_equal key_eq() const { return _M_equals; }
+
+private:
+ typedef _Hashtable_node<_Val> _Node;
+
+public:
+ typedef typename _Alloc::template rebind<_Val>::other allocator_type;
+ allocator_type get_allocator() const { return _M_node_allocator; }
+private:
+ typedef typename _Alloc::template rebind<_Node>::other _M_node_allocator_type;
+ typedef typename _Alloc::template rebind<_Node*>::other _M_node_ptr_allocator_type;
+ typedef std::vector<_Node*,_M_node_ptr_allocator_type> _M_buckets_type;
+
+private:
+ _M_node_allocator_type _M_node_allocator;
+ hasher _M_hash;
+ key_equal _M_equals;
+ _ExtractKey _M_get_key;
+ _M_buckets_type _M_buckets;
+ size_type _M_num_elements;
+
+ _Node* _M_get_node() { return _M_node_allocator.allocate(1); }
+ void _M_put_node(_Node* __p) { _M_node_allocator.deallocate(__p, 1); }
+
+public:
+ typedef _Hashtable_iterator<_Val,_Key,_HashFcn,_ExtractKey,_EqualKey,_Alloc>
+ iterator;
+ typedef _Hashtable_const_iterator<_Val,_Key,_HashFcn,_ExtractKey,_EqualKey,
+ _Alloc>
+ const_iterator;
+
+ friend struct
+ _Hashtable_iterator<_Val,_Key,_HashFcn,_ExtractKey,_EqualKey,_Alloc>;
+ friend struct
+ _Hashtable_const_iterator<_Val,_Key,_HashFcn,_ExtractKey,_EqualKey,_Alloc>;
+
+public:
+ hashtable(size_type __n,
+ const _HashFcn& __hf,
+ const _EqualKey& __eql,
+ const _ExtractKey& __ext,
+ const allocator_type& __a = allocator_type())
+ : _M_node_allocator(__a),
+ _M_hash(__hf),
+ _M_equals(__eql),
+ _M_get_key(__ext),
+ _M_buckets(__a),
+ _M_num_elements(0)
+ {
+ _M_initialize_buckets(__n);
+ }
+
+ hashtable(size_type __n,
+ const _HashFcn& __hf,
+ const _EqualKey& __eql,
+ const allocator_type& __a = allocator_type())
+ : _M_node_allocator(__a),
+ _M_hash(__hf),
+ _M_equals(__eql),
+ _M_get_key(_ExtractKey()),
+ _M_buckets(__a),
+ _M_num_elements(0)
+ {
+ _M_initialize_buckets(__n);
+ }
+
+ hashtable(const hashtable& __ht)
+ : _M_node_allocator(__ht.get_allocator()),
+ _M_hash(__ht._M_hash),
+ _M_equals(__ht._M_equals),
+ _M_get_key(__ht._M_get_key),
+ _M_buckets(__ht.get_allocator()),
+ _M_num_elements(0)
+ {
+ _M_copy_from(__ht);
+ }
+
+ hashtable& operator= (const hashtable& __ht)
+ {
+ if (&__ht != this) {
+ clear();
+ _M_hash = __ht._M_hash;
+ _M_equals = __ht._M_equals;
+ _M_get_key = __ht._M_get_key;
+ _M_copy_from(__ht);
+ }
+ return *this;
+ }
+
+ ~hashtable() { clear(); }
+
+ size_type size() const { return _M_num_elements; }
+ size_type max_size() const { return size_type(-1); }
+ bool empty() const { return size() == 0; }
+
+ void swap(hashtable& __ht)
+ {
+ std::swap(_M_hash, __ht._M_hash);
+ std::swap(_M_equals, __ht._M_equals);
+ std::swap(_M_get_key, __ht._M_get_key);
+ _M_buckets.swap(__ht._M_buckets);
+ std::swap(_M_num_elements, __ht._M_num_elements);
+ }
+
+ iterator begin()
+ {
+ for (size_type __n = 0; __n < _M_buckets.size(); ++__n)
+ if (_M_buckets[__n])
+ return iterator(_M_buckets[__n], this);
+ return end();
+ }
+
+ iterator end() { return iterator(0, this); }
+
+ const_iterator begin() const
+ {
+ for (size_type __n = 0; __n < _M_buckets.size(); ++__n)
+ if (_M_buckets[__n])
+ return const_iterator(_M_buckets[__n], this);
+ return end();
+ }
+
+ const_iterator end() const { return const_iterator(0, this); }
+
+ friend bool operator==<>(const hashtable&,
+ const hashtable&);
+
+public:
+
+ size_type bucket_count() const { return _M_buckets.size(); }
+
+ size_type max_bucket_count() const
+ { return get_stl_prime_list()[(int)_stl_num_primes - 1]; }
+
+ size_type elems_in_bucket(size_type __bucket) const
+ {
+ size_type __result = 0;
+ for (_Node* __cur = _M_buckets[__bucket]; __cur; __cur = __cur->_M_next)
+ __result += 1;
+ return __result;
+ }
+
+ std::pair<iterator, bool> insert_unique(const value_type& __obj)
+ {
+ resize(_M_num_elements + 1);
+ return insert_unique_noresize(__obj);
+ }
+
+ iterator insert_equal(const value_type& __obj)
+ {
+ resize(_M_num_elements + 1);
+ return insert_equal_noresize(__obj);
+ }
+
+ std::pair<iterator, bool> insert_unique_noresize(const value_type& __obj);
+ iterator insert_equal_noresize(const value_type& __obj);
+
+ template <class _InputIterator>
+ void insert_unique(_InputIterator __f, _InputIterator __l)
+ {
+ insert_unique(__f, __l,
+ typename std::iterator_traits<_InputIterator>::iterator_category());
+ }
+
+ template <class _InputIterator>
+ void insert_equal(_InputIterator __f, _InputIterator __l)
+ {
+ insert_equal(__f, __l,
+ typename std::iterator_traits<_InputIterator>::iterator_category());
+ }
+
+ template <class _InputIterator>
+ void insert_unique(_InputIterator __f, _InputIterator __l,
+ std::input_iterator_tag)
+ {
+ for ( ; __f != __l; ++__f)
+ insert_unique(*__f);
+ }
+
+ template <class _InputIterator>
+ void insert_equal(_InputIterator __f, _InputIterator __l,
+ std::input_iterator_tag)
+ {
+ for ( ; __f != __l; ++__f)
+ insert_equal(*__f);
+ }
+
+ template <class _ForwardIterator>
+ void insert_unique(_ForwardIterator __f, _ForwardIterator __l,
+ std::forward_iterator_tag)
+ {
+ size_type __n = 0;
+ std::distance(__f, __l, __n);
+ resize(_M_num_elements + __n);
+ for ( ; __n > 0; --__n, ++__f)
+ insert_unique_noresize(*__f);
+ }
+
+ template <class _ForwardIterator>
+ void insert_equal(_ForwardIterator __f, _ForwardIterator __l,
+ std::forward_iterator_tag)
+ {
+ size_type __n = 0;
+ std::distance(__f, __l, __n);
+ resize(_M_num_elements + __n);
+ for ( ; __n > 0; --__n, ++__f)
+ insert_equal_noresize(*__f);
+ }
+
+ reference find_or_insert(const value_type& __obj);
+
+ iterator find(const key_type& __key)
+ {
+ size_type __n = _M_bkt_num_key(__key);
+ _Node* __first;
+ for ( __first = _M_buckets[__n];
+ __first && !_M_equals(_M_get_key(__first->_M_val), __key);
+ __first = __first->_M_next)
+ {}
+ return iterator(__first, this);
+ }
+
+ const_iterator find(const key_type& __key) const
+ {
+ size_type __n = _M_bkt_num_key(__key);
+ const _Node* __first;
+ for ( __first = _M_buckets[__n];
+ __first && !_M_equals(_M_get_key(__first->_M_val), __key);
+ __first = __first->_M_next)
+ {}
+ return const_iterator(__first, this);
+ }
+
+ size_type count(const key_type& __key) const
+ {
+ const size_type __n = _M_bkt_num_key(__key);
+ size_type __result = 0;
+
+ for (const _Node* __cur = _M_buckets[__n]; __cur; __cur = __cur->_M_next)
+ if (_M_equals(_M_get_key(__cur->_M_val), __key))
+ ++__result;
+ return __result;
+ }
+
+ std::pair<iterator, iterator>
+ equal_range(const key_type& __key);
+
+ std::pair<const_iterator, const_iterator>
+ equal_range(const key_type& __key) const;
+
+ size_type erase(const key_type& __key);
+ void erase(const iterator& __it);
+ void erase(iterator __first, iterator __last);
+
+ void erase(const const_iterator& __it);
+ void erase(const_iterator __first, const_iterator __last);
+
+ void resize(size_type __num_elements_hint);
+ void clear();
+
+private:
+ size_type _M_next_size(size_type __n) const
+ { return _stl_next_prime(__n); }
+
+ void _M_initialize_buckets(size_type __n)
+ {
+ const size_type __n_buckets = _M_next_size(__n);
+ _M_buckets.reserve(__n_buckets);
+ _M_buckets.insert(_M_buckets.end(), __n_buckets, (_Node*) 0);
+ _M_num_elements = 0;
+ }
+
+ size_type _M_bkt_num_key(const key_type& __key) const
+ {
+ return _M_bkt_num_key(__key, _M_buckets.size());
+ }
+
+ size_type _M_bkt_num(const value_type& __obj) const
+ {
+ return _M_bkt_num_key(_M_get_key(__obj));
+ }
+
+ size_type _M_bkt_num_key(const key_type& __key, size_t __n) const
+ {
+ return _M_hash(__key) % __n;
+ }
+
+ size_type _M_bkt_num(const value_type& __obj, size_t __n) const
+ {
+ return _M_bkt_num_key(_M_get_key(__obj), __n);
+ }
+
+ void construct(_Val* p, const _Val& v)
+ {
+ new (p) _Val(v);
+ }
+ void destroy(_Val* p)
+ {
+ (void)p;
+ p->~_Val();
+ }
+
+ _Node* _M_new_node(const value_type& __obj)
+ {
+ _Node* __n = _M_get_node();
+ __n->_M_next = 0;
+ try {
+ construct(&__n->_M_val, __obj);
+ return __n;
+ }
+ catch(...) {_M_put_node(__n); throw;}
+ }
+
+ void _M_delete_node(_Node* __n)
+ {
+ destroy(&__n->_M_val);
+ _M_put_node(__n);
+ }
+
+ void _M_erase_bucket(const size_type __n, _Node* __first, _Node* __last);
+ void _M_erase_bucket(const size_type __n, _Node* __last);
+
+ void _M_copy_from(const hashtable& __ht);
+
+};
+
+template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
+ class _All>
+_Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>&
+_Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>::operator++()
+{
+ const _Node* __old = _M_cur;
+ _M_cur = _M_cur->_M_next;
+ if (!_M_cur) {
+ size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val);
+ while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size())
+ _M_cur = _M_ht->_M_buckets[__bucket];
+ }
+ return *this;
+}
+
+template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
+ class _All>
+inline _Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>
+_Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>::operator++(int)
+{
+ iterator __tmp = *this;
+ ++*this;
+ return __tmp;
+}
+
+template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
+ class _All>
+_Hashtable_const_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>&
+_Hashtable_const_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>::operator++()
+{
+ const _Node* __old = _M_cur;
+ _M_cur = _M_cur->_M_next;
+ if (!_M_cur) {
+ size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val);
+ while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size())
+ _M_cur = _M_ht->_M_buckets[__bucket];
+ }
+ return *this;
+}
+
+template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
+ class _All>
+inline _Hashtable_const_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>
+_Hashtable_const_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>::operator++(int)
+{
+ const_iterator __tmp = *this;
+ ++*this;
+ return __tmp;
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+bool operator==(const hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>& __ht1,
+ const hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>& __ht2)
+{
+ typedef typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::_Node _Node;
+ if (__ht1._M_buckets.size() != __ht2._M_buckets.size())
+ return false;
+ for (int __n = 0; __n < __ht1._M_buckets.size(); ++__n) {
+ _Node* __cur1 = __ht1._M_buckets[__n];
+ _Node* __cur2 = __ht2._M_buckets[__n];
+ for ( ; __cur1 && __cur2 && __cur1->_M_val == __cur2->_M_val;
+ __cur1 = __cur1->_M_next, __cur2 = __cur2->_M_next)
+ {}
+ if (__cur1 || __cur2)
+ return false;
+ }
+ return true;
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+inline bool operator!=(const hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>& __ht1,
+ const hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>& __ht2) {
+ return !(__ht1 == __ht2);
+}
+
+template <class _Val, class _Key, class _HF, class _Extract, class _EqKey,
+ class _All>
+inline void swap(hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht1,
+ hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht2) {
+ __ht1.swap(__ht2);
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+std::pair<typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::iterator, bool>
+hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
+ ::insert_unique_noresize(const value_type& __obj)
+{
+ const size_type __n = _M_bkt_num(__obj);
+ _Node* __first = _M_buckets[__n];
+
+ for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
+ if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj)))
+ return std::pair<iterator, bool>(iterator(__cur, this), false);
+
+ _Node* __tmp = _M_new_node(__obj);
+ __tmp->_M_next = __first;
+ _M_buckets[__n] = __tmp;
+ ++_M_num_elements;
+ return std::pair<iterator, bool>(iterator(__tmp, this), true);
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::iterator
+hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
+ ::insert_equal_noresize(const value_type& __obj)
+{
+ const size_type __n = _M_bkt_num(__obj);
+ _Node* __first = _M_buckets[__n];
+
+ for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
+ if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) {
+ _Node* __tmp = _M_new_node(__obj);
+ __tmp->_M_next = __cur->_M_next;
+ __cur->_M_next = __tmp;
+ ++_M_num_elements;
+ return iterator(__tmp, this);
+ }
+
+ _Node* __tmp = _M_new_node(__obj);
+ __tmp->_M_next = __first;
+ _M_buckets[__n] = __tmp;
+ ++_M_num_elements;
+ return iterator(__tmp, this);
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::reference
+hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::find_or_insert(const value_type& __obj)
+{
+ resize(_M_num_elements + 1);
+
+ size_type __n = _M_bkt_num(__obj);
+ _Node* __first = _M_buckets[__n];
+
+ for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
+ if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj)))
+ return __cur->_M_val;
+
+ _Node* __tmp = _M_new_node(__obj);
+ __tmp->_M_next = __first;
+ _M_buckets[__n] = __tmp;
+ ++_M_num_elements;
+ return __tmp->_M_val;
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+std::pair<typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::iterator,
+ typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::iterator>
+hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::equal_range(const key_type& __key)
+{
+ typedef std::pair<iterator, iterator> _Pii;
+ const size_type __n = _M_bkt_num_key(__key);
+
+ for (_Node* __first = _M_buckets[__n]; __first; __first = __first->_M_next)
+ if (_M_equals(_M_get_key(__first->_M_val), __key)) {
+ for (_Node* __cur = __first->_M_next; __cur; __cur = __cur->_M_next)
+ if (!_M_equals(_M_get_key(__cur->_M_val), __key))
+ return _Pii(iterator(__first, this), iterator(__cur, this));
+ for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m)
+ if (_M_buckets[__m])
+ return _Pii(iterator(__first, this),
+ iterator(_M_buckets[__m], this));
+ return _Pii(iterator(__first, this), end());
+ }
+ return _Pii(end(), end());
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+std::pair<typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::const_iterator,
+ typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::const_iterator>
+hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
+ ::equal_range(const key_type& __key) const
+{
+ typedef std::pair<const_iterator, const_iterator> _Pii;
+ const size_type __n = _M_bkt_num_key(__key);
+
+ for (const _Node* __first = _M_buckets[__n] ;
+ __first;
+ __first = __first->_M_next) {
+ if (_M_equals(_M_get_key(__first->_M_val), __key)) {
+ for (const _Node* __cur = __first->_M_next;
+ __cur;
+ __cur = __cur->_M_next)
+ if (!_M_equals(_M_get_key(__cur->_M_val), __key))
+ return _Pii(const_iterator(__first, this),
+ const_iterator(__cur, this));
+ for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m)
+ if (_M_buckets[__m])
+ return _Pii(const_iterator(__first, this),
+ const_iterator(_M_buckets[__m], this));
+ return _Pii(const_iterator(__first, this), end());
+ }
+ }
+ return _Pii(end(), end());
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::size_type
+hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::erase(const key_type& __key)
+{
+ const size_type __n = _M_bkt_num_key(__key);
+ _Node* __first = _M_buckets[__n];
+ size_type __erased = 0;
+
+ if (__first) {
+ _Node* __cur = __first;
+ _Node* __next = __cur->_M_next;
+ while (__next) {
+ if (_M_equals(_M_get_key(__next->_M_val), __key)) {
+ __cur->_M_next = __next->_M_next;
+ _M_delete_node(__next);
+ __next = __cur->_M_next;
+ ++__erased;
+ --_M_num_elements;
+ }
+ else {
+ __cur = __next;
+ __next = __cur->_M_next;
+ }
+ }
+ if (_M_equals(_M_get_key(__first->_M_val), __key)) {
+ _M_buckets[__n] = __first->_M_next;
+ _M_delete_node(__first);
+ ++__erased;
+ --_M_num_elements;
+ }
+ }
+ return __erased;
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::erase(const iterator& __it)
+{
+ _Node* __p = __it._M_cur;
+ if (__p) {
+ const size_type __n = _M_bkt_num(__p->_M_val);
+ _Node* __cur = _M_buckets[__n];
+
+ if (__cur == __p) {
+ _M_buckets[__n] = __cur->_M_next;
+ _M_delete_node(__cur);
+ --_M_num_elements;
+ }
+ else {
+ _Node* __next = __cur->_M_next;
+ while (__next) {
+ if (__next == __p) {
+ __cur->_M_next = __next->_M_next;
+ _M_delete_node(__next);
+ --_M_num_elements;
+ break;
+ }
+ else {
+ __cur = __next;
+ __next = __cur->_M_next;
+ }
+ }
+ }
+ }
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
+ ::erase(iterator __first, iterator __last)
+{
+ size_type __f_bucket = __first._M_cur ?
+ _M_bkt_num(__first._M_cur->_M_val) : _M_buckets.size();
+ size_type __l_bucket = __last._M_cur ?
+ _M_bkt_num(__last._M_cur->_M_val) : _M_buckets.size();
+
+ if (__first._M_cur == __last._M_cur)
+ return;
+ else if (__f_bucket == __l_bucket)
+ _M_erase_bucket(__f_bucket, __first._M_cur, __last._M_cur);
+ else {
+ _M_erase_bucket(__f_bucket, __first._M_cur, 0);
+ for (size_type __n = __f_bucket + 1; __n < __l_bucket; ++__n)
+ _M_erase_bucket(__n, 0);
+ if (__l_bucket != _M_buckets.size())
+ _M_erase_bucket(__l_bucket, __last._M_cur);
+ }
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+inline void
+hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::erase(const_iterator __first,
+ const_iterator __last)
+{
+ erase(iterator(const_cast<_Node*>(__first._M_cur),
+ const_cast<hashtable*>(__first._M_ht)),
+ iterator(const_cast<_Node*>(__last._M_cur),
+ const_cast<hashtable*>(__last._M_ht)));
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+inline void
+hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::erase(const const_iterator& __it)
+{
+ erase(iterator(const_cast<_Node*>(__it._M_cur),
+ const_cast<hashtable*>(__it._M_ht)));
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
+ ::resize(size_type __num_elements_hint)
+{
+ const size_type __old_n = _M_buckets.size();
+ if (__num_elements_hint > __old_n) {
+ const size_type __n = _M_next_size(__num_elements_hint);
+ if (__n > __old_n) {
+ _M_buckets_type __tmp(
+ __n, (_Node*)(0),
+ _M_buckets.get_allocator());
+ try {
+ for (size_type __bucket = 0; __bucket < __old_n; ++__bucket) {
+ _Node* __first = _M_buckets[__bucket];
+ while (__first) {
+ size_type __new_bucket = _M_bkt_num(__first->_M_val, __n);
+ _M_buckets[__bucket] = __first->_M_next;
+ __first->_M_next = __tmp[__new_bucket];
+ __tmp[__new_bucket] = __first;
+ __first = _M_buckets[__bucket];
+ }
+ }
+ _M_buckets.swap(__tmp);
+ }
+ catch(...) {
+ for (size_type __bucket = 0; __bucket < __tmp.size(); ++__bucket) {
+ while (__tmp[__bucket]) {
+ _Node* __next = __tmp[__bucket]->_M_next;
+ _M_delete_node(__tmp[__bucket]);
+ __tmp[__bucket] = __next;
+ }
+ }
+ throw;
+ }
+ }
+ }
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
+ ::_M_erase_bucket(const size_type __n, _Node* __first, _Node* __last)
+{
+ _Node* __cur = _M_buckets[__n];
+ if (__cur == __first)
+ _M_erase_bucket(__n, __last);
+ else {
+ _Node* __next;
+ for (__next = __cur->_M_next;
+ __next != __first;
+ __cur = __next, __next = __cur->_M_next)
+ ;
+ while (__next != __last) {
+ __cur->_M_next = __next->_M_next;
+ _M_delete_node(__next);
+ __next = __cur->_M_next;
+ --_M_num_elements;
+ }
+ }
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
+ ::_M_erase_bucket(const size_type __n, _Node* __last)
+{
+ _Node* __cur = _M_buckets[__n];
+ while (__cur != __last) {
+ _Node* __next = __cur->_M_next;
+ _M_delete_node(__cur);
+ __cur = __next;
+ _M_buckets[__n] = __cur;
+ --_M_num_elements;
+ }
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::clear()
+{
+ for (size_type __i = 0; __i < _M_buckets.size(); ++__i) {
+ _Node* __cur = _M_buckets[__i];
+ while (__cur != 0) {
+ _Node* __next = __cur->_M_next;
+ _M_delete_node(__cur);
+ __cur = __next;
+ }
+ _M_buckets[__i] = 0;
+ }
+ _M_num_elements = 0;
+}
+
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
+ ::_M_copy_from(const hashtable& __ht)
+{
+ _M_buckets.clear();
+ _M_buckets.reserve(__ht._M_buckets.size());
+ _M_buckets.insert(_M_buckets.end(), __ht._M_buckets.size(), (_Node*) 0);
+ try {
+ for (size_type __i = 0; __i < __ht._M_buckets.size(); ++__i) {
+ const _Node* __cur = __ht._M_buckets[__i];
+ if (__cur) {
+ _Node* __copy = _M_new_node(__cur->_M_val);
+ _M_buckets[__i] = __copy;
+
+ for (_Node* __next = __cur->_M_next;
+ __next;
+ __cur = __next, __next = __cur->_M_next) {
+ __copy->_M_next = _M_new_node(__next->_M_val);
+ __copy = __copy->_M_next;
+ }
+ }
+ }
+ _M_num_elements = __ht._M_num_elements;
+ }
+ catch(...) {clear(); throw;}
+}
+
+} // namespace @KWSYS_NAMESPACE@
+
+// Undo warning suppression.
+#if defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wdeprecated")
+# pragma clang diagnostic pop
+# endif
+#endif
+
+#if defined(_MSC_VER)
+# pragma warning (pop)
+#endif
+
+#endif
diff --git a/Source/kwsys/kwsysHeaderDump.pl b/Source/kwsys/kwsysHeaderDump.pl
new file mode 100755
index 0000000..0dc4a52
--- /dev/null
+++ b/Source/kwsys/kwsysHeaderDump.pl
@@ -0,0 +1,50 @@
+#!/usr/bin/perl
+#=============================================================================
+# KWSys - Kitware System Library
+# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+if ( $#ARGV+1 < 2 )
+{
+ print "Usage: ./kwsysHeaderDump.pl <name> <header>\n";
+ exit(1);
+}
+
+$name = $ARGV[0];
+$max = 0;
+open(INFILE, $ARGV[1]);
+while (chomp ($line = <INFILE>))
+{
+ if (($line !~ /^\#/) &&
+ ($line =~ s/.*kwsys${name}_([A-Za-z0-9_]*).*/\1/) &&
+ ($i{$line}++ < 1))
+ {
+ push(@lines, "$line");
+ if (length($line) > $max)
+ {
+ $max = length($line);
+ }
+ }
+}
+close(INFILE);
+
+$width = $max + 13;
+print sprintf("#define %-${width}s kwsys_ns(${name})\n", "kwsys${name}");
+foreach $l (@lines)
+{
+ print sprintf("#define %-${width}s kwsys_ns(${name}_$l)\n",
+ "kwsys${name}_$l");
+}
+print "\n";
+print sprintf("# undef kwsys${name}\n");
+foreach $l (@lines)
+{
+ print sprintf("# undef kwsys${name}_$l\n");
+}
diff --git a/Source/kwsys/kwsysPlatformTests.cmake b/Source/kwsys/kwsysPlatformTests.cmake
new file mode 100644
index 0000000..0da0f63
--- /dev/null
+++ b/Source/kwsys/kwsysPlatformTests.cmake
@@ -0,0 +1,219 @@
+#=============================================================================
+# KWSys - Kitware System Library
+# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+SET(KWSYS_PLATFORM_TEST_FILE_C kwsysPlatformTestsC.c)
+SET(KWSYS_PLATFORM_TEST_FILE_CXX kwsysPlatformTestsCXX.cxx)
+
+MACRO(KWSYS_PLATFORM_TEST lang var description invert)
+ IF(NOT DEFINED ${var}_COMPILED)
+ MESSAGE(STATUS "${description}")
+ TRY_COMPILE(${var}_COMPILED
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}}
+ COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS}
+ CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=${KWSYS_PLATFORM_TEST_LINK_LIBRARIES}"
+ OUTPUT_VARIABLE OUTPUT)
+ IF(${var}_COMPILED)
+ FILE(APPEND
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "${description} compiled with the following output:\n${OUTPUT}\n\n")
+ ELSE()
+ FILE(APPEND
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "${description} failed to compile with the following output:\n${OUTPUT}\n\n")
+ ENDIF()
+ IF(${invert} MATCHES INVERT)
+ IF(${var}_COMPILED)
+ MESSAGE(STATUS "${description} - no")
+ ELSE()
+ MESSAGE(STATUS "${description} - yes")
+ ENDIF()
+ ELSE()
+ IF(${var}_COMPILED)
+ MESSAGE(STATUS "${description} - yes")
+ ELSE()
+ MESSAGE(STATUS "${description} - no")
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ IF(${invert} MATCHES INVERT)
+ IF(${var}_COMPILED)
+ SET(${var} 0)
+ ELSE()
+ SET(${var} 1)
+ ENDIF()
+ ELSE()
+ IF(${var}_COMPILED)
+ SET(${var} 1)
+ ELSE()
+ SET(${var} 0)
+ ENDIF()
+ ENDIF()
+ENDMACRO()
+
+MACRO(KWSYS_PLATFORM_TEST_RUN lang var description invert)
+ IF(NOT DEFINED ${var})
+ MESSAGE(STATUS "${description}")
+ TRY_RUN(${var} ${var}_COMPILED
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}}
+ COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS}
+ OUTPUT_VARIABLE OUTPUT)
+
+ # Note that ${var} will be a 0 return value on success.
+ IF(${var}_COMPILED)
+ IF(${var})
+ FILE(APPEND
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "${description} compiled but failed to run with the following output:\n${OUTPUT}\n\n")
+ ELSE()
+ FILE(APPEND
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "${description} compiled and ran with the following output:\n${OUTPUT}\n\n")
+ ENDIF()
+ ELSE()
+ FILE(APPEND
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "${description} failed to compile with the following output:\n${OUTPUT}\n\n")
+ SET(${var} -1 CACHE INTERNAL "${description} failed to compile.")
+ ENDIF()
+
+ IF(${invert} MATCHES INVERT)
+ IF(${var}_COMPILED)
+ IF(${var})
+ MESSAGE(STATUS "${description} - yes")
+ ELSE()
+ MESSAGE(STATUS "${description} - no")
+ ENDIF()
+ ELSE()
+ MESSAGE(STATUS "${description} - failed to compile")
+ ENDIF()
+ ELSE()
+ IF(${var}_COMPILED)
+ IF(${var})
+ MESSAGE(STATUS "${description} - no")
+ ELSE()
+ MESSAGE(STATUS "${description} - yes")
+ ENDIF()
+ ELSE()
+ MESSAGE(STATUS "${description} - failed to compile")
+ ENDIF()
+ ENDIF()
+ ENDIF()
+
+ IF(${invert} MATCHES INVERT)
+ IF(${var}_COMPILED)
+ IF(${var})
+ SET(${var} 1)
+ ELSE()
+ SET(${var} 0)
+ ENDIF()
+ ELSE()
+ SET(${var} 1)
+ ENDIF()
+ ELSE()
+ IF(${var}_COMPILED)
+ IF(${var})
+ SET(${var} 0)
+ ELSE()
+ SET(${var} 1)
+ ENDIF()
+ ELSE()
+ SET(${var} 0)
+ ENDIF()
+ ENDIF()
+ENDMACRO()
+
+MACRO(KWSYS_PLATFORM_C_TEST var description invert)
+ SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES})
+ SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS})
+ KWSYS_PLATFORM_TEST(C "${var}" "${description}" "${invert}")
+ SET(KWSYS_PLATFORM_TEST_DEFINES)
+ SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS)
+ENDMACRO()
+
+MACRO(KWSYS_PLATFORM_C_TEST_RUN var description invert)
+ SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES})
+ SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS})
+ KWSYS_PLATFORM_TEST_RUN(C "${var}" "${description}" "${invert}")
+ SET(KWSYS_PLATFORM_TEST_DEFINES)
+ SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS)
+ENDMACRO()
+
+MACRO(KWSYS_PLATFORM_CXX_TEST var description invert)
+ SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES})
+ SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS})
+ SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES ${KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES})
+ KWSYS_PLATFORM_TEST(CXX "${var}" "${description}" "${invert}")
+ SET(KWSYS_PLATFORM_TEST_DEFINES)
+ SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS)
+ SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES)
+ENDMACRO()
+
+MACRO(KWSYS_PLATFORM_CXX_TEST_RUN var description invert)
+ SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES})
+ SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS})
+ KWSYS_PLATFORM_TEST_RUN(CXX "${var}" "${description}" "${invert}")
+ SET(KWSYS_PLATFORM_TEST_DEFINES)
+ SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS)
+ENDMACRO()
+
+#-----------------------------------------------------------------------------
+# KWSYS_PLATFORM_INFO_TEST(lang var description)
+#
+# Compile test named by ${var} and store INFO strings extracted from binary.
+MACRO(KWSYS_PLATFORM_INFO_TEST lang var description)
+ # We can implement this macro on CMake 2.6 and above.
+ IF("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.6)
+ SET(${var} "")
+ ELSE()
+ # Choose a location for the result binary.
+ SET(KWSYS_PLATFORM_INFO_FILE
+ ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${var}.bin)
+
+ # Compile the test binary.
+ IF(NOT EXISTS ${KWSYS_PLATFORM_INFO_FILE})
+ MESSAGE(STATUS "${description}")
+ TRY_COMPILE(${var}_COMPILED
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}}
+ COMPILE_DEFINITIONS -DTEST_${var}
+ ${KWSYS_PLATFORM_${lang}_TEST_DEFINES}
+ ${KWSYS_PLATFORM_${lang}_TEST_EXTRA_FLAGS}
+ OUTPUT_VARIABLE OUTPUT
+ COPY_FILE ${KWSYS_PLATFORM_INFO_FILE}
+ )
+ IF(${var}_COMPILED)
+ FILE(APPEND
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "${description} compiled with the following output:\n${OUTPUT}\n\n")
+ ELSE()
+ FILE(APPEND
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "${description} failed to compile with the following output:\n${OUTPUT}\n\n")
+ ENDIF()
+ IF(${var}_COMPILED)
+ MESSAGE(STATUS "${description} - compiled")
+ ELSE()
+ MESSAGE(STATUS "${description} - failed")
+ ENDIF()
+ ENDIF()
+
+ # Parse info strings out of the compiled binary.
+ IF(${var}_COMPILED)
+ FILE(STRINGS ${KWSYS_PLATFORM_INFO_FILE} ${var} REGEX "INFO:[A-Za-z0-9]+\\[[^]]*\\]")
+ ELSE()
+ SET(${var} "")
+ ENDIF()
+
+ SET(KWSYS_PLATFORM_INFO_FILE)
+ ENDIF()
+ENDMACRO()
diff --git a/Source/kwsys/kwsysPlatformTestsC.c b/Source/kwsys/kwsysPlatformTestsC.c
new file mode 100644
index 0000000..e602964
--- /dev/null
+++ b/Source/kwsys/kwsysPlatformTestsC.c
@@ -0,0 +1,100 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+ Macros to define main() in a cross-platform way.
+
+ Usage:
+
+ int KWSYS_PLATFORM_TEST_C_MAIN()
+ {
+ return 0;
+ }
+
+ int KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv)
+ {
+ (void)argc; (void)argv;
+ return 0;
+ }
+*/
+#if defined(__CLASSIC_C__)
+# define KWSYS_PLATFORM_TEST_C_MAIN() \
+ main()
+# define KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv) \
+ main(argc,argv) int argc; char* argv[];
+#else
+# define KWSYS_PLATFORM_TEST_C_MAIN() \
+ main(void)
+# define KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv) \
+ main(int argc, char* argv[])
+#endif
+
+/*--------------------------------------------------------------------------*/
+#ifdef TEST_KWSYS_C_HAS_PTRDIFF_T
+#include <stddef.h>
+int f(ptrdiff_t n) { return n > 0; }
+int KWSYS_PLATFORM_TEST_C_MAIN()
+{
+ char* p = 0;
+ ptrdiff_t d = p - p;
+ (void)d;
+ return f(p - p);
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+#ifdef TEST_KWSYS_C_HAS_SSIZE_T
+#include <unistd.h>
+int f(ssize_t n) { return (int)n; }
+int KWSYS_PLATFORM_TEST_C_MAIN()
+{
+ ssize_t n = 0;
+ return f(n);
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+#ifdef TEST_KWSYS_C_TYPE_MACROS
+char* info_macros =
+#if defined(__SIZEOF_SHORT__)
+"INFO:macro[__SIZEOF_SHORT__]\n"
+#endif
+#if defined(__SIZEOF_INT__)
+"INFO:macro[__SIZEOF_INT__]\n"
+#endif
+#if defined(__SIZEOF_LONG__)
+"INFO:macro[__SIZEOF_LONG__]\n"
+#endif
+#if defined(__SIZEOF_LONG_LONG__)
+"INFO:macro[__SIZEOF_LONG_LONG__]\n"
+#endif
+#if defined(__SHORT_MAX__)
+"INFO:macro[__SHORT_MAX__]\n"
+#endif
+#if defined(__INT_MAX__)
+"INFO:macro[__INT_MAX__]\n"
+#endif
+#if defined(__LONG_MAX__)
+"INFO:macro[__LONG_MAX__]\n"
+#endif
+#if defined(__LONG_LONG_MAX__)
+"INFO:macro[__LONG_LONG_MAX__]\n"
+#endif
+ "";
+
+int KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv)
+{
+ int require = 0;
+ require += info_macros[argc];
+ (void)argv;
+ return require;
+}
+#endif
diff --git a/Source/kwsys/kwsysPlatformTestsCXX.cxx b/Source/kwsys/kwsysPlatformTestsCXX.cxx
new file mode 100644
index 0000000..fc87f91
--- /dev/null
+++ b/Source/kwsys/kwsysPlatformTestsCXX.cxx
@@ -0,0 +1,351 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifdef TEST_KWSYS_CXX_HAS_CSTDIO
+#include <cstdio>
+int main() { return 0; }
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_LONG_LONG
+long long f(long long n) { return n; }
+int main()
+{
+ long long n = 0;
+ return static_cast<int>(f(n));
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS___INT64
+__int64 f(__int64 n) { return n; }
+int main()
+{
+ __int64 n = 0;
+ return static_cast<int>(f(n));
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIM
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+int main()
+{
+ struct stat stat1;
+ (void)stat1.st_mtim.tv_sec;
+ (void)stat1.st_mtim.tv_nsec;
+ return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIMESPEC
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+int main()
+{
+ struct stat stat1;
+ (void)stat1.st_mtimespec.tv_sec;
+ (void)stat1.st_mtimespec.tv_nsec;
+ return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_SAME_LONG_AND___INT64
+void function(long**) {}
+int main()
+{
+ __int64** p = 0;
+ function(p);
+ return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_SAME_LONG_LONG_AND___INT64
+void function(long long**) {}
+int main()
+{
+ __int64** p = 0;
+ function(p);
+ return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_IOS_HAS_ISTREAM_LONG_LONG
+# include <iostream>
+int test_istream(std::istream& is, long long& x)
+{
+ return (is >> x)? 1:0;
+}
+int main()
+{
+ long long x = 0;
+ return test_istream(std::cin, x);
+}
+#endif
+
+#ifdef TEST_KWSYS_IOS_HAS_OSTREAM_LONG_LONG
+# include <iostream>
+int test_ostream(std::ostream& os, long long x)
+{
+ return (os << x)? 1:0;
+}
+int main()
+{
+ long long x = 0;
+ return test_ostream(std::cout, x);
+}
+#endif
+
+#ifdef TEST_KWSYS_IOS_HAS_ISTREAM___INT64
+# include <iostream>
+int test_istream(std::istream& is, __int64& x)
+{
+ return (is >> x)? 1:0;
+}
+int main()
+{
+ __int64 x = 0;
+ return test_istream(std::cin, x);
+}
+#endif
+
+#ifdef TEST_KWSYS_IOS_HAS_OSTREAM___INT64
+# include <iostream>
+int test_ostream(std::ostream& os, __int64 x)
+{
+ return (os << x)? 1:0;
+}
+int main()
+{
+ __int64 x = 0;
+ return test_ostream(std::cout, x);
+}
+#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 <sys/stat.h>
+#include <assert.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()
+{
+ return setenv("A", "B", 1);
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_UNSETENV
+#include <stdlib.h>
+int main()
+{
+ unsetenv("A");
+ return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
+#include <stdlib.h>
+int main()
+{
+ char* e = environ[0];
+ return e? 0:1;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_GETLOADAVG
+// Match feature definitions from SystemInformation.cxx
+#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
+# define _GNU_SOURCE
+#endif
+#include <stdlib.h>
+int main()
+{
+ double loadavg[3] = { 0.0, 0.0, 0.0 };
+ return getloadavg(loadavg, 3);
+}
+#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()
+{
+ struct rlimit64 rlim;
+ return getrlimit64(0,&rlim);
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_ATOLL
+#include <stdlib.h>
+int main()
+{
+ const char *str="1024";
+ return static_cast<int>(atoll(str));
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_ATOL
+#include <stdlib.h>
+int main()
+{
+ const char *str="1024";
+ return static_cast<int>(atol(str));
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS__ATOI64
+#include <stdlib.h>
+int main()
+{
+ const char *str="1024";
+ return static_cast<int>(_atoi64(str));
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_UTIMES
+#include <sys/time.h>
+int main()
+{
+ struct timeval* current_time = 0;
+ return utimes("/example", current_time);
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_UTIMENSAT
+#include <fcntl.h>
+#include <sys/stat.h>
+int main()
+{
+ struct timespec times[2] = {{0,UTIME_OMIT},{0,UTIME_NOW}};
+ return utimensat(AT_FDCWD, "/example", times, AT_SYMLINK_NOFOLLOW);
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_BACKTRACE
+#if defined(__PATHSCALE__) || defined(__PATHCC__) \
+ || (defined(__LSB_VERSION__) && (__LSB_VERSION__ < 41))
+backtrace doesnt work with this compiler or os
+#endif
+#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
+# define _GNU_SOURCE
+#endif
+#include <execinfo.h>
+int main()
+{
+ void *stackSymbols[256];
+ backtrace(stackSymbols,256);
+ backtrace_symbols(&stackSymbols[0],1);
+ return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_DLADDR
+#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
+# define _GNU_SOURCE
+#endif
+#include <dlfcn.h>
+int main()
+{
+ Dl_info info;
+ int ierr=dladdr((void*)main,&info);
+ return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_CXXABI
+#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
+# define _GNU_SOURCE
+#endif
+#if defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5130 \
+ && __linux && __SUNPRO_CC_COMPAT == 'G'
+# include <iostream>
+#endif
+#include <cxxabi.h>
+int main()
+{
+ int status = 0;
+ size_t bufferLen = 512;
+ char buffer[512] = {'\0'};
+ const char *function="_ZN5kwsys17SystemInformation15GetProgramStackEii";
+ char *demangledFunction =
+ abi::__cxa_demangle(function, buffer, &bufferLen, &status);
+ return status;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM
+int main()
+{
+ int a = 1;
+ __asm {
+ xor EBX, EBX;
+ mov a, EBX;
+ }
+
+ return a;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM_CPUID
+int main()
+{
+ int a = 0;
+ __asm {
+ xor EAX, EAX;
+ cpuid;
+ mov a, EAX;
+ }
+
+ return a;
+}
+#endif
+
+#ifdef TEST_KWSYS_STL_HAS_WSTRING
+#include <string>
+void f(std ::wstring*) {}
+int main() { return 0; }
+#endif
diff --git a/Source/kwsys/kwsysPrivate.h b/Source/kwsys/kwsysPrivate.h
new file mode 100644
index 0000000..3a26c26
--- /dev/null
+++ b/Source/kwsys/kwsysPrivate.h
@@ -0,0 +1,41 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef KWSYS_NAMESPACE
+# error "Do not include kwsysPrivate.h outside of kwsys c and cxx files."
+#endif
+
+#ifndef _kwsysPrivate_h
+#define _kwsysPrivate_h
+
+/*
+ Define KWSYS_HEADER macro to help the c and cxx files include kwsys
+ headers from the configured namespace directory. The macro can be
+ used like this:
+
+ #include KWSYS_HEADER(Directory.hxx)
+ #include KWSYS_HEADER(std/vector)
+*/
+#define KWSYS_HEADER(x) KWSYS_HEADER0(KWSYS_NAMESPACE/x)
+#define KWSYS_HEADER0(x) KWSYS_HEADER1(x)
+#define KWSYS_HEADER1(x) <x>
+
+/*
+ Define KWSYS_NAMESPACE_STRING to be a string constant containing the
+ name configured for this instance of the kwsys library.
+*/
+#define KWSYS_NAMESPACE_STRING KWSYS_NAMESPACE_STRING0(KWSYS_NAMESPACE)
+#define KWSYS_NAMESPACE_STRING0(x) KWSYS_NAMESPACE_STRING1(x)
+#define KWSYS_NAMESPACE_STRING1(x) #x
+
+#else
+# error "kwsysPrivate.h included multiple times."
+#endif
diff --git a/Source/kwsys/testCommandLineArguments.cxx b/Source/kwsys/testCommandLineArguments.cxx
new file mode 100644
index 0000000..525522d
--- /dev/null
+++ b/Source/kwsys/testCommandLineArguments.cxx
@@ -0,0 +1,187 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(CommandLineArguments.hxx)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "CommandLineArguments.hxx.in"
+#endif
+
+#include <iostream>
+#include <vector>
+
+#include <stddef.h> /* size_t */
+#include <string.h> /* strcmp */
+
+static void* random_ptr = reinterpret_cast<void*>(0x123);
+
+static int argument(const char* arg, const char* value, void* call_data)
+{
+ std::cout << "Got argument: \"" << arg << "\" value: \"" << (value?value:"(null)") << "\"" << std::endl;
+ if ( call_data != random_ptr )
+ {
+ std::cerr << "Problem processing call_data" << std::endl;
+ return 0;
+ }
+ return 1;
+}
+
+static int unknown_argument(const char* argument, void* call_data)
+{
+ std::cout << "Got unknown argument: \"" << argument << "\"" << std::endl;
+ if ( call_data != random_ptr )
+ {
+ std::cerr << "Problem processing call_data" << std::endl;
+ return 0;
+ }
+ return 1;
+}
+
+static bool CompareTwoItemsOnList(bool i1, bool i2) { return i1 == i2; }
+static bool CompareTwoItemsOnList(int i1, int i2) { return i1 == i2; }
+static bool CompareTwoItemsOnList(double i1, double i2) { return i1 == i2; }
+static bool CompareTwoItemsOnList(const char* i1,
+ const char* i2) { return strcmp(i1, i2) == 0; }
+static bool CompareTwoItemsOnList(const std::string& i1,
+ const std::string& i2) { return i1 == i2; }
+
+int testCommandLineArguments(int argc, char* argv[])
+{
+ // Example run: ./testCommandLineArguments --some-int-variable 4
+ // --another-bool-variable --some-bool-variable=yes
+ // --some-stl-string-variable=foobar --set-bool-arg1 --set-bool-arg2
+ // --some-string-variable=hello
+
+ int res = 0;
+ kwsys::CommandLineArguments arg;
+ arg.Initialize(argc, argv);
+
+ // For error handling
+ arg.SetClientData(random_ptr);
+ arg.SetUnknownArgumentCallback(unknown_argument);
+
+ int some_int_variable = 10;
+ double some_double_variable = 10.10;
+ char* some_string_variable = 0;
+ std::string some_stl_string_variable = "";
+ bool some_bool_variable = false;
+ bool some_bool_variable1 = false;
+ bool bool_arg1 = false;
+ int bool_arg2 = 0;
+
+ std::vector<int> numbers_argument;
+ int valid_numbers[] = { 5, 1, 8, 3, 7, 1, 3, 9, 7, 1 };
+
+ std::vector<double> doubles_argument;
+ double valid_doubles[] = { 12.5, 1.31, 22 };
+
+ std::vector<bool> bools_argument;
+ bool valid_bools[] = { true, true, false };
+
+ std::vector<char*> strings_argument;
+ const char* valid_strings[] = { "andy", "bill", "brad", "ken" };
+
+ std::vector<std::string> stl_strings_argument;
+ std::string valid_stl_strings[] = { "ken", "brad", "bill", "andy" };
+
+ typedef kwsys::CommandLineArguments argT;
+
+ arg.AddArgument("--some-int-variable", argT::SPACE_ARGUMENT, &some_int_variable, "Set some random int variable");
+ arg.AddArgument("--some-double-variable", argT::CONCAT_ARGUMENT, &some_double_variable, "Set some random double variable");
+ arg.AddArgument("--some-string-variable", argT::EQUAL_ARGUMENT, &some_string_variable, "Set some random string variable");
+ arg.AddArgument("--some-stl-string-variable", argT::EQUAL_ARGUMENT, &some_stl_string_variable, "Set some random stl string variable");
+ arg.AddArgument("--some-bool-variable", argT::EQUAL_ARGUMENT, &some_bool_variable, "Set some random bool variable");
+ arg.AddArgument("--another-bool-variable", argT::NO_ARGUMENT, &some_bool_variable1, "Set some random bool variable 1");
+ arg.AddBooleanArgument("--set-bool-arg1", &bool_arg1, "Test AddBooleanArgument 1");
+ arg.AddBooleanArgument("--set-bool-arg2", &bool_arg2, "Test AddBooleanArgument 2");
+ arg.AddArgument("--some-multi-argument", argT::MULTI_ARGUMENT, &numbers_argument, "Some multiple values variable");
+ arg.AddArgument("-N", argT::SPACE_ARGUMENT, &doubles_argument, "Some explicit multiple values variable");
+ arg.AddArgument("-BB", argT::CONCAT_ARGUMENT, &bools_argument, "Some explicit multiple values variable");
+ arg.AddArgument("-SS", argT::EQUAL_ARGUMENT, &strings_argument, "Some explicit multiple values variable");
+ arg.AddArgument("-SSS", argT::MULTI_ARGUMENT, &stl_strings_argument, "Some explicit multiple values variable");
+
+ arg.AddCallback("-A", argT::NO_ARGUMENT, argument, random_ptr, "Some option -A. This option has a multiline comment. It should demonstrate how the code splits lines.");
+ arg.AddCallback("-B", argT::SPACE_ARGUMENT, argument, random_ptr, "Option -B takes argument with space");
+ arg.AddCallback("-C", argT::EQUAL_ARGUMENT, argument, random_ptr, "Option -C takes argument after =");
+ arg.AddCallback("-D", argT::CONCAT_ARGUMENT, argument, random_ptr, "This option takes concatinated argument");
+ arg.AddCallback("--long1", argT::NO_ARGUMENT, argument, random_ptr, "-A");
+ arg.AddCallback("--long2", argT::SPACE_ARGUMENT, argument, random_ptr, "-B");
+ arg.AddCallback("--long3", argT::EQUAL_ARGUMENT, argument, random_ptr, "Same as -C but a bit different");
+ arg.AddCallback("--long4", argT::CONCAT_ARGUMENT, argument, random_ptr, "-C");
+
+ if ( !arg.Parse() )
+ {
+ std::cerr << "Problem parsing arguments" << std::endl;
+ res = 1;
+ }
+ std::cout << "Help: " << arg.GetHelp() << std::endl;
+
+ std::cout << "Some int variable was set to: " << some_int_variable << std::endl;
+ std::cout << "Some double variable was set to: " << some_double_variable << std::endl;
+ if ( some_string_variable && strcmp(some_string_variable, "test string with space") == 0)
+ {
+ std::cout << "Some string variable was set to: " << some_string_variable << std::endl;
+ delete [] some_string_variable;
+ }
+ else
+ {
+ std::cerr << "Problem setting string variable" << std::endl;
+ res = 1;
+ }
+ size_t cc;
+#define CompareTwoLists(list1, list_valid, lsize) \
+ if ( list1.size() != lsize ) \
+ { \
+ std::cerr << "Problem setting " #list1 ". Size is: " << list1.size() \
+ << " should be: " << lsize << std::endl; \
+ res = 1; \
+ } \
+ else \
+ { \
+ std::cout << #list1 " argument set:"; \
+ for ( cc =0; cc < lsize; ++ cc ) \
+ { \
+ std::cout << " " << list1[cc]; \
+ if ( !CompareTwoItemsOnList(list1[cc], list_valid[cc]) ) \
+ { \
+ std::cerr << "Problem setting " #list1 ". Value of " \
+ << cc << " is: [" << list1[cc] << "] <> [" \
+ << list_valid[cc] << "]" << std::endl; \
+ res = 1; \
+ break; \
+ } \
+ } \
+ std::cout << std::endl; \
+ }
+
+ CompareTwoLists(numbers_argument, valid_numbers, 10);
+ CompareTwoLists(doubles_argument, valid_doubles, 3);
+ CompareTwoLists(bools_argument, valid_bools, 3);
+ CompareTwoLists(strings_argument, valid_strings, 4);
+ CompareTwoLists(stl_strings_argument, valid_stl_strings, 4);
+
+ std::cout << "Some STL String variable was set to: " << some_stl_string_variable << std::endl;
+ std::cout << "Some bool variable was set to: " << some_bool_variable << std::endl;
+ std::cout << "Some bool variable was set to: " << some_bool_variable1 << std::endl;
+ std::cout << "bool_arg1 variable was set to: " << bool_arg1 << std::endl;
+ std::cout << "bool_arg2 variable was set to: " << bool_arg2 << std::endl;
+ std::cout << std::endl;
+
+ for ( cc = 0; cc < strings_argument.size(); ++ cc )
+ {
+ delete [] strings_argument[cc];
+ strings_argument[cc] = 0;
+ }
+ return res;
+}
diff --git a/Source/kwsys/testCommandLineArguments1.cxx b/Source/kwsys/testCommandLineArguments1.cxx
new file mode 100644
index 0000000..6eb465d
--- /dev/null
+++ b/Source/kwsys/testCommandLineArguments1.cxx
@@ -0,0 +1,108 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(CommandLineArguments.hxx)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "CommandLineArguments.hxx.in"
+#endif
+
+#include <iostream>
+#include <vector>
+
+#include <assert.h> /* assert */
+#include <string.h> /* strcmp */
+
+int testCommandLineArguments1(int argc, char* argv[])
+{
+ kwsys::CommandLineArguments arg;
+ arg.Initialize(argc, argv);
+
+ int n = 0;
+ char* m = 0;
+ std::string p;
+ int res = 0;
+
+ typedef kwsys::CommandLineArguments argT;
+ arg.AddArgument("-n", argT::SPACE_ARGUMENT, &n, "Argument N");
+ arg.AddArgument("-m", argT::EQUAL_ARGUMENT, &m, "Argument M");
+ arg.AddBooleanArgument("-p", &p, "Argument P");
+
+ arg.StoreUnusedArguments(true);
+
+ if ( !arg.Parse() )
+ {
+ std::cerr << "Problem parsing arguments" << std::endl;
+ res = 1;
+ }
+ if ( n != 24 )
+ {
+ std::cout << "Problem setting N. Value of N: " << n << std::endl;
+ res = 1;
+ }
+ if ( !m || strcmp(m, "test value") != 0 )
+ {
+ std::cout << "Problem setting M. Value of M: " << m << std::endl;
+ res = 1;
+ }
+ if ( p != "1" )
+ {
+ std::cout << "Problem setting P. Value of P: " << p << std::endl;
+ res = 1;
+ }
+ std::cout << "Value of N: " << n << std::endl;
+ std::cout << "Value of M: " << m << std::endl;
+ std::cout << "Value of P: " << p << std::endl;
+ if ( m )
+ {
+ delete [] m;
+ }
+
+ char** newArgv = 0;
+ int newArgc = 0;
+ arg.GetUnusedArguments(&newArgc, &newArgv);
+ int cc;
+ const char* valid_unused_args[9] = {
+ 0, "--ignored", "--second-ignored", "third-ignored",
+ "some", "junk", "at", "the", "end"
+ };
+ if ( newArgc != 9 )
+ {
+ std::cerr << "Bad number of unused arguments: " << newArgc << std::endl;
+ res = 1;
+ }
+ for ( cc = 0; cc < newArgc; ++ cc )
+ {
+ assert(newArgv[cc]); /* Quiet Clang scan-build. */
+ std::cout << "Unused argument[" << cc << "] = [" << newArgv[cc] << "]"
+ << std::endl;
+ if ( cc >= 9 )
+ {
+ std::cerr << "Too many unused arguments: " << cc << std::endl;
+ res = 1;
+ }
+ else if ( valid_unused_args[cc] &&
+ strcmp(valid_unused_args[cc], newArgv[cc]) != 0 )
+ {
+ std::cerr << "Bad unused argument [" << cc << "] \""
+ << newArgv[cc] << "\" should be: \"" << valid_unused_args[cc] << "\""
+ << std::endl;
+ res = 1;
+ }
+ }
+ arg.DeleteRemainingArguments(newArgc, &newArgv);
+
+ return res;
+}
+
diff --git a/Source/kwsys/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx
new file mode 100644
index 0000000..7c58769
--- /dev/null
+++ b/Source/kwsys/testDynamicLoader.cxx
@@ -0,0 +1,128 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+
+#include KWSYS_HEADER(DynamicLoader.hxx)
+
+#if defined(__BEOS__) || defined(__HAIKU__)
+#include <be/kernel/OS.h> /* disable_debugger() API. */
+#endif
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "DynamicLoader.hxx.in"
+#endif
+
+#include <string>
+#include <iostream>
+
+// Include with <> instead of "" to avoid getting any in-source copy
+// left on disk.
+#include <testSystemTools.h>
+
+static std::string GetLibName(const char* lname)
+{
+ // Construct proper name of lib
+ std::string slname;
+ slname = EXECUTABLE_OUTPUT_PATH;
+#ifdef CMAKE_INTDIR
+ slname += "/";
+ slname += CMAKE_INTDIR;
+#endif
+ slname += "/";
+ slname += kwsys::DynamicLoader::LibPrefix();
+ slname += lname;
+ slname += kwsys::DynamicLoader::LibExtension();
+
+ return slname;
+}
+
+/* libname = Library name (proper prefix, proper extension)
+ * System = symbol to lookup in libname
+ * r1: should OpenLibrary succeed ?
+ * r2: should GetSymbolAddress succeed ?
+ * r3: should CloseLibrary succeed ?
+ */
+static int TestDynamicLoader(const char* libname, const char* symbol, int r1, int r2, int r3)
+{
+ std::cerr << "Testing: " << libname << std::endl;
+ kwsys::DynamicLoader::LibraryHandle l
+ = kwsys::DynamicLoader::OpenLibrary(libname);
+ // If result is incompatible with expectation just fails (xor):
+ if( (r1 && !l) || (!r1 && l) )
+ {
+ std::cerr
+ << 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;
+ return 1;
+ }
+#ifndef __APPLE__
+ int s = kwsys::DynamicLoader::CloseLibrary(l);
+ if( (r3 && !s) || (!r3 && s) )
+ {
+ std::cerr
+ << kwsys::DynamicLoader::LastError() << std::endl;
+ return 1;
+ }
+#else
+ (void)r3;
+#endif
+ return 0;
+}
+
+int testDynamicLoader(int argc, char *argv[])
+{
+#if defined(_WIN32)
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+#elif defined(__BEOS__) || defined(__HAIKU__)
+ disable_debugger(1);
+#endif
+ int res = 0;
+ if( argc == 3 )
+ {
+ // User specify a libname and symbol to check.
+ res = TestDynamicLoader(argv[1], argv[2],1,1,1);
+ return res;
+ }
+
+// dlopen() on Syllable before 11/22/2007 doesn't return 0 on error
+#ifndef __SYLLABLE__
+ // Make sure that inexistent lib is giving correct result
+ res += TestDynamicLoader("azerty_", "foo_bar",0,0,0);
+ // Make sure that random binary file cannot be assimilated as dylib
+ res += TestDynamicLoader(TEST_SYSTEMTOOLS_SOURCE_DIR "/testSystemTools.bin", "wp",0,0,0);
+#endif
+
+#ifdef __linux__
+ // This one is actually fun to test, since dlopen is by default loaded...wonder why :)
+ res += TestDynamicLoader("foobar.lib", "dlopen",0,1,0);
+ res += TestDynamicLoader("libdl.so", "dlopen",1,1,1);
+ res += TestDynamicLoader("libdl.so", "TestDynamicLoader",1,0,1);
+#endif
+ // Now try on the generated library
+ std::string libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynload");
+ res += TestDynamicLoader(libname.c_str(), "dummy",1,0,1);
+ res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderSymbolPointer",1,1,1);
+ res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderSymbolPointer",1,0,1);
+ res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderData",1,1,1);
+ res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderData",1,0,1);
+
+ return res;
+}
diff --git a/Source/kwsys/testDynload.c b/Source/kwsys/testDynload.c
new file mode 100644
index 0000000..ba60bec
--- /dev/null
+++ b/Source/kwsys/testDynload.c
@@ -0,0 +1,22 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifdef _WIN32
+#define DL_EXPORT __declspec( dllexport )
+#else
+#define DL_EXPORT
+#endif
+
+DL_EXPORT int TestDynamicLoaderData = 0;
+
+DL_EXPORT void TestDynamicLoaderSymbolPointer()
+{
+}
diff --git a/Source/kwsys/testEncode.c b/Source/kwsys/testEncode.c
new file mode 100644
index 0000000..26d483b
--- /dev/null
+++ b/Source/kwsys/testEncode.c
@@ -0,0 +1,76 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(MD5.h)
+
+/* Work-around CMake dependency scanning limitation. This must
+ duplicate the above list of headers. */
+#if 0
+# include "MD5.h.in"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+static const unsigned char testMD5input1[] =
+" A quick brown fox jumps over the lazy dog.\n"
+" This is sample text for MD5 sum input.\n";
+static const char testMD5output1[] = "8f146af46ed4f267921bb937d4d3500c";
+
+static const int testMD5input2len = 28;
+static const unsigned char testMD5input2[] = "the cow jumped over the moon";
+static const char testMD5output2[] = "a2ad137b746138fae4e5adca9c85d3ae";
+
+static int testMD5_1(kwsysMD5* md5)
+{
+ char md5out[33];
+ kwsysMD5_Initialize(md5);
+ kwsysMD5_Append(md5, testMD5input1, -1);
+ kwsysMD5_FinalizeHex(md5, md5out);
+ md5out[32] = 0;
+ printf("md5sum 1: expected [%s]\n"
+ " got [%s]\n",
+ testMD5output1, md5out);
+ return (strcmp(md5out, testMD5output1) != 0)? 1:0;
+}
+
+static int testMD5_2(kwsysMD5* md5)
+{
+ unsigned char digest[16];
+ char md5out[33];
+ kwsysMD5_Initialize(md5);
+ kwsysMD5_Append(md5, testMD5input2, testMD5input2len);
+ kwsysMD5_Finalize(md5, digest);
+ kwsysMD5_DigestToHex(digest, md5out);
+ md5out[32] = 0;
+ printf("md5sum 2: expected [%s]\n"
+ " got [%s]\n",
+ testMD5output2, md5out);
+ return (strcmp(md5out, testMD5output2) != 0)? 1:0;
+}
+
+int testEncode(int argc, char* argv[])
+{
+ int result = 0;
+ (void)argc;
+ (void)argv;
+
+ /* Test MD5 digest. */
+ {
+ kwsysMD5* md5 = kwsysMD5_New();
+ result |= testMD5_1(md5);
+ result |= testMD5_2(md5);
+ kwsysMD5_Delete(md5);
+ }
+
+ return result;
+}
diff --git a/Source/kwsys/testEncoding.cxx b/Source/kwsys/testEncoding.cxx
new file mode 100644
index 0000000..80ec040
--- /dev/null
+++ b/Source/kwsys/testEncoding.cxx
@@ -0,0 +1,198 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+
+#if defined(_MSC_VER)
+# pragma warning (disable:4786)
+#endif
+
+#include KWSYS_HEADER(Encoding.hxx)
+#include KWSYS_HEADER(Encoding.h)
+
+#include <iostream>
+#include <locale.h>
+#include <string.h>
+#include <stdlib.h>
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "Encoding.hxx.in"
+# include "Encoding.h.in"
+#endif
+
+//----------------------------------------------------------------------------
+static const unsigned char helloWorldStrings[][32] =
+{
+ // English
+ {'H','e','l','l','o',' ','W','o','r','l','d',0},
+ // Japanese
+ {0xE3, 0x81, 0x93, 0xE3, 0x82, 0x93, 0xE3, 0x81, 0xAB, 0xE3,
+ 0x81, 0xA1, 0xE3, 0x81, 0xAF, 0xE4, 0xB8, 0x96, 0xE7, 0x95,
+ 0x8C, 0},
+ // Arabic
+ {0xD9, 0x85, 0xD8, 0xB1, 0xD8, 0xAD, 0xD8, 0xA8, 0xD8, 0xA7,
+ 0x20, 0xD8, 0xA7, 0xD9, 0x84, 0xD8, 0xB9, 0xD8, 0xA7, 0xD9,
+ 0x84, 0xD9, 0x85, 0},
+ // Yiddish
+ {0xD7, 0x94, 0xD7, 0xA2, 0xD7, 0x9C, 0xD7, 0x90, 0x20, 0xD7,
+ 0x95, 0xD7, 0x95, 0xD7, 0xA2, 0xD7, 0x9C, 0xD7, 0x98, 0},
+ // Russian
+ {0xD0, 0xBF, 0xD1, 0x80, 0xD0, 0xB8, 0xD0, 0xB2, 0xD0, 0xB5,
+ 0xD1, 0x82, 0x20, 0xD0, 0xBC, 0xD0, 0xB8, 0xD1, 0x80, 0},
+ // Latin
+ {0x4D, 0x75, 0x6E, 0x64, 0x75, 0x73, 0x20, 0x73, 0x61, 0x6C,
+ 0x76, 0x65, 0},
+ // Swahili
+ {0x68, 0x75, 0x6A, 0x61, 0x6D, 0x62, 0x6F, 0x20, 0x44, 0x75,
+ 0x6E, 0x69, 0x61, 0},
+ // Icelandic
+ {0x48, 0x61, 0x6C, 0x6C, 0xC3, 0xB3, 0x20, 0x68, 0x65, 0x69,
+ 0x6D, 0x75, 0x72, 0},
+ {0}
+};
+
+//----------------------------------------------------------------------------
+static int testHelloWorldEncoding()
+{
+ int ret = 0;
+ for(int i=0; helloWorldStrings[i][0] != 0; i++)
+ {
+ std::string str = reinterpret_cast<const char*>(helloWorldStrings[i]);
+ std::cout << str << std::endl;
+ std::wstring wstr = kwsys::Encoding::ToWide(str);
+ std::string str2 = kwsys::Encoding::ToNarrow(wstr);
+ wchar_t* c_wstr = kwsysEncoding_DupToWide(str.c_str());
+ char* c_str2 = kwsysEncoding_DupToNarrow(c_wstr);
+ if(!wstr.empty() && (str != str2 || strcmp(c_str2, str.c_str())))
+ {
+ std::cout << "converted string was different: " << str2 << std::endl;
+ std::cout << "converted string was different: " << c_str2 << std::endl;
+ ret++;
+ }
+ free(c_wstr);
+ free(c_str2);
+ }
+ return ret;
+}
+
+static int testRobustEncoding()
+{
+ // test that the conversion functions handle invalid
+ // unicode correctly/gracefully
+
+ int ret = 0;
+ char cstr[] = {(char)-1, 0};
+ // this conversion could fail
+ std::wstring wstr = kwsys::Encoding::ToWide(cstr);
+
+ wstr = kwsys::Encoding::ToWide(NULL);
+ if(wstr != L"")
+ {
+ const wchar_t* wcstr = wstr.c_str();
+ std::cout << "ToWide(NULL) returned";
+ for(size_t i=0; i<wstr.size(); i++)
+ {
+ std::cout << " " << std::hex << (int)wcstr[i];
+ }
+ std::cout << std::endl;
+ ret++;
+ }
+ wstr = kwsys::Encoding::ToWide("");
+ if(wstr != L"")
+ {
+ const wchar_t* wcstr = wstr.c_str();
+ std::cout << "ToWide(\"\") returned";
+ for(size_t i=0; i<wstr.size(); i++)
+ {
+ std::cout << " " << std::hex << (int)wcstr[i];
+ }
+ std::cout << std::endl;
+ ret++;
+ }
+
+#ifdef _WIN32
+ // 16 bit wchar_t - we make an invalid surrogate pair
+ wchar_t cwstr[] = {0xD801, 0xDA00, 0};
+ // this conversion could fail
+ std::string win_str = kwsys::Encoding::ToNarrow(cwstr);
+#endif
+
+ std::string str = kwsys::Encoding::ToNarrow(NULL);
+ if(str != "")
+ {
+ std::cout << "ToNarrow(NULL) returned " << str << std::endl;
+ ret++;
+ }
+
+ str = kwsys::Encoding::ToNarrow(L"");
+ if(wstr != L"")
+ {
+ std::cout << "ToNarrow(\"\") returned " << str << std::endl;
+ ret++;
+ }
+
+ return ret;
+}
+
+static int testCommandLineArguments()
+{
+ int status = 0;
+
+ char const* argv[2] = {
+ "./app.exe",
+ (char const*)helloWorldStrings[1]
+ };
+
+ kwsys::Encoding::CommandLineArguments args(2, argv);
+ kwsys::Encoding::CommandLineArguments arg2 =
+ kwsys::Encoding::CommandLineArguments(args);
+
+ char const* const* u8_argv = args.argv();
+ for(int i=0; i<args.argc(); i++)
+ {
+ char const* u8_arg = u8_argv[i];
+ if(strcmp(argv[i], u8_arg) != 0)
+ {
+ std::cout << "argv[" << i << "] " << argv[i] << " != "
+ << u8_arg << std::endl;
+ status++;
+ }
+ }
+
+ kwsys::Encoding::CommandLineArguments args3 =
+ kwsys::Encoding::CommandLineArguments::Main(2, argv);
+
+ return status;
+}
+
+//----------------------------------------------------------------------------
+int testEncoding(int, char*[])
+{
+ const char* loc = setlocale(LC_ALL, "");
+ if(loc)
+ {
+ std::cout << "Locale: " << loc << std::endl;
+ }
+ else
+ {
+ std::cout << "Locale: None" << std::endl;
+ }
+
+ int ret = 0;
+
+ ret |= testHelloWorldEncoding();
+ ret |= testRobustEncoding();
+ ret |= testCommandLineArguments();
+
+ return ret;
+}
diff --git a/Source/kwsys/testFStream.cxx b/Source/kwsys/testFStream.cxx
new file mode 100644
index 0000000..5e53725
--- /dev/null
+++ b/Source/kwsys/testFStream.cxx
@@ -0,0 +1,138 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+
+#if defined(_MSC_VER)
+# pragma warning (disable:4786)
+#endif
+
+#include KWSYS_HEADER(FStream.hxx)
+#include <string.h>
+#ifdef __BORLANDC__
+# include <mem.h> /* memcmp */
+#endif
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "FStream.hxx.in"
+#endif
+
+#include <iostream>
+
+//----------------------------------------------------------------------------
+static int testNoFile()
+{
+ kwsys::ifstream in_file("NoSuchFile.txt");
+ if(in_file)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+static const int num_test_files = 7;
+static const int max_test_file_size = 45;
+
+static kwsys::FStream::BOM expected_bom[num_test_files] =
+{
+ kwsys::FStream::BOM_None,
+ kwsys::FStream::BOM_None,
+ kwsys::FStream::BOM_UTF8,
+ kwsys::FStream::BOM_UTF16LE,
+ kwsys::FStream::BOM_UTF16BE,
+ kwsys::FStream::BOM_UTF32LE,
+ kwsys::FStream::BOM_UTF32BE
+};
+
+static unsigned char expected_bom_data[num_test_files][5] =
+{
+ {0},
+ {0},
+ {3, 0xEF, 0xBB, 0xBF},
+ {2, 0xFF, 0xFE},
+ {2, 0xFE, 0xFF},
+ {4, 0xFF, 0xFE, 0x00, 0x00},
+ {4, 0x00, 0x00, 0xFE, 0xFF},
+};
+
+static unsigned char file_data[num_test_files][max_test_file_size] =
+{
+ {1, 'H'},
+ {11, 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'},
+ {11, 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'},
+ {22, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x20, 0x00,
+ 0x57, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64, 0x00},
+ {22, 0x00, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x20,
+ 0x00, 0x57, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64},
+ {44, 0x48, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
+ 0x6C, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x57, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00,
+ 0x6C, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00},
+ {44, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x6C,
+ 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x20,
+ 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x72,
+ 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x64},
+};
+
+//----------------------------------------------------------------------------
+static int testBOM()
+{
+ // test various encodings in binary mode
+ for(int i=0; i<num_test_files; i++)
+ {
+ {
+ kwsys::ofstream out("bom.txt", kwsys::ofstream::binary);
+ out.write(reinterpret_cast<const char*>(expected_bom_data[i]+1),
+ *expected_bom_data[i]);
+ out.write(reinterpret_cast<const char*>(file_data[i]+1),
+ file_data[i][0]);
+ }
+
+ kwsys::ifstream in("bom.txt", kwsys::ofstream::binary);
+ kwsys::FStream::BOM bom = kwsys::FStream::ReadBOM(in);
+ if(bom != expected_bom[i])
+ {
+ std::cout << "Unexpected BOM " << i << std::endl;
+ return 1;
+ }
+ char data[max_test_file_size];
+ in.read(data, file_data[i][0]);
+ if(!in.good())
+ {
+ std::cout << "Unable to read data " << i << std::endl;
+ return 1;
+ }
+
+ if(memcmp(data, file_data[i]+1, file_data[i][0]) != 0)
+ {
+ std::cout << "Incorrect read data " << i << std::endl;
+ return 1;
+ }
+
+ }
+
+ return 0;
+}
+
+
+//----------------------------------------------------------------------------
+int testFStream(int, char*[])
+{
+ int ret = 0;
+
+ ret |= testNoFile();
+ ret |= testBOM();
+
+ return ret;
+}
diff --git a/Source/kwsys/testFail.c b/Source/kwsys/testFail.c
new file mode 100644
index 0000000..7e062c1
--- /dev/null
+++ b/Source/kwsys/testFail.c
@@ -0,0 +1,35 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int testFail(int argc, char* argv[])
+{
+ char* env = getenv("DASHBOARD_TEST_FROM_CTEST");
+ int oldCtest = 0;
+ if(env)
+ {
+ if(strcmp(env, "1") == 0)
+ {
+ oldCtest = 1;
+ }
+ printf("DASHBOARD_TEST_FROM_CTEST = %s\n", env);
+ }
+ printf("%s: This test intentionally fails\n", argv[0]);
+ if(oldCtest)
+ {
+ printf("The version of ctest is not able to handle intentionally failing tests, so pass.\n");
+ return 0;
+ }
+ return argc;
+}
diff --git a/Source/kwsys/testHashSTL.cxx b/Source/kwsys/testHashSTL.cxx
new file mode 100644
index 0000000..ae66ceb
--- /dev/null
+++ b/Source/kwsys/testHashSTL.cxx
@@ -0,0 +1,74 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(hash_map.hxx)
+#include KWSYS_HEADER(hash_set.hxx)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "hash_map.hxx.in"
+# include "hash_set.hxx.in"
+#endif
+
+#include <iostream>
+
+#if defined(_MSC_VER)
+# pragma warning (disable:4786)
+#endif
+
+#if defined(__sgi) && !defined(__GNUC__)
+# pragma set woff 1468 /* inline function cannot be explicitly instantiated */
+#endif
+
+template class kwsys::hash_map<const char*, int>;
+template class kwsys::hash_set<int>;
+
+static bool test_hash_map()
+{
+ typedef kwsys::hash_map<const char*, int> mtype;
+ mtype m;
+ const char* keys[] = {"hello", "world"};
+ m[keys[0]] = 1;
+ m.insert(mtype::value_type(keys[1], 2));
+ int sum = 0;
+ for(mtype::iterator mi = m.begin(); mi != m.end(); ++mi)
+ {
+ std::cout << "Found entry [" << mi->first << "," << mi->second << "]"
+ << std::endl;
+ sum += mi->second;
+ }
+ return sum == 3;
+}
+
+static bool test_hash_set()
+{
+ typedef kwsys::hash_set<int> stype;
+ stype s;
+ s.insert(1);
+ s.insert(2);
+ int sum = 0;
+ for(stype::iterator si = s.begin(); si != s.end(); ++si)
+ {
+ std::cout << "Found entry [" << *si << "]" << std::endl;
+ sum += *si;
+ }
+ return sum == 3;
+}
+
+int testHashSTL(int, char*[])
+{
+ bool result = true;
+ result = test_hash_map() && result;
+ result = test_hash_set() && result;
+ return result? 0:1;
+}
diff --git a/Source/kwsys/testIOS.cxx b/Source/kwsys/testIOS.cxx
new file mode 100644
index 0000000..5ff7955
--- /dev/null
+++ b/Source/kwsys/testIOS.cxx
@@ -0,0 +1,164 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Configure.hxx)
+
+#include <sstream>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <string.h> /* strlen */
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "Configure.hxx.in"
+#endif
+
+int testIOS(int, char*[])
+{
+ std::ostringstream ostr;
+ const char hello[] = "hello";
+ ostr << hello;
+ if(ostr.str() != hello)
+ {
+ std::cerr << "failed to write hello to ostr" << std::endl;
+ return 1;
+ }
+ const char world[] = "world";
+ std::ostringstream ostr2;
+ ostr2.write( hello, strlen(hello) ); /* I could do sizeof */
+ ostr2.put( '\0' );
+ ostr2.write( world, strlen(world) );
+ if(ostr2.str().size() != strlen(hello) + 1 + strlen(world) )
+ {
+ std::cerr << "failed to write hello to ostr2" << std::endl;
+ return 1;
+ }
+ static const unsigned char array[] = { 0xff,0x4f,0xff,0x51,0x00,0x29,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x07,0x01,0x01,0xff,0x52,0x00,0x0c,0x00,0x00,0x00,0x01,0x00,0x05,0x04,0x04,0x00,0x01,0xff,0x5c,0x00,0x13,0x40,0x40,0x48,0x48,0x50,0x48,0x48,0x50,0x48,0x48,0x50,0x48,0x48,0x50,0x48,0x48,0x50,0xff,0x64,0x00,0x2c,0x00,0x00,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x49,0x54,0x4b,0x2f,0x47,0x44,0x43,0x4d,0x2f,0x4f,0x70,0x65,0x6e,0x4a,0x50,0x45,0x47,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x2e,0x30,0xff,0x90,0x00,0x0a,0x00,0x00,0x00,0x00,0x06,0x2c,0x00,0x01,0xff,0x93,0xcf,0xb0,0x18,0x08,0x7f,0xc6,0x99,0xbf,0xff,0xc0,0xf8,0xc1,0xc1,0xf3,0x05,0x81,0xf2,0x83,0x0a,0xa5,0xff,0x10,0x90,0xbf,0x2f,0xff,0x04,0xa8,0x7f,0xc0,0xf8,0xc4,0xc1,0xf3,0x09,0x81,0xf3,0x0c,0x19,0x34 };
+ const size_t narray = sizeof(array); // 180
+ std::stringstream strstr;
+ strstr.write( (char*)array, narray );
+ //strstr.seekp( narray / 2 ); // set position of put pointer in mid string
+ if(strstr.str().size() != narray )
+ {
+ std::cerr << "failed to write array to strstr" << std::endl;
+ return 1;
+ }
+
+ std::istringstream istr(" 10 20 str ");
+ std::string s;
+ int x;
+ if(istr >> x)
+ {
+ if(x != 10)
+ {
+ std::cerr << "x != 10" << std::endl;
+ return 1;
+ }
+ }
+ else
+ {
+ std::cerr << "Failed to read 10 from istr" << std::endl;
+ return 1;
+ }
+ if(istr >> x)
+ {
+ if(x != 20)
+ {
+ std::cerr << "x != 20" << std::endl;
+ return 1;
+ }
+ }
+ else
+ {
+ std::cerr << "Failed to read 20 from istr" << std::endl;
+ return 1;
+ }
+ if(istr >> s)
+ {
+ if(s != "str")
+ {
+ std::cerr << "s != \"str\"" << std::endl;
+ return 1;
+ }
+ }
+ else
+ {
+ std::cerr << "Failed to read str from istr" << std::endl;
+ return 1;
+ }
+ if(istr >> s)
+ {
+ std::cerr << "Able to read past end of stream" << std::endl;
+ return 1;
+ }
+ else
+ {
+ // Clear the failure.
+ istr.clear(istr.rdstate() & ~std::ios::eofbit);
+ istr.clear(istr.rdstate() & ~std::ios::failbit);
+ }
+ istr.str("30");
+ if(istr >> x)
+ {
+ if(x != 30)
+ {
+ std::cerr << "x != 30" << std::endl;
+ return 1;
+ }
+ }
+ else
+ {
+ std::cerr << "Failed to read 30 from istr" << std::endl;
+ return 1;
+ }
+
+ std::stringstream sstr;
+ sstr << "40 str2";
+ if(sstr >> x)
+ {
+ if(x != 40)
+ {
+ std::cerr << "x != 40" << std::endl;
+ return 1;
+ }
+ }
+ else
+ {
+ std::cerr << "Failed to read 40 from sstr" << std::endl;
+ return 1;
+ }
+ if(sstr >> s)
+ {
+ if(s != "str2")
+ {
+ std::cerr << "s != \"str2\"" << std::endl;
+ return 1;
+ }
+ }
+ else
+ {
+ std::cerr << "Failed to read str2 from sstr" << std::endl;
+ return 1;
+ }
+
+ // Just try to compile this.
+ if(x == 12345)
+ {
+ std::ifstream fin("/does_not_exist",
+ std::ios::in | std::ios::binary);
+ }
+
+ std::cout << "IOS tests passed" << std::endl;
+ return 0;
+}
diff --git a/Source/kwsys/testProcess.c b/Source/kwsys/testProcess.c
new file mode 100644
index 0000000..8fd3382
--- /dev/null
+++ b/Source/kwsys/testProcess.c
@@ -0,0 +1,755 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Process.h)
+#include KWSYS_HEADER(Encoding.h)
+
+/* Work-around CMake dependency scanning limitation. This must
+ duplicate the above list of headers. */
+#if 0
+# include "Process.h.in"
+# include "Encoding.h.in"
+#endif
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(_WIN32)
+# include <windows.h>
+#else
+# include <unistd.h>
+# include <signal.h>
+#endif
+
+#if defined(__BORLANDC__)
+# pragma warn -8060 /* possibly incorrect assignment */
+#endif
+
+/* Platform-specific sleep functions. */
+
+#if defined(__BEOS__) && !defined(__ZETA__)
+/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */
+# include <be/kernel/OS.h>
+static inline void testProcess_usleep(unsigned int usec)
+{
+ snooze(usec);
+}
+#elif defined(_WIN32)
+/* Windows can only sleep in millisecond intervals. */
+static void testProcess_usleep(unsigned int usec)
+{
+ Sleep(usec / 1000);
+}
+#else
+# define testProcess_usleep usleep
+#endif
+
+#if defined(_WIN32)
+static void testProcess_sleep(unsigned int sec)
+{
+ Sleep(sec*1000);
+}
+#else
+static void testProcess_sleep(unsigned int sec)
+{
+ sleep(sec);
+}
+#endif
+
+int runChild(const char* cmd[], int state, int exception, int value,
+ int share, int output, int delay, double timeout, int poll,
+ int repeat, int disown, int createNewGroup,
+ unsigned int interruptDelay);
+
+static int test1(int argc, const char* argv[])
+{
+ /* This is a very basic functional test of kwsysProcess. It is repeated
+ numerous times to verify that there are no resource leaks in kwsysProcess
+ that eventually lead to an error. Many versions of OS X will fail after
+ 256 leaked file handles, so 257 iterations seems to be a good test. On
+ the other hand, too many iterations will cause the test to time out -
+ especially if the test is instrumented with e.g. valgrind.
+
+ If you have problems with this test timing out on your system, or want to
+ run more than 257 iterations, you can change the number of iterations by
+ setting the KWSYS_TEST_PROCESS_1_COUNT environment variable. */
+ (void)argc; (void)argv;
+ fprintf(stdout, "Output on stdout from test returning 0.\n");
+ fprintf(stderr, "Output on stderr from test returning 0.\n");
+ return 0;
+}
+
+static int test2(int argc, const char* argv[])
+{
+ (void)argc; (void)argv;
+ fprintf(stdout, "Output on stdout from test returning 123.\n");
+ fprintf(stderr, "Output on stderr from test returning 123.\n");
+ return 123;
+}
+
+static int test3(int argc, const char* argv[])
+{
+ (void)argc; (void)argv;
+ fprintf(stdout, "Output before sleep on stdout from timeout test.\n");
+ fprintf(stderr, "Output before sleep on stderr from timeout test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ testProcess_sleep(15);
+ fprintf(stdout, "Output after sleep on stdout from timeout test.\n");
+ fprintf(stderr, "Output after sleep on stderr from timeout test.\n");
+ return 0;
+}
+
+static int test4(int argc, const char* argv[])
+{
+ /* Prepare a pointer to an invalid address. Don't use null, because
+ dereferencing null is undefined behaviour and compilers are free to
+ do whatever they want. ex: Clang will warn at compile time, or even
+ optimize away the write. We hope to 'outsmart' them by using
+ 'volatile' and a slightly larger address, based on a runtime value. */
+ volatile int* invalidAddress = 0;
+ invalidAddress += argc?1:2;
+
+#if defined(_WIN32)
+ /* Avoid error diagnostic popups since we are crashing on purpose. */
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+#elif defined(__BEOS__) || defined(__HAIKU__)
+ /* Avoid error diagnostic popups since we are crashing on purpose. */
+ disable_debugger(1);
+#endif
+ (void)argc; (void)argv;
+ fprintf(stdout, "Output before crash on stdout from crash test.\n");
+ fprintf(stderr, "Output before crash on stderr from crash test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ assert(invalidAddress); /* Quiet Clang scan-build. */
+ /* Provoke deliberate crash by writing to the invalid address. */
+ *invalidAddress = 0;
+ fprintf(stdout, "Output after crash on stdout from crash test.\n");
+ fprintf(stderr, "Output after crash on stderr from crash test.\n");
+ return 0;
+}
+
+static int test5(int argc, const char* argv[])
+{
+ int r;
+ const char* cmd[4];
+ (void)argc;
+ cmd[0] = argv[0];
+ cmd[1] = "run";
+ cmd[2] = "4";
+ cmd[3] = 0;
+ fprintf(stdout, "Output on stdout before recursive test.\n");
+ fprintf(stderr, "Output on stderr before recursive test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ r = runChild(cmd, kwsysProcess_State_Exception,
+ kwsysProcess_Exception_Fault, 1, 1, 1, 0, 15, 0, 1, 0, 0, 0);
+ fprintf(stdout, "Output on stdout after recursive test.\n");
+ fprintf(stderr, "Output on stderr after recursive test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ return r;
+}
+
+#define TEST6_SIZE (4096*2)
+static void test6(int argc, const char* argv[])
+{
+ int i;
+ char runaway[TEST6_SIZE+1];
+ (void)argc; (void)argv;
+ for(i=0;i < TEST6_SIZE;++i)
+ {
+ runaway[i] = '.';
+ }
+ runaway[TEST6_SIZE] = '\n';
+
+ /* Generate huge amounts of output to test killing. */
+ for(;;)
+ {
+ fwrite(runaway, 1, TEST6_SIZE+1, stdout);
+ fflush(stdout);
+ }
+}
+
+/* Define MINPOLL to be one more than the number of times output is
+ written. Define MAXPOLL to be the largest number of times a loop
+ delaying 1/10th of a second should ever have to poll. */
+#define MINPOLL 5
+#define MAXPOLL 20
+static int test7(int argc, const char* argv[])
+{
+ (void)argc; (void)argv;
+ fprintf(stdout, "Output on stdout before sleep.\n");
+ fprintf(stderr, "Output on stderr before sleep.\n");
+ fflush(stdout);
+ fflush(stderr);
+ /* Sleep for 1 second. */
+ testProcess_sleep(1);
+ fprintf(stdout, "Output on stdout after sleep.\n");
+ fprintf(stderr, "Output on stderr after sleep.\n");
+ fflush(stdout);
+ fflush(stderr);
+ return 0;
+}
+
+static int test8(int argc, const char* argv[])
+{
+ /* Create a disowned grandchild to test handling of processes
+ that exit before their children. */
+ int r;
+ const char* cmd[4];
+ (void)argc;
+ cmd[0] = argv[0];
+ cmd[1] = "run";
+ cmd[2] = "108";
+ cmd[3] = 0;
+ fprintf(stdout, "Output on stdout before grandchild test.\n");
+ fprintf(stderr, "Output on stderr before grandchild test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ r = runChild(cmd, kwsysProcess_State_Disowned, kwsysProcess_Exception_None,
+ 1, 1, 1, 0, 10, 0, 1, 1, 0, 0);
+ fprintf(stdout, "Output on stdout after grandchild test.\n");
+ fprintf(stderr, "Output on stderr after grandchild test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ return r;
+}
+
+static int test8_grandchild(int argc, const char* argv[])
+{
+ (void)argc; (void)argv;
+ fprintf(stdout, "Output on stdout from grandchild before sleep.\n");
+ fprintf(stderr, "Output on stderr from grandchild before sleep.\n");
+ fflush(stdout);
+ fflush(stderr);
+ /* TODO: Instead of closing pipes here leave them open to make sure
+ the grandparent can stop listening when the parent exits. This
+ part of the test cannot be enabled until the feature is
+ implemented. */
+ fclose(stdout);
+ fclose(stderr);
+ testProcess_sleep(15);
+ return 0;
+}
+
+static int test9(int argc, const char* argv[])
+{
+ /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this
+ process. Here, we start a child process that sleeps for a long time
+ while ignoring signals. The test is successful if this process waits
+ for the child to return before exiting from the Ctrl+C handler.
+
+ WARNING: This test will falsely pass if the share parameter of runChild
+ was set to 0 when invoking the test9 process. */
+ int r;
+ const char* cmd[4];
+ (void)argc;
+ cmd[0] = argv[0];
+ cmd[1] = "run";
+ cmd[2] = "109";
+ cmd[3] = 0;
+ fprintf(stdout, "Output on stdout before grandchild test.\n");
+ fprintf(stderr, "Output on stderr before grandchild test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ r = runChild(cmd, kwsysProcess_State_Exited,
+ kwsysProcess_Exception_None,
+ 0, 1, 1, 0, 30, 0, 1, 0, 0, 0);
+ /* This sleep will avoid a race condition between this function exiting
+ normally and our Ctrl+C handler exiting abnormally after the process
+ exits. */
+ testProcess_sleep(1);
+ fprintf(stdout, "Output on stdout after grandchild test.\n");
+ fprintf(stderr, "Output on stderr after grandchild test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ return r;
+}
+
+#if defined(_WIN32)
+static BOOL WINAPI test9_grandchild_handler(DWORD dwCtrlType)
+{
+ /* Ignore all Ctrl+C/Break signals. We must use an actual handler function
+ instead of using SetConsoleCtrlHandler(NULL, TRUE) so that we can also
+ ignore Ctrl+Break in addition to Ctrl+C. */
+ (void)dwCtrlType;
+ return TRUE;
+}
+#endif
+
+static int test9_grandchild(int argc, const char* argv[])
+{
+ /* The grandchild just sleeps for a few seconds while ignoring signals. */
+ (void)argc; (void)argv;
+#if defined(_WIN32)
+ if(!SetConsoleCtrlHandler(test9_grandchild_handler, TRUE))
+ {
+ return 1;
+ }
+#else
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ sigemptyset(&sa.sa_mask);
+ if(sigaction(SIGINT, &sa, 0) < 0)
+ {
+ return 1;
+ }
+#endif
+ fprintf(stdout, "Output on stdout from grandchild before sleep.\n");
+ fprintf(stderr, "Output on stderr from grandchild before sleep.\n");
+ fflush(stdout);
+ fflush(stderr);
+ /* Sleep for 9 seconds. */
+ testProcess_sleep(9);
+ fprintf(stdout, "Output on stdout from grandchild after sleep.\n");
+ fprintf(stderr, "Output on stderr from grandchild after sleep.\n");
+ fflush(stdout);
+ fflush(stderr);
+ return 0;
+}
+
+static int test10(int argc, const char* argv[])
+{
+ /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this
+ process. Here, we start a child process that sleeps for a long time and
+ processes signals normally. However, this grandchild is created in a new
+ process group - ensuring that Ctrl+C we receive is sent to our process
+ groups. We make sure it exits anyway. */
+ int r;
+ const char* cmd[4];
+ (void)argc;
+ cmd[0] = argv[0];
+ cmd[1] = "run";
+ cmd[2] = "110";
+ cmd[3] = 0;
+ fprintf(stdout, "Output on stdout before grandchild test.\n");
+ fprintf(stderr, "Output on stderr before grandchild test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ r = runChild(cmd, kwsysProcess_State_Exception,
+ kwsysProcess_Exception_Interrupt,
+ 0, 1, 1, 0, 30, 0, 1, 0, 1, 0);
+ fprintf(stdout, "Output on stdout after grandchild test.\n");
+ fprintf(stderr, "Output on stderr after grandchild test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ return r;
+}
+
+static int test10_grandchild(int argc, const char* argv[])
+{
+ /* The grandchild just sleeps for a few seconds and handles signals. */
+ (void)argc; (void)argv;
+ fprintf(stdout, "Output on stdout from grandchild before sleep.\n");
+ fprintf(stderr, "Output on stderr from grandchild before sleep.\n");
+ fflush(stdout);
+ fflush(stderr);
+ /* Sleep for 6 seconds. */
+ testProcess_sleep(6);
+ fprintf(stdout, "Output on stdout from grandchild after sleep.\n");
+ fprintf(stderr, "Output on stderr from grandchild after sleep.\n");
+ fflush(stdout);
+ fflush(stderr);
+ return 0;
+}
+
+static int runChild2(kwsysProcess* kp,
+ const char* cmd[], int state, int exception, int value,
+ int share, int output, int delay, double timeout,
+ int poll, int disown, int createNewGroup,
+ unsigned int interruptDelay)
+{
+ int result = 0;
+ char* data = 0;
+ int length = 0;
+ double userTimeout = 0;
+ double* pUserTimeout = 0;
+ kwsysProcess_SetCommand(kp, cmd);
+ if(timeout >= 0)
+ {
+ kwsysProcess_SetTimeout(kp, timeout);
+ }
+ if(share)
+ {
+ kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDOUT, 1);
+ kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDERR, 1);
+ }
+ if(disown)
+ {
+ kwsysProcess_SetOption(kp, kwsysProcess_Option_Detach, 1);
+ }
+ if(createNewGroup)
+ {
+ kwsysProcess_SetOption(kp, kwsysProcess_Option_CreateProcessGroup, 1);
+ }
+ kwsysProcess_Execute(kp);
+
+ if(poll)
+ {
+ pUserTimeout = &userTimeout;
+ }
+
+ if(interruptDelay)
+ {
+ testProcess_sleep(interruptDelay);
+ kwsysProcess_Interrupt(kp);
+ }
+
+ if(!share && !disown)
+ {
+ int p;
+ while((p = kwsysProcess_WaitForData(kp, &data, &length, pUserTimeout)))
+ {
+ if(output)
+ {
+ if(poll && p == kwsysProcess_Pipe_Timeout)
+ {
+ fprintf(stdout, "WaitForData timeout reached.\n");
+ fflush(stdout);
+
+ /* Count the number of times we polled without getting data.
+ If it is excessive then kill the child and fail. */
+ if(++poll >= MAXPOLL)
+ {
+ fprintf(stdout, "Poll count reached limit %d.\n",
+ MAXPOLL);
+ kwsysProcess_Kill(kp);
+ }
+ }
+ else
+ {
+ fwrite(data, 1, (size_t) length, stdout);
+ fflush(stdout);
+ }
+ }
+ if(poll)
+ {
+ /* Delay to avoid busy loop during polling. */
+ testProcess_usleep(100000);
+ }
+ if(delay)
+ {
+ /* Purposely sleeping only on Win32 to let pipe fill up. */
+#if defined(_WIN32)
+ testProcess_usleep(100000);
+#endif
+ }
+ }
+ }
+
+ if(disown)
+ {
+ kwsysProcess_Disown(kp);
+ }
+ else
+ {
+ kwsysProcess_WaitForExit(kp, 0);
+ }
+
+ switch (kwsysProcess_GetState(kp))
+ {
+ case kwsysProcess_State_Starting:
+ printf("No process has been executed.\n"); break;
+ case kwsysProcess_State_Executing:
+ printf("The process is still executing.\n"); break;
+ case kwsysProcess_State_Expired:
+ printf("Child was killed when timeout expired.\n"); break;
+ case kwsysProcess_State_Exited:
+ printf("Child exited with value = %d\n",
+ kwsysProcess_GetExitValue(kp));
+ result = ((exception != kwsysProcess_GetExitException(kp)) ||
+ (value != kwsysProcess_GetExitValue(kp))); break;
+ case kwsysProcess_State_Killed:
+ printf("Child was killed by parent.\n"); break;
+ case kwsysProcess_State_Exception:
+ printf("Child terminated abnormally: %s\n",
+ kwsysProcess_GetExceptionString(kp));
+ result = ((exception != kwsysProcess_GetExitException(kp)) ||
+ (value != kwsysProcess_GetExitValue(kp))); break;
+ case kwsysProcess_State_Disowned:
+ printf("Child was disowned.\n"); break;
+ case kwsysProcess_State_Error:
+ printf("Error in administrating child process: [%s]\n",
+ kwsysProcess_GetErrorString(kp)); break;
+ };
+
+ if(result)
+ {
+ if(exception != kwsysProcess_GetExitException(kp))
+ {
+ fprintf(stderr, "Mismatch in exit exception. "
+ "Should have been %d, was %d.\n",
+ exception, kwsysProcess_GetExitException(kp));
+ }
+ if(value != kwsysProcess_GetExitValue(kp))
+ {
+ fprintf(stderr, "Mismatch in exit value. "
+ "Should have been %d, was %d.\n",
+ value, kwsysProcess_GetExitValue(kp));
+ }
+ }
+
+ if(kwsysProcess_GetState(kp) != state)
+ {
+ fprintf(stderr, "Mismatch in state. "
+ "Should have been %d, was %d.\n",
+ state, kwsysProcess_GetState(kp));
+ result = 1;
+ }
+
+ /* We should have polled more times than there were data if polling
+ was enabled. */
+ if(poll && poll < MINPOLL)
+ {
+ fprintf(stderr, "Poll count is %d, which is less than %d.\n",
+ poll, MINPOLL);
+ result = 1;
+ }
+
+ return result;
+}
+
+/**
+ * Runs a child process and blocks until it returns. Arguments as follows:
+ *
+ * cmd = Command line to run.
+ * state = Expected return value of kwsysProcess_GetState after exit.
+ * exception = Expected return value of kwsysProcess_GetExitException.
+ * value = Expected return value of kwsysProcess_GetExitValue.
+ * share = Whether to share stdout/stderr child pipes with our pipes
+ * by way of kwsysProcess_SetPipeShared. If false, new pipes
+ * are created.
+ * output = If !share && !disown, whether to write the child's stdout
+ * and stderr output to our stdout.
+ * delay = If !share && !disown, adds an additional short delay to
+ * the pipe loop to allow the pipes to fill up; Windows only.
+ * timeout = Non-zero to sets a timeout in seconds via
+ * kwsysProcess_SetTimeout.
+ * poll = If !share && !disown, we count the number of 0.1 second
+ * intervals where the child pipes had no new data. We fail
+ * if not in the bounds of MINPOLL/MAXPOLL.
+ * repeat = Number of times to run the process.
+ * disown = If set, the process is disowned.
+ * createNewGroup = If set, the process is created in a new process group.
+ * interruptDelay = If non-zero, number of seconds to delay before
+ * interrupting the process. Note that this delay will occur
+ * BEFORE any reading/polling of pipes occurs and before any
+ * detachment occurs.
+ */
+int runChild(const char* cmd[], int state, int exception, int value,
+ int share, int output, int delay, double timeout,
+ int poll, int repeat, int disown, int createNewGroup,
+ unsigned int interruptDelay)
+{
+ int result = 1;
+ kwsysProcess* kp = kwsysProcess_New();
+ if(!kp)
+ {
+ fprintf(stderr, "kwsysProcess_New returned NULL!\n");
+ return 1;
+ }
+ while(repeat-- > 0)
+ {
+ result = runChild2(kp, cmd, state, exception, value, share,
+ output, delay, timeout, poll, disown, createNewGroup,
+ interruptDelay);
+ if(result)
+ {
+ break;
+ }
+ }
+ kwsysProcess_Delete(kp);
+ return result;
+}
+
+int main(int argc, const char* argv[])
+{
+ int n = 0;
+
+#ifdef _WIN32
+ int i;
+ char new_args[10][_MAX_PATH];
+ LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &argc);
+ for(i=0; i<argc; i++)
+ {
+ kwsysEncoding_wcstombs(new_args[i], w_av[i], _MAX_PATH);
+ argv[i] = new_args[i];
+ }
+ LocalFree(w_av);
+#endif
+
+#if 0
+ {
+ HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
+ DuplicateHandle(GetCurrentProcess(), out,
+ GetCurrentProcess(), &out, 0, FALSE,
+ DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
+ SetStdHandle(STD_OUTPUT_HANDLE, out);
+ }
+ {
+ HANDLE out = GetStdHandle(STD_ERROR_HANDLE);
+ DuplicateHandle(GetCurrentProcess(), out,
+ GetCurrentProcess(), &out, 0, FALSE,
+ DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
+ SetStdHandle(STD_ERROR_HANDLE, out);
+ }
+#endif
+ if(argc == 2)
+ {
+ n = atoi(argv[1]);
+ }
+ else if(argc == 3 && strcmp(argv[1], "run") == 0)
+ {
+ n = atoi(argv[2]);
+ }
+ /* Check arguments. */
+ if(((n >= 1 && n <= 10) || n == 108 || n == 109 || n == 110) && argc == 3)
+ {
+ /* This is the child process for a requested test number. */
+ switch (n)
+ {
+ case 1: return test1(argc, argv);
+ case 2: return test2(argc, argv);
+ case 3: return test3(argc, argv);
+ case 4: return test4(argc, argv);
+ case 5: return test5(argc, argv);
+ case 6: test6(argc, argv); return 0;
+ case 7: return test7(argc, argv);
+ case 8: return test8(argc, argv);
+ case 9: return test9(argc, argv);
+ case 10: return test10(argc, argv);
+ case 108: return test8_grandchild(argc, argv);
+ case 109: return test9_grandchild(argc, argv);
+ case 110: return test10_grandchild(argc, argv);
+ }
+ fprintf(stderr, "Invalid test number %d.\n", n);
+ return 1;
+ }
+ else if(n >= 1 && n <= 10)
+ {
+ /* This is the parent process for a requested test number. */
+ int states[10] =
+ {
+ kwsysProcess_State_Exited,
+ kwsysProcess_State_Exited,
+ kwsysProcess_State_Expired,
+ kwsysProcess_State_Exception,
+ kwsysProcess_State_Exited,
+ kwsysProcess_State_Expired,
+ kwsysProcess_State_Exited,
+ kwsysProcess_State_Exited,
+ kwsysProcess_State_Expired, /* Ctrl+C handler test */
+ kwsysProcess_State_Exception /* Process group test */
+ };
+ int exceptions[10] =
+ {
+ kwsysProcess_Exception_None,
+ kwsysProcess_Exception_None,
+ kwsysProcess_Exception_None,
+ kwsysProcess_Exception_Fault,
+ kwsysProcess_Exception_None,
+ kwsysProcess_Exception_None,
+ kwsysProcess_Exception_None,
+ kwsysProcess_Exception_None,
+ kwsysProcess_Exception_None,
+ kwsysProcess_Exception_Interrupt
+ };
+ int values[10] = {0, 123, 1, 1, 0, 0, 0, 0, 1, 1};
+ int shares[10] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1};
+ int outputs[10] = {1, 1, 1, 1, 1, 0, 1, 1, 1, 1};
+ int delays[10] = {0, 0, 0, 0, 0, 1, 0, 0, 0, 0};
+ double timeouts[10] = {10, 10, 10, 30, 30, 10, -1, 10, 6, 4};
+ int polls[10] = {0, 0, 0, 0, 0, 0, 1, 0, 0, 0};
+ int repeat[10] = {257, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+ int createNewGroups[10] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1};
+ unsigned int interruptDelays[10] = {0, 0, 0, 0, 0, 0, 0, 0, 3, 2};
+ int r;
+ const char* cmd[4];
+#ifdef _WIN32
+ char* argv0 = 0;
+#endif
+ char* test1IterationsStr = getenv("KWSYS_TEST_PROCESS_1_COUNT");
+ if(test1IterationsStr)
+ {
+ long int test1Iterations = strtol(test1IterationsStr, 0, 10);
+ if(test1Iterations > 10 && test1Iterations != LONG_MAX)
+ {
+ repeat[0] = (int)test1Iterations;
+ }
+ }
+#ifdef _WIN32
+ if(n == 0 && (argv0 = strdup(argv[0])))
+ {
+ /* Try converting to forward slashes to see if it works. */
+ char* c;
+ for(c=argv0; *c; ++c)
+ {
+ if(*c == '\\')
+ {
+ *c = '/';
+ }
+ }
+ cmd[0] = argv0;
+ }
+ else
+ {
+ cmd[0] = argv[0];
+ }
+#else
+ cmd[0] = argv[0];
+#endif
+ cmd[1] = "run";
+ cmd[2] = argv[1];
+ cmd[3] = 0;
+ fprintf(stdout, "Output on stdout before test %d.\n", n);
+ fprintf(stderr, "Output on stderr before test %d.\n", n);
+ fflush(stdout);
+ fflush(stderr);
+ r = runChild(cmd, states[n-1], exceptions[n-1], values[n-1], shares[n-1],
+ outputs[n-1], delays[n-1], timeouts[n-1],
+ polls[n-1], repeat[n-1], 0, createNewGroups[n-1],
+ interruptDelays[n-1]);
+ fprintf(stdout, "Output on stdout after test %d.\n", n);
+ fprintf(stderr, "Output on stderr after test %d.\n", n);
+ fflush(stdout);
+ fflush(stderr);
+#if defined(_WIN32)
+ if(argv0) { free(argv0); }
+#endif
+ return r;
+ }
+ else if(argc > 2 && strcmp(argv[1], "0") == 0)
+ {
+ /* This is the special debugging test to run a given command
+ line. */
+ const char** cmd = argv+2;
+ int state = kwsysProcess_State_Exited;
+ int exception = kwsysProcess_Exception_None;
+ int value = 0;
+ double timeout = 0;
+ int r = runChild(cmd, state, exception, value, 0, 1, 0, timeout,
+ 0, 1, 0, 0, 0);
+ return r;
+ }
+ else
+ {
+ /* Improper usage. */
+ fprintf(stdout, "Usage: %s <test number>\n", argv[0]);
+ return 1;
+ }
+}
diff --git a/Source/kwsys/testSharedForward.c.in b/Source/kwsys/testSharedForward.c.in
new file mode 100644
index 0000000..ee753ef
--- /dev/null
+++ b/Source/kwsys/testSharedForward.c.in
@@ -0,0 +1,36 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#if defined(CMAKE_INTDIR)
+# define CONFIG_DIR_PRE CMAKE_INTDIR "/"
+# define CONFIG_DIR_POST "/" CMAKE_INTDIR
+#else
+# define CONFIG_DIR_PRE ""
+# define CONFIG_DIR_POST ""
+#endif
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD "@EXEC_DIR@"
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD "." CONFIG_DIR_POST
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL 0
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD \
+ CONFIG_DIR_PRE "@KWSYS_NAMESPACE@TestProcess"
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL \
+ "@KWSYS_NAMESPACE@TestProcess"
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND "--command"
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT "--print"
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD "--ldd"
+#if defined(CMAKE_INTDIR)
+# define @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME CMAKE_INTDIR
+#endif
+#include <@KWSYS_NAMESPACE@/SharedForward.h>
+int main(int argc, char** argv)
+{
+ return @KWSYS_NAMESPACE@_shared_forward_to_real(argc, argv);
+}
diff --git a/Source/kwsys/testSystemInformation.cxx b/Source/kwsys/testSystemInformation.cxx
new file mode 100644
index 0000000..c96751a
--- /dev/null
+++ b/Source/kwsys/testSystemInformation.cxx
@@ -0,0 +1,119 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(SystemInformation.hxx)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "SystemInformation.hxx.in"
+#endif
+
+#include <iostream>
+
+#if defined(KWSYS_USE_LONG_LONG)
+# if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG)
+# define iostreamLongLong(x) (x)
+# else
+# define iostreamLongLong(x) ((long)x)
+# endif
+#elif defined(KWSYS_USE___INT64)
+# if defined(KWSYS_IOS_HAS_OSTREAM___INT64)
+# define iostreamLongLong(x) (x)
+# else
+# define iostreamLongLong(x) ((long)x)
+# endif
+#else
+# error "No Long Long"
+#endif
+
+#define printMethod(info, m) std::cout << #m << ": " \
+<< info.m() << "\n"
+
+#define printMethod2(info, m, unit) std::cout << #m << ": " \
+<< info.m() << " " << unit << "\n"
+
+#define printMethod3(info, m, unit) std::cout << #m << ": " \
+<< iostreamLongLong(info.m) << " " << unit << "\n"
+
+int testSystemInformation(int, char*[])
+{
+ std::cout << "CTEST_FULL_OUTPUT\n"; // avoid truncation
+
+ kwsys::SystemInformation info;
+ info.RunCPUCheck();
+ info.RunOSCheck();
+ info.RunMemoryCheck();
+ printMethod(info, GetOSName);
+ printMethod(info, GetOSIsLinux);
+ printMethod(info, GetOSIsApple);
+ printMethod(info, GetOSIsWindows);
+ printMethod(info, GetHostname);
+ printMethod(info, GetFullyQualifiedDomainName);
+ printMethod(info, GetOSRelease);
+ printMethod(info, GetOSVersion);
+ printMethod(info, GetOSPlatform);
+ printMethod(info, GetVendorString);
+ printMethod(info, GetVendorID);
+ printMethod(info, GetTypeID);
+ printMethod(info, GetFamilyID);
+ printMethod(info, GetModelID);
+ printMethod(info, GetExtendedProcessorName);
+ printMethod(info, GetSteppingCode);
+ printMethod(info, GetProcessorSerialNumber);
+ printMethod2(info, GetProcessorCacheSize, "KB");
+ printMethod(info, GetLogicalProcessorsPerPhysical);
+ printMethod2(info, GetProcessorClockFrequency, "MHz");
+ printMethod(info, Is64Bits);
+ printMethod(info, GetNumberOfLogicalCPU);
+ printMethod(info, GetNumberOfPhysicalCPU);
+ printMethod(info, DoesCPUSupportCPUID);
+ printMethod(info, GetProcessorAPICID);
+ printMethod2(info, GetTotalVirtualMemory, "MB");
+ printMethod2(info, GetAvailableVirtualMemory, "MB");
+ printMethod2(info, GetTotalPhysicalMemory, "MB");
+ printMethod2(info, GetAvailablePhysicalMemory, "MB");
+ printMethod3(info, GetHostMemoryTotal(), "KiB");
+ printMethod3(info, GetHostMemoryAvailable("KWSHL"), "KiB");
+ printMethod3(info, GetProcMemoryAvailable("KWSHL","KWSPL"), "KiB");
+ printMethod3(info, GetHostMemoryUsed(), "KiB");
+ printMethod3(info, GetProcMemoryUsed(), "KiB");
+ printMethod(info, GetLoadAverage);
+
+ for (long int i = 0; i <= 31; i++)
+ {
+ if (info.DoesCPUSupportFeature(static_cast<long int>(1) << i))
+ {
+ std::cout << "CPU feature " << i << "\n";
+ }
+ }
+
+ /* test stack trace
+ */
+ std::cout
+ << "Program Stack:" << std::endl
+ << kwsys::SystemInformation::GetProgramStack(0,0) << std::endl
+ << std::endl;
+
+ /* test segv handler
+ info.SetStackTraceOnError(1);
+ double *d = (double*)100;
+ *d=0;
+ */
+
+ /* test abort handler
+ info.SetStackTraceOnError(1);
+ abort();
+ */
+
+ return 0;
+}
diff --git a/Source/kwsys/testSystemTools.bin b/Source/kwsys/testSystemTools.bin
new file mode 100644
index 0000000..961a404
--- /dev/null
+++ b/Source/kwsys/testSystemTools.bin
Binary files differ
diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx
new file mode 100644
index 0000000..4d97688
--- /dev/null
+++ b/Source/kwsys/testSystemTools.cxx
@@ -0,0 +1,1080 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+
+#if defined(_MSC_VER)
+# pragma warning (disable:4786)
+#endif
+
+#include KWSYS_HEADER(SystemTools.hxx)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "SystemTools.hxx.in"
+#endif
+
+// Include with <> instead of "" to avoid getting any in-source copy
+// left on disk.
+#include <testSystemTools.h>
+
+#include <iostream>
+#include <sstream>
+#include <string.h> /* strcmp */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <io.h> /* _umask (MSVC) / umask (Borland) */
+# ifdef _MSC_VER
+# define umask _umask // Note this is still umask on Borland
+# endif
+#endif
+#include <sys/stat.h> /* umask (POSIX), _S_I* constants (Windows) */
+// Visual C++ does not define mode_t (note that Borland does, however).
+#if defined( _MSC_VER )
+typedef unsigned short mode_t;
+#endif
+
+//----------------------------------------------------------------------------
+static const char* toUnixPaths[][2] =
+{
+ { "/usr/local/bin/passwd", "/usr/local/bin/passwd" },
+ { "/usr/lo cal/bin/pa sswd", "/usr/lo cal/bin/pa sswd" },
+ { "/usr/lo\\ cal/bin/pa\\ sswd", "/usr/lo\\ cal/bin/pa\\ sswd" },
+ { "c:/usr/local/bin/passwd", "c:/usr/local/bin/passwd" },
+ { "c:/usr/lo cal/bin/pa sswd", "c:/usr/lo cal/bin/pa sswd" },
+ { "c:/usr/lo\\ cal/bin/pa\\ sswd", "c:/usr/lo\\ cal/bin/pa\\ sswd" },
+ { "\\usr\\local\\bin\\passwd", "/usr/local/bin/passwd" },
+ { "\\usr\\lo cal\\bin\\pa sswd", "/usr/lo cal/bin/pa sswd" },
+ { "\\usr\\lo\\ cal\\bin\\pa\\ sswd", "/usr/lo\\ cal/bin/pa\\ sswd" },
+ { "c:\\usr\\local\\bin\\passwd", "c:/usr/local/bin/passwd" },
+ { "c:\\usr\\lo cal\\bin\\pa sswd", "c:/usr/lo cal/bin/pa sswd" },
+ { "c:\\usr\\lo\\ cal\\bin\\pa\\ sswd", "c:/usr/lo\\ cal/bin/pa\\ sswd" },
+ { "\\\\usr\\local\\bin\\passwd", "//usr/local/bin/passwd" },
+ { "\\\\usr\\lo cal\\bin\\pa sswd", "//usr/lo cal/bin/pa sswd" },
+ { "\\\\usr\\lo\\ cal\\bin\\pa\\ sswd", "//usr/lo\\ cal/bin/pa\\ sswd" },
+ {0, 0}
+};
+
+static bool CheckConvertToUnixSlashes(std::string input,
+ std::string output)
+{
+ std::string result = input;
+ kwsys::SystemTools::ConvertToUnixSlashes(result);
+ if ( result != output )
+ {
+ std::cerr
+ << "Problem with ConvertToUnixSlashes - input: " << input
+ << " output: " << result << " expected: " << output
+ << std::endl;
+ return false;
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+static const char* checkEscapeChars[][4] =
+{
+ { "1 foo 2 bar 2", "12", "\\", "\\1 foo \\2 bar \\2"},
+ { " {} ", "{}", "#", " #{#} "},
+ {0, 0, 0, 0}
+};
+
+static bool CheckEscapeChars(std::string input,
+ const char *chars_to_escape,
+ char escape_char,
+ std::string output)
+{
+ std::string result = kwsys::SystemTools::EscapeChars(
+ input.c_str(), chars_to_escape, escape_char);
+ if (result != output)
+ {
+ std::cerr
+ << "Problem with CheckEscapeChars - input: " << input
+ << " output: " << result << " expected: " << output
+ << std::endl;
+ return false;
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+static bool CheckFileOperations()
+{
+ bool res = true;
+ const std::string testNonExistingFile(TEST_SYSTEMTOOLS_SOURCE_DIR
+ "/testSystemToolsNonExistingFile");
+ const std::string testDotFile(TEST_SYSTEMTOOLS_SOURCE_DIR
+ "/.");
+ const std::string testBinFile(TEST_SYSTEMTOOLS_SOURCE_DIR
+ "/testSystemTools.bin");
+ const std::string testTxtFile(TEST_SYSTEMTOOLS_SOURCE_DIR
+ "/testSystemTools.cxx");
+ const std::string testNewDir(TEST_SYSTEMTOOLS_BINARY_DIR
+ "/testSystemToolsNewDir");
+ const std::string testNewFile(testNewDir + "/testNewFile.txt");
+
+ if (kwsys::SystemTools::DetectFileType(testNonExistingFile.c_str()) !=
+ kwsys::SystemTools::FileTypeUnknown)
+ {
+ std::cerr
+ << "Problem with DetectFileType - failed to detect type of: "
+ << testNonExistingFile << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::DetectFileType(testDotFile.c_str()) !=
+ kwsys::SystemTools::FileTypeUnknown)
+ {
+ std::cerr
+ << "Problem with DetectFileType - failed to detect type of: "
+ << testDotFile << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::DetectFileType(testBinFile.c_str()) !=
+ kwsys::SystemTools::FileTypeBinary)
+ {
+ std::cerr
+ << "Problem with DetectFileType - failed to detect type of: "
+ << testBinFile << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::DetectFileType(testTxtFile.c_str()) !=
+ kwsys::SystemTools::FileTypeText)
+ {
+ std::cerr
+ << "Problem with DetectFileType - failed to detect type of: "
+ << testTxtFile << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::FileLength(testBinFile) != 766)
+ {
+ std::cerr
+ << "Problem with FileLength - incorrect length for: "
+ << testBinFile << std::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::MakeDirectory(testNewDir))
+ {
+ std::cerr
+ << "Problem with MakeDirectory for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+ // calling it again should just return true
+ if (!kwsys::SystemTools::MakeDirectory(testNewDir))
+ {
+ std::cerr
+ << "Problem with second call to MakeDirectory for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+ // calling with 0 pointer should return false
+ if (kwsys::SystemTools::MakeDirectory(0))
+ {
+ std::cerr
+ << "Problem with MakeDirectory(0)"
+ << std::endl;
+ res = false;
+ }
+ // calling with an empty string should return false
+ if (kwsys::SystemTools::MakeDirectory(std::string()))
+ {
+ std::cerr
+ << "Problem with MakeDirectory(std::string())"
+ << std::endl;
+ res = false;
+ }
+ // check existence
+ if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false))
+ {
+ std::cerr
+ << "Problem with FileExists as C string and not file for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+ // remove it
+ if (!kwsys::SystemTools::RemoveADirectory(testNewDir))
+ {
+ std::cerr
+ << "Problem with RemoveADirectory for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+ // check existence
+ if (kwsys::SystemTools::FileExists(testNewDir.c_str(), false))
+ {
+ std::cerr
+ << "After RemoveADirectory: "
+ << "Problem with FileExists as C string and not file for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+ // create it using the char* version
+ if (!kwsys::SystemTools::MakeDirectory(testNewDir.c_str()))
+ {
+ std::cerr
+ << "Problem with second call to MakeDirectory as C string for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::Touch(testNewFile.c_str(), true))
+ {
+ std::cerr
+ << "Problem with Touch for: "
+ << testNewFile << std::endl;
+ res = false;
+ }
+ // calling MakeDirectory with something that is no file should fail
+ if (kwsys::SystemTools::MakeDirectory(testNewFile))
+ {
+ std::cerr
+ << "Problem with to MakeDirectory for: "
+ << testNewFile << std::endl;
+ res = false;
+ }
+
+ // calling with 0 pointer should return false
+ if (kwsys::SystemTools::FileExists(0))
+ {
+ std::cerr
+ << "Problem with FileExists(0)"
+ << std::endl;
+ res = false;
+ }
+ if (kwsys::SystemTools::FileExists(0, true))
+ {
+ std::cerr
+ << "Problem with FileExists(0) as file"
+ << std::endl;
+ res = false;
+ }
+ // calling with an empty string should return false
+ if (kwsys::SystemTools::FileExists(std::string()))
+ {
+ std::cerr
+ << "Problem with FileExists(std::string())"
+ << std::endl;
+ res = false;
+ }
+ // FileExists(x, true) should return false on a directory
+ if (kwsys::SystemTools::FileExists(testNewDir, true))
+ {
+ std::cerr
+ << "Problem with FileExists as file for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+ if (kwsys::SystemTools::FileExists(testNewDir.c_str(), true))
+ {
+ std::cerr
+ << "Problem with FileExists as C string and file for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+ // FileExists(x, false) should return true even on a directory
+ if (!kwsys::SystemTools::FileExists(testNewDir, false))
+ {
+ std::cerr
+ << "Problem with FileExists as not file for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+ if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false))
+ {
+ std::cerr
+ << "Problem with FileExists as C string and not file for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+ // should work, was created as new file before
+ if (!kwsys::SystemTools::FileExists(testNewFile))
+ {
+ std::cerr
+ << "Problem with FileExists for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+ if (!kwsys::SystemTools::FileExists(testNewFile.c_str()))
+ {
+ std::cerr
+ << "Problem with FileExists as C string for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+ if (!kwsys::SystemTools::FileExists(testNewFile, true))
+ {
+ std::cerr
+ << "Problem with FileExists as file for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+ if (!kwsys::SystemTools::FileExists(testNewFile.c_str(), true))
+ {
+ std::cerr
+ << "Problem with FileExists as C string and file for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+
+ // Reset umask
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // NOTE: Windows doesn't support toggling _S_IREAD.
+ mode_t fullMask = _S_IWRITE;
+#else
+ // On a normal POSIX platform, we can toggle all permissions.
+ mode_t fullMask = S_IRWXU | S_IRWXG | S_IRWXO;
+#endif
+ mode_t orig_umask = umask(fullMask);
+
+ // Test file permissions without umask
+ mode_t origPerm, thisPerm;
+ if (!kwsys::SystemTools::GetPermissions(testNewFile, origPerm))
+ {
+ std::cerr
+ << "Problem with GetPermissions (1) for: "
+ << testNewFile << std::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::SetPermissions(testNewFile, 0))
+ {
+ std::cerr
+ << "Problem with SetPermissions (1) for: "
+ << testNewFile << std::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm))
+ {
+ std::cerr
+ << "Problem with GetPermissions (2) for: "
+ << testNewFile << std::endl;
+ res = false;
+ }
+
+ if ((thisPerm & fullMask) != 0)
+ {
+ std::cerr
+ << "SetPermissions failed to set permissions (1) for: "
+ << testNewFile << ": actual = " << thisPerm << "; expected = "
+ << 0 << std::endl;
+ res = false;
+ }
+
+ // While we're at it, check proper TestFileAccess functionality.
+ if (kwsys::SystemTools::TestFileAccess(testNewFile,
+ kwsys::TEST_FILE_WRITE))
+ {
+ std::cerr
+ << "TestFileAccess incorrectly indicated that this is a writable file:"
+ << testNewFile << std::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::TestFileAccess(testNewFile,
+ kwsys::TEST_FILE_OK))
+ {
+ std::cerr
+ << "TestFileAccess incorrectly indicated that this file does not exist:"
+ << testNewFile << std::endl;
+ res = false;
+ }
+
+ // Test restoring/setting full permissions.
+ if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask))
+ {
+ std::cerr
+ << "Problem with SetPermissions (2) for: "
+ << testNewFile << std::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm))
+ {
+ std::cerr
+ << "Problem with GetPermissions (3) for: "
+ << testNewFile << std::endl;
+ res = false;
+ }
+
+ if ((thisPerm & fullMask) != fullMask)
+ {
+ std::cerr
+ << "SetPermissions failed to set permissions (2) for: "
+ << testNewFile << ": actual = " << thisPerm << "; expected = "
+ << fullMask << std::endl;
+ res = false;
+ }
+
+ // Test setting file permissions while honoring umask
+ if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask, true))
+ {
+ std::cerr
+ << "Problem with SetPermissions (3) for: "
+ << testNewFile << std::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm))
+ {
+ std::cerr
+ << "Problem with GetPermissions (4) for: "
+ << testNewFile << std::endl;
+ res = false;
+ }
+
+ if ((thisPerm & fullMask) != 0)
+ {
+ std::cerr
+ << "SetPermissions failed to honor umask for: "
+ << testNewFile << ": actual = " << thisPerm << "; expected = "
+ << 0 << std::endl;
+ res = false;
+ }
+
+ // Restore umask
+ umask(orig_umask);
+
+ // Restore file permissions
+ if (!kwsys::SystemTools::SetPermissions(testNewFile, origPerm))
+ {
+ std::cerr
+ << "Problem with SetPermissions (4) for: "
+ << testNewFile << std::endl;
+ res = false;
+ }
+
+ // Remove the test file
+ if (!kwsys::SystemTools::RemoveFile(testNewFile))
+ {
+ std::cerr
+ << "Problem with RemoveFile: "
+ << testNewFile << std::endl;
+ res = false;
+ }
+
+ std::string const testFileMissing(testNewDir + "/testMissingFile.txt");
+ if (!kwsys::SystemTools::RemoveFile(testFileMissing))
+ {
+ std::string const& msg = kwsys::SystemTools::GetLastSystemError();
+ std::cerr <<
+ "RemoveFile(\"" << testFileMissing << "\") failed: " << msg << "\n";
+ res = false;
+ }
+
+ std::string const testFileMissingDir(testNewDir + "/missing/file.txt");
+ if (!kwsys::SystemTools::RemoveFile(testFileMissingDir))
+ {
+ std::string const& msg = kwsys::SystemTools::GetLastSystemError();
+ std::cerr <<
+ "RemoveFile(\"" << testFileMissingDir << "\") failed: " << msg << "\n";
+ res = false;
+ }
+
+ kwsys::SystemTools::Touch(testNewFile.c_str(), true);
+ if (!kwsys::SystemTools::RemoveADirectory(testNewDir))
+ {
+ std::cerr
+ << "Problem with RemoveADirectory for: "
+ << testNewDir << std::endl;
+ res = false;
+ }
+
+#ifdef KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS
+ // Perform the same file and directory creation and deletion tests but
+ // with paths > 256 characters in length.
+
+ const std::string testNewLongDir(
+ TEST_SYSTEMTOOLS_BINARY_DIR "/"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "01234567890123");
+ const std::string testNewLongFile(testNewLongDir + "/"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "0123456789.txt");
+
+ if (!kwsys::SystemTools::MakeDirectory(testNewLongDir))
+ {
+ std::cerr
+ << "Problem with MakeDirectory for: "
+ << testNewLongDir << std::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::Touch(testNewLongFile.c_str(), true))
+ {
+ std::cerr
+ << "Problem with Touch for: "
+ << testNewLongFile << std::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::RemoveFile(testNewLongFile))
+ {
+ std::cerr
+ << "Problem with RemoveFile: "
+ << testNewLongFile << std::endl;
+ res = false;
+ }
+
+ kwsys::SystemTools::Touch(testNewLongFile.c_str(), true);
+ if (!kwsys::SystemTools::RemoveADirectory(testNewLongDir))
+ {
+ std::cerr
+ << "Problem with RemoveADirectory for: "
+ << testNewLongDir << std::endl;
+ res = false;
+ }
+#endif
+
+ return res;
+}
+
+//----------------------------------------------------------------------------
+static bool CheckStringOperations()
+{
+ bool res = true;
+
+ std::string test = "mary had a little lamb.";
+ if (kwsys::SystemTools::CapitalizedWords(test) != "Mary Had A Little Lamb.")
+ {
+ std::cerr
+ << "Problem with CapitalizedWords "
+ << '"' << test << '"' << std::endl;
+ res = false;
+ }
+
+ test = "Mary Had A Little Lamb.";
+ if (kwsys::SystemTools::UnCapitalizedWords(test) !=
+ "mary had a little lamb.")
+ {
+ std::cerr
+ << "Problem with UnCapitalizedWords "
+ << '"' << test << '"' << std::endl;
+ res = false;
+ }
+
+ test = "MaryHadTheLittleLamb.";
+ if (kwsys::SystemTools::AddSpaceBetweenCapitalizedWords(test) !=
+ "Mary Had The Little Lamb.")
+ {
+ std::cerr
+ << "Problem with AddSpaceBetweenCapitalizedWords "
+ << '"' << test << '"' << std::endl;
+ res = false;
+ }
+
+ char * cres =
+ kwsys::SystemTools::AppendStrings("Mary Had A"," Little Lamb.");
+ if (strcmp(cres,"Mary Had A Little Lamb."))
+ {
+ std::cerr
+ << "Problem with AppendStrings "
+ << "\"Mary Had A\" \" Little Lamb.\"" << std::endl;
+ res = false;
+ }
+ delete [] cres;
+
+ cres =
+ kwsys::SystemTools::AppendStrings("Mary Had"," A ","Little Lamb.");
+ if (strcmp(cres,"Mary Had A Little Lamb."))
+ {
+ std::cerr
+ << "Problem with AppendStrings "
+ << "\"Mary Had\" \" A \" \"Little Lamb.\"" << std::endl;
+ res = false;
+ }
+ delete [] cres;
+
+ if (kwsys::SystemTools::CountChar("Mary Had A Little Lamb.",'a') != 3)
+ {
+ std::cerr
+ << "Problem with CountChar "
+ << "\"Mary Had A Little Lamb.\"" << std::endl;
+ res = false;
+ }
+
+ cres =
+ kwsys::SystemTools::RemoveChars("Mary Had A Little Lamb.","aeiou");
+ if (strcmp(cres,"Mry Hd A Lttl Lmb."))
+ {
+ std::cerr
+ << "Problem with RemoveChars "
+ << "\"Mary Had A Little Lamb.\"" << std::endl;
+ res = false;
+ }
+ delete [] cres;
+
+ cres =
+ kwsys::SystemTools::RemoveCharsButUpperHex("Mary Had A Little Lamb.");
+ if (strcmp(cres,"A"))
+ {
+ std::cerr
+ << "Problem with RemoveCharsButUpperHex "
+ << "\"Mary Had A Little Lamb.\"" << std::endl;
+ res = false;
+ }
+ delete [] cres;
+
+ char *cres2 = new char [strlen("Mary Had A Little Lamb.")+1];
+ strcpy(cres2,"Mary Had A Little Lamb.");
+ kwsys::SystemTools::ReplaceChars(cres2,"aeiou",'X');
+ if (strcmp(cres2,"MXry HXd A LXttlX LXmb."))
+ {
+ std::cerr
+ << "Problem with ReplaceChars "
+ << "\"Mary Had A Little Lamb.\"" << std::endl;
+ res = false;
+ }
+ delete [] cres2;
+
+ if (!kwsys::SystemTools::StringStartsWith("Mary Had A Little Lamb.",
+ "Mary "))
+ {
+ std::cerr
+ << "Problem with StringStartsWith "
+ << "\"Mary Had A Little Lamb.\"" << std::endl;
+ res = false;
+ }
+
+ if (!kwsys::SystemTools::StringEndsWith("Mary Had A Little Lamb.",
+ " Lamb."))
+ {
+ std::cerr
+ << "Problem with StringEndsWith "
+ << "\"Mary Had A Little Lamb.\"" << std::endl;
+ res = false;
+ }
+
+ cres = kwsys::SystemTools::DuplicateString("Mary Had A Little Lamb.");
+ if (strcmp(cres,"Mary Had A Little Lamb."))
+ {
+ std::cerr
+ << "Problem with DuplicateString "
+ << "\"Mary Had A Little Lamb.\"" << std::endl;
+ res = false;
+ }
+ delete [] cres;
+
+ test = "Mary Had A Little Lamb.";
+ if (kwsys::SystemTools::CropString(test,13) !=
+ "Mary ...Lamb.")
+ {
+ std::cerr
+ << "Problem with CropString "
+ << "\"Mary Had A Little Lamb.\"" << std::endl;
+ res = false;
+ }
+
+ std::vector<std::string> lines;
+ kwsys::SystemTools::Split("Mary Had A Little Lamb.",lines,' ');
+ if (lines[0] != "Mary" || lines[1] != "Had" ||
+ lines[2] != "A" || lines[3] != "Little" || lines[4] != "Lamb.")
+ {
+ std::cerr
+ << "Problem with Split "
+ << "\"Mary Had A Little Lamb.\"" << std::endl;
+ res = false;
+ }
+
+#ifdef _WIN32
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath
+ ("L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") !=
+ L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath
+ ("L:/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+ L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"L:/Local Mojo/Hex Power Pack/Iffy Voodoo\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath
+ ("\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") !=
+ L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath
+ ("//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+ L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("//") !=
+ L"//")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"//\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("\\\\.\\") !=
+ L"\\\\.\\")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\.\\\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("\\\\.\\X") !=
+ L"\\\\.\\X")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\.\\X\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("\\\\.\\X:") !=
+ L"\\\\?\\X:")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\.\\X:\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("\\\\.\\X:\\") !=
+ L"\\\\?\\X:\\")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\.\\X:\\\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("NUL") !=
+ L"\\\\.\\NUL")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"NUL\""
+ << std::endl;
+ res = false;
+ }
+
+#endif
+
+ if (kwsys::SystemTools::ConvertToWindowsOutputPath
+ ("L://Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+ "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsOutputPath "
+ << "\"L://Local Mojo/Hex Power Pack/Iffy Voodoo\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsOutputPath
+ ("//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+ "\"\\\\grayson\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsOutputPath "
+ << "\"//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToUnixOutputPath
+ ("//Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+ "//Local\\ Mojo/Hex\\ Power\\ Pack/Iffy\\ Voodoo")
+ {
+ std::cerr
+ << "Problem with ConvertToUnixOutputPath "
+ << "\"//Local Mojo/Hex Power Pack/Iffy Voodoo\""
+ << std::endl;
+ res = false;
+ }
+
+ return res;
+}
+
+//----------------------------------------------------------------------------
+
+static bool CheckPutEnv(const std::string& env, const char* name, const char* value)
+{
+ if(!kwsys::SystemTools::PutEnv(env))
+ {
+ std::cerr << "PutEnv(\"" << env
+ << "\") failed!" << std::endl;
+ return false;
+ }
+ const char* v = kwsys::SystemTools::GetEnv(name);
+ v = v? v : "(null)";
+ if(strcmp(v, value) != 0)
+ {
+ std::cerr << "GetEnv(\"" << name << "\") returned \""
+ << v << "\", not \"" << value << "\"!" << std::endl;
+ return false;
+ }
+ return true;
+}
+
+static bool CheckUnPutEnv(const char* env, const char* name)
+{
+ if(!kwsys::SystemTools::UnPutEnv(env))
+ {
+ std::cerr << "UnPutEnv(\"" << env << "\") failed!"
+ << std::endl;
+ return false;
+ }
+ if(const char* v = kwsys::SystemTools::GetEnv(name))
+ {
+ std::cerr << "GetEnv(\"" << name << "\") returned \""
+ << v << "\", not (null)!" << std::endl;
+ return false;
+ }
+ return true;
+}
+
+static bool CheckEnvironmentOperations()
+{
+ bool res = true;
+ res &= CheckPutEnv("A=B", "A", "B");
+ res &= CheckPutEnv("B=C", "B", "C");
+ res &= CheckPutEnv("C=D", "C", "D");
+ res &= CheckPutEnv("D=E", "D", "E");
+ res &= CheckUnPutEnv("A", "A");
+ res &= CheckUnPutEnv("B=", "B");
+ res &= CheckUnPutEnv("C=D", "C");
+ /* Leave "D=E" in environment so a memory checker can test for leaks. */
+ return res;
+}
+
+
+static bool CheckRelativePath(
+ const std::string& local,
+ const std::string& remote,
+ const std::string& expected)
+{
+ std::string result = kwsys::SystemTools::RelativePath(local, remote);
+ if(expected != result)
+ {
+ std::cerr << "RelativePath(" << local << ", " << remote
+ << ") yielded " << result << " instead of " << expected << std::endl;
+ return false;
+ }
+ return true;
+}
+
+static bool CheckRelativePaths()
+{
+ bool res = true;
+ res &= CheckRelativePath("/usr/share", "/bin/bash", "../../bin/bash");
+ res &= CheckRelativePath("/usr/./share/", "/bin/bash", "../../bin/bash");
+ res &= CheckRelativePath("/usr//share/", "/bin/bash", "../../bin/bash");
+ res &= CheckRelativePath("/usr/share/../bin/", "/bin/bash", "../../bin/bash");
+ res &= CheckRelativePath("/usr/share", "/usr/share//bin", "bin");
+ return res;
+}
+
+static bool CheckCollapsePath(
+ const std::string& path,
+ const std::string& expected)
+{
+ std::string result = kwsys::SystemTools::CollapseFullPath(path);
+ if(expected != result)
+ {
+ std::cerr << "CollapseFullPath(" << path
+ << ") yielded " << result << " instead of " << expected << std::endl;
+ return false;
+ }
+ return true;
+}
+
+static bool CheckCollapsePath()
+{
+ bool res = true;
+ res &= CheckCollapsePath("/usr/share/*", "/usr/share/*");
+ res &= CheckCollapsePath("C:/Windows/*", "C:/Windows/*");
+ return res;
+}
+
+static std::string StringVectorToString(const std::vector<std::string>& vec)
+{
+ std::stringstream ss;
+ ss << "vector(";
+ for (std::vector<std::string>::const_iterator i = vec.begin();
+ i != vec.end(); ++i)
+ {
+ if (i != vec.begin())
+ {
+ ss << ", ";
+ }
+ ss << *i;
+ }
+ ss << ")";
+ return ss.str();
+}
+
+static bool CheckGetPath()
+{
+ const char* envName = "S";
+#ifdef _WIN32
+ const char* envValue = "C:\\Somewhere\\something;D:\\Temp";
+#else
+ const char* envValue = "/Somewhere/something:/tmp";
+#endif
+ const char* registryPath = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MyApp; MyKey]";
+
+ std::vector<std::string> originalPathes;
+ originalPathes.push_back(registryPath);
+
+ std::vector<std::string> expectedPathes;
+ expectedPathes.push_back(registryPath);
+#ifdef _WIN32
+ expectedPathes.push_back("C:/Somewhere/something");
+ expectedPathes.push_back("D:/Temp");
+#else
+ expectedPathes.push_back("/Somewhere/something");
+ expectedPathes.push_back("/tmp");
+#endif
+
+ bool res = true;
+ res &= CheckPutEnv(std::string(envName) + "=" + envValue, envName, envValue);
+
+ std::vector<std::string> pathes = originalPathes;
+ kwsys::SystemTools::GetPath(pathes, envName);
+
+ if (pathes != expectedPathes)
+ {
+ std::cerr <<
+ "GetPath(" << StringVectorToString(originalPathes) <<
+ ", " << envName << ") yielded " << StringVectorToString(pathes) <<
+ " instead of " << StringVectorToString(expectedPathes) <<
+ std::endl;
+ res = false;
+ }
+
+ res &= CheckUnPutEnv(envName, envName);
+ return res;
+}
+
+static bool CheckFind()
+{
+ bool res = true;
+ const std::string testFindFileName("testFindFile.txt");
+ const std::string testFindFile(TEST_SYSTEMTOOLS_BINARY_DIR "/"
+ + testFindFileName);
+
+ if (!kwsys::SystemTools::Touch(testFindFile.c_str(), true))
+ {
+ std::cerr
+ << "Problem with Touch for: "
+ << testFindFile << std::endl;
+ // abort here as the existence of the file only makes the test meaningful
+ return false;
+ }
+
+ std::vector<std::string> searchPaths;
+ searchPaths.push_back(TEST_SYSTEMTOOLS_BINARY_DIR);
+ if (kwsys::SystemTools::FindFile(testFindFileName,
+ searchPaths, true).empty())
+ {
+ std::cerr
+ << "Problem with FindFile without system paths for: "
+ << testFindFileName << std::endl;
+ res = false;
+ }
+ if (kwsys::SystemTools::FindFile(testFindFileName,
+ searchPaths, false).empty())
+ {
+ std::cerr
+ << "Problem with FindFile with system paths for: "
+ << testFindFileName << std::endl;
+ res = false;
+ }
+
+ return res;
+}
+
+//----------------------------------------------------------------------------
+int testSystemTools(int, char*[])
+{
+ bool res = true;
+
+ int cc;
+ for ( cc = 0; toUnixPaths[cc][0]; cc ++ )
+ {
+ res &= CheckConvertToUnixSlashes(toUnixPaths[cc][0], toUnixPaths[cc][1]);
+ }
+
+ // Special check for ~
+ std::string output;
+ if(kwsys::SystemTools::GetEnv("HOME", output))
+ {
+ output += "/foo bar/lala";
+ res &= CheckConvertToUnixSlashes("~/foo bar/lala", output);
+ }
+
+ for (cc = 0; checkEscapeChars[cc][0]; cc ++ )
+ {
+ res &= CheckEscapeChars(checkEscapeChars[cc][0], checkEscapeChars[cc][1],
+ *checkEscapeChars[cc][2], checkEscapeChars[cc][3]);
+ }
+
+ res &= CheckFileOperations();
+
+ res &= CheckStringOperations();
+
+ res &= CheckEnvironmentOperations();
+
+ res &= CheckRelativePaths();
+
+ res &= CheckCollapsePath();
+
+ res &= CheckGetPath();
+
+ res &= CheckFind();
+
+ return res ? 0 : 1;
+}
diff --git a/Source/kwsys/testSystemTools.h.in b/Source/kwsys/testSystemTools.h.in
new file mode 100644
index 0000000..66f0f72
--- /dev/null
+++ b/Source/kwsys/testSystemTools.h.in
@@ -0,0 +1,21 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_testSystemtools_h
+#define @KWSYS_NAMESPACE@_testSystemtools_h
+
+#define EXECUTABLE_OUTPUT_PATH "@CMAKE_CURRENT_BINARY_DIR@"
+
+#define TEST_SYSTEMTOOLS_SOURCE_DIR "@TEST_SYSTEMTOOLS_SOURCE_DIR@"
+#define TEST_SYSTEMTOOLS_BINARY_DIR "@TEST_SYSTEMTOOLS_BINARY_DIR@"
+#cmakedefine KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS
+
+#endif
diff --git a/Source/kwsys/testTerminal.c b/Source/kwsys/testTerminal.c
new file mode 100644
index 0000000..0d2d7a7
--- /dev/null
+++ b/Source/kwsys/testTerminal.c
@@ -0,0 +1,31 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Terminal.h)
+
+/* Work-around CMake dependency scanning limitation. This must
+ duplicate the above list of headers. */
+#if 0
+# include "Terminal.h.in"
+#endif
+
+int testTerminal(int argc, char* argv[])
+{
+ (void)argc;
+ (void)argv;
+ kwsysTerminal_cfprintf(kwsysTerminal_Color_ForegroundYellow |
+ kwsysTerminal_Color_BackgroundBlue |
+ kwsysTerminal_Color_AssumeTTY,
+ stdout, "Hello %s!", "World");
+ fprintf(stdout, "\n");
+ return 0;
+}